Primitive Computables
The inquanto.computables.primitive
submodule provides primitive computable objects
which do not represent physical quantities themselves but function as
building blocks for more complex structures. Moreover, primitive computables can
evaluate themselves recursively without the need for an evaluator,
as they are generally not the leaf nodes in a computable tree.
A basic computable, which is primarily intended for demonstration purposes,
is ComputableInt
.
It stores an integer value and returns this value upon evaluation.
As it does not require any quantum measurement, but returns directly the stored integer,
no evaluator function needs to be passed to the
evaluate()
method.
from inquanto.computables.primitive import ComputableInt
cint = ComputableInt(2)
print(cint)
print(cint.evaluate())
ComputableInt(value=2)
2
Other primitive computables extend to more advanced data structures such as lists, arrays,
tuples, and callables.
These structures can house other computables, with evaluations performed recursively.
The ComputableInt
will serve as an atomic computable,
demonstrating how to build these more complex data structures with it.
Computable Lists and Tuples
In this section, we illustrate the usage of ComputableTuple
and ComputableList
.
These classes mirror Python’s tuple and list data structures, but can also contain other
computable structures.
When the evaluate()
method is called,
the corresponding evaluate()
methods of the
child computables (the elements of the tuple or list that are also computables), are invoked.
from inquanto.computables.primitive import ComputableTuple, ComputableList
ctuple = ComputableTuple(ComputableInt(1), ComputableInt(0), -1)
print(ctuple)
print(ctuple.evaluate())
clist = ComputableList([ComputableInt(3), ComputableInt(4), 5])
print(clist)
print(clist.evaluate())
(ComputableInt(value=1), ComputableInt(value=0), -1)
(1, 0, -1)
[ComputableInt(value=3), ComputableInt(value=4), 5]
[3, 4, 5]
You can explore the child computables contained within these structures using built-in methods:
print(list(ctuple.children()))
[ComputableInt(value=1), ComputableInt(value=0)]
This will print the child computables. Note that the ctuple
has three elements,
but only two children. Additionally, you can inspect the tree structure of computables
using the print_tree()
method:
ctuple.print_tree()
(ComputableInt(value=1), ComputableInt(value=0), -1)
ComputableInt(value=1)
ComputableInt(value=0)
Iterating Over Computable Trees
The computables can be further composed into larger structures.
co = ComputableTuple(ctuple, clist, "something else")
You can iterate over the nodes of a computable tree using the
walk()
method, which allows
for detailed exploration of the tree structure:
for cnode, depth in co.walk():
print(cnode, depth)
((ComputableInt(value=1), ComputableInt(value=0), -1), [ComputableInt(value=3), ComputableInt(value=4), 5], 'something else') 0
(ComputableInt(value=1), ComputableInt(value=0), -1) 1
ComputableInt(value=1) 2
ComputableInt(value=0) 2
[ComputableInt(value=3), ComputableInt(value=4), 5] 1
ComputableInt(value=3) 2
ComputableInt(value=4) 2
Computable Multi-dimensional Arrays
The ComputableNDArray
class allows for handling multi-dimensional arrays of computables,
utilizing numpy’s ndarray.
This computable ndarray stores computables as objects and returns
an ndarray with evaluated values in their respective locations upon successful evaluation of
all child computables. The type of values depends on the computables housed in the computable
ndarray; hence, the returned ndarray will retain object
dtype.
from inquanto.computables.primitive import ComputableNDArray
carr = ComputableNDArray([[ComputableInt(3), ComputableInt(4)], [ComputableInt(3), ComputableInt(4)]])
print(carr)
print(carr.evaluate())
[[ComputableInt(value=3) ComputableInt(value=4)]
[ComputableInt(value=3) ComputableInt(value=4)]]
[[3 4]
[3 4]]
Calling a Function with Computables
The ComputableFunction
class enables the conversion of any lambda function that operates
on values into a function that operates on computables.
For instance, if we have a list of computables and want to evaluate the sum of their values,
we might proceed as follows:
from inquanto.computables.primitive import ComputableFunction
csum = ComputableFunction(lambda x: sum(x), clist)
print(csum)
print(csum.evaluate()) # 12
ComputableFunction(<lambda>, [ComputableInt(value=3), ComputableInt(value=4), 5])
12
Another example might be the division of one computable by another:
from inquanto.computables.primitive import ComputableFunction
cfunc = ComputableFunction(lambda x, y: x / y, csum, ComputableInt(4))
print(cfunc)
print(cfunc.evaluate())
ComputableFunction(<lambda>, ComputableFunction(<lambda>, [ComputableInt(value=3), ComputableInt(value=4), 5]), ComputableInt(value=4))
3.0