lazy graph framework
Project description
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.
Install
Please either copy or create a soft link for the directory in the site-packages
directory.
Alternatively, you can utilize pip to install the lazy-graph package by running the command pip install lazy_graph
.
Documents
A simple example
We can create a root node a
with the value 1
and another root node b
with the value 2
,
followed by creating a new node called c
, where its value is equal to the sum of the values of nodes a
and b
.
The function for adding these nodes will be triggered whenever we attempt to retrieve the value of node c
.
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 3
As demonstrated earlier, to create a root node containing the value of x
, we use the expression Root(x)
.
On the other hand, to obtain a node with its value determined by the function func
along with any additional arguments or keyword arguments (if provided),
you would call Node(func, *args, **kwargs)
.
This will generate a node whose value is computed as func(*args, **kwargs)
.
To obtain the value of a given node n
, simply use the function n()
.
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 computed
To determine if the value of a specified node n
has already been computed and stored in cache,
you can utilize bool(n)
.
This function returns True
if the node's value exists in the cache, and False
otherwise.
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
True
An example of updating an upstream node
print("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 6
In the provided code snippet, prior to resetting the upstream node a
,
the value of node c
is computed only once during its initial execution and subsequently utilizes a cache mechanism for subsequent calls.
Then, by calling a.reset(v)
, where v
equals 4
here, the value of node a
can be reset to this new value.
After this operation, invoking c()
will cause the function to be executed once more in order to obtain the updated value of node c
.
Both positional and keyword arguments are accepted, as well as regular values and lazy nodes
Both 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 node z
.
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 10
Copy the graph of lazy nodes
from 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 3
In addition to the previously simple example, we duplicate the graph,
copying a
to new_a
, b
to new_b
, and c
to new_c
.
This is done using a copy handle acquired through the `Copy()` function.
Once you have obtained the handle with copy = Copy()
,
you can then utilize copy(old_node)
to obtain the corresponding new_node
.
After copying the graph, the cache is also reused whenever possible.
For instance, the add
function isn't called when retrieving the value of node new_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 10
In 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 node a
is shared between the two graphs.
However, the second graph contains unique nodes new_b
and new_c
, which correspond to a
and b
respectively 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 16
In 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))
True
When 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file lazy_graph-0.3.14-py3-none-any.whl
.
File metadata
- Download URL: lazy_graph-0.3.14-py3-none-any.whl
- Upload date:
- Size: 7.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/4.0.2 CPython/3.11.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7872b08178696d8e093943746e508977be31b169d46d69314f26bbfb0a768c16 |
|
MD5 | ff616548513864107ea1807deb3f47da |
|
BLAKE2b-256 | f6b36e8b2dbcbeb59a0f964f7c54e422be9804f69cb1a91f2a4d92d01effcb4b |