qalgebra.core.algebraic_properties module

Summary

Functions:

accept_bras

Accept operands that are all bras, and turn that into to bra of the operation applied to all corresponding kets

assoc

Associatively expand out nested arguments of the flat class.

assoc_indexed

Flatten nested indexed structures while pulling out prefactors.

basis_ket_zero_outside_hs

For BasisKet.create(ind, hs) with an integer label ind, return a ZeroKet if ind is outside of the range of the underlying Hilbert space

check_cdims

Check that all operands (ops) have equal channel dimension.

collect_scalar_summands

Collect ScalarValue and ScalarExpression summands.

collect_summands

Collect summands that occur multiple times into a single summand

commutator_order

Apply anti-commutative property of the commutator to apply a standard ordering of the commutator arguments

convert_to_scalars

Convert any entry in ops that is not a Scalar instance into a ScalarValue instance

convert_to_spaces

Allow for str, int as LocalSpace shorthand.

delegate_to_method

Create a simplification rule that delegates the instantiation to the method mtd of the operand (if defined)

derivative_via_diff

Delegate QuantumDerivative.create() to the _diff method.

disjunct_hs_zero

Return ZeroOperator if all the operators in ops have a disjunct Hilbert space, or an unchanged ops, kwargs otherwise

empty_trivial

A ProductSpace of zero Hilbert spaces should yield the TrivialSpace.

filter_neutral

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.::.

idem

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

implied_local_space

Return a simplification that converts the positional argument arg_index from (str, int) to a subclass of LocalSpace, as well as any keyword argument with one of the given keys.

indexed_sum_over_const

Execute an indexed sum over a term that does not depend on the summation indices.

indexed_sum_over_kronecker

Execute sums over KroneckerDelta prefactors

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.

orderby

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

scalars_to_op

Convert any scalar \(\alpha\) in ops into an operator $alpha identity$

Reference

qalgebra.core.algebraic_properties.assoc(cls, ops, kwargs)[source]

Associatively expand out nested arguments of the flat class.

For example:

>>> class Plus(Operation):
...     simplifications = [assoc, ]
>>> Plus.create(1,Plus(2,3))
Plus(1, 2, 3)
qalgebra.core.algebraic_properties.assoc_indexed(cls, ops, kwargs)[source]

Flatten nested indexed structures while pulling out prefactors.

For example, for an IndexedSum:

\[\sum_j \left( a \sum_i \dots \right) = a \sum_{j, i} \dots\]
qalgebra.core.algebraic_properties.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)
qalgebra.core.algebraic_properties.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)
qalgebra.core.algebraic_properties.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)
qalgebra.core.algebraic_properties.collect_summands(cls, ops, kwargs)[source]

Collect summands that occur multiple times into a single summand

Also filters out zero-summands.

Example

>>> A, B, C = (OperatorSymbol(s, hs=0) for s in ('A', 'B', 'C'))
>>> collect_summands(
...     OperatorPlus, (A, B, C, ZeroOperator, 2 * A, B, -C) , {})
((3 * A^(0), 2 * B^(0)), {})
>>> collect_summands(OperatorPlus, (A, -A), {})
ZeroOperator
>>> collect_summands(OperatorPlus, (B, A, -B), {})
A^(0)
qalgebra.core.algebraic_properties.collect_scalar_summands(cls, ops, kwargs)[source]

Collect ScalarValue and ScalarExpression summands.

Example::
>>> srepr(collect_scalar_summands(Scalar, (1, 2, 3), {}))
'ScalarValue(6)'
>>> collect_scalar_summands(Scalar, (1, 1, -1), {})
One
>>> collect_scalar_summands(Scalar, (1, -1), {})
Zero
>>> Psi = KetSymbol("Psi", hs=0)
>>> Phi = KetSymbol("Phi", hs=0)
>>> braket = BraKet.create(Psi, Phi)
>>> collect_scalar_summands(Scalar, (1, braket, -1), {})
<Psi|Phi>^(0)
>>> collect_scalar_summands(Scalar, (1, 2 * braket, 2, 2 * braket), {})
((3, 4 * <Psi|Phi>^(0)), {})
>>> collect_scalar_summands(Scalar, (2 * braket, -braket, -braket), {})
Zero
qalgebra.core.algebraic_properties.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:

