lineq.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from .utils import find_variable
  2. from ..node import ExpressionLeaf as L, Scope, OP_EQ, OP_ADD, OP_MUL, OP_DIV, \
  3. eq
  4. from ..possibilities import Possibility as P, MESSAGES
  5. from ..translate import _
  6. def match_move_term(node):
  7. """
  8. Perform the same action on both sides of the equation such that variable
  9. terms are moved to the left, and constants (in relation to the variable
  10. that is being solved) are brought to the right side of the equation.
  11. If the variable is only present on the right side of the equation, swap the
  12. sides first.
  13. # Swap
  14. a = b * x -> b * x = a
  15. # Subtraction
  16. x + a = b -> x + a - a = b - a
  17. a = b + x -> a - x = b + x - x # =>* x = b / a
  18. # Division
  19. x * a = b -> x * a / a = b / a # =>* x = b / a
  20. # Multiplication
  21. x / a = b -> x / a * a = b * a # =>* x = a * b
  22. a / x = b -> a / x * x = b * x # =>* x = a / b
  23. -x = b -> -x * -1 = b * -1 # =>* x = -b
  24. """
  25. assert node.is_op(OP_EQ)
  26. x = find_variable(node)
  27. left, right = node
  28. # Swap the left and right side if only the right side contains x
  29. if not left.contains(x):
  30. return [P(node, swap_sides)]
  31. p = []
  32. # Bring terms without x to the right
  33. if left.is_op(OP_ADD):
  34. for n in Scope(left):
  35. if not n.contains(x):
  36. p.append(P(node, subtract_term, (n,)))
  37. # Bring terms with x to the left
  38. if right.is_op(OP_ADD):
  39. for n in Scope(right):
  40. if n.contains(x):
  41. p.append(P(node, subtract_term, (n,)))
  42. # Divide both sides by a constant to 'free' x
  43. if left.is_op(OP_MUL):
  44. for n in Scope(left):
  45. if not n.contains(x):
  46. p.append(P(node, divide_term, (n,)))
  47. # Multiply both sides by the denominator to move x out of the division
  48. if left.is_op(OP_DIV):
  49. p.append(P(node, multiply_term, (left[1],)))
  50. # Remove any negation from the left side of the equation
  51. if left.negated:
  52. p.append(P(node, multiply_term, (-L(1),)))
  53. return p
  54. def swap_sides(root, args):
  55. """
  56. a = bx -> bx = a
  57. """
  58. left, right = root
  59. return eq(right, left)
  60. MESSAGES[swap_sides] = _('Swap the left and right side of the equation so ' \
  61. 'that the variable is on the left side.')
  62. def subtract_term(root, args):
  63. """
  64. x + a = b -> x + a - a = b - a
  65. a = b + x -> a - x = b + x - x
  66. """
  67. left, right = root
  68. term = args[0]
  69. return eq(left - term, right - term)
  70. MESSAGES[subtract_term] = _('Subtract {1} from both sides of the equation.')
  71. def divide_term(root, args):
  72. """
  73. x * a = b -> x * a / a = b / a # =>* x = b / a
  74. """
  75. left, right = root
  76. term = args[0]
  77. return eq(left / term, right / term)
  78. MESSAGES[divide_term] = _('Divide both sides of the equation by {1}.')
  79. def multiply_term(root, args):
  80. """
  81. x / a = b -> x / a * a = b * a # =>* x = a * b
  82. a / x = b -> a / x * x = b * x # =>* x = a / b
  83. """
  84. left, right = root
  85. term = args[0]
  86. return eq(left * term, right * term)
  87. MESSAGES[multiply_term] = _('Multiply both sides of the equation with {1}.')