computation-graph 67__tar.gz → 68__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {computation_graph-67 → computation_graph-68}/PKG-INFO +1 -1
- computation_graph-68/computation_graph/composers/duplication.py +154 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/graph.py +40 -1
- {computation_graph-67 → computation_graph-68}/computation_graph/graph_test.py +27 -0
- {computation_graph-67 → computation_graph-68}/computation_graph.egg-info/PKG-INFO +1 -1
- {computation_graph-67 → computation_graph-68}/setup.py +1 -1
- computation_graph-67/computation_graph/composers/duplication.py +0 -124
- {computation_graph-67 → computation_graph-68}/LICENSE.md +0 -0
- {computation_graph-67 → computation_graph-68}/README.md +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/__init__.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/base_types.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/__init__.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/composers_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/condition.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/condition_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/debug.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/lift.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/lift_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/logic.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/memory.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/composers/memory_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/graph_runners.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/infer_sink.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/infer_sink_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/legacy.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/run.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/signature.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/__init__.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/ascii.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/graphviz.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/graphviz_test.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/mermaid.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph/trace/trace_utils.py +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph.egg-info/SOURCES.txt +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph.egg-info/dependency_links.txt +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph.egg-info/requires.txt +0 -0
- {computation_graph-67 → computation_graph-68}/computation_graph.egg-info/top_level.txt +0 -0
- {computation_graph-67 → computation_graph-68}/pyproject.toml +0 -0
- {computation_graph-67 → computation_graph-68}/setup.cfg +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import dataclasses
|
|
3
|
+
import functools
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
import gamla
|
|
7
|
+
|
|
8
|
+
from computation_graph import base_types, graph
|
|
9
|
+
from computation_graph.composers import debug
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def duplicate_function(func):
|
|
13
|
+
if asyncio.iscoroutinefunction(func):
|
|
14
|
+
|
|
15
|
+
@functools.wraps(func)
|
|
16
|
+
async def inner(*args, **kwargs):
|
|
17
|
+
return await func(*args, **kwargs)
|
|
18
|
+
|
|
19
|
+
else:
|
|
20
|
+
|
|
21
|
+
@functools.wraps(func)
|
|
22
|
+
def inner(*args, **kwargs):
|
|
23
|
+
return func(*args, **kwargs)
|
|
24
|
+
|
|
25
|
+
return debug.name_callable(inner, f"duplicate of {func.__name__}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _duplicate_computation_edge(get_duplicated_node):
|
|
29
|
+
return gamla.compose_left(
|
|
30
|
+
gamla.dataclass_transform("source", get_duplicated_node),
|
|
31
|
+
gamla.dataclass_transform("destination", get_duplicated_node),
|
|
32
|
+
gamla.dataclass_transform(
|
|
33
|
+
"args", gamla.compose_left(gamla.map(get_duplicated_node), tuple)
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _signature_is_empty(signature: base_types.NodeSignature) -> bool:
|
|
39
|
+
return not (
|
|
40
|
+
signature.kwargs
|
|
41
|
+
or signature.optional_kwargs
|
|
42
|
+
or signature.is_args
|
|
43
|
+
or signature.is_kwargs
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _duplicate_node(node: base_types.ComputationNode) -> base_types.ComputationNode:
|
|
48
|
+
if _signature_is_empty(node.signature):
|
|
49
|
+
return node
|
|
50
|
+
inner = duplicate_function(node.func)
|
|
51
|
+
return dataclasses.replace(node, name=inner.__name__, func=inner)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _node_to_duplicated_node(nodes):
|
|
55
|
+
return {node: _duplicate_node(node) for node in nodes if not node.is_terminal}.get
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def duplicate_graph(original: base_types.GraphType) -> base_types.GraphType:
|
|
59
|
+
|
|
60
|
+
_node_to_duplicated_node_index = gamla.pipe(
|
|
61
|
+
original.edges, graph.get_all_nodes, _node_to_duplicated_node
|
|
62
|
+
)
|
|
63
|
+
get_duplicated_node = gamla.when(
|
|
64
|
+
_node_to_duplicated_node_index, _node_to_duplicated_node_index
|
|
65
|
+
)
|
|
66
|
+
return base_types.GraphType(
|
|
67
|
+
edges=gamla.pipe(
|
|
68
|
+
original.edges,
|
|
69
|
+
gamla.map(
|
|
70
|
+
_duplicate_computation_edge(
|
|
71
|
+
gamla.when(get_duplicated_node, get_duplicated_node)
|
|
72
|
+
)
|
|
73
|
+
),
|
|
74
|
+
frozenset,
|
|
75
|
+
),
|
|
76
|
+
sink=get_duplicated_node(original.sink),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
duplicate_function_or_graph = gamla.ternary(
|
|
81
|
+
gamla.is_instance(base_types.GraphType), duplicate_graph, duplicate_function
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def safe_replace_sources(
|
|
86
|
+
source_to_replacement_dict: Dict[
|
|
87
|
+
base_types.CallableOrNode, base_types.CallableOrNodeOrGraph
|
|
88
|
+
],
|
|
89
|
+
cg: base_types.GraphType,
|
|
90
|
+
) -> base_types.GraphType:
|
|
91
|
+
if not len(source_to_replacement_dict):
|
|
92
|
+
return cg
|
|
93
|
+
|
|
94
|
+
source_to_replacement_dict = gamla.pipe(
|
|
95
|
+
source_to_replacement_dict,
|
|
96
|
+
gamla.keymap(graph.make_computation_node),
|
|
97
|
+
gamla.valmap(
|
|
98
|
+
gamla.unless(
|
|
99
|
+
gamla.is_instance(base_types.GraphType), graph.make_computation_node
|
|
100
|
+
)
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
get_duplicate = gamla.pipe(
|
|
104
|
+
gamla.graph_traverse_many(
|
|
105
|
+
source_to_replacement_dict.keys(), graph.traverse_forward(cg.edges)
|
|
106
|
+
),
|
|
107
|
+
gamla.remove(gamla.contains(source_to_replacement_dict.keys())),
|
|
108
|
+
_node_to_duplicated_node,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def node_replacement(node):
|
|
112
|
+
replacement = source_to_replacement_dict.get(node)
|
|
113
|
+
if replacement is not None:
|
|
114
|
+
return replacement
|
|
115
|
+
duplicate = get_duplicate(node)
|
|
116
|
+
return duplicate if duplicate is not None else node
|
|
117
|
+
|
|
118
|
+
replacement_graphs_edges = {}
|
|
119
|
+
|
|
120
|
+
def source_replacement(node):
|
|
121
|
+
replacement = node_replacement(node)
|
|
122
|
+
if isinstance(replacement, base_types.GraphType):
|
|
123
|
+
replacement_graphs_edges[id(replacement)] = replacement.edges
|
|
124
|
+
return replacement.sink
|
|
125
|
+
return replacement
|
|
126
|
+
|
|
127
|
+
new_edges = []
|
|
128
|
+
for edge in cg.edges:
|
|
129
|
+
destination = node_replacement(edge.destination)
|
|
130
|
+
if edge.args:
|
|
131
|
+
args = tuple(source_replacement(arg) for arg in edge.args)
|
|
132
|
+
if destination is edge.destination and all(
|
|
133
|
+
new is old for new, old in zip(args, edge.args)
|
|
134
|
+
):
|
|
135
|
+
new_edges.append(edge)
|
|
136
|
+
else:
|
|
137
|
+
new_edges.append(
|
|
138
|
+
dataclasses.replace(edge, args=args, destination=destination)
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
source = source_replacement(edge.source)
|
|
142
|
+
if source is edge.source and destination is edge.destination:
|
|
143
|
+
new_edges.append(edge)
|
|
144
|
+
else:
|
|
145
|
+
new_edges.append(
|
|
146
|
+
dataclasses.replace(edge, source=source, destination=destination)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return base_types.GraphType(
|
|
150
|
+
edges=base_types.merge_edges(
|
|
151
|
+
frozenset(new_edges), *replacement_graphs_edges.values()
|
|
152
|
+
),
|
|
153
|
+
sink=node_replacement(cg.sink),
|
|
154
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import functools
|
|
3
|
-
from typing import Callable, FrozenSet, Optional, Tuple
|
|
3
|
+
from typing import Callable, Dict, FrozenSet, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
import gamla
|
|
6
6
|
from gamla.optimized import sync as opt_gamla
|
|
@@ -231,6 +231,45 @@ def replace_node(
|
|
|
231
231
|
)
|
|
232
232
|
|
|
233
233
|
|
|
234
|
+
def replace_nodes(
|
|
235
|
+
node_map: Dict[base_types.ComputationNode, base_types.ComputationNode]
|
|
236
|
+
) -> Callable[[base_types.GraphType], base_types.GraphType]:
|
|
237
|
+
"""Replace many nodes at once (sources, destinations and sink) in a single pass."""
|
|
238
|
+
|
|
239
|
+
def replace_nodes(g: base_types.GraphType) -> base_types.GraphType:
|
|
240
|
+
if not node_map:
|
|
241
|
+
return g
|
|
242
|
+
new_edges = []
|
|
243
|
+
for edge in g.edges:
|
|
244
|
+
destination = node_map.get(edge.destination, edge.destination)
|
|
245
|
+
if edge.args:
|
|
246
|
+
args = tuple(node_map.get(arg, arg) for arg in edge.args)
|
|
247
|
+
if destination is edge.destination and all(
|
|
248
|
+
new is old for new, old in zip(args, edge.args)
|
|
249
|
+
):
|
|
250
|
+
new_edges.append(edge)
|
|
251
|
+
else:
|
|
252
|
+
new_edges.append(
|
|
253
|
+
dataclasses.replace(edge, args=args, destination=destination)
|
|
254
|
+
)
|
|
255
|
+
else:
|
|
256
|
+
assert edge.source is not None
|
|
257
|
+
source = node_map.get(edge.source, edge.source)
|
|
258
|
+
if source is edge.source and destination is edge.destination:
|
|
259
|
+
new_edges.append(edge)
|
|
260
|
+
else:
|
|
261
|
+
new_edges.append(
|
|
262
|
+
dataclasses.replace(
|
|
263
|
+
edge, source=source, destination=destination
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
return base_types.GraphType(
|
|
267
|
+
edges=frozenset(new_edges), sink=node_map.get(g.sink, g.sink)
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
return replace_nodes
|
|
271
|
+
|
|
272
|
+
|
|
234
273
|
def transform_edges(
|
|
235
274
|
query: Callable[[base_types.ComputationEdge], bool],
|
|
236
275
|
edge_mapper: Callable[[base_types.ComputationEdge], base_types.ComputationEdge],
|
|
@@ -1000,6 +1000,33 @@ def test_replace_node():
|
|
|
1000
1000
|
)
|
|
1001
1001
|
|
|
1002
1002
|
|
|
1003
|
+
@pytest.mark.parametrize(
|
|
1004
|
+
"node_map",
|
|
1005
|
+
[
|
|
1006
|
+
pytest.param({}, id="empty map is a no-op"),
|
|
1007
|
+
pytest.param({_node1: _node1_async}, id="single node"),
|
|
1008
|
+
pytest.param({_node1: _node1_async, _node2: _next_int}, id="multiple nodes"),
|
|
1009
|
+
pytest.param({(lambda x: x): _node1_async}, id="node not in graph is a no-op"),
|
|
1010
|
+
],
|
|
1011
|
+
)
|
|
1012
|
+
def test_replace_nodes(node_map: Dict):
|
|
1013
|
+
a = graph.make_source()
|
|
1014
|
+
g = graph.merge_graphs(
|
|
1015
|
+
composers.compose_source_unary(_node1, a),
|
|
1016
|
+
composers.compose_left_unary(_node1, _node2),
|
|
1017
|
+
sink_node_or_graph=graph.make_computation_node(_node2),
|
|
1018
|
+
)
|
|
1019
|
+
node_map = gamla.pipe(
|
|
1020
|
+
node_map,
|
|
1021
|
+
gamla.keymap(graph.make_computation_node),
|
|
1022
|
+
gamla.valmap(graph.make_computation_node),
|
|
1023
|
+
)
|
|
1024
|
+
expected = g
|
|
1025
|
+
for original, replacement in node_map.items():
|
|
1026
|
+
expected = graph.replace_node(original, replacement)(expected)
|
|
1027
|
+
assert graph.replace_nodes(node_map)(g) == expected
|
|
1028
|
+
|
|
1029
|
+
|
|
1003
1030
|
def test_ambig_edges_assertion_in_merge_graphs_active_only_when_env_var_is_active(
|
|
1004
1031
|
monkeypatch,
|
|
1005
1032
|
):
|
|
@@ -7,7 +7,7 @@ with open("README.md", "r") as fh:
|
|
|
7
7
|
setuptools.setup(
|
|
8
8
|
name="computation-graph",
|
|
9
9
|
python_requires=">=3",
|
|
10
|
-
version="
|
|
10
|
+
version="68",
|
|
11
11
|
long_description=_LONG_DESCRIPTION,
|
|
12
12
|
long_description_content_type="text/markdown",
|
|
13
13
|
packages=setuptools.find_namespace_packages(),
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import functools
|
|
3
|
-
import inspect
|
|
4
|
-
from typing import Dict
|
|
5
|
-
|
|
6
|
-
import gamla
|
|
7
|
-
|
|
8
|
-
from computation_graph import base_types, graph
|
|
9
|
-
from computation_graph.composers import debug
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def duplicate_function(func):
|
|
13
|
-
if asyncio.iscoroutinefunction(func):
|
|
14
|
-
|
|
15
|
-
@functools.wraps(func)
|
|
16
|
-
async def inner(*args, **kwargs):
|
|
17
|
-
return await func(*args, **kwargs)
|
|
18
|
-
|
|
19
|
-
else:
|
|
20
|
-
|
|
21
|
-
@functools.wraps(func)
|
|
22
|
-
def inner(*args, **kwargs):
|
|
23
|
-
return func(*args, **kwargs)
|
|
24
|
-
|
|
25
|
-
return debug.name_callable(inner, f"duplicate of {func.__name__}")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _duplicate_computation_edge(get_duplicated_node):
|
|
29
|
-
return gamla.compose_left(
|
|
30
|
-
gamla.dataclass_transform("source", get_duplicated_node),
|
|
31
|
-
gamla.dataclass_transform("destination", get_duplicated_node),
|
|
32
|
-
gamla.dataclass_transform(
|
|
33
|
-
"args", gamla.compose_left(gamla.map(get_duplicated_node), tuple)
|
|
34
|
-
),
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
_duplicate_node = gamla.compose_left(
|
|
39
|
-
base_types.node_implementation,
|
|
40
|
-
gamla.when(
|
|
41
|
-
gamla.compose_left(inspect.signature, gamla.attrgetter("parameters"), len),
|
|
42
|
-
duplicate_function,
|
|
43
|
-
),
|
|
44
|
-
graph.make_computation_node,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
duplicate_node = _duplicate_node
|
|
48
|
-
|
|
49
|
-
_node_to_duplicated_node = gamla.compose_left(
|
|
50
|
-
gamla.remove(base_types.node_is_terminal),
|
|
51
|
-
gamla.map(gamla.pair_right(_duplicate_node)),
|
|
52
|
-
dict,
|
|
53
|
-
gamla.dict_to_getter_with_default(None),
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def duplicate_graph(original: base_types.GraphType) -> base_types.GraphType:
|
|
58
|
-
|
|
59
|
-
_node_to_duplicated_node_index = gamla.pipe(
|
|
60
|
-
original.edges, graph.get_all_nodes, _node_to_duplicated_node
|
|
61
|
-
)
|
|
62
|
-
get_duplicated_node = gamla.when(
|
|
63
|
-
_node_to_duplicated_node_index, _node_to_duplicated_node_index
|
|
64
|
-
)
|
|
65
|
-
return base_types.GraphType(
|
|
66
|
-
edges=gamla.pipe(
|
|
67
|
-
original.edges,
|
|
68
|
-
gamla.map(
|
|
69
|
-
_duplicate_computation_edge(
|
|
70
|
-
gamla.when(get_duplicated_node, get_duplicated_node)
|
|
71
|
-
)
|
|
72
|
-
),
|
|
73
|
-
frozenset,
|
|
74
|
-
),
|
|
75
|
-
sink=get_duplicated_node(original.sink),
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
duplicate_function_or_graph = gamla.ternary(
|
|
80
|
-
gamla.is_instance(base_types.GraphType), duplicate_graph, duplicate_function
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def safe_replace_sources(
|
|
85
|
-
source_to_replacement_dict: Dict[
|
|
86
|
-
base_types.CallableOrNode, base_types.CallableOrNodeOrGraph
|
|
87
|
-
],
|
|
88
|
-
cg: base_types.GraphType,
|
|
89
|
-
) -> base_types.GraphType:
|
|
90
|
-
if not len(source_to_replacement_dict):
|
|
91
|
-
return cg
|
|
92
|
-
|
|
93
|
-
source_to_replacement_dict = gamla.keymap(graph.make_computation_node)(
|
|
94
|
-
source_to_replacement_dict
|
|
95
|
-
)
|
|
96
|
-
reachable_to_duplicate_map = gamla.pipe(
|
|
97
|
-
gamla.graph_traverse_many(
|
|
98
|
-
source_to_replacement_dict.keys(), graph.traverse_forward(cg.edges)
|
|
99
|
-
),
|
|
100
|
-
gamla.remove(gamla.contains(source_to_replacement_dict.keys())),
|
|
101
|
-
_node_to_duplicated_node,
|
|
102
|
-
)
|
|
103
|
-
get_node_replacement = gamla.compose_left(
|
|
104
|
-
gamla.lazyjuxt(
|
|
105
|
-
gamla.dict_to_getter_with_default(None)(source_to_replacement_dict),
|
|
106
|
-
reachable_to_duplicate_map,
|
|
107
|
-
gamla.identity,
|
|
108
|
-
),
|
|
109
|
-
gamla.find(gamla.identity),
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
def update_edge(e: base_types.ComputationEdge) -> base_types.GraphType:
|
|
113
|
-
dest = base_types.edge_destination(e)
|
|
114
|
-
g = graph.replace_node(dest, get_node_replacement(dest))(
|
|
115
|
-
base_types.GraphType(edges=frozenset((e,)), sink=dest)
|
|
116
|
-
)
|
|
117
|
-
for source in base_types.edge_sources(e):
|
|
118
|
-
g = graph.replace_source(source, get_node_replacement(source), g)
|
|
119
|
-
return g
|
|
120
|
-
|
|
121
|
-
return base_types.GraphType(
|
|
122
|
-
edges=frozenset(edge for e in cg.edges for edge in update_edge(e).edges),
|
|
123
|
-
sink=get_node_replacement(cg.sink),
|
|
124
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{computation_graph-67 → computation_graph-68}/computation_graph.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|