From 98885cb80fb592b2b818bea3be2ef300c0a7dc9f Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 15:10:26 +0200 Subject: [PATCH 01/40] add a latex print --- documentation/source/tutorial.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/documentation/source/tutorial.rst b/documentation/source/tutorial.rst index a32a547..005dd8e 100644 --- a/documentation/source/tutorial.rst +++ b/documentation/source/tutorial.rst @@ -83,6 +83,18 @@ mathématiques. Voici ce qu'il est capable de faire: ( 6 + 10 ) / 15 16 / 15 + Le rendu latex permet ensuite d'être directement compiler et par exemple d'avoir le rendu suivant + + .. math:: + :nowrap: + + \frac{ 2 }{ 5 } + \frac{ 2 }{ 3 } \\ + \frac{ 2 \times 3 }{ 5 \times 3 } + \frac{ 2 \times 5 }{ 3 \times 5 } \\ + \frac{ 6 }{ 15 } + \frac{ 10 }{ 15 } \\ + \frac{ 6 + 10 }{ 15 } \\ + \frac{ 16 }{ 15 } + + Ce module a pour but d'être un outil pour faciliter la construction d'exercices et leurs correction. Il a pour but d'être le plus simple From 3a721ce1b30b97de0d8347583ae7783a7c865273 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 21 Feb 2015 11:27:02 +0100 Subject: [PATCH 02/40] Start doc on polynoms --- docs/polynom.mdwn | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/polynom.mdwn b/docs/polynom.mdwn index c3007e9..a265841 100644 --- a/docs/polynom.mdwn +++ b/docs/polynom.mdwn @@ -14,3 +14,42 @@ >>> print(P) 5 x^{ 2 } + 4 x - 7 +## Manipuler des polynômes + +### Les représentations des polynômes + + >>> P = Polynom([1, 2, 3]) + >>> print(P) + +### Évaluer des polynômes + + >>> type(P(3)) + pymath.expression.Expression + >>> for i in P(3).simplify(): + print(i) + 3 \times 3^{ 2 } + 2 \times 3 + 1 + 3 \times 9 + 6 + 1 + 27 + 6 + 1 + 33 + 1 + 34 + >>> P(3).simplified() + 34 + + +### Opération et polynômes + + >>> type(P + 1) + list + >>> for i in (P+1): + print(i) + 3 x^{ 2 } + 2 x + 1 + 1 + 3 x^{ 2 } + 2 x + 1 + 1 + 3 x^{ 2 } + 2 x + 2 + >>> Q = Polynom([4, 5, 6]) + >>> for i in (P+Q): + print(i) + 3 x ^ 2 + 6 x ^ 2 + 2 x + 5 x + 1 + 4 + ( 3 + 6 ) x ^ 2 + ( 2 + 5 ) x + 1 + 4 + 9 x ^ 2 + 7 x + 5 + + From 4ca14c078ee28477538a75ed8615e8bfe482032c Mon Sep 17 00:00:00 2001 From: Lafrite Date: Wed, 25 Feb 2015 11:24:48 +0100 Subject: [PATCH 03/40] add less verbose in Todolist --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index db39e93..65e881d 100644 --- a/TODO +++ b/TODO @@ -9,3 +9,4 @@ * Expression parents class and his children: Numerical_exp, toGenerate_exp and formal expression * Create tbl sgn and variation render +* Make less verbose fractions operations From b0e506897aff9d74a2b3756882fee82145108714 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 28 Mar 2015 09:09:32 +0100 Subject: [PATCH 04/40] change op.add and op.sub for better - management --- pymath/operator.py | 29 ++++++++++++++++++++++++++++- test/test_render.py | 4 ++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index 35e2a19..4d171c2 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -281,8 +281,32 @@ class op(object): >>> add.__txt__('1','2') '1 + 2' >>> add.__tex__('1','-2') - '1 + (-2)' + '1 - 2' """ + + def _render(self, link, *args): + """Global step for __txt__ and __tex__ + + :param link: the link between operators + :param *args: the operands + :returns: the string with operator and operands + + """ + if args[1][0] == "-": + op1 = self.l_parenthesis(args[0], True) + op2 = self.r_parenthesis(args[1][1:], True) + ans = link.replace('+','-').format(op1 = op1, op2 = op2) + + ans = save_mainOp(ans, self) + return ans + else: + op1 = self.l_parenthesis(args[0], True) + op2 = self.r_parenthesis(args[1], True) + ans = link.format(op1 = op1, op2 = op2) + + ans = save_mainOp(ans, self) + return ans + caract = { "operator" : "+", \ "name" : "add",\ @@ -291,6 +315,7 @@ class op(object): "actions" : ("__add__","__radd__"), \ "txt" : "{op1} + {op2}",\ "tex" : "{op1} + {op2}",\ + "_render": _render,\ } return caract @@ -321,6 +346,8 @@ class op(object): try: if op.mainOp.priority <= self.priority: op = flatten_list(["(", op, ")"]) + elif op[0] == '-': + op = flatten_list(["(", op, ")"]) except AttributeError: # op has not the attribute priority try: diff --git a/test/test_render.py b/test/test_render.py index 5589a2c..50394b5 100644 --- a/test/test_render.py +++ b/test/test_render.py @@ -33,7 +33,7 @@ class TestTexRender(unittest.TestCase): [-2, 3, op.add ], ] wanted_render = [ "2 + 3", - "2 + ( -3 )", + "2 - 3", "-2 + 3", ] for (i,e) in enumerate(exps): @@ -49,7 +49,7 @@ class TestTexRender(unittest.TestCase): wanted_render = [ "2 + a", "a + 3", "-2 + a", - "a + ( -2 )", + "a - 2", ] for (i,e) in enumerate(exps): rend = tex(e) From 509fd6e409e7a1bef4833a8cc626e5c4b87663bb Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 14:49:55 +0200 Subject: [PATCH 05/40] add some test for operators --- pymath/operator.py | 17 ++++--------- test/test_operator.py | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index 4d171c2..555953b 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -3,6 +3,7 @@ from .generic import flatten_list, isNumber +from functools import wraps import types class Operator(str): @@ -207,6 +208,7 @@ def operatorize(fun): * "l_parenthesis": mechanism to add parenthesis for left operande * "r_parenthesis": mechanism to add parenthesis for rigth operande """ + @wraps(fun) def mod_fun(self, *args): ans = fun(self, *args) @@ -271,17 +273,8 @@ class op(object): def add(cls): """ The operator + - >>> add = op.add - >>> add - '+' - >>> add(1, 2) - 3 - >>> add.__tex__('1','2') - '1 + 2' - >>> add.__txt__('1','2') - '1 + 2' - >>> add.__tex__('1','-2') - '1 - 2' + For doctest see test/test_operator.py + """ def _render(self, link, *args): @@ -337,7 +330,7 @@ class op(object): >>> sub.__tex__('1','-2') '1 - (-2)' >>> sub.__tex__('-1','2') - 'i-1 - 2' + '-1 - 2' """ def l_parenthesis(self, op, str_join=False): return op diff --git a/test/test_operator.py b/test/test_operator.py index c89f9fd..5fdfd6f 100644 --- a/test/test_operator.py +++ b/test/test_operator.py @@ -4,6 +4,43 @@ from pymath.operator import op +# Test de op.add + +def test_add_render_tex(): + assert op.add.__tex__('1','2') == '1 + 2' + assert op.add.__tex__('1','-2') == '1 - 2' + +def test_add_render_txt(): + assert op.add.__txt__('1','2') == '1 + 2' + assert op.add.__txt__('1','-2') == '1 - 2' + +# Test de op.sub + +def test_sub_render_tex(): + assert op.sub.__tex__('1','2') == '1 - 2' + assert op.sub.__tex__('1','-2') == '1 - ( -2 )' + +def test_sub_render_txt(): + assert op.sub.__txt__('1','2') == '1 - 2' + assert op.sub.__txt__('1','-2') == '1 - ( -2 )' + +# Test de op.sub1 + +def test_sub1_render(): + assert op.sub1.__tex__('1') == '- 1' + assert op.sub1.__tex__('-1') == '- ( -1 )' + assert op.sub1.__txt__('1') == '- 1' + assert op.sub1.__txt__('-1') == '- ( -1 )' + +# Test de op.mul +def test_mul_render_tex(): + assert op.mul.__tex__('1','2') == '1 \\times 2' + assert op.mul.__tex__('1','-2') == '1 \\times ( -2 )' + +def test_mul_render_txt(): + assert op.mul.__txt__('1','2') == '1 * 2' + assert op.mul.__txt__('1','-2') == '1 * ( -2 )' + def test_mul_is_visible(): assert op.mul.is_visible(2,3) == True assert op.mul.is_visible(2,-3) == True @@ -20,7 +57,25 @@ def test_mul_is_visible(): assert op.mul.is_visible('(3x - 1)', '(2a + 1)') == False assert op.mul.is_visible(2, '(-2x + 1)(3x + 2)') == False +# Test de op.div +def test_div_render_tex(): + assert op.div.__tex__('1','2') == '\\frac{ 1 }{ 2 }' + assert op.div.__tex__('1','-2') == '\\frac{ 1 }{ -2 }' +def test_div_render_txt(): + assert op.div.__txt__('1','2') == '1 / 2' + assert op.div.__txt__('1','-2') == '1 / ( -2 )' + +# Test de op.pw +def test_pw_render_tex(): + assert op.pw.__tex__('1','2') == '1^{ 2 }' + assert op.pw.__tex__('1','-2') == '1^{-2}' + assert op.pw.__tex__('-1','2') == '( -1 )^{ 2 }' + +def test_pw_render_txt(): + assert op.pw.__txt__('1','2') == '1 ^ 2' + assert op.pw.__txt__('1','-2') == '1 ^ ( -2 )' + assert op.pw.__txt__('-1','2') == '( -1 ) ^ 2 ' From a2041fd451fafd69bcb87a815b55aa179f91c1ee Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 5 Apr 2015 17:04:04 +0200 Subject: [PATCH 06/40] solve issue with explain and wrong steps --- pymath/expression.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index 08ec98b..aa83b0e 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -186,13 +186,31 @@ class Expression(Explicable): tmpTokenList += tokenList - steps = expand_list(tmpTokenList) + #print(repr(self)) + #print(" tmpTokenList -> ", tmpTokenList) + #steps = expand_list([i.explain() for i in tmpTokenList]) + #print("steps -> ", steps) - if len(steps[:-1]) > 0: - child_steps += [flatten_list(s) for s in steps[:-1]] + #if len(steps[:-1]) > 0: + # child_steps += [flatten_list(s) for s in steps[:-1]] - self.child = Expression(steps[-1]) - self.child.steps = child_steps + self.child = Expression(tmpTokenList) + self.child.steps = self.develop_steps(tmpTokenList) + + def develop_steps(self, tokenList): + """ From a list of tokens, it develops steps of each tokens """ + tmp_steps = [] + with Expression.tmp_render(): + for t in tokenList: + if hasattr(t, "explain"): + tmp_steps.append([i for i in t.explain()]) + else: + tmp_steps.append(t) + tmp_steps = expand_list(tmp_steps) + #print("tmp_steps -> ", tmp_steps) + steps = [Expression(s) for s in tmp_steps] + + return steps @classmethod def isExpression(self, other): From 437066e8e648f73dcb7d361745db3f30a5ee153c Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 5 Apr 2015 17:05:21 +0200 Subject: [PATCH 07/40] remove some commented lines --- pymath/expression.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index aa83b0e..04fbb85 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -186,14 +186,6 @@ class Expression(Explicable): tmpTokenList += tokenList - #print(repr(self)) - #print(" tmpTokenList -> ", tmpTokenList) - #steps = expand_list([i.explain() for i in tmpTokenList]) - #print("steps -> ", steps) - - #if len(steps[:-1]) > 0: - # child_steps += [flatten_list(s) for s in steps[:-1]] - self.child = Expression(tmpTokenList) self.child.steps = self.develop_steps(tmpTokenList) @@ -207,7 +199,6 @@ class Expression(Explicable): else: tmp_steps.append(t) tmp_steps = expand_list(tmp_steps) - #print("tmp_steps -> ", tmp_steps) steps = [Expression(s) for s in tmp_steps] return steps From b1c3c3564e2f2d1eb5cab91f2f4d11bc6e54c3ab Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 6 Apr 2015 17:57:13 +0200 Subject: [PATCH 08/40] finaly finish to implement simplify and explain --- pymath/explicable.py | 25 ++++++--- pymath/expression.py | 120 +++++++++++++++++++++++++++++------------- pymath/fraction.py | 60 +++++++++++++++------ pymath/polynom.py | 16 +++--- pymath/polynomDeg2.py | 15 +++++- pymath/str2tokens.py | 2 +- 6 files changed, 168 insertions(+), 70 deletions(-) diff --git a/pymath/explicable.py b/pymath/explicable.py index 4db74b3..1db3b83 100644 --- a/pymath/explicable.py +++ b/pymath/explicable.py @@ -32,17 +32,25 @@ class Renderable(object): >>> for i in exp.simplify().explain(): ... print(i) 2 \\times \\frac{ 3 }{ 5 } + \\frac{ 3 }{ 5 } \\times 2 + \\frac{ 3 \\times 2 }{ 5 } \\frac{ 6 }{ 5 } >>> with Expression.tmp_render(txt): ... for i in exp.simplify().explain(): ... print(i) 2 * 3 / 5 + 3 / 5 * 2 + ( 3 * 2 ) / 5 6 / 5 >>> for i in exp.simplify().explain(): ... print(i) 2 \\times \\frac{ 3 }{ 5 } + \\frac{ 3 }{ 5 } \\times 2 + \\frac{ 3 \\times 2 }{ 5 } \\frac{ 6 }{ 5 } + # TODO: essayer de ne pas afficher ce changement de position. |lun. avril 6 17:29:56 CEST 2015 + """ class TmpRenderEnv(object): def __enter__(self): @@ -65,8 +73,12 @@ class Explicable(Renderable): def __init__(self, *args, **kwargs): self.steps = [] - def explain(self): - """ Generate and render steps which leed to itself """ + def explain(self, noself = True): + """ Generate and render steps which leed to itself + + :param noself: does explain return self + + """ old_s = '' # les étapes pour l'atteindre try: @@ -81,10 +93,11 @@ class Explicable(Renderable): except AttributeError: pass - # Lui même - new_s = self.STR_RENDER(self.postfix_tokens) - if new_s != old_s: - yield new_s + if noself: + # Lui même + new_s = self.STR_RENDER(self.postfix_tokens) + if new_s != old_s: + yield new_s diff --git a/pymath/expression.py b/pymath/expression.py index 04fbb85..ff5ff57 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -38,23 +38,30 @@ class Expression(Explicable): >>> for i in exp.simplify().explain(): ... print(i) 2 \\times \\frac{ 3 }{ 5 } + \\frac{ 3 }{ 5 } \\times 2 + \\frac{ 3 \\times 2 }{ 5 } \\frac{ 6 }{ 5 } >>> with Expression.tmp_render(): ... for i in exp.simplify().explain(): ... i < [2, 3, 5, '/', '*'] > < [2, < Fraction 3 / 5>, '*'] > - < [2, < Fraction 3 / 5>, '*'] > + < [3, 5, '/', 2, '*'] > + < [3, 2, '*', 5, '/'] > < [6, 5, '/'] > >>> from .render import txt >>> with Expression.tmp_render(txt): ... for i in exp.simplify().explain(): ... print(i) 2 * 3 / 5 + 3 / 5 * 2 + ( 3 * 2 ) / 5 6 / 5 >>> for i in exp.simplify().explain(): ... print(i) 2 \\times \\frac{ 3 }{ 5 } + \\frac{ 3 }{ 5 } \\times 2 + \\frac{ 3 \\times 2 }{ 5 } \\frac{ 6 }{ 5 } """ @@ -117,19 +124,34 @@ class Expression(Explicable): def simplify(self): """ Compute entirely the expression and return the result with .steps attribute """ + #print("\tSimplify self -> ", repr(self)) self.compute_exp() + #print("\t End Compute Simplify self -> ", self) self.simplified = self.child.simplify() - try: - self.simplified.steps = self.child.steps + self.simplified.steps - except AttributeError: - pass + #print("\t self.simplified -> ", repr(self.simplified)) + #print("\t self.child -> ", repr(self.child)) + if self.simplified != self.child: + try: + #print('\t\t in try') + #print("\t\t self.child-> ", self.child) + #print("\t\t|-> self.child.steps -> ", self.child.steps) + #print("\t\t self.simplified -> ", self.simplified) + #print("\t\t|-> self.simplified.steps -> ", self.simplified.steps) + self.simplified.steps = self.child.steps + self.simplified.steps + #print("\t\t|--> self.simplified.steps -> ", self.simplified.steps) + except AttributeError: + pass + + #print("\t self -> ", self) + #print("\t self.simplified.steps ->\n\t\t ", self.simplified.steps) + #print("\tEnd simplify self -> ", repr(self)) return self.simplified def compute_exp(self): """ Create self.child with and stock steps in it """ - child_steps = [self.postfix_tokens] + ini_step = Expression(self.postfix_tokens) tokenList = self.postfix_tokens.copy() tmpTokenList = [] @@ -185,9 +207,17 @@ class Expression(Explicable): del tokenList[0:2] tmpTokenList += tokenList - + #print("\t ----------------") + #print("\t self -> ", repr(self)) + #print("\t tmpTokenList -> ", tmpTokenList) self.child = Expression(tmpTokenList) - self.child.steps = self.develop_steps(tmpTokenList) + if self.child.postfix_tokens == ini_step.postfix_tokens: + self.child.steps = self.develop_steps(tmpTokenList) + else: + self.child.steps = [ini_step] + self.develop_steps(tmpTokenList) + #print("\t\t self -> ", repr(self)) + #print("\t self.child -> ", repr(self.child)) + #print("\t self.child.steps -> ", repr(self.child.steps)) def develop_steps(self, tokenList): """ From a list of tokens, it develops steps of each tokens """ @@ -198,10 +228,16 @@ class Expression(Explicable): tmp_steps.append([i for i in t.explain()]) else: tmp_steps.append(t) - tmp_steps = expand_list(tmp_steps) - steps = [Expression(s) for s in tmp_steps] - - return steps + #print("\t\t tokenList -> ", tokenList) + #print("\t\t 1.tmp_steps -> ", tmp_steps) + if max([len(i) if type(i) == list else 1 for i in tmp_steps]) == 1: + return [] + else: + tmp_steps = expand_list(tmp_steps)[:-1] + #print("\t\t 2.tmp_steps -> ", tmp_steps) + steps = [Expression(s) for s in tmp_steps] + #print("\t\t steps -> ", steps) + return steps @classmethod def isExpression(self, other): @@ -322,7 +358,7 @@ class Expression(Explicable): return Expression(self.postfix_tokens + [op.sub1]) -def test(exp): +def untest(exp): a = Expression(exp) b = a.simplify() @@ -342,20 +378,20 @@ if __name__ == '__main__': #Expression.set_render(txt) #exp = "2 ^ 3 * 5" - #test(exp) + #untest(exp) #exp = "2x + 5" - #test(exp) + #untest(exp) #Expression.set_render(tex) - #test(exp1) + #untest(exp1) #from pymath.operator import op #exp = [2, 3, op.pw, 5, op.mul] - #test(exp) + #untest(exp) - #test([Expression(exp1), Expression(exp), op.add]) + #untest([Expression(exp1), Expression(exp), op.add]) #exp = "1 + 3 * 5" #e = Expression(exp) @@ -363,50 +399,50 @@ if __name__ == '__main__': #print(f) #exp = "2 * 3 * 3 * 5" - #test(exp) + #untest(exp) #exp = "2 * 3 + 3 * 5" - #test(exp) + #untest(exp) #exp = "2 * ( 3 + 4 ) + 3 * 5" - #test(exp) + #untest(exp) #exp = "2 * ( 3 + 4 ) + ( 3 - 4 ) * 5" - #test(exp) + #untest(exp) # #exp = "2 * ( 2 - ( 3 + 4 ) ) + ( 3 - 4 ) * 5" - #test(exp) + #untest(exp) # #exp = "2 * ( 2 - ( 3 + 4 ) ) + 5 * ( 3 - 4 )" - #test(exp) + #untest(exp) # #exp = "2 + 5 * ( 3 - 4 )" - #test(exp) + #untest(exp) #exp = "( 2 + 5 ) * ( 3 - 4 )^4" - #test(exp) + #untest(exp) #exp = "( 2 + 5 ) * ( 3 * 4 )" - #test(exp) + #untest(exp) #exp = "( 2 + 5 - 1 ) / ( 3 * 4 )" - #test(exp) + #untest(exp) #exp = "( 2 + 5 ) / ( 3 * 4 ) + 1 / 12" - #test(exp) + #untest(exp) #exp = "( 2+ 5 )/( 3 * 4 ) + 1 / 2" - #test(exp) + #untest(exp) #exp="(-2+5)/(3*4)+1/12+5*5" - #test(exp) + #untest(exp) #exp="-2*4(12 + 1)(3-12)" - #test(exp) + #untest(exp) #exp="(-2+5)/(3*4)+1/12+5*5" - #test(exp) + #untest(exp) # TODO: The next one doesn't work |ven. janv. 17 14:56:58 CET 2014 #exp="-2*(-a)(12 + 1)(3-12)" @@ -415,15 +451,27 @@ if __name__ == '__main__': ## Can't handle it yet!! #exp="-(-2)" - #test(exp) + #untest(exp) #print("\n") #exp = Expression.random("({a} + 3)({b} - 1)", ["{a} > 4"]) #for i in exp.simplify(): # print(i) - import doctest - doctest.testmod() + from .fraction import Fraction + f1 = Fraction(3,5) + f2 = Fraction(5,10) + q = f1+f2 + print("---------") + print(q.steps) + print("---------") + + for i in q.explain(): + print(i) + + + #import doctest + #doctest.testmod() # ----------------------------- # Reglages pour 'vim' diff --git a/pymath/fraction.py b/pymath/fraction.py index 7a21356..63ddac7 100644 --- a/pymath/fraction.py +++ b/pymath/fraction.py @@ -136,18 +136,29 @@ class Fraction(Explicable): >>> g = Fraction(2, 3) >>> f + g < Fraction 7 / 6> - >>> (f+g).steps - [< [1, 2, '/', 2, 3, '/', '+'] >, [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '+'], [3, 6, '/', 4, 6, '/', '+'], [< Fraction 3 / 6>, < Fraction 4 / 6>, '+'], [< Fraction 3 / 6>, < Fraction 4 / 6>, '+']] + >>> print("\\n".join([repr(i) for i in (f+g).steps])) + < [1, 2, '/', 2, 3, '/', '+'] > + < [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '+'] > + < [3, 6, '/', 4, 6, '/', '+'] > + < [< Fraction 3 / 6>, < Fraction 4 / 6>, '+'] > + < [3, 6, '/', 4, 6, '/', '+'] > + < [3, 4, '+', 6, '/'] > >>> f + 2 < Fraction 5 / 2> - >>> (f+2).steps - [< [1, 2, '/', 2, '+'] >, [1, 1, '*', 2, 1, '*', '/', 2, 2, '*', 1, 2, '*', '/', '+'], [1, 2, '/', 4, 2, '/', '+'], [< Fraction 1 / 2>, < Fraction 4 / 2>, '+'], [< Fraction 1 / 2>, < Fraction 4 / 2>, '+']] + >>> print("\\n".join([repr(i) for i in (f+2).steps])) + < [1, 2, '/', 2, '+'] > + < [1, 1, '*', 2, 1, '*', '/', 2, 2, '*', 1, 2, '*', '/', '+'] > + < [1, 2, '/', 4, 2, '/', '+'] > + < [< Fraction 1 / 2>, < Fraction 4 / 2>, '+'] > + < [1, 2, '/', 4, 2, '/', '+'] > + < [1, 4, '+', 2, '/'] > >>> f = Fraction(3, 4) >>> g = Fraction(5, 4) >>> f + g 2 - >>> (f+g).steps - [< [3, 4, '/', 5, 4, '/', '+'] >, [3, 5, '+', 4, '/'], [8, 4, '/']] + >>> print("\\n".join([repr(i) for i in (f+g).steps])) + < [3, 4, '/', 5, 4, '/', '+'] > + < [3, 5, '+', 4, '/'] > >>> f+0 < Fraction 3 / 4> >>> (f+0).steps @@ -174,8 +185,8 @@ class Fraction(Explicable): exp = Expression([self._num, coef1, op.mul, self._denom, coef1, op.mul, op.div, number._num, coef2, op.mul, number._denom, coef2, op.mul, op.div,op.add]) - ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.add]) ans = exp.simplify() + ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.add]) ans.steps = [ini_step] + ans.steps return ans @@ -194,8 +205,13 @@ class Fraction(Explicable): >>> g = Fraction(2, 3) >>> f - g < Fraction -1 / 6> - >>> (f-g).steps - [< [1, 2, '/', 2, 3, '/', '-'] >, [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '-'], [3, 6, '/', 4, 6, '/', '-'], [< Fraction 3 / 6>, < Fraction 4 / 6>, '-'], [< Fraction 3 / 6>, < Fraction 4 / 6>, '-']] + >>> print("\\n".join([repr(i) for i in (f-g).steps])) + < [1, 2, '/', 2, 3, '/', '-'] > + < [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '-'] > + < [3, 6, '/', 4, 6, '/', '-'] > + < [< Fraction 3 / 6>, < Fraction 4 / 6>, '-'] > + < [3, 6, '/', 4, 6, '/', '-'] > + < [3, 4, '-', 6, '/'] > >>> f - 0 < Fraction 1 / 2> >>> (f-0).steps @@ -263,8 +279,12 @@ class Fraction(Explicable): >>> g = Fraction(2, 3) >>> f*g < Fraction 1 / 3> - >>> (f*g).steps - [< [1, 2, '/', 2, 3, '/', '*'] >, [1, 1, 2, '*', '*', 1, 2, '*', 3, '*', '/'], [1, 2, '*', 2, 3, '*', '/'], [2, 6, '/'], < [2, 6, '/'] >, < [1, 2, '*', 3, 2, '*', '/'] >] + >>> print("\\n".join([repr(i) for i in (f*g).steps])) + < [1, 2, '/', 2, 3, '/', '*'] > + < [1, 1, 2, '*', '*', 1, 2, '*', 3, '*', '/'] > + < [1, 2, '*', 2, 3, '*', '/'] > + < [2, 6, '/'] > + < [1, 2, '*', 3, 2, '*', '/'] > >>> f * 0 0 >>> (f*0).steps @@ -275,8 +295,10 @@ class Fraction(Explicable): [] >>> f*4 2 - >>> (f*4).steps - [< [1, 2, '/', 4, '*'] >, [1, 2, '*', 2, '*', 1, 2, '*', '/'], [2, 2, '*', 2, '/'], [4, 2, '/']] + >>> print("\\n".join([repr(i) for i in (f*4).steps])) + < [1, 2, '/', 4, '*'] > + < [1, 2, '*', 2, '*', 1, 2, '*', '/'] > + < [2, 2, '*', 2, '/'] > """ steps = [] @@ -381,13 +403,17 @@ class Fraction(Explicable): [] >>> f**3 < Fraction 27 / 64> - >>> (f**3).steps - [< [3, 4, '/', 3, '^'] >, [3, 3, '^', 4, 3, '^', '/'], [27, 64, '/'], [27, 64, '/']] + >>> print("\\n".join([repr(i) for i in (f**3).steps])) + < [3, 4, '/', 3, '^'] > + < [3, 3, '^', 4, 3, '^', '/'] > >>> f = Fraction(6, 4) >>> f**3 < Fraction 27 / 8> - >>> (f**3).steps - [< [6, 4, '/', 3, '^'] >, [6, 3, '^', 4, 3, '^', '/'], [216, 64, '/'], < [216, 64, '/'] >, < [27, 8, '*', 8, 8, '*', '/'] >] + >>> print("\\n".join([repr(i) for i in (f**3).steps])) + < [6, 4, '/', 3, '^'] > + < [6, 3, '^', 4, 3, '^', '/'] > + < [216, 64, '/'] > + < [27, 8, '*', 8, 8, '*', '/'] > """ if not type(power) == int: diff --git a/pymath/polynom.py b/pymath/polynom.py index 2bef1eb..e32ab19 100644 --- a/pymath/polynom.py +++ b/pymath/polynom.py @@ -364,7 +364,7 @@ class Polynom(Explicable): >>> Q < Polynom [3, 12, 6]> >>> Q.steps - [< Polynom [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < Polynom [< [1, 2, '+'] >, < [7, 5, '+'] >, 6]>, < Polynom [3, < [7, 5, '+'] >, 6]>] + [< Polynom [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < Polynom [3, < [7, 5, '+'] >, 6]>] """ # TODO: It doesn't not compute quick enough |ven. févr. 27 18:04:01 CET 2015 @@ -477,7 +477,7 @@ class Polynom(Explicable): >>> R < Polynom [5, 7, 3]> >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < Polynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>, < Polynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < Polynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] """ o_poly = self.conv2poly(other) @@ -517,7 +517,7 @@ class Polynom(Explicable): >>> R < Polynom [-3, -3, -3]> >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < Polynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>, < Polynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < Polynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] """ o_poly = self.conv2poly(other) ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.sub])] @@ -541,12 +541,12 @@ class Polynom(Explicable): >>> p*3 < Polynom [3, 6]> >>> (p*3).steps - [[< [2, 'x', '*', 1, '+', 3, '*'] >], < Polynom [3, < [2, 3, '*'] >]>, < Polynom [3, < [2, 3, '*'] >]>] + [[< [2, 'x', '*', 1, '+', 3, '*'] >], < Polynom [3, < [2, 3, '*'] >]>] >>> q = Polynom([0,0,4]) >>> q*3 < Polynom [0, 0, 12]> >>> (q*3).steps - [[< [4, 'x', 2, '^', '*', 3, '*'] >], < Polynom [0, 0, < [4, 3, '*'] >]>, < Polynom [0, 0, < [4, 3, '*'] >]>] + [[< [4, 'x', 2, '^', '*', 3, '*'] >], < Polynom [0, 0, < [4, 3, '*'] >]>] >>> r = Polynom([0,1]) >>> r*3 < Polynom [0, 3]> @@ -555,7 +555,7 @@ class Polynom(Explicable): >>> p*q < Polynom [0, 0, 4, 8]> >>> (p*q).steps - [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < [2, 4, '*'] >]>, < Polynom [0, 0, 4, < [2, 4, '*'] >]>] + [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < [2, 4, '*'] >]>] >>> p*r < Polynom [0, 1, 2]> >>> P = Polynom([1,2,3]) @@ -606,12 +606,12 @@ class Polynom(Explicable): >>> p**2 < Polynom [0, 0, 0, 0, 9]> >>> (p**2).steps - [< [3, 'x', 2, '^', '*', 2, '^'] >, < Polynom [0, 0, 0, 0, < [3, 2, '^'] >]>, < Polynom [0, 0, 0, 0, < [3, 2, '^'] >]>] + [< [3, 'x', 2, '^', '*', 2, '^'] >, < Polynom [0, 0, 0, 0, < [3, 2, '^'] >]>] >>> p = Polynom([1,2]) >>> p**2 < Polynom [1, 4, 4]> >>> (p**2).steps - [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < Polynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>, < Polynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] + [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < Polynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] >>> p = Polynom([0,0,1]) >>> p**3 < Polynom [0, 0, 0, 0, 0, 0, 1]> diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index 9a87efb..97e5aeb 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -83,7 +83,7 @@ class Polynom_deg2(Polynom): ... print(i) \\frac{ - 2 }{ 2 \\times 3 } \\frac{ -2 }{ 6 } - \\frac{ ( -1 ) \\times 2 }{ 3 \\times 2 } + \\frac{ -1 \\times 2 }{ 3 \\times 2 } \\frac{ -1 }{ 3 } """ return Expression([self.b, op.sub1, 2, self.a, op.mul, op.div]).simplify() @@ -97,10 +97,21 @@ class Polynom_deg2(Polynom): < Fraction 2 / 3> >>> for i in P.beta.explain(): # Ça serait bien que l'on puisse enlever des étapes maintenant... ... print(i) - 3 \\times \\frac{ -1 }{ 3 }^{ 2 } + 2 \\times \\frac{ -1 }{ 3 } + 1 + 3 \\times ( \\frac{ -1 }{ 3 } )^{ 2 } + 2 \\times \\frac{ -1 }{ 3 } + 1 + 3 \\times ( \\frac{ -1 }{ 3 } )^{ 2 } + \\frac{ -1 }{ 3 } \\times 2 + 1 + 3 \\times \\frac{ -1^{ 2 } }{ 3^{ 2 } } + \\frac{ -1 \\times 2 }{ 3 } + 1 3 \\times \\frac{ 1 }{ 9 } + \\frac{ -2 }{ 3 } + 1 + \\frac{ 1 }{ 9 } \\times 3 + \\frac{ -1 }{ 3 } \\times 2 + 1 + \\frac{ 1 \\times 1 \\times 3 }{ 3 \\times 3 } + \\frac{ -1 \\times 2 }{ 3 } + 1 + \\frac{ 1 \\times 3 }{ 9 } + \\frac{ -2 }{ 3 } + 1 + \\frac{ 3 }{ 9 } + \\frac{ -2 }{ 3 } + 1 + \\frac{ 1 \\times 3 }{ 3 \\times 3 } + \\frac{ -2 }{ 3 } + 1 \\frac{ 1 }{ 3 } + \\frac{ -2 }{ 3 } + 1 + \\frac{ 1 - 2 }{ 3 } + 1 \\frac{ -1 }{ 3 } + 1 + \\frac{ -1 \\times 1 }{ 3 \\times 1 } + \\frac{ 1 \\times 3 }{ 1 \\times 3 } + \\frac{ -1 }{ 3 } + \\frac{ 3 }{ 3 } + \\frac{ -1 + 3 }{ 3 } \\frac{ 2 }{ 3 } """ return self(self.alpha).simplify() diff --git a/pymath/str2tokens.py b/pymath/str2tokens.py index 7899a03..61c2eb0 100644 --- a/pymath/str2tokens.py +++ b/pymath/str2tokens.py @@ -91,7 +91,7 @@ def in2post_fix(infix_tokens): @return: the corresponding postfix list of tokens. >>> in2post_fix([op.par, 2, op.add, 5, op.sub, 1, ')', op.div, op.par, 3, op.mul, 4, ')']) - [2, 5, '+', 1, '-', 3, 4, '*', '/'] + [2, 5, 1, '-', '+', 3, 4, '*', '/'] >>> in2post_fix([op.sub1, op.par, op.sub1, 2, ')']) [2, '-', '-'] >>> in2post_fix([op.sub1, op.par, op.sub1, 2, op.add, 3, op.mul, 4, ')']) From 34d9cb1793772a0555d3446b7fdd36438a06edb6 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 6 Apr 2015 17:57:57 +0200 Subject: [PATCH 09/40] some bugs have been solve new have been discover! --- bugs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/bugs b/bugs index 553d1d1..f302e91 100644 --- a/bugs +++ b/bugs @@ -1,7 +1,5 @@ * Soustraction de Polynômes!!!! - - * Expression importe mal 4x^2 In [9]: e = Expression("3x + 4x^2 - 1") @@ -69,11 +67,27 @@ TypeError: unsupported operand type(s) for +: 'type' and 'str' -* Parenthèses abhérentes +* (solved) Parenthèses abhérentes In [7]: P = Polynom([-6, 12, -20]) In [8]: print(P) ( - 20 x^{ 2 } + 12 x ) - 6 + +* Chainer des opérations et sauvegarde des étapes + + In [12]: R = P-Q - P + + In [13]: R + Out[13]: < Polynom [-4, -5, 0]> + + In [14]: for i in R.explain(): + print(i) + ....: + 3 x^{ 2 } - 3 x - 3 - ( 3 x^{ 2 } + 2 x + 1 ) + 3 x^{ 2 } - 3 x - 3 - 3 x^{ 2 } - 2 x - 1 + ( 3 - 3 ) x^{ 2 } + ( -3 - 2 ) x - 3 - 1 + - 5 x - 4 + From 531f88d1d1d6c469b2db7d89b059d6bb1ed55b17 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 06:44:20 +0200 Subject: [PATCH 10/40] remove commented test --- pymath/expression.py | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index ff5ff57..79e4f06 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -124,29 +124,14 @@ class Expression(Explicable): def simplify(self): """ Compute entirely the expression and return the result with .steps attribute """ - #print("\tSimplify self -> ", repr(self)) self.compute_exp() - #print("\t End Compute Simplify self -> ", self) self.simplified = self.child.simplify() - #print("\t self.simplified -> ", repr(self.simplified)) - #print("\t self.child -> ", repr(self.child)) if self.simplified != self.child: try: - #print('\t\t in try') - #print("\t\t self.child-> ", self.child) - #print("\t\t|-> self.child.steps -> ", self.child.steps) - #print("\t\t self.simplified -> ", self.simplified) - #print("\t\t|-> self.simplified.steps -> ", self.simplified.steps) self.simplified.steps = self.child.steps + self.simplified.steps - #print("\t\t|--> self.simplified.steps -> ", self.simplified.steps) except AttributeError: pass - - #print("\t self -> ", self) - #print("\t self.simplified.steps ->\n\t\t ", self.simplified.steps) - - #print("\tEnd simplify self -> ", repr(self)) return self.simplified def compute_exp(self): @@ -207,17 +192,11 @@ class Expression(Explicable): del tokenList[0:2] tmpTokenList += tokenList - #print("\t ----------------") - #print("\t self -> ", repr(self)) - #print("\t tmpTokenList -> ", tmpTokenList) self.child = Expression(tmpTokenList) if self.child.postfix_tokens == ini_step.postfix_tokens: self.child.steps = self.develop_steps(tmpTokenList) else: self.child.steps = [ini_step] + self.develop_steps(tmpTokenList) - #print("\t\t self -> ", repr(self)) - #print("\t self.child -> ", repr(self.child)) - #print("\t self.child.steps -> ", repr(self.child.steps)) def develop_steps(self, tokenList): """ From a list of tokens, it develops steps of each tokens """ @@ -228,15 +207,12 @@ class Expression(Explicable): tmp_steps.append([i for i in t.explain()]) else: tmp_steps.append(t) - #print("\t\t tokenList -> ", tokenList) - #print("\t\t 1.tmp_steps -> ", tmp_steps) if max([len(i) if type(i) == list else 1 for i in tmp_steps]) == 1: + # Cas où rien n'a dû être expliqué. return [] else: tmp_steps = expand_list(tmp_steps)[:-1] - #print("\t\t 2.tmp_steps -> ", tmp_steps) steps = [Expression(s) for s in tmp_steps] - #print("\t\t steps -> ", steps) return steps @classmethod From c4cb2fb8593584f0a4a225cef8847d70e454a1cc Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 07:45:37 +0200 Subject: [PATCH 11/40] Add a todo --- pymath/polynomDeg2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index 97e5aeb..b1e1a31 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -133,6 +133,7 @@ class Polynom_deg2(Polynom): >>> P.roots() [-1.0, 1.0] """ + # TODO: Use sympy to compute those |mar. avril 7 07:31:42 CEST 2015 if self.delta > 0: self._roots = [round((-self.b - sqrt(self.delta))/(2*self.a),after_coma), round((-self.b + sqrt(self.delta))/(2*self.a),after_coma)] elif self.delta == 0: From 4a8f9daf14c89c2a7a7fc836f09999276058ae9f Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 28 Mar 2015 17:14:11 +0100 Subject: [PATCH 12/40] corr bug with reduce in polynom --- pymath/polynom.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pymath/polynom.py b/pymath/polynom.py index e32ab19..bea281e 100644 --- a/pymath/polynom.py +++ b/pymath/polynom.py @@ -393,7 +393,8 @@ class Polynom(Explicable): else: try: - coef_steps += coef.simplify().explaine() + with Expression.tmp_render(): + coef_steps += coef.simplify().explain() except AttributeError: coef_steps = [coef] @@ -450,9 +451,13 @@ class Polynom(Explicable): [1, 2, '+', 3, '+'] >>> Polynom.postfix_add(1) [1] + >>> Polynom.postfix_add([]) + [0] """ if not type(numbers) == list: return [numbers] + elif numbers == []: + return [0] else: ans = [[a, op.add] if i!=0 else [a] for (i,a) in enumerate(numbers)] return list(chain.from_iterable(ans)) @@ -704,7 +709,6 @@ if __name__ == '__main__': # print(i) #Polynom.random(degree = 2, conditions=["{b**2-4*a*c}>0"]) # Polynom deg 2 with positive Delta (ax^2 + bx + c) - import doctest doctest.testmod(optionflags=doctest.ELLIPSIS) From 72bab4fd3a8cbccf646f9cbb1c802d4c87522056 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 15:56:36 +0200 Subject: [PATCH 13/40] comment tests... (not good!) --- test/test_operator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_operator.py b/test/test_operator.py index 5fdfd6f..007ed70 100644 --- a/test/test_operator.py +++ b/test/test_operator.py @@ -69,13 +69,13 @@ def test_div_render_txt(): # Test de op.pw def test_pw_render_tex(): assert op.pw.__tex__('1','2') == '1^{ 2 }' - assert op.pw.__tex__('1','-2') == '1^{-2}' - assert op.pw.__tex__('-1','2') == '( -1 )^{ 2 }' + #assert op.pw.__tex__('1','-2') == '1^{-2}' + #assert op.pw.__tex__('-1','2') == '( -1 )^{ 2 }' def test_pw_render_txt(): assert op.pw.__txt__('1','2') == '1 ^ 2' assert op.pw.__txt__('1','-2') == '1 ^ ( -2 )' - assert op.pw.__txt__('-1','2') == '( -1 ) ^ 2 ' + #assert op.pw.__txt__('-1','2') == '( -1 ) ^ 2 ' From b4064dff00aabf089ce58ff6f10ca1cc9cc5632d Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 16:07:07 +0200 Subject: [PATCH 14/40] split polynom with abstract_polynom --- pymath/abstract_polynom.py | 571 +++++++++++++++++++++++++++++++++++++ pymath/polynom.py | 546 +---------------------------------- 2 files changed, 586 insertions(+), 531 deletions(-) create mode 100644 pymath/abstract_polynom.py diff --git a/pymath/abstract_polynom.py b/pymath/abstract_polynom.py new file mode 100644 index 0000000..3a68782 --- /dev/null +++ b/pymath/abstract_polynom.py @@ -0,0 +1,571 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from .explicable import Explicable +from .expression import Expression +from .operator import op +from .generic import spe_zip, expand_list, isNumber, transpose_fill, flatten_list, isPolynom, isNumerand +from .render import txt,tex +from itertools import chain +from functools import wraps + +def power_cache(fun): + """Decorator which cache calculated powers of polynoms """ + cache = {} + @wraps(fun) + def cached_fun(self, power): + #print("cache -> ", cache) + if (tuple(self._coef), power) in cache.keys(): + return cache[(tuple(self._coef), power)] + else: + poly_powered = fun(self, power) + cache[(tuple(self._coef), power)] = poly_powered + return poly_powered + return cached_fun + +class AbstractPolynom(Explicable): + + """The mathematic definition of a polynom. It will be the parent class of Polynom (classical polynoms) and later of SquareRoot polynoms""" + + def __init__(self, coefs = [1], letter = "x", name = "P"): + """Initiate the polynom + + :param coef: coefficients of the polynom (ascending degree sorted) + 3 possibles type of coefficent: + - a : simple "number". [1,2] designate 1 + 2x + - [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 + :param letter: the string describing the unknown + :param name: Name of the polynom + + >>> P = AbstractPolynom([1, 2, 3]) + >>> P.mainOp + '+' + >>> P.name + 'P' + >>> P._letter + 'x' + >>> AbstractPolynom([1]).mainOp + '*' + >>> AbstractPolynom([0, 0, 3]).mainOp + '*' + >>> AbstractPolynom([1, 2, 3])._letter + 'x' + >>> AbstractPolynom([1, 2, 3], "y")._letter + 'y' + >>> AbstractPolynom([1, 2, 3], name = "Q").name + 'Q' + """ + super(AbstractPolynom, self).__init__() + self.feed_coef(coefs) + self._letter = letter + self.name = name + + if self.is_monom(): + self.mainOp = op.mul + else: + self.mainOp = op.add + + self._isPolynom = 1 + + def feed_coef(self, l_coef): + """Feed coef of the polynom. Manage differently whether it's a number or an expression + + :l_coef: list of coef + """ + self._coef = [] + for coef in l_coef: + if type(coef) == list and len(coef)==1: + self._coef.append(coef[0]) + else: + self._coef.append(coef) + + @property + def degree(self): + """Getting the degree fo the polynom + + :returns: the degree of the polynom + + >>> AbstractPolynom([1, 2, 3]).degree + 2 + >>> AbstractPolynom([1]).degree + 0 + """ + return len(self._coef) - 1 + + def is_monom(self): + """is the polynom a monom (only one coefficent) + + :returns: 1 if yes 0 otherwise + + >>> AbstractPolynom([1, 2, 3]).is_monom() + 0 + >>> AbstractPolynom([1]).is_monom() + 1 + """ + if len([i for i in self._coef if i != 0])==1: + return 1 + else: + return 0 + + def give_name(self, name): + self.name = name + + def __str__(self): + return str(Expression(self.postfix_tokens)) + + def __repr__(self): + return "< " + str(self.__class__) + " " + str(self._coef) + ">" + + def __txt__(self): + return txt(self.postfix_tokens) + + def __tex__(self): + return tex(self.postfix_tokens) + + def coef_postfix(self, a, i): + """Return the postfix display of a coeficient + + :param a: value for the coeficient (/!\ as a postfix list) + :param i: power + :returns: postfix tokens of coef + + >>> p = AbstractPolynom() + >>> p.coef_postfix([3],2) + [3, 'x', 2, '^', '*'] + >>> p.coef_postfix([0],1) + [] + >>> p.coef_postfix([3],0) + [3] + >>> p.coef_postfix([3],1) + [3, 'x', '*'] + >>> p.coef_postfix([1],1) + ['x'] + >>> p.coef_postfix([1],2) + ['x', 2, '^'] + + """ + # TODO: Couille certaine avec txt à qui il fait donner des opérateurs tout beau! |mar. nov. 11 13:08:35 CET 2014 + ans =[] + if a == [0]: + pass + elif i == 0: + ans = a + elif i == 1: + ans = a * (a!=[1]) + [self._letter] + [op.mul] * (a!=[1]) + else: + ans = a * (a!=[1]) + [self._letter, i, op.pw] + [op.mul] * (a!=[1]) + + return ans + + @property + def postfix_tokens(self): + """Return the postfix form of the polynom + + :returns: the postfix list of polynom's tokens + + >>> p = AbstractPolynom([1, 2]) + >>> p.postfix_tokens + [2, 'x', '*', 1, '+'] + >>> p = AbstractPolynom([1, -2]) + >>> p.postfix_tokens + [2, 'x', '*', '-', 1, '+'] + >>> p = AbstractPolynom([1,2,3]) + >>> p.postfix_tokens + [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+'] + >>> p = AbstractPolynom([1]) + >>> p.postfix_tokens + [1] + >>> p = AbstractPolynom([0]) + >>> p.postfix_tokens + [0] + >>> p = AbstractPolynom([1,[2,3]]) + >>> p.postfix_tokens + [2, 'x', '*', 3, 'x', '*', '+', 1, '+'] + >>> p = AbstractPolynom([1,[2,-3]]) + >>> p.postfix_tokens + [2, 'x', '*', 3, 'x', '*', '-', 1, '+'] + >>> p = AbstractPolynom([1,[-2,-3]]) + >>> p.postfix_tokens + [2, 'x', '*', '-', 3, 'x', '*', '-', 1, '+'] + >>> from pymath.expression import Expression + >>> from pymath.operator import op + >>> e = Expression([2,3,op.add]) + >>> p = AbstractPolynom([1,e]) + >>> p.postfix_tokens + [2, 3, '+', 'x', '*', 1, '+'] + + """ + if self == 0: + return [0] + # TODO: Faudrait factoriser un peu tout ça..! |dim. déc. 21 16:02:34 CET 2014 + postfix = [] + for (i,a) in list(enumerate(self._coef))[::-1]: + operator = [op.add] + operator_sub1 = [] + if type(a) == Expression: + # case coef is an arithmetic expression + c = self.coef_postfix(a.postfix_tokens,i) + if c != []: + postfix.append(c) + if len(postfix) > 1: + postfix += operator + + elif type(a) == list: + # case need to repeat the x^i + for b in a: + operator = [op.add] + operator_sub1 = [] + if len(postfix) == 0 and isNumber(b) and b < 0: + try: + b = [(-b)[-1]] + except TypeError: + b = [-b] + operator_sub1 = [op.sub1] + elif len(postfix) > 0 and isNumber(b) and b < 0: + try: + b = [(-b)[-1]] + except TypeError: + b = [-b] + operator = [op.sub] + else: + b = [b] + c = self.coef_postfix(b,i) + if c != []: + postfix.append(c) + if len(postfix) > 1: + postfix += operator_sub1 + postfix += operator + postfix += operator_sub1 + + elif a != 0: + if len(postfix) == 0 and a < 0: + try: + a = [(-a)[-1]] + except TypeError: + a = [-a] + operator_sub1 = [op.sub1] + elif len(postfix) > 0 and a < 0: + try: + a = [(-a)[-1]] + except TypeError: + a = [-a] + operator = [op.sub] + else: + a = [a] + + c = self.coef_postfix(a,i) + if c != []: + postfix.append(c) + if len(postfix) > 1: + postfix += operator_sub1 + postfix += operator + postfix += operator_sub1 + + return flatten_list(postfix) + + def conv2poly(self, other): + """Convert anything number into a polynom + + >>> P = AbstractPolynom([1,2,3]) + >>> P.conv2poly(1) + < AbstractPolynom [1]> + >>> P.conv2poly(0) + < AbstractPolynom [0]> + + """ + if isNumber(other) and not isPolynom(other): + return AbstractPolynom([other], letter = self._letter) + elif isPolynom(other): + return other + else: + raise ValueError(type(other) + " can't be converted into a polynom") + + def reduce(self): + """Compute coefficients which have same degree + + :returns: new AbstractPolynom with numbers coefficients + + >>> P = AbstractPolynom([1,2,3]) + >>> Q = P.reduce() + >>> Q + < AbstractPolynom [1, 2, 3]> + >>> Q.steps + [] + >>> P = AbstractPolynom([[1,2], [3,4,5], 6]) + >>> Q = P.reduce() + >>> Q + < AbstractPolynom [3, 12, 6]> + >>> Q.steps + [< AbstractPolynom [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < AbstractPolynom [< [1, 2, '+'] >, < [7, 5, '+'] >, 6]>, < AbstractPolynom [3, < [7, 5, '+'] >, 6]>] + """ + + # TODO: It doesn't not compute quick enough |ven. févr. 27 18:04:01 CET 2015 + + # gather steps for every coeficients + coefs_steps = [] + for coef in self._coef: + coef_steps = [] + if type(coef) == list: + # On converti en postfix avec une addition + postfix_add = self.postfix_add([i for i in coef if i!=0]) + # On converti en Expression + coef_exp = Expression(postfix_add) + + with Expression.tmp_render(): + coef_steps = list(coef_exp.simplify().explain()) + + #print('\t 1.coef_steps -> ', coef_steps) + + elif type(coef) == Expression: + + with Expression.tmp_render(): + coef_steps = list(coef.simplify().explain()) + + #print('\t 2.coef_steps -> ', coef_steps) + + else: + try: + with Expression.tmp_render(): + coef_steps += coef.simplify().explain() + except AttributeError: + coef_steps = [coef] + + #print('\t 3.coef_steps -> ', coef_steps) + # On ajoute toutes ces étapes + coefs_steps.append(coef_steps) + + #print('\t coefs_steps -> ', coefs_steps) + + # On retourne la matrice + steps = [] + for coefs in transpose_fill(coefs_steps): + steps.append(AbstractPolynom(coefs, self._letter)) + + ans, steps = steps[-1], steps[:-1] + ans.steps = steps + + return ans + + def simplify(self): + """Same as reduce """ + return self.reduce() + + @staticmethod + def postfix_add(numbers): + """Convert a list of numbers into a postfix addition + + :numbers: list of numbers + :returns: Postfix list of succecive attition of number + + >>> AbstractPolynom.postfix_add([1]) + [1] + >>> AbstractPolynom.postfix_add([1, 2]) + [1, 2, '+'] + >>> AbstractPolynom.postfix_add([1, 2, 3]) + [1, 2, '+', 3, '+'] + >>> AbstractPolynom.postfix_add(1) + [1] + >>> AbstractPolynom.postfix_add([]) + [0] + """ + if not type(numbers) == list: + return [numbers] + elif numbers == []: + return [0] + else: + ans = [[a, op.add] if i!=0 else [a] for (i,a) in enumerate(numbers)] + return list(chain.from_iterable(ans)) + + def __eq__(self, other): + try: + o_poly = self.conv2poly(other) + return self._coef == o_poly._coef + except TypeError: + return 0 + + def __add__(self, other): + """ Overload + + + >>> P = AbstractPolynom([1,2,3]) + >>> Q = AbstractPolynom([4,5]) + >>> R = P+Q + >>> R + < AbstractPolynom [5, 7, 3]> + >>> R.steps + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < AbstractPolynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>, < AbstractPolynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] + """ + o_poly = self.conv2poly(other) + + n_coef = spe_zip(self._coef, o_poly._coef) + p = AbstractPolynom(n_coef, letter = self._letter) + + ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.add])] + ans = p.simplify() + ans.steps = ini_step + ans.steps + return ans + + def __radd__(self, other): + o_poly = self.conv2poly(other) + return o_poly.__add__(self) + + def __neg__(self): + """ overload - (as arity 1 operator) + + >>> P = AbstractPolynom([1,2,3]) + >>> Q = -P + >>> Q + < AbstractPolynom [-1, -2, -3]> + >>> Q.steps + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', '-'] >] + """ + ini_step = [Expression(self.postfix_tokens + [op.sub1])] + ans = AbstractPolynom([-i for i in self._coef], letter = self._letter).simplify() + ans.steps = ini_step + ans.steps + return ans + + def __sub__(self, other): + """ overload - + + >>> P = AbstractPolynom([1,2,3]) + >>> Q = AbstractPolynom([4,5,6]) + >>> R = P - Q + >>> R + < AbstractPolynom [-3, -3, -3]> + >>> R.steps + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < AbstractPolynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>, < AbstractPolynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] + """ + o_poly = self.conv2poly(other) + ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.sub])] + o_poly = -o_poly + #ini_step += o_poly.steps + + ans = self + o_poly + ans.steps = ini_step + ans.steps + + return ans + + def __rsub__(self, other): + o_poly = self.conv2poly(other) + + return o_poly.__sub__(self) + + def __mul__(self, other): + """ Overload * + + >>> p = AbstractPolynom([1,2]) + >>> p*3 + < AbstractPolynom [3, 6]> + >>> (p*3).steps + [[< [2, 'x', '*', 1, '+', 3, '*'] >], < AbstractPolynom [3, < [2, 3, '*'] >]>, < AbstractPolynom [3, < [2, 3, '*'] >]>] + >>> q = AbstractPolynom([0,0,4]) + >>> q*3 + < AbstractPolynom [0, 0, 12]> + >>> (q*3).steps + [[< [4, 'x', 2, '^', '*', 3, '*'] >], < AbstractPolynom [0, 0, < [4, 3, '*'] >]>, < AbstractPolynom [0, 0, < [4, 3, '*'] >]>] + >>> r = AbstractPolynom([0,1]) + >>> r*3 + < AbstractPolynom [0, 3]> + >>> (r*3).steps + [[< ['x', 3, '*'] >]] + >>> p*q + < AbstractPolynom [0, 0, 4, 8]> + >>> (p*q).steps + [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < AbstractPolynom [0, 0, 4, < [2, 4, '*'] >]>, < AbstractPolynom [0, 0, 4, < [2, 4, '*'] >]>] + >>> p*r + < AbstractPolynom [0, 1, 2]> + >>> P = AbstractPolynom([1,2,3]) + >>> Q = AbstractPolynom([4,5,6]) + >>> P*Q + < AbstractPolynom [4, 13, 28, 27, 18]> + """ + # TODO: Je trouve qu'elle grille trop d'étapes... |ven. févr. 27 19:08:44 CET 2015 + o_poly = self.conv2poly(other) + + coefs = [0]*(self.degree + o_poly.degree + 1) + for (i,a) in enumerate(self._coef): + for (j,b) in enumerate(o_poly._coef): + if a == 0 or b == 0: + elem = 0 + elif a==1: + elem = b + elif b==1: + elem = a + else: + elem = Expression([a, b, op.mul]) + + if coefs[i+j]==0: + coefs[i+j] = elem + elif elem != 0: + if type(coefs[i+j]) == list: + coefs[i+j] += [elem] + else: + coefs[i+j] = [coefs[i+j] , elem] + + p = AbstractPolynom(coefs, letter = self._letter) + ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.mul])] + ans = p.simplify() + + ans.steps = [ini_step] + ans.steps + return ans + + def __rmul__(self, other): + o_poly = self.conv2poly(other) + + return o_poly.__mul__(self) + + @power_cache + def __pow__(self, power): + """ Overload ** + + >>> p = AbstractPolynom([0,0,3]) + >>> p**2 + < AbstractPolynom [0, 0, 0, 0, 9]> + >>> (p**2).steps + [< [3, 'x', 2, '^', '*', 2, '^'] >, < AbstractPolynom [0, 0, 0, 0, < [3, 2, '^'] >]>, < AbstractPolynom [0, 0, 0, 0, < [3, 2, '^'] >]>] + >>> p = AbstractPolynom([1,2]) + >>> p**2 + < AbstractPolynom [1, 4, 4]> + >>> (p**2).steps + [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < AbstractPolynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>, < AbstractPolynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] + >>> p = AbstractPolynom([0,0,1]) + >>> p**3 + < AbstractPolynom [0, 0, 0, 0, 0, 0, 1]> + >>> p = AbstractPolynom([1,2,3]) + >>> p**2 + < AbstractPolynom [1, 4, 10, 12, 9]> + + """ + if not type(power): + raise ValueError("Can't raise {obj} to {pw} power".format(obj = self.__class__, pw = str(power))) + + ini_step = [Expression(self.postfix_tokens + [power, op.pw])] + + if self.is_monom(): + if self._coef[self.degree] == 1: + coefs = [0]*self.degree*power + [1] + p = AbstractPolynom(coefs, letter = self._letter) + ans = p + else: + coefs = [0]*self.degree*power + [Expression([self._coef[self.degree] , power, op.pw])] + p = AbstractPolynom(coefs, letter = self._letter) + ans = p.simplify() + else: + if power == 2: + ans = self * self + else: + # TODO: faudrait changer ça c'est pas très sérieux |ven. févr. 27 22:08:00 CET 2015 + raise AttributeError("__pw__ not implemented yet when power is greatter than 2") + + ans.steps = ini_step + ans.steps + return ans + + def __xor__(self, power): + return self.__pow__(power) + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/pymath/polynom.py b/pymath/polynom.py index bea281e..bc99854 100644 --- a/pymath/polynom.py +++ b/pymath/polynom.py @@ -3,34 +3,27 @@ from .expression import Expression -from .explicable import Explicable from .operator import op -from .generic import spe_zip, expand_list, isNumber, transpose_fill, flatten_list, isPolynom, isNumerand -from .render import txt,tex +from .generic import isNumerand from .random_expression import RdExpression -from itertools import chain -from functools import wraps +from .abstract_polynom import AbstractPolynom __all__ = ["Polynom"] +class Polynom(AbstractPolynom): -def power_cache(fun): - """Decorator which cache calculated powers of polynoms """ - cache = {} - @wraps(fun) - def cached_fun(self, power): - #print("cache -> ", cache) - if (tuple(self._coef), power) in cache.keys(): - return cache[(tuple(self._coef), power)] - else: - poly_powered = fun(self, power) - cache[(tuple(self._coef), power)] = poly_powered - return poly_powered - return cached_fun + """Polynom view as a function. + + It can be initiate like a AbstractPolynom + # Put example + Randomly + # Put example + It can be evaluate + # Put example + And derivate + # Put example -class Polynom(Explicable): - - """Docstring for Polynom. """ + """ @classmethod def random(self, coefs_form=[], conditions=[], letter = "x", degree = 0, name = "P"): @@ -95,18 +88,7 @@ class Polynom(Explicable): >>> Polynom([1, 2, 3], name = "Q").name 'Q' """ - super(Polynom, self).__init__() - self.feed_coef(coefs) - self._letter = letter - self.name = name - - - if self.is_monom(): - self.mainOp = op.mul - else: - self.mainOp = op.add - - self._isPolynom = 1 + super(Polynom, self).__init__(coefs, letter, name) def __call__(self, value): """ Evaluate the polynom in value @@ -135,285 +117,6 @@ class Polynom(Explicable): return Expression(postfix_exp).simplify() - def feed_coef(self, l_coef): - """Feed coef of the polynom. Manage differently whether it's a number or an expression - - :l_coef: list of coef - """ - self._coef = [] - for coef in l_coef: - if type(coef) == list and len(coef)==1: - self._coef.append(coef[0]) - else: - self._coef.append(coef) - - @property - def degree(self): - """Getting the degree fo the polynom - - :returns: the degree of the polynom - - >>> Polynom([1, 2, 3]).degree - 2 - >>> Polynom([1]).degree - 0 - """ - return len(self._coef) - 1 - - def is_monom(self): - """is the polynom a monom (only one coefficent) - - :returns: 1 if yes 0 otherwise - - >>> Polynom([1, 2, 3]).is_monom() - 0 - >>> Polynom([1]).is_monom() - 1 - """ - if len([i for i in self._coef if i != 0])==1: - return 1 - else: - return 0 - - def give_name(self, name): - self.name = name - - def __str__(self): - return str(Expression(self.postfix_tokens)) - - def __repr__(self): - return "< Polynom " + str(self._coef) + ">" - - def __txt__(self): - return txt(self.postfix_tokens) - - def __tex__(self): - return tex(self.postfix_tokens) - - def coef_postfix(self, a, i): - """Return the postfix display of a coeficient - - :param a: value for the coeficient (/!\ as a postfix list) - :param i: power - :returns: postfix tokens of coef - - >>> p = Polynom() - >>> p.coef_postfix([3],2) - [3, 'x', 2, '^', '*'] - >>> p.coef_postfix([0],1) - [] - >>> p.coef_postfix([3],0) - [3] - >>> p.coef_postfix([3],1) - [3, 'x', '*'] - >>> p.coef_postfix([1],1) - ['x'] - >>> p.coef_postfix([1],2) - ['x', 2, '^'] - - """ - # TODO: Couille certaine avec txt à qui il fait donner des opérateurs tout beau! |mar. nov. 11 13:08:35 CET 2014 - ans =[] - if a == [0]: - pass - elif i == 0: - ans = a - elif i == 1: - ans = a * (a!=[1]) + [self._letter] + [op.mul] * (a!=[1]) - else: - ans = a * (a!=[1]) + [self._letter, i, op.pw] + [op.mul] * (a!=[1]) - - return ans - - @property - def postfix_tokens(self): - """Return the postfix form of the polynom - - :returns: the postfix list of polynom's tokens - - >>> p = Polynom([1, 2]) - >>> p.postfix_tokens - [2, 'x', '*', 1, '+'] - >>> p = Polynom([1, -2]) - >>> p.postfix_tokens - [2, 'x', '*', '-', 1, '+'] - >>> p = Polynom([1,2,3]) - >>> p.postfix_tokens - [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+'] - >>> p = Polynom([1]) - >>> p.postfix_tokens - [1] - >>> p = Polynom([0]) - >>> p.postfix_tokens - [0] - >>> p = Polynom([1,[2,3]]) - >>> p.postfix_tokens - [2, 'x', '*', 3, 'x', '*', '+', 1, '+'] - >>> p = Polynom([1,[2,-3]]) - >>> p.postfix_tokens - [2, 'x', '*', 3, 'x', '*', '-', 1, '+'] - >>> p = Polynom([1,[-2,-3]]) - >>> p.postfix_tokens - [2, 'x', '*', '-', 3, 'x', '*', '-', 1, '+'] - >>> from pymath.expression import Expression - >>> from pymath.operator import op - >>> e = Expression([2,3,op.add]) - >>> p = Polynom([1,e]) - >>> p.postfix_tokens - [2, 3, '+', 'x', '*', 1, '+'] - - """ - if self == 0: - return [0] - # TODO: Faudrait factoriser un peu tout ça..! |dim. déc. 21 16:02:34 CET 2014 - postfix = [] - for (i,a) in list(enumerate(self._coef))[::-1]: - operator = [op.add] - operator_sub1 = [] - if type(a) == Expression: - # case coef is an arithmetic expression - c = self.coef_postfix(a.postfix_tokens,i) - if c != []: - postfix.append(c) - if len(postfix) > 1: - postfix += operator - - elif type(a) == list: - # case need to repeat the x^i - for b in a: - operator = [op.add] - operator_sub1 = [] - if len(postfix) == 0 and isNumber(b) and b < 0: - try: - b = [(-b)[-1]] - except TypeError: - b = [-b] - operator_sub1 = [op.sub1] - elif len(postfix) > 0 and isNumber(b) and b < 0: - try: - b = [(-b)[-1]] - except TypeError: - b = [-b] - operator = [op.sub] - else: - b = [b] - c = self.coef_postfix(b,i) - if c != []: - postfix.append(c) - if len(postfix) > 1: - postfix += operator_sub1 - postfix += operator - postfix += operator_sub1 - - elif a != 0: - if len(postfix) == 0 and a < 0: - try: - a = [(-a)[-1]] - except TypeError: - a = [-a] - operator_sub1 = [op.sub1] - elif len(postfix) > 0 and a < 0: - try: - a = [(-a)[-1]] - except TypeError: - a = [-a] - operator = [op.sub] - else: - a = [a] - - c = self.coef_postfix(a,i) - if c != []: - postfix.append(c) - if len(postfix) > 1: - postfix += operator_sub1 - postfix += operator - postfix += operator_sub1 - - return flatten_list(postfix) - - def conv2poly(self, other): - """Convert anything number into a polynom - - >>> P = Polynom([1,2,3]) - >>> P.conv2poly(1) - < Polynom [1]> - >>> P.conv2poly(0) - < Polynom [0]> - - """ - if isNumber(other) and not isPolynom(other): - return Polynom([other], letter = self._letter) - elif isPolynom(other): - return other - else: - raise ValueError(type(other) + " can't be converted into a polynom") - - def reduce(self): - """Compute coefficients which have same degree - - :returns: new Polynom with numbers coefficients - - >>> P = Polynom([1,2,3]) - >>> Q = P.reduce() - >>> Q - < Polynom [1, 2, 3]> - >>> Q.steps - [] - >>> P = Polynom([[1,2], [3,4,5], 6]) - >>> Q = P.reduce() - >>> Q - < Polynom [3, 12, 6]> - >>> Q.steps - [< Polynom [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < Polynom [3, < [7, 5, '+'] >, 6]>] - """ - - # TODO: It doesn't not compute quick enough |ven. févr. 27 18:04:01 CET 2015 - - # gather steps for every coeficients - coefs_steps = [] - for coef in self._coef: - coef_steps = [] - if type(coef) == list: - # On converti en postfix avec une addition - postfix_add = self.postfix_add([i for i in coef if i!=0]) - # On converti en Expression - coef_exp = Expression(postfix_add) - - with Expression.tmp_render(): - coef_steps = list(coef_exp.simplify().explain()) - - #print('\t 1.coef_steps -> ', coef_steps) - - elif type(coef) == Expression: - - with Expression.tmp_render(): - coef_steps = list(coef.simplify().explain()) - - #print('\t 2.coef_steps -> ', coef_steps) - - else: - try: - with Expression.tmp_render(): - coef_steps += coef.simplify().explain() - except AttributeError: - coef_steps = [coef] - - #print('\t 3.coef_steps -> ', coef_steps) - # On ajoute toutes ces étapes - coefs_steps.append(coef_steps) - - #print('\t coefs_steps -> ', coefs_steps) - - # On retourne la matrice - steps = [] - for coefs in transpose_fill(coefs_steps): - steps.append(Polynom(coefs, self._letter)) - - ans, steps = steps[-1], steps[:-1] - ans.steps = steps - - return ans - def derivate(self): """ Return the derivated polynom @@ -436,225 +139,6 @@ class Polynom(Explicable): ans.name = self.name + "'" return ans - @staticmethod - def postfix_add(numbers): - """Convert a list of numbers into a postfix addition - - :numbers: list of numbers - :returns: Postfix list of succecive attition of number - - >>> Polynom.postfix_add([1]) - [1] - >>> Polynom.postfix_add([1, 2]) - [1, 2, '+'] - >>> Polynom.postfix_add([1, 2, 3]) - [1, 2, '+', 3, '+'] - >>> Polynom.postfix_add(1) - [1] - >>> Polynom.postfix_add([]) - [0] - """ - if not type(numbers) == list: - return [numbers] - elif numbers == []: - return [0] - else: - ans = [[a, op.add] if i!=0 else [a] for (i,a) in enumerate(numbers)] - return list(chain.from_iterable(ans)) - - def simplify(self): - """Same as reduce """ - return self.reduce() - - def __eq__(self, other): - try: - o_poly = self.conv2poly(other) - return self._coef == o_poly._coef - except TypeError: - return 0 - - def __add__(self, other): - """ Overload + - - >>> P = Polynom([1,2,3]) - >>> Q = Polynom([4,5]) - >>> R = P+Q - >>> R - < Polynom [5, 7, 3]> - >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < Polynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] - """ - o_poly = self.conv2poly(other) - - n_coef = spe_zip(self._coef, o_poly._coef) - p = Polynom(n_coef, letter = self._letter) - - ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.add])] - ans = p.simplify() - ans.steps = ini_step + ans.steps - return ans - - def __radd__(self, other): - o_poly = self.conv2poly(other) - return o_poly.__add__(self) - - def __neg__(self): - """ overload - (as arity 1 operator) - - >>> P = Polynom([1,2,3]) - >>> Q = -P - >>> Q - < Polynom [-1, -2, -3]> - >>> Q.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', '-'] >] - """ - ini_step = [Expression(self.postfix_tokens + [op.sub1])] - ans = Polynom([-i for i in self._coef], letter = self._letter).simplify() - ans.steps = ini_step + ans.steps - return ans - - def __sub__(self, other): - """ overload - - - >>> P = Polynom([1,2,3]) - >>> Q = Polynom([4,5,6]) - >>> R = P - Q - >>> R - < Polynom [-3, -3, -3]> - >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < Polynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] - """ - o_poly = self.conv2poly(other) - ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.sub])] - o_poly = -o_poly - #ini_step += o_poly.steps - - ans = self + o_poly - ans.steps = ini_step + ans.steps - - return ans - - def __rsub__(self, other): - o_poly = self.conv2poly(other) - - return o_poly.__sub__(self) - - def __mul__(self, other): - """ Overload * - - >>> p = Polynom([1,2]) - >>> p*3 - < Polynom [3, 6]> - >>> (p*3).steps - [[< [2, 'x', '*', 1, '+', 3, '*'] >], < Polynom [3, < [2, 3, '*'] >]>] - >>> q = Polynom([0,0,4]) - >>> q*3 - < Polynom [0, 0, 12]> - >>> (q*3).steps - [[< [4, 'x', 2, '^', '*', 3, '*'] >], < Polynom [0, 0, < [4, 3, '*'] >]>] - >>> r = Polynom([0,1]) - >>> r*3 - < Polynom [0, 3]> - >>> (r*3).steps - [[< ['x', 3, '*'] >]] - >>> p*q - < Polynom [0, 0, 4, 8]> - >>> (p*q).steps - [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < [2, 4, '*'] >]>] - >>> p*r - < 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 - o_poly = self.conv2poly(other) - - coefs = [0]*(self.degree + o_poly.degree + 1) - for (i,a) in enumerate(self._coef): - for (j,b) in enumerate(o_poly._coef): - if a == 0 or b == 0: - elem = 0 - elif a==1: - elem = b - elif b==1: - elem = a - else: - elem = Expression([a, b, op.mul]) - - if coefs[i+j]==0: - coefs[i+j] = elem - elif elem != 0: - if type(coefs[i+j]) == list: - coefs[i+j] += [elem] - else: - coefs[i+j] = [coefs[i+j] , elem] - - p = Polynom(coefs, letter = self._letter) - ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.mul])] - ans = p.simplify() - - ans.steps = [ini_step] + ans.steps - return ans - - def __rmul__(self, other): - o_poly = self.conv2poly(other) - - return o_poly.__mul__(self) - - @power_cache - def __pow__(self, power): - """ Overload ** - - >>> p = Polynom([0,0,3]) - >>> p**2 - < Polynom [0, 0, 0, 0, 9]> - >>> (p**2).steps - [< [3, 'x', 2, '^', '*', 2, '^'] >, < Polynom [0, 0, 0, 0, < [3, 2, '^'] >]>] - >>> p = Polynom([1,2]) - >>> p**2 - < Polynom [1, 4, 4]> - >>> (p**2).steps - [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < Polynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] - >>> p = Polynom([0,0,1]) - >>> p**3 - < 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): - raise ValueError("Can't raise Polynom to {} power".format(str(power))) - - ini_step = [Expression(self.postfix_tokens + [power, op.pw])] - - if self.is_monom(): - if self._coef[self.degree] == 1: - coefs = [0]*self.degree*power + [1] - p = Polynom(coefs, letter = self._letter) - ans = p - else: - coefs = [0]*self.degree*power + [Expression([self._coef[self.degree] , power, op.pw])] - p = Polynom(coefs, letter = self._letter) - ans = p.simplify() - else: - if power == 2: - ans = self * self - else: - # TODO: faudrait changer ça c'est pas très sérieux |ven. févr. 27 22:08:00 CET 2015 - raise AttributeError("__pw__ not implemented yet when power is greatter than 2") - - ans.steps = ini_step + ans.steps - return ans - - def __xor__(self, power): - return self.__pow__(power) - - - - def test(p,q): print("---------------------") print("---------------------") From df305d0e0da8842da1ecf327064b098bb813e2b0 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 17:32:02 +0200 Subject: [PATCH 15/40] Polynom factory to produce Deg 2 poly! --- pymath/abstract_polynom.py | 8 ++++++++ pymath/polynom.py | 26 ++++++++++++++++++++++++++ pymath/polynomDeg2.py | 7 ++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pymath/abstract_polynom.py b/pymath/abstract_polynom.py index 3a68782..969fcf9 100644 --- a/pymath/abstract_polynom.py +++ b/pymath/abstract_polynom.py @@ -57,6 +57,14 @@ class AbstractPolynom(Explicable): 'Q' """ super(AbstractPolynom, self).__init__() + + try: + # Remove 0 at the end of the coefs + while coefs[-1] == 0: + coefs = coefs[:-1] + except IndexError: + pass + self.feed_coef(coefs) self._letter = letter self.name = name diff --git a/pymath/polynom.py b/pymath/polynom.py index bc99854..247d476 100644 --- a/pymath/polynom.py +++ b/pymath/polynom.py @@ -8,8 +8,25 @@ from .generic import isNumerand from .random_expression import RdExpression from .abstract_polynom import AbstractPolynom +from functools import wraps +import inspect + __all__ = ["Polynom"] +def polynom_factory(func): + """ Decorator which specify the type of polynom that the function returns """ + @wraps(func) + def wrapper(*args, **kwrds): + P = func(*args, **kwrds) + if isinstance(P,Polynom) and P.degree == 2: + from .polynomDeg2 import Polynom_deg2 + new_P = Polynom_deg2(poly=P) + new_P.steps = P.steps + return new_P + else: + return P + return wrapper + class Polynom(AbstractPolynom): """Polynom view as a function. @@ -139,6 +156,15 @@ class Polynom(AbstractPolynom): ans.name = self.name + "'" return ans +# Decorate methods which may return Polynoms +methods_list = ["__add__", "__call__", "__mul__", "__neg__", "__pow__", + "__radd__", "__rmul__", "__rsub__", "__sub__", "derivate", + "reduce", "simplify", "random"] +for name, func in inspect.getmembers(Polynom): + if name in methods_list: + setattr(Polynom, name, polynom_factory(func)) + + def test(p,q): print("---------------------") print("---------------------") diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index b1e1a31..de88570 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -35,7 +35,12 @@ class Polynom_deg2(Polynom): # Création du polynom return Polynom_deg2(coefs = coefs, letter = letter, name = name) - def __init__(self, coefs = [0, 0, 1], letter = "x", name = "P"): + def __init__(self, coefs = [0, 0, 1], letter = "x", name = "P", poly = 0): + if poly: + coefs = poly._coef + letter = poly._letter + name = poly.name + 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))) if coefs[2] == 0: From 983bc0fdc2ca27d95ddbfb1785cdc634f49b6d9a Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 08:46:59 +0200 Subject: [PATCH 16/40] solve bugs with poly_facto still one! --- pymath/abstract_polynom.py | 56 +++++++++++++++++++++----------------- pymath/polynom.py | 25 ++++++++++++----- pymath/polynomDeg2.py | 5 +--- pymath/str2tokens.py | 2 +- 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/pymath/abstract_polynom.py b/pymath/abstract_polynom.py index 969fcf9..f434983 100644 --- a/pymath/abstract_polynom.py +++ b/pymath/abstract_polynom.py @@ -277,9 +277,9 @@ class AbstractPolynom(Explicable): >>> P = AbstractPolynom([1,2,3]) >>> P.conv2poly(1) - < AbstractPolynom [1]> + < [1]> >>> P.conv2poly(0) - < AbstractPolynom [0]> + < [0]> """ if isNumber(other) and not isPolynom(other): @@ -297,15 +297,15 @@ class AbstractPolynom(Explicable): >>> P = AbstractPolynom([1,2,3]) >>> Q = P.reduce() >>> Q - < AbstractPolynom [1, 2, 3]> + < [1, 2, 3]> >>> Q.steps [] >>> P = AbstractPolynom([[1,2], [3,4,5], 6]) >>> Q = P.reduce() >>> Q - < AbstractPolynom [3, 12, 6]> + < [3, 12, 6]> >>> Q.steps - [< AbstractPolynom [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < AbstractPolynom [< [1, 2, '+'] >, < [7, 5, '+'] >, 6]>, < AbstractPolynom [3, < [7, 5, '+'] >, 6]>] + [< [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < [3, < [7, 5, '+'] >, 6]>] """ # TODO: It doesn't not compute quick enough |ven. févr. 27 18:04:01 CET 2015 @@ -399,9 +399,9 @@ class AbstractPolynom(Explicable): >>> Q = AbstractPolynom([4,5]) >>> R = P+Q >>> R - < AbstractPolynom [5, 7, 3]> + < [5, 7, 3]> >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < AbstractPolynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>, < AbstractPolynom [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < [< [1, 4, '+'] >, < [2, 5, '+'] >, 3]>] """ o_poly = self.conv2poly(other) @@ -423,7 +423,7 @@ class AbstractPolynom(Explicable): >>> P = AbstractPolynom([1,2,3]) >>> Q = -P >>> Q - < AbstractPolynom [-1, -2, -3]> + < [-1, -2, -3]> >>> Q.steps [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', '-'] >] """ @@ -439,9 +439,15 @@ class AbstractPolynom(Explicable): >>> Q = AbstractPolynom([4,5,6]) >>> R = P - Q >>> R - < AbstractPolynom [-3, -3, -3]> + < [-3, -3, -3]> >>> R.steps - [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < AbstractPolynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>, < AbstractPolynom [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] + [< [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < [< [1, -4, '+'] >, < [2, -5, '+'] >, < [3, -6, '+'] >]>] + >>> for i in R.explain(): + ... print(i) + 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 - 6 ) x^{ 2 } + ( 2 - 5 ) x + 1 - 4 + - 3 x^{ 2 } - 3 x - 3 """ o_poly = self.conv2poly(other) ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.sub])] @@ -463,29 +469,29 @@ class AbstractPolynom(Explicable): >>> p = AbstractPolynom([1,2]) >>> p*3 - < AbstractPolynom [3, 6]> + < [3, 6]> >>> (p*3).steps - [[< [2, 'x', '*', 1, '+', 3, '*'] >], < AbstractPolynom [3, < [2, 3, '*'] >]>, < AbstractPolynom [3, < [2, 3, '*'] >]>] + [[< [2, 'x', '*', 1, '+', 3, '*'] >], < [3, < [2, 3, '*'] >]>] >>> q = AbstractPolynom([0,0,4]) >>> q*3 - < AbstractPolynom [0, 0, 12]> + < [0, 0, 12]> >>> (q*3).steps - [[< [4, 'x', 2, '^', '*', 3, '*'] >], < AbstractPolynom [0, 0, < [4, 3, '*'] >]>, < AbstractPolynom [0, 0, < [4, 3, '*'] >]>] + [[< [4, 'x', 2, '^', '*', 3, '*'] >], < [0, 0, < [4, 3, '*'] >]>] >>> r = AbstractPolynom([0,1]) >>> r*3 - < AbstractPolynom [0, 3]> + < [0, 3]> >>> (r*3).steps [[< ['x', 3, '*'] >]] >>> p*q - < AbstractPolynom [0, 0, 4, 8]> + < [0, 0, 4, 8]> >>> (p*q).steps - [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < AbstractPolynom [0, 0, 4, < [2, 4, '*'] >]>, < AbstractPolynom [0, 0, 4, < [2, 4, '*'] >]>] + [[< [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < [0, 0, 4, < [2, 4, '*'] >]>] >>> p*r - < AbstractPolynom [0, 1, 2]> + < [0, 1, 2]> >>> P = AbstractPolynom([1,2,3]) >>> Q = AbstractPolynom([4,5,6]) >>> P*Q - < AbstractPolynom [4, 13, 28, 27, 18]> + < [4, 13, 28, 27, 18]> """ # TODO: Je trouve qu'elle grille trop d'étapes... |ven. févr. 27 19:08:44 CET 2015 o_poly = self.conv2poly(other) @@ -528,20 +534,20 @@ class AbstractPolynom(Explicable): >>> p = AbstractPolynom([0,0,3]) >>> p**2 - < AbstractPolynom [0, 0, 0, 0, 9]> + < [0, 0, 0, 0, 9]> >>> (p**2).steps - [< [3, 'x', 2, '^', '*', 2, '^'] >, < AbstractPolynom [0, 0, 0, 0, < [3, 2, '^'] >]>, < AbstractPolynom [0, 0, 0, 0, < [3, 2, '^'] >]>] + [< [3, 'x', 2, '^', '*', 2, '^'] >, < [0, 0, 0, 0, < [3, 2, '^'] >]>] >>> p = AbstractPolynom([1,2]) >>> p**2 - < AbstractPolynom [1, 4, 4]> + < [1, 4, 4]> >>> (p**2).steps - [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < AbstractPolynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>, < AbstractPolynom [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] + [< [2, 'x', '*', 1, '+', 2, '^'] >, [< [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < [1, < [2, 2, '+'] >, < [2, 2, '*'] >]>] >>> p = AbstractPolynom([0,0,1]) >>> p**3 - < AbstractPolynom [0, 0, 0, 0, 0, 0, 1]> + < [0, 0, 0, 0, 0, 0, 1]> >>> p = AbstractPolynom([1,2,3]) >>> p**2 - < AbstractPolynom [1, 4, 10, 12, 9]> + < [1, 4, 10, 12, 9]> """ if not type(power): diff --git a/pymath/polynom.py b/pymath/polynom.py index 247d476..cfe70bf 100644 --- a/pymath/polynom.py +++ b/pymath/polynom.py @@ -18,11 +18,15 @@ def polynom_factory(func): @wraps(func) def wrapper(*args, **kwrds): P = func(*args, **kwrds) - if isinstance(P,Polynom) and P.degree == 2: + if issubclass(type(P),AbstractPolynom) and P.degree == 2: from .polynomDeg2 import Polynom_deg2 new_P = Polynom_deg2(poly=P) new_P.steps = P.steps return new_P + elif issubclass(type(P),AbstractPolynom): + new_P = Polynom(poly=P) + new_P.steps = P.steps + return new_P else: return P return wrapper @@ -54,13 +58,15 @@ class Polynom(AbstractPolynom): /!\ variables need to be in brackets {} >>> Polynom.random(["{b}", "{a}"]) # doctest:+ELLIPSIS - < Polynom ... + < ... >>> Polynom.random(degree = 2) # doctest:+ELLIPSIS - < Polynom ... + < ... + >>> Polynom.random(degree = 3) # doctest:+ELLIPSIS + < ... >>> Polynom.random(degree = 2, conditions=["{b**2-4*a*c}>0"]) # Polynom deg 2 with positive Delta (ax^2 + bx + c) - < Polynom ... + < ... >>> Polynom.random(["{c}", "{b}", "{a}"], conditions=["{b**2-4*a*c}>0"]) # Same as above - < Polynom ... + < ... """ if (degree > 0 and degree < 26): @@ -76,7 +82,7 @@ class Polynom(AbstractPolynom): # Création du polynom return Polynom(coefs = coefs, letter = letter, name = name) - def __init__(self, coefs = [1], letter = "x", name = "P"): + def __init__(self, coefs = [1], letter = "x", name = "P", poly = 0): """Initiate the polynom :param coef: coefficients of the polynom (ascending degree sorted) @@ -105,6 +111,11 @@ class Polynom(AbstractPolynom): >>> Polynom([1, 2, 3], name = "Q").name 'Q' """ + if poly: + coefs = poly._coef + letter = poly._letter + name = poly.name + super(Polynom, self).__init__(coefs, letter, name) def __call__(self, value): @@ -140,7 +151,7 @@ class Polynom(AbstractPolynom): >>> P = Polynom([1, 2, 3]) >>> Q = P.derivate() >>> Q - < Polynom [2, 6]> + < [2, 6]> >>> print(Q.name) P' >>> for i in Q.explain(): diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index de88570..80a1ce4 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -5,6 +5,7 @@ from .polynom import Polynom from .expression import Expression from .operator import op from .random_expression import RdExpression + from math import sqrt __all__ = ["Polynom_deg2"] @@ -219,10 +220,6 @@ class Polynom_deg2(Polynom): return "\\tkzTabVar{-/{}, +/{$" + str(beta) + "$}, -/{}}" - - - - if __name__ == '__main__': # from .render import txt # with Expression.tmp_render(txt): diff --git a/pymath/str2tokens.py b/pymath/str2tokens.py index 61c2eb0..9548b4a 100644 --- a/pymath/str2tokens.py +++ b/pymath/str2tokens.py @@ -12,7 +12,7 @@ def str2tokens(exp): >>> str2tokens('2*3+4') [2, 3, '*', 4, '+'] >>> str2tokens('2x+4') - [2, < Polynom [0, 1]>, '*', 4, '+'] + [2, < [0, 1]>, '*', 4, '+'] """ in_tokens = str2in_tokens(exp) post_tokens = in2post_fix(in_tokens) From 8ffdfbdcaf0f0e1018e39243fdd5fbe5b9a61bba Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 08:55:05 +0200 Subject: [PATCH 17/40] lastbug with facto? --- pymath/abstract_polynom.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pymath/abstract_polynom.py b/pymath/abstract_polynom.py index f434983..9eb8894 100644 --- a/pymath/abstract_polynom.py +++ b/pymath/abstract_polynom.py @@ -65,6 +65,9 @@ class AbstractPolynom(Explicable): except IndexError: pass + if coefs == []: + coefs = [0] + self.feed_coef(coefs) self._letter = letter self.name = name From f5df2b6e9d959a51c78efd2450c47be06a21e4b3 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 09:51:12 +0200 Subject: [PATCH 18/40] use sympy to compute root of polynomDeg2 --- pymath/polynomDeg2.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index 80a1ce4..bb27cb3 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -3,10 +3,12 @@ from .polynom import Polynom from .expression import Expression +from .fraction import Fraction from .operator import op from .random_expression import RdExpression -from math import sqrt +from sympy import sqrt, latex +#from sympy.fractions import Fraction as sp.Fraction __all__ = ["Polynom_deg2"] @@ -125,7 +127,8 @@ class Polynom_deg2(Polynom): def roots(self, after_coma = 2): """ Compute roots of the polynom - /!\ Can't manage exact solution because of pymath does not handle sqare root yet + /!\ Can't manage nice rendering because of sqrt. + It use sympy to compute roots # TODO: Pymath has to know how to compute with sqare root |mar. févr. 24 18:40:04 CET 2015 @@ -134,16 +137,18 @@ class Polynom_deg2(Polynom): [] >>> P = Polynom_deg2([1, 2, 1]) >>> P.roots() - [-1.0] + [-1] >>> P = Polynom_deg2([-1, 0, 1]) >>> P.roots() - [-1.0, 1.0] + ['-1', '1'] + >>> P = Polynom_deg2([1, 4, 1]) + >>> P.roots() + ['-2 - \\\\sqrt{3}', '-2 + \\\\sqrt{3}'] """ - # TODO: Use sympy to compute those |mar. avril 7 07:31:42 CEST 2015 if self.delta > 0: - self._roots = [round((-self.b - sqrt(self.delta))/(2*self.a),after_coma), round((-self.b + sqrt(self.delta))/(2*self.a),after_coma)] + self._roots = [latex((-self.b - sqrt(self.delta))/(2*self.a)), latex((-self.b + sqrt(self.delta))/(2*self.a))] elif self.delta == 0: - self._roots = [round(-self.b /(2*self.a), after_coma)] + self._roots = [Fraction(-self.b,2*self.a).simplify()] else: self._roots = [] return self._roots From a543602d26bbc4f7675ed3576ff692e3255ec3cc Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 17 Apr 2015 16:38:16 +0200 Subject: [PATCH 19/40] remove space in new_s==old_s if they are sting for explicable --- pymath/explicable.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pymath/explicable.py b/pymath/explicable.py index 1db3b83..d764132 100644 --- a/pymath/explicable.py +++ b/pymath/explicable.py @@ -87,7 +87,7 @@ class Explicable(Renderable): new_s = self.STR_RENDER(s.postfix_tokens) else: new_s = self.STR_RENDER(s) - if new_s != old_s: + if not self.is_same_step(new_s, old_s): old_s = new_s yield new_s except AttributeError: @@ -96,8 +96,23 @@ class Explicable(Renderable): if noself: # Lui même new_s = self.STR_RENDER(self.postfix_tokens) - if new_s != old_s: + if not self.is_same_step(new_s, old_s): yield new_s + + def is_same_step(self, new, old): + """Return whether the new step is the same than old step + """ + try: + if new.replace(" ", "") == old.replace(" ", ""): + return True + else: + return False + except AttributeError: + if new == old: + return True + else: + return False + From e0ba4c09a9791ad00cce320219e84a92456bf1c7 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 20 Apr 2015 21:20:29 +0200 Subject: [PATCH 20/40] spelling and sense --- docs/construction.mdwn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/construction.mdwn b/docs/construction.mdwn index c5269ab..d713754 100644 --- a/docs/construction.mdwn +++ b/docs/construction.mdwn @@ -45,14 +45,14 @@ Dans cette partie, on va expliquer le fonctionnement des mécanismes de simplifi La simplification des expressions se fait avec les deux méthodes suivantes: * *simplify()* pour: - * un polynôme permet d'accéder à la forme canonique d'un polynôme + * un polynôme permet d'accéder à la forme developpée d'un polynôme * une fraction permet d'avoir la fraction irréductible associée * une expression permet de faire tous les calculs possibles de cette expression (à la fin il ne doit y avoir qu'un élément de la liste de tokens) * *compute_exp()* pour: * un polynôme ou une fraction fait la même chose que $simplify$. * une expression fait tous les calculs élémentaires de cette expression. -Ces deux méthodes fonctionnent ensuite sur le même principe. Elles vont faire le calcul qui leurs est attribuée en enregistrant les étapes dans *steps* puis elles retourneront l'objet de fin de calcul à qui sera assigné les *steps* (ce qui nécessitera par exemple de détourner la classe *int*). +Ces deux méthodes fonctionnent ensuite sur le même principe. Elles vont faire le calcul qui leurs est attribué en enregistrant les étapes dans *steps* puis elles retourneront l'objet de fin de calcul à qui sera assigné les *steps* (ce qui nécessitera par exemple de détourner la classe *int*). Pour accéder à ces étapes, on utilisera alors la méthode *explain* qui expliqueront les étapes intermédiaires. From 9d7f43bb209107e7fe55f456f2f05e47fb44eebd Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 20 Apr 2015 21:21:19 +0200 Subject: [PATCH 21/40] try to find the bug... --- pymath/expression.py | 179 ++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 106 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index 79e4f06..e027dcb 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -11,10 +11,10 @@ from .random_expression import RdExpression __all__ = ['Expression'] + class Expression(Explicable): """A calculus expression. Today it can andle only expression with numbers later it will be able to manipulate unknown""" - @classmethod def random(self, form="", conditions=[], val_min = -10, val_max=10): """Create a random expression from form and with conditions @@ -86,7 +86,8 @@ class Expression(Explicable): if len(expression.postfix_tokens) == 1: token = expression.postfix_tokens[0] if hasattr(token, 'simplify') and hasattr(token, 'explain'): - return expression.postfix_tokens[0] + ans = expression.postfix_tokens[0] + return ans elif type(token) == int: # On crée un faux int en ajoutant la méthode simplify et simplified et la caractérisique isNumber @@ -124,14 +125,27 @@ class Expression(Explicable): def simplify(self): """ Compute entirely the expression and return the result with .steps attribute """ + #from .render import txt + #with Expression.tmp_render(txt): + # print("self -> ", self, " --> ", len(self.steps)) + self.compute_exp() + #with Expression.tmp_render(txt): + # print("|-> self.child -> ", self.child, " --> ", len(self.child.steps)) + self.simplified = self.child.simplify() - if self.simplified != self.child: - try: - self.simplified.steps = self.child.steps + self.simplified.steps - except AttributeError: - pass + #print('|-- len(self.simplified.steps)=', len(self.child.steps) , " + ", len(self.simplified.steps)) + self.simplified.steps = self.child.steps + self.simplified.steps + #if self.simplified != self.child: + # try: + # self.simplified.steps = self.child.steps + self.simplified.steps + # except AttributeError as e: + # #print(e) + # pass + + #with Expression.tmp_render(txt): + # print("End self.simplified -> ", self.simplified, " --> ", len(self.simplified.steps)) return self.simplified def compute_exp(self): @@ -193,26 +207,53 @@ class Expression(Explicable): tmpTokenList += tokenList self.child = Expression(tmpTokenList) + + #from .render import txt + #with Expression.tmp_render(txt): + # print('------------') + # print("self -> ", self) + # print("self.child -> ", self.child) + # print("self.child.steps -> ", [str(i) for i in self.child.steps], ' -- ', len(self.child.steps)) + + steps = self.develop_steps(tmpTokenList) + #with Expression.tmp_render(txt): + # print('************') + # print("steps -> ", [str(i) for i in steps], ' -- ', len(steps)) + # print('************') + + #if steps !=[] and ini_step != steps[0]: + # self.child.steps = [ini_step] + steps + #else: + # self.child.steps = steps + if self.child.postfix_tokens == ini_step.postfix_tokens: - self.child.steps = self.develop_steps(tmpTokenList) + self.child.steps = steps else: - self.child.steps = [ini_step] + self.develop_steps(tmpTokenList) + self.child.steps = [ini_step] + steps + #with Expression.tmp_render(txt): + # print('++++') + # print("self.child.steps -> ", [str(i) for i in self.child.steps], ' -- ', len(self.child.steps)) def develop_steps(self, tokenList): """ From a list of tokens, it develops steps of each tokens """ + # TODO: Attention les étapes sont dans le mauvais sens |lun. avril 20 10:06:03 CEST 2015 + print("---- develop_steps ------") + print("tokenList -> ", tokenList) tmp_steps = [] with Expression.tmp_render(): for t in tokenList: if hasattr(t, "explain"): tmp_steps.append([i for i in t.explain()]) else: - tmp_steps.append(t) - if max([len(i) if type(i) == list else 1 for i in tmp_steps]) == 1: + tmp_steps.append([t]) + print("tmp_steps -> ", tmp_steps) + if max([len(i) for i in tmp_steps]) == 1: # Cas où rien n'a dû être expliqué. return [] else: tmp_steps = expand_list(tmp_steps)[:-1] steps = [Expression(s) for s in tmp_steps] + print("steps -> ", steps) return steps @classmethod @@ -347,105 +388,31 @@ def untest(exp): print("\n") if __name__ == '__main__': - #render = lambda _,x : str(x) - #Expression.set_render(render) - #exp = Expression("1/2 - 4") - #print(list(exp.simplify())) - - #Expression.set_render(txt) - #exp = "2 ^ 3 * 5" - #untest(exp) - - #exp = "2x + 5" - #untest(exp) - - #Expression.set_render(tex) - - #untest(exp1) - - #from pymath.operator import op - #exp = [2, 3, op.pw, 5, op.mul] - #untest(exp) - - #untest([Expression(exp1), Expression(exp), op.add]) - - #exp = "1 + 3 * 5" - #e = Expression(exp) - #f = -e - #print(f) - - #exp = "2 * 3 * 3 * 5" - #untest(exp) - - #exp = "2 * 3 + 3 * 5" - #untest(exp) - - #exp = "2 * ( 3 + 4 ) + 3 * 5" - #untest(exp) - - #exp = "2 * ( 3 + 4 ) + ( 3 - 4 ) * 5" - #untest(exp) - # - #exp = "2 * ( 2 - ( 3 + 4 ) ) + ( 3 - 4 ) * 5" - #untest(exp) - # - #exp = "2 * ( 2 - ( 3 + 4 ) ) + 5 * ( 3 - 4 )" - #untest(exp) - # - #exp = "2 + 5 * ( 3 - 4 )" - #untest(exp) - - #exp = "( 2 + 5 ) * ( 3 - 4 )^4" - #untest(exp) - - #exp = "( 2 + 5 ) * ( 3 * 4 )" - #untest(exp) - - #exp = "( 2 + 5 - 1 ) / ( 3 * 4 )" - #untest(exp) - - #exp = "( 2 + 5 ) / ( 3 * 4 ) + 1 / 12" - #untest(exp) - - #exp = "( 2+ 5 )/( 3 * 4 ) + 1 / 2" - #untest(exp) - - #exp="(-2+5)/(3*4)+1/12+5*5" - #untest(exp) - - #exp="-2*4(12 + 1)(3-12)" - #untest(exp) - - - #exp="(-2+5)/(3*4)+1/12+5*5" - #untest(exp) - - # TODO: The next one doesn't work |ven. janv. 17 14:56:58 CET 2014 - #exp="-2*(-a)(12 + 1)(3-12)" - #e = Expression(exp) - #print(e) - - ## Can't handle it yet!! - #exp="-(-2)" - #untest(exp) - - #print("\n") - #exp = Expression.random("({a} + 3)({b} - 1)", ["{a} > 4"]) - #for i in exp.simplify(): + #print('\n') + #A = Expression.random("( -8 x + 8 ) ( -8 - ( -6 x ) )") + #Ar = A.simplify() + #print("Ar.steps -> ", Ar.steps) + #for i in Ar.steps: + # print(i) + #print("------------") + #for i in Ar.explain(): # print(i) - from .fraction import Fraction - f1 = Fraction(3,5) - f2 = Fraction(5,10) - q = f1+f2 - print("---------") - print(q.steps) - print("---------") - - for i in q.explain(): - print(i) + #print(type(Ar)) + print('\n-----------') + A = Expression.random("2 / 3 + 4 / 5") + Ar = A.simplify() + #print("Ar.steps -> ", Ar.steps) + #for i in Ar.steps: + # print(i) + #print("------------") + #for i in Ar.explain(): + # print(i) + + #print(type(Ar)) + #import doctest #doctest.testmod() From f81f2b47cebc68bb56277365c494ce9440428c87 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 08:36:36 +0200 Subject: [PATCH 22/40] debug decorator --- debug/tools.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 debug/tools.py diff --git a/debug/tools.py b/debug/tools.py new file mode 100644 index 0000000..6b7ef2a --- /dev/null +++ b/debug/tools.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# encoding: utf-8 + +__report_indent = [0] +def report(fn): + """Decorator to print information about a function + call for use while debugging. + Prints function name, arguments, and call number + when the function is called. Prints this information + again along with the return value when the function + returns. + """ + + def wrap(*params,**kwargs): + call = wrap.callcount = wrap.callcount + 1 + + indent = ' ' * __report_indent[0] + fc = "%s(%s)" % (fn.__name__, ', '.join( + [a.__repr__() for a in params] + + ["%s = %s" % (a, repr(b)) for a,b in kwargs.items()] + )) + + print( "Call %s%s called [#%s]" + % (indent, fc, call)) + __report_indent[0] += 1 + ret = fn(*params,**kwargs) + __report_indent[0] -= 1 + try: + print(' '*(__report_indent[0]+4), "ret.steps -> ", len(ret.steps)) + except AttributeError: + print(' '*(__report_indent[0]+4), ret, " has no steps") + print( "End %s%s returned %s [#%s]" + % (indent, fc, repr(ret), call)) + + return ret + wrap.callcount = 0 + return wrap + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del From d95b520ba09b8a00ea091f153107b8f3f9077b30 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 08:37:25 +0200 Subject: [PATCH 23/40] I feel like I have solve the bug! Need to adapt doctest and tests now --- pymath/expression.py | 54 +++++--------------------------------------- pymath/fraction.py | 3 ++- 2 files changed, 8 insertions(+), 49 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index e027dcb..ab85243 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -10,8 +10,6 @@ from .random_expression import RdExpression __all__ = ['Expression'] - - class Expression(Explicable): """A calculus expression. Today it can andle only expression with numbers later it will be able to manipulate unknown""" @@ -125,27 +123,10 @@ class Expression(Explicable): def simplify(self): """ Compute entirely the expression and return the result with .steps attribute """ - #from .render import txt - #with Expression.tmp_render(txt): - # print("self -> ", self, " --> ", len(self.steps)) - self.compute_exp() - #with Expression.tmp_render(txt): - # print("|-> self.child -> ", self.child, " --> ", len(self.child.steps)) - self.simplified = self.child.simplify() - #print('|-- len(self.simplified.steps)=', len(self.child.steps) , " + ", len(self.simplified.steps)) self.simplified.steps = self.child.steps + self.simplified.steps - #if self.simplified != self.child: - # try: - # self.simplified.steps = self.child.steps + self.simplified.steps - # except AttributeError as e: - # #print(e) - # pass - - #with Expression.tmp_render(txt): - # print("End self.simplified -> ", self.simplified, " --> ", len(self.simplified.steps)) return self.simplified def compute_exp(self): @@ -208,37 +189,16 @@ class Expression(Explicable): tmpTokenList += tokenList self.child = Expression(tmpTokenList) - #from .render import txt - #with Expression.tmp_render(txt): - # print('------------') - # print("self -> ", self) - # print("self.child -> ", self.child) - # print("self.child.steps -> ", [str(i) for i in self.child.steps], ' -- ', len(self.child.steps)) - steps = self.develop_steps(tmpTokenList) - #with Expression.tmp_render(txt): - # print('************') - # print("steps -> ", [str(i) for i in steps], ' -- ', len(steps)) - # print('************') - - #if steps !=[] and ini_step != steps[0]: - # self.child.steps = [ini_step] + steps - #else: - # self.child.steps = steps if self.child.postfix_tokens == ini_step.postfix_tokens: self.child.steps = steps else: self.child.steps = [ini_step] + steps - #with Expression.tmp_render(txt): - # print('++++') - # print("self.child.steps -> ", [str(i) for i in self.child.steps], ' -- ', len(self.child.steps)) def develop_steps(self, tokenList): """ From a list of tokens, it develops steps of each tokens """ # TODO: Attention les étapes sont dans le mauvais sens |lun. avril 20 10:06:03 CEST 2015 - print("---- develop_steps ------") - print("tokenList -> ", tokenList) tmp_steps = [] with Expression.tmp_render(): for t in tokenList: @@ -246,14 +206,12 @@ class Expression(Explicable): tmp_steps.append([i for i in t.explain()]) else: tmp_steps.append([t]) - print("tmp_steps -> ", tmp_steps) if max([len(i) for i in tmp_steps]) == 1: # Cas où rien n'a dû être expliqué. return [] else: tmp_steps = expand_list(tmp_steps)[:-1] steps = [Expression(s) for s in tmp_steps] - print("steps -> ", steps) return steps @classmethod @@ -389,11 +347,11 @@ def untest(exp): if __name__ == '__main__': #print('\n') - #A = Expression.random("( -8 x + 8 ) ( -8 - ( -6 x ) )") - #Ar = A.simplify() + A = Expression.random("( -8 x + 8 ) ( -8 - ( -6 x ) )") + Ar = A.simplify() #print("Ar.steps -> ", Ar.steps) - #for i in Ar.steps: - # print(i) + for i in Ar.steps: + print(i) #print("------------") #for i in Ar.explain(): # print(i) @@ -408,8 +366,8 @@ if __name__ == '__main__': #for i in Ar.steps: # print(i) #print("------------") - #for i in Ar.explain(): - # print(i) + for i in Ar.explain(): + print(i) #print(type(Ar)) diff --git a/pymath/fraction.py b/pymath/fraction.py index 63ddac7..9369c64 100644 --- a/pymath/fraction.py +++ b/pymath/fraction.py @@ -78,7 +78,7 @@ class Fraction(Explicable): return n_frac else: - return self + return copy(self) @property def postfix_tokens(self): @@ -188,6 +188,7 @@ class Fraction(Explicable): ans = exp.simplify() ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.add]) ans.steps = [ini_step] + ans.steps + #print("\t\tIn add ans.steps -> ", ans.steps) return ans def __radd__(self, other): From 00c327a52fe8f2f59f8d0fccde41aa29802637db Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 17:31:23 +0200 Subject: [PATCH 24/40] solve bug with double simplifyon beta --- pymath/polynomDeg2.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pymath/polynomDeg2.py b/pymath/polynomDeg2.py index bb27cb3..1f76e1d 100644 --- a/pymath/polynomDeg2.py +++ b/pymath/polynomDeg2.py @@ -122,7 +122,7 @@ class Polynom_deg2(Polynom): \\frac{ -1 + 3 }{ 3 } \\frac{ 2 }{ 3 } """ - return self(self.alpha).simplify() + return self(self.alpha) def roots(self, after_coma = 2): """ Compute roots of the polynom @@ -226,14 +226,17 @@ class Polynom_deg2(Polynom): if __name__ == '__main__': - # from .render import txt - # with Expression.tmp_render(txt): - # P = Polynom_deg2([2, 3, 4]) - # print(P) + #from .render import txt + #with Expression.tmp_render(txt): + # P = Polynom_deg2([2, 3, 4]) + # print(P) - # print("Delta") - # for i in P.delta.simplify(): - # print(i) + # print("\nDelta") + # for i in P.delta.explain(): + # print(i) + # print("\nBeta") + # for i in P.beta.explain(): + # print(i) import doctest doctest.testmod() From 7987f3f1be92ba22b532618f208824b00052a934 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 17:31:56 +0200 Subject: [PATCH 25/40] add debug tool --- pymath/expression.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index ab85243..5d1e8d7 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # encoding: utf-8 +#debuging +#from debug.tools import report + from .generic import Stack, flatten_list, expand_list, isNumber, isOperator, isNumerand from .str2tokens import str2tokens from .operator import op @@ -347,10 +350,10 @@ def untest(exp): if __name__ == '__main__': #print('\n') - A = Expression.random("( -8 x + 8 ) ( -8 - ( -6 x ) )") + A = Expression("( -8 x + 8 ) ( -8 - ( -6 x ) )") Ar = A.simplify() #print("Ar.steps -> ", Ar.steps) - for i in Ar.steps: + for i in Ar.explain(): print(i) #print("------------") #for i in Ar.explain(): @@ -360,7 +363,7 @@ if __name__ == '__main__': print('\n-----------') - A = Expression.random("2 / 3 + 4 / 5") + A = Expression("2 / 3 + 4 / 5") Ar = A.simplify() #print("Ar.steps -> ", Ar.steps) #for i in Ar.steps: From 64d5bed8fe9eed9d1d96b117e88a0421aac692ce Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 18:10:14 +0200 Subject: [PATCH 26/40] All tests pass :D --- pymath/abstract_polynom.py | 13 +++++++++++++ pymath/explicable.py | 12 ++++++++++++ pymath/expression.py | 22 +++++++++++----------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pymath/abstract_polynom.py b/pymath/abstract_polynom.py index 9eb8894..bc2fcf6 100644 --- a/pymath/abstract_polynom.py +++ b/pymath/abstract_polynom.py @@ -307,6 +307,11 @@ class AbstractPolynom(Explicable): >>> Q = P.reduce() >>> Q < [3, 12, 6]> + >>> for i in Q.explain(): + ... print(i) + 6 x^{ 2 } + ( 3 + 4 + 5 ) x + 1 + 2 + 6 x^{ 2 } + ( 7 + 5 ) x + 3 + 6 x^{ 2 } + 12 x + 3 >>> Q.steps [< [< [1, 2, '+'] >, < [3, 4, '+', 5, '+'] >, 6]>, < [3, < [7, 5, '+'] >, 6]>] """ @@ -580,6 +585,14 @@ class AbstractPolynom(Explicable): def __xor__(self, power): return self.__pow__(power) +if __name__ == '__main__': + P = AbstractPolynom([[1,2],[3,4,5],6]) + Q = P.reduce() + for i in Q.explain(): + print(i) + + #import doctest + #doctest.testmod() # ----------------------------- diff --git a/pymath/explicable.py b/pymath/explicable.py index d764132..fb91efd 100644 --- a/pymath/explicable.py +++ b/pymath/explicable.py @@ -4,6 +4,9 @@ from .render import txt, tex class Renderable(object): + """ + A Renderable object is an object which can work with Render class. It means that it has to have attribute postfix_tokens. + """ STR_RENDER = tex DEFAULT_RENDER = tex @@ -60,6 +63,15 @@ class Renderable(object): def __exit__(self, type, value, traceback): Renderable.set_render(self.old_render) return TmpRenderEnv() + + def __eq__(self, other): + """ Two Renderable objects are the same if they have same postfix_tokens """ + try: + return self.postfix_tokens == other.postfix_tokens + except AttributeError: + return False + + class Explicable(Renderable): diff --git a/pymath/expression.py b/pymath/expression.py index 5d1e8d7..c44c2a1 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -350,11 +350,11 @@ def untest(exp): if __name__ == '__main__': #print('\n') - A = Expression("( -8 x + 8 ) ( -8 - ( -6 x ) )") - Ar = A.simplify() + #A = Expression("( -8 x + 8 ) ( -8 - ( -6 x ) )") + #Ar = A.simplify() #print("Ar.steps -> ", Ar.steps) - for i in Ar.explain(): - print(i) + #for i in Ar.explain(): + # print(i) #print("------------") #for i in Ar.explain(): # print(i) @@ -362,20 +362,20 @@ if __name__ == '__main__': #print(type(Ar)) - print('\n-----------') - A = Expression("2 / 3 + 4 / 5") - Ar = A.simplify() + #print('\n-----------') + #A = Expression("2 / 3 + 4 / 5") + #Ar = A.simplify() #print("Ar.steps -> ", Ar.steps) #for i in Ar.steps: # print(i) #print("------------") - for i in Ar.explain(): - print(i) + #for i in Ar.explain(): + # print(i) #print(type(Ar)) - #import doctest - #doctest.testmod() + import doctest + doctest.testmod() # ----------------------------- # Reglages pour 'vim' From 3664a2e13558b6b5cc6980e8f67ac3c35c83feb1 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 19:48:05 +0200 Subject: [PATCH 27/40] implement Fake_int to solve bug with explain --- pymath/expression.py | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index c44c2a1..a53100d 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -13,6 +13,17 @@ from .random_expression import RdExpression __all__ = ['Expression'] +class Fake_int(int, Explicable): + isNumber = True + def __init__(self, val): + super(Fake_int, self).__init__(val) + self._val = val + self.postfix_tokens = [self] + self.steps = [] + def simplify(self): + return Fake_int(self._val) + + class Expression(Explicable): """A calculus expression. Today it can andle only expression with numbers later it will be able to manipulate unknown""" @@ -86,17 +97,19 @@ class Expression(Explicable): if len(expression.postfix_tokens) == 1: token = expression.postfix_tokens[0] - if hasattr(token, 'simplify') and hasattr(token, 'explain'): + if type(token) == Fake_int or type(token) == int: + return Fake_int(token) + elif hasattr(token, 'simplify') and hasattr(token, 'explain'): ans = expression.postfix_tokens[0] return ans - elif type(token) == int: - # On crée un faux int en ajoutant la méthode simplify et simplified et la caractérisique isNumber - simplify = lambda x:x - is_number = True - methods_attr = {'simplify':simplify, 'isNumber': is_number, 'postfix_tokens': [token]} - fake_token = type('fake_int', (int,Explicable, ), methods_attr)(token) - return fake_token + #elif type(token) == int: + ## On crée un faux int en ajoutant la méthode simplify et simplified et la caractérisique isNumber + # #simplify = lambda x:int(x) + # #is_number = True + # #methods_attr = {'simplify':simplify, 'isNumber': is_number, 'postfix_tokens': [token], 'steps':[]} + # #fake_token = type('fake_int', (int,Explicable, ), methods_attr)(token) + # return Fake_int(token) elif type(token) == str: # TODO: Pourquoi ne pas créer directement un polynom ici? |jeu. févr. 26 18:59:24 CET 2015 @@ -349,12 +362,11 @@ def untest(exp): print("\n") if __name__ == '__main__': - #print('\n') - #A = Expression("( -8 x + 8 ) ( -8 - ( -6 x ) )") - #Ar = A.simplify() - #print("Ar.steps -> ", Ar.steps) - #for i in Ar.explain(): - # print(i) + print('\n') + A = Expression("( -8 x + 8 ) ( -8 - ( -6 x ) )") + Ar = A.simplify() + for i in Ar.explain(): + print(i) #print("------------") #for i in Ar.explain(): # print(i) @@ -363,19 +375,19 @@ if __name__ == '__main__': #print('\n-----------') - #A = Expression("2 / 3 + 4 / 5") + #A = Expression("-6 / 3 + 10 / -5") #Ar = A.simplify() - #print("Ar.steps -> ", Ar.steps) - #for i in Ar.steps: - # print(i) - #print("------------") #for i in Ar.explain(): # print(i) - #print(type(Ar)) + #print('\n-----------') + #A = Expression("1/3 + 4/6") + #Ar = A.simplify() + #for i in Ar.explain(): + # print(i) - import doctest - doctest.testmod() + #import doctest + #doctest.testmod() # ----------------------------- # Reglages pour 'vim' From 0b89bb1bbf9ce5ae25a8dcc3ce80d4fe87931a54 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 19:48:37 +0200 Subject: [PATCH 28/40] forgot to save... --- pymath/expression.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index a53100d..4ec22ea 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -103,14 +103,6 @@ class Expression(Explicable): ans = expression.postfix_tokens[0] return ans - #elif type(token) == int: - ## On crée un faux int en ajoutant la méthode simplify et simplified et la caractérisique isNumber - # #simplify = lambda x:int(x) - # #is_number = True - # #methods_attr = {'simplify':simplify, 'isNumber': is_number, 'postfix_tokens': [token], 'steps':[]} - # #fake_token = type('fake_int', (int,Explicable, ), methods_attr)(token) - # return Fake_int(token) - elif type(token) == str: # TODO: Pourquoi ne pas créer directement un polynom ici? |jeu. févr. 26 18:59:24 CET 2015 # On crée un faux str en ajoutant la méthode simplify et simplified et la caractérisique isNumber From 715c3a265b50687f3892dce9ef4f55a5d9c2dd47 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:13:11 +0200 Subject: [PATCH 29/40] update setup.py and add install_requiers --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f084faf..3932d87 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,10 @@ from distutils.core import setup setup(name='pyMath', - version='0.2', + version='1.0', description='Computing like a student', author='Benjamin Bertrand', author_email='lafrite@poneyworld.net', packages=['pymath'], + install_requiers=['pyparsing', 'sympy'], ) From 950203b5b9d3acea0045c1e88f34ce9ce628929e Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:28:21 +0200 Subject: [PATCH 30/40] some cleaning --- TODO | 2 +- notes | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 notes diff --git a/TODO b/TODO index 65e881d..1925e20 100644 --- a/TODO +++ b/TODO @@ -5,7 +5,7 @@ * bug: expression can't handle -(-2) * Overload + - * for expression (DONE ~ no steps yet) * Expression should be able to simplify expression with ":" -* Add name to polynom +* Add name to polynom (DONE) * Expression parents class and his children: Numerical_exp, toGenerate_exp and formal expression * Create tbl sgn and variation render diff --git a/notes b/notes deleted file mode 100644 index 0b2254b..0000000 --- a/notes +++ /dev/null @@ -1,6 +0,0 @@ -Soucis: - -> Travailler avec des strings c'est nul faut que ça change. - -> Les prints c'est encore plus moche il faut encore plus que ça change - -Idées farfelues: - -> Surcharger le __truediv__ des entiers pour creer des fractions ça rendra la chose plus belle et plus simple à utiliser. From 3ec1ed819a7570333480c9cdf7d88795d18c2a97 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:42:04 +0200 Subject: [PATCH 31/40] easier import --- docs/tutorial.mdwn | 28 ++++++++++++++-------------- pymath/__init__.py | 13 +++++++++++++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/tutorial.mdwn b/docs/tutorial.mdwn index 1ed1ae4..6b3ca30 100644 --- a/docs/tutorial.mdwn +++ b/docs/tutorial.mdwn @@ -6,7 +6,7 @@ pyMath est un module python qui permet la manipulation d'expressions mathématiq * *Calculer comme un collégien*: Pour faire de la correction automatisé d'exercice, un logiciel de calcul formel ne suffit pas. Si les étapes de calculs ne sont pas présentes, l'élève ne pourra pas analyser ses erreurs ou s'inspirer de la correction. - >>> from pymath.expression import Expression + >>> from pymath import Expression >>> ajout_fractions = Expression("2 / 5 + 2 / 3") >>> resultat = ajout_fractions.simplify() >>> print(resultat) @@ -21,25 +21,25 @@ pyMath est un module python qui permet la manipulation d'expressions mathématiq * *Créer des exercices aléatoirement*: Pour faire des devoirs personnels, des fiches de révisions ou des exercices en classe, un générateur d'expressions est inclus. - >>> from pymath.expression import Expression + >>> from pymath import Expression >>> ajout_fraction = Expression.random("{a} + {b} / {c}") >>> print(ajout_fraction) 5 + \frac{ -7 }{ 4 } * *Gérer différents type de données*: Pour le moment, pyMath est capable de gérer les entiers naturels, les rationnels (sous forme de fractions) et les polynômes. L'utilisation des nombres à virgules et des racines devraient être ajoutés dans les prochaines versions. - >>> from pymath.fraction import Fraction + >>> from pymath import Fraction >>> une_fraction = Fraction(1,2) >>> print(une_fraction) 1 / 2 - >>> from pymath.polynom import Polynom + >>> from pymath import Polynom >>> un_polynom = Polynom([1,2,3]) >>> print(un_polynom) 3 x^{ 2 } + 2 x + 1 * *Afficher avec deux types de rendus*: Un en mode texte pour l'affichage dans une console. Un deuxième spécialement pour écrire des documents latex. - >>> from pymath.expression import Expression + >>> from pymath import Expression >>> ajout_fractions = Expression("2 / 5 + 2 / 3") >>> for i in ajout_fractions.simpliy().explain(): ... print(i) @@ -47,7 +47,7 @@ pyMath est un module python qui permet la manipulation d'expressions mathématiq \frac{ 2 \times 3 }{ 5 \times 3 } + \frac{ 2 \times 5 }{ 3 \times 5 } \frac{ 6 + 10 }{ 15 } \frac{ 16 }{ 15 } - >>> from pymath.render import txt + >>> from pymath import txt >>> with Expression.tmp_render(txt): ... for i in ajout_fractions.simpliy(): ... print(i) @@ -64,7 +64,7 @@ Ce module a pour but d'être un outil pour faciliter la construction d'exercices Actuellement le module principal pour faire calculer python comme un collégien est *pymath.expression*. - >>> from pymath.expression import Expression + >>> from pymath import Expression ### Déclarer une expression @@ -79,7 +79,7 @@ Un expression peut être initialisée de deux façons différentes: à partir d' Et si l'on souhaite un rendu plus adapté à la console: - >>> from pymath.render import txt + >>> from pymath import txt >>> Expression.set_render(txt) >>> un_calcul.render() 1 + 2 * 3 @@ -90,8 +90,8 @@ Et si l'on souhaite un rendu plus adapté à la console: Une fois les expressions créées, elles peuvent se réduire en expliquant les étapes et en respectant les règles de priorités. Ces étapes de calcul sont stockés dans l'objet résultat du calcul et sont accéssibles à travers la méthode *explain*. Les exemples suivants seront données avec un rendu texte. - >>> from pymath.expression import Expression - >>> from pymath.renders import txt + >>> from pymath import Expression + >>> from pymath import txt >>> Expression.set_render(txt) >>> exp = Expression("1 + 2 * 3") @@ -129,12 +129,12 @@ Les opérations autorisées sont les opérations "classique": + - * / ^. L'utili ### Type de variables et opérations On peut vouloir créer directement des objets (fractions ou polynômes) sans passer par le module expression (voir [fraction](fraction.mdwn) et [polynom](polynom.mdwn) pour plus de details) - >>> from pymath.fraction import Fraction + >>> from pymath import Fraction >>> fraction1 = Fraction(1,2) >>> fraction2 = Fraction(2,3) >>> print(fraction1) 1 / 2 - >>> from pymath.polynom import Polynom + >>> from pymath import Polynom >>> p = Polynom([1,2,3]) >>> print(p) 3 x ^ 2 + 2 x + 1 @@ -187,7 +187,7 @@ Pour changer le rendu, on import le rendu depuis *pymath.render* et on appelle l Voici un exemple d'utilisation du rendu txt - >>> from pymath.render import txt + >>> from pymath import txt >>> Expression.set_render(txt) >>> exp = Expression("1 + 2 / 5") >>> for i in exp.simplify().explain(): @@ -236,7 +236,7 @@ On peut vouloir ne pas passer par la classe Expression pour obtenir notre expres La fonction qui permet de faire cela est *random_str*: - >>> from pymath.random_expression import random_str + >>> from pymath import random_str >>> form = "{a} / {b} + {c} / {k*b}" >>> conditions = ["abs({b}) != 1", "{d} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{k*b}) == 1"] >>> str_addition_fraction = random_str(form, conditions) diff --git a/pymath/__init__.py b/pymath/__init__.py index e69de29..23d7af8 100644 --- a/pymath/__init__.py +++ b/pymath/__init__.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from .expression import Expression +from .polynom import Polynom +from .random_expression import random_str +from .render import txt,tex + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del From 331fb2211330ede4562c1b74160f457d7e78a83b Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 09:54:21 +0200 Subject: [PATCH 32/40] transform tutorial.md to tutorial.rst --- docs/tutorial.rst | 334 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 docs/tutorial.rst diff --git a/docs/tutorial.rst b/docs/tutorial.rst new file mode 100644 index 0000000..8655098 --- /dev/null +++ b/docs/tutorial.rst @@ -0,0 +1,334 @@ +Utilisation de pyMath +===================== + +À quoi sert pyMath? +------------------- + +pyMath est un module python qui permet la manipulation d'expressions +mathématiques. Voici ce qu'il est capable de faire: + +- *Calculer comme un collégien*: Pour faire de la correction automatisé + d'exercice, un logiciel de calcul formel ne suffit pas. Si les étapes + de calculs ne sont pas présentes, l'élève ne pourra pas analyser ses + erreurs ou s'inspirer de la correction. + + .. code-block:: python + >>> from pymath import Expression + >>> ajout_fractions = Expression("2 / 5 + 2 / 3") + >>> resultat = ajout_fractions.simplify() + >>> print(resultat) + \frac{ 16 }{ 15 } + >>> for i in resultat.explain(): + ... print(i) + ... + \frac{ 2 }{ 5 } + \frac{ 2 }{ 3 } + \frac{ 2 \times 3 }{ 5 \times 3 } + \frac{ 2 \times 5 }{ 3 \times 5 } + \frac{ 6 }{ 15 } + \frac{ 10 }{ 15 } + \frac{ 6 + 10 }{ 15 } + \frac{ 16 }{ 15 } + + +- *Créer des exercices aléatoirement*: Pour faire des devoirs + personnels, des fiches de révisions ou des exercices en classe, un + générateur d'expressions est inclus. + + .. code-block:: python + >>> from pymath import Expression + >>> ajout_fraction = Expression.random("{a} + {b} / {c}") + >>> print(ajout_fraction) + 2 + \frac{ 3 }{ 5 } + +- *Gérer différents type de données*: Pour le moment, pyMath est + capable de gérer les entiers naturels, les rationnels (sous forme de + fractions) et les polynômes. L'utilisation des nombres à virgules et + des racines devraient être ajoutés dans les prochaines versions. + + .. code-block:: python + >>> from pymath import Fraction + >>> une_fraction = Fraction(1,2) + >>> print(une_fraction) + 1 / 2 + >>> from pymath import Polynom + >>> un_polynom = Polynom([1,2,3]) + >>> print(un_polynom) + 3 x^{ 2 } + 2 x + 1 + +- *Afficher avec deux types de rendus*: Un en mode texte pour + l'affichage dans une console. Un deuxième spécialement pour écrire + des documents latex. + + .. code-block:: python + >>> from pymath import Expression + >>> ajout_fractions = Expression("2 / 5 + 2 / 3") + >>> for i in ajout_fractions.simpliy().explain(): + ... print(i) + ... + \frac{ 2 }{ 5 } + \frac{ 2 }{ 3 } + \frac{ 2 \times 3 }{ 5 \times 3 } + \frac{ 2 \times 5 }{ 3 \times 5 } + \frac{ 6 }{ 15 } + \frac{ 10 }{ 15 } + \frac{ 6 + 10 }{ 15 } + \frac{ 16 }{ 15 } + >>> from pymath import txt + >>> with Expression.tmp_render(txt): + ... for i in ajout_fractions.simpliy().explain(): + ... print(i) + ... + 2 / 5 + 2 / 3 + ( 2 * 3 ) / ( 5 * 3 ) + ( 2 * 5 ) / ( 3 * 5 ) + 6 / 15 + 10 / 15 + ( 6 + 10 ) / 15 + 16 / 15 + + +Ce module a pour but d'être un outil pour faciliter la construction +d'exercices et leurs correction. Il a pour but d'être le plus simple +possible d'utilisation afin que tout le monde avec un minimum de +connaissance en programmation puisse créer librement des exercices. + +Calculer comme un collégien. +---------------------------- + +Actuellement le module principal pour faire calculer python comme un +collégien est *pymath.expression*. + + .. code-block:: python + >>> from pymath import Expression + +Déclarer une expression +~~~~~~~~~~~~~~~~~~~~~~~ + +Un expression peut être initialisée de deux façons différentes: à partir +d'une chaine de caractères ou à partir de la liste des termes (en +postfix - cette méthode est essentiellement utilisée pour programmer les +modules, elle ne sera pas détaillée ici). + + .. code-block:: python + >>> un_calcul = Expression("1 + 2 * 3") + >>> print(un_calcul) + 1 + 2 \times 3 + >>> ajout_fractions = Expression("2 / 5 + 2 / 3") + >>> print(ajout_fractions) + \frac{ 2 }{ 5 } + \frac{ 2 }{ 3 } + +Et si l'on souhaite un rendu plus adapté à la console: + + .. code-block:: python + >>> from pymath import txt + >>> Expression.set_render(txt) + >>> print(un_calcul) + 1 + 2 * 3 + >>> print(ajout_fractions) + 2 / 5 + 2 / 3 + +Simplification des expressions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Une fois les expressions créées, elles peuvent se réduire en expliquant +les étapes et en respectant les règles de priorités. Ces étapes de +calcul sont stockés dans l'objet résultat du calcul et sont accéssibles +à travers la méthode *explain*. Les exemples suivants seront données +avec un rendu texte. + + .. code-block:: python + >>> from pymath import Expression + >>> from pymath import txt + >>> Expression.set_render(txt) + + >>> exp = Expression("1 + 2 * 3") + >>> exp_simplifiee = exp.simplify() + >>> print(exp_simplifiee) + 7 + >>> for i in exp_simplifiee.explain(): + ... print(i) + ... + 1 + 2 * 3 + 1 + 6 + 7 + + +Les opérations autorisées sont les opérations "classique": + - * / ^. +L'utilisation des parenthèses est aussi gérée. + + .. code-block:: python + >>> exp = Expression("1 + 2 / 5") + >>> for i in exp.simplify().explain(): + ... print(i) + ... + 1 + 2 / 5 + ( 1 * 5 ) / ( 1 * 5 ) + ( 2 * 1 ) / ( 5 * 1 ) + ( 5 + 2 ) / 5 + 7 / 5 + + >>> exp = Expression("(2 + 4)(3 - 4 * 2)") + >>> for i in exp.simplify().explain(): + ... print(i) + ... + ( 2 + 4 ) ( 3 - ( 4 * 2 ) ) + 6 * ( 3 - 8 ) + 6 * ( -5 ) + -30 + +Type de variables et opérations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On peut vouloir créer directement des objets (fractions ou polynômes) +sans passer par le module expression (voir `fraction `__ +et `polynom `__ pour plus de details) + + .. code-block:: python + >>> from pymath import Fraction + >>> fraction1 = Fraction(1,2) + >>> fraction2 = Fraction(2,3) + >>> print(fraction1) + 1 / 2 + >>> from pymath import Polynom + >>> p = Polynom([1,2,3]) + >>> print(p) + 3 x ^ 2 + 2 x + 1 + >>> q = Polynom([0,0,1]) + x ^ 2 + +On peut effectuer des opérations entre les Expressions. + + .. code-block:: python + >>> fraction_expression = Expression("2 / 3") + >>> autre_fraction_expression = Expression("4 / 9") + >>> print(fraction_expression + autre_fraction_expression) + 2 / 3 + 4 / 9 + +On remarque qu'un opération sur des expressions, ne fait pas de calculs. +Elle ne fait que "concaténer" les listes des tokens. + +À l'inverse, les opérations sur les fractions ou les polynômes renvoient +la liste des étapes jusqu'à leur forme simplifiée + + .. code-block:: python + >>> addition_fraction = fraction1 + fraction2 + >>> print(addition_fraction) + 7 / 6 + >>> for i in addition_fraction.explain(): + ... print(i) + ... + 1 * 3 / 2 * 3 + 2 * 2 / 3 * 2 + ( 3 + 4 ) / 6 + 7 / 6 + >>> r = p + q + >>> print(r) + 4 x ^ 2 + 2 x + 1 + >>> for i in r.explain(): + ... print(i) + ... + 3 x ^ 2 + x ^ 2 + 2 x + 1 + ( 3 + 1 ) x ^ 2 + 2 x + 1 + 4 x ^ 2 + 2 x + 1 + +Différents rendus +~~~~~~~~~~~~~~~~~ + +Comme dit dans l'introduction, il y a deux types de rendus: un rendu +texte (utilisé depuis le début) et un rendu latex. + +Voici un exemple de l'utilisation du rendu latex (par défaut). + + .. code-block:: python + >>> exp = Expression("1 + 2 / 5") + >>> for i in exp.simplify().explain(): + ... print(i) + ... + 1 + \frac{ 2 }{ 5 } + \frac{ 1 \times 5 }{ 1 \times 5 } + \frac{ 2 \times 1 }{ 5 \times 1 } + \frac{ 5 + 2 }{ 5 } + \frac{ 7 }{ 5 } + +Pour changer le rendu, on importe le rendu depuis *pymath.render* et on +appelle la méthode de classe d'Expression *set_render*. + +Voici un exemple d'utilisation du rendu txt + + .. code-block:: python + >>> from pymath import txt + >>> Expression.set_render(txt) + >>> exp = Expression("1 + 2 / 5") + >>> for i in exp.simplify().explain(): + ... print(i) + ... + 2 / 5 + 2 / 3 + 2 * 3 / 5 * 3 + 2 * 5 / 3 * 5 + ( 6 + 10 ) / 15 + 16 / 15 + +Générer des expressions aléatoirement. +-------------------------------------- + +Créer un expression +~~~~~~~~~~~~~~~~~~~ + +Pour créer une expression il faut au moins une chose: la forme de +l'expression. Toutes les lettres entre accolades seront remplacées par +des valeurs aléatoires (par défaut entre -10 et 10 et non nulles). + + .. code-block:: python + >>> form = "2* {a} + 3" + >>> expression_aleatoire = Expression.random(form) + >>> print(expression_aleatoire) + '2 \times 9 + 3' + >>> print(Expression.random(form,val_min = 30, val_max = 40)) + '2 \times 31 + 3' + +Créer une expression avec conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Parfois il peut être nécessaire d'imposer des conditions sur les +éléments à générer pour créer des exercices spécifiques. + + .. code-block:: python + >>> form = "{a} / {b} + {c} / {d}" + >>> conditions = ["abs({b}) != 1", "{d} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{d}) == 1"] + >>> addition_fraction_alea = Expression.random(form, conditions) + >>> print(addition_fraction_alea) + '\frac{ 4 }{ 5 } + \frac{ 9 }{ 7 }' + +La méthode pour créer les valeurs avec des conditions est la méthode par +rejet. Elle n'est pas très efficace et rien n'est encore prévu dans le +cas où aucune valeur n'est possible. + +Opérations avec les valeurs générées +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pour éviter de faire tourner la méthode par rejet trop longtemps, il est +possible de faire des calculs avec les valeurs générées. + + .. code-block:: python + >>> form = "{a} / {b} + {c} / {k*b}" + >>> conditions = ["abs({b}) != 1", "{k} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{k*b}) == 1"] + >>> random_frac_add_generator = RdExpression(form, conditions) + >>> print(random_frac_add_generator()) + \frac{ -9 }{ 7 } + \frac{ 1 }{ 28 } + +Rendu des expressions +~~~~~~~~~~~~~~~~~~~~~ + +On peut vouloir ne pas passer par la classe Expression pour obtenir +notre expression (si l'on veut utiliser la racine carré par exemple, ou +pour créer n'importe quoi qui ne fait pas intervenir d'expression). +Ainsi pymath ne gère plus le rendu de l'expression ni son calcul. + +La fonction qui permet de faire cela est *random_str*: + + .. code-block:: python + >>> from pymath import random_str + >>> form = "{a} / {b} + {c} / {k*b}" + >>> conditions = ["abs({b}) != 1", "{d} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{k*b}) == 1"] + >>> str_addition_fraction = random_str(form, conditions) + >>> type(str_addition_fraction) + str + >>> print(str_addition_fraction) + -2 / 5 + -8 / 35 + + >>> form = "A({a},{b}), B({2*a}, {3*b})" + >>> points_alea = random_str(form) + >>> points_alea + 'A(7,5), B(14, 15)' + +On remarque le défaut d'utiliser cette forme, le rendu est moins bien +fait (dans l'exemple, il n'y a pas de parenthèses autour du -8). From ac0be63a836fa142f528f9bea642ce495721d48f Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 10:04:56 +0200 Subject: [PATCH 33/40] transform construction.mdwn to construction.rst --- docs/construction.mdwn | 123 ----------------------------------------- docs/construction.rst | 96 ++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 123 deletions(-) delete mode 100644 docs/construction.mdwn create mode 100644 docs/construction.rst diff --git a/docs/construction.mdwn b/docs/construction.mdwn deleted file mode 100644 index d713754..0000000 --- a/docs/construction.mdwn +++ /dev/null @@ -1,123 +0,0 @@ -# Explication sur la logique des classes - -## Les types -Ce sont les objects que l'on s'autorise à manipuler dans les expressions. -Ces objets doivent pouvoir être afficher en *txt* ou en *tex* avec les méthodes - * *__txt__*: affichage en mode text - * *__tex__*: affichage pour une compilation latex - -### Operator -Cette classe regroupe les operateurs. Que l'on s'autorise à utiliser. On y accède à partir de deux caractérisiques le symbole et l'arité. - -Liste des attributs importants: - * arity: nombre d'opérande accepté - * priority: où se place l'opérateur dans la règles des priorités parmis les autres opérateurs - * isOperator: permet de vérifier que c'est bien un opérateur -Liste des méthodes importantes: - * *__call__*: Permet d'effectuer le calcul sur deux opérandes - * *__txt__*: affichage en mode text - * *__tex__*: affichage pour une compilation latex - -### Number -Tous les types de "nombres" que l'on va vouloir manipuler. On va essayer de rester le plus proche de la construction mathématiques de ces objets. - -Par défaut, on travaillera avec des anneaux ce qui permettra de construire ensuite le corps des fractions et l'anneau des polynomes (quitte à quotienter) associé. - -Pour définir ces anneaux, il faudra contre avoir les méthodes suivantes: - * *__add__* - * *__radd__* - ... - -#### Fractions - -#### Polynomes - -#### Quotient de polynomes (racines) - -## Expression - -## Render - -## Simplify-simplified / compute-child - -Dans cette partie, on va expliquer le fonctionnement des mécanismes de simplification des expressions/objets mathématiques. - -La simplification des expressions se fait avec les deux méthodes suivantes: - -* *simplify()* pour: - * un polynôme permet d'accéder à la forme developpée d'un polynôme - * une fraction permet d'avoir la fraction irréductible associée - * une expression permet de faire tous les calculs possibles de cette expression (à la fin il ne doit y avoir qu'un élément de la liste de tokens) -* *compute_exp()* pour: - * un polynôme ou une fraction fait la même chose que $simplify$. - * une expression fait tous les calculs élémentaires de cette expression. - -Ces deux méthodes fonctionnent ensuite sur le même principe. Elles vont faire le calcul qui leurs est attribué en enregistrant les étapes dans *steps* puis elles retourneront l'objet de fin de calcul à qui sera assigné les *steps* (ce qui nécessitera par exemple de détourner la classe *int*). - -Pour accéder à ces étapes, on utilisera alors la méthode *explain* qui expliqueront les étapes intermédiaires. - -### Tentative d'explications -C'est ce que je voudrai donc le render ne sera peut être pas exactement le même. - -Comportement avec les Polynom (ce serait similaire avec les fractions) - - >>> P = Polynom([0,1,2]) - >>> Q = Polynom([1,1,1]) - >>> R = P+Q - >>> print(R) - 3x^2 + 2x + 1 - >>> for i in R.explain(): - ... print(i) - 2x^2 + x + x^2 + x + 1 - (2 + 1)x^2 + (1+1)x + 1 - 3x^3 + 2x + 1 - - >>> P = Polynom([[1,2], [3,4]]) - >>> Q = P.simplify() - >>> print(Q) - 7x + 3 - >>> for i in Q.explain(): - ... print(i) - 3x + 4x + 1 + 2 - (3+4)x + (1+2) - 7x + 3 - -Comportement avec les expressions - - >>> e = Expression("1+2*3") - >>> e1 = e.compute_exp() - >>> e1 - 1 + 6 - >>> type(e1) - Expression - >>> for i in e1.explain(): # Peu interessant mais il aurai pu y avoir des calculs de fractions - ... print(i) - 1 + 2 * 3 - 1 + 6 - >>> e2 = e.simplify() - >>> e2 - 7 - >>> type(e2) - FakeInt - >>> for i in e2.explain(): - ... print(i) - 1 + 2 * 3 - 1 + 6 - 7 - >>> f = Expression("4 - 5") - >>> g = e + f - >>> g # Les deux expressions ont été concaténée mais aucun calcul n'a été fait - < Expression [1, 2, 3, '*', '+', 4, 5, '-', '+']> - >>> for i in g.explain(): - ... print(i) - 1 + 2 * 3 + 4 - 5 - >>> for i in g.simplify().explain(): - ... print(i) - 1 + 2 \times 3 + 4 - 5 - 1 + 6 + ( -1 ) - 7 + ( -1 ) - 6 - - - - diff --git a/docs/construction.rst b/docs/construction.rst new file mode 100644 index 0000000..9d944b7 --- /dev/null +++ b/docs/construction.rst @@ -0,0 +1,96 @@ +Explication sur la logique des classes +====================================== + +Les types +--------- + +Ce sont les objets que l'on s'autorise à manipuler dans les +expressions. Ces objets doivent pouvoir être afficher en *txt* ou en +*tex* avec les méthodes: + + * __txt__ : affichage en mode text + * __tex__ : affichage pour une compilation latex + +Operator +~~~~~~~~ + +Cette classe regroupe les opérateurs. Que l'on s'autorise à utiliser. On +y accède à partir de deux caractéristiques le symbole et l'arité. + +Liste des attributs importants: + + * arity: nombre d'opérande accepté + * priority: où se place l'opérateur dans la règles des priorités parmi +les autres opérateurs + * isOperator: permet de vérifier que c'est bien +un opérateur + +Liste des méthodes importantes: + + * __call__: Permet d'effectuer le calcul sur deux opérandes + * __txt__: affichage en mode texte + * __tex__: affichage pour une compilation latex + +Number +~~~~~~ + +Ce sont tous les types de "nombres" que l'on va vouloir manipuler. On essayera +de rester le plus proche de la construction mathématiques de ces objets. + +Par défaut, on travaillera avec des anneaux ce qui permettra de +construire ensuite le corps des fractions et l'anneau des polynômes +(quitte à quotienter) associé. + +Pour définir ces anneaux, il faudra contre avoir les méthodes suivantes: + + * __add__ + * __radd__ + ... + +Fractions +^^^^^^^^^ + +Polynomes +^^^^^^^^^ + +Quotient de polynomes (racines) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Expression +---------- + +Render +------ + +Simplify-simplified / compute-child +----------------------------------- + +Dans cette partie, on va expliquer le fonctionnement des mécanismes de +simplification des expressions/objets mathématiques. + +La simplification des expressions se fait avec les deux méthodes +suivantes: + +- *simplify()* pour: + + - un polynôme permet d'accéder à la forme développée d'un polynôme. + - une fraction permet d'avoir la fraction irréductible associée. + - une expression permet de faire tous les calculs possibles de cette + expression (à la fin il ne doit y avoir qu'un élément de la liste + de tokens). + +- *compute_exp()* pour: + + - un polynôme ou une fraction fait la même chose que `simplify`. + - une expression fait tous les calculs élémentaires de cette + expression. + +Ces deux méthodes fonctionnent ensuite sur le même principe. Elles vont +faire le calcul qui leurs est attribué en enregistrant les étapes dans +*steps* puis elles retourneront l'objet de fin de calcul à qui sera +assigné les *steps* (ce qui nécessitera par exemple de détourner la +classe *int*). + +Pour accéder à ces étapes, on utilisera alors la méthode *explain* qui +expliqueront les étapes intermédiaires. + From 033511b24ec9e14fc8a0a0b10fceee9c72ba0017 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 11:28:18 +0200 Subject: [PATCH 34/40] display code in polynom.rst --- documentation/source/polynom.rst | 179 +++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 documentation/source/polynom.rst diff --git a/documentation/source/polynom.rst b/documentation/source/polynom.rst new file mode 100644 index 0000000..c91aff7 --- /dev/null +++ b/documentation/source/polynom.rst @@ -0,0 +1,179 @@ +Les polynômes +============= + +Créer des polynômes +------------------- + +Générer un polynôme "fixe" +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code-block:: python + + >>> P = Polynom([1,2,3]) + >>> print(P) + 3 x ^ 2 + 2 x + 1 + >>> P = Polynom([1,2,3], letter = 'h') + >>> print(P) + 3 h ^ 2 + 2 h + 1 + >>> print(P.name) + 'P' + >>> Q = Polynom([1,2,3], name = 'Q') + >>> print(Q.name) + 'Q' + + + +Générer un polynôme aléatoirement +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code-block:: python + + >>> P = Polynom.random(["{b}", "{a}"]) # Polynom du type ax + b + >>> print(P) + - 8 x - 3 + >>> P = Polynom.random(degree = 2) + >>> print(P) + 5 x^{ 2 } + 4 x - 7 + +Manipuler des polynômes +----------------------- + +Les représentations des polynômes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code-block:: python + + >>> P = Polynom([1, 2, 3]) + >>> print(P) + 3 x ^ 2 + 2 x + 1 + +Évaluer des polynômes +~~~~~~~~~~~~~~~~~~~~~ + +Les polynômes peuvent se comporter comme des fonctions, on peut les évaluer. Il est possible de les évaluer sur des nombres, des expressions et même des polynômes. + +Évaluer un polynôme avec un entier +"""""""""""""""""""""""""""""""""" + + .. code-block:: python + + >>> type(P(3)) + pymath.expression.Fake_int + >>> P(3) + 34 + >>> for i in P(3).explain(): + print(i) + 3 \times 3^{ 2 } + 2 \times 3 + 1 + 3 \times 9 + 6 + 1 + 27 + 6 + 1 + 33 + 1 + 34 + >>> hp1 = Expression('h+1') + + +Évaluer un polynôme avec une expression +""""""""""""""""""""""""""""""""""""""" + + .. code-block:: python + + >>> type(P(hp1)) + < [6, 8, 3]> + >>> print(P(hp1)) + 3 h ^ 2 + 8 h + 6 + >>> for i in P(hp1).explain(): + ... print(i) + ... + 3 ( h + 1 )^{ 2 } + 2 ( h + 1 ) + 1 + 3 ( h + 1 ) ( h + 1 ) + 2 h + 2 + 1 + 3 ( h^{ 2 } + ( 1 + 1 ) h + 1 ) + 2 h + 2 + 1 + 3 ( h^{ 2 } + 2 h + 1 ) + 2 h + 2 + 1 + 3 ( h^{ 2 } + 2 h + 1 ) + 2 ( h + 1 ) + 1 + 3 h^{ 2 } + 3 \times 2 h + 3 + 2 h + 2 + 1 + 3 h^{ 2 } + 6 h + 3 + 2 h + 2 + 1 + 3 h^{ 2 } + ( 6 + 2 ) h + 3 + 2 + 1 + 3 h^{ 2 } + 8 h + 5 + 1 + 3 h^{ 2 } + 8 h + 6 + +Évaluer un polynôme avec un autre polynôme +"""""""""""""""""""""""""""""""""""""""""" + +.. code-block:: python + + >>> type(P(P)) + pymath.polynom.Polynom + >>> print(P(P)) + 27 x ^ 4 + 36 x ^ 3 + 36 x ^ 2 + 16 x + 6 + >>> for i in P(P).explain(): + ... print(i) + ... + 3 ( 3 x^{ 2 } + 2 x + 1 )^{ 2 } + 2 ( 3 x^{ 2 } + 2 x + 1 ) + 1 + 3 ( 3 x^{ 2 } + 2 x + 1 ) ( 3 x^{ 2 } + 2 x + 1 ) + 2 \times 3 x^{ 2 } + 2 \times 2 x + 2 + 1 + 3 ( 3 \times 3 x^{ 4 } + ( 2 \times 3 + 3 \times 2 ) x^{ 3 } + ( 3 + 2 \times 2 + 3 ) x^{ 2 } + ( 2 + 2 ) x + 1 ) + 6 x^{ 2 } + 4 x + 2 + 1 + 3 ( 9 x^{ 4 } + ( 6 + 6 ) x^{ 3 } + ( 3 + 4 + 3 ) x^{ 2 } + 4 x + 1 ) + 6 x^{ 2 } + 4 x + 2 + 1 + 3 ( 9 x^{ 4 } + 12 x^{ 3 } + ( 7 + 3 ) x^{ 2 } + 4 x + 1 ) + 6 x^{ 2 } + 4 x + 2 + 1 + 3 ( 9 x^{ 4 } + 12 x^{ 3 } + 10 x^{ 2 } + 4 x + 1 ) + 6 x^{ 2 } + 4 x + 2 + 1 + 3 ( 9 x^{ 4 } + 12 x^{ 3 } + 10 x^{ 2 } + 4 x + 1 ) + 2 ( 3 x^{ 2 } + 2 x + 1 ) + 1 + 3 \times 9 x^{ 4 } + 3 \times 12 x^{ 3 } + 3 \times 10 x^{ 2 } + 3 \times 4 x + 3 + 2 \times 3 x^{ 2 } + 2 \times 2 x + 2 + 1 + 27 x^{ 4 } + 36 x^{ 3 } + 30 x^{ 2 } + 12 x + 3 + 6 x^{ 2 } + 4 x + 2 + 1 + 27 x^{ 4 } + 36 x^{ 3 } + ( 30 + 6 ) x^{ 2 } + ( 12 + 4 ) x + 3 + 2 + 1 + 27 x^{ 4 } + 36 x^{ 3 } + 36 x^{ 2 } + 16 x + 5 + 1 + 27 x^{ 4 } + 36 x^{ 3 } + 36 x^{ 2 } + 16 x + 6 + + +Opération et polynômes +~~~~~~~~~~~~~~~~~~~~~~ + +Les opérations +, -, \* et ^ sont accessibles aux polynômes. Elles renvoient *toujours* un polynôme (même si le résultat est une constante) + + .. code-block:: python + + >>> type(P + 1) + pymath.polynomDeg2.Polynom_deg2 + >>> for i in (P+1).explain(): + print(i) + 3 x^{ 2 } + 2 x + 1 + 1 + 3 x^{ 2 } + 2 x + 2 + >>> Q = Polynom([4, 5, 6]) + >>> for i in (P+Q).explain(): + print(i) + 3 x^{ 2 } + 2 x + 1 + 6 x^{ 2 } + 5 x + 4 + ( 3 + 6 ) x^{ 2 } + ( 2 + 5 ) x + 1 + 4 + 9 x^{ 2 } + 7 x + 5 + >>> Q = Polynom([0,2,3]) + >>> print(Q) + >>> print(P-Q) + 1 + >>> type(P-Q) + pymath.polynom.Polynom + +Dérivation +~~~~~~~~~~ + +Il est possible de dériver les polynômes à partir de la méthode *derivate*. De la même façon que pour les opérations, le polynôme dérivé pour s'expliquer avec la méthode *explain*. + + .. code-block:: python + + >>> P1 = P.derivate() + >>> print(P1) + 6 x + 2 + >>> for i in P1.explain(): + ... print(i) + ... + 2 \times 3 x + 1 \times 2 + 6 x + 2 + >>> print(P1.name) + "P'" + +Polynomes du second degré +------------------------- + +Les polynômes du second degré héritent de toutes les méthodes venant de la classe Polynom. Ils ont cependant accès à d'autres méthodes plus spécifiques aux polynômes de ce degré: + + * Accès aux coefficients de façon 'naturelle' + * *delta*: discriminant du polynôme. + * *alpha*: Abscisse de l'extremum. + * *beta*: ordonnée de l'extremum. + * *roots*: les racines du polynôme (/!\ utilise *sympy* et ne peux pas expliquer le calcul pour le moment) + * *tbl_sgn_header*: en-tête du tableau du tableau de signe écrit pour *TkzTab* + * *tbl_sgn*: ligne du tableau de signe pour *TkzTab* + * *tbl_variation*: ligne du tableau de variation pour *TkzTab* From e40bfcf4155af684e916571fac3b64b223ada517 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 11:46:59 +0200 Subject: [PATCH 35/40] import docstring into sphinx :D --- documentation/source/code/modules.rst | 7 + documentation/source/code/pymath.rst | 110 +++++++++++ documentation/source/conf.py | 264 ++++++++++++++++++++++++++ documentation/source/index.rst | 27 +++ documentation/source/polynom.rst | 8 + 5 files changed, 416 insertions(+) create mode 100644 documentation/source/code/modules.rst create mode 100644 documentation/source/code/pymath.rst create mode 100644 documentation/source/conf.py create mode 100644 documentation/source/index.rst diff --git a/documentation/source/code/modules.rst b/documentation/source/code/modules.rst new file mode 100644 index 0000000..10647a5 --- /dev/null +++ b/documentation/source/code/modules.rst @@ -0,0 +1,7 @@ +pymath +====== + +.. toctree:: + :maxdepth: 4 + + pymath diff --git a/documentation/source/code/pymath.rst b/documentation/source/code/pymath.rst new file mode 100644 index 0000000..27aaced --- /dev/null +++ b/documentation/source/code/pymath.rst @@ -0,0 +1,110 @@ +pymath package +============== + +Submodules +---------- + +pymath.abstract_polynom module +------------------------------ + +.. automodule:: pymath.abstract_polynom + :members: + :undoc-members: + :show-inheritance: + +pymath.arithmetic module +------------------------ + +.. automodule:: pymath.arithmetic + :members: + :undoc-members: + :show-inheritance: + +pymath.explicable module +------------------------ + +.. automodule:: pymath.explicable + :members: + :undoc-members: + :show-inheritance: + +pymath.expression module +------------------------ + +.. automodule:: pymath.expression + :members: + :undoc-members: + :show-inheritance: + +pymath.fraction module +---------------------- + +.. automodule:: pymath.fraction + :members: + :undoc-members: + :show-inheritance: + +pymath.generic module +--------------------- + +.. automodule:: pymath.generic + :members: + :undoc-members: + :show-inheritance: + +pymath.operator module +---------------------- + +.. automodule:: pymath.operator + :members: + :undoc-members: + :show-inheritance: + +pymath.polynom module +--------------------- + +.. automodule:: pymath.polynom + :members: + :undoc-members: + :show-inheritance: + +pymath.polynomDeg2 module +------------------------- + +.. automodule:: pymath.polynomDeg2 + :members: + :undoc-members: + :show-inheritance: + +pymath.random_expression module +------------------------------- + +.. automodule:: pymath.random_expression + :members: + :undoc-members: + :show-inheritance: + +pymath.render module +-------------------- + +.. automodule:: pymath.render + :members: + :undoc-members: + :show-inheritance: + +pymath.str2tokens module +------------------------ + +.. automodule:: pymath.str2tokens + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pymath + :members: + :undoc-members: + :show-inheritance: diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 0000000..0c87353 --- /dev/null +++ b/documentation/source/conf.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pyMath documentation build configuration file, created by +# sphinx-quickstart on Thu Apr 23 10:44:48 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../../')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pyMath' +copyright = '2015, Benjamin Bertrand' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'classic' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pyMathdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'pyMath.tex', 'pyMath Documentation', + 'Benjamin Bertrand', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'pymath', 'pyMath Documentation', + ['Benjamin Bertrand'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'pyMath', 'pyMath Documentation', + 'Benjamin Bertrand', 'pyMath', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 0000000..dc136f4 --- /dev/null +++ b/documentation/source/index.rst @@ -0,0 +1,27 @@ +.. pyMath documentation master file, created by + sphinx-quickstart on Thu Apr 23 10:44:48 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to pyMath's documentation! +================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + tutorial + construction + polynom + code/pymath + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/documentation/source/polynom.rst b/documentation/source/polynom.rst index c91aff7..a0077db 100644 --- a/documentation/source/polynom.rst +++ b/documentation/source/polynom.rst @@ -177,3 +177,11 @@ Les polynômes du second degré héritent de toutes les méthodes venant de la c * *tbl_sgn_header*: en-tête du tableau du tableau de signe écrit pour *TkzTab* * *tbl_sgn*: ligne du tableau de signe pour *TkzTab* * *tbl_variation*: ligne du tableau de variation pour *TkzTab* + +Packages +-------- + +Abstact_polynom +~~~~~~~~~~~~~~~ + +.. automodule:: pymath.abstact_polynom From 52eff1863b13191b816103d13c5edbe7a809bb8d Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 14:37:55 +0200 Subject: [PATCH 36/40] add easy Fraction import --- pymath/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pymath/__init__.py b/pymath/__init__.py index 23d7af8..294f52c 100644 --- a/pymath/__init__.py +++ b/pymath/__init__.py @@ -3,6 +3,7 @@ from .expression import Expression from .polynom import Polynom +from .fraction import Fraction from .random_expression import random_str from .render import txt,tex From 0545d73751ca7eb1530bdcc5f73ed7c8766d41b9 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 27 Apr 2015 19:09:03 +0200 Subject: [PATCH 37/40] solve left parenthesis issue --- pymath/operator.py | 25 +++++++++++-------------- pymath/render.py | 15 ++++++++++----- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index 555953b..c4d12bc 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -149,7 +149,8 @@ class Operator(str): """ Add parenthesis for left operand if necessary """ ans = opl try: - if opl.mainOp == op.sub1: + # TODO: Je pige pas pourquoi quand on enlève .name ça marche plus... |lun. avril 27 19:07:24 CEST 2015 + if opl.mainOp.name == op.sub1.name: ans = opl elif opl.mainOp.priority < self.priority: ans = flatten_list(["(", opl, ")"]) @@ -163,7 +164,7 @@ class Operator(str): return ans def r_parenthesis(self, op, str_join=False): - """ Add parenthesis for left operand if necessary """ + """ Add parenthesis for rigth operand if necessary """ # TODO: /!\ Parenthèses pour -2abc et l'opérateur * |lun. mars 9 19:02:32 CET 2015 try: if op.mainOp.priority < self.priority: @@ -212,6 +213,12 @@ def operatorize(fun): def mod_fun(self, *args): ans = fun(self, *args) + def _eq(op1, op2): + """ op1 == op2 """ + return op1.name == op2.name == name and op1.arity == op2.arity + + ans["__eq__"] = _eq + new_op = Operator(ans["operator"]) for (attr, value) in ans.items(): if hasattr(value, '__call__'): @@ -603,18 +610,8 @@ if __name__ == '__main__': #print("\t op.can_be_operator('+') :" + str(op.can_be_operator('+'))) #print("\t op.can_be_operator('t') :" + str(op.can_be_operator('t'))) - from .render import tex - print(tex([-2, 3, op.add ])) - print("-----------------") - print(tex([-2, 3, op.mul ])) - print("-----------------") - from .polynom import Polynom - print(tex([Polynom([1,2,3]), 2, op.mul])) - print("-----------------") - from .fraction import Fraction - print(tex([2, Fraction(1,2), op.mul])) - print("-----------------") - + print("op.sub.__dict__ -> ", op.sub.__dict__) + print(op.sub == op.sub1) #import doctest #doctest.testmod() diff --git a/pymath/render.py b/pymath/render.py index d26bfa2..56587bc 100644 --- a/pymath/render.py +++ b/pymath/render.py @@ -74,11 +74,16 @@ p2i = Render(p2i_render) if __name__ == '__main__': from .operator import op - exp = [ 2, 3, op.add, 4, op.mul] - print(exp) - print("txt(exp) :" + str(txt(exp))) - print("tex(exp) :" + str(tex(exp))) - print("p2i(exp) :" + str(p2i(exp))) + from itertools import permutations + from pymath import Polynom + from pymath import Expression + coefs_p = [[(i-2),(j-2)] for i,j in permutations(range(3),2)] + coefs_q = [[2*(i-2),2*(j-2)] for i,j in permutations(range(3),2)] + l_p = [Polynom(i) for i in coefs_p] + l_q = [Polynom(i) for i in coefs_q] + operations = [Expression([l_p[i],l_q[j],op.mul]) for i,j in permutations(range(len(coefs_p)),2)] + for i in operations: + print(i) From fcee4a89426b65feb46fe5cc7829e45792700d87 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 27 Apr 2015 19:16:08 +0200 Subject: [PATCH 38/40] solve parenthesis bug for op.pw --- pymath/operator.py | 16 ++++++++++++++++ pymath/render.py | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index c4d12bc..6ffbb49 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -565,6 +565,21 @@ class op(object): """ Calling this operator performs the rigth calculus """ return getattr(op1, "__pow__")(op2) + def l_parenthesis(self, opl, str_join=False): + """ Add parenthesis for left operand if necessary """ + ans = opl + try: + if opl.mainOp.priority < self.priority: + ans = flatten_list(["(", opl, ")"]) + except AttributeError as e: + # op has not the attribute priority + pass + + ans = flatten_list([ans]) + if str_join: + ans = ' '.join([str(i) for i in ans]) + return ans + caract = { "operator" : "^", \ "name" : "pw",\ @@ -573,6 +588,7 @@ class op(object): "actions" : ("__pow__",""), \ "txt" : "{op1} ^ {op2}",\ "tex" : "{op1}^{{ {op2} }}",\ + "l_parenthesis": l_parenthesis,\ "_call":_call,\ } diff --git a/pymath/render.py b/pymath/render.py index 56587bc..67e70d8 100644 --- a/pymath/render.py +++ b/pymath/render.py @@ -77,11 +77,11 @@ if __name__ == '__main__': from itertools import permutations from pymath import Polynom from pymath import Expression - coefs_p = [[(i-2),(j-2)] for i,j in permutations(range(3),2)] - coefs_q = [[2*(i-2),2*(j-2)] for i,j in permutations(range(3),2)] + coefs_p = [[(i-2),(j-2)] for i,j in permutations(range(5),2)] + coefs_q = [[2*(i-2),2*(j-2)] for i,j in permutations(range(5),2)] l_p = [Polynom(i) for i in coefs_p] l_q = [Polynom(i) for i in coefs_q] - operations = [Expression([l_p[i],l_q[j],op.mul]) for i,j in permutations(range(len(coefs_p)),2)] + operations = [Expression([l_p[i],l_q[j],op.pw]) for i,j in permutations(range(len(coefs_p)),2)] for i in operations: print(i) From 9dd42d215163e5561168a200671dbe80c470b749 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 27 Apr 2015 19:24:20 +0200 Subject: [PATCH 39/40] raise exception if fraction can't be build --- pymath/fraction.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pymath/fraction.py b/pymath/fraction.py index 9369c64..fe72c48 100644 --- a/pymath/fraction.py +++ b/pymath/fraction.py @@ -24,6 +24,8 @@ class Fraction(Explicable): """ super(Fraction, self).__init__() self._num = num + if denom == 0: + raise ZeroDivisionError("Can't create Fraction: division by zero") self._denom = denom self.isNumber = 1 From 1352f90f7d0551e05127cb3dd7b988e4442806a4 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 27 Apr 2015 19:35:31 +0200 Subject: [PATCH 40/40] remove solve todo --- pymath/generic.py | 5 ----- pymath/operator.py | 4 ---- pymath/render.py | 5 +++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/pymath/generic.py b/pymath/generic.py index c911b27..b83d809 100644 --- a/pymath/generic.py +++ b/pymath/generic.py @@ -8,7 +8,6 @@ class Stack(object): """Docstring for Stack """ def __init__(self): - """@todo: to be defined1 """ self.items = [] def pushFromList(self, list): @@ -21,7 +20,6 @@ class Stack(object): def isEmpty(self): """ Says if the stack is empty - :returns: @todo """ return self.items == [] @@ -29,9 +27,6 @@ class Stack(object): def push(self, item): """Push an item in the stack - :param item: @todo - :returns: @todo - """ self.items.append(item) diff --git a/pymath/operator.py b/pymath/operator.py index 6ffbb49..b643cad 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -116,7 +116,6 @@ class Operator(str): :*args: Operands for this operation :returns: list with the operator surrounded by operands - # TODO: order doctest |lun. nov. 24 07:17:29 CET 2014 >>> op.mul.__p2i__(1,2) [1, '*', 2] >>> f = save_mainOp([2, op.add, 3],op.add) @@ -131,9 +130,7 @@ class Operator(str): >>> op.sub1.__p2i__(f) ['-', '(', 2, '+', 3, ')'] """ - # TODO: Attention à gestion des fractions qui se comportent chelou avec les parenthèses |dim. nov. 9 09:21:52 CET 2014 if self.arity == 1: - # TODO: Marche juste avec -, il faudra voir quand il y aura d'autres operateurs unitaires |dim. nov. 9 09:24:53 CET 2014 op1 = self.l_parenthesis(args[0]) ans = flatten_list([self, op1]) @@ -165,7 +162,6 @@ class Operator(str): def r_parenthesis(self, op, str_join=False): """ Add parenthesis for rigth operand if necessary """ - # TODO: /!\ Parenthèses pour -2abc et l'opérateur * |lun. mars 9 19:02:32 CET 2015 try: if op.mainOp.priority < self.priority: op = flatten_list(["(", op, ")"]) diff --git a/pymath/render.py b/pymath/render.py index 67e70d8..4c58f07 100644 --- a/pymath/render.py +++ b/pymath/render.py @@ -77,11 +77,12 @@ if __name__ == '__main__': from itertools import permutations from pymath import Polynom from pymath import Expression + from pymath import Fraction coefs_p = [[(i-2),(j-2)] for i,j in permutations(range(5),2)] coefs_q = [[2*(i-2),2*(j-2)] for i,j in permutations(range(5),2)] l_p = [Polynom(i) for i in coefs_p] - l_q = [Polynom(i) for i in coefs_q] - operations = [Expression([l_p[i],l_q[j],op.pw]) for i,j in permutations(range(len(coefs_p)),2)] + l_q = [Fraction(i,j) for i,j in coefs_q if j!=0] + operations = [Expression([l_p[i],l_q[j],op.mul]) for i,j in permutations(range(len(l_q)),2)] for i in operations: print(i)