Skip to content

Commit a32fc67

Browse files
committed
binomail_tree() supporting create_using ...
Also submitted as PR networkx/networkx#4461 This allows us to create trees with directed edges.
1 parent bc1c917 commit a32fc67

File tree

3 files changed

+76
-26
lines changed

3 files changed

+76
-26
lines changed

pymathics/graph/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ def _process_graph_options(g, options: dict) -> None:
100100
else ""
101101
)
102102

103-
g.G.graph_layout = g.graph_layout = WL_LAYOUT_TO_NETWORKX.get(g.graph_layout, g.graph_layout)
103+
g.G.graph_layout = g.graph_layout = WL_LAYOUT_TO_NETWORKX.get(
104+
g.graph_layout, g.graph_layout
105+
)
104106

105107
g.G.node_color = g.node_color = WL_COLOR_TO_NETWORKX.get(color, color)
106108

@@ -232,7 +234,7 @@ def _not_an_edge(self, expression, pos, evaluation):
232234

233235
def _build_graph(self, graph, evaluation, options, expr, quiet=False):
234236
head = graph.get_head_name()
235-
if head == "System`Graph" and isinstance(graph, Atom):
237+
if head == "System`Graph" and isinstance(graph, Atom) and hasattr(graph, "G"):
236238
return graph
237239
elif head == "System`List":
238240
return _graph_from_list(graph.leaves, options)

pymathics/graph/algorithms.py

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,47 @@
2222
# SymbolFalse = Symbol("System`False")
2323
# SymbolTrue = Symbol("System`True")
2424

25+
class ConnectedComponents(_NetworkXBuiltin):
26+
"""
27+
>> g = Graph[{1 -> 2, 2 -> 3, 3 <-> 4}]; ConnectedComponents[g]
28+
= {{3, 4}, {2}, {1}}
29+
30+
>> g = Graph[{1 -> 2, 2 -> 3, 3 -> 1}]; ConnectedComponents[g]
31+
= {{1, 2, 3}}
32+
33+
>> g = Graph[{1 <-> 2, 2 <-> 3, 3 -> 4, 4 <-> 5}]; ConnectedComponents[g]
34+
= {{4, 5}, {1, 2, 3}}
35+
"""
36+
37+
def apply(self, graph, expression, evaluation, options):
38+
"ConnectedComponents[graph_, OptionsPattern[%(name)s]]"
39+
graph = self._build_graph(graph, evaluation, options, expression)
40+
if graph:
41+
connect_fn = nx.strongly_connected_components if graph.G.is_directed() else nx.connected_components
42+
components = [
43+
Expression("List", *c) for c in connect_fn(graph.G)
44+
]
45+
return Expression("List", *components)
46+
47+
48+
# class FindHamiltonianPath(_NetworkXBuiltin):
49+
# """
50+
# <dl>
51+
# <dt>'FindHamiltonianPath[$g$]'
52+
# <dd>returns a Hamiltonian path in the given tournament graph.
53+
# </dl>
54+
# """
55+
# def apply_(self, graph, expression, evaluation, options):
56+
# "%(name)s[graph_, OptionsPattern[%(name)s]]"
57+
58+
# graph = self._build_graph(graph, evaluation, options, expression)
59+
# if graph:
60+
# # FIXME: for this to work we need to fill in all O(n^2) edges as an adjacency matrix?
61+
# path = nx.algorithms.tournament.hamiltonian_path(graph.G)
62+
# if path:
63+
# # int_path = map(Integer, path)
64+
# return Expression("List", *path)
65+
2566
class GraphDistance(_NetworkXBuiltin):
2667
"""
2768
<dl>
@@ -141,29 +182,6 @@ def apply(self, graph, expression, evaluation, options):
141182
is_planar, _ = nx.check_planarity(graph.G)
142183
return Symbol("System`True") if is_planar else Symbol("System`False")
143184

144-
class ConnectedComponents(_NetworkXBuiltin):
145-
"""
146-
>> g = Graph[{1 -> 2, 2 -> 3, 3 <-> 4}]; ConnectedComponents[g]
147-
= {{3, 4}, {2}, {1}}
148-
149-
>> g = Graph[{1 -> 2, 2 -> 3, 3 -> 1}]; ConnectedComponents[g]
150-
= {{1, 2, 3}}
151-
152-
>> g = Graph[{1 <-> 2, 2 <-> 3, 3 -> 4, 4 <-> 5}]; ConnectedComponents[g]
153-
= {{4, 5}, {1, 2, 3}}
154-
"""
155-
156-
def apply(self, graph, expression, evaluation, options):
157-
"ConnectedComponents[graph_, OptionsPattern[%(name)s]]"
158-
graph = self._build_graph(graph, evaluation, options, expression)
159-
if graph:
160-
connect_fn = nx.strongly_connected_components if graph.G.is_directed() else nx.connected_components
161-
components = [
162-
Expression("List", *c) for c in connect_fn(graph.G)
163-
]
164-
return Expression("List", *components)
165-
166-
167185
class WeaklyConnectedComponents(_NetworkXBuiltin):
168186
"""
169187
>> g = Graph[{1 -> 2, 2 -> 3, 3 <-> 4}]; WeaklyConnectedComponents[g]

pymathics/graph/generators.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
from mathics.builtin.randomnumbers import RandomEnv
9+
from mathics.core.expression import String
910

1011
from pymathics.graph.__main__ import (
1112
Graph,
@@ -141,6 +142,35 @@ def apply(self, m1, m2, expression, evaluation, options):
141142
return g
142143

143144

145+
# Oddly, networkX doesn't allow the directed case.
146+
def binomial_tree(n, create_using=None):
147+
"""Returns the Binomial Tree of order n.
148+
149+
The binomial tree of order 0 consists of a single vertex. A binomial tree of order k
150+
is defined recursively by linking two binomial trees of order k-1: the root of one is
151+
the leftmost child of the root of the other.
152+
153+
Parameters
154+
----------
155+
n : int
156+
Order of the binomial tree.
157+
158+
Returns
159+
-------
160+
G : NetworkX graph
161+
A binomial tree of $2^n$ vertices and $2^n - 1$ edges.
162+
163+
"""
164+
G = nx.empty_graph(1, create_using=create_using)
165+
N = 1
166+
for i in range(n):
167+
edges = [(u + N, v + N) for (u, v) in G.edges]
168+
G.add_edges_from(edges)
169+
G.add_edge(0, N)
170+
N *= 2
171+
return G
172+
173+
144174
class BinomialTree(_NetworkXBuiltin):
145175
"""
146176
<dl>
@@ -175,7 +205,7 @@ def apply(self, n, expression, evaluation, options):
175205
return
176206

177207
args = (py_n,)
178-
g = graph_helper(nx.binomial_tree, options, False, "tree", 0, *args)
208+
g = graph_helper(binomial_tree, options, True, "tree", 0, *args)
179209
if not g:
180210
return None
181211
g.G.n = n

0 commit comments

Comments
 (0)