# qnet.algebra.abstract_algebra module¶

The abstract algebra package provides the foundation for symbolic algebra of quantum objects or circuits. All symbolic objects are either scalars (see scalar_types) or an instance of Expression. Algebraic combinations of atomic expressions are instances of Operation. In this way, any symbolic expression is a tree of operations, with children of each node defined through the Operation.operands attribute, and the leaves being atomic expressions or scalars.

See Expressions and Operations for design details and usage.

## Summary¶

Exceptions:

 AlgebraError Base class for all errors concerning the mathematical definitions and rules of an algebra. AlgebraException Base class for all errors concerning the mathematical definitions and rules of an algebra. CannotSimplify Raised when an expression cannot be further simplified WrongSignatureError Raised when an operation is instantiated with operands of the wrong signature.

Classes:

 Expression Abstract class for QNET Expressions. Operation Base class for all “operations”, i.e.

Functions:

 all_symbols Return all all_symbols featured within an expression. assoc Associatively expand out nested arguments of the flat class. check_idempotent_create Check that an expression is ‘idempotent’ check_rules_dict Verify the rules that classes may use for the _rules or _binary_rules class attribute. extra_binary_rules Context manager that temporarily adds the given rules to cls (to be processed by match_replace_binary. extra_rules Context manager that temporarily adds the given rules to cls (to be processed by match_replace. filter_neutral Remove occurrences of a neutral element from the argument/operand list, if that list has at least two elements. idem Remove duplicate arguments and order them via the cls’s order_key key object/function. match_replace Match and replace a full operand specification to a function that provides a replacement for the whole expression or raises a CannotSimplify exception. match_replace_binary Similar to func:match_replace, but for arbitrary length operations, such that each two pairs of subsequent operands are matched pairwise. no_instance_caching Temporarily disable the caching of instances through no_rules Context manager that temporarily disables all rules (processed by match_replace or match_replace_binary) for the given cls. orderby Re-order arguments via the class’s order_key key object/function. set_union Similar to sum(), but for sets. simplify Recursively re-instantiate the expression, while applying all of the substitute Substitute symbols or (sub-)expressions with the given replacements and temporary_instance_cache Use a temporary cache for instances obtained from the create method of the given cls.

## Reference¶

exception qnet.algebra.abstract_algebra.AlgebraException[source]

Bases: Exception

Base class for all errors concerning the mathematical definitions and rules of an algebra.

exception qnet.algebra.abstract_algebra.AlgebraError[source]

Base class for all errors concerning the mathematical definitions and rules of an algebra.

exception qnet.algebra.abstract_algebra.CannotSimplify[source]

Raised when an expression cannot be further simplified

exception qnet.algebra.abstract_algebra.WrongSignatureError[source]

Raised when an operation is instantiated with operands of the wrong signature.

class qnet.algebra.abstract_algebra.Expression(*args, **kwargs)[source]

Bases: object

Abstract class for QNET Expressions. All algebraic objects are either scalars (numbers or Sympy expressions) or instances of Expression.

Expressions should generally be instantiated using the create class method, which takes into account the algebraic properties of the Expression and and applies simplifications. It also uses memoization to cache all known (sub-)expression. This is possible because expressions are intended to be immutable. Any changes to an expression should be made through e.g. substitute(), which returns a new modified expression.

Every expression has a well-defined list of positional and keyword arguments that uniquely determine the expression and that may be accessed through the args and kwargs property. That is,

expr.__class__(*expr.args, **expr.kwargs)


will return and object identical to expr.

Class Attributes:
instance_caching (bool) – Flag to indicate whether the create class method should cache the instantiation of instances
instance_caching = True
classmethod create(*args, **kwargs)[source]

Instead of directly instantiating, it is recommended to use create, which applies simplifications to the args and keyword arguments according to the _simplifications class attribute, and returns an appropriate object (which may or may not be an instance of the original class)

args

The tuple of positional arguments for the instantiation of the Expression

kwargs

The dictionary of keyword-only arguments for the instantiation of the Expression

minimal_kwargs

A “minimal” dictionary of keyword-only arguments, i.e. a subset of kwargs that may exclude default options

substitute(var_map)[source]

Substitute all_symbols for other expressions.

Parameters: var_map (dict) – Dictionary with entries of the form {expr: substitution}
simplify(rules=None)[source]

Recursively re-instantiate the expression, while applying all of the given rules to all encountered (sub-) expressions

Parameters: rules (list, OrderedDict) – List of rules or dictionary mapping names to rules, where each rule is a tuple (Pattern, replacement callable)
all_symbols()[source]

Set of all_symbols contained within the expression.

__ne__(other)[source]

If it is well-defined (i.e. boolean), simply return the negation of self.__eq__(other) Otherwise return NotImplemented.

qnet.algebra.abstract_algebra.check_idempotent_create(expr)[source]

Check that an expression is ‘idempotent’

qnet.algebra.abstract_algebra.substitute(expr, var_map)[source]

Substitute symbols or (sub-)expressions with the given replacements and re-evalute the result

Parameters: expr – The expression in which to perform the substitution var_map (dict) – The substitution dictionary.
qnet.algebra.abstract_algebra.simplify(expr, rules=None)[source]

Recursively re-instantiate the expression, while applying all of the given rules to all encountered (sub-) expressions

Parameters: expr – Any Expression or scalar object rules (list, OrderedDict) – A list of rules dictionary mapping names to rules, where each rule is a tuple (pattern, replacement) where pattern is an instance of Pattern) and replacement is a callable. The pattern will be matched against any expression that is encountered during the re-instantiation. If the pattern matches, then the (sub-)expression is replaced by the result of calling replacement while passing any wildcards from pattern as keyword arguments. If replacement raises CannotSimplify, it will be ignored

Note

Instead of or in addition to passing rules, simplify can often be combined with e.g. extra_rules / extra_binary_rules context managers. If a simplification can be handled through these context managers, this is usually more efficient than an equivalent rule. However, both really are complementary: the rules defined in the context managers are applied before instantiation (hence these these patterns are instantiated through pattern_head). In contrast, the patterns defined in rules are applied against instantiated expressions.

qnet.algebra.abstract_algebra.set_union(*sets)[source]

Similar to sum(), but for sets. Generate the union of an arbitrary number of set arguments.

qnet.algebra.abstract_algebra.all_symbols(expr)[source]

Return all all_symbols featured within an expression.

class qnet.algebra.abstract_algebra.Operation(*operands, **kwargs)[source]

Base class for all “operations”, i.e. Expressions that act algebraically on other expressions (their “operands”).

Operations differ from more general Expressions by the convention that the arguments of the Operator are exactly the operands (which must be members of the algebra!) Any other parameters (non-operands) that may be required must be given as keyword-arguments.

operands

Tuple of operands of the operation

args

Alias for operands

qnet.algebra.abstract_algebra.assoc(cls, ops, kwargs)[source]

Associatively expand out nested arguments of the flat class. E.g.:

>>> class Plus(Operation):
...     _simplifications = [assoc, ]
>>> Plus.create(1,Plus(2,3))
Plus(1, 2, 3)

qnet.algebra.abstract_algebra.idem(cls, ops, kwargs)[source]

Remove duplicate arguments and order them via the cls’s order_key key object/function. E.g.:

>>> class Set(Operation):
...     order_key = lambda val: val
...     _simplifications = [idem, ]
>>> Set.create(1,2,3,1,3)
Set(1, 2, 3)

qnet.algebra.abstract_algebra.orderby(cls, ops, kwargs)[source]

Re-order arguments via the class’s order_key key object/function. Use this for commutative operations: E.g.:

>>> class Times(Operation):
...     order_key = lambda val: val
...     _simplifications = [orderby, ]
>>> Times.create(2,1)
Times(1, 2)

qnet.algebra.abstract_algebra.filter_neutral(cls, ops, kwargs)[source]

Remove occurrences of a neutral element from the argument/operand list, if that list has at least two elements. To use this, one must also specify a neutral element, which can be anything that allows for an equality check with each argument. E.g.:

>>> class X(Operation):
...     neutral_element = 1
...     _simplifications = [filter_neutral, ]
>>> X.create(2,1,3,1)
X(2, 3)

qnet.algebra.abstract_algebra.match_replace(cls, ops, kwargs)[source]

Match and replace a full operand specification to a function that provides a replacement for the whole expression or raises a CannotSimplify exception. E.g.

First define an operation:

>>> class Invert(Operation):
...     _rules = OrderedDict()
...     _simplifications = [match_replace, ]


Then some _rules:

>>> A = wc("A")
>>> A_float = wc("A", head=float)
>>> Invert_A = pattern(Invert, A)
>>> Invert._rules.update([
...     ('r1', (pattern_head(Invert_A), lambda A: A)),
...     ('r2', (pattern_head(A_float), lambda A: 1./A)),
... ])


Check rule application:

>>> from qnet.printing import srepr
>>> print(srepr(Invert.create("hallo")))  # matches no rule
Invert('hallo')
>>> Invert.create(Invert("hallo"))        # matches first rule
'hallo'
>>> Invert.create(.2)                     # matches second rule
5.0


A pattern can also have the same wildcard appear twice:

>>> class X(Operation):
...     _rules = {
...         'r1': (pattern_head(A, A), lambda A: A),
...     }
...     _simplifications = [match_replace, ]
>>> X.create(1,2)
X(1, 2)
>>> X.create(1,1)
1

qnet.algebra.abstract_algebra.match_replace_binary(cls, ops, kwargs)[source]

Similar to func:match_replace, but for arbitrary length operations, such that each two pairs of subsequent operands are matched pairwise.

>>> A = wc("A")
>>> class FilterDupes(Operation):
...     _binary_rules = {
...          'filter_dupes': (pattern_head(A,A), lambda A: A)}
...     _simplifications = [match_replace_binary, assoc]
...     neutral_element = 0
>>> FilterDupes.create(1,2,3,4)         # No duplicates
FilterDupes(1, 2, 3, 4)
>>> FilterDupes.create(1,2,2,3,4)       # Some duplicates
FilterDupes(1, 2, 3, 4)


Note that this only works for subsequent duplicate entries:

>>> FilterDupes.create(1,2,3,2,4)       # No *subsequent* duplicates
FilterDupes(1, 2, 3, 2, 4)


Any operation that uses binary reduction must be associative and define a neutral element. The binary rules must be compatible with associativity, i.e. there is no specific order in which the rules are applied to pairs of operands.

qnet.algebra.abstract_algebra.check_rules_dict(rules)[source]

Verify the rules that classes may use for the _rules or _binary_rules class attribute.

Specifically, rules must be a OrderedDict-compatible object (list of key-value tuples, dict, OrderedDict) that maps a rule name (str) to a rule. Each rule consists of a Pattern and a replaceent callable. The Pattern must be set up to match a ProtoExpr. That is, the Pattern should be constructed through the pattern_head() routine.

Raises: TypeError – If rules is not compatible with OrderedDict, the keys in rules are not strings, or rule is not a tuple of (Pattern, callable) ValueError – If the head-attribute of each Pattern is not an instance of ProtoExpr, or if there are duplicate keys in rules OrderedDict(rules)
qnet.algebra.abstract_algebra.no_instance_caching()[source]

Temporarily disable the caching of instances through Expression.create()

qnet.algebra.abstract_algebra.temporary_instance_cache(cls)[source]

Use a temporary cache for instances obtained from the create method of the given cls. That is, no cached instances from outside of the managed context will be used within the managed context, and vice versa

qnet.algebra.abstract_algebra.extra_rules(cls, rules)[source]

Context manager that temporarily adds the given rules to cls (to be processed by match_replace. Implies temporary_instance_cache.

qnet.algebra.abstract_algebra.extra_binary_rules(cls, rules)[source]

Context manager that temporarily adds the given rules to cls (to be processed by match_replace_binary. Implies temporary_instance_cache.

qnet.algebra.abstract_algebra.no_rules(cls)[source]

Context manager that temporarily disables all rules (processed by match_replace or match_replace_binary) for the given cls. Implies temporary_instance_cache.