From 5bbf535756612bfa435fa976c2a6288e1f3444a6 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 21 Feb 2015 11:27:02 +0100 Subject: [PATCH 01/37] 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 12af21b2a62aa48d33eb666f4b75066ff0ee42ed Mon Sep 17 00:00:00 2001 From: Lafrite Date: Wed, 25 Feb 2015 11:24:48 +0100 Subject: [PATCH 02/37] add less verbose in Todolist --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 375517a..d1c0436 100644 --- a/TODO +++ b/TODO @@ -7,3 +7,4 @@ * Expression should be able to simplify expression with ":" * Expression parents class and his children: Numerical_exp, toGenerate_exp and formal expression +* Make less verbose fractions operations From e58567b2f8da44c381e1ec4fcb23ebf9294a5281 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 28 Mar 2015 09:09:32 +0100 Subject: [PATCH 03/37] 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 0b50961c841fb60060e3f0e930080d577840f4c3 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 14:49:55 +0200 Subject: [PATCH 04/37] 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 8175c48cd0ca517d7634199c7732108b7df81e1d Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 5 Apr 2015 17:04:04 +0200 Subject: [PATCH 05/37] 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 1d643df36f1702ff1d56041b19e61cc94497769d Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 5 Apr 2015 17:05:21 +0200 Subject: [PATCH 06/37] 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 a9f1f90e8d96fafb15161e6ad0401a8297c1bd39 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 6 Apr 2015 17:57:13 +0200 Subject: [PATCH 07/37] 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 525c3bda5623dd0ae42bfb60d9cf620b973ea075 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 6 Apr 2015 17:57:57 +0200 Subject: [PATCH 08/37] 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 27b3ba51150347f14e40e04135f117ce61a5fcfc Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 06:44:20 +0200 Subject: [PATCH 09/37] 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 862c1b663a9d3710ac46849c521d488ad1727ebf Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 07:45:37 +0200 Subject: [PATCH 10/37] 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 e37a77624e309971dba7fa8ab9fd317f0682dd55 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 28 Mar 2015 17:14:11 +0100 Subject: [PATCH 11/37] 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 71e427f63466cc9c45788710aa99040067ad1b3f Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 15:56:36 +0200 Subject: [PATCH 12/37] 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 045b28b1e5799dbfd039f1c77e2b3e53248855f5 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 16:07:07 +0200 Subject: [PATCH 13/37] 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 ec735175f72d9643cbc7b5f74ccfc7a823ce7bff Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 3 Apr 2015 17:32:02 +0200 Subject: [PATCH 14/37] 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 fc23a9540199723b9ebc3cb1ef5a265bd68450bc Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 08:46:59 +0200 Subject: [PATCH 15/37] 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 7f79e23cd3b8f6768fa84a5663c3ab31ee47bf95 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 08:55:05 +0200 Subject: [PATCH 16/37] 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 3af50d0eab48bed74e744f2433a03a0c0f0cc7d9 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 7 Apr 2015 09:51:12 +0200 Subject: [PATCH 17/37] 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 0e140cb30473a5b50484fa03e736f8b18c8ba2a9 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Fri, 17 Apr 2015 16:38:16 +0200 Subject: [PATCH 18/37] 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 895620b374d64df35c052c74d116daf887956217 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 20 Apr 2015 21:20:29 +0200 Subject: [PATCH 19/37] 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 84a04841aaf854b8743fa8225ae4d372b4218d57 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Mon, 20 Apr 2015 21:21:19 +0200 Subject: [PATCH 20/37] 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 c8ac23f4436def299de3a0f611056bbf5210e2d0 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 08:36:36 +0200 Subject: [PATCH 21/37] 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 9a2e6254b85ed7bde03b70240d9181e494ecbb22 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 08:37:25 +0200 Subject: [PATCH 22/37] 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 def0e098518430986d87916eabbe1a0d29e0147c Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 17:31:23 +0200 Subject: [PATCH 23/37] 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 3589a2733a700f69b6913a99d26306a4fcf7f1ac Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 17:31:56 +0200 Subject: [PATCH 24/37] 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 d9744cbcaeaa24095fed99f2714c5f3bdfdc8e19 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 18:10:14 +0200 Subject: [PATCH 25/37] 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 f3b52e2f11c08a485debe1117504641ff8b56a2a Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 19:48:05 +0200 Subject: [PATCH 26/37] 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 4be09185b758ff4e417d5ff24e3fb004a8172fce Mon Sep 17 00:00:00 2001 From: Lafrite Date: Tue, 21 Apr 2015 19:48:37 +0200 Subject: [PATCH 27/37] 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 885514cbdb46a2420e7157669eed4ae72ae02eda Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:13:11 +0200 Subject: [PATCH 28/37] 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 5c2d97b1b38aefed8ca541d345a193dd168fcb16 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:28:21 +0200 Subject: [PATCH 29/37] some cleaning --- TODO | 2 +- notes | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 notes diff --git a/TODO b/TODO index db39e93..5d42b34 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 88e87e035db6861e818b94820fe5ce90a7476642 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 08:42:04 +0200 Subject: [PATCH 30/37] 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 62ec67ebb2a4b930561f61bac3e5c94abdb9f6b1 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 09:54:21 +0200 Subject: [PATCH 31/37] transform tutorial.md to tutorial.rst --- docs/tutorial.rst | 334 ++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 335 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). diff --git a/setup.py b/setup.py index f084faf..9d8eb67 100644 --- a/setup.py +++ b/setup.py @@ -8,4 +8,5 @@ setup(name='pyMath', author='Benjamin Bertrand', author_email='lafrite@poneyworld.net', packages=['pymath'], + install_requires=['pyparsing', 'sympy'], ) From f4fbda48af6338c68b2c71c9967334bca6076526 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 10:04:56 +0200 Subject: [PATCH 32/37] 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 3984f101bd481db447ba038612770d5ebec051b2 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 10:40:02 +0200 Subject: [PATCH 33/37] finish translate doc from markdown to ReST --- docs/{fraction.mdwn => fraction.rst} | 0 docs/polynom.mdwn | 55 ------ docs/polynom.rst | 165 +++++++++++++++++ docs/tutorial.mdwn | 253 --------------------------- 4 files changed, 165 insertions(+), 308 deletions(-) rename docs/{fraction.mdwn => fraction.rst} (100%) delete mode 100644 docs/polynom.mdwn create mode 100644 docs/polynom.rst delete mode 100644 docs/tutorial.mdwn diff --git a/docs/fraction.mdwn b/docs/fraction.rst similarity index 100% rename from docs/fraction.mdwn rename to docs/fraction.rst diff --git a/docs/polynom.mdwn b/docs/polynom.mdwn deleted file mode 100644 index a265841..0000000 --- a/docs/polynom.mdwn +++ /dev/null @@ -1,55 +0,0 @@ -# Les polynômes - - -## Créer des polynômes - -### Générer un polynôme "fixe" - -### Générer un polynôme aléatoirement - - >>> 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 - - >>> 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 - - diff --git a/docs/polynom.rst b/docs/polynom.rst new file mode 100644 index 0000000..d2a3af8 --- /dev/null +++ b/docs/polynom.rst @@ -0,0 +1,165 @@ +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* diff --git a/docs/tutorial.mdwn b/docs/tutorial.mdwn deleted file mode 100644 index 1ed1ae4..0000000 --- a/docs/tutorial.mdwn +++ /dev/null @@ -1,253 +0,0 @@ -# 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. - - >>> from pymath.expression 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 + 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. - - >>> from pymath.expression 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 - >>> une_fraction = Fraction(1,2) - >>> print(une_fraction) - 1 / 2 - >>> from pymath.polynom 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 - >>> 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 + 10 }{ 15 } - \frac{ 16 }{ 15 } - >>> from pymath.render import txt - >>> with Expression.tmp_render(txt): - ... for i in ajout_fractions.simpliy(): - ... print(i) - ... - 2 / 5 + 2 / 3 - 2 * 3 / 5 * 3 + 2 * 5 / 3 * 5 - ( 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*. - - >>> from pymath.expression 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). - - >>> 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: - - >>> from pymath.render import txt - >>> Expression.set_render(txt) - >>> un_calcul.render() - 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. - - >>> from pymath.expression import Expression - >>> from pymath.renders 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. - - >>> 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](fraction.mdwn) et [polynom](polynom.mdwn) pour plus de details) - - >>> from pymath.fraction import Fraction - >>> fraction1 = Fraction(1,2) - >>> fraction2 = Fraction(2,3) - >>> print(fraction1) - 1 / 2 - >>> from pymath.polynom 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. - - >>> fraction_expression = Expression("2 / 3") - >>> autre_fraction_expression = Expression("4 / 9") - >>> print(fraction_expression + autre_fraction_expression) - 2 / 3 + 4 / 9 - -les opérations sur les fractions ou les polynômes renvoient la liste des étapes jusqu'à leur forme simplifiée - - >>> 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). - - >>> 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 import 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 - - >>> from pymath.render 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). - - >>> 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. - - >>> 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. - - >>> 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*: - - >>> from pymath.random_expression 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 e8854eeef72e8fe05213fe1c695d14dc1b76936d Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 11:23:08 +0200 Subject: [PATCH 34/37] start using sphinx for documentation --- .gitignore | 1 + docs/tutorial.mdwn | 253 ------------- docs/tutorial.rst | 334 ----------------- documentation/Makefile | 177 +++++++++ documentation/source/conf.py | 264 +++++++++++++ .../source}/construction.rst | 0 {docs => documentation/source}/fraction.rst | 0 documentation/source/index.rst | 26 ++ {docs => documentation/source}/polynom.rst | 0 documentation/source/tutorial.rst | 352 ++++++++++++++++++ 10 files changed, 820 insertions(+), 587 deletions(-) delete mode 100644 docs/tutorial.mdwn delete mode 100644 docs/tutorial.rst create mode 100644 documentation/Makefile create mode 100644 documentation/source/conf.py rename {docs => documentation/source}/construction.rst (100%) rename {docs => documentation/source}/fraction.rst (100%) create mode 100644 documentation/source/index.rst rename {docs => documentation/source}/polynom.rst (100%) create mode 100644 documentation/source/tutorial.rst diff --git a/.gitignore b/.gitignore index 644cdba..f988e77 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ *.pyc dist/ *.egg-info/ +documentation/build/ diff --git a/docs/tutorial.mdwn b/docs/tutorial.mdwn deleted file mode 100644 index 6b3ca30..0000000 --- a/docs/tutorial.mdwn +++ /dev/null @@ -1,253 +0,0 @@ -# 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. - - >>> 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 + 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. - - >>> 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 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. - - >>> 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 + 10 }{ 15 } - \frac{ 16 }{ 15 } - >>> from pymath import txt - >>> with Expression.tmp_render(txt): - ... for i in ajout_fractions.simpliy(): - ... print(i) - ... - 2 / 5 + 2 / 3 - 2 * 3 / 5 * 3 + 2 * 5 / 3 * 5 - ( 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*. - - >>> 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). - - >>> 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: - - >>> from pymath import txt - >>> Expression.set_render(txt) - >>> un_calcul.render() - 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. - - >>> 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. - - >>> 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](fraction.mdwn) et [polynom](polynom.mdwn) pour plus de details) - - >>> 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. - - >>> fraction_expression = Expression("2 / 3") - >>> autre_fraction_expression = Expression("4 / 9") - >>> print(fraction_expression + autre_fraction_expression) - 2 / 3 + 4 / 9 - -les opérations sur les fractions ou les polynômes renvoient la liste des étapes jusqu'à leur forme simplifiée - - >>> 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). - - >>> 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 import 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 - - >>> 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). - - >>> 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. - - >>> 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. - - >>> 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*: - - >>> 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). diff --git a/docs/tutorial.rst b/docs/tutorial.rst deleted file mode 100644 index 8655098..0000000 --- a/docs/tutorial.rst +++ /dev/null @@ -1,334 +0,0 @@ -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). diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 0000000..76646c2 --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyMath.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyMath.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/pyMath" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyMath" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 0000000..bf1bc60 --- /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 = 'default' + +# 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/docs/construction.rst b/documentation/source/construction.rst similarity index 100% rename from docs/construction.rst rename to documentation/source/construction.rst diff --git a/docs/fraction.rst b/documentation/source/fraction.rst similarity index 100% rename from docs/fraction.rst rename to documentation/source/fraction.rst diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 0000000..e77f13e --- /dev/null +++ b/documentation/source/index.rst @@ -0,0 +1,26 @@ +.. 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 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/polynom.rst b/documentation/source/polynom.rst similarity index 100% rename from docs/polynom.rst rename to documentation/source/polynom.rst diff --git a/documentation/source/tutorial.rst b/documentation/source/tutorial.rst new file mode 100644 index 0000000..a32a547 --- /dev/null +++ b/documentation/source/tutorial.rst @@ -0,0 +1,352 @@ +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 0d030fa204819947e5ae24ec6aa25620d20cebcb Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 11:28:18 +0200 Subject: [PATCH 35/37] display code in polynom.rst --- documentation/source/polynom.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/documentation/source/polynom.rst b/documentation/source/polynom.rst index d2a3af8..c91aff7 100644 --- a/documentation/source/polynom.rst +++ b/documentation/source/polynom.rst @@ -8,6 +8,7 @@ Générer un polynôme "fixe" ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python + >>> P = Polynom([1,2,3]) >>> print(P) 3 x ^ 2 + 2 x + 1 @@ -26,6 +27,7 @@ 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 @@ -40,6 +42,7 @@ Les représentations des polynômes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python + >>> P = Polynom([1, 2, 3]) >>> print(P) 3 x ^ 2 + 2 x + 1 @@ -49,8 +52,11 @@ Les représentations 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. +Évaluer un polynôme avec un entier +"""""""""""""""""""""""""""""""""" + .. code-block:: python + >>> type(P(3)) pymath.expression.Fake_int >>> P(3) @@ -65,8 +71,11 @@ Les polynômes peuvent se comporter comme des fonctions, on peut les évaluer. I >>> hp1 = Expression('h+1') -Évaluer un polynôme avec une expression. +Évaluer un polynôme avec une expression +""""""""""""""""""""""""""""""""""""""" + .. code-block:: python + >>> type(P(hp1)) < [6, 8, 3]> >>> print(P(hp1)) @@ -85,8 +94,11 @@ Les polynômes peuvent se comporter comme des fonctions, on peut les évaluer. I 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 +Évaluer un polynôme avec un autre polynôme +"""""""""""""""""""""""""""""""""""""""""" + +.. code-block:: python + >>> type(P(P)) pymath.polynom.Polynom >>> print(P(P)) @@ -114,6 +126,7 @@ 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(): @@ -139,6 +152,7 @@ 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 From f2762bec5971e56c7dec785c8ce053793d343dde Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 11:46:59 +0200 Subject: [PATCH 36/37] import docstring into sphinx :D --- documentation/source/code/modules.rst | 7 ++ documentation/source/code/pymath.rst | 110 ++++++++++++++++++++++++++ documentation/source/conf.py | 4 +- documentation/source/index.rst | 1 + documentation/source/polynom.rst | 8 ++ 5 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 documentation/source/code/modules.rst create mode 100644 documentation/source/code/pymath.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 index bf1bc60..0c87353 100644 --- a/documentation/source/conf.py +++ b/documentation/source/conf.py @@ -19,7 +19,7 @@ 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('.')) +sys.path.insert(0, os.path.abspath('../../')) # -- General configuration ------------------------------------------------ @@ -104,7 +104,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +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 diff --git a/documentation/source/index.rst b/documentation/source/index.rst index e77f13e..dc136f4 100644 --- a/documentation/source/index.rst +++ b/documentation/source/index.rst @@ -14,6 +14,7 @@ Contents: tutorial construction polynom + code/pymath 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 98885cb80fb592b2b818bea3be2ef300c0a7dc9f Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Apr 2015 15:10:26 +0200 Subject: [PATCH 37/37] 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