Symbolic Parameters¶
ParityOS supports symbolic parameters as placeholders for numerical values. They can be used e.g. as angles in rotation operators, coefficients in OperatorPolynomials, amplitudes in QuantumStates or appear in Circuits with parameterized gates.
Classes that support symbolic parameters implement the Parameterized interface, which supplies:
A
parametersattribute, returning all symbolic parameters of this objectA
substitute_parametersmethod that allows for replacing individual symbolic parameters with numerical values or other symbolic expressions
ParityOS represents symbolic expressions through:
Parameter: An atomic, named symbol, that acts as a symbolic variable. They are always assumed to be real and finite.ParameterExpression: A mathematical expression containing one or more symbolicParameters. They are constructed from arithmetic operations on individualParameters.
Complex symbolic expressions can be constructed by involving the complex unit 1j in mathematical expressions.
Symbolic parameters use SymPy as symbolic engine backend.
Assumptions¶
Parameters and ParameterExpressions support assumptions through the Assumptions interface. Refer to the class documentation for a full list of supported assumptions, which is a subset of all currently supported SymPy assumption predicates.
Parameters use ParameterAssumptions, which fix real = True and finite = True. The assumptions of ParameterExpressions are automatically deduced from its constituent Parameters and their mathematical relations.
Assumption predicates are None per default, unless explicitly given or an automatic consequence of other assumptions (e.g. positive = True automatically entails zero = False, nonzero = True and negative = False).
Note
SymPy supports the following numerical tower integer <: rational <: real <: complex where <: means “is a subtype of”. That means every well defined number is considered complex. Strictly complex symbols with a non-zero imaginary part are therefore marked with real = False.
Parameters¶
A Parameter represents an atomic, named, symbolic variable similar to sympy.Symbol. It is uniquely defined by its:
name: A descriptive name of this symbolic variable, e.g."alpha".assumptions: The assumptions on this variable in form of aParameterAssumptionsobject.
Elements of the set returned by the parameters property of Parameterized objects are of this type.
Note
Parameters are always real and finite.
from parityos.bits import Qubit
from parityos.operators.rotation_operator import RX
from parityos.utils.parameter import Parameter, ParameterAssumptions
phi = Parameter("phi", ParameterAssumptions(positive=True))
# fixed
assert phi.assumptions.real
assert phi.assumptions.finite
# deduced
assert phi.assumptions.zero is False
assert phi.assumptions.negative is False
# undefined
assert phi.assumptions.rational is None
assert phi.assumptions.irrational is None
assert phi.assumptions.integer is None
assert phi.assumptions.even is None
assert phi.assumptions.odd is None
# Parameters with same name, but different assumptions are considered different
phi_neg = Parameter("phi", ParameterAssumptions(negative=True))
assert phi.name == phi_neg.name
assert phi != phi_neg
# phi as symbolic angle in a rotation
rx = RX(Qubit(0), phi)
assert rx.parameters == {phi}
# substitute symbolic parameter with a numerical value
rx_num = rx.substitute_parameters({phi: -2})
assert rx_num.angle == -2
assert not rx_num.parameters
Parameter Expressions¶
A ParameterExpression represents a mathematical expression involving one or more symbolic Parameters. They are uniquely defined by their underlying expr of type sympy.Expr (which also contains all assumptions).
Note
While ParameterExpressions can be constructed from a sympy.Expr, it is easier and more natural to create them from arithmetic operations on individual Parameters.
from parityos.utils.parameter import Parameter, ParameterAssumptions, ParameterExpression
a = Parameter("a")
b = Parameter("b")
c = Parameter("c", ParameterAssumptions(nonzero=True))
# If `c` were not assumed to be nonzero, `expr`'s assumptions would all be undefined
# (as `c` could be zero, turning `expr` into an undefined expression)
expr = (a**2 - 2 * b) / c
assert isinstance(expr, ParameterExpression)
assert expr.parameters == {a, b, c}
# deduced
assert expr.assumptions.real
assert expr.assumptions.finite
# undefined
assert expr.assumptions.zero is None
assert expr.assumptions.nonzero is None
assert expr.assumptions.positive is None
assert expr.assumptions.negative is None
assert expr.assumptions.rational is None
assert expr.assumptions.irrational is None
assert expr.assumptions.integer is None
assert expr.assumptions.even is None
assert expr.assumptions.odd is None
# a complex expression (`c` is guaranteed to be nonzero)
z = a + 1j * c
assert isinstance(z, ParameterExpression)
assert z.assumptions.real is False
assert z.assumptions.finite
assert z.assumptions.zero is False # at least the imaginary part is nonzero
assert z.assumptions.positive is False # not defined for complex numbers
assert z.assumptions.negative is False # not defined for complex numbers
# being complex automatically turns these False
assert z.assumptions.rational is False
assert z.assumptions.irrational is False
assert z.assumptions.integer is False
assert z.assumptions.even is False
assert z.assumptions.odd is False
# substitute
assert expr.substitute_parameters({a: 2, b: 2, c: 100}) == 0 # pure numerical result
assert expr.substitute_parameters({a: 3, b: 2 * a, c: -1}) == 4 * a - 9 # symbolic result
Mathematical Functions¶
ParityOS combines numerical and symbolic numbers into a Coefficient type. To simplify applications of mathematical functions (such as e.g. sqrt, exp, log, tan, etc.) on Coefficients, a set of common functions is defined in the module parityos.utils.functions in a generalized form. They are callable objects that forward the input argument either to the corresponding built-in numeric or sympy function (which is applied to the underlying sympy expr of the parameter expression).
Assumptions are also updated accordingly when applying functions to symbolic expressions.
Refer to parityos.utils.functions for all currently supported generalized functions.
from parityos.utils.functions import exp, log, sqrt
from parityos.utils.parameter import Parameter, ParameterAssumptions
a = Parameter("a")
b = Parameter("b", ParameterAssumptions(positive=True))
# mixed application
e = exp(2 * a) / sqrt(2)
# log and exp are inverse to each other
assert log(exp(2 * a)) == 2 * a
# exponentials of real finite numbers are always positive
assert exp(a).assumptions.positive
# realness not defined, as `a` could be negative
assert sqrt(a).assumptions.real is None
# `b` is positive, and so is its square root
assert sqrt(b).assumptions.real
assert sqrt(b).assumptions.positive