test_rules_powers.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. # This file is part of TRS (http://math.kompiler.org)
  2. #
  3. # TRS is free software: you can redistribute it and/or modify it under the
  4. # terms of the GNU Affero General Public License as published by the Free
  5. # Software Foundation, either version 3 of the License, or (at your option) any
  6. # later version.
  7. #
  8. # TRS is distributed in the hope that it will be useful, but WITHOUT ANY
  9. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  10. # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  11. # details.
  12. #
  13. # You should have received a copy of the GNU Affero General Public License
  14. # along with TRS. If not, see <http://www.gnu.org/licenses/>.
  15. from src.rules.powers import match_add_exponents, add_exponents, \
  16. match_subtract_exponents, subtract_exponents, \
  17. match_multiply_exponents, multiply_exponents, \
  18. match_duplicate_exponent, duplicate_exponent, \
  19. match_raised_fraction, raised_fraction, \
  20. match_remove_negative_child, remove_negative_exponent, \
  21. remove_negative_root, match_exponent_to_root, exponent_to_root, \
  22. match_constant_exponent, remove_power_of_zero, remove_power_of_one
  23. from src.node import Scope, ExpressionNode as N
  24. from src.possibilities import Possibility as P
  25. from tests.rulestestcase import RulesTestCase, tree
  26. class TestRulesPowers(RulesTestCase):
  27. def test_match_add_exponents_binary(self):
  28. a, p, q = tree('a,p,q')
  29. n0, n1 = root = a ** p * a ** q
  30. possibilities = match_add_exponents(root)
  31. self.assertEqualPos(possibilities,
  32. [P(root, add_exponents, (Scope(root), n0, n1, a, p, q))])
  33. def test_match_add_exponents_ternary(self):
  34. a, p, q, r = tree('a,p,q,r')
  35. (n0, n1), n2 = root = a ** p * a ** q * a ** r
  36. possibilities = match_add_exponents(root)
  37. self.assertEqualPos(possibilities,
  38. [P(root, add_exponents, (Scope(root), n0, n1, a, p, q)),
  39. P(root, add_exponents, (Scope(root), n0, n2, a, p, r)),
  40. P(root, add_exponents, (Scope(root), n1, n2, a, q, r))])
  41. def test_match_add_exponents_multiple_identifiers(self):
  42. a, b, p, q = tree('a,b,p,q')
  43. ((a0, b0), a1), b1 = root = a ** p * b ** p * a ** q * b ** q
  44. possibilities = match_add_exponents(root)
  45. self.assertEqualPos(possibilities,
  46. [P(root, add_exponents, (Scope(root), a0, a1, a, p, q)),
  47. P(root, add_exponents, (Scope(root), b0, b1, b, p, q))])
  48. def test_match_add_exponents_nary_multiplication(self):
  49. a, p, q = tree('a,p,q')
  50. (n0, l1), n1 = root = a ** p * 2 * a ** q
  51. possibilities = match_add_exponents(root)
  52. self.assertEqualPos(possibilities,
  53. [P(root, add_exponents, (Scope(root), n0, n1, a, p, q))])
  54. def test_match_add_exponents_negated(self):
  55. a, q = tree('a,q')
  56. n0, n1 = root = (-a) * a ** q
  57. possibilities = match_add_exponents(root)
  58. self.assertEqualPos(possibilities,
  59. [P(root, add_exponents, (Scope(root), n0, n1, a, 1, q))])
  60. def test_match_subtract_exponents_powers(self):
  61. a, p, q = tree('a,p,q')
  62. root = a ** p / a ** q
  63. possibilities = match_subtract_exponents(root)
  64. self.assertEqualPos(possibilities,
  65. [P(root, subtract_exponents, (a, p, q))])
  66. def test_match_subtract_power_id(self):
  67. a, p = tree('a,p')
  68. root = a ** p / a
  69. possibilities = match_subtract_exponents(root)
  70. self.assertEqualPos(possibilities,
  71. [P(root, subtract_exponents, (a, p, 1))])
  72. def test_match_subtract_id_power(self):
  73. a, q = tree('a,q')
  74. root = a / a ** q
  75. possibilities = match_subtract_exponents(root)
  76. self.assertEqualPos(possibilities,
  77. [P(root, subtract_exponents, (a, 1, q))])
  78. def test_match_multiply_exponents(self):
  79. a, p, q = tree('a,p,q')
  80. root = (a ** p) ** q
  81. possibilities = match_multiply_exponents(root)
  82. self.assertEqualPos(possibilities,
  83. [P(root, multiply_exponents, (a, p, q))])
  84. def test_match_duplicate_exponent(self):
  85. a, b, p = tree('a,b,p')
  86. root = (a * b) ** p
  87. possibilities = match_duplicate_exponent(root)
  88. self.assertEqualPos(possibilities,
  89. [P(root, duplicate_exponent, ([a, b], p))])
  90. def test_match_raised_fraction(self):
  91. ab, p = root = tree('(a / b) ^ p')
  92. self.assertEqualPos(match_raised_fraction(root),
  93. [P(root, raised_fraction, (ab, p))])
  94. def test_raised_fraction(self):
  95. ab, p = root = tree('(a / b) ^ p')
  96. a, b = ab
  97. self.assertEqual(raised_fraction(root, (ab, p)), a ** p / b ** p)
  98. def test_match_remove_negative_child(self):
  99. root = tree('a ^ -p')
  100. self.assertEqualPos(match_remove_negative_child(root),
  101. [P(root, remove_negative_exponent)])
  102. root = tree('(-a) ^ 3')
  103. self.assertEqualPos(match_remove_negative_child(root),
  104. [P(root, remove_negative_root)])
  105. root = tree('(-a) ^ 2')
  106. self.assertEqualPos(match_remove_negative_child(root), [])
  107. root = tree('(-a) ^ -3')
  108. self.assertEqualPos(match_remove_negative_child(root),
  109. [P(root, remove_negative_exponent),
  110. P(root, remove_negative_root)])
  111. def test_match_exponent_to_root(self):
  112. a, n, m, l1 = tree('a,n,m,1')
  113. root = a ** (n / m)
  114. possibilities = match_exponent_to_root(root)
  115. self.assertEqualPos(possibilities,
  116. [P(root, exponent_to_root, (a, n, m))])
  117. root = a ** (l1 / m)
  118. possibilities = match_exponent_to_root(root)
  119. self.assertEqualPos(possibilities,
  120. [P(root, exponent_to_root, (a, 1, m))])
  121. def test_add_exponents(self):
  122. a, p, q = tree('a,p,q')
  123. n0, n1 = root = a ** p * a ** q
  124. self.assertEqualNodes(add_exponents(root,
  125. (Scope(root), n0, n1, a, p, q)), a ** (p + q))
  126. def test_subtract_exponents(self):
  127. a, p, q = tree('a,p,q')
  128. root = a ** p / a ** q
  129. self.assertEqualNodes(subtract_exponents(root, (a, p, q)),
  130. a ** (p - q))
  131. def test_multiply_exponents(self):
  132. a, p, q = tree('a,p,q')
  133. root = (a ** p) ** q
  134. self.assertEqualNodes(multiply_exponents(root, (a, p, q)),
  135. a ** (p * q))
  136. def test_duplicate_exponent(self):
  137. a, b, c, p = tree('a,b,c,p')
  138. root = (a * b) ** p
  139. self.assertEqualNodes(duplicate_exponent(root, ([a, b], p)),
  140. a ** p * b ** p)
  141. root = (a * b * c) ** p
  142. self.assertEqualNodes(duplicate_exponent(root, ([a, b, c], p)),
  143. a ** p * b ** p * c ** p)
  144. def test_remove_negative_exponent(self):
  145. a, p, l1 = tree('a,-p,1')
  146. root = a ** p
  147. self.assertEqualNodes(remove_negative_exponent(root, ()),
  148. l1 / a ** +p)
  149. def test_remove_negative_root(self):
  150. root, expect = tree('(-a) ^ 3, -a ^ 3')
  151. self.assertEqualNodes(remove_negative_root(root, ()), expect)
  152. root, expect = tree('(-a) ^ -3, -a ^ -3')
  153. self.assertEqualNodes(remove_negative_root(root, ()), expect)
  154. def test_exponent_to_root(self):
  155. a, n, m, l1 = tree('a,n,m,1')
  156. root = a ** (n / m)
  157. self.assertEqualNodes(exponent_to_root(root, (a, n, m)),
  158. N('sqrt', a ** n, m))
  159. self.assertEqualNodes(exponent_to_root(root, (a, l1, m)),
  160. N('sqrt', a, m))
  161. def test_match_constant_exponent(self):
  162. a0, a1, a2 = tree('a ^ 0, a ^ 1, a ^ 2')
  163. self.assertEqualPos(match_constant_exponent(a0),
  164. [P(a0, remove_power_of_zero, ())])
  165. self.assertEqualPos(match_constant_exponent(a1),
  166. [P(a1, remove_power_of_one, ())])
  167. self.assertEqualPos(match_constant_exponent(a2), [])
  168. def test_remove_power_of_zero(self):
  169. self.assertEqual(remove_power_of_zero(tree('a0'), ()), 1)
  170. def test_remove_power_of_one(self):
  171. a1 = tree('a1')
  172. self.assertEqual(remove_power_of_one(a1, ()), a1[0])