def test_sympify_scalar(braket): """Test that ScalarValue can be converted to sympy""" two = ScalarValue.create(2) half = sympify(1) / 2 assert One / 2 == half alpha = symbols('alpha') assert sympify(two) == sympify(2) assert sympify(ScalarValue.create(alpha)) == alpha with pytest.raises(SympifyError): sympify(braket)
def test_scalar_invariant_create(braket): """Test that `ScalarValue.create` is invariant w.r.t existing scalars""" three = ScalarValue(3) assert ScalarValue.create(3) == three == 3 assert ScalarValue.create(three) is three assert ScalarValue.create(braket) is braket assert ScalarValue.create(One) is One assert ScalarValue.create(Zero) is Zero with pytest.raises(TypeError): ScalarValue(ScalarValue(3))
def sqrt(scalar): """Square root of a :class:`.Scalar` or scalar value. This always returns a :class:`Scalar`, and uses a symbolic square root if possible (i.e., for non-floats):: >>> sqrt(2) sqrt(2) >>> sqrt(2.0) 1.414213... For a :class:`ScalarExpression` argument, it returns a :class:`ScalarPower` instance:: >>> braket = KetSymbol('Psi', hs=0).dag() * KetSymbol('Phi', hs=0) >>> nrm = sqrt(braket * braket.dag()) >>> print(srepr(nrm, indented=True)) ScalarPower( ScalarTimes( BraKet( KetSymbol( 'Phi', hs=LocalSpace( '0')), KetSymbol( 'Psi', hs=LocalSpace( '0'))), BraKet( KetSymbol( 'Psi', hs=LocalSpace( '0')), KetSymbol( 'Phi', hs=LocalSpace( '0')))), ScalarValue( Rational(1, 2))) """ if isinstance(scalar, ScalarValue): scalar = scalar.val if scalar == 1: return One elif scalar == 0: return Zero elif isinstance(scalar, (float, complex, complex128, float64)): return ScalarValue.create(numpy.sqrt(scalar)) elif isinstance(scalar, (int, sympy.Basic, int64)): return ScalarValue.create(sympy.sqrt(scalar)) elif isinstance(scalar, Scalar): return scalar ** (_sympyOne / 2) else: raise TypeError("Unknown type of scalar: %r" % type(scalar))
def test_one(): """Test use of the scalar One""" alpha = ScalarValue(symbols('alpha')) expr = alpha * One assert expr == alpha expr = alpha * 1 assert expr == alpha expr = alpha / alpha assert expr is One assert expr == 1 assert hash(expr) == hash(1) assert ScalarValue.create(1) is One assert ScalarValue(1) == One assert sympify(1) == One assert One == sympify(1) assert 1 == One assert One == 1 assert 1 + 0j == One assert One.val == 1 assert len(One.args) == 0 assert One.adjoint() == One.conjugate() == One
def test_zero(): """Test use of the scalar Zero""" alpha = ScalarValue(symbols('alpha')) expr = alpha - alpha assert expr is Zero assert expr == 0 assert hash(expr) == hash(0) expr = alpha + Zero assert expr == alpha expr = alpha + 0 assert expr == alpha assert ScalarValue.create(0) is Zero assert ScalarValue(0) == Zero assert sympify(0) == Zero assert Zero == sympify(0) assert 0 == Zero assert Zero == 0 assert 0j == Zero assert Zero.val == 0 assert len(Zero.args) == 0 assert Zero.adjoint() == Zero.conjugate() == Zero
def _extract_delta(expr, idx): """Extract a "simple" Kronecker delta containing `idx` from `expr`. Assuming `expr` can be written as the product of a Kronecker Delta and a `new_expr`, return a tuple of the sympy.KroneckerDelta instance and `new_expr`. Otherwise, return a tuple of None and the original `expr` (possibly converted to a :class:`.QuantumExpression`). On input, `expr` can be a :class:`QuantumExpression` or a :class:`sympy.Basic` object. On output, `new_expr` is guaranteed to be a :class:`QuantumExpression`. """ from qalgebra.core.abstract_quantum_algebra import QuantumExpression from qalgebra.core.scalar_algebra import ScalarValue sympy_factor, quantum_factor = _split_sympy_quantum_factor(expr) delta, new_expr = _sympy_extract_delta(sympy_factor, idx) if delta is None: new_expr = expr else: new_expr = new_expr * quantum_factor if isinstance(new_expr, ScalarValue._val_types): new_expr = ScalarValue.create(new_expr) assert isinstance(new_expr, QuantumExpression) return delta, new_expr
def __init__(self, label, *sym_args, hs): from qalgebra.core.scalar_algebra import ScalarValue self._label = label sym_args = [ScalarValue.create(arg) for arg in sym_args] self._sym_args = tuple(sym_args) if isinstance(label, str): if not self._rx_label.match(label): raise ValueError( "label '%s' does not match pattern '%s'" % (label, self._rx_label.pattern) ) elif isinstance(label, SymbolicLabelBase): self._label = label else: raise TypeError( "type of label must be str or SymbolicLabelBase, not %s" % type(label) ) if isinstance(hs, (str, int)): hs = self._default_hs_cls(hs) elif isinstance(hs, tuple): hs = ProductSpace.create(*[self._default_hs_cls(h) for h in hs]) self._hs = hs super().__init__(label, *sym_args, hs=hs)
def __init__(self, coeff, term): from qalgebra.core.scalar_algebra import Scalar, ScalarValue if not isinstance(coeff, Scalar): coeff = ScalarValue.create(coeff) self._order_coeff = coeff self._order_args = KeyTuple([term._order_key]) super().__init__(coeff, term)
def __mul__(self, other): from qalgebra.core.scalar_algebra import ScalarValue, is_scalar if not isinstance(other, self._base_cls): if is_scalar(other): other = ScalarValue.create(other) # if other was an ScalarExpression, the conversion above leaves # it unchanged return self.__class__._scalar_times_expr_cls.create( other, self ) if isinstance(other, self.__class__._base_cls): return self.__class__._times_cls.create(self, other) else: return NotImplemented
def terms(self): """Iterator over the terms of the sum. Yield from the (possibly) infinite list of terms of the indexed sum, if the sum was written out explicitly. Each yielded term in an instance of :class:`.Expression` """ from qalgebra.core.scalar_algebra import ScalarValue for mapping in yield_from_ranges(self.ranges): term = self.term.substitute(mapping) if isinstance(term, ScalarValue._val_types): term = ScalarValue.create(term) assert isinstance(term, Expression) yield term
def test_scalar_times_expr_conversion(braket): """Test that the coefficient in ScalarTimesQuantumExpression is a Scalar, and that Scalar times QuantumExpression is ScalarTimesQantumExpression""" # We test with with a ScalarTimesOperator, but this will work for any # ScalarTimesQuantumExpression A = OperatorSymbol("A", hs=0) alpha = symbols('alpha') for coeff in (0.5, alpha / 2, braket, ScalarValue.create(alpha)): for expr in (coeff * A, A * coeff): assert isinstance(expr, ScalarTimesOperator) assert isinstance(expr.coeff, Scalar) assert expr.coeff == coeff assert One * A == A assert A * One == A assert Zero * A is ZeroOperator assert A * Zero is ZeroOperator
def KroneckerDelta(i, j, simplify=True): """Kronecker delta symbol. Return :class:`One` (`i` equals `j`)), :class:`Zero` (`i` and `j` are non-symbolic an unequal), or a :class:`ScalarValue` wrapping SymPy's :class:`~sympy.functions.special.tensor_functions.KroneckerDelta`. >>> i, j = IdxSym('i'), IdxSym('j') >>> KroneckerDelta(i, i) One >>> KroneckerDelta(1, 2) Zero >>> KroneckerDelta(i, j) KroneckerDelta(i, j) By default, the Kronecker delta is returned in a simplified form, e.g:: >>> KroneckerDelta((i+1)/2, (j+1)/2) KroneckerDelta(i, j) This may be suppressed by setting `simplify` to False:: >>> KroneckerDelta((i+1)/2, (j+1)/2, simplify=False) KroneckerDelta(i/2 + 1/2, j/2 + 1/2) Raises: TypeError: if `i` or `j` is not an integer or sympy expression. There is no automatic sympification of `i` and `j`. """ from qalgebra.core.scalar_algebra import One, ScalarValue if not isinstance(i, (int, sympy.Basic)): raise TypeError( "i is not an integer or sympy expression: %s" % type(i) ) if not isinstance(j, (int, sympy.Basic)): raise TypeError( "j is not an integer or sympy expression: %s" % type(j) ) if i == j: return One else: delta = sympy.KroneckerDelta(i, j) if simplify: delta = _simplify_delta(delta) return ScalarValue.create(delta)
def test_scalar_numeric_methods(braket): """Test all of the numerical magic methods for scalars""" three = ScalarValue(3) two = ScalarValue(2) spOne = sympify(1) spZero = sympify(0) spHalf = spOne / 2 assert three == 3 assert three == three assert three != symbols('alpha') assert three <= 3 assert three <= ScalarValue(4) assert three >= 3 assert three >= ScalarValue(2) assert three < 3.1 assert three < ScalarValue(4) assert three > ScalarValue(2) assert three == sympify(3) assert three <= sympify(3) assert three >= sympify(3) assert three < sympify(3.1) assert three > sympify(2.9) with pytest.raises(TypeError): assert three < symbols('alpha') with pytest.raises(TypeError): assert three <= symbols('alpha') with pytest.raises(TypeError): assert three > symbols('alpha') with pytest.raises(TypeError): assert three >= symbols('alpha') assert hash(three) == hash(3) v = -three assert v == -3 assert isinstance(v, ScalarValue) v = three + 1 assert v == 4 assert isinstance(v, ScalarValue) v = three + two assert v == 5 assert isinstance(v, ScalarValue) v = three + Zero assert v is three assert three + spZero == three v = three + One assert v == 4 assert isinstance(v, ScalarValue) assert three + spOne == 4 v = abs(ScalarValue(-3)) assert v == 3 assert isinstance(v, ScalarValue) v = three - 4 assert v == -1 assert isinstance(v, ScalarValue) v = three - two assert v == 1 assert v is One v = three - Zero assert v is three assert three - spZero == three v = three - One assert v == 2 assert isinstance(v, ScalarValue) assert three - spOne == 2 v = three * 2 assert v == 6 assert isinstance(v, ScalarValue) v = three * two assert v == 6 assert isinstance(v, ScalarValue) v = three * Zero assert v == 0 assert v is Zero assert three * spZero is Zero v = three * One assert v is three assert three * spOne == three v = three // 2 assert v is One assert ScalarValue(3.5) // 1 == 3.0 v = three // two assert v is One v = three // One assert v == three assert three // spOne == three with pytest.raises(ZeroDivisionError): v = three // Zero with pytest.raises(ZeroDivisionError): v = three // spZero with pytest.raises(ZeroDivisionError): v = three // 0 v = three / 2 assert v == 3 / 2 assert isinstance(v, ScalarValue) v = three / two assert v == 3 / 2 assert isinstance(v, ScalarValue) v = three / One assert v is three assert three / spOne == three with pytest.raises(ZeroDivisionError): v = three / Zero with pytest.raises(ZeroDivisionError): v = three / spZero with pytest.raises(ZeroDivisionError): v = three / 0 v = three % 2 assert v is One assert three % 0.2 == 3 % 0.2 v = three % two assert v is One v = three % One assert v is Zero assert three % spOne is Zero with pytest.raises(ZeroDivisionError): v = three % Zero with pytest.raises(ZeroDivisionError): v = three % spZero with pytest.raises(ZeroDivisionError): v = three % 0 v = three**2 assert v == 9 assert isinstance(v, ScalarValue) v = three**two assert v == 9 assert isinstance(v, ScalarValue) v = three**One assert v is three assert three**spOne == three v = three**Zero assert v is One assert three**spZero is One v = 1 + three assert v == 4 assert isinstance(v, ScalarValue) v = two + three assert v == 5 assert isinstance(v, ScalarValue) v = sympify(2) + three assert v == 5 assert isinstance(v, SympyBasic) v = 2.0 + three assert v == 5 assert isinstance(v, ScalarValue) v = Zero + three assert v is three with pytest.raises(TypeError): None + three assert spZero + three == three v = One + three assert v == 4 assert isinstance(v, ScalarValue) assert spOne + three == 4 v = 1 - three assert v == -2 assert isinstance(v, ScalarValue) v = two - three assert v == -1 assert isinstance(v, ScalarValue) v = 2.0 - three assert v == -1 assert isinstance(v, ScalarValue) v = sympify(2) - three assert v == -1 assert isinstance(v, SympyBasic) v = Zero - three assert v == -3 assert isinstance(v, ScalarValue) with pytest.raises(TypeError): None - three assert spZero - three == -3 v = One - three assert v == -2 assert isinstance(v, ScalarValue) assert spOne - three == -2 v = 2 * three assert v == 6 assert isinstance(v, ScalarValue) v = Zero * three assert v == 0 assert v is Zero v = spZero * three assert v == Zero assert isinstance(v, SympyBasic) v = One * three assert v is three assert spOne * three == three with pytest.raises(TypeError): None * three v = 2 // three assert v is Zero v = two // three assert v is Zero v = One // three assert v is Zero v = spOne // three assert v == Zero assert isinstance(v, SympyBasic) v = Zero // three assert v is Zero v = spZero // three assert v == Zero assert isinstance(v, SympyBasic) v = 1 // three assert v is Zero with pytest.raises(TypeError): None // three v = 2 / three assert float(v) == 2 / 3 assert v == Rational(2, 3) assert isinstance(v, ScalarValue) v = two / three assert v == 2 / 3 assert isinstance(v, ScalarValue) v = One / three assert v == 1 / 3 assert isinstance(v, ScalarValue) v = 1 / three assert v == Rational(1, 3) assert isinstance(v, ScalarValue) assert float(spOne / three) == 1 / 3 v = Zero / three assert v is Zero v = spZero / three assert v == Zero assert isinstance(v, SympyBasic) with pytest.raises(TypeError): None / three v = 2**three assert v == 8 assert isinstance(v, ScalarValue) v = 0**three assert v is Zero v = two**three assert v == 8 assert isinstance(v, ScalarValue) v = One**three assert v is One with pytest.raises(TypeError): None**three v = 1**three assert v is One v = One**spHalf assert v is One v = spOne**three assert v == One assert isinstance(v, SympyBasic) v = Zero**three assert v is Zero v = spZero**three assert v == Zero assert isinstance(v, SympyBasic) v = complex(three) assert v == 3 + 0j assert isinstance(v, complex) v = int(ScalarValue(3.45)) assert v == 3 assert isinstance(v, int) v = float(three) assert v == 3.0 assert isinstance(v, float) assert Zero == 0 assert Zero != symbols('alpha') assert Zero <= One assert Zero <= three assert Zero >= Zero assert Zero >= -three assert Zero < One assert Zero < three assert Zero > -One assert Zero > -three assert Zero == spZero assert Zero <= spZero assert Zero >= spZero assert Zero < spOne assert Zero > -spOne with pytest.raises(TypeError): assert Zero < symbols('alpha') with pytest.raises(TypeError): assert Zero <= symbols('alpha') with pytest.raises(TypeError): assert Zero > symbols('alpha') with pytest.raises(TypeError): assert Zero >= symbols('alpha') assert hash(Zero) == hash(0) assert abs(Zero) is Zero assert abs(One) is One assert abs(ScalarValue(-1)) is One assert -Zero is Zero v = -One assert v == -1 assert isinstance(v, ScalarValue) assert Zero + One is One assert One + Zero is One assert Zero + Zero is Zero assert Zero - Zero is Zero assert One + One == 2 assert One - One is Zero v = Zero + 2 assert v == 2 assert isinstance(v, ScalarValue) v = Zero - One assert v == -1 assert isinstance(v, ScalarValue) v = Zero - 5 assert v == -5 assert isinstance(v, ScalarValue) v = 2 + Zero assert v == 2 assert isinstance(v, ScalarValue) v = 2 - Zero assert v == 2 assert isinstance(v, ScalarValue) v = sympify(2) + Zero assert v == 2 assert isinstance(v, SympyBasic) v = sympify(2) - Zero assert v == 2 assert isinstance(v, SympyBasic) v = One + 2 assert v == 3 assert isinstance(v, ScalarValue) v = 2 + One assert v == 3 assert isinstance(v, ScalarValue) v = 2 - One assert v is One v = 3 - One assert v == 2 assert isinstance(v, ScalarValue) v = One - 3 assert v == -2 assert isinstance(v, ScalarValue) v = sympify(2) + One assert v == 3 assert isinstance(v, SympyBasic) v = sympify(2) - One assert v == 1 assert isinstance(v, SympyBasic) v = sympify(3) - One assert v == 2 assert isinstance(v, SympyBasic) with pytest.raises(TypeError): None + Zero with pytest.raises(TypeError): None - Zero with pytest.raises(TypeError): None + One with pytest.raises(TypeError): None - One alpha = symbols('alpha') assert Zero * alpha is Zero v = alpha * Zero assert v == Zero assert isinstance(v, SympyBasic) assert 3 * Zero is Zero with pytest.raises(TypeError): None * Zero assert Zero * alpha is Zero assert Zero // 3 is Zero assert One // 1 is One assert One / 1 is One assert One == 1 assert One != symbols('alpha') assert One <= One assert One <= three assert One >= Zero assert One >= -three assert One < three assert One > -three assert One == spOne assert One <= spOne assert One >= spOne assert One < sympify(3) assert One > -sympify(3) with pytest.raises(TypeError): assert One < symbols('alpha') with pytest.raises(TypeError): assert One <= symbols('alpha') with pytest.raises(TypeError): assert One > symbols('alpha') with pytest.raises(TypeError): assert One >= symbols('alpha') with pytest.raises(ZeroDivisionError): One // 0 with pytest.raises(ZeroDivisionError): One / 0 with pytest.raises(TypeError): One // None with pytest.raises(TypeError): One / None with pytest.raises(ZeroDivisionError): 3 // Zero with pytest.raises(TypeError): Zero // None with pytest.raises(TypeError): None // Zero assert Zero / 3 is Zero with pytest.raises(TypeError): Zero / None assert Zero % 3 is Zero assert Zero % three is Zero with pytest.raises(TypeError): assert Zero % None assert One % 3 is One assert One % three is One assert three % One is Zero assert 3 % One is Zero with pytest.raises(TypeError): None % 3 v = sympify(3) % One assert v == 0 assert isinstance(v, SympyBasic) with pytest.raises(TypeError): assert One % None with pytest.raises(TypeError): assert None % One assert Zero**2 is Zero assert Zero**spHalf is Zero with pytest.raises(TypeError): Zero**None with pytest.raises(ZeroDivisionError): v = Zero**-1 with pytest.raises(ZeroDivisionError): v = 1 / Zero v = spOne / Zero assert v == sympy_infinity with pytest.raises(ZeroDivisionError): v = 1 / Zero assert One - Zero is One assert Zero * One is Zero assert One * Zero is Zero with pytest.raises(ZeroDivisionError): v = 3 / Zero with pytest.raises(ZeroDivisionError): v = 3 % Zero v = 3 / One assert v == 3 assert isinstance(v, ScalarValue) v = 3 % One assert v is Zero v = 1 % three assert v is One v = spOne % three assert v == 1 assert isinstance(v, SympyBasic) v = sympify(2) % three assert v == 2 with pytest.raises(TypeError): None % three assert 3**Zero is One v = 3**One assert v == 3 assert isinstance(v, ScalarValue) v = complex(Zero) assert v == 0j assert isinstance(v, complex) v = int(Zero) assert v == 0 assert isinstance(v, int) v = float(Zero) assert v == 0.0 assert isinstance(v, float) v = complex(One) assert v == 1j assert isinstance(v, complex) v = int(One) assert v == 1 assert isinstance(v, int) v = float(One) assert v == 1.0 assert isinstance(v, float) assert braket**Zero is One assert braket**0 is One assert braket**One is braket assert braket**1 is braket v = 1 / braket assert v == braket**(-1) assert isinstance(v, ScalarPower) assert v.base == braket assert v.exp == -1 v = three * braket assert isinstance(v, ScalarTimes) assert v == braket * 3 assert v == braket * sympify(3) assert v == 3 * braket assert v == sympify(3) * braket assert braket * One is braket assert braket * Zero is Zero assert One * braket is braket assert Zero * braket is Zero assert spOne * braket is braket assert spZero * braket is Zero with pytest.raises(TypeError): braket // 3 with pytest.raises(TypeError): braket % 3 with pytest.raises(TypeError): 1 // braket with pytest.raises(TypeError): 3 % braket with pytest.raises(TypeError): 3**braket assert 0**braket is Zero assert 1**braket is One assert spZero**braket is Zero assert spOne**braket is One assert One**braket is One assert 0 // braket is Zero assert 0 / braket is Zero assert 0 % braket is Zero with pytest.raises(ZeroDivisionError): assert 0 / Zero with pytest.raises(ZeroDivisionError): assert 0 / ScalarValue.create(0) assert 0 / ScalarValue(0) == sympy.nan A = OperatorSymbol('A', hs=0) v = A / braket assert isinstance(v, ScalarTimesOperator) assert v.coeff == braket**-1 assert v.term == A with pytest.raises(TypeError): v = None / braket assert braket / three == (1 / three) * braket == (spOne / 3) * braket assert braket / 3 == (1 / three) * braket v = braket / 0.25 assert v == 4 * braket # 0.25 and 4 are exact floats assert braket / sympify(3) == (1 / three) * braket assert 3 / braket == 3 * braket**-1 assert three / braket == 3 * braket**-1 assert spOne / braket == braket**-1 braket2 = BraKet.create(KetSymbol("Chi", hs=0), KetSymbol("Psi", hs=0)) v = braket / braket2 assert v == braket * braket2**-1 with pytest.raises(ZeroDivisionError): braket / Zero with pytest.raises(ZeroDivisionError): braket / 0 with pytest.raises(ZeroDivisionError): braket / sympify(0) assert braket / braket is One with pytest.raises(TypeError): braket / None v = 1 + braket assert v == braket + 1 assert isinstance(v, Scalar) v = One + braket assert v == braket + One assert isinstance(v, Scalar) assert Zero + braket is braket assert spZero + braket is braket assert braket + Zero is braket assert braket + spZero is braket assert 0 + braket is braket assert braket + 0 is braket assert (-1) * braket == -braket assert Zero - braket == -braket assert spZero - braket == -braket assert braket - Zero is braket assert braket - spZero is braket assert 0 - braket == -braket assert braket - 0 is braket assert sympify(3) - braket == 3 - braket
def create(cls, coeff, term): from qalgebra.core.scalar_algebra import Scalar, ScalarValue if not isinstance(coeff, Scalar): coeff = ScalarValue.create(coeff) return super().create(coeff, term)
def sum(term): if isinstance(term, ScalarValue._val_types): term = ScalarValue.create(term) idx_range = idx_range_func(term, idx, *args, **kwargs) return term._indexed_sum_cls.create(term, ranges=(idx_range,))