Merge branch 'dev' into 2nd_deg

This commit is contained in:
Lafrite 2015-03-08 18:56:59 +01:00
commit 285b71d2da
6 changed files with 129 additions and 51 deletions

2
TODO
View File

@ -9,5 +9,3 @@
* Expression parents class and his children: Numerical_exp, toGenerate_exp and formal expression * Expression parents class and his children: Numerical_exp, toGenerate_exp and formal expression
* Create tbl sgn and variation render * Create tbl sgn and variation render

View File

@ -139,10 +139,15 @@ class Operator(str):
return ans return ans
def add_parenthesis(self, op): def add_parenthesis(self, op):
""" Add parenthesis if necessary """ """ Add parenthesis if necessary
>>> from pymath.polynom import Polynom
>>> P = Polynom([1,2,3])
"""
try: try:
if op.mainOp.priority < self.priority: if op.mainOp.priority < self.priority:
op = flatten_list(["("] + [op] + [")"]) op = flatten_list(["(", op, ")"])
except AttributeError: except AttributeError:
# op has not the attribute priority # op has not the attribute priority
try: try:
@ -293,7 +298,7 @@ class op(object):
caract = { caract = {
"operator" : "-", \ "operator" : "-", \
"name" : "sub",\ "name" : "sub",\
"priority" : 1, \ "priority" : 2, \
"arity" : 2, \ "arity" : 2, \
"actions" : ("__sub__","__rsub__"), \ "actions" : ("__sub__","__rsub__"), \
"txt" : "{op1} - {op2}",\ "txt" : "{op1} - {op2}",\
@ -336,7 +341,7 @@ class op(object):
caract = { caract = {
"operator" : "-", \ "operator" : "-", \
"name" : "sub1",\ "name" : "sub1",\
"priority" : 2, \ "priority" : 3, \
"arity" : 1, \ "arity" : 1, \
"actions" : "__neg__",\ "actions" : "__neg__",\
"txt" : "- {op1}",\ "txt" : "- {op1}",\
@ -461,7 +466,7 @@ class op(object):
caract = { caract = {
"operator" : "^", \ "operator" : "^", \
"name" : "pw",\ "name" : "pw",\
"priority" : 5, \ "priority" : 6, \
"arity" : 2, \ "arity" : 2, \
"actions" : ("__pow__",""), \ "actions" : ("__pow__",""), \
"txt" : "{op1} ^ {op2}",\ "txt" : "{op1} ^ {op2}",\

View File

@ -5,8 +5,8 @@
from .expression import Expression from .expression import Expression
from .explicable import Explicable from .explicable import Explicable
from .operator import op from .operator import op
from .generic import spe_zip, expand_list, isNumber, transpose_fill, flatten_list, isPolynom from .generic import spe_zip, expand_list, isNumber, transpose_fill, flatten_list, isPolynom, isNumerand
from .render import txt from .render import txt,tex
from .random_expression import RdExpression from .random_expression import RdExpression
from itertools import chain from itertools import chain
from functools import wraps from functools import wraps
@ -33,7 +33,7 @@ class Polynom(Explicable):
"""Docstring for Polynom. """ """Docstring for Polynom. """
@classmethod @classmethod
def random(self, coefs_form=[], conditions=[], letter = "x", degree = 0): def random(self, coefs_form=[], conditions=[], letter = "x", degree = 0, name = "P"):
""" Create a random polynom from coefs_form and conditions """ Create a random polynom from coefs_form and conditions
:param coefs_form: list of forms (one by coef) (ascending degree sorted) :param coefs_form: list of forms (one by coef) (ascending degree sorted)
@ -64,9 +64,9 @@ class Polynom(Explicable):
# On "parse" ce string pour créer les coefs # On "parse" ce string pour créer les coefs
coefs = [eval(i) if type(i)==str else i for i in eval(coefs)] coefs = [eval(i) if type(i)==str else i for i in eval(coefs)]
# Création du polynom # Création du polynom
return Polynom(coefs = coefs, letter = letter) return Polynom(coefs = coefs, letter = letter, name = name)
def __init__(self, coefs = [1], letter = "x" ): def __init__(self, coefs = [1], letter = "x", name = "P"):
"""Initiate the polynom """Initiate the polynom
:param coef: coefficients of the polynom (ascending degree sorted) :param coef: coefficients of the polynom (ascending degree sorted)
@ -75,25 +75,36 @@ class Polynom(Explicable):
- [a,b,c]: list of coeficient for same degree. [1,[2,3],4] designate 1 + 2x + 3x + 4x^2 - [a,b,c]: list of coeficient for same degree. [1,[2,3],4] designate 1 + 2x + 3x + 4x^2
- a: a Expression. [1, Expression("2+3"), 4] designate 1 + (2+3)x + 4x^2 - a: a Expression. [1, Expression("2+3"), 4] designate 1 + (2+3)x + 4x^2
:param letter: the string describing the unknown :param letter: the string describing the unknown
:param name: Name of the polynom
>>> Polynom([1,2,3]).mainOp >>> P = Polynom([1, 2, 3])
>>> P.mainOp
'+' '+'
>>> P.name
'P'
>>> P._letter
'x'
>>> Polynom([1]).mainOp >>> Polynom([1]).mainOp
'*' '*'
>>> Polynom([0, 0, 3]).mainOp
'*'
>>> Polynom([1, 2, 3])._letter >>> Polynom([1, 2, 3])._letter
'x' 'x'
>>> Polynom([1, 2, 3], "y")._letter >>> Polynom([1, 2, 3], "y")._letter
'y' 'y'
>>> Polynom([1, 2, 3], name = "Q").name
'Q'
""" """
super(Polynom, self).__init__() super(Polynom, self).__init__()
self.feed_coef(coefs) self.feed_coef(coefs)
self._letter = letter self._letter = letter
self.name = name
if self.is_monom(): if self.is_monom():
self.mainOp = "*" self.mainOp = op.mul
else: else:
self.mainOp = "+" self.mainOp = op.add
self._isPolynom = 1 self._isPolynom = 1
@ -102,13 +113,27 @@ class Polynom(Explicable):
:returns: Expression ready to be simplify :returns: Expression ready to be simplify
>>> P = Polynom([1, 2, 3])
>>> P(2)
17
>>> for i in P(2).explain():
... print(i)
3 \\times 2^{ 2 } + 2 \\times 2 + 1
3 \\times 4 + 4 + 1
12 + 4 + 1
16 + 1
17
>>> Q = P("1+h")
>>> print(Q)
3 h^{ 2 } + 8 h + 6
>>> R = P(Q)
""" """
if isNumber(value): if isNumerand(value) or Expression.isExpression(value):
postfix_exp = [value if i==self._letter else i for i in self.postfix_tokens] postfix_exp = [value if i==self._letter else i for i in self.postfix_tokens]
else: else:
postfix_exp = [Expression(value) if i==self._letter else i for i in self.postfix_tokens] postfix_exp = [Expression(value) if i==self._letter else i for i in self.postfix_tokens]
return Expression(postfix_exp) return Expression(postfix_exp).simplify()
def feed_coef(self, l_coef): def feed_coef(self, l_coef):
"""Feed coef of the polynom. Manage differently whether it's a number or an expression """Feed coef of the polynom. Manage differently whether it's a number or an expression
@ -157,10 +182,10 @@ class Polynom(Explicable):
return "< Polynom " + str(self._coef) + ">" return "< Polynom " + str(self._coef) + ">"
def __txt__(self): def __txt__(self):
return self.postfix_tokens return txt(self.postfix_tokens)
def __tex__(self): def __tex__(self):
return self.postfix_tokens return tex(self.postfix_tokens)
def coef_postfix(self, a, i): def coef_postfix(self, a, i):
"""Return the postfix display of a coeficient """Return the postfix display of a coeficient
@ -392,6 +417,8 @@ class Polynom(Explicable):
>>> Q = P.derivate() >>> Q = P.derivate()
>>> Q >>> Q
< Polynom [2, 6]> < Polynom [2, 6]>
>>> print(Q.name)
P'
>>> for i in Q.explain(): >>> for i in Q.explain():
... print(i) ... print(i)
2 \\times 3 x + 1 \\times 2 2 \\times 3 x + 1 \\times 2
@ -400,7 +427,10 @@ class Polynom(Explicable):
derv_coefs = [] derv_coefs = []
for (i,c) in enumerate(self._coef): for (i,c) in enumerate(self._coef):
derv_coefs += [Expression([i, c, op.mul])] derv_coefs += [Expression([i, c, op.mul])]
return Polynom(derv_coefs[1:]).simplify()
ans = Polynom(derv_coefs[1:]).simplify()
ans.name = self.name + "'"
return ans
@staticmethod @staticmethod
def postfix_add(numbers): def postfix_add(numbers):
@ -525,12 +555,15 @@ class Polynom(Explicable):
[[< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>, < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>] [[< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>, < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>]
>>> p*r >>> p*r
< Polynom [0, 1, 2]> < Polynom [0, 1, 2]>
>>> P = Polynom([1,2,3])
>>> Q = Polynom([4,5,6])
>>> P*Q
< Polynom [4, 13, 28, 27, 18]>
""" """
# TODO: Je trouve qu'elle grille trop d'étapes... |ven. févr. 27 19:08:44 CET 2015 # TODO: Je trouve qu'elle grille trop d'étapes... |ven. févr. 27 19:08:44 CET 2015
o_poly = self.conv2poly(other) o_poly = self.conv2poly(other)
coefs = [] coefs = [0]*(self.degree + o_poly.degree + 1)
for (i,a) in enumerate(self._coef): for (i,a) in enumerate(self._coef):
for (j,b) in enumerate(o_poly._coef): for (j,b) in enumerate(o_poly._coef):
if a == 0 or b == 0: if a == 0 or b == 0:
@ -541,13 +574,14 @@ class Polynom(Explicable):
elem = a elem = a
else: else:
elem = Expression([a, b, op.mul]) elem = Expression([a, b, op.mul])
try:
if coefs[i+j]==0: if coefs[i+j]==0:
coefs[i+j] = elem coefs[i+j] = elem
elif elem != 0: elif elem != 0:
if type(coefs[i+j]) == list:
coefs[i+j] += [elem]
else:
coefs[i+j] = [coefs[i+j] , elem] coefs[i+j] = [coefs[i+j] , elem]
except IndexError:
coefs.append(elem)
p = Polynom(coefs, letter = self._letter) p = Polynom(coefs, letter = self._letter)
ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.mul])] ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.mul])]
@ -578,6 +612,9 @@ class Polynom(Explicable):
>>> p = Polynom([0,0,1]) >>> p = Polynom([0,0,1])
>>> p**3 >>> p**3
< Polynom [0, 0, 0, 0, 0, 0, 1]> < Polynom [0, 0, 0, 0, 0, 0, 1]>
>>> p = Polynom([1,2,3])
>>> p**2
< Polynom [1, 4, 10, 12, 9]>
""" """
if not type(power): if not type(power):
@ -648,7 +685,7 @@ if __name__ == '__main__':
#from .fraction import Fraction #from .fraction import Fraction
#with Expression.tmp_render(txt): #with Expression.tmp_render(txt):
# p = Polynom([1, 2, 3]) # p = Polynom([1, 2, 3])
# q = Polynom([0, 2]) # q = Polynom([4, 5, 6])
# for i in (p*q).explain(): # for i in (p*q).explain():
# print(i) # print(i)
# r = Polynom([0,1]) # r = Polynom([0,1])
@ -662,7 +699,7 @@ if __name__ == '__main__':
# print(p-q) # print(p-q)
# for i in p-q: # for i in p-q:
# print(i) # print(i)
Polynom.random(degree = 2, conditions=["{b**2-4*a*c}>0"]) # Polynom deg 2 with positive Delta (ax^2 + bx + c) #Polynom.random(degree = 2, conditions=["{b**2-4*a*c}>0"]) # Polynom deg 2 with positive Delta (ax^2 + bx + c)
import doctest import doctest

View File

@ -35,12 +35,12 @@ class Polynom_deg2(Polynom):
# Création du polynom # Création du polynom
return Polynom_deg2(coefs = coefs, letter = letter) return Polynom_deg2(coefs = coefs, letter = letter)
def __init__(self, coefs = [0, 0, 1], letter = "x"): def __init__(self, coefs = [0, 0, 1], letter = "x", name = "P"):
if len(coefs) < 3 or len(coefs) > 4: if len(coefs) < 3 or len(coefs) > 4:
raise ValueError("Polynom_deg2 have to be degree 2 polynoms, they need 3 coefficients, {} are given".format(len(coefs))) raise ValueError("Polynom_deg2 have to be degree 2 polynoms, they need 3 coefficients, {} are given".format(len(coefs)))
if coefs[2] == 0: if coefs[2] == 0:
raise ValueError("Polynom_deg2 have to be degree 2 polynoms, coefficient of x^2 can't be 0") raise ValueError("Polynom_deg2 have to be degree 2 polynoms, coefficient of x^2 can't be 0")
Polynom.__init__(self, coefs, letter) Polynom.__init__(self, coefs, letter, name = name)
@property @property
def a(self): def a(self):

View File

@ -33,20 +33,19 @@ class TestPolynom(unittest.TestCase):
def test_eval_base(self): def test_eval_base(self):
p = Polynom([1, 2]) p = Polynom([1, 2])
self.assertEqual(p(3).simplify(), 7) self.assertEqual(p(3), 7)
def test_eval_const(self): def test_eval_const(self):
p = Polynom([1]) p = Polynom([1])
self.assertEqual(p(3).simplify(), 1) self.assertEqual(p(3), 1)
def test_eval_const_neg(self): def test_eval_const_neg(self):
p = Polynom([-1]) p = Polynom([-1])
self.assertEqual(p(3).simplify(), -1) self.assertEqual(p(3), -1)
def test_eval_poly(self): def test_eval_poly(self):
p = Polynom([1, 2]) p = Polynom([1, 2])
hp1 = Expression("h+1") self.assertEqual(p("h+1"), Polynom([3,2], "h"))
self.assertEqual(p(hp1).simplify(), Polynom([3,2], "h"))
#def test_print(self): #def test_print(self):
# p = Polynom([1,2,3]) # p = Polynom([1,2,3])

View File

@ -6,6 +6,7 @@ import unittest
from pymath.render import tex, txt,p2i from pymath.render import tex, txt,p2i
from pymath.fraction import Fraction from pymath.fraction import Fraction
from pymath.polynom import Polynom
from pymath.operator import op from pymath.operator import op
@ -22,6 +23,10 @@ class TestTexRender(unittest.TestCase):
def test_type_render_fraction(self): def test_type_render_fraction(self):
self.assertEqual(tex([Fraction(1,2)]), "\\frac{ 1 }{ 2 }") self.assertEqual(tex([Fraction(1,2)]), "\\frac{ 1 }{ 2 }")
def test_type_render_poly(self):
P = Polynom([1,2,3])
self.assertEqual(tex([P]), "3 x^{ 2 } + 2 x + 1")
def test_mult_interger(self): def test_mult_interger(self):
exps = [ [2, 3, op.get_op("*", 2)], [2, -3, op.get_op("*", 2)], [-2, 3, op.get_op("*", 2)]] exps = [ [2, 3, op.get_op("*", 2)], [2, -3, op.get_op("*", 2)], [-2, 3, op.get_op("*", 2)]]
wanted_render = [ "2 \\times 3", "2 \\times ( -3 )", "-2 \\times 3"] wanted_render = [ "2 \\times 3", "2 \\times ( -3 )", "-2 \\times 3"]
@ -37,26 +42,60 @@ class TestTexRender(unittest.TestCase):
self.assertEqual(rend, wanted_render[i]) self.assertEqual(rend, wanted_render[i])
def test_mult_fraction(self): def test_mult_fraction(self):
exps = [ [2, Fraction(1,2), op.get_op("*", 2)], [Fraction(1,2), 3, op.get_op("*", 2)]] exps = [ [2, Fraction(1,2), op.mul], [Fraction(1,2), 3, op.mul]]
wanted_render = [ "2 \\times \\frac{ 1 }{ 2 }", "\\frac{ 1 }{ 2 } \\times 3"] wanted_render = [ "2 \\times \\frac{ 1 }{ 2 }", "\\frac{ 1 }{ 2 } \\times 3"]
for (i,e) in enumerate(exps): for (i,e) in enumerate(exps):
rend = tex(e) rend = tex(e)
self.assertEqual(rend, wanted_render[i]) self.assertEqual(rend, wanted_render[i])
def test_parentheses(self): def test_mult_poly(self):
mul = op.get_op("*", 2) exps = [[2, Polynom([1,2,3]), op.mul],
add = op.get_op("+", 2) [Polynom([1,2,3]), 2, op.mul],
[Polynom([1,2,3]), Polynom([4,5,6]), op.mul],
]
wanted_render = [ "2 ( 3 x^{ 2 } + 2 x + 1 )",
"( 3 x^{ 2 } + 2 x + 1 ) \\times 2",
"( 3 x^{ 2 } + 2 x + 1 ) ( 3 x^{ 2 } + 2 x + 1 )",
]
for (i,e) in enumerate(exps):
rend = tex(e)
self.assertEqual(rend, wanted_render[i])
def test_parentheses_int(self):
exps = [\ exps = [\
[ 2, 3, add, 4, mul],\ [ 2, 3, op.add, 4, op.mul],\
[ 2, 3, mul, 4, add],\ [ 2, 3, op.mul, 4, op.add],\
[ 2, 3, 4, mul, add],\ [ 2, 3, 4, op.mul, op.add],\
[ 2, 3, 4, add, add],\ [ 2, 3, 4, op.add, op.add],\
[ 2, 3, 4, op.add, op.sub],\
] ]
wanted_render = [\ wanted_render = [\
'( 2 + 3 ) \\times 4',\ '( 2 + 3 ) \\times 4',\
'2 \\times 3 + 4',\ '2 \\times 3 + 4',\
'2 + 3 \\times 4',\ '2 + 3 \\times 4',\
'2 + 3 + 4',\ '2 + 3 + 4',\
'2 - ( 3 + 4 )',\
]
for (i,e) in enumerate(exps):
rend = tex(e)
self.assertEqual(rend, wanted_render[i])
def test_parentheses_poly(self):
P = Polynom([1,2,3])
Q = Polynom([4,5,6])
exps = [\
[ 2, P, op.add],\
[ 2, P, op.sub],\
[ 2, P, P, op.mul, op.sub],\
[ Q, P, op.add],\
[ Q, P, op.sub],\
]
wanted_render = [\
'2 + 3 x^{ 2 } + 2 x + 1' ,\
'2 - ( 3 x^{ 2 } + 2 x + 1 )' ,\
'2 - ( 3 x^{ 2 } + 2 x + 1 ) ( 3 x^{ 2 } + 2 x + 1 )' ,\
'6 x^{ 2 } + 5 x + 4 + 3 x^{ 2 } + 2 x + 1' ,\
'6 x^{ 2 } + 5 x + 4 - ( 3 x^{ 2 } + 2 x + 1 )' ,\
] ]
for (i,e) in enumerate(exps): for (i,e) in enumerate(exps):
rend = tex(e) rend = tex(e)