circkit.operation¶
Operations may include arbitrary parameters. It is important to distinguish parameters (arbitrary objects) from node’s inputs (other nodes in the same circuit).
An Operation (sub)class describes an operation and all its parameters,
including validation of parameters, number of node’s inputs and outputs.
An Operation instance describes a concrete operation with all
parameters set. It does not however define a node in a circuit or node’s
inputs/outputs. One Operation instance can be used by multiple nodes.
The node/operation creation API is a double-step call (similar to e.g. Keras Layers API):
x = circuit.INPUT("x")()
xcube = circuit.EXP(3)(x)
assert issubclass(circuit.EXP, Operation)
assert isinstance(circuit.EXP(3), Operation)
assert isinstance(circuit.EXP(3)(x), circuit.Node)
Here, both lines follow this API, in which the first call creates an Operation
instance and the second call creates a circkit.node.Node instance.
In the first line, we first create
the Circuit.INPUT operation, which has the input name “x” as the only parameter:
circuit.INPUT("x"). Then, we call this operation without any incoming nodes
to create a new node in the circuit, corresponding to the input “x”.
In the second line, we first create the EXP operation with the parameter power = 3. We then call this operation with a node as an argument which defines the incoming node for exponentitation.
The reason for the double-call is to separate clearly the two different
notions - parameters and inputs, and to allow using the full python’s call
syntax. For example, we could use keyword args such as Circuit.EXP(power=3).
This is particularly useful for complex operations to reduce the number of
errors e.g. in parameter/input order.
Defining operation example:
class NewCircuitType(Circuit):
class Operations(Circuit.Operations): # subclass to include
# standard INPUT, GET, CONST
class ADD(Operation.Binary):
def eval(self, a, b):
return a + b
class SUB(Operation.Binary):
SYMMETRIC = False
def eval(self, a, b):
return a - b
class MIX(Operation.MultiVariadic):
alpha : Param.Int(min_value=1) = 2
def determine_n_outputs(self, node):
return len(node.incoming)
def eval(self, *args):
t = self.alpha * sum(args)
return [a - t for a in args]
Module contents¶
- circkit.operation.VARIABLE = <VARIABLE>¶
Special
Operation.n_inputs/Operation.n_outputsvalue - unspecified number of inputs/outputs (or determined dynamically).
- circkit.operation.UNIT = <UNIT>¶
Special
Operation.n_outputsvalue - non-iterable output.
- class circkit.operation.OperationMeta(clsname, bases, attrs)¶
Bases:
typeMetaclass for the
Operationclass.Manages definition of operations (classes) and creation of operation instances (e.g. preparing parameters, caching operatios).
- static __new__(meta, clsname, bases, attrs)¶
Define a new Operation class (in a circuit class).
Parse definitions of parameters from the annotations and assignments (defaults).
Update
__slots__to include new parameters.Collects parameters from superclasses. If such a parameter attribute is overriden by a non-parameter attribute, the parameter is excluded. This allows e.g. to remove superclass’ parameter by setting attribute
param = None.Create dynamically new
Operationclass with given slots and parameters descriptions.
- class circkit.operation.Operation(*values, **kvalues)¶
Bases:
objectDescribes a (parametrized) operation that can be used in a circuit.
Parameters of an
Operationinstance are accessible directly as attributes.All supporting attributes are either prefixed with “_” or are UPPERCASE to avoid collisions with possible parameter names. Exceptions:
n_inputsandn_outputs.- Defining attributes (may/should be overwritten in subclasses)
- n_inputs¶
Number of node inputs the operation requires.
- Type
int
- n_outputs¶
Number of node outputs the operation has (to be retrieved with the
Circuit.Operations.GEToperation). By default, is set to the special objectUNIT, which means that the output is non iterable. Note that this is different fromn_outputs = 1, where the actual output has to be retrieved e.g. asout = node[0]or out, = node.- Type
int = UNIT
- SYMMETRIC¶
Whether the order of the input nodes does not matter. Used e.g. for caching nodes (
b + amay return the cached nodea + b).- Type
bool
- PRECOMPUTABLE¶
Whether the operation is precomputable (given the inputs and the parameters).
- Type
bool
- STR_LIMIT¶
Maximum length of the string describing parameters to keep (for
__str__()).- Type
int = 30
- Functional attributes (should not be overriden manually)
- _param_descriptions¶
Mapping from parameter names to
Paramobjects describing the parameters.- Type
dict`[str, :class:.Param`]
- __init__(*values, **kvalues)¶
Create an
Operationinstance by specifying parameters (if any).Note that it is not linked to any
Nodeyet.
- __call__(*incoming, **kwargs)¶
Create a new node using this operation.
- reapply(circuit, name=None)¶
Create new operation instance with same parameters (by name), but in the other circuit. @name define name of the operation, by default it is the name of this operation.
- __eq__(other)¶
Test equality of two operations.
Two operations are equal if their names are equal and all parameters are equal.
To check the class of the operation (e.g. INPUT, ADD, CONST, etc.) use:
isinstance(op, CircuitClass.ADD): checks circuit class;isinstance(op, CircuitInstance.ADD): checks circuit instance too;op.is_ADD(): ADD must be present in the circuit’s class;op._name == "ADD": by name, does not check circuit class/instance.
- Parameters
other (Operation) –
- __hash__()¶
Return hash(self).
- __str__()¶
Return str(self).
- __repr__()¶
Return repr(self).
- eval_with_node(node, *args)¶
This method should be overriden if the evaluation requires some information from the node. By default, it ignores the node and calls
eval().
- eval(*args)¶
Evaluate the operation on given inputs (typically values, not nodes).
- before_create_node(*args)¶
Validate node inputs before creating a new node with this operation.
- after_create_node(node)¶
Check new node after creation (node uses this operation).
- classmethod on_new_circuit(circuit)¶
Callback on linking the operation class to a new circuit instance.
E.g. can store common circuit-level data in the circuit instance.
- determine_n_outputs(node)¶
Determine number of outputs of a new node using this operation.
By default, returns operation’s
n_outputs. However, this method must be overriden for multi-operations. For example, the number of outputs may be set equal to the number of inputs.- Return type
int
- __reduce__()¶
Helper for pickle.
- __setstate__(src)¶
To update class.__dict__ with dict/map
- class MultiBinary(*values, **kvalues)¶
Bases:
OperationOperation with 2 inputs and (possibly) multiple number of outputs.
- class MultiNullary(*values, **kvalues)¶
Bases:
OperationOperation with no inputs and (possibly) multiple number of outputs.
- class MultiTernary(*values, **kvalues)¶
Bases:
OperationOperation with 3 inputs and (possibly) multiple number of outputs.
- class MultiUnary(*values, **kvalues)¶
Bases:
OperationOperation with 1 input and (possibly) multiple number of outputs.
- class circkit.operation.Variadic(*values, **kvalues)¶
Bases:
OperationOperation with variable number of inputs.
- class circkit.operation.MultiNullary(*values, **kvalues)¶
Bases:
OperationOperation with no inputs and (possibly) multiple number of outputs.
- class circkit.operation.MultiUnary(*values, **kvalues)¶
Bases:
OperationOperation with 1 input and (possibly) multiple number of outputs.
- class circkit.operation.MultiBinary(*values, **kvalues)¶
Bases:
OperationOperation with 2 inputs and (possibly) multiple number of outputs.
- class circkit.operation.MultiTernary(*values, **kvalues)¶
Bases:
OperationOperation with 3 inputs and (possibly) multiple number of outputs.