qnet.algebra.core.abstract_algebra module¶
Base classes for all Expressions and Operations.
The abstract algebra package provides the foundation for
symbolic algebra of quantum objects or circuits. All symbolic objects are
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.
See Expressions and Operations for design details and usage.
Summary¶
Classes:
Expression |
Base class for all QNET Expressions |
Operation |
Base class for “operations” |
Functions:
substitute |
Substitute symbols or (sub-)expressions with the given replacements and re-evalute the result |
__all__
: Expression
, Operation
, substitute
Reference¶
-
class
qnet.algebra.core.abstract_algebra.
Expression
(*args, **kwargs)[source]¶ Bases:
object
Base class for all QNET Expressions
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()
orapply_rule()
, 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
andkwargs
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. If True, repeated calls tocreate()
with the same arguments return instantly, instead of re-evaluating all simplifications and rules. - simplifications (list) – List of callable simplifications that
create()
will use to process its positional and keyword arguments. Each callable must take three parameters (the class, the list args of positional arguments given tocreate()
and a dictionary kwargs of keyword arguments given tocreate()
) and return either a tuple of new args and kwargs (which are then handed to the next callable), or anExpression
(which is directly returned as the result of the call tocreate()
). The built-in available simplification callables are inalgebraic_properties
-
simplifications
= []¶
-
instance_caching
= True¶
-
classmethod
create
(*args, **kwargs)[source]¶ Instantiate while applying automatic simplifications
Instead of directly instantiating cls, it is recommended to use
create()
, which applies simplifications to the args and keyword arguments according to thesimplifications
class attribute, and returns an appropriate object (which may or may not be an instance of the original cls).Two simplifications of particular importance are
match_replace()
andmatch_replace_binary()
which apply rule-based simplifications.The
temporary_rules()
context manager may be used to allow temporary modification of the automatic simplifications thatcreate()
uses, in particular the rules formatch_replace()
andmatch_replace_binary()
. Inside the managed context, thesimplifications
class attribute may be modified and rules can be managed withadd_rule()
anddel_rules()
.
-
classmethod
add_rule
(name, pattern, replacement, attr=None)[source]¶ Add an algebraic rule for
create()
to the classParameters: - name (str) – Name of the rule. This is used for debug logging to
allow an analysis of which rules where applied when creating an
expression. The name can be arbitrary, but it must be unique.
Built-in rules have names
'Rxxx'
wherex
is a digit - pattern (Pattern) – A pattern constructed by
pattern_head()
to match aProtoExpr
- replacement (callable) – callable that takes the wildcard names defined in pattern as keyword arguments and returns an evaluated expression.
- attr (None or str) – Name of the class attribute to which to add the
rule. If None, one of
'_rules'
,'_binary_rules'
is automatically chosen
Raises: TypeError
– if name is not astr
or pattern is not aPattern
instanceValueError
– if pattern is not set up to match aProtoExpr
; if there there is already a rule with the same name; if replacement is not a callable or does not take all the wildcard names in pattern as argumentsAttributeError
– If invalid attr
Note
The “automatic” rules added by this method are applied before expressions are instantiated (against a corresponding
ProtoExpr
). In contrast,apply_rules()
/apply_rule()
are applied to fully instantiated objects.The
temporary_rules()
context manager may be used to create a context in which rules may be defined locally.- name (str) – Name of the rule. This is used for debug logging to
allow an analysis of which rules where applied when creating an
expression. The name can be arbitrary, but it must be unique.
Built-in rules have names
-
classmethod
show_rules
(*names, attr=None)[source]¶ Print algebraic rules used by
create
Print a summary of the algebraic rules with the given names, or all rules if not names a given.
Parameters: - names (str) – Names of rules to show
- attr (None or str) – Name of the class attribute from which to get
the rules. Cf.
add_rule()
.
Raises: AttributeError
– If invalid attr
-
classmethod
del_rules
(*names, attr=None)[source]¶ Delete algebraic rules used by
create()
Remove the rules with the given names, or all rules if no names are given
Parameters: - names (str) – Names of rules to delete
- attr (None or str) – Name of the class attribute from which to
delete the rules. Cf.
add_rule()
.
Raises: KeyError
– If any rules in names does not existAttributeError
– If invalid attr
-
classmethod
rules
(attr=None)[source]¶ Iterable of rule names used by
create()
Parameters: attr (None or str) – Name of the class attribute to which to get the names. If None, one of '_rules'
,'_binary_rules'
is automatically chosen
-
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 sub-expressions
Parameters: var_map (dict) – Dictionary with entries of the form {expr: substitution}
-
doit
(classes=None, recursive=True, **kwargs)[source]¶ Rewrite (sub-)expressions in a more explicit form
Return a modified expression that is more explicit than the original expression. The definition of “more explicit” is decided by the relevant subclass, e.g. a
Commutator
is written out according to its definition.Parameters: - classes (None or list) – an optional list of classes. If given, only (sub-)expressions that an instance of one of the classes in the list will be rewritten.
- recursive (bool) – If True, also rewrite any sub-expressions of any
rewritten expression. Note that
doit()
always recurses into sub-expressions of expressions not affected by it. - kwargs – Any remaining keyword arguments may be used by the
doit()
method of a particular expression.
Example
Consider the following expression:
>>> from sympy import IndexedBase >>> i = IdxSym('i'); N = symbols('N') >>> Asym, Csym = symbols('A, C', cls=IndexedBase) >>> A = lambda i: OperatorSymbol(StrLabel(Asym[i]), hs=0) >>> B = OperatorSymbol('B', hs=0) >>> C = lambda i: OperatorSymbol(StrLabel(Csym[i]), hs=0) >>> def show(expr): ... print(unicode(expr, show_hs_label=False)) >>> expr = Sum(i, 1, 3)(Commutator(A(i), B) + C(i)) / N >>> show(expr) 1/N (∑_{i=1}^{3} (Ĉ_i + [Â_i, B̂]))
Calling
doit()
without parameters rewrites both the indexed sum and the commutator:>>> show(expr.doit()) 1/N (Ĉ₁ + Ĉ₂ + Ĉ₃ + Â₁ B̂ + Â₂ B̂ + Â₃ B̂ - B̂ Â₁ - B̂ Â₂ - B̂ Â₃)
A non-recursive call only expands the sum, as it does not recurse into the expanded summands:
>>> show(expr.doit(recursive=False)) 1/N (Ĉ₁ + Ĉ₂ + Ĉ₃ + [Â₁, B̂] + [Â₂, B̂] + [Â₃, B̂])
We can selectively expand only the sum or only the commutator:
>>> show(expr.doit(classes=[IndexedSum])) 1/N (Ĉ₁ + Ĉ₂ + Ĉ₃ + [Â₁, B̂] + [Â₂, B̂] + [Â₃, B̂]) >>> show(expr.doit(classes=[Commutator])) 1/N (∑_{i=1}^{3} (Ĉ_i - B̂ Â_i + Â_i B̂))
Also we can pass a keyword argument that expands the sum only to the 2nd term, as documented in
Commutator.doit()
>>> show(expr.doit(classes=[IndexedSum], max_terms=2)) 1/N (Ĉ₁ + Ĉ₂ + [Â₁, B̂] + [Â₂, B̂])
-
apply
(func, *args, **kwargs)[source]¶ Apply func to expression.
Equivalent to
func(self, *args, **kwargs)
. This method exists for easy chaining:>>> A, B, C, D = ( ... OperatorSymbol(s, hs=1) for s in ('A', 'B', 'C', 'D')) >>> expr = ( ... Commutator(A * B, C * D) ... .apply(lambda expr: expr**2) ... .apply(expand_commutators_leibniz, expand_expr=False) ... .substitute({A: IdentityOperator}))
-
apply_rules
(rules, recursive=True)[source]¶ Rebuild the expression while applying a list of rules
The rules are applied against the instantiated expression, and any sub-expressions if recursive is True. Rule application is best though of as a pattern-based substitution. This is different from the automatic rules that
create()
uses (seeadd_rule()
), which are applied before expressions are instantiated.Parameters: - rules (list or OrderedDict) – List of rules or
dictionary mapping names to rules, where each rule is a tuple
(
Pattern
, replacement callable), cf.apply_rule()
- recursive (bool) – If true (default), apply rules to all arguments and keyword arguments of the expression. Otherwise, only the expression itself will be re-instantiated.
If rules is a dictionary, the keys (rules names) are used only for debug logging, to allow an analysis of which rules lead to the final form of an expression.
- rules (list or OrderedDict) – List of rules or
dictionary mapping names to rules, where each rule is a tuple
(
-
apply_rule
(pattern, replacement, recursive=True)[source]¶ Apply a single rules to the expression
This is equivalent to
apply_rules()
withrules=[(pattern, replacement)]
Parameters: - pattern (Pattern) – A pattern containing one or more wildcards
- replacement (callable) – A callable that takes the wildcard names in pattern as keyword arguments, and returns a replacement for any expression that pattern matches.
Example
Consider the following Heisenberg Hamiltonian:
>>> tls = SpinSpace(label='s', spin='1/2') >>> i, j, n = symbols('i, j, n', cls=IdxSym) >>> J = symbols('J', cls=sympy.IndexedBase) >>> def Sig(i): ... return OperatorSymbol( ... StrLabel(sympy.Indexed('sigma', i)), hs=tls) >>> H = - Sum(i, tls)(Sum(j, tls)( ... J[i, j] * Sig(i) * Sig(j))) >>> unicode(H) '- (∑_{i,j ∈ ℌₛ} J_ij σ̂_i^(s) σ̂_j^(s))'
We can transform this into a classical Hamiltonian by replacing the operators with scalars:
>>> H_classical = H.apply_rule( ... pattern(OperatorSymbol, wc('label', head=StrLabel)), ... lambda label: label.expr * IdentityOperator) >>> unicode(H_classical) '- (∑_{i,j ∈ ℌₛ} J_ij σ_i σ_j)'
-
rebuild
()[source]¶ Recursively re-instantiate the expression
This is generally used within a managed context such as
extra_rules()
,extra_binary_rules()
, orno_rules()
.
-
free_symbols
¶ Set of free SymPy symbols contained within the expression.
-
bound_symbols
¶ Set of bound SymPy symbols in the expression
-
all_symbols
¶ Combination of
free_symbols
andbound_symbols
- instance_caching (bool) – Flag to indicate whether the
-
qnet.algebra.core.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.
-
class
qnet.algebra.core.abstract_algebra.
Operation
(*operands, **kwargs)[source]¶ Bases:
qnet.algebra.core.abstract_algebra.Expression
Base class for “operations”
Operations are 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
-