test_rules_logarithmic.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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.logarithmic import log, match_constant_logarithm, \
  16. base_equals_raised, logarithm_of_one, divide_same_base, \
  17. match_add_logarithms, add_logarithms, expand_negations, \
  18. subtract_logarithms, match_raised_base, raised_base, \
  19. match_factor_out_exponent, split_negative_exponent, \
  20. factor_out_exponent, match_factor_in_multiplicant, \
  21. factor_in_multiplicant, match_expand_terms, \
  22. expand_multiplication_terms, expand_division_terms, \
  23. factor_in_exponent_multiplicant, factor_out_exponent_important, \
  24. make_raised_base
  25. from src.node import Scope
  26. from src.possibilities import Possibility as P
  27. from tests.rulestestcase import RulesTestCase, tree
  28. class TestRulesLogarithmic(RulesTestCase):
  29. def test_match_constant_logarithm(self):
  30. self.assertRaises(ValueError, match_constant_logarithm,
  31. tree('log_1(a)'))
  32. root = tree('log 1')
  33. self.assertEqualPos(match_constant_logarithm(root),
  34. [P(root, logarithm_of_one)])
  35. root = tree('log 10')
  36. self.assertEqualPos(match_constant_logarithm(root),
  37. [P(root, base_equals_raised),
  38. P(root, divide_same_base)])
  39. root = tree('log(a, a)')
  40. self.assertEqualPos(match_constant_logarithm(root),
  41. [P(root, base_equals_raised),
  42. P(root, divide_same_base)])
  43. root = tree('log(a, b)')
  44. self.assertEqualPos(match_constant_logarithm(root),
  45. [P(root, divide_same_base)])
  46. def test_logarithm_of_one(self):
  47. root = tree('log 1')
  48. self.assertEqual(logarithm_of_one(root, ()), 0)
  49. def test_base_equals_raised(self):
  50. root, expect = tree('log(a, a), 1')
  51. self.assertEqual(base_equals_raised(root, ()), expect)
  52. root, expect = tree('-log(a, a), -1')
  53. self.assertEqual(base_equals_raised(root, ()), expect)
  54. def test_divide_same_base(self):
  55. root, l5, l6 = tree('log(5, 6), 5, 6')
  56. self.assertEqual(divide_same_base(root, ()), log(l5) / log(l6))
  57. def test_match_add_logarithms(self):
  58. root = tree('log a + ln b')
  59. self.assertEqualPos(match_add_logarithms(root), [])
  60. # log(ab) is not desired if ab is not reduceable
  61. root = tree('log a + log b')
  62. self.assertEqualPos(match_add_logarithms(root), [])
  63. log_a, log_b = root = tree('log 2 + log 3')
  64. self.assertEqualPos(match_add_logarithms(root),
  65. [P(root, add_logarithms, (Scope(root), log_a, log_b))])
  66. log_a, log_b = root = tree('-log 2 - log 3')
  67. self.assertEqualPos(match_add_logarithms(root),
  68. [P(root, expand_negations, (Scope(root), log_a, log_b))])
  69. # log(2 / 3) is not desired because 2 / 3 cannot be reduced
  70. log_a, log_b = root = tree('log 2 - log 3')
  71. self.assertEqualPos(match_add_logarithms(root), [])
  72. log_a, log_b = root = tree('log 4 - log 2')
  73. self.assertEqualPos(match_add_logarithms(root),
  74. [P(root, subtract_logarithms, (Scope(root), log_a, log_b))])
  75. log_a, log_b = root = tree('-log 2 + log 4')
  76. self.assertEqualPos(match_add_logarithms(root),
  77. [P(root, subtract_logarithms, (Scope(root), log_b, log_a))])
  78. def test_add_logarithms(self):
  79. root, expect = tree('log a + log b, log(ab)')
  80. log_a, log_b = root
  81. self.assertEqual(add_logarithms(root, (Scope(root), log_a, log_b)),
  82. expect)
  83. def test_expand_negations(self):
  84. root, expect = tree('-log(a) - log(b), -(log(a) + log(b))')
  85. log_a, log_b = root
  86. self.assertEqual(expand_negations(root, (Scope(root), log_a, log_b)),
  87. expect)
  88. def test_subtract_logarithms(self):
  89. root, expect = tree('log(a) - log(b), log(a / b)')
  90. loga, logb = root
  91. self.assertEqual(subtract_logarithms(root, (Scope(root), loga, logb)),
  92. expect)
  93. root, expect = tree('-log(a) + log(b), log(b / a)')
  94. loga, logb = root
  95. self.assertEqual(subtract_logarithms(root, (Scope(root), logb, loga)),
  96. expect)
  97. def test_match_raised_base(self):
  98. root, a = tree('2 ^ log_2(a), a')
  99. self.assertEqualPos(match_raised_base(root),
  100. [P(root, raised_base, (a,))])
  101. root, a = tree('e ^ ln(a), a')
  102. self.assertEqualPos(match_raised_base(root),
  103. [P(root, raised_base, (a,))])
  104. root = tree('2 ^ log_3(a)')
  105. self.assertEqualPos(match_raised_base(root), [])
  106. root = tree('e ^ (2ln x)')
  107. l2, lnx = mul = root[1]
  108. self.assertEqualPos(match_raised_base(root),
  109. [P(root, factor_in_exponent_multiplicant,
  110. (Scope(mul), l2, lnx))])
  111. def test_factor_in_exponent_multiplicant(self):
  112. root, expect = tree('e ^ (2ln x), e ^ ln x ^ 2')
  113. l2, lnx = mul = root[1]
  114. self.assertEqual(factor_in_exponent_multiplicant(root,
  115. (Scope(mul), l2, lnx)), expect)
  116. def test_raised_base(self):
  117. root, a = tree('2 ^ log_2(a), a')
  118. self.assertEqual(raised_base(root, (root[1][0],)), a)
  119. def test_match_factor_out_exponent(self):
  120. for root in tree('log(a ^ 2), log(2 ^ a), log(a ^ a), log(2 ^ 2)'):
  121. self.assertEqualPos(match_factor_out_exponent(root),
  122. [P(root, factor_out_exponent)])
  123. root = tree('log(a ^ -b)')
  124. self.assertEqualPos(match_factor_out_exponent(root),
  125. [P(root, split_negative_exponent),
  126. P(root, factor_out_exponent)])
  127. def test_match_factor_out_exponent_important(self):
  128. root = tree('log(10 ^ 2)')
  129. self.assertEqualPos(match_factor_out_exponent(root),
  130. [P(root, factor_out_exponent_important)])
  131. def test_match_factor_out_exponent_make_raised_base(self):
  132. root = tree('log(100)')
  133. self.assertEqualPos(match_factor_out_exponent(root),
  134. [P(root, make_raised_base, (2,))])
  135. root = tree('log(1000)')
  136. self.assertEqualPos(match_factor_out_exponent(root),
  137. [P(root, make_raised_base, (3,))])
  138. root = tree('log_2(16)')
  139. self.assertEqualPos(match_factor_out_exponent(root),
  140. [P(root, make_raised_base, (4,))])
  141. root = tree('log(99)')
  142. self.assertEqualPos(match_factor_out_exponent(root), [])
  143. def test_split_negative_exponent(self):
  144. root, expect = tree('log(a ^ -b), log((a ^ b) ^ -1)')
  145. self.assertEqual(split_negative_exponent(root, ()), expect)
  146. def test_factor_out_exponent(self):
  147. ((a, l2), l10) = root = tree('log(a ^ 2)')
  148. self.assertEqual(factor_out_exponent(root, ()), l2 * log(a))
  149. def test_make_raised_base(self):
  150. root, expect = tree('log(1000), log(10 ^ 3)')
  151. self.assertEqual(make_raised_base(root, (3,)), expect)
  152. root, expect = tree('log_2(64), log_2(2 ^ 4)')
  153. self.assertEqual(make_raised_base(root, (4,)), expect)
  154. def test_factor_out_exponent_important(self):
  155. ((a, l2), l10) = root = tree('log(10 ^ 2)')
  156. self.assertEqual(factor_out_exponent_important(root, ()), l2 * log(a))
  157. def test_match_factor_in_multiplicant(self):
  158. (l2, log_3) = root = tree('2log(3)')
  159. self.assertEqualPos(match_factor_in_multiplicant(root),
  160. [P(root, factor_in_multiplicant, (Scope(root), l2, log_3))])
  161. (l2, log_3), l4 = root = tree('2log(3)4')
  162. self.assertEqualPos(match_factor_in_multiplicant(root),
  163. [P(root, factor_in_multiplicant, (Scope(root), l2, log_3)),
  164. P(root, factor_in_multiplicant, (Scope(root), l4, log_3))])
  165. root = tree('2log(a)')
  166. self.assertEqualPos(match_factor_in_multiplicant(root), [])
  167. root = tree('alog(3)')
  168. self.assertEqualPos(match_factor_in_multiplicant(root), [])
  169. def test_factor_in_multiplicant(self):
  170. root, expect = tree('2log(3), log(3 ^ 2)')
  171. l2, log3 = root
  172. self.assertEqual(factor_in_multiplicant(root, (Scope(root), l2, log3)),
  173. expect)
  174. def test_match_expand_terms(self):
  175. ab, base = root = tree('log(2x)')
  176. a, b = ab
  177. self.assertEqualPos(match_expand_terms(root),
  178. [P(root, expand_multiplication_terms, (Scope(ab), b))])
  179. root = tree('log(2 * 3)')
  180. self.assertEqualPos(match_expand_terms(root), [])
  181. root = tree('log(2 / a)')
  182. self.assertEqualPos(match_expand_terms(root),
  183. [P(root, expand_division_terms)])
  184. def test_expand_multiplication_terms(self):
  185. root, expect = tree('log(2x), log x + log 2')
  186. self.assertEqual(expand_multiplication_terms(root,
  187. (Scope(root[0]), root[0][1])), expect)
  188. def test_expand_division_terms(self):
  189. root, expect = tree('log(2 / x), log 2 - log x')
  190. self.assertEqual(expand_division_terms(root, ()), expect)