test_rules_derivatives.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. from src.rules.derivatives import der, get_derivation_variable, \
  2. match_zero_derivative, match_one_derivative, one_derivative, \
  3. zero_derivative, match_variable_power, variable_root, \
  4. variable_exponent, match_const_deriv_multiplication, \
  5. const_deriv_multiplication, chain_rule, match_logarithmic, \
  6. logarithmic, match_goniometric, sinus, cosinus, tangens, \
  7. match_sum_product_rule, sum_rule, product_rule, match_quotient_rule, \
  8. quotient_rule, power_rule
  9. from src.rules.logarithmic import ln
  10. from src.rules.goniometry import sin, cos
  11. from src.node import Scope
  12. from src.possibilities import Possibility as P
  13. from tests.rulestestcase import RulesTestCase, tree
  14. class TestRulesDerivatives(RulesTestCase):
  15. def test_get_derivation_variable(self):
  16. xy0, xy1, x, l1 = tree('der(xy, x), der(xy), der(x), der(1)')
  17. self.assertEqual(get_derivation_variable(xy0), 'x')
  18. self.assertEqual(get_derivation_variable(xy1), 'x')
  19. self.assertEqual(get_derivation_variable(x), 'x')
  20. self.assertIsNone(get_derivation_variable(l1))
  21. def test_match_zero_derivative(self):
  22. root = tree('der(x, y)')
  23. self.assertEqualPos(match_zero_derivative(root),
  24. [P(root, zero_derivative)])
  25. root = tree('der(2)')
  26. self.assertEqualPos(match_zero_derivative(root),
  27. [P(root, zero_derivative)])
  28. def test_zero_derivative(self):
  29. root = tree('der(1)')
  30. self.assertEqual(zero_derivative(root, ()), 0)
  31. def test_match_one_derivative(self):
  32. root = tree('der(x)')
  33. self.assertEqualPos(match_one_derivative(root),
  34. [P(root, one_derivative)])
  35. root = tree('der(x, x)')
  36. self.assertEqualPos(match_one_derivative(root),
  37. [P(root, one_derivative)])
  38. def test_one_derivative(self):
  39. root = tree('der(x)')
  40. self.assertEqual(one_derivative(root, ()), 1)
  41. def test_match_const_deriv_multiplication(self):
  42. root = tree('der(2x)')
  43. l2, x = root[0]
  44. self.assertEqualPos(match_const_deriv_multiplication(root),
  45. [P(root, const_deriv_multiplication, (Scope(root[0]), l2, x))])
  46. (x, y), x = root = tree('der(xy, x)')
  47. self.assertEqualPos(match_const_deriv_multiplication(root),
  48. [P(root, const_deriv_multiplication, (Scope(root[0]), y, x))])
  49. def test_match_const_deriv_multiplication_multiple_constants(self):
  50. root = tree('der(2x * 3)')
  51. (l2, x), l3 = root[0]
  52. scope = Scope(root[0])
  53. self.assertEqualPos(match_const_deriv_multiplication(root),
  54. [P(root, const_deriv_multiplication, (scope, l2, x)),
  55. P(root, const_deriv_multiplication, (scope, l3, x))])
  56. def test_const_deriv_multiplication(self):
  57. root = tree('der(2x)')
  58. l2, x = root[0]
  59. args = Scope(root[0]), l2, x
  60. self.assertEqual(const_deriv_multiplication(root, args),
  61. l2 * der(x, x))
  62. def test_match_variable_power(self):
  63. root, x, l2 = tree('der(x ^ 2), x, 2')
  64. self.assertEqualPos(match_variable_power(root),
  65. [P(root, variable_root)])
  66. root = tree('der(2 ^ x)')
  67. self.assertEqualPos(match_variable_power(root),
  68. [P(root, variable_exponent)])
  69. def test_match_variable_power_chain_rule(self):
  70. root, x, l2, x3 = tree('der((x ^ 3) ^ 2), x, 2, x ^ 3')
  71. self.assertEqualPos(match_variable_power(root),
  72. [P(root, chain_rule, (x3, variable_root, ()))])
  73. root = tree('der(2 ^ x ^ 3)')
  74. self.assertEqualPos(match_variable_power(root),
  75. [P(root, chain_rule, (x3, variable_exponent, ()))])
  76. # Below is not mathematically underivable, it's just not within the
  77. # scope of our program
  78. root, x = tree('der(x ^ x), x')
  79. self.assertEqualPos(match_variable_power(root),
  80. [P(root, power_rule)])
  81. def test_power_rule(self):
  82. root, expect = tree("[x ^ x]', [e ^ ln(x ^ x)]'")
  83. self.assertEqual(power_rule(root, ()), expect)
  84. def test_power_rule_chain(self):
  85. self.assertRewrite([
  86. "[x ^ x]'",
  87. "[e ^ ln(x ^ x)]'",
  88. "[e ^ (xln(x))]'",
  89. "e ^ (xln(x))ln(e)[xln(x)]'",
  90. "e ^ (xln(x))1[xln(x)]'",
  91. "e ^ (xln(x))[xln(x)]'",
  92. "e ^ (xln(x))([x]' * ln(x) + x[ln(x)]')",
  93. "e ^ (xln(x))(1ln(x) + x[ln(x)]')",
  94. "e ^ (xln(x))(ln(x) + x[ln(x)]')",
  95. "e ^ (xln(x))(ln(x) + x(1 / (xln(e))))",
  96. "e ^ (xln(x))(ln(x) + x(1 / (x * 1)))",
  97. "e ^ (xln(x))(ln(x) + x(1 / x))",
  98. "e ^ (xln(x))(ln(x) + x * 1 / x)",
  99. "e ^ (xln(x))(ln(x) + x / x)",
  100. "e ^ (xln(x))(ln(x) + 1)",
  101. "e ^ ln(x ^ x)(ln(x) + 1)",
  102. # FIXME: "x ^ x(ln(x) + 1)", -> needs strategy
  103. ])
  104. def test_variable_root(self):
  105. root = tree('der(x ^ 2)')
  106. x, n = root[0]
  107. self.assertEqual(variable_root(root, ()), n * x ** (n - 1))
  108. def test_variable_exponent(self):
  109. root = tree('der(2 ^ x)')
  110. g, x = root[0]
  111. self.assertEqual(variable_exponent(root, ()), g ** x * ln(g))
  112. def test_chain_rule(self):
  113. root = tree('der(2 ^ x ^ 3)')
  114. l2, x3 = root[0]
  115. x, l3 = x3
  116. self.assertEqual(chain_rule(root, (x3, variable_exponent, ())),
  117. l2 ** x3 * ln(l2) * der(x3))
  118. def test_match_logarithmic(self):
  119. root = tree('der(log(x))')
  120. self.assertEqualPos(match_logarithmic(root), [P(root, logarithmic)])
  121. def test_match_logarithmic_chain_rule(self):
  122. root, f = tree('der(log(x ^ 2)), x ^ 2')
  123. self.assertEqualPos(match_logarithmic(root),
  124. [P(root, chain_rule, (f, logarithmic, ()))])
  125. def test_logarithmic(self):
  126. root, x, l1, l10 = tree('der(log(x)), x, 1, 10')
  127. self.assertEqual(logarithmic(root, ()), l1 / (x * ln(l10)))
  128. def test_match_goniometric(self):
  129. root = tree('der(sin(x))')
  130. self.assertEqualPos(match_goniometric(root), [P(root, sinus)])
  131. root = tree('der(cos(x))')
  132. self.assertEqualPos(match_goniometric(root), [P(root, cosinus)])
  133. root = tree('der(tan(x))')
  134. self.assertEqualPos(match_goniometric(root), [P(root, tangens)])
  135. def test_match_goniometric_chain_rule(self):
  136. root, x2 = tree('der(sin(x ^ 2)), x ^ 2')
  137. self.assertEqualPos(match_goniometric(root),
  138. [P(root, chain_rule, (x2, sinus, ()))])
  139. root = tree('der(cos(x ^ 2))')
  140. self.assertEqualPos(match_goniometric(root),
  141. [P(root, chain_rule, (x2, cosinus, ()))])
  142. def test_sinus(self):
  143. root, x = tree('der(sin(x)), x')
  144. self.assertEqual(sinus(root, ()), cos(x))
  145. def test_cosinus(self):
  146. root, x = tree('der(cos(x)), x')
  147. self.assertEqual(cosinus(root, ()), -sin(x))
  148. def test_tangens(self):
  149. root, x = tree('der(tan(x), x), x')
  150. self.assertEqual(tangens(root, ()), der(sin(x) / cos(x), x))
  151. root = tree('der(tan(x))')
  152. self.assertEqual(tangens(root, ()), der(sin(x) / cos(x)))
  153. def test_match_sum_product_rule_sum(self):
  154. root = tree('der(x ^ 2 + x)')
  155. x2, x = f = root[0]
  156. self.assertEqualPos(match_sum_product_rule(root),
  157. [P(root, sum_rule, (Scope(f), x2)),
  158. P(root, sum_rule, (Scope(f), x))])
  159. root = tree('der(x ^ 2 + 3 + x)')
  160. self.assertEqualPos(match_sum_product_rule(root),
  161. [P(root, sum_rule, (Scope(root[0]), x2)),
  162. P(root, sum_rule, (Scope(root[0]), x))])
  163. def test_match_sum_product_rule_product(self):
  164. root = tree('der(x ^ 2 * x)')
  165. x2, x = f = root[0]
  166. self.assertEqualPos(match_sum_product_rule(root),
  167. [P(root, product_rule, (Scope(f), x2)),
  168. P(root, product_rule, (Scope(f), x))])
  169. def test_match_sum_product_rule_none(self):
  170. root = tree('der(x ^ 2 + 2)')
  171. self.assertEqualPos(match_sum_product_rule(root), [])
  172. root = tree('der(x ^ 2 * 2)')
  173. self.assertEqualPos(match_sum_product_rule(root), [])
  174. def test_sum_rule(self):
  175. root = tree('der(x ^ 2 + x)')
  176. x2, x = f = root[0]
  177. self.assertEqual(sum_rule(root, (Scope(f), x2)), der(x2) + der(x))
  178. self.assertEqual(sum_rule(root, (Scope(f), x)), der(x) + der(x2))
  179. root = tree('der(x ^ 2 + 3 + x)')
  180. (x2, l3), x = f = root[0]
  181. self.assertEqual(sum_rule(root, (Scope(f), x2)), der(x2) + der(l3 + x))
  182. self.assertEqual(sum_rule(root, (Scope(f), x)), der(x) + der(x2 + l3))
  183. def test_product_rule(self):
  184. root = tree('der(x ^ 2 * x)')
  185. x2, x = f = root[0]
  186. self.assertEqual(product_rule(root, (Scope(f), x2)),
  187. der(x2) * x + x2 * der(x))
  188. self.assertEqual(product_rule(root, (Scope(f), x)),
  189. der(x) * x2 + x * der(x2))
  190. root = tree('der(x ^ 2 * x * x ^ 3)')
  191. (x2, x), x3 = f = root[0]
  192. self.assertEqual(product_rule(root, (Scope(f), x2)),
  193. der(x2) * (x * x3) + x2 * der(x * x3))
  194. self.assertEqual(product_rule(root, (Scope(f), x)),
  195. der(x) * (x2 * x3) + x * der(x2 * x3))
  196. self.assertEqual(product_rule(root, (Scope(f), x3)),
  197. der(x3) * (x2 * x) + x3 * der(x2 * x))
  198. def test_match_quotient_rule(self):
  199. root = tree('der(x ^ 2 / x)')
  200. self.assertEqualPos(match_quotient_rule(root),
  201. [P(root, quotient_rule)])
  202. root = tree('der(x ^ 2 / 2)')
  203. self.assertEqualPos(match_quotient_rule(root), [])
  204. def test_quotient_rule(self):
  205. root = tree('der(x ^ 2 / x)')
  206. f, g = root[0]
  207. self.assertEqual(quotient_rule(root, ()),
  208. (der(f) * g - f * der(g)) / g ** 2)
  209. def test_natural_pase_chain(self):
  210. self.assertRewrite([
  211. 'der(e ^ x)',
  212. 'e ^ x * ln(e)',
  213. 'e ^ x * 1',
  214. 'e ^ x',
  215. ])