Skip to content

Commit 6faf955

Browse files
authored
Merge pull request #22 from Mathics3/go-over-parameter-graph-docs+type-check
Make a pass over parametric graph section..
2 parents d3780b2 + b1cf2f3 commit 6faf955

File tree

7 files changed

+248
-186
lines changed

7 files changed

+248
-186
lines changed

pymathics/graph/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
AdjacencyList,
4242
DirectedEdge,
4343
EdgeConnectivity,
44+
EdgeDelete,
4445
EdgeIndex,
4546
EdgeList,
4647
EdgeRules,
@@ -60,7 +61,7 @@
6061
VertexList,
6162
)
6263

63-
from pymathics.graph.centralities import(
64+
from pymathics.graph.centralities import (
6465
BetweennessCentrality,
6566
ClosenessCentrality,
6667
DegreeCentrality,
@@ -86,7 +87,6 @@
8687
CompleteGraph,
8788
CompleteKaryTree,
8889
CycleGraph,
89-
FullRAryTree,
9090
GraphAtlas,
9191
HknHararyGraph,
9292
HmnHararyGraph,
@@ -137,14 +137,14 @@
137137
"DirectedGraphQ",
138138
"EdgeConnectivity",
139139
"EdgeCount",
140+
"EdgeDelete",
140141
"EdgeIndex",
141142
"EdgeList",
142143
"EdgeRules",
143144
"EigenvectorCentrality",
144145
"FindShortestPath",
145146
"FindSpanningTree",
146147
"FindVertexCut",
147-
"FullRAryTree",
148148
"Graph",
149149
"GraphAtlas",
150150
"GraphAtom",

pymathics/graph/base.py

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
from collections import defaultdict
1010
from inspect import isgenerator
11-
from typing import Callable, Optional
11+
from typing import Callable, Optional, Union
1212

1313
from mathics.builtin.base import AtomBuiltin, Builtin
1414
from mathics.core.atoms import Atom, Integer, Integer0, Integer1, Integer2, String
15-
from mathics.core.convert.expression import ListExpression, from_python
15+
from mathics.core.convert.expression import ListExpression, from_python, to_mathics_list
1616
from mathics.core.element import BaseElement
1717
from mathics.core.expression import Expression
1818
from mathics.core.symbols import Symbol, SymbolList, SymbolTrue
@@ -86,7 +86,18 @@ def graph_helper(
8686
root: Optional[int] = None,
8787
*args,
8888
**kwargs,
89-
) -> Optional[Callable]:
89+
) -> Optional["Graph"]:
90+
"""
91+
This is a wrapping function for a NetworkX function of some sort indicated in ``graph_generator``,
92+
e.g. ``nx.complete_graph``.
93+
94+
``args`` and ``kwargs`` are passed to the NetworkX function, while ``can_digraph`` determines
95+
whether ``create_using=nx.DiGraph``is added to the NetworkX graph-generation function call.
96+
97+
Parameter ``options`` and ``graph_layout`` are Mathics3 Graph
98+
options; ``graph_layout`` has a ``String()`` wrapped around it
99+
``root`` is used when the graph is a tree.
100+
"""
90101
should_digraph = can_digraph and has_directed_option(options)
91102
try:
92103
G = (
@@ -97,7 +108,11 @@ def graph_helper(
97108
except MemoryError:
98109
evaluation.message("Graph", "mem", evaluation)
99110
return None
100-
if graph_layout and not options["System`GraphLayout"].get_string_value():
111+
if (
112+
graph_layout and not options["System`GraphLayout"].get_string_value()
113+
if "System`GraphLayout" in options
114+
else False
115+
):
101116
options["System`GraphLayout"] = String(graph_layout)
102117

103118
g = Graph(G)
@@ -279,7 +294,14 @@ def _not_a_vertex(self, expression, pos, evaluation):
279294
def _not_an_edge(self, expression, pos, evaluation):
280295
evaluation.message(self.get_name(), "inv", "edge", pos, expression)
281296

282-
def _build_graph(self, graph, evaluation, options, expr, quiet=False):
297+
def _build_graph(
298+
self,
299+
graph: Union["Graph", Expression],
300+
evaluation,
301+
options: dict,
302+
expr,
303+
quiet=False,
304+
) -> Optional["Graph"]:
283305
head = graph.get_head()
284306
if head is SymbolGraph and isinstance(graph, Atom) and hasattr(graph, "G"):
285307
return graph
@@ -380,6 +402,16 @@ def __init__(self, Gr, **kwargs):
380402
self.G = Gr
381403
self.mixed = kwargs.get("mixed", False)
382404

405+
# Here we define types that appear on some, but not all
406+
# graphs. So these are optional, which we given an initial
407+
# value of None
408+
409+
# Some graphs has a second int parameter like HknHarary
410+
self.n: Optional[int] = None
411+
412+
# Trees have a root
413+
self.root: Optional[int] = None
414+
383415
def __hash__(self):
384416
return hash(("Pymathics`Graph", self.G))
385417

@@ -424,14 +456,13 @@ def coalesced_graph(self, evaluation):
424456

425457
return new_graph, "WEIGHT"
426458

427-
def delete_edges(self, edges_to_delete):
459+
def delete_edges(self, edges_to_delete) -> "Graph":
428460
G = self.G.copy()
429461
directed = G.is_directed()
430462

431-
edges_to_delete = list(_normalize_edges(edges_to_delete))
432-
edges_to_delete = self.edges.filter(edges_to_delete)
463+
normalized_edges_to_delete = list(_normalize_edges(edges_to_delete))
433464

434-
for edge in edges_to_delete:
465+
for edge in normalized_edges_to_delete:
435466
if edge.has_form("DirectedEdge", 2):
436467
if directed:
437468
u, v = edge.elements
@@ -444,12 +475,7 @@ def delete_edges(self, edges_to_delete):
444475
else:
445476
G.remove_edge(u, v)
446477

447-
edges = self.edges.clone()
448-
edges.delete(edges_to_delete)
449-
450-
return Graph(
451-
self.vertices, edges, G, self.layout, self.options, self.highlights
452-
)
478+
return Graph(G)
453479

454480
def delete_vertices(self, vertices_to_delete):
455481
G = self.G.copy()
@@ -800,8 +826,7 @@ class AdjacencyList(_NetworkXBuiltin):
800826
:Adjacency list:
801827
https://en.wikipedia.org/wiki/Adjacency_list</url> (<url>
802828
:NetworkX:
803-
https://networkx.org/documentation/networkx-2.8.8/reference/readwrite/adjlist.html</url>,
804-
<url>
829+
https://networkx.org/documentation/networkx-2.8.8/reference/readwrite/adjlist.html</url>, <url>
805830
:WMA:
806831
https://reference.wolfram.com/language/ref/AdjacencyList.html</url>)
807832
@@ -1401,8 +1426,8 @@ class VertexDelete(_NetworkXBuiltin):
14011426

14021427
summary_text = "remove a vertex"
14031428

1404-
def eval(self, graph, what, expression, evaluation, options):
1405-
"%(name)s[graph_, what_, OptionsPattern[%(name)s]]"
1429+
def eval(self, graph, what, expression, evaluation, options) -> Optional[Graph]:
1430+
"VertexDelete[graph_, what_, OptionsPattern[VertexDelete]]"
14061431
graph = self._build_graph(graph, evaluation, options, expression)
14071432
if graph:
14081433
from mathics.builtin import pattern_objects
@@ -1516,41 +1541,46 @@ class UndirectedEdge(Builtin):
15161541
# return mathics_graph.add_edges(*zip(*[_parse_item(what)]))
15171542

15181543

1519-
# class EdgeDelete(_NetworkXBuiltin):
1520-
# """
1521-
# >> Length[EdgeList[EdgeDelete[{a -> b, b -> c, c -> d}, b -> c]]]
1522-
# = 2
1544+
class EdgeDelete(_NetworkXBuiltin):
1545+
"""
1546+
<url>
1547+
:WMA:
1548+
https://reference.wolfram.com/language/ref/EdgeDelete.html</url>
15231549
1524-
# >> Length[EdgeList[EdgeDelete[{a -> b, b -> c, c -> b, c -> d}, b <-> c]]]
1525-
# = 4
1550+
<dl>
1551+
<dt>'EdgeDelete'[$g$, $edge$]
1552+
<dd>remove the edge $edge$.
1553+
</dl>
15261554
1527-
# >> Length[EdgeList[EdgeDelete[{a -> b, b <-> c, c -> d}, b -> c]]]
1528-
# = 3
1555+
>> g = Graph[{1 -> 2, 2 -> 3, 3 -> 1}, VertexLabels->True]
1556+
= -Graph-
15291557
1530-
# >> Length[EdgeList[EdgeDelete[{a -> b, b <-> c, c -> d}, c -> b]]]
1531-
# = 3
1558+
>> EdgeList[EdgeDelete[g, 2 -> 3]]
1559+
= {{1, 2}, {3, 1}}
15321560
1533-
# >> Length[EdgeList[EdgeDelete[{a -> b, b <-> c, c -> d}, b <-> c]]]
1534-
# = 2
1561+
## >> g = Graph[{4<->5,5<->7,7<->9,9<->5,2->4,4->6,6->2}, VertexLabels->True]
1562+
## = -Graph-
15351563
1536-
# >> EdgeDelete[{4<->5,5<->7,7<->9,9<->5,2->4,4->6,6->2}, _UndirectedEdge]
1537-
# = -Graph-
1538-
# """
1564+
## >> EdgeDelete[g, _UndirectedEdge]
1565+
## = -Graph-
1566+
"""
15391567

1540-
# def eval(self, graph, what, expression, evaluation, options):
1541-
# "%(name)s[graph_, what_, OptionsPattern[%(name)s]]"
1542-
# graph = self._build_graph(graph, evaluation, options, expression)
1543-
# if graph:
1544-
# from mathics.builtin import pattern_objects
1545-
1546-
# head_name = what.get_head_name()
1547-
# if head_name in pattern_objects:
1548-
# cases = Expression(
1549-
# SymbolCases, ListExpression(*graph.edges), what
1550-
# ).evaluate(evaluation)
1551-
# if cases.get_head_name() == "System`List":
1552-
# return graph.delete_edges(cases.elements)
1553-
# elif head_name == "System`List":
1554-
# return graph.delete_edges(what.elements)
1555-
# else:
1556-
# return graph.delete_edges([what])
1568+
summary_text = "remove an edge"
1569+
1570+
def eval(self, graph, what, expression, evaluation, options) -> Optional[Graph]:
1571+
"EdgeDelete[graph_, what_, OptionsPattern[EdgeDelete]]"
1572+
graph = self._build_graph(graph, evaluation, options, expression)
1573+
if graph:
1574+
from mathics.builtin import pattern_objects
1575+
1576+
head_name = what.get_head_name()
1577+
if head_name in pattern_objects:
1578+
cases = Expression(
1579+
SymbolCases, to_mathics_list(*graph.edges), what
1580+
).evaluate(evaluation)
1581+
if cases.get_head_name() == "System`List":
1582+
return graph.delete_edges(cases.elements)
1583+
elif head_name == "System`List":
1584+
return graph.delete_edges(what.elements)
1585+
else:
1586+
return graph.delete_edges([what])

pymathics/graph/eval/parametric.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def eval_full_rary_tree(
3636
self, r: Integer, n: Integer, expression, evaluation: Evaluation, options: dict
3737
) -> Optional[Graph]:
3838
"""
39-
Call networkx to get a full_raray_tree using parameters, ``r`` and ``t``.
39+
Call ``networkx.full_rary_tree()`` using parameters, ``r`` and ``t``.
4040
"""
4141
py_r = r.value
4242

@@ -80,5 +80,4 @@ def eval_hkn_harary(
8080
if not g:
8181
return None
8282
g.k = py_k
83-
g.n = py_n
8483
return g

0 commit comments

Comments
 (0)