>>> 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
qalgebra.core.algebraic_properties.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.

qalgebra.core.algebraic_properties.check_cdims(cls, ops, kwargs)[source]

Check that all operands (ops) have equal channel dimension.

qalgebra.core.algebraic_properties.convert_to_spaces(cls, ops, kwargs)[source]

Allow for str, int as LocalSpace shorthand.

For all operands that are merely of type str or int, substitute LocalSpace objects with corresponding labels: For a string, just itself, for an int, a string version of that int.

qalgebra.core.algebraic_properties.empty_trivial(cls, ops, kwargs)[source]

A ProductSpace of zero Hilbert spaces should yield the TrivialSpace.

qalgebra.core.algebraic_properties.implied_local_space(*, arg_index=None, keys=None)[source]

Return a simplification that converts the positional argument arg_index from (str, int) to a subclass of LocalSpace, as well as any keyword argument with one of the given keys.

The exact type of the resulting Hilbert space is determined by the default_hs_cls argument of init_algebra().

In many cases, we have implied_local_space() (in create) in addition to a conversion in __init__, so that match_replace() etc can rely on the relevant arguments being a HilbertSpace instance.

qalgebra.core.algebraic_properties.delegate_to_method(mtd)[source]

Create a simplification rule that delegates the instantiation to the method mtd of the operand (if defined)

qalgebra.core.algebraic_properties.scalars_to_op(cls, ops, kwargs)[source]

Convert any scalar \(\alpha\) in ops into an operator $alpha identity$

qalgebra.core.algebraic_properties.convert_to_scalars(cls, ops, kwargs)[source]

Convert any entry in ops that is not a Scalar instance into a ScalarValue instance

qalgebra.core.algebraic_properties.disjunct_hs_zero(cls, ops, kwargs)[source]

Return ZeroOperator if all the operators in ops have a disjunct Hilbert space, or an unchanged ops, kwargs otherwise

qalgebra.core.algebraic_properties.commutator_order(cls, ops, kwargs)[source]

Apply anti-commutative property of the commutator to apply a standard ordering of the commutator arguments

qalgebra.core.algebraic_properties.accept_bras(cls, ops, kwargs)[source]

Accept operands that are all bras, and turn that into to bra of the operation applied to all corresponding kets

qalgebra.core.algebraic_properties.basis_ket_zero_outside_hs(cls, ops, kwargs)[source]

For BasisKet.create(ind, hs) with an integer label ind, return a ZeroKet if ind is outside of the range of the underlying Hilbert space

qalgebra.core.algebraic_properties.indexed_sum_over_const(cls, ops, kwargs)[source]

Execute an indexed sum over a term that does not depend on the summation indices.

\[\sum_{j=1}^{N} a = N a\]
>>> a = symbols('a')
>>> i, j  = (IdxSym(s) for s in ('i', 'j'))
>>> unicode(Sum(i, 1, 2)(a))
'2 a'
>>> unicode(Sum(j, 1, 2)(Sum(i, 1, 2)(a * i)))
'∑_{i=1}^{2} 2 i a'
qalgebra.core.algebraic_properties.indexed_sum_over_kronecker(cls, ops, kwargs)[source]

Execute sums over KroneckerDelta prefactors

qalgebra.core.algebraic_properties.derivative_via_diff(cls, ops, kwargs)[source]

Delegate QuantumDerivative.create() to the _diff method.

Thus, by having QuantumExpression.diff() delegate to QuantumDerivative.create(), instead of the _diff method directly, we get automatic caching of derivatives