99
1010# uses networkx
1111
12+ from collections import defaultdict
1213from inspect import isgenerator
1314
1415from mathics .builtin .base import AtomBuiltin , Builtin
@@ -463,6 +464,29 @@ def __str__(self):
463464 def atom_to_boxes (self , f , evaluation ) -> _BoxedString :
464465 return _BoxedString ("-Graph-" )
465466
467+ def coalesced_graph (self , evaluation ):
468+ if not isinstance (self .G , (nx .MultiDiGraph , nx .MultiGraph )):
469+ return self .G , "WEIGHT"
470+
471+ new_edges = defaultdict (lambda : 0 )
472+ for u , v , w in self .G .edges .data ("System`EdgeWeight" , default = None ):
473+ if w is not None :
474+ w = w .evaluate (evaluation ).to_mpmath ()
475+ else :
476+ w = 1
477+ new_edges [(u , v )] += w
478+
479+ if self .G .is_directed ():
480+ new_graph = nx .DiGraph ()
481+ else :
482+ new_graph = nx .Graph ()
483+
484+ new_graph .add_edges_from (
485+ ((u , v , {"WEIGHT" : w }) for (u , v ), w in new_edges .items ())
486+ )
487+
488+ return new_graph , "WEIGHT"
489+
466490 def default_format (self , evaluation , form ):
467491 return "-Graph-"
468492
@@ -514,6 +538,29 @@ def get_sort_key(self, pattern_sort=False) -> tuple:
514538 ]
515539 return hash (self )
516540
541+ def update_weights (self , evaluation ):
542+ weights = None
543+ G = self .G
544+
545+ if self .is_multigraph ():
546+ for u , v , k , w in G .edges .data (
547+ "System`EdgeWeight" , default = None , keys = True
548+ ):
549+ data = G .get_edge_data (u , v , key = k )
550+ w = data .get ()
551+ if w is not None :
552+ w = w .evaluate (evaluation ).to_mpmath ()
553+ G [u ][v ][k ]["WEIGHT" ] = w
554+ weights = "WEIGHT"
555+ else :
556+ for u , v , w in G .edges .data ("System`EdgeWeight" , default = None ):
557+ if w is not None :
558+ w = w .evaluate (evaluation ).to_mpmath ()
559+ G [u ][v ]["WEIGHT" ] = w
560+ weights = "WEIGHT"
561+
562+ return weights
563+
517564 @property
518565 def value (self ):
519566 return self .G
@@ -1578,7 +1625,7 @@ def apply(self, graph, expression, evaluation, options):
15781625 graph .G , normalized = False , weight = weight
15791626 )
15801627 return ListExpression (
1581- * [Real (centrality .get (v , 0.0 )) for v in graph .vertices . expressions ],
1628+ * [Real (centrality .get (v , 0.0 )) for v in graph .vertices ],
15821629 )
15831630
15841631
@@ -1601,7 +1648,7 @@ def apply(self, graph, expression, evaluation, options):
16011648 G = G .reverse ()
16021649 centrality = nx .closeness_centrality (G , distance = weight , wf_improved = False )
16031650 return ListExpression (
1604- * [Real (centrality .get (v , 0.0 )) for v in graph .vertices . expressions ],
1651+ * [Real (centrality .get (v , 0.0 )) for v in graph .vertices ],
16051652 )
16061653
16071654
@@ -1620,7 +1667,7 @@ class DegreeCentrality(_Centrality):
16201667 def _from_dict (self , graph , centrality ):
16211668 s = len (graph .G ) - 1 # undo networkx's normalization
16221669 return ListExpression (
1623- * [Integer (s * centrality .get (v , 0 )) for v in graph .vertices . expressions ],
1670+ * [Integer (s * centrality .get (v , 0 )) for v in graph .vertices ],
16241671 )
16251672
16261673 def apply (self , graph , expression , evaluation , options ):
@@ -1647,7 +1694,7 @@ def _centrality(self, g, weight):
16471694 raise NotImplementedError
16481695
16491696 def _compute (self , graph , evaluation , reverse = False , normalized = True , ** kwargs ):
1650- vertices = graph .vertices . expressions
1697+ vertices = graph .vertices
16511698 G , weight = graph .coalesced_graph (evaluation )
16521699 if reverse :
16531700 G = G .reverse ()
@@ -1758,7 +1805,7 @@ def apply_alpha_beta(self, graph, alpha, expression, evaluation, options):
17581805 G , weight = graph .coalesced_graph (evaluation )
17591806 centrality = nx .pagerank (G , alpha = py_alpha , weight = weight , tol = 1.0e-7 )
17601807 return ListExpression (
1761- * [Real (centrality .get (v , 0 )) for v in graph .vertices . expressions ],
1808+ * [Real (centrality .get (v , 0 )) for v in graph .vertices ],
17621809 )
17631810
17641811
@@ -1781,7 +1828,7 @@ def apply(self, graph, expression, evaluation, options):
17811828 def _crop (x ):
17821829 return 0 if x < tol else x
17831830
1784- vertices = graph .vertices . expressions
1831+ vertices = graph .vertices
17851832 return ListExpression (
17861833 ListExpression (* [Real (_crop (a .get (v , 0 ))) for v in vertices ]),
17871834 ListExpression (* [Real (_crop (h .get (v , 0 ))) for v in vertices ]),
@@ -1903,7 +1950,7 @@ def apply(self, graph, what, expression, evaluation, options):
19031950 head_name = what .get_head_name ()
19041951 if head_name in pattern_objects :
19051952 cases = Expression (
1906- SymbolCases , ListExpression (* graph .vertices . expressions ), what
1953+ SymbolCases , ListExpression (* graph .vertices ), what
19071954 ).evaluate (evaluation )
19081955 if cases .get_head_name () == "System`List" :
19091956 return graph .delete_vertices (cases .elements )
@@ -1959,7 +2006,7 @@ def apply(self, graph, what, expression, evaluation, options):
19592006 head_name = what .get_head_name ()
19602007 if head_name in pattern_objects :
19612008 cases = Expression (
1962- SymbolCases , ListExpression (* graph .edges . expressions ), what
2009+ SymbolCases , ListExpression (* graph .edges ), what
19632010 ).evaluate (evaluation )
19642011 if cases .get_head_name () == "System`List" :
19652012 return graph .delete_edges (cases .elements )
0 commit comments