Commit 7d0df6c9 authored by Taddeus Kroes's avatar Taddeus Kroes

Added absolute value to linear equation rules.

parent 03feca7a
from .utils import find_variable
from .utils import find_variable, evals_to_numeric
from ..node import ExpressionLeaf as L, Scope, OP_EQ, OP_ADD, OP_MUL, OP_DIV, \
eq
eq, OP_ABS
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
......@@ -23,18 +23,23 @@ def match_move_term(node):
# Multiplication
x / a = b -> x / a * a = b * a # =>* x = a * b
a / x = b -> a / x * x = b * x # =>* x = a / b
-x = b -> -x * -1 = b * -1 # =>* x = -b
-x = b -> -x * -1 = b * -1 # =>* x = -b
# Absolute value
|f(x)| = c and eval(c) in Z -> f(x) = c vv f(x) = -c
"""
assert node.is_op(OP_EQ)
x = find_variable(node)
left, right = node
p = []
# Swap the left and right side if only the right side contains x
if not left.contains(x):
return [P(node, swap_sides)]
# Swap the left and right side if only the right side contains x
if right.contains(x):
p.append(P(node, swap_sides))
p = []
return p
# Bring terms without x to the right
if left.is_op(OP_ADD):
......@@ -62,6 +67,10 @@ def match_move_term(node):
if left.negated:
p.append(P(node, multiply_term, (-L(1),)))
# Split absolute equations into two separate, non-absolute equations
if left.is_op(OP_ABS) and evals_to_numeric(right):
p.append(P(node, split_absolute_equation))
return p
......@@ -117,3 +126,16 @@ def multiply_term(root, args):
MESSAGES[multiply_term] = _('Multiply both sides of the equation with {1}.')
def split_absolute_equation(root, args):
"""
|f(x)| = c and eval(c) in Z -> f(x) = c vv f(x) = -c
"""
(f,), c = root
return eq(f, c) | eq(f, -c)
MESSAGES[split_absolute_equation] = _('Split absolute equation {0} into a ' \
'negative and a positive equation.')
......@@ -3,6 +3,7 @@ import doctest
from src.node import ExpressionNode
from src.parser import Parser
from src.validation import validate
from tests.parser import ParserWrapper
......@@ -73,3 +74,7 @@ class RulesTestCase(unittest.TestCase):
e.args = (e.message,) + e.args[1:]
raise
def assertValidate(self, exp, result):
self.assertTrue(validate(exp, result),
'Validation failed: %s !=> %s')
from src.rules.lineq import match_move_term, swap_sides, subtract_term, \
divide_term, multiply_term
divide_term, multiply_term, split_absolute_equation
from src.node import Scope
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -41,6 +41,15 @@ class TestRulesLineq(RulesTestCase):
self.assertEqualPos(match_move_term(root),
[P(root, multiply_term, (l1,))])
def test_match_move_term_absolute(self):
root = tree('|x| = 2')
self.assertEqualPos(match_move_term(root),
[P(root, split_absolute_equation)])
root = tree('|x - 1| = 2')
self.assertEqualPos(match_move_term(root),
[P(root, split_absolute_equation)])
def test_swap_sides(self):
root, expect = tree('a = bx, bx = a')
self.assertEqual(swap_sides(root, ()), expect)
......@@ -57,6 +66,13 @@ class TestRulesLineq(RulesTestCase):
root, a, expect = tree('x / a = b, a, x / a * a = b * a')
self.assertEqual(multiply_term(root, (a,)), expect)
def test_split_absolute_equation(self):
root, expect = tree('|x| = 2, x = 2 vv x = -2')
self.assertEqual(split_absolute_equation(root, ()), expect)
# FIXME: following call exeeds recursion limit
# FIXME: self.assertValidate('|x - 1| = 2', 'x = -1 vv x = 3')
def test_match_move_term_chain_negation(self):
self.assertRewrite([
'2x + 3 = -3x - 2',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment