Package: lazy-graph
The lazy-graph is a Python library designed to facilitate lazy evaluation,
offering additional functionality for updating upstream values
and allowing easy duplication of the entire lazy graph structure.InstallPlease either copy or create a soft link for the directory in thesite-packagesdirectory.
Alternatively, you can utilize pip to install the lazy-graph package by running the commandpip install lazy_graph.DocumentsA simple exampleWe can create a root nodeawith the value1and another root nodebwith the value2,
followed by creating a new node calledc, where its value is equal to the sum of the values of nodesaandb.
The function for adding these nodes will be triggered whenever we attempt to retrieve the value of nodec.from lazy import Root, Node


def add(a, b):
    print(f"calculating {a} + {b}")
    return a + b


print("create nodes")
a = Root(1)
b = Root(2)
c = Node(add, a, b)
print("get the value")
print(f"c is {c()}")

create nodes
get the value
calculating 1 + 2
c is 3As demonstrated earlier, to create a root node containing the value ofx, we use the expressionRoot(x).
On the other hand, to obtain a node with its value determined by the functionfuncalong with any additional arguments or keyword arguments (if provided),
you would callNode(func, *args, **kwargs).
This will generate a node whose value is computed asfunc(*args, **kwargs).To obtain the value of a given noden, simply use the functionn().
This calculates the value for the initial run and then utilizes caching for subsequent calls, ensuring efficiency in your code.Check if a node has already been computedTo determine if the value of a specified nodenhas already been computed and stored in cache,
you can utilizebool(n).
This function returnsTrueif the node's value exists in the cache, andFalseotherwise.a = Root(1)
b = Root(2)
c = Node(add, a, b)
print(bool(c))
print("c is", c())
print(bool(c))

False
calculating 1 + 2
c is 3
TrueAn example of updating an upstream nodeprint("create nodes")
a = Root(1)
b = Root(2)
c = Node(add, a, b)
print("get the value")
print(f"c is {c()}")
print("get the value again")
print(f"c is {c()}")
print("update upstream")
a.reset(4)
print("get the new value")
print(f"c is {c()}")

create nodes
get the value
calculating 1 + 2
c is 3
get the value again
c is 3
update upstream
get the new value
calculating 4 + 2
c is 6In the provided code snippet, prior to resetting the upstream nodea,
the value of nodecis computed only once during its initial execution and subsequently utilizes a cache mechanism for subsequent calls.
Then, by callinga.reset(v), wherevequals4here, the value of nodeacan be reset to this new value.
After this operation, invokingc()will cause the function to be executed once more in order to obtain the updated value of nodec.Both positional and keyword arguments are accepted, as well as regular values and lazy nodesBoth positional and keyword arguments are supported, allowing for a flexible approach when creating nodes.
You can mix these arguments with regular values as needed.
In the example provided, we utilize various types of arguments,
such as positional regular values, positional lazy nodes, keyword regular values, and keyword lazy nodes,
to construct nodez.def add4(a, b, c, d):
    print(f"calculating {a} + {b} + {c} + {d}")
    return a + b + c + d


print("create nodes")
a = Root(1)
c = Root(3)
z = Node(add4, a, 2, c=c, d=4)
print("get the value")
print(f"c is {z()}")

create nodes
get the value
calculating 1 + 2 + 3 + 4
c is 10Copy the graph of lazy nodesfrom lazy import Copy

print("create nodes")
a = Root(1)
b = Root(2)
c = Node(add, a, b)
print("get the value")
print(f"c is {c()}")

print("copy lazy graph")
copy = Copy()
new_a = copy(a)
new_b = copy(b)
new_c = copy(c)

print("get the new value")
print(f"new c is {new_c()}")

create nodes
get the value
calculating 1 + 2
c is 3
copy lazy graph
get the new value
new c is 3In addition to the previously simple example, we duplicate the graph,
copyingatonew_a,btonew_b, andctonew_c.
This is done using a copy handle acquired through the `Copy()` function.
Once you have obtained the handle withcopy = Copy(),
you can then utilizecopy(old_node)to obtain the correspondingnew_node.After copying the graph, the cache is also reused whenever possible.
For instance, theaddfunction isn't called when retrieving the value of nodenew_c.print("reset value")
a.reset(4)
new_a.reset(8)
print("get the old value and new value")
print(f"c is {c()}, new c is {new_c()}")

reset value
get the old value and new value
calculating 4 + 2
calculating 8 + 2
c is 6, new c is 10In the copied graph, the relationships between nodes are identical to those in the original graph,
along with the cache when feasible.
However, resetting the value of a node in one graph does not impact any other graphs.In some cases, users might wish to duplicate just a portion of an entire graph.
In such instances, both graphs will share the same upstream nodes for those that haven't been replicated.
For instance, consider the example below where nodeais shared between the two graphs.
However, the second graph contains unique nodesnew_bandnew_c, which correspond toaandbrespectively in the initial graph.copy = Copy()
new_b = copy(b)
new_c = copy(c)

print(f"a is {a()}")
print(f"b is {b()}, new b is {new_b()}")
print(f"c is {c()}, new c is {new_c()}")
b.reset(8)
print(f"c is {c()}, new c is {new_c()}")
new_b.reset(10)
print(f"c is {c()}, new c is {new_c()}")
a.reset(6)
print(f"c is {c()}, new c is {new_c()}")

a is 4
b is 2, new b is 2
c is 6, new c is 6
calculating 4 + 8
c is 12, new c is 6
calculating 4 + 10
c is 12, new c is 14
calculating 6 + 8
calculating 6 + 10
c is 14, new c is 16In order to prevent misuse, if a user attempts to duplicate the same node multiple times, the copy handler will provide the same new node each time.new_c = copy(c)
new_c_2 = copy(c)
print(id(new_c) == id(new_c_2))

TrueWhen duplicating a lazy graph,
it is essential to replicate the upstream nodes prior to proceeding with the downstream nodes.
This guarantees that the package can effectively handle the dependencies among the various nodes of the graph.