test_stochastic_process.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. from sympy.concrete.summations import Sum
  2. from sympy.core.containers import Tuple
  3. from sympy.core.function import Lambda
  4. from sympy.core.numbers import (Float, Rational, oo, pi)
  5. from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
  6. from sympy.core.singleton import S
  7. from sympy.core.symbol import (Symbol, symbols)
  8. from sympy.functions.combinatorial.factorials import factorial
  9. from sympy.functions.elementary.exponential import exp
  10. from sympy.functions.elementary.integers import ceiling
  11. from sympy.functions.elementary.miscellaneous import sqrt
  12. from sympy.functions.elementary.piecewise import Piecewise
  13. from sympy.functions.special.error_functions import erf
  14. from sympy.functions.special.gamma_functions import (gamma, lowergamma)
  15. from sympy.logic.boolalg import (And, Not)
  16. from sympy.matrices.dense import Matrix
  17. from sympy.matrices.expressions.matexpr import MatrixSymbol
  18. from sympy.matrices.immutable import ImmutableMatrix
  19. from sympy.sets.contains import Contains
  20. from sympy.sets.fancysets import Range
  21. from sympy.sets.sets import (FiniteSet, Interval)
  22. from sympy.stats import (DiscreteMarkovChain, P, TransitionMatrixOf, E,
  23. StochasticStateSpaceOf, variance, ContinuousMarkovChain,
  24. BernoulliProcess, PoissonProcess, WienerProcess,
  25. GammaProcess, sample_stochastic_process)
  26. from sympy.stats.joint_rv import JointDistribution
  27. from sympy.stats.joint_rv_types import JointDistributionHandmade
  28. from sympy.stats.rv import RandomIndexedSymbol
  29. from sympy.stats.symbolic_probability import Probability, Expectation
  30. from sympy.testing.pytest import (raises, skip, ignore_warnings,
  31. warns_deprecated_sympy)
  32. from sympy.external import import_module
  33. from sympy.stats.frv_types import BernoulliDistribution
  34. from sympy.stats.drv_types import PoissonDistribution
  35. from sympy.stats.crv_types import NormalDistribution, GammaDistribution
  36. from sympy.core.symbol import Str
  37. def test_DiscreteMarkovChain():
  38. # pass only the name
  39. X = DiscreteMarkovChain("X")
  40. assert isinstance(X.state_space, Range)
  41. assert X.index_set == S.Naturals0
  42. assert isinstance(X.transition_probabilities, MatrixSymbol)
  43. t = symbols('t', positive=True, integer=True)
  44. assert isinstance(X[t], RandomIndexedSymbol)
  45. assert E(X[0]) == Expectation(X[0])
  46. raises(TypeError, lambda: DiscreteMarkovChain(1))
  47. raises(NotImplementedError, lambda: X(t))
  48. raises(NotImplementedError, lambda: X.communication_classes())
  49. raises(NotImplementedError, lambda: X.canonical_form())
  50. raises(NotImplementedError, lambda: X.decompose())
  51. nz = Symbol('n', integer=True)
  52. TZ = MatrixSymbol('M', nz, nz)
  53. SZ = Range(nz)
  54. YZ = DiscreteMarkovChain('Y', SZ, TZ)
  55. assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1]
  56. raises(ValueError, lambda: sample_stochastic_process(t))
  57. raises(ValueError, lambda: next(sample_stochastic_process(X)))
  58. # pass name and state_space
  59. # any hashable object should be a valid state
  60. # states should be valid as a tuple/set/list/Tuple/Range
  61. sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True)
  62. state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain("Y", (1,2,3))],
  63. Tuple(S(1), exp(sym), Str('World'), sympify=False), Range(-1, 5, 2),
  64. [rainy, cloudy, sunny]]
  65. chains = [DiscreteMarkovChain("Y", state_space) for state_space in state_spaces]
  66. for i, Y in enumerate(chains):
  67. assert isinstance(Y.transition_probabilities, MatrixSymbol)
  68. assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet(*state_spaces[i])
  69. assert Y.number_of_states == 3
  70. with ignore_warnings(UserWarning): # TODO: Restore tests once warnings are removed
  71. assert P(Eq(Y[2], 1), Eq(Y[0], 2), evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2))
  72. assert E(Y[0]) == Expectation(Y[0])
  73. raises(ValueError, lambda: next(sample_stochastic_process(Y)))
  74. raises(TypeError, lambda: DiscreteMarkovChain("Y", {1: 1}))
  75. Y = DiscreteMarkovChain("Y", Range(1, t, 2))
  76. assert Y.number_of_states == ceiling((t-1)/2)
  77. # pass name and transition_probabilities
  78. chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([[]])),
  79. DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])),
  80. DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1-pi], [sym, 1-sym]]))]
  81. for Z in chains:
  82. assert Z.number_of_states == Z.transition_probabilities.shape[0]
  83. assert isinstance(Z.transition_probabilities, ImmutableMatrix)
  84. # pass name, state_space and transition_probabilities
  85. T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]])
  86. TS = MatrixSymbol('T', 3, 3)
  87. Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
  88. YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS)
  89. assert Y.joint_distribution(1, Y[2], 3) == JointDistribution(Y[1], Y[2], Y[3])
  90. raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol))
  91. assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2)
  92. assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) -
  93. (TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2])).simplify() == 0
  94. assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1))
  95. 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]
  96. TO = Matrix([[0.25, 0.75, 0],[0, 0.25, 0.75],[0.75, 0, 0.25]])
  97. assert P(Eq(Y[3], 2), Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float(0.375, 3)
  98. with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed
  99. assert E(Y[3], evaluate=False) == Expectation(Y[3])
  100. assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3)
  101. TSO = MatrixSymbol('T', 4, 4)
  102. raises(ValueError, lambda: str(P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO))))
  103. raises(TypeError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M')))
  104. raises(ValueError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4)))
  105. raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6)))
  106. raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1)))
  107. # extended tests for probability queries
  108. 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)]])
  109. assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)),
  110. Eq(Probability(Eq(Y[0], 0)), Rational(1, 4)) & TransitionMatrixOf(Y, TO1)) == Rational(1, 16)
  111. assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \
  112. Probability(Eq(Y[0], 0))/4
  113. assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) &
  114. StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
  115. assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) &
  116. StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
  117. assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) &
  118. StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) is S.Zero
  119. assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) &
  120. StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) is S.Zero
  121. 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))
  122. # testing properties of Markov chain
  123. TO2 = Matrix([[S.One, 0, 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]])
  124. 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)]])
  125. Y2 = DiscreteMarkovChain('Y', trans_probs=TO2)
  126. Y3 = DiscreteMarkovChain('Y', trans_probs=TO3)
  127. assert Y3.fundamental_matrix() == ImmutableMatrix([[176, 81, -132], [36, 141, -52], [-44, -39, 208]])/125
  128. assert Y2.is_absorbing_chain() == True
  129. assert Y3.is_absorbing_chain() == False
  130. assert Y2.canonical_form() == ([0, 1, 2], TO2)
  131. assert Y3.canonical_form() == ([0, 1, 2], TO3)
  132. assert Y2.decompose() == ([0, 1, 2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3])
  133. assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3, []), Matrix(0, 0, []))
  134. 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)]])
  135. Y4 = DiscreteMarkovChain('Y', trans_probs=TO4)
  136. w = ImmutableMatrix([[Rational(11, 39), Rational(16, 39), Rational(4, 13)]])
  137. assert Y4.limiting_distribution == w
  138. assert Y4.is_regular() == True
  139. assert Y4.is_ergodic() == True
  140. TS1 = MatrixSymbol('T', 3, 3)
  141. Y5 = DiscreteMarkovChain('Y', trans_probs=TS1)
  142. assert Y5.limiting_distribution(w, TO4).doit() == True
  143. assert Y5.stationary_distribution(condition_set=True).subs(TS1, TO4).contains(w).doit() == S.true
  144. 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]])
  145. Y6 = DiscreteMarkovChain('Y', trans_probs=TO6)
  146. 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)]])
  147. assert Y6.absorbing_probabilities() == ImmutableMatrix([[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half], [Rational(1, 4), Rational(3, 4)]])
  148. with warns_deprecated_sympy():
  149. Y6.absorbing_probabilites()
  150. 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)]])
  151. Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
  152. assert Y7.is_absorbing_chain() == False
  153. assert Y7.fundamental_matrix() == ImmutableMatrix([[Rational(86, 75), Rational(1, 25), Rational(-14, 75)],
  154. [Rational(2, 25), Rational(21, 25), Rational(2, 25)],
  155. [Rational(-14, 75), Rational(1, 25), Rational(86, 75)]])
  156. # test for zero-sized matrix functionality
  157. X = DiscreteMarkovChain('X', trans_probs=Matrix([[]]))
  158. assert X.number_of_states == 0
  159. assert X.stationary_distribution() == Matrix([[]])
  160. assert X.communication_classes() == []
  161. assert X.canonical_form() == ([], Matrix([[]]))
  162. assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]]))
  163. assert X.is_regular() == False
  164. assert X.is_ergodic() == False
  165. # test communication_class
  166. # see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing
  167. # tutorial 2.pdf
  168. TO7 = Matrix([[0, 5, 5, 0, 0],
  169. [0, 0, 0, 10, 0],
  170. [5, 0, 5, 0, 0],
  171. [0, 10, 0, 0, 0],
  172. [0, 3, 0, 3, 4]])/10
  173. Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
  174. tuples = Y7.communication_classes()
  175. classes, recurrence, periods = list(zip(*tuples))
  176. assert classes == ([1, 3], [0, 2], [4])
  177. assert recurrence == (True, False, False)
  178. assert periods == (2, 1, 1)
  179. TO8 = Matrix([[0, 0, 0, 10, 0, 0],
  180. [5, 0, 5, 0, 0, 0],
  181. [0, 4, 0, 0, 0, 6],
  182. [10, 0, 0, 0, 0, 0],
  183. [0, 10, 0, 0, 0, 0],
  184. [0, 0, 0, 5, 5, 0]])/10
  185. Y8 = DiscreteMarkovChain('Y', trans_probs=TO8)
  186. tuples = Y8.communication_classes()
  187. classes, recurrence, periods = list(zip(*tuples))
  188. assert classes == ([0, 3], [1, 2, 5, 4])
  189. assert recurrence == (True, False)
  190. assert periods == (2, 2)
  191. TO9 = Matrix([[2, 0, 0, 3, 0, 0, 3, 2, 0, 0],
  192. [0, 10, 0, 0, 0, 0, 0, 0, 0, 0],
  193. [0, 2, 2, 0, 0, 0, 0, 0, 3, 3],
  194. [0, 0, 0, 3, 0, 0, 6, 1, 0, 0],
  195. [0, 0, 0, 0, 5, 5, 0, 0, 0, 0],
  196. [0, 0, 0, 0, 0, 10, 0, 0, 0, 0],
  197. [4, 0, 0, 5, 0, 0, 1, 0, 0, 0],
  198. [2, 0, 0, 4, 0, 0, 2, 2, 0, 0],
  199. [3, 0, 1, 0, 0, 0, 0, 0, 4, 2],
  200. [0, 0, 4, 0, 0, 0, 0, 0, 3, 3]])/10
  201. Y9 = DiscreteMarkovChain('Y', trans_probs=TO9)
  202. tuples = Y9.communication_classes()
  203. classes, recurrence, periods = list(zip(*tuples))
  204. assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4])
  205. assert recurrence == (True, True, False, True, False)
  206. assert periods == (1, 1, 1, 1, 1)
  207. # test canonical form
  208. # see https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
  209. # example 11.13
  210. T = Matrix([[1, 0, 0, 0, 0],
  211. [S(1) / 2, 0, S(1) / 2, 0, 0],
  212. [0, S(1) / 2, 0, S(1) / 2, 0],
  213. [0, 0, S(1) / 2, 0, S(1) / 2],
  214. [0, 0, 0, 0, S(1)]])
  215. DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T)
  216. states, A, B, C = DW.decompose()
  217. assert states == [0, 4, 1, 2, 3]
  218. assert A == Matrix([[1, 0], [0, 1]])
  219. assert B == Matrix([[S(1)/2, 0], [0, 0], [0, S(1)/2]])
  220. assert C == Matrix([[0, S(1)/2, 0], [S(1)/2, 0, S(1)/2], [0, S(1)/2, 0]])
  221. states, new_matrix = DW.canonical_form()
  222. assert states == [0, 4, 1, 2, 3]
  223. assert new_matrix == Matrix([[1, 0, 0, 0, 0],
  224. [0, 1, 0, 0, 0],
  225. [S(1)/2, 0, 0, S(1)/2, 0],
  226. [0, 0, S(1)/2, 0, S(1)/2],
  227. [0, S(1)/2, 0, S(1)/2, 0]])
  228. # test regular and ergodic
  229. # https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
  230. T = Matrix([[0, 4, 0, 0, 0],
  231. [1, 0, 3, 0, 0],
  232. [0, 2, 0, 2, 0],
  233. [0, 0, 3, 0, 1],
  234. [0, 0, 0, 4, 0]])/4
  235. X = DiscreteMarkovChain('X', trans_probs=T)
  236. assert not X.is_regular()
  237. assert X.is_ergodic()
  238. T = Matrix([[0, 1], [1, 0]])
  239. X = DiscreteMarkovChain('X', trans_probs=T)
  240. assert not X.is_regular()
  241. assert X.is_ergodic()
  242. # http://www.math.wisc.edu/~valko/courses/331/MC2.pdf
  243. T = Matrix([[2, 1, 1],
  244. [2, 0, 2],
  245. [1, 1, 2]])/4
  246. X = DiscreteMarkovChain('X', trans_probs=T)
  247. assert X.is_regular()
  248. assert X.is_ergodic()
  249. # https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf
  250. T = Matrix([[1, 1], [1, 1]])/2
  251. X = DiscreteMarkovChain('X', trans_probs=T)
  252. assert X.is_regular()
  253. assert X.is_ergodic()
  254. # test is_absorbing_chain
  255. T = Matrix([[0, 1, 0],
  256. [1, 0, 0],
  257. [0, 0, 1]])
  258. X = DiscreteMarkovChain('X', trans_probs=T)
  259. assert not X.is_absorbing_chain()
  260. # https://en.wikipedia.org/wiki/Absorbing_Markov_chain
  261. T = Matrix([[1, 1, 0, 0],
  262. [0, 1, 1, 0],
  263. [1, 0, 0, 1],
  264. [0, 0, 0, 2]])/2
  265. X = DiscreteMarkovChain('X', trans_probs=T)
  266. assert X.is_absorbing_chain()
  267. T = Matrix([[2, 0, 0, 0, 0],
  268. [1, 0, 1, 0, 0],
  269. [0, 1, 0, 1, 0],
  270. [0, 0, 1, 0, 1],
  271. [0, 0, 0, 0, 2]])/2
  272. X = DiscreteMarkovChain('X', trans_probs=T)
  273. assert X.is_absorbing_chain()
  274. # test custom state space
  275. Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2)
  276. tuples = Y10.communication_classes()
  277. classes, recurrence, periods = list(zip(*tuples))
  278. assert classes == ([1], [2, 3])
  279. assert recurrence == (True, False)
  280. assert periods == (1, 1)
  281. assert Y10.canonical_form() == ([1, 2, 3], TO2)
  282. assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3])
  283. # testing miscellaneous queries
  284. T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)],
  285. [Rational(1, 3), 0, Rational(2, 3)],
  286. [S.Half, S.Half, 0]])
  287. X = DiscreteMarkovChain('X', [0, 1, 2], T)
  288. assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
  289. Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
  290. assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
  291. assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
  292. assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
  293. assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3)
  294. assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9)
  295. raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))
  296. raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T))
  297. # testing miscellaneous queries with different state space
  298. X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T)
  299. assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
  300. Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
  301. assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
  302. assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
  303. assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
  304. a = X.state_space.args[0]
  305. c = X.state_space.args[2]
  306. assert (E(X[1] ** 2, Eq(X[0], 1)) - (a**2/3 + 2*c**2/3)).simplify() == 0
  307. 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
  308. raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))
  309. #testing queries with multiple RandomIndexedSymbols
  310. 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)]])
  311. Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
  312. assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5)
  313. assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2)
  314. assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6)
  315. 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)
  316. 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)
  317. 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)
  318. assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1))
  319. assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1))
  320. assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1))
  321. #test symbolic queries
  322. a, b, c, d = symbols('a b c d')
  323. 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)]])
  324. Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
  325. query = P(Eq(Y[a], b), Eq(Y[c], d))
  326. 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)
  327. 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)
  328. query_gt = P(Gt(Y[a], b), Eq(Y[c], d))
  329. query_le = P(Le(Y[a], b), Eq(Y[c], d))
  330. 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
  331. query_ge = P(Ge(Y[a], b), Eq(Y[c], d))
  332. query_lt = P(Lt(Y[a], b), Eq(Y[c], d))
  333. 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
  334. #test issue 20078
  335. assert (2*Y[1] + 3*Y[1]).simplify() == 5*Y[1]
  336. assert (2*Y[1] - 3*Y[1]).simplify() == -Y[1]
  337. assert (2*(0.25*Y[1])).simplify() == 0.5*Y[1]
  338. assert ((2*Y[1]) * (0.25*Y[1])).simplify() == 0.5*Y[1]**2
  339. assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1)*Y[1]**2
  340. def test_sample_stochastic_process():
  341. if not import_module('scipy'):
  342. skip('SciPy Not installed. Skip sampling tests')
  343. import random
  344. random.seed(0)
  345. numpy = import_module('numpy')
  346. if numpy:
  347. numpy.random.seed(0) # scipy uses numpy to sample so to set its seed
  348. T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]])
  349. Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
  350. for samps in range(10):
  351. assert next(sample_stochastic_process(Y)) in Y.state_space
  352. Z = DiscreteMarkovChain("Z", ['1', 1, 0], T)
  353. for samps in range(10):
  354. assert next(sample_stochastic_process(Z)) in Z.state_space
  355. T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)],
  356. [Rational(1, 3), 0, Rational(2, 3)],
  357. [S.Half, S.Half, 0]])
  358. X = DiscreteMarkovChain('X', [0, 1, 2], T)
  359. for samps in range(10):
  360. assert next(sample_stochastic_process(X)) in X.state_space
  361. W = DiscreteMarkovChain('W', [1, pi, oo], T)
  362. for samps in range(10):
  363. assert next(sample_stochastic_process(W)) in W.state_space
  364. def test_ContinuousMarkovChain():
  365. T1 = Matrix([[S(-2), S(2), S.Zero],
  366. [S.Zero, S.NegativeOne, S.One],
  367. [Rational(3, 2), Rational(3, 2), S(-3)]])
  368. C1 = ContinuousMarkovChain('C', [0, 1, 2], T1)
  369. assert C1.limiting_distribution() == ImmutableMatrix([[Rational(3, 19), Rational(12, 19), Rational(4, 19)]])
  370. T2 = Matrix([[-S.One, S.One, S.Zero], [S.One, -S.One, S.Zero], [S.Zero, S.One, -S.One]])
  371. C2 = ContinuousMarkovChain('C', [0, 1, 2], T2)
  372. A, t = C2.generator_matrix, symbols('t', positive=True)
  373. assert C2.transition_probabilities(A)(t) == Matrix([[S.Half + exp(-2*t)/2, S.Half - exp(-2*t)/2, 0],
  374. [S.Half - exp(-2*t)/2, S.Half + exp(-2*t)/2, 0],
  375. [S.Half - exp(-t) + exp(-2*t)/2, S.Half - exp(-2*t)/2, exp(-t)]])
  376. with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed
  377. assert P(Eq(C2(1), 1), Eq(C2(0), 1), evaluate=False) == Probability(Eq(C2(1), 1), Eq(C2(0), 1))
  378. assert P(Eq(C2(1), 1), Eq(C2(0), 1)) == exp(-2)/2 + S.Half
  379. assert P(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 1),
  380. Eq(P(Eq(C2(1), 0)), S.Half)) == (Rational(1, 4) - exp(-2)/4)*(exp(-2)/2 + S.Half)
  381. assert P(Not(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)) |
  382. (Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)),
  383. Eq(P(Eq(C2(1), 0)), Rational(1, 4)) & Eq(P(Eq(C2(1), 1)), Rational(1, 4))) is S.One
  384. assert E(C2(Rational(3, 2)), Eq(C2(0), 2)) == -exp(-3)/2 + 2*exp(Rational(-3, 2)) + S.Half
  385. assert variance(C2(Rational(3, 2)), Eq(C2(0), 1)) == ((S.Half - exp(-3)/2)**2*(exp(-3)/2 + S.Half)
  386. + (Rational(-1, 2) - exp(-3)/2)**2*(S.Half - exp(-3)/2))
  387. raises(KeyError, lambda: P(Eq(C2(1), 0), Eq(P(Eq(C2(1), 1)), S.Half)))
  388. assert P(Eq(C2(1), 0), Eq(P(Eq(C2(5), 1)), S.Half)) == Probability(Eq(C2(1), 0))
  389. TS1 = MatrixSymbol('G', 3, 3)
  390. CS1 = ContinuousMarkovChain('C', [0, 1, 2], TS1)
  391. A = CS1.generator_matrix
  392. assert CS1.transition_probabilities(A)(t) == exp(t*A)
  393. C3 = ContinuousMarkovChain('C', [Symbol('0'), Symbol('1'), Symbol('2')], T2)
  394. assert P(Eq(C3(1), 1), Eq(C3(0), 1)) == exp(-2)/2 + S.Half
  395. assert P(Eq(C3(1), Symbol('1')), Eq(C3(0), Symbol('1'))) == exp(-2)/2 + S.Half
  396. #test probability queries
  397. 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)]])
  398. C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G)
  399. assert P(Eq(C(7.385), C(3.19)), Eq(C(0.862), 0)).round(5) == Float(0.35469, 5)
  400. assert P(Gt(C(98.715), C(19.807)), Eq(C(11.314), 2)).round(5) == Float(0.32452, 5)
  401. assert P(Le(C(5.9), C(10.112)), Eq(C(4), 1)).round(6) == Float(0.675214, 6)
  402. 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)
  403. 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)
  404. 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)
  405. 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))
  406. 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))
  407. 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))
  408. #test symbolic queries
  409. a, b, c, d = symbols('a b c d')
  410. query = P(Eq(C(a), b), Eq(C(c), d))
  411. 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)
  412. query_gt = P(Gt(C(a), b), Eq(C(c), d))
  413. query_le = P(Le(C(a), b), Eq(C(c), d))
  414. 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
  415. query_ge = P(Ge(C(a), b), Eq(C(c), d))
  416. query_lt = P(Lt(C(a), b), Eq(C(c), d))
  417. 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
  418. #test issue 20078
  419. assert (2*C(1) + 3*C(1)).simplify() == 5*C(1)
  420. assert (2*C(1) - 3*C(1)).simplify() == -C(1)
  421. assert (2*(0.25*C(1))).simplify() == 0.5*C(1)
  422. assert (2*C(1) * 0.25*C(1)).simplify() == 0.5*C(1)**2
  423. assert (C(1)**2 + C(1)**3).simplify() == (C(1) + 1)*C(1)**2
  424. def test_BernoulliProcess():
  425. B = BernoulliProcess("B", p=0.6, success=1, failure=0)
  426. assert B.state_space == FiniteSet(0, 1)
  427. assert B.index_set == S.Naturals0
  428. assert B.success == 1
  429. assert B.failure == 0
  430. X = BernoulliProcess("X", p=Rational(1,3), success='H', failure='T')
  431. assert X.state_space == FiniteSet('H', 'T')
  432. H, T = symbols("H,T")
  433. assert E(X[1]+X[2]*X[3]) == H**2/9 + 4*H*T/9 + H/3 + 4*T**2/9 + 2*T/3
  434. t, x = symbols('t, x', positive=True, integer=True)
  435. assert isinstance(B[t], RandomIndexedSymbol)
  436. raises(ValueError, lambda: BernoulliProcess("X", p=1.1, success=1, failure=0))
  437. raises(NotImplementedError, lambda: B(t))
  438. raises(IndexError, lambda: B[-3])
  439. assert B.joint_distribution(B[3], B[9]) == JointDistributionHandmade(Lambda((B[3], B[9]),
  440. Piecewise((0.6, Eq(B[3], 1)), (0.4, Eq(B[3], 0)), (0, True))
  441. *Piecewise((0.6, Eq(B[9], 1)), (0.4, Eq(B[9], 0)), (0, True))))
  442. assert B.joint_distribution(2, B[4]) == JointDistributionHandmade(Lambda((B[2], B[4]),
  443. Piecewise((0.6, Eq(B[2], 1)), (0.4, Eq(B[2], 0)), (0, True))
  444. *Piecewise((0.6, Eq(B[4], 1)), (0.4, Eq(B[4], 0)), (0, True))))
  445. # Test for the sum distribution of Bernoulli Process RVs
  446. Y = B[1] + B[2] + B[3]
  447. assert P(Eq(Y, 0)).round(2) == Float(0.06, 1)
  448. assert P(Eq(Y, 2)).round(2) == Float(0.43, 2)
  449. assert P(Eq(Y, 4)).round(2) == 0
  450. assert P(Gt(Y, 1)).round(2) == Float(0.65, 2)
  451. # Test for independency of each Random Indexed variable
  452. assert P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) == Float(0.06, 1)
  453. assert E(2 * B[1] + B[2]).round(2) == Float(1.80, 3)
  454. assert E(2 * B[1] + B[2] + 5).round(2) == Float(6.80, 3)
  455. assert E(B[2] * B[4] + B[10]).round(2) == Float(0.96, 2)
  456. assert E(B[2] > 0, Eq(B[1],1) & Eq(B[2],1)).round(2) == Float(0.60,2)
  457. assert E(B[1]) == 0.6
  458. assert P(B[1] > 0).round(2) == Float(0.60, 2)
  459. assert P(B[1] < 1).round(2) == Float(0.40, 2)
  460. assert P(B[1] > 0, B[2] <= 1).round(2) == Float(0.60, 2)
  461. assert P(B[12] * B[5] > 0).round(2) == Float(0.36, 2)
  462. assert P(B[12] * B[5] > 0, B[4] < 1).round(2) == Float(0.36, 2)
  463. assert P(Eq(B[2], 1), B[2] > 0) == 1.0
  464. assert P(Eq(B[5], 3)) == 0
  465. assert P(Eq(B[1], 1), B[1] < 0) == 0
  466. assert P(B[2] > 0, Eq(B[2], 1)) == 1
  467. assert P(B[2] < 0, Eq(B[2], 1)) == 0
  468. assert P(B[2] > 0, B[2]==7) == 0
  469. assert P(B[5] > 0, B[5]) == BernoulliDistribution(0.6, 0, 1)
  470. raises(ValueError, lambda: P(3))
  471. raises(ValueError, lambda: P(B[3] > 0, 3))
  472. # test issue 19456
  473. expr = Sum(B[t], (t, 0, 4))
  474. expr2 = Sum(B[t], (t, 1, 3))
  475. expr3 = Sum(B[t]**2, (t, 1, 3))
  476. assert expr.doit() == B[0] + B[1] + B[2] + B[3] + B[4]
  477. assert expr2.doit() == Y
  478. assert expr3.doit() == B[1]**2 + B[2]**2 + B[3]**2
  479. assert B[2*t].free_symbols == {B[2*t], t}
  480. assert B[4].free_symbols == {B[4]}
  481. assert B[x*t].free_symbols == {B[x*t], x, t}
  482. #test issue 20078
  483. assert (2*B[t] + 3*B[t]).simplify() == 5*B[t]
  484. assert (2*B[t] - 3*B[t]).simplify() == -B[t]
  485. assert (2*(0.25*B[t])).simplify() == 0.5*B[t]
  486. assert (2*B[t] * 0.25*B[t]).simplify() == 0.5*B[t]**2
  487. assert (B[t]**2 + B[t]**3).simplify() == (B[t] + 1)*B[t]**2
  488. def test_PoissonProcess():
  489. X = PoissonProcess("X", 3)
  490. assert X.state_space == S.Naturals0
  491. assert X.index_set == Interval(0, oo)
  492. assert X.lamda == 3
  493. t, d, x, y = symbols('t d x y', positive=True)
  494. assert isinstance(X(t), RandomIndexedSymbol)
  495. assert X.distribution(t) == PoissonDistribution(3*t)
  496. with warns_deprecated_sympy():
  497. X.distribution(X(t))
  498. raises(ValueError, lambda: PoissonProcess("X", -1))
  499. raises(NotImplementedError, lambda: X[t])
  500. raises(IndexError, lambda: X(-5))
  501. assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(Lambda((X(2), X(3)),
  502. 6**X(2)*9**X(3)*exp(-15)/(factorial(X(2))*factorial(X(3)))))
  503. assert X.joint_distribution(4, 6) == JointDistributionHandmade(Lambda((X(4), X(6)),
  504. 12**X(4)*18**X(6)*exp(-30)/(factorial(X(4))*factorial(X(6)))))
  505. assert P(X(t) < 1) == exp(-3*t)
  506. assert P(Eq(X(t), 0), Contains(t, Interval.Lopen(3, 5))) == exp(-6) # exp(-2*lamda)
  507. res = P(Eq(X(t), 1), Contains(t, Interval.Lopen(3, 4)))
  508. assert res == 3*exp(-3)
  509. # Equivalent to P(Eq(X(t), 1))**4 because of non-overlapping intervals
  510. assert P(Eq(X(t), 1) & Eq(X(d), 1) & Eq(X(x), 1) & Eq(X(y), 1), Contains(t, Interval.Lopen(0, 1))
  511. & Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3))
  512. & Contains(y, Interval.Lopen(3, 4))) == res**4
  513. # Return Probability because of overlapping intervals
  514. assert P(Eq(X(t), 2) & Eq(X(d), 3), Contains(t, Interval.Lopen(0, 2))
  515. & Contains(d, Interval.Ropen(2, 4))) == \
  516. Probability(Eq(X(d), 3) & Eq(X(t), 2), Contains(t, Interval.Lopen(0, 2))
  517. & Contains(d, Interval.Ropen(2, 4)))
  518. raises(ValueError, lambda: P(Eq(X(t), 2) & Eq(X(d), 3),
  519. Contains(t, Interval.Lopen(0, 4)) & Contains(d, Interval.Lopen(3, oo)))) # no bound on d
  520. assert P(Eq(X(3), 2)) == 81*exp(-9)/2
  521. assert P(Eq(X(t), 2), Contains(t, Interval.Lopen(0, 5))) == 225*exp(-15)/2
  522. # Check that probability works correctly by adding it to 1
  523. res1 = P(X(t) <= 3, Contains(t, Interval.Lopen(0, 5)))
  524. res2 = P(X(t) > 3, Contains(t, Interval.Lopen(0, 5)))
  525. assert res1 == 691*exp(-15)
  526. assert (res1 + res2).simplify() == 1
  527. # Check Not and Or
  528. assert P(Not(Eq(X(t), 2) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & \
  529. Contains(d, Interval.Lopen(7, 8))).simplify() == -18*exp(-6) + 234*exp(-9) + 1
  530. assert P(Eq(X(t), 2) | Ne(X(t), 4), Contains(t, Interval.Ropen(2, 4))) == 1 - 36*exp(-6)
  531. raises(ValueError, lambda: P(X(t) > 2, X(t) + X(d)))
  532. assert E(X(t)) == 3*t # property of the distribution at a given timestamp
  533. assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1))
  534. & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == 75
  535. assert E(X(t)**2, Contains(t, Interval.Lopen(0, 1))) == 12
  536. assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1))
  537. & Contains(d, Interval.Ropen(1, 2))) == \
  538. Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), Contains(t, Interval.Lopen(0, 1))
  539. & Contains(d, Interval.Ropen(1, 2)))
  540. # Value Error because of infinite time bound
  541. raises(ValueError, lambda: E(X(t)**3, Contains(t, Interval.Lopen(1, oo))))
  542. # Equivalent to E(X(t)**2) - E(X(d)**2) == E(X(1)**2) - E(X(1)**2) == 0
  543. assert E((X(t) + X(d))*(X(t) - X(d)), Contains(t, Interval.Lopen(0, 1))
  544. & Contains(d, Interval.Lopen(1, 2))) == 0
  545. assert E(X(2) + x*E(X(5))) == 15*x + 6
  546. assert E(x*X(1) + y) == 3*x + y
  547. assert P(Eq(X(1), 2) & Eq(X(t), 3), Contains(t, Interval.Lopen(1, 2))) == 81*exp(-6)/4
  548. Y = PoissonProcess("Y", 6)
  549. Z = X + Y
  550. assert Z.lamda == X.lamda + Y.lamda == 9
  551. raises(ValueError, lambda: X + 5) # should be added be only PoissonProcess instance
  552. N, M = Z.split(4, 5)
  553. assert N.lamda == 4
  554. assert M.lamda == 5
  555. raises(ValueError, lambda: Z.split(3, 2)) # 2+3 != 9
  556. raises(ValueError, lambda :P(Eq(X(t), 0), Contains(t, Interval.Lopen(1, 3)) & Eq(X(1), 0)))
  557. # check if it handles queries with two random variables in one args
  558. res1 = P(Eq(N(3), N(5)))
  559. assert res1 == P(Eq(N(t), 0), Contains(t, Interval(3, 5)))
  560. res2 = P(N(3) > N(1))
  561. assert res2 == P((N(t) > 0), Contains(t, Interval(1, 3)))
  562. assert P(N(3) < N(1)) == 0 # condition is not possible
  563. res3 = P(N(3) <= N(1)) # holds only for Eq(N(3), N(1))
  564. assert res3 == P(Eq(N(t), 0), Contains(t, Interval(1, 3)))
  565. # tests from https://www.probabilitycourse.com/chapter11/11_1_2_basic_concepts_of_the_poisson_process.php
  566. X = PoissonProcess('X', 10) # 11.1
  567. assert P(Eq(X(S(1)/3), 3) & Eq(X(1), 10)) == exp(-10)*Rational(8000000000, 11160261)
  568. assert P(Eq(X(1), 1), Eq(X(S(1)/3), 3)) == 0
  569. assert P(Eq(X(1), 10), Eq(X(S(1)/3), 3)) == P(Eq(X(S(2)/3), 7))
  570. X = PoissonProcess('X', 2) # 11.2
  571. assert P(X(S(1)/2) < 1) == exp(-1)
  572. assert P(X(3) < 1, Eq(X(1), 0)) == exp(-4)
  573. assert P(Eq(X(4), 3), Eq(X(2), 3)) == exp(-4)
  574. X = PoissonProcess('X', 3)
  575. assert P(Eq(X(2), 5) & Eq(X(1), 2)) == Rational(81, 4)*exp(-6)
  576. # check few properties
  577. 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))
  578. assert P(X(2) <= 3, X(1) > 1) == 2*P(Eq(X(1), 0)) + 1*P(Eq(X(1), 1))
  579. assert P(Eq(X(2), 5) & Eq(X(1), 2)) == P(Eq(X(1), 3))*P(Eq(X(1), 2))
  580. assert P(Eq(X(3), 4), Eq(X(1), 3)) == P(Eq(X(2), 1))
  581. #test issue 20078
  582. assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
  583. assert (2*X(t) - 3*X(t)).simplify() == -X(t)
  584. assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
  585. assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
  586. assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
  587. def test_WienerProcess():
  588. X = WienerProcess("X")
  589. assert X.state_space == S.Reals
  590. assert X.index_set == Interval(0, oo)
  591. t, d, x, y = symbols('t d x y', positive=True)
  592. assert isinstance(X(t), RandomIndexedSymbol)
  593. assert X.distribution(t) == NormalDistribution(0, sqrt(t))
  594. with warns_deprecated_sympy():
  595. X.distribution(X(t))
  596. raises(ValueError, lambda: PoissonProcess("X", -1))
  597. raises(NotImplementedError, lambda: X[t])
  598. raises(IndexError, lambda: X(-2))
  599. assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(
  600. Lambda((X(2), X(3)), sqrt(6)*exp(-X(2)**2/4)*exp(-X(3)**2/6)/(12*pi)))
  601. assert X.joint_distribution(4, 6) == JointDistributionHandmade(
  602. Lambda((X(4), X(6)), sqrt(6)*exp(-X(4)**2/8)*exp(-X(6)**2/12)/(24*pi)))
  603. assert P(X(t) < 3).simplify() == erf(3*sqrt(2)/(2*sqrt(t)))/2 + S(1)/2
  604. assert P(X(t) > 2, Contains(t, Interval.Lopen(3, 7))).simplify() == S(1)/2 -\
  605. erf(sqrt(2)/2)/2
  606. # Equivalent to P(X(1)>1)**4
  607. assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1),
  608. Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2))
  609. & Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() ==\
  610. (1 - erf(sqrt(2)/2))*(1 - erf(sqrt(2)))*(1 - erf(3*sqrt(2)/2))*(1 - erf(2*sqrt(2)))/16
  611. # Contains an overlapping interval so, return Probability
  612. assert P((X(t)< 2) & (X(d)> 3), Contains(t, Interval.Lopen(0, 2))
  613. & Contains(d, Interval.Ropen(2, 4))) == Probability((X(d) > 3) & (X(t) < 2),
  614. Contains(d, Interval.Ropen(2, 4)) & Contains(t, Interval.Lopen(0, 2)))
  615. assert str(P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) &
  616. Contains(d, Interval.Lopen(7, 8))).simplify()) == \
  617. '-(1 - erf(3*sqrt(2)/2))*(2 - erfc(5/2))/4 + 1'
  618. # Distribution has mean 0 at each timestamp
  619. assert E(X(t)) == 0
  620. assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1))
  621. & Contains(d, Interval.Ropen(1, 2))) == Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2),
  622. Contains(d, Interval.Ropen(1, 2)) & Contains(t, Interval.Lopen(0, 1)))
  623. assert E(X(t) + x*E(X(3))) == 0
  624. #test issue 20078
  625. assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
  626. assert (2*X(t) - 3*X(t)).simplify() == -X(t)
  627. assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
  628. assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
  629. assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
  630. def test_GammaProcess_symbolic():
  631. t, d, x, y, g, l = symbols('t d x y g l', positive=True)
  632. X = GammaProcess("X", l, g)
  633. raises(NotImplementedError, lambda: X[t])
  634. raises(IndexError, lambda: X(-1))
  635. assert isinstance(X(t), RandomIndexedSymbol)
  636. assert X.state_space == Interval(0, oo)
  637. assert X.distribution(t) == GammaDistribution(g*t, 1/l)
  638. with warns_deprecated_sympy():
  639. X.distribution(X(t))
  640. assert X.joint_distribution(5, X(3)) == JointDistributionHandmade(Lambda(
  641. (X(5), X(3)), l**(8*g)*exp(-l*X(3))*exp(-l*X(5))*X(3)**(3*g - 1)*X(5)**(5*g
  642. - 1)/(gamma(3*g)*gamma(5*g))))
  643. # property of the gamma process at any given timestamp
  644. assert E(X(t)) == g*t/l
  645. assert variance(X(t)).simplify() == g*t/l**2
  646. # Equivalent to E(2*X(1)) + E(X(1)**2) + E(X(1)**3), where E(X(1)) == g/l
  647. assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1))
  648. & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == \
  649. 2*g/l + (g**2 + g)/l**2 + (g**3 + 3*g**2 + 2*g)/l**3
  650. assert P(X(t) > 3, Contains(t, Interval.Lopen(3, 4))).simplify() == \
  651. 1 - lowergamma(g, 3*l)/gamma(g) # equivalent to P(X(1)>3)
  652. #test issue 20078
  653. assert (2*X(t) + 3*X(t)).simplify() == 5*X(t)
  654. assert (2*X(t) - 3*X(t)).simplify() == -X(t)
  655. assert (2*(0.25*X(t))).simplify() == 0.5*X(t)
  656. assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2
  657. assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2
  658. def test_GammaProcess_numeric():
  659. t, d, x, y = symbols('t d x y', positive=True)
  660. X = GammaProcess("X", 1, 2)
  661. assert X.state_space == Interval(0, oo)
  662. assert X.index_set == Interval(0, oo)
  663. assert X.lamda == 1
  664. assert X.gamma == 2
  665. raises(ValueError, lambda: GammaProcess("X", -1, 2))
  666. raises(ValueError, lambda: GammaProcess("X", 0, -2))
  667. raises(ValueError, lambda: GammaProcess("X", -1, -2))
  668. # all are independent because of non-overlapping intervals
  669. assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), Contains(t,
  670. Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x,
  671. Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() == \
  672. 120*exp(-10)
  673. # Check working with Not and Or
  674. assert P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) &
  675. Contains(d, Interval.Lopen(7, 8))).simplify() == -4*exp(-3) + 472*exp(-8)/3 + 1
  676. assert P((X(t) > 2) | (X(t) < 4), Contains(t, Interval.Ropen(1, 4))).simplify() == \
  677. -643*exp(-4)/15 + 109*exp(-2)/15 + 1
  678. assert E(X(t)) == 2*t # E(X(t)) == gamma*t/l
  679. assert E(X(2) + x*E(X(5))) == 10*x + 4