This is my code:
module Main where
import Data.Graph.Inductive
import Data.Graph.Inductive.Example
func :: Graph gr=> gr a b ->[Node]->Int-> [(Node,Int)]
func graph (x:xs) y
|indeg graph x == 0 = (x,y+1):func (delNode x graph ) xs (y+1)
graph2:: Gr Int Int
graph2 = mkGraph (genLNodes 1 14)[(1,2,1),
(1,3,1),
(3,14,1),
(14,6,1),
(14,7,1),
(2,4,1),
(2,5,1),
(4,6,1),
(5,7,1),
(6,8,1),
(7,9,1),
(8,10,1),
(9,11,1),
(10,12,1),
(11,12,1),
(12,13,1),
(14,13,1)]
Graph2 have 14 nodes and e.g (1,2,1) means, edge from node 1 to node 2 with a weight of 1.
Func takes my Graph2, topological sorting vertices and some number e.g 0.
Func checks if inward-bound degree of the Node is equal to 0 and creates list of tuples where x is IdNode and y is increasing when indeg graph x == 0 is true. The vertex is removed
And here is my problem, I want to see if more vertices has a degree of 0 and add 1.
EDIT:
The function should act as follow:
topsort: [1,3,14,2,5,7,9,11,4,6,8,10,12,13]
check in-bound degree for each node in the list.
if degree is equal 0, add 1 to path lenght ( node 1 in-bound is equal 0 so path length= 1)
remove node from graph and check in-bound degree of nodes after removing node and return to step 2.
continuing example:
after removing node 1, nodes 2 and 3 have in-bound = 0 so I add 1 to path length (path lenght = 2 for node 2 and 3 ) and I remove node 2 and 3.
Now in-bound degree =0 have 14,4,5 so I add 1 to path length (path lenght =3) and I remove these nodes and so on
I hope that the image of the graph will help.
With lazy evaluation you can use the "tie-the-knot" method to compute the depths very declaratively:
minOr0 [] = 0
minOr0 ds = minimum ds
depths :: Graph gr => gr a b -> [(Node, Int)]
depths gr =
let pairs = [ (x, depth x) | x <- nodes gr ]
depth x = 1 + minOr0 [ d | y <- pre gr x, let Just d = lookup y pairs ]
in pairs
test2 = depths graph2
The definition between pairs and depth is circular: evaluating a tuple in pairs calls depth. Calling depth will look up other tuples in pairs. If the graph does not have any cycles the process will eventually
terminate.
Due to the way lazy evaluation works in Haskell, the calls to depth
are effectively memoized.
Related
I don't understand why we are increasing e += 1 when the parents are not same. And why the while loop stops based on e's value? Why we need that index?
def kruskal(self):
i, e = 0, 0
ds = dst.disjointSet(self.nodes)
self.graph = sorted(self.graph, key=lambda graph:graph[2])
while e < self.v - 1: # vertices start from zero thats why -1
s,d,w = self.graph[i]
i += 1
x = ds.findParent(s)
y = ds.findParent(d)
if x != y:
e += 1
self.MST.append([s,d,w])
ds.union(x, y)
self.printSolution()
ds is disjointSet's object where findParent and union methods are.
Variable e, I'd rather call it edges, represents a number of edges here. You may ask a question what is the mininum number of edges needed to connect n vertices? You can easily prove that's n - 1. So we iterate until we have a necessary number of edges to connect all vertices. We're checking parents x!=y to be sure there's no cycle.
Definition of H Index used in this algorithm
Supposing a relational expression is represented as y = F(x1, x2, . . . , xn), where F returns an integer number greater than 0, and the function is to find a maximum value y satisfying the condition that there exist at least y elements whose values are not less than y. Hence, the H-index of any node i is defined as
H(i) = F(kj1 ,kj2 ,...,k jki)
where kj1, kj2, . . . , kjki represent the set of degrees of neighboring nodes of node i.
Now I want to find the H Index of the nodes of the following graphs using the algorithm given below :
Graph :
Code (Written in Python and NetworkX) :
def hindex(g, n):
nd = {}
h = 0
# print(len(list(g.neighbors(n))))
for v in g.neighbors(n):
#nd[v] = len(list(g.neighbors(v)))
nd[v] = g.degree(v)
snd = sorted(nd.values(), reverse=True)
for i in range(0,len(snd)):
h = i
if snd[i] < i:
break
#print("H index of " + str(n)+ " : " + str(h))
return h
Problem :
This algorithm is returning the wrong values of nodes 1, 5, 8 and 9
Actual Values :
Node 1 - 6 : H Index = 2
Node 7 - 9 : H Index = 1
But for Node 1 and 5 I am getting 1, and for Node 8 and 9 I am getting 0.
Any leads on where I am going wrong will be highly appreciated!
Try this:
def hindex(g, n):
sorted_neighbor_degrees = sorted((g.degree(v) for v in g.neighbors(n)), reverse=True)
h = 0
for i in range(1, len(sorted_neighbor_degrees)+1):
if sorted_neighbor_degrees[i-1] < i:
break
h = i
return h
There's no need for a nested loop; just make a decreasing list, and calculate the h-index like normal.
The reason for 'i - 1' is just that our arrays are 0-indexed, while h-index is based on rankings (i.e. the k largest values) which are 1-indexed.
From the definition of h-index: For a non-increasing function f, h(f) is max i >= 0 such that f(i) >= i. This is, equivalently, the min i >= 1 such that f(i) < i, minus 1. Here, f(i) is equal to sorted_neighbor_degrees[i - 1]. There are of course many other ways (with different time and space requirements) to calculate h.
I have a file shows different points' coordinates(first 10 rows):
1 10.381090522139 55.39134945301
2 10.37928179195319 55.38858713256631
3 10.387152479898077 55.3923338690609
4 10.380048819655258 55.393938880906745
5 10.380679138517507 55.39459444742785
6 10.382474625286 55.392132993022
7 10.383736185130601 55.39454404088371
8 10.387334283235987 55.39433237195271
9 10.388468103023115 55.39536574771765
10 10.390814951258335 55.396308397998475
Now I want to calculate the MST(minimum spanning tree) of them so firstly I change my coordinates to weight graph(distance->weight):
n = 10
data = []
for i in range(0, n):
for j in range(i + 1, n):
temp = []
temp.append(i)
temp.append(j)
x = np.array(rawdata[i, 1:3])
y = np.array(rawdata[j, 1:3])
temp.append(np.linalg.norm(x - y))
data.append(temp)
Then, using networkx to load weight data:
G = nx.read_weighted_edgelist("data.txt")
T = nx.minimum_spanning_tree(G)
nx.draw(T)
plt.show()
but I cannot see the orignal shape from result:
how to solve this problem?
I'm just answering the question about the position of the nodes. I can't tell from what you've done whether the minimum spanning tree is what you're after or not.
When you plot a network, it will assign positions based on an algorithm that is in part stochastic. If you want the nodes to go at particular positions, you will have to include that information in the call in an optional argument. So define a dictionary (it's usually called pos) such that pos[node] is a tuple (x,y) where x is the x-coordinate of node and y is the y-coordinate of node.
Then the call is nx.draw(T, pos=pos).
I have an undirected graph, and I want to iteratively remove each serial edge and replace it with a new edge. The weight of the new edge represents the number of spanning trees, and should be computed as follows: T_new = (1/a+b) * T_old, where a and b are the weights of the removed edges, T_new is the number of spanning trees in current iteration and T_old is the number of spanning trees in the previous iteration. This equation changes iteratively, as the graph changes, so if we have 4 iterations we will have 4 equations, each one is in terms of the previous one. We stop once the graph has no more serial edges. If the final graph is composed of 1 edge, the weight of that edge is the last T_new, and we will have a numerical value of T-old. Otherwise, we should have T_old in terms of T_new. Here is an attached image explaining what I said in case it is not well explained.
Here is the part of my code describing the problem :
** PS : I only need the part where the equation changes in every iteration, not the things to do to remove and add new edges and so on.here is an example : **
import networkx as nx
def fun2(G) :
L1= G.degree()
print(L1)
L= list(L1)
for x in L :
if G.degree(x[0]) == 2 : #if the adjacent edges to x[0] are serial
... do somthing(remove edges and add new one with new weight)
#T-new = 1/(a+b) T-old here the equation should change
def tau(G) : # it should return T_old which is the number of spanning trees of the initial graph
if G.number_of_edges() == 1 :
T_new = list(G.edges(data=True))[0][2]['weight']
T_old = (a+b) * t_new
else :
T_new = 1/(a+b) * tau(G)
T_old = (a+b) * t_new
return t_old
No recursion is needed, as we change the graph as we go. Here's a solution:
import networkx as nx
G = nx.Graph()
G.add_weighted_edges_from([(0,1,5),(0,2,10),(2,3,30)])
for node in list(G.nodes()):
if G.degree(node) == 2:
neighbors = list(G.neighbors(node))
a = G.get_edge_data(neighbors[0], node)['weight']
b = G.get_edge_data(neighbors[1], node)['weight']
w = (a * b) / (a + b)
G.add_edge(neighbors[0], neighbors[1], weight=w)
G.remove_node(node)
I'm writing a program which randomly chooses two integers within a certain interval. I also wrote a class (which I didn't add below) which uses two numbers 'a' and 'b' and creates an elliptical curve of the form:
y^2 = x^3 + ax + b
I've written the following to create the two random numbers.
def numbers():
n = 1
while n>0:
a = random.randint(-100,100)
b = random.randint(-100,100)
if -16 * (4 * a ** 3 + 27 * b ** 2) != 0:
result = [a,b]
return result
n = n+1
Now I would like to generate a random point on this elliptical curve. How do I do that?
The curve has an infinite length, as for every y ϵ ℝ there is at least one x ϵ ℝ so that (x, y) is on the curve. So if we speak of a random point on the curve we cannot hope to have a homogeneous distribution of the random point over the whole curve.
But if that is not important, you could take a random value for y within some range, and then calculate the roots of the following function:
f(x) = x3 + ax + b - y2
This will result in three roots, of which possibly two are complex (not real numbers). You can take a random real root from that. This will be the x coordinate for the random point.
With the help of numpy, getting the roots is easy, so this is the function for getting a random point on the curve, given values for a and b:
def randomPoint(a, b):
y = random.randint(-100,100)
# Get roots of: f(x) = x^3 + ax + b - y^2
roots = numpy.roots([1, 0, a, b - y**2])
# 3 roots are returned, but ignore potential complex roots
# At least one will be real
roots = [val.real for val in roots if val.imag == 0]
# Choose a random root among those real root(s)
x = random.choice(roots)
return [x, y]
See it run on repl.it.