CombinatoricsAxiomsTest.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. namespace MathPHP\Tests\Probability;
  3. use MathPHP\Probability\Combinatorics;
  4. /**
  5. * Tests of Combinatorics axioms
  6. * These tests don't test specific functions,
  7. * but rather combinatorics axioms which in term make use of multiple functions.
  8. * If all the combinatorics math is implemented properly, these tests should
  9. * all work out according to the axioms.
  10. *
  11. * Axioms tested:
  12. * - Lah numbers, rising and falling factorials
  13. * - x⁽ⁿ⁾ = ∑ L⟮n,k⟯ x₍k₎
  14. * - x₍n₎ = ∑ (-1)ⁿ⁻ᵏ L(n,k) x⁽ᵏ⁾
  15. * - L(n,1) = n!
  16. * - L(n,2) = (n - 1)n! / 2
  17. * - L(n,n) = 1
  18. */
  19. class CombinatoricsAxiomsTest extends \PHPUnit\Framework\TestCase
  20. {
  21. /**
  22. * @testCase Axiom: x⁽ⁿ⁾ = L⟮n,k⟯ x₍k₎
  23. * Rising factorial can be represented as the summation of Lah numbers and falling factorials
  24. *
  25. * @dataProvider dataProivderForLahNumbers
  26. * @param int $x
  27. * @param int $n
  28. * @throws \Exception
  29. */
  30. public function testRisingFactorialAsLahNumberAndFallingFactorial(int $x, int $n)
  31. {
  32. $x⁽ⁿ⁾ = Combinatorics::risingFactorial($x, $n);
  33. $∑L⟮n、k⟯x₍k₎ = 0;
  34. for ($k = 1; $k <= $n; $k++) {
  35. $x₍k₎ = Combinatorics::fallingFactorial($x, $k);
  36. $L⟮n、k⟯ = Combinatorics::lahNumber($n, $k);
  37. $∑L⟮n、k⟯x₍k₎ += $L⟮n、k⟯ * $x₍k₎;
  38. }
  39. $this->assertEquals($x⁽ⁿ⁾, $∑L⟮n、k⟯x₍k₎);
  40. }
  41. /**
  42. * @testCase Axiom: x₍n₎ = ∑ (-1)ⁿ⁻ᵏ L(n,k) x⁽ᵏ⁾
  43. * Falling factorial can be represented as the summation of Lah numbers and rising factorials
  44. *
  45. * @dataProvider dataProivderForLahNumbers
  46. * @param int $x
  47. * @param int $n
  48. * @throws \Exception
  49. */
  50. public function testFallingFactorialAsLahNumberAndRisingFactorial(int $x, int $n)
  51. {
  52. $x₍n₎ = Combinatorics::fallingFactorial($x, $n);
  53. $∑⟮−1⟯ⁿ⁻ᵏL⟮n、k⟯x₍k₎ = 0;
  54. for ($k = 1; $k <= $n; $k++) {
  55. $⟮−1⟯ⁿ⁻ᵏ = (-1) ** ($n - $k);
  56. $L⟮n、k⟯ = Combinatorics::lahNumber($n, $k);
  57. $x⁽ᵏ⁾ = Combinatorics::risingFactorial($x, $k);
  58. $∑⟮−1⟯ⁿ⁻ᵏL⟮n、k⟯x₍k₎ += $⟮−1⟯ⁿ⁻ᵏ * $L⟮n、k⟯ * $x⁽ᵏ⁾;
  59. }
  60. $this->assertEquals($x₍n₎, $∑⟮−1⟯ⁿ⁻ᵏL⟮n、k⟯x₍k₎);
  61. }
  62. /**
  63. * @testCase Axiom: L(n,1) = n!
  64. * Lah number identity when k is 1
  65. *
  66. * @dataProvider dataProivderForLahNumberIdentities
  67. * @param int $n
  68. * @throws \Exception
  69. */
  70. public function testLahNumberIdentityKEqualsOne(int $n)
  71. {
  72. $L⟮n、1⟯ = Combinatorics::lahNumber($n, 1);
  73. $n! = Combinatorics::factorial($n);
  74. $this->assertEquals($L⟮n、1⟯, $n!);
  75. }
  76. /**
  77. * @testCase Axiom: L(n,2) = (n - 1)n! / 2
  78. * Lah number identity when k is 2
  79. *
  80. * @dataProvider dataProivderForLahNumberIdentitiesGreaterThanOne
  81. * @param int $n
  82. * @throws \Exception
  83. */
  84. public function testLahNumberIdentityKEqualsTwo(int $n)
  85. {
  86. $L⟮n、1⟯ = Combinatorics::lahNumber($n, 2);
  87. $⟮n−1⟯n!/2 = (($n - 1) * Combinatorics::factorial($n)) / 2;
  88. $this->assertEquals($L⟮n、1⟯, $⟮n−1⟯n!/2);
  89. }
  90. /**
  91. * @testCase Axiom: L(n,n) = 1
  92. * Lah number identity when n = n
  93. *
  94. * @dataProvider dataProivderForLahNumberIdentities
  95. * @param int $n
  96. * @throws \Exception
  97. */
  98. public function testLahNumberIdentityNNEqualsOne(int $n)
  99. {
  100. $L⟮n、n⟯ = Combinatorics::lahNumber($n, $n);
  101. $this->assertEquals(1, $L⟮n、n⟯);
  102. }
  103. /**
  104. * @return array [n, k]
  105. */
  106. public function dataProivderForLahNumbers(): array
  107. {
  108. return [
  109. [1, 1],
  110. [5, 1],
  111. [5, 2],
  112. [5, 3],
  113. [4, 4],
  114. [3, 5],
  115. [2, 6],
  116. [1, 1],
  117. [2, 1],
  118. [2, 2],
  119. [3, 1],
  120. [3, 2],
  121. [3, 3],
  122. [4, 1],
  123. [4, 2],
  124. [4, 3],
  125. [4, 4],
  126. [5, 1],
  127. [5, 2],
  128. [5, 3],
  129. [5, 4],
  130. [5, 5],
  131. [6, 1],
  132. [6, 2],
  133. [6, 3],
  134. [6, 4],
  135. [6, 5],
  136. [6, 6],
  137. [12, 1],
  138. [12, 2],
  139. [12, 3],
  140. [12, 4],
  141. [12, 5],
  142. [12, 6],
  143. [12, 7],
  144. [12, 8],
  145. [12, 9],
  146. [12, 10],
  147. [12, 11],
  148. [12, 12],
  149. ];
  150. }
  151. /**
  152. * @return array [n]
  153. */
  154. public function dataProivderForLahNumberIdentities(): array
  155. {
  156. return [
  157. [1],
  158. [2],
  159. [3],
  160. [4],
  161. [5],
  162. [6],
  163. [7],
  164. [8],
  165. [9],
  166. [12],
  167. ];
  168. }
  169. /**
  170. * @return array [n]
  171. */
  172. public function dataProivderForLahNumberIdentitiesGreaterThanOne(): array
  173. {
  174. return [
  175. [2],
  176. [3],
  177. [4],
  178. [5],
  179. [6],
  180. [7],
  181. [8],
  182. [9],
  183. [12],
  184. ];
  185. }
  186. }