Skip to content

Commit f1a171d

Browse files
committed
More conversions and fixes
1 parent a6bf64f commit f1a171d

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

pymathics/graph/__main__.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
# uses networkx
1111

12+
from collections import defaultdict
1213
from inspect import isgenerator
1314

1415
from 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)

pymathics/graph/algorithms.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
networkx does all the heavy lifting.
66
"""
77

8+
from mathics.core.convert.expression import to_mathics_list
89
from mathics.core.convert.python import from_python
910
from mathics.core.expression import Expression
1011
from mathics.core.list import ListExpression
1112
from mathics.core.symbols import SymbolFalse
13+
from mathics.core.systemsymbols import SymbolDirectedInfinity
1214

1315
from pymathics.graph.__main__ import (
1416
DEFAULT_GRAPH_OPTIONS,
@@ -23,7 +25,7 @@
2325
class ConnectedComponents(_NetworkXBuiltin):
2426
"""
2527
>> g = Graph[{1 -> 2, 2 -> 3, 3 <-> 4}]; ConnectedComponents[g]
26-
= {{3, 4}, {2}, {1}}
28+
= {{4, 3}, {2}, {1}}
2729
2830
>> g = Graph[{1 -> 2, 2 -> 3, 3 -> 1}]; ConnectedComponents[g]
2931
= {{1, 2, 3}}
@@ -41,8 +43,8 @@ def apply(self, graph, expression, evaluation, options):
4143
if graph.G.is_directed()
4244
else nx.connected_components
4345
)
44-
components = [Expression("List", *c) for c in connect_fn(graph.G)]
45-
return Expression("List", *components)
46+
components = [to_mathics_list(*c) for c in connect_fn(graph.G)]
47+
return ListExpression(*components)
4648

4749

4850
# class FindHamiltonianPath(_NetworkXBuiltin):
@@ -61,7 +63,7 @@ def apply(self, graph, expression, evaluation, options):
6163
# path = nx.algorithms.tournament.hamiltonian_path(graph.G)
6264
# if path:
6365
# # int_path = map(Integer, path)
64-
# return Expression("List", *path)
66+
# return to_mathics_list(*path)
6567

6668

6769
class GraphDistance(_NetworkXBuiltin):
@@ -110,8 +112,8 @@ def apply_s(self, graph, s, expression, evaluation, options):
110112
if graph:
111113
weight = graph.update_weights(evaluation)
112114
d = nx.shortest_path_length(graph.G, source=s, weight=weight)
113-
inf = Expression("DirectedInfinity", 1)
114-
return Expression("List", *[d.get(v, inf) for v in graph.vertices])
115+
inf = Expression(SymbolDirectedInfinity, 1)
116+
return to_mathics_list(*[d.get(v, inf) for v in graph.vertices])
115117

116118
def apply_s_t(self, graph, s, t, expression, evaluation, options):
117119
"%(name)s[graph_, s_, t_, OptionsPattern[%(name)s]]"
@@ -130,7 +132,7 @@ def apply_s_t(self, graph, s, t, expression, evaluation, options):
130132
nx.shortest_path_length(graph.G, source=s, target=t, weight=weight)
131133
)
132134
except nx.exception.NetworkXNoPath:
133-
return Expression("DirectedInfinity", 1)
135+
return Expression(SymbolDirectedInfinity, 1)
134136

135137

136138
class FindSpanningTree(_NetworkXBuiltin):

0 commit comments

Comments
 (0)