ai-content-maker/.venv/Lib/site-packages/sympy/stats/tests/test_stochastic_process.py

764 lines
38 KiB
Python

from sympy.concrete.summations import Sum
from sympy.core.containers import Tuple
from sympy.core.function import Lambda
from sympy.core.numbers import (Float, Rational, oo, pi)
from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.exponential import exp
from sympy.functions.elementary.integers import ceiling
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.piecewise import Piecewise
from sympy.functions.special.error_functions import erf
from sympy.functions.special.gamma_functions import (gamma, lowergamma)
from sympy.logic.boolalg import (And, Not)
from sympy.matrices.dense import Matrix
from sympy.matrices.expressions.matexpr import MatrixSymbol
from sympy.matrices.immutable import ImmutableMatrix
from sympy.sets.contains import Contains
from sympy.sets.fancysets import Range
from sympy.sets.sets import (FiniteSet, Interval)
from sympy.stats import (DiscreteMarkovChain, P, TransitionMatrixOf, E,
StochasticStateSpaceOf, variance, ContinuousMarkovChain,
BernoulliProcess, PoissonProcess, WienerProcess,
GammaProcess, sample_stochastic_process)
from sympy.stats.joint_rv import JointDistribution
from sympy.stats.joint_rv_types import JointDistributionHandmade
from sympy.stats.rv import RandomIndexedSymbol
from sympy.stats.symbolic_probability import Probability, Expectation
from sympy.testing.pytest import (raises, skip, ignore_warnings,
warns_deprecated_sympy)
from sympy.external import import_module
from sympy.stats.frv_types import BernoulliDistribution
from sympy.stats.drv_types import PoissonDistribution
from sympy.stats.crv_types import NormalDistribution, GammaDistribution
from sympy.core.symbol import Str
def test_DiscreteMarkovChain():
# pass only the name
X = DiscreteMarkovChain("X")
assert isinstance(X.state_space, Range)
assert X.index_set == S.Naturals0
assert isinstance(X.transition_probabilities, MatrixSymbol)
t = symbols('t', positive=True, integer=True)
assert isinstance(X[t], RandomIndexedSymbol)
assert E(X[0]) == Expectation(X[0])
raises(TypeError, lambda: DiscreteMarkovChain(1))
raises(NotImplementedError, lambda: X(t))
raises(NotImplementedError, lambda: X.communication_classes())
raises(NotImplementedError, lambda: X.canonical_form())
raises(NotImplementedError, lambda: X.decompose())
nz = Symbol('n', integer=True)
TZ = MatrixSymbol('M', nz, nz)
SZ = Range(nz)
YZ = DiscreteMarkovChain('Y', SZ, TZ)
assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1]
raises(ValueError, lambda: sample_stochastic_process(t))
raises(ValueError, lambda: next(sample_stochastic_process(X)))
# pass name and state_space
# any hashable object should be a valid state
# states should be valid as a tuple/set/list/Tuple/Range
sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True)
state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain("Y", (1,2,3))],
Tuple(S(1), exp(sym), Str('World'), sympify=False), Range(-1, 5, 2),
[rainy, cloudy, sunny]]
chains = [DiscreteMarkovChain("Y", state_space) for state_space in state_spaces]
for i, Y in enumerate(chains):
assert isinstance(Y.transition_probabilities, MatrixSymbol)
assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet(*state_spaces[i])
assert Y.number_of_states == 3
with ignore_warnings(UserWarning): # TODO: Restore tests once warnings are removed
assert P(Eq(Y[2], 1), Eq(Y[0], 2), evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2))
assert E(Y[0]) == Expectation(Y[0])
raises(ValueError, lambda: next(sample_stochastic_process(Y)))
raises(TypeError, lambda: DiscreteMarkovChain("Y", {1: 1}))
Y = DiscreteMarkovChain("Y", Range(1, t, 2))
assert Y.number_of_states == ceiling((t-1)/2)
# pass name and transition_probabilities
chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([[]])),
DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])),
DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1-pi], [sym, 1-sym]]))]
for Z in chains:
assert Z.number_of_states == Z.transition_probabilities.shape[0]
assert isinstance(Z.transition_probabilities, ImmutableMatrix)
# pass name, state_space and transition_probabilities
T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]])
TS = MatrixSymbol('T', 3, 3)
Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS)
assert Y.joint_distribution(1, Y[2], 3) == JointDistribution(Y[1], Y[2], Y[3])
raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol))
assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2)
assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) -
(TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2])).simplify() == 0
assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1))
assert P(Eq(YS[3], 3), Eq(YS[1], 1)) == TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2]
TO = Matrix([[0.25, 0.75, 0],[0, 0.25, 0.75],[0.75, 0, 0.25]])
assert P(Eq(Y[3], 2), Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float(0.375, 3)
with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed
assert E(Y[3], evaluate=False) == Expectation(Y[3])
assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3)
TSO = MatrixSymbol('T', 4, 4)
raises(ValueError, lambda: str(P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO))))
raises(TypeError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M')))
raises(ValueError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4)))
raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6)))
raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1)))
# extended tests for probability queries
TO1 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]])
assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)),
Eq(Probability(Eq(Y[0], 0)), Rational(1, 4)) & TransitionMatrixOf(Y, TO1)) == Rational(1, 16)
assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \
Probability(Eq(Y[0], 0))/4
assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) &
StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) &
StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) &
StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) is S.Zero
assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) &
StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) is S.Zero
assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Y[1], 1)) == 0.1*Probability(Eq(Y[0], 0))
# testing properties of Markov chain
TO2 = Matrix([[S.One, 0, 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]])
TO3 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]])
Y2 = DiscreteMarkovChain('Y', trans_probs=TO2)
Y3 = DiscreteMarkovChain('Y', trans_probs=TO3)
assert Y3.fundamental_matrix() == ImmutableMatrix([[176, 81, -132], [36, 141, -52], [-44, -39, 208]])/125
assert Y2.is_absorbing_chain() == True
assert Y3.is_absorbing_chain() == False
assert Y2.canonical_form() == ([0, 1, 2], TO2)
assert Y3.canonical_form() == ([0, 1, 2], TO3)
assert Y2.decompose() == ([0, 1, 2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3])
assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3, []), Matrix(0, 0, []))
TO4 = Matrix([[Rational(1, 5), Rational(2, 5), Rational(2, 5)], [Rational(1, 10), S.Half, Rational(2, 5)], [Rational(3, 5), Rational(3, 10), Rational(1, 10)]])
Y4 = DiscreteMarkovChain('Y', trans_probs=TO4)
w = ImmutableMatrix([[Rational(11, 39), Rational(16, 39), Rational(4, 13)]])
assert Y4.limiting_distribution == w
assert Y4.is_regular() == True
assert Y4.is_ergodic() == True
TS1 = MatrixSymbol('T', 3, 3)
Y5 = DiscreteMarkovChain('Y', trans_probs=TS1)
assert Y5.limiting_distribution(w, TO4).doit() == True
assert Y5.stationary_distribution(condition_set=True).subs(TS1, TO4).contains(w).doit() == S.true
TO6 = Matrix([[S.One, 0, 0, 0, 0],[S.Half, 0, S.Half, 0, 0],[0, S.Half, 0, S.Half, 0], [0, 0, S.Half, 0, S.Half], [0, 0, 0, 0, 1]])
Y6 = DiscreteMarkovChain('Y', trans_probs=TO6)
assert Y6.fundamental_matrix() == ImmutableMatrix([[Rational(3, 2), S.One, S.Half], [S.One, S(2), S.One], [S.Half, S.One, Rational(3, 2)]])
assert Y6.absorbing_probabilities() == ImmutableMatrix([[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half], [Rational(1, 4), Rational(3, 4)]])
with warns_deprecated_sympy():
Y6.absorbing_probabilites()
TO7 = Matrix([[Rational(1, 2), Rational(1, 4), Rational(1, 4)], [Rational(1, 2), 0, Rational(1, 2)], [Rational(1, 4), Rational(1, 4), Rational(1, 2)]])
Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
assert Y7.is_absorbing_chain() == False
assert Y7.fundamental_matrix() == ImmutableMatrix([[Rational(86, 75), Rational(1, 25), Rational(-14, 75)],
[Rational(2, 25), Rational(21, 25), Rational(2, 25)],
[Rational(-14, 75), Rational(1, 25), Rational(86, 75)]])
# test for zero-sized matrix functionality
X = DiscreteMarkovChain('X', trans_probs=Matrix([[]]))
assert X.number_of_states == 0
assert X.stationary_distribution() == Matrix([[]])
assert X.communication_classes() == []
assert X.canonical_form() == ([], Matrix([[]]))
assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]]))
assert X.is_regular() == False
assert X.is_ergodic() == False
# test communication_class
# see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing
# tutorial 2.pdf
TO7 = Matrix([[0, 5, 5, 0, 0],
[0, 0, 0, 10, 0],
[5, 0, 5, 0, 0],
[0, 10, 0, 0, 0],
[0, 3, 0, 3, 4]])/10
Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
tuples = Y7.communication_classes()
classes, recurrence, periods = list(zip(*tuples))
assert classes == ([1, 3], [0, 2], [4])
assert recurrence == (True, False, False)
assert periods == (2, 1, 1)
TO8 = Matrix([[0, 0, 0, 10, 0, 0],
[5, 0, 5, 0, 0, 0],
[0, 4, 0, 0, 0, 6],
[10, 0, 0, 0, 0, 0],
[0, 10, 0, 0, 0, 0],
[0, 0, 0, 5, 5, 0]])/10
Y8 = DiscreteMarkovChain('Y', trans_probs=TO8)
tuples = Y8.communication_classes()
classes, recurrence, periods = list(zip(*tuples))
assert classes == ([0, 3], [1, 2, 5, 4])
assert recurrence == (True, False)
assert periods == (2, 2)
TO9 = Matrix([[2, 0, 0, 3, 0, 0, 3, 2, 0, 0],
[0, 10, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 2, 2, 0, 0, 0, 0, 0, 3, 3],
[0, 0, 0, 3, 0, 0, 6, 1, 0, 0],
[0, 0, 0, 0, 5, 5, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 10, 0, 0, 0, 0],
[4, 0, 0, 5, 0, 0, 1, 0, 0, 0],
[2, 0, 0, 4, 0, 0, 2, 2, 0, 0],
[3, 0, 1, 0, 0, 0, 0, 0, 4, 2],
[0, 0, 4, 0, 0, 0, 0, 0, 3, 3]])/10
Y9 = DiscreteMarkovChain('Y', trans_probs=TO9)
tuples = Y9.communication_classes()
classes, recurrence, periods = list(zip(*tuples))
assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4])
assert recurrence == (True, True, False, True, False)
assert periods == (1, 1, 1, 1, 1)
# test canonical form
# see https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
# example 11.13
T = Matrix([[1, 0, 0, 0, 0],
[S(1) / 2, 0, S(1) / 2, 0, 0],
[0, S(1) / 2, 0, S(1) / 2, 0],
[0, 0, S(1) / 2, 0, S(1) / 2],
[0, 0, 0, 0, S(1)]])
DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T)
states, A, B, C = DW.decompose()
assert states == [0, 4, 1, 2, 3]
assert A == Matrix([[1, 0], [0, 1]])
assert B == Matrix([[S(1)/2, 0], [0, 0], [0, S(1)/2]])
assert C == Matrix([[0, S(1)/2, 0], [S(1)/2, 0, S(1)/2], [0, S(1)/2, 0]])
states, new_matrix = DW.canonical_form()
assert states == [0, 4, 1, 2, 3]
assert new_matrix == Matrix([[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[S(1)/2, 0, 0, S(1)/2, 0],
[0, 0, S(1)/2, 0, S(1)/2],
[0, S(1)/2, 0, S(1)/2, 0]])
# test regular and ergodic
# https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
T = Matrix([[0, 4, 0, 0, 0],
[1, 0, 3, 0, 0],
[0, 2, 0, 2, 0],
[0, 0, 3, 0, 1],
[0, 0, 0, 4, 0]])/4
X = DiscreteMarkovChain('X', trans_probs=T)
assert not X.is_regular()
assert X.is_ergodic()
T = Matrix([[0, 1], [1, 0]])
X = DiscreteMarkovChain('X', trans_probs=T)
assert not X.is_regular()
assert X.is_ergodic()
# http://www.math.wisc.edu/~valko/courses/331/MC2.pdf
T = Matrix([[2, 1, 1],
[2, 0, 2],
[1, 1, 2]])/4
X = DiscreteMarkovChain('X', trans_probs=T)
assert X.is_regular()
assert X.is_ergodic()
# https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf
T = Matrix([[1, 1], [1, 1]])/2
X = DiscreteMarkovChain('X', trans_probs=T)
assert X.is_regular()
assert X.is_ergodic()
# test is_absorbing_chain
T = Matrix([[0, 1, 0],
[1, 0, 0],
[0, 0, 1]])
X = DiscreteMarkovChain('X', trans_probs=T)
assert not X.is_absorbing_chain()
# https://en.wikipedia.org/wiki/Absorbing_Markov_chain
T = Matrix([[1, 1, 0, 0],
[0, 1, 1, 0],
[1, 0, 0, 1],
[0, 0, 0, 2]])/2
X = DiscreteMarkovChain('X', trans_probs=T)
assert X.is_absorbing_chain()
T = Matrix([[2, 0, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 0, 2]])/2
X = DiscreteMarkovChain('X', trans_probs=T)
assert X.is_absorbing_chain()
# test custom state space
Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2)
tuples = Y10.communication_classes()
classes, recurrence, periods = list(zip(*tuples))
assert classes == ([1], [2, 3])
assert recurrence == (True, False)
assert periods == (1, 1)
assert Y10.canonical_form() == ([1, 2, 3], TO2)
assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3])
# testing miscellaneous queries
T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)],
[Rational(1, 3), 0, Rational(2, 3)],
[S.Half, S.Half, 0]])
X = DiscreteMarkovChain('X', [0, 1, 2], T)
assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3)
assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9)
raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))
raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T))
# testing miscellaneous queries with different state space
X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T)
assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
a = X.state_space.args[0]
c = X.state_space.args[2]
assert (E(X[1] ** 2, Eq(X[0], 1)) - (a**2/3 + 2*c**2/3)).simplify() == 0
assert (variance(X[1], Eq(X[0], 1)) - (2*(-a/3 + c/3)**2/3 + (2*a/3 - 2*c/3)**2/3)).simplify() == 0
raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))
#testing queries with multiple RandomIndexedSymbols
T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]])
Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5)
assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2)
assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6)
assert Float(P(Eq(Y[10], Y[5]), Eq(Y[4], 1)), 14) == Float(1 - P(Ne(Y[10], Y[5]), Eq(Y[4], 1)), 14)
assert Float(P(Gt(Y[8], Y[9]), Eq(Y[3], 2)), 14) == Float(1 - P(Le(Y[8], Y[9]), Eq(Y[3], 2)), 14)
assert Float(P(Lt(Y[1], Y[4]), Eq(Y[0], 0)), 14) == Float(1 - P(Ge(Y[1], Y[4]), Eq(Y[0], 0)), 14)
assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1))
assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1))
assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1))
#test symbolic queries
a, b, c, d = symbols('a b c d')
T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]])
Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
query = P(Eq(Y[a], b), Eq(Y[c], d))
assert query.subs({a:10, b:2, c:5, d:1}).evalf().round(4) == P(Eq(Y[10], 2), Eq(Y[5], 1)).round(4)
assert query.subs({a:15, b:0, c:10, d:1}).evalf().round(4) == P(Eq(Y[15], 0), Eq(Y[10], 1)).round(4)
query_gt = P(Gt(Y[a], b), Eq(Y[c], d))
query_le = P(Le(Y[a], b), Eq(Y[c], d))
assert query_gt.subs({a:5, b:2, c:1, d:0}).evalf() + query_le.subs({a:5, b:2, c:1, d:0}).evalf() == 1.0
query_ge = P(Ge(Y[a], b), Eq(Y[c], d))
query_lt = P(Lt(Y[a], b), Eq(Y[c], d))
assert query_ge.subs({a:4, b:1, c:0, d:2}).evalf() + query_lt.subs({a:4, b:1, c:0, d:2}).evalf() == 1.0
#test issue 20078
assert (2*Y[1] + 3*Y[1]).simplify() == 5*Y[1]
assert (2*Y[1] - 3*Y[1]).simplify() == -Y[1]
assert (2*(0.25*Y[1])).simplify() == 0.5*Y[1]
assert ((2*Y[1]) * (0.25*Y[1])).simplify() == 0.5*Y[1]**2
assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1)*Y[1]**2
def test_sample_stochastic_process():
if not import_module('scipy'):
skip('SciPy Not installed. Skip sampling tests')
import random
random.seed(0)
numpy = import_module('numpy')
if numpy:
numpy.random.seed(0) # scipy uses numpy to sample so to set its seed
T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]])
Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
for samps in range(10):
assert next(sample_stochastic_process(Y)) in Y.state_space
Z = DiscreteMarkovChain("Z", ['1', 1, 0], T)
for samps in range(10):
assert next(sample_stochastic_process(Z)) in Z.state_space
T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)],
[Rational(1, 3), 0, Rational(2, 3)],
[S.Half, S.Half, 0]])
X = DiscreteMarkovChain('X', [0, 1, 2], T)
for samps in range(10):
assert next(sample_stochastic_process(X)) in X.state_space
W = DiscreteMarkovChain('W', [1, pi, oo], T)
for samps in range(10):
assert next(sample_stochastic_process(W)) in W.state_space
def test_ContinuousMarkovChain():
T1 = Matrix([[S(-2), S(2), S.Zero],
[S.Zero, S.NegativeOne, S.One],
[Rational(3, 2), Rational(3, 2), S(-3)]])
C1 = ContinuousMarkovChain('C', [0, 1, 2], T1)
assert C1.limiting_distribution() == ImmutableMatrix([[Rational(3, 19), Rational(12, 19), Rational(4, 19)]])
T2 = Matrix([[-S.One, S.One, S.Zero], [S.One, -S.One, S.Zero], [S.Zero, S.One, -S.One]])
C2 = ContinuousMarkovChain('C', [0, 1, 2], T2)
A, t = C2.generator_matrix, symbols('t', positive=True)
assert C2.transition_probabilities(A)(t) == Matrix([[S.Half + exp(-2*t)/2, S.Half - exp(-2*t)/2, 0],
[S.Half - exp(-2*t)/2, S.Half + exp(-2*t)/2, 0],
[S.Half - exp(-t) + exp(-2*t)/2, S.Half - exp(-2*t)/2, exp(-t)]])
with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed
assert P(Eq(C2(1), 1), Eq(C2(0), 1), evaluate=False) == Probability(Eq(C2(1), 1), Eq(C2(0), 1))
assert P(Eq(C2(1), 1), Eq(C2(0), 1)) == exp(-2)/2 + S.Half
assert P(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 1),
Eq(P(Eq(C2(1), 0)), S.Half)) == (Rational(1, 4) - exp(-2)/4)*(exp(-2)/2 + S.Half)
assert P(Not(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)) |
(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)),
Eq(P(Eq(C2(1), 0)), Rational(1, 4)) & Eq(P(Eq(C2(1), 1)), Rational(1, 4))) is S.One
assert E(C2(Rational(3, 2)), Eq(C2(0), 2)) == -exp(-3)/2 + 2*exp(Rational(-3, 2)) + S.Half
assert variance(C2(Rational(3, 2)), Eq(C2(0), 1)) == ((S.Half - exp(-3)/2)**2*(exp(-3)/2 + S.Half)
+ (Rational(-1, 2) - exp(-3)/2)**2*(S.Half - exp(-3)/2))
raises(KeyError, lambda: P(Eq(C2(1), 0), Eq(P(Eq(C2(1), 1)), S.Half)))
assert P(Eq(C2(1), 0), Eq(P(Eq(C2(5), 1)), S.Half)) == Probability(Eq(C2(1), 0))
TS1 = MatrixSymbol('G', 3, 3)
CS1 = ContinuousMarkovChain('C', [0, 1, 2], TS1)
A = CS1.generator_matrix
assert CS1.transition_probabilities(A)(t) == exp(t*A)
C3 = ContinuousMarkovChain('C', [Symbol('0'), Symbol('1'), Symbol('2')], T2)
assert P(Eq(C3(1), 1), Eq(C3(0), 1)) == exp(-2)/2 + S.Half
assert P(Eq(C3(1), Symbol('1')), Eq(C3(0), Symbol('1'))) == exp(-2)/2 + S.Half
#test probability queries
G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]])
C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G)
assert P(Eq(C(7.385), C(3.19)), Eq(C(0.862), 0)).round(5) == Float(0.35469, 5)
assert P(Gt(C(98.715), C(19.807)), Eq(C(11.314), 2)).round(5) == Float(0.32452, 5)
assert P(Le(C(5.9), C(10.112)), Eq(C(4), 1)).round(6) == Float(0.675214, 6)
assert Float(P(Eq(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14) == Float(1 - P(Ne(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14)
assert Float(P(Gt(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14) == Float(1 - P(Le(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14)
assert Float(P(Lt(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14) == Float(1 - P(Ge(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14)
assert P(Eq(C(5.243), C(10.912)), Eq(C(2.174), 1)) == P(Eq(C(10.912), C(5.243)), Eq(C(2.174), 1))
assert P(Gt(C(2.344), C(9.9)), Eq(C(1.102), 1)) == P(Lt(C(9.9), C(2.344)), Eq(C(1.102), 1))
assert P(Ge(C(7.87), C(1.008)), Eq(C(0.153), 1)) == P(Le(C(1.008), C(7.87)), Eq(C(0.153), 1))
#test symbolic queries
a, b, c, d = symbols('a b c d')
query = P(Eq(C(a), b), Eq(C(c), d))
assert query.subs({a:3.65, b:2, c:1.78, d:1}).evalf().round(10) == P(Eq(C(3.65), 2), Eq(C(1.78), 1)).round(10)
query_gt = P(Gt(C(a), b), Eq(C(c), d))
query_le = P(Le(C(a), b), Eq(C(c), d))
assert query_gt.subs({a:13.2, b:0, c:3.29, d:2}).evalf() + query_le.subs({a:13.2, b:0, c:3.29, d:2}).evalf() == 1.0
query_ge = P(Ge(C(a), b), Eq(C(c), d))
query_lt = P(Lt(C(a), b), Eq(C(c), d))
assert query_ge.subs({a:7.43, b:1, c:1.45, d:0}).evalf() + query_lt.subs({a:7.43, b:1, c:1.45, d:0}).evalf() == 1.0
#test issue 20078
assert (2*C(1) + 3*C(1)).simplify() == 5*C(1)
assert (2*C(1) - 3*C(1)).simplify() == -C(1)
assert (2*(0.25*C(1))).simplify() == 0.5*C(1)
assert (2*C(1) * 0.25*C(1)).simplify() == 0.5*C(1)**2
assert (C(1)**2 + C(1)**3).simplify() == (C(1) + 1)*C(1)**2
def test_BernoulliProcess():
B = BernoulliProcess("B", p=0.6, success=1, failure=0)
assert B.state_space == FiniteSet(0, 1)
assert B.index_set == S.Naturals0
assert B.success == 1
assert B.failure == 0
X = BernoulliProcess("X", p=Rational(1,3), success='H', failure='T')
assert X.state_space == FiniteSet('H', 'T')
H, T = symbols("H,T")
assert E(X[1]+X[2]*X[3]) == H**2/9 + 4*H*T/9 + H/3 + 4*T**2/9 + 2*T/3
t, x = symbols('t, x', positive=True, integer=True)
assert isinstance(B[t], RandomIndexedSymbol)
raises(ValueError, lambda: BernoulliProcess("X", p=1.1, success=1, failure=0))
raises(NotImplementedError, lambda: B(t))
raises(IndexError, lambda: B[-3])
assert B.joint_distribution(B[3], B[9]) == JointDistributionHandmade(Lambda((B[3], B[9]),
Piecewise((0.6, Eq(B[3], 1)), (0.4, Eq(B[3], 0)), (0, True))
*Piecewise((0.6, Eq(B[9], 1)), (0.4, Eq(B[9], 0)), (0, True))))
assert B.joint_distribution(2, B[4]) == JointDistributionHandmade(Lambda((B[2], B[4]),
Piecewise((0.6, Eq(B[2], 1)), (0.4, Eq(B[2], 0)), (0, True))
*Piecewise((0.6, Eq(B[4], 1)), (0.4, Eq(B[4], 0)), (0, True))))
# Test for the sum distribution of Bernoulli Process RVs
Y = B[1] + B[2] + B[3]
assert P(Eq(Y, 0)).round(2) == Float(0.06, 1)
assert P(Eq(Y, 2)).round(2) == Float(0.43, 2)
assert P(Eq(Y, 4)).round(2) == 0
assert P(Gt(Y, 1)).round(2) == Float(0.65, 2)
# Test for independency of each Random Indexed variable
assert P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) == Float(0.06, 1)
assert E(2 * B[1] + B[2]).round(2) == Float(1.80, 3)
assert E(2 * B[1] + B[2] + 5).round(2) == Float(6.80, 3)
assert E(B[2] * B[4] + B[10]).round(2) == Float(0.96, 2)
assert E(B[2] > 0, Eq(B[1],1) & Eq(B[2],1)).round(2) == Float(0.60,2)
assert E(B[1]) == 0.6
assert P(B[1] > 0).round(2) == Float(0.60, 2)
assert P(B[1] < 1).round(2) == Float(0.40, 2)
assert P(B[1] > 0, B[2] <= 1).round(2) == Float(0.60, 2)
assert P(B[12] * B[5] > 0).round(2) == Float(0.36, 2)
assert P(B[12] * B[5] > 0, B[4] < 1).round(2) == Float(0.36, 2)
assert P(Eq(B[2], 1), B[2] > 0) == 1.0
assert P(Eq(B[5], 3)) == 0
assert P(Eq(B[1], 1), B[1] < 0) == 0
assert P(B[2] > 0, Eq(B[2], 1)) == 1
assert P(B[2] < 0, Eq(B[2], 1)) == 0
assert P(B[2] > 0, B[2]==7) == 0
assert P(B[5] > 0, B[5]) == BernoulliDistribution(0.6, 0, 1)
raises(ValueError, lambda: P(3))
raises(ValueError, lambda: P(B[3] > 0, 3))
# test issue 19456
expr = Sum(B[t], (t, 0, 4))
expr2 = Sum(B[t], (t, 1, 3))
expr3 = Sum(B[t]**2, (t, 1, 3))
assert expr.doit() == B[0] + B[1] + B[2] + B[3] + B[4]
assert expr2.doit() == Y
assert expr3.doit() == B[1]**2 + B[2]**2 + B[3]**2
assert B[2*t].free_symbols == {B[2*t], t}
assert B[4].free_symbols == {B[4]}
assert B[x*t].free_symbols == {B[x*t], x, t}
#test issue 20078
assert (2*B[t] + 3*B[t]).simplify() == 5*B[t]
assert (2*B[t] - 3*B[t]).simplify() == -B[t]
assert (2*(0.25*B[t])).simplify() == 0.5*B[t]
assert (2*B[t] * 0.25*B[t]).simplify() == 0.5*B[t]**2
assert (B[t]**2 + B[t]**3).simplify() == (B[t] + 1)*B[t]**2
def test_PoissonProcess():
X = PoissonProcess("X", 3)
assert X.state_space == S.Naturals0
assert X.index_set == Interval(0, oo)
assert X.lamda == 3
t, d, x, y = symbols('t d x y', positive=True)
assert isinstance(X(t), RandomIndexedSymbol)
assert X.distribution(t) == PoissonDistribution(3*t)
with warns_deprecated_sympy():
X.distribution(X(t))
raises(ValueError, lambda: PoissonProcess("X", -1))
raises(NotImplementedError, lambda: X[t])
raises(IndexError, lambda: X(-5))
assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(Lambda((X(2), X(3)),
6**X(2)*9**X(3)*exp(-15)/(factorial(X(2))*factorial(X(3)))))
assert X.joint_distribution(4, 6) == JointDistributionHandmade(Lambda((X(4), X(6)),
12**X(4)*18**X(6)*exp(-30)/(factorial(X(4))*factorial(X(6)))))
assert P(X(t) < 1) == exp(-3*t)
assert P(Eq(X(t), 0), Contains(t, Interval.Lopen(3, 5))) == exp(-6) # exp(-2*lamda)
res = P(Eq(X(t), 1), Contains(t, Interval.Lopen(3, 4)))
assert res == 3*exp(-3)
# Equivalent to P(Eq(X(t), 1))**4 because of non-overlapping intervals
assert P(Eq(X(t), 1) & Eq(X(d), 1) & Eq(X(x), 1) & Eq(X(y), 1), Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3))
& Contains(y, Interval.Lopen(3, 4))) == res**4
# Return Probability because of overlapping intervals
assert P(Eq(X(t), 2) & Eq(X(d), 3), Contains(t, Interval.Lopen(0, 2))
& Contains(d, Interval.Ropen(2, 4))) == \
Probability(Eq(X(d), 3) & Eq(X(t), 2), Contains(t, Interval.Lopen(0, 2))
& Contains(d, Interval.Ropen(2, 4)))
raises(ValueError, lambda: P(Eq(X(t), 2) & Eq(X(d), 3),
Contains(t, Interval.Lopen(0, 4)) & Contains(d, Interval.Lopen(3, oo)))) # no bound on d
assert P(Eq(X(3), 2)) == 81*exp(-9)/2
assert P(Eq(X(t), 2), Contains(t, Interval.Lopen(0, 5))) == 225*exp(-15)/2
# Check that probability works correctly by adding it to 1
res1 = P(X(t) <= 3, Contains(t, Interval.Lopen(0, 5)))
res2 = P(X(t) > 3, Contains(t, Interval.Lopen(0, 5)))
assert res1 == 691*exp(-15)
assert (res1 + res2).simplify() == 1
# Check Not and Or
assert P(Not(Eq(X(t), 2) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & \
Contains(d, Interval.Lopen(7, 8))).simplify() == -18*exp(-6) + 234*exp(-9) + 1
assert P(Eq(X(t), 2) | Ne(X(t), 4), Contains(t, Interval.Ropen(2, 4))) == 1 - 36*exp(-6)
raises(ValueError, lambda: P(X(t) > 2, X(t) + X(d)))
assert E(X(t)) == 3*t # property of the distribution at a given timestamp
assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == 75
assert E(X(t)**2, Contains(t, Interval.Lopen(0, 1))) == 12
assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Ropen(1, 2))) == \
Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Ropen(1, 2)))
# Value Error because of infinite time bound
raises(ValueError, lambda: E(X(t)**3, Contains(t, Interval.Lopen(1, oo))))
# Equivalent to E(X(t)**2) - E(X(d)**2) == E(X(1)**2) - E(X(1)**2) == 0
assert E((X(t) + X(d))*(X(t) - X(d)), Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Lopen(1, 2))) == 0
assert E(X(2) + x*E(X(5))) == 15*x + 6
assert E(x*X(1) + y) == 3*x + y
assert P(Eq(X(1), 2) & Eq(X(t), 3), Contains(t, Interval.Lopen(1, 2))) == 81*exp(-6)/4
Y = PoissonProcess("Y", 6)
Z = X + Y
assert Z.lamda == X.lamda + Y.lamda == 9
raises(ValueError, lambda: X + 5) # should be added be only PoissonProcess instance
N, M = Z.split(4, 5)
assert N.lamda == 4
assert M.lamda == 5
raises(ValueError, lambda: Z.split(3, 2)) # 2+3 != 9
raises(ValueError, lambda :P(Eq(X(t), 0), Contains(t, Interval.Lopen(1, 3)) & Eq(X(1), 0)))
# check if it handles queries with two random variables in one args
res1 = P(Eq(N(3), N(5)))
assert res1 == P(Eq(N(t), 0), Contains(t, Interval(3, 5)))
res2 = P(N(3) > N(1))
assert res2 == P((N(t) > 0), Contains(t, Interval(1, 3)))
assert P(N(3) < N(1)) == 0 # condition is not possible
res3 = P(N(3) <= N(1)) # holds only for Eq(N(3), N(1))
assert res3 == P(Eq(N(t), 0), Contains(t, Interval(1, 3)))
# tests from https://www.probabilitycourse.com/chapter11/11_1_2_basic_concepts_of_the_poisson_process.php
X = PoissonProcess('X', 10) # 11.1
assert P(Eq(X(S(1)/3), 3) & Eq(X(1), 10)) == exp(-10)*Rational(8000000000, 11160261)
assert P(Eq(X(1), 1), Eq(X(S(1)/3), 3)) == 0
assert P(Eq(X(1), 10), Eq(X(S(1)/3), 3)) == P(Eq(X(S(2)/3), 7))
X = PoissonProcess('X', 2) # 11.2
assert P(X(S(1)/2) < 1) == exp(-1)
assert P(X(3) < 1, Eq(X(1), 0)) == exp(-4)
assert P(Eq(X(4), 3), Eq(X(2), 3)) == exp(-4)
X = PoissonProcess('X', 3)
assert P(Eq(X(2), 5) & Eq(X(1), 2)) == Rational(81, 4)*exp(-6)
# check few properties
assert P(X(2) <= 3, X(1)>=1) == 3*P(Eq(X(1), 0)) + 2*P(Eq(X(1), 1)) + P(Eq(X(1), 2))
assert P(X(2) <= 3, X(1) > 1) == 2*P(Eq(X(1), 0)) + 1*P(Eq(X(1), 1))
assert P(Eq(X(2), 5) & Eq(X(1), 2)) == P(Eq(X(1), 3))*P(Eq(X(1), 2))
assert P(Eq(X(3), 4), Eq(X(1), 3)) == P(Eq(X(2), 1))
#test issue 20078
assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
assert (2*X(t) - 3*X(t)).simplify() == -X(t)
assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
def test_WienerProcess():
X = WienerProcess("X")
assert X.state_space == S.Reals
assert X.index_set == Interval(0, oo)
t, d, x, y = symbols('t d x y', positive=True)
assert isinstance(X(t), RandomIndexedSymbol)
assert X.distribution(t) == NormalDistribution(0, sqrt(t))
with warns_deprecated_sympy():
X.distribution(X(t))
raises(ValueError, lambda: PoissonProcess("X", -1))
raises(NotImplementedError, lambda: X[t])
raises(IndexError, lambda: X(-2))
assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(
Lambda((X(2), X(3)), sqrt(6)*exp(-X(2)**2/4)*exp(-X(3)**2/6)/(12*pi)))
assert X.joint_distribution(4, 6) == JointDistributionHandmade(
Lambda((X(4), X(6)), sqrt(6)*exp(-X(4)**2/8)*exp(-X(6)**2/12)/(24*pi)))
assert P(X(t) < 3).simplify() == erf(3*sqrt(2)/(2*sqrt(t)))/2 + S(1)/2
assert P(X(t) > 2, Contains(t, Interval.Lopen(3, 7))).simplify() == S(1)/2 -\
erf(sqrt(2)/2)/2
# Equivalent to P(X(1)>1)**4
assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1),
Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2))
& Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() ==\
(1 - erf(sqrt(2)/2))*(1 - erf(sqrt(2)))*(1 - erf(3*sqrt(2)/2))*(1 - erf(2*sqrt(2)))/16
# Contains an overlapping interval so, return Probability
assert P((X(t)< 2) & (X(d)> 3), Contains(t, Interval.Lopen(0, 2))
& Contains(d, Interval.Ropen(2, 4))) == Probability((X(d) > 3) & (X(t) < 2),
Contains(d, Interval.Ropen(2, 4)) & Contains(t, Interval.Lopen(0, 2)))
assert str(P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) &
Contains(d, Interval.Lopen(7, 8))).simplify()) == \
'-(1 - erf(3*sqrt(2)/2))*(2 - erfc(5/2))/4 + 1'
# Distribution has mean 0 at each timestamp
assert E(X(t)) == 0
assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Ropen(1, 2))) == Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2),
Contains(d, Interval.Ropen(1, 2)) & Contains(t, Interval.Lopen(0, 1)))
assert E(X(t) + x*E(X(3))) == 0
#test issue 20078
assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
assert (2*X(t) - 3*X(t)).simplify() == -X(t)
assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
def test_GammaProcess_symbolic():
t, d, x, y, g, l = symbols('t d x y g l', positive=True)
X = GammaProcess("X", l, g)
raises(NotImplementedError, lambda: X[t])
raises(IndexError, lambda: X(-1))
assert isinstance(X(t), RandomIndexedSymbol)
assert X.state_space == Interval(0, oo)
assert X.distribution(t) == GammaDistribution(g*t, 1/l)
with warns_deprecated_sympy():
X.distribution(X(t))
assert X.joint_distribution(5, X(3)) == JointDistributionHandmade(Lambda(
(X(5), X(3)), l**(8*g)*exp(-l*X(3))*exp(-l*X(5))*X(3)**(3*g - 1)*X(5)**(5*g
- 1)/(gamma(3*g)*gamma(5*g))))
# property of the gamma process at any given timestamp
assert E(X(t)) == g*t/l
assert variance(X(t)).simplify() == g*t/l**2
# Equivalent to E(2*X(1)) + E(X(1)**2) + E(X(1)**3), where E(X(1)) == g/l
assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1))
& Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == \
2*g/l + (g**2 + g)/l**2 + (g**3 + 3*g**2 + 2*g)/l**3
assert P(X(t) > 3, Contains(t, Interval.Lopen(3, 4))).simplify() == \
1 - lowergamma(g, 3*l)/gamma(g) # equivalent to P(X(1)>3)
#test issue 20078
assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
assert (2*X(t) - 3*X(t)).simplify() == -X(t)
assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
def test_GammaProcess_numeric():
t, d, x, y = symbols('t d x y', positive=True)
X = GammaProcess("X", 1, 2)
assert X.state_space == Interval(0, oo)
assert X.index_set == Interval(0, oo)
assert X.lamda == 1
assert X.gamma == 2
raises(ValueError, lambda: GammaProcess("X", -1, 2))
raises(ValueError, lambda: GammaProcess("X", 0, -2))
raises(ValueError, lambda: GammaProcess("X", -1, -2))
# all are independent because of non-overlapping intervals
assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), Contains(t,
Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x,
Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() == \
120*exp(-10)
# Check working with Not and Or
assert P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) &
Contains(d, Interval.Lopen(7, 8))).simplify() == -4*exp(-3) + 472*exp(-8)/3 + 1
assert P((X(t) > 2) | (X(t) < 4), Contains(t, Interval.Ropen(1, 4))).simplify() == \
-643*exp(-4)/15 + 109*exp(-2)/15 + 1
assert E(X(t)) == 2*t # E(X(t)) == gamma*t/l
assert E(X(2) + x*E(X(5))) == 10*x + 4