Commit aa2d137d authored by Taddeus Kroes's avatar Taddeus Kroes

Implemented standard radians.

parent be87484c
from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS, \
OP_TAN
from .groups import match_combine_groups from .groups import match_combine_groups
from .factors import match_expand from .factors import match_expand
from .powers import match_add_exponents, match_subtract_exponents, \ from .powers import match_add_exponents, match_subtract_exponents, \
...@@ -13,7 +14,7 @@ from .negation import match_negated_factor, match_negate_polynome, \ ...@@ -13,7 +14,7 @@ from .negation import match_negated_factor, match_negate_polynome, \
match_negated_division match_negated_division
from .sort import match_sort_multiplicants from .sort import match_sort_multiplicants
from .goniometry import match_add_quadrants, match_negated_parameter, \ from .goniometry import match_add_quadrants, match_negated_parameter, \
match_half_pi_subtraction match_half_pi_subtraction, match_standard_radian
RULES = { RULES = {
OP_ADD: [match_add_numerics, match_add_constant_fractions, OP_ADD: [match_add_numerics, match_add_constant_fractions,
...@@ -28,6 +29,9 @@ RULES = { ...@@ -28,6 +29,9 @@ RULES = {
match_remove_negative_exponent, match_exponent_to_root, match_remove_negative_exponent, match_exponent_to_root,
match_extend_exponent, match_constant_exponent], match_extend_exponent, match_constant_exponent],
OP_NEG: [match_negate_polynome], OP_NEG: [match_negate_polynome],
OP_SIN: [match_negated_parameter, match_half_pi_subtraction], OP_SIN: [match_negated_parameter, match_half_pi_subtraction,
OP_COS: [match_negated_parameter, match_half_pi_subtraction], match_standard_radian],
OP_COS: [match_negated_parameter, match_half_pi_subtraction,
match_standard_radian],
OP_TAN: [match_standard_radian],
} }
from .utils import is_fraction from .utils import is_fraction
from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_ADD, \ from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_ADD, \
OP_POW, OP_MUL, OP_SIN, OP_COS, OP_TAN, PI OP_POW, OP_MUL, OP_DIV, OP_SIN, OP_COS, OP_TAN, PI, TYPE_OPERATOR
from ..possibilities import Possibility as P, MESSAGES from ..possibilities import Possibility as P, MESSAGES
from ..translate import _ from ..translate import _
...@@ -102,9 +102,44 @@ def match_half_pi_subtraction(node): ...@@ -102,9 +102,44 @@ def match_half_pi_subtraction(node):
return [] return []
def is_pi_frac(node, denominator):
"""
Check if a node is a fraction of 1 multiplied with PI.
Example:
>>> print is_pi_frac(L(1) / 2 * L(PI), 2)
True
"""
if not node.is_op(OP_MUL):
return False
frac, pi = node
if not frac.is_op(OP_DIV) or not pi.is_leaf or pi.value != PI:
return False
n, d = frac
return n == 1 and d == denominator
def sqrt(value):
return N('sqrt', L(value))
l0, l1, sq2, sq3 = L(0), L(1), sqrt(2), sqrt(3)
half = l1 / 2
CONSTANTS = {
OP_SIN: [l0, half, half * sq2, half * sq3, l1],
OP_COS: [l1, half * sq3, half * sq2, half, l0],
OP_TAN: [l0, l1 / 3 * sq3, l1, sq3]
}
def match_standard_radian(node): def match_standard_radian(node):
""" """
Apply a direct constant calculation from the following table. Apply a direct constant calculation from the constants table.
| 0 | pi / 6 | pi / 4 | pi / 3 | pi / 2 | 0 | pi / 6 | pi / 4 | pi / 3 | pi / 2
----+---+-----------+-----------+-----------+------- ----+---+-----------+-----------+-----------+-------
...@@ -112,5 +147,29 @@ def match_standard_radian(node): ...@@ -112,5 +147,29 @@ def match_standard_radian(node):
cos | 1 | sqrt(3)/2 | sqrt(2)/2 | 1/2 | 0 cos | 1 | sqrt(3)/2 | sqrt(2)/2 | 1/2 | 0
tan | 0 | sqrt(3)/3 | 1 | sqrt(3) | - tan | 0 | sqrt(3)/3 | 1 | sqrt(3) | -
""" """
# TODO: implement assert node.type == TYPE_OPERATOR and node.op in (OP_SIN, OP_COS, OP_TAN)
pass
t = node[0]
if t == 0:
return [P(node, standard_radian, (node.op, 0))]
denoms = [6, 4, 3]
if node.op != OP_TAN:
denoms.append(2)
for i, denominator in enumerate(denoms):
if is_pi_frac(t, denominator):
return [P(node, standard_radian, (node.op, i + 1))]
return []
def standard_radian(root, args):
op, column = args
return CONSTANTS[op][column].clone()
MESSAGES[standard_radian] = _('Replace standard radian {0}.')
# vim: set fileencoding=utf-8 : # vim: set fileencoding=utf-8 :
from src.rules.goniometry import match_add_quadrants, add_quadrants, \ from src.rules.goniometry import sin, cos, tan, match_add_quadrants, \
match_negated_parameter, negated_sinus_parameter, \ add_quadrants, match_negated_parameter, negated_sinus_parameter, \
negated_cosinus_parameter, sin, cos negated_cosinus_parameter, match_standard_radian, standard_radian, \
is_pi_frac
from src.node import PI, OP_SIN, OP_COS, OP_TAN
from src.possibilities import Possibility as P from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree from tests.rulestestcase import RulesTestCase, tree
from src.rules import goniometry
import doctest
class TestRulesGoniometry(RulesTestCase): class TestRulesGoniometry(RulesTestCase):
def test_doctest(self):
self.assertEqual(doctest.testmod(m=goniometry)[0], 0)
def test_match_add_quadrants(self): def test_match_add_quadrants(self):
root = tree('sin t ^ 2 + cos t ^ 2') root = tree('sin t ^ 2 + cos t ^ 2')
possibilities = match_add_quadrants(root) possibilities = match_add_quadrants(root)
...@@ -35,3 +42,30 @@ class TestRulesGoniometry(RulesTestCase): ...@@ -35,3 +42,30 @@ class TestRulesGoniometry(RulesTestCase):
c = tree('cos -t') c = tree('cos -t')
t = c[0] t = c[0]
self.assertEqual(negated_cosinus_parameter(c, (t,)), cos(+t)) self.assertEqual(negated_cosinus_parameter(c, (t,)), cos(+t))
def test_is_pi_frac(self):
l1, pi = tree('1,' + PI)
self.assertTrue(is_pi_frac(l1 / 2 * pi, 2))
self.assertFalse(is_pi_frac(l1 / 2 * pi, 3))
self.assertFalse(is_pi_frac(l1 * pi, 3))
def test_match_standard_radian(self):
s, c, t = tree('sin(1 / 6 * pi), cos(1 / 2 * pi), tan(0)')
self.assertEqualPos(match_standard_radian(s), \
[P(s, standard_radian, (OP_SIN, 1))])
self.assertEqualPos(match_standard_radian(c), \
[P(c, standard_radian, (OP_COS, 4))])
self.assertEqualPos(match_standard_radian(t), \
[P(t, standard_radian, (OP_TAN, 0))])
def test_standard_radian(self):
l0, l1, sq3, pi6, pi4, pi2 = tree('0,1,sqrt(3),1/6*pi,1/4*pi,1/2*pi')
self.assertEqual(standard_radian(sin(pi6), (OP_SIN, 1)), l1 / 2)
self.assertEqual(standard_radian(sin(pi2), (OP_SIN, 4)), 1)
self.assertEqual(standard_radian(cos(l0), (OP_COS, 0)), 1)
self.assertEqual(standard_radian(tan(pi4), (OP_TAN, 3)), sq3)
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