Skip to content
Snippets Groups Projects
Commit 71bb5823 authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Implemented substitution for solving sets of linear equations..

parent ce4874ef
No related branches found
No related tags found
No related merge requests found
......@@ -294,8 +294,9 @@ class Parser(BisonParser):
while self.possibilities:
# Find the first implicit possibliity in the list
# FIXME: Is it smart to apply a rule that is not a hint?
# ANSWER: Yes, but there must be an extra list that prevents
# deliberately generated implicit rules from being applied
# ANSWER: Yes, but there must be something like an extra list
# that prevents deliberately generated implicit rules from
# being applied
#sugg = self.possibilities[0]
#if sugg.handler not in IMPLICIT_RULES:
......
from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS, \
OP_TAN, OP_DER, OP_LOG, OP_INT, OP_INT_INDEF, OP_EQ, OP_ABS, OP_SQRT
OP_TAN, OP_DER, OP_LOG, OP_INT, OP_INT_INDEF, OP_EQ, OP_ABS, OP_SQRT, \
OP_AND
from .groups import match_combine_groups
from .factors import match_expand
from .powers import match_add_exponents, match_subtract_exponents, \
......@@ -27,7 +28,7 @@ from .integrals import match_solve_indef, match_constant_integral, \
match_integrate_variable_power, match_factor_out_constant, \
match_division_integral, match_function_integral, \
match_sum_rule_integral, match_remove_indef_constant
from .lineq import match_move_term
from .lineq import match_move_term, match_multiple_equations
from .absolute import match_factor_out_abs_term
from .sqrt import match_reduce_sqrt
......@@ -67,4 +68,5 @@ RULES = {
OP_EQ: [match_move_term],
OP_ABS: [match_factor_out_abs_term],
OP_SQRT: [match_reduce_sqrt],
OP_AND: [match_multiple_equations],
}
from .utils import find_variable, evals_to_numeric
from itertools import permutations
from .utils import find_variable, evals_to_numeric, substitute
from ..node import ExpressionLeaf as L, Scope, OP_EQ, OP_ADD, OP_MUL, OP_DIV, \
eq, OP_ABS
eq, OP_ABS, OP_AND
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
......@@ -148,3 +150,47 @@ def split_absolute_equation(root, args):
MESSAGES[split_absolute_equation] = _('Split absolute equation {0} into a ' \
'negative and a positive equation.')
def match_multiple_equations(node):
"""
Multiple equations can be solved using substitution and/or elimination.
Substitution rule:
x = a ^^ f(x) = g(x) -> x = a ^^ f(a) = g(a) # Substitute x with a
Substitution example:
x = ay + b ^^ cx + dy = e -> x = ay + b ^^ c(ay + b) + dy = e
# =>* x = eval(a * eval((e - bc) / (ca + b)) + b)
# ^^ y = eval((e - bc) / (ca + b))
"""
assert node.is_op(OP_AND)
scope = Scope(node)
equations = filter(lambda exp: exp.is_op(OP_EQ), scope)
p = []
if len(equations) < 2:
return p
for eq0, eq1 in permutations(equations, 2):
x, subs = eq0
# Substitution rule
if x.is_variable() and eq1.contains(x):
p.append(P(node, substitute_variable, (scope, x, subs, eq1)))
return p
def substitute_variable(root, args):
"""
Substitution rule:
x = a ^^ f(x) = g(x) -> x = a ^^ f(a) = g(a) # Substitute x with a
"""
scope, x, subs, eq = args
scope.replace(eq, substitute(eq, x, subs))
return scope.as_nary_node()
MESSAGES[substitute_variable] = _('Substitute {2} with {3} in {4}.')
......@@ -12,6 +12,7 @@ from .fractions import multiply_with_fraction, extract_fraction_terms, \
from .integrals import factor_out_constant, integrate_variable_root
from .powers import remove_power_of_one
from .sqrt import quadrant_sqrt, extract_sqrt_mult_priority
from .lineq import substitute_variable, swap_sides
# Functions to move to the beginning of the possibilities list. Pairs of within
......@@ -39,7 +40,7 @@ LOW = [
# higher priority than B. This list ignores occurences in the HIGH or LOW lists
# above
RELATIVE = [
# Precedences needed for 'power rule'
# Precedences needed for 'power rule' (derivative of an exponentiation)
(chain_rule, raised_base),
(raised_base, factor_out_exponent),
......@@ -58,11 +59,15 @@ RELATIVE = [
# root first
(extract_sqrt_mult_priority, multiply_numerics),
# sqrt(2 ^ 2) -> 2 # not sqrt 4
# sqrt(2 ^ 2) -> 2 # rather than sqrt(4)
(quadrant_sqrt, raise_numerics),
#
# Prevent cycles that are caused by multiplication reductions when
# splitting up fractions
(extract_fraction_terms, multiply_numerics),
# Prevent useless swapping when solving multiple equations
(substitute_variable, swap_sides),
]
......@@ -84,6 +89,5 @@ IMPLICIT_RULES = [
remove_zero,
remove_power_of_one,
negated_factor,
multiply_numerics,
add_numerics,
]
from src.rules.lineq import match_move_term, swap_sides, subtract_term, \
divide_term, multiply_term, split_absolute_equation
divide_term, multiply_term, split_absolute_equation, \
match_multiple_equations, substitute_variable
from src.node import Scope
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -107,3 +109,15 @@ class TestRulesLineq(RulesTestCase):
'x = -a * 1',
'x = -a',
])
def test_match_multiple_equations(self):
eq0, eq1 = root = tree('x = 2 ^^ ay + x = 3')
x = eq0[0]
self.assertEqualPos(match_multiple_equations(root),
[P(root, substitute_variable, (Scope(root), x, 2, eq1))])
def test_substitute_variable(self):
root, expect = tree('x = 2 ^^ ay + x = 3, x = 2 ^^ ay + 2 = 3')
(x, l2), eq = root
self.assertEqual(substitute_variable(root, ((Scope(root), x, l2, eq))),
expect)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment