Merge branch 'dev' into 2nd_deg
This commit is contained in:
95
pymath/explicable.py
Normal file
95
pymath/explicable.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from .render import txt, tex
|
||||
|
||||
class Renderable(object):
|
||||
STR_RENDER = tex
|
||||
DEFAULT_RENDER = tex
|
||||
|
||||
@classmethod
|
||||
def set_render(cls, render):
|
||||
cls.STR_RENDER = render
|
||||
|
||||
@classmethod
|
||||
def get_render(cls):
|
||||
return cls.STR_RENDER
|
||||
|
||||
@classmethod
|
||||
def set_default_render(cls):
|
||||
cls.set_render(cls.DEFAULT_RENDER)
|
||||
|
||||
@classmethod
|
||||
def tmp_render(cls, render = tex):
|
||||
""" Create a container in which Expression render is temporary modify
|
||||
|
||||
The default temporary render is Expression in order to perform calculus inside numbers
|
||||
|
||||
>>> from .expression import Expression
|
||||
>>> exp = Expression("2*3/5")
|
||||
>>> print(exp)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
>>> for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
>>> with Expression.tmp_render(txt):
|
||||
... for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 * 3 / 5
|
||||
6 / 5
|
||||
>>> for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
|
||||
"""
|
||||
class TmpRenderEnv(object):
|
||||
def __enter__(self):
|
||||
self.old_render = Renderable.get_render()
|
||||
Renderable.set_render(render)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
Renderable.set_render(self.old_render)
|
||||
return TmpRenderEnv()
|
||||
|
||||
class Explicable(Renderable):
|
||||
|
||||
""" An Explicable object is an object which can be explicable!
|
||||
|
||||
It's a parent class of a more classical Expression, Fraction and Polynom (and later square root)
|
||||
Child class will have the following method
|
||||
* explain: Generator which return steps which leed to himself
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.steps = []
|
||||
|
||||
def explain(self):
|
||||
""" Generate and render steps which leed to itself """
|
||||
old_s = ''
|
||||
# les étapes pour l'atteindre
|
||||
try:
|
||||
for s in self.steps:
|
||||
if hasattr(s, 'postfix_tokens'):
|
||||
new_s = self.STR_RENDER(s.postfix_tokens)
|
||||
else:
|
||||
new_s = self.STR_RENDER(s)
|
||||
if new_s != old_s:
|
||||
old_s = new_s
|
||||
yield new_s
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Lui même
|
||||
new_s = self.STR_RENDER(self.postfix_tokens)
|
||||
if new_s != old_s:
|
||||
yield new_s
|
||||
|
||||
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# Reglages pour 'vim'
|
||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||
# cursor: 16 del
|
@@ -2,71 +2,18 @@
|
||||
# encoding: utf-8
|
||||
|
||||
from .generic import Stack, flatten_list, expand_list, isNumber, isOperator, isNumerand
|
||||
from .render import txt, tex
|
||||
from .str2tokens import str2tokens
|
||||
from .operator import op
|
||||
from .explicable import Explicable
|
||||
|
||||
from .random_expression import RdExpression
|
||||
|
||||
__all__ = ['Expression']
|
||||
|
||||
class Expression(object):
|
||||
|
||||
class Expression(Explicable):
|
||||
"""A calculus expression. Today it can andle only expression with numbers later it will be able to manipulate unknown"""
|
||||
|
||||
STR_RENDER = tex
|
||||
DEFAULT_RENDER = tex
|
||||
|
||||
@classmethod
|
||||
def set_render(cls, render):
|
||||
cls.STR_RENDER = render
|
||||
|
||||
@classmethod
|
||||
def get_render(cls ):
|
||||
return cls.STR_RENDER
|
||||
|
||||
@classmethod
|
||||
def set_default_render(cls):
|
||||
cls.set_render(cls.DEFAULT_RENDER)
|
||||
|
||||
@classmethod
|
||||
def tmp_render(cls, render = lambda _,x:Expression(x)):
|
||||
""" Create a container in which Expression render is temporary modify
|
||||
|
||||
The default temporary render is Expression in order to perform calculus inside numbers
|
||||
|
||||
>>> exp = Expression("2*3/5")
|
||||
>>> print(exp)
|
||||
\\frac{ 2 \\times 3 }{ 5 }
|
||||
>>> for i in exp.simplify():
|
||||
... print(i)
|
||||
\\frac{ 2 \\times 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
>>> with Expression.tmp_render():
|
||||
... for i in exp.simplify():
|
||||
... i
|
||||
< Expression [2, 3, '*', 5, '/']>
|
||||
< Expression [6, 5, '/']>
|
||||
< Fraction 6 / 5>
|
||||
|
||||
>>> with Expression.tmp_render(txt):
|
||||
... for i in exp.simplify():
|
||||
... print(i)
|
||||
2 * 3 / 5
|
||||
6 / 5
|
||||
>>> for i in exp.simplify():
|
||||
... print(i)
|
||||
\\frac{ 2 \\times 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
|
||||
"""
|
||||
class TmpRenderEnv(object):
|
||||
def __enter__(self):
|
||||
self.old_render = Expression.get_render()
|
||||
Expression.set_render(render)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
Expression.set_render(self.old_render)
|
||||
return TmpRenderEnv()
|
||||
|
||||
@classmethod
|
||||
def random(self, form="", conditions=[], val_min = -10, val_max=10):
|
||||
@@ -81,6 +28,38 @@ class Expression(object):
|
||||
random_generator = RdExpression(form, conditions)
|
||||
return Expression(random_generator(val_min, val_max))
|
||||
|
||||
@classmethod
|
||||
def tmp_render(cls, render = lambda _,x:Expression(x)):
|
||||
""" Same ad tmp_render for Renderable but default render is Expression
|
||||
|
||||
>>> exp = Expression("2*3/5")
|
||||
>>> print(exp)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
>>> for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
>>> with Expression.tmp_render():
|
||||
... for i in exp.simplify().explain():
|
||||
... i
|
||||
< <class 'pymath.expression.Expression'> [2, 3, 5, '/', '*'] >
|
||||
< <class 'pymath.expression.Expression'> [2, < Fraction 3 / 5>, '*'] >
|
||||
< <class 'pymath.expression.Expression'> [2, < Fraction 3 / 5>, '*'] >
|
||||
< <class 'pymath.expression.Expression'> [6, 5, '/'] >
|
||||
>>> from .render import txt
|
||||
>>> with Expression.tmp_render(txt):
|
||||
... for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 * 3 / 5
|
||||
6 / 5
|
||||
>>> for i in exp.simplify().explain():
|
||||
... print(i)
|
||||
2 \\times \\frac{ 3 }{ 5 }
|
||||
\\frac{ 6 }{ 5 }
|
||||
|
||||
"""
|
||||
return super(Expression, cls).tmp_render(render)
|
||||
|
||||
def __new__(cls, exp):
|
||||
"""Create Expression objects
|
||||
|
||||
@@ -89,36 +68,35 @@ class Expression(object):
|
||||
"""
|
||||
expression = object.__new__(cls)
|
||||
if type(exp) == str:
|
||||
#self._exp = exp
|
||||
expression.postfix_tokens = str2tokens(exp) # les tokens seront alors stockés dans self.tokens temporairement
|
||||
expression.postfix_tokens = str2tokens(exp)
|
||||
elif type(exp) == list:
|
||||
expression.postfix_tokens = flatten_list([tok.postfix_tokens if Expression.isExpression(tok) else tok for tok in exp])
|
||||
elif type(exp) == Expression:
|
||||
return exp
|
||||
else:
|
||||
raise ValueError("Can't build Expression with {} object".format(type(exp)))
|
||||
|
||||
if len(expression.postfix_tokens) == 1:
|
||||
token = expression.postfix_tokens[0]
|
||||
if hasattr(token, 'simplify'):
|
||||
if hasattr(token, 'simplify') and hasattr(token, 'explain'):
|
||||
return expression.postfix_tokens[0]
|
||||
|
||||
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]
|
||||
simplified = lambda x:x
|
||||
simplify = lambda x:x
|
||||
is_number = True
|
||||
methods_attr = {'simplify':simplify, 'simplified':simplified, 'isNumber': is_number}
|
||||
fake_token = type('fake_int', (int,), methods_attr)(token)
|
||||
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) == 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
|
||||
simplify = lambda x:[x]
|
||||
simplified = lambda x:x
|
||||
is_polynom = True
|
||||
methods_attr = {'simplify':simplify, 'simplified':simplified, '_isPolynom': is_polynom}
|
||||
fake_token = type('fake_str', (str,), methods_attr)(token)
|
||||
methods_attr = {'simplify':simplify, '_isPolynom': is_polynom, 'postfix_tokens': [token]}
|
||||
fake_token = type('fake_str', (str,Explicable, ), methods_attr)(token)
|
||||
return fake_token
|
||||
|
||||
else:
|
||||
raise ValueError("Unknow type in Expression: {}".format(type(token)))
|
||||
|
||||
@@ -129,74 +107,29 @@ class Expression(object):
|
||||
def __str__(self):
|
||||
"""
|
||||
Overload str
|
||||
If you want to changer render use Expression.set_render(...)
|
||||
|
||||
If you want to changer render use Expression.set_render(...) or use tmp_render context manager.
|
||||
"""
|
||||
return self.STR_RENDER(self.postfix_tokens)
|
||||
|
||||
def __repr__(self):
|
||||
return "< Expression " + str(self.postfix_tokens) + ">"
|
||||
|
||||
def render(self, render = lambda x:str(x)):
|
||||
""" Same as __str__ but accept render as argument
|
||||
:param render: function which render the list of token (postfix form) to string
|
||||
|
||||
"""
|
||||
# TODO: I don't like the name of this method |ven. janv. 17 12:48:14 CET 2014
|
||||
return render(self.postfix_tokens)
|
||||
|
||||
## ---------------------
|
||||
## Mechanism functions
|
||||
return " ".join(["<", str(self.__class__) , str(self.postfix_tokens), ">"])
|
||||
|
||||
def simplify(self):
|
||||
""" Generator which return steps for computing the expression """
|
||||
if not self.can_go_further():
|
||||
yield self.STR_RENDER(self.postfix_tokens)
|
||||
else:
|
||||
self.compute_exp()
|
||||
old_s = ''
|
||||
for s in self.steps:
|
||||
new_s = self.STR_RENDER(s)
|
||||
# Astuce pour éviter d'avoir deux fois la même étape (par exemple pour la transfo d'une division en fraction)
|
||||
if new_s != old_s:
|
||||
old_s = new_s
|
||||
yield new_s
|
||||
|
||||
if Expression.isExpression(self.child):
|
||||
for s in self.child.simplify():
|
||||
if old_s != s:
|
||||
old_s = s
|
||||
yield s
|
||||
else:
|
||||
for s in self.child.simplify():
|
||||
new_s = self.STR_RENDER([s])
|
||||
# Astuce pour éviter d'avoir deux fois la même étape (par exemple pour la transfo d'une division en fraction)
|
||||
if new_s != old_s:
|
||||
old_s = new_s
|
||||
yield new_s
|
||||
if old_s != self.STR_RENDER([self.child]):
|
||||
yield self.STR_RENDER([self.child])
|
||||
|
||||
|
||||
def simplified(self):
|
||||
""" Get the simplified version of the expression """
|
||||
""" Compute entirely the expression and return the result with .steps attribute """
|
||||
self.compute_exp()
|
||||
try:
|
||||
return self.child.simplified()
|
||||
except AttributeError:
|
||||
return self.child
|
||||
|
||||
def can_go_further(self):
|
||||
"""Check whether it's a last step or not. If not create self.child the next expression.
|
||||
:returns: 1 if it's not the last step, 0 otherwise
|
||||
"""
|
||||
if len(self.postfix_tokens) == 1:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
self.simplified = self.child.simplify()
|
||||
try:
|
||||
self.simplified.steps = self.child.steps + self.simplified.steps
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return self.simplified
|
||||
|
||||
def compute_exp(self):
|
||||
""" Create self.child with self.steps to go up to it """
|
||||
self.steps = [self.postfix_tokens]
|
||||
""" Create self.child with and stock steps in it """
|
||||
child_steps = [self.postfix_tokens]
|
||||
|
||||
tokenList = self.postfix_tokens.copy()
|
||||
tmpTokenList = []
|
||||
@@ -256,9 +189,10 @@ class Expression(object):
|
||||
steps = expand_list(tmpTokenList)
|
||||
|
||||
if len(steps[:-1]) > 0:
|
||||
self.steps += [flatten_list(s) for s in steps[:-1]]
|
||||
child_steps += [flatten_list(s) for s in steps[:-1]]
|
||||
|
||||
self.child = Expression(steps[-1])
|
||||
self.child.steps = child_steps
|
||||
|
||||
@classmethod
|
||||
def isExpression(self, other):
|
||||
@@ -297,31 +231,83 @@ class Expression(object):
|
||||
return Expression([other] + self.postfix_tokens + [operator])
|
||||
|
||||
def __add__(self, other):
|
||||
""" Overload +
|
||||
|
||||
>>> a = Expression("1+2")
|
||||
>>> print(a.postfix_tokens)
|
||||
[1, 2, '+']
|
||||
>>> b = Expression("3+4")
|
||||
>>> print(b.postfix_tokens)
|
||||
[3, 4, '+']
|
||||
>>> c = a + b
|
||||
>>> print(c.postfix_tokens)
|
||||
[1, 2, '+', 3, 4, '+', '+']
|
||||
"""
|
||||
return self.operate(other, op.add)
|
||||
|
||||
def __radd__(self, other):
|
||||
return self.roperate(other, op.add)
|
||||
|
||||
def __sub__(self, other):
|
||||
""" Overload -
|
||||
|
||||
>>> a = Expression("1+2")
|
||||
>>> print(a.postfix_tokens)
|
||||
[1, 2, '+']
|
||||
>>> b = Expression("3+4")
|
||||
>>> print(b.postfix_tokens)
|
||||
[3, 4, '+']
|
||||
>>> c = a - b
|
||||
>>> print(c.postfix_tokens)
|
||||
[1, 2, '+', 3, 4, '+', '-']
|
||||
"""
|
||||
return self.operate(other, op.sub)
|
||||
|
||||
def __rsub__(self, other):
|
||||
return self.roperate(other, op.sub)
|
||||
|
||||
def __mul__(self, other):
|
||||
""" Overload *
|
||||
|
||||
>>> a = Expression("1+2")
|
||||
>>> print(a.postfix_tokens)
|
||||
[1, 2, '+']
|
||||
>>> b = Expression("3+4")
|
||||
>>> print(b.postfix_tokens)
|
||||
[3, 4, '+']
|
||||
>>> c = a * b
|
||||
>>> print(c.postfix_tokens)
|
||||
[1, 2, '+', 3, 4, '+', '*']
|
||||
"""
|
||||
return self.operate(other, op.mul)
|
||||
|
||||
def __rmul__(self, other):
|
||||
return self.roperate(other, op.mul)
|
||||
|
||||
def __div__(self, other):
|
||||
def __truediv__(self, other):
|
||||
""" Overload /
|
||||
|
||||
>>> a = Expression("1+2")
|
||||
>>> print(a.postfix_tokens)
|
||||
[1, 2, '+']
|
||||
>>> b = Expression("3+4")
|
||||
>>> print(b.postfix_tokens)
|
||||
[3, 4, '+']
|
||||
>>> c = a / b
|
||||
>>> print(c.postfix_tokens)
|
||||
[1, 2, '+', 3, 4, '+', '/']
|
||||
>>>
|
||||
"""
|
||||
return self.operate(other, op.div)
|
||||
|
||||
def __rdiv__(self, other):
|
||||
def __rtruediv__(self, other):
|
||||
return self.roperate(other, op.div)
|
||||
|
||||
def __pow__(self, other):
|
||||
return self.operate(other, op.pow)
|
||||
return self.operate(other, op.pw)
|
||||
|
||||
def __xor__(self, other):
|
||||
return self.operate(other, op.pw)
|
||||
|
||||
def __neg__(self):
|
||||
return Expression(self.postfix_tokens + [op.sub1])
|
||||
@@ -329,9 +315,10 @@ class Expression(object):
|
||||
|
||||
def test(exp):
|
||||
a = Expression(exp)
|
||||
print(a)
|
||||
for i in a.simplify():
|
||||
print(type(i))
|
||||
b = a.simplify()
|
||||
|
||||
for i in b.explain():
|
||||
#print(type(i))
|
||||
print(i)
|
||||
|
||||
#print(type(a.simplified()), ":", a.simplified())
|
||||
|
@@ -5,12 +5,14 @@ from .arithmetic import gcd
|
||||
from .generic import isNumber
|
||||
from .operator import op
|
||||
from .expression import Expression
|
||||
from .explicable import Explicable
|
||||
from .render import txt, tex
|
||||
from copy import copy
|
||||
|
||||
|
||||
__all__ = ['Fraction']
|
||||
|
||||
class Fraction(object):
|
||||
class Fraction(Explicable):
|
||||
"""Fractions!"""
|
||||
|
||||
def __init__(self, num, denom = 1):
|
||||
@@ -20,6 +22,7 @@ class Fraction(object):
|
||||
:param denom: the denominator
|
||||
|
||||
"""
|
||||
super(Fraction, self).__init__()
|
||||
self._num = num
|
||||
self._denom = denom
|
||||
|
||||
@@ -32,44 +35,57 @@ class Fraction(object):
|
||||
|
||||
>>> f = Fraction(3, 6)
|
||||
>>> f.simplify()
|
||||
[< Expression [1, 3, '*', 2, 3, '*', '/']>, < Fraction 1 / 2>]
|
||||
< Fraction 1 / 2>
|
||||
>>> for i in f.simplify().explain():
|
||||
... print(i)
|
||||
\\frac{ 3 }{ 6 }
|
||||
\\frac{ 1 \\times 3 }{ 2 \\times 3 }
|
||||
\\frac{ 1 }{ 2 }
|
||||
>>> f = Fraction(6,9)
|
||||
>>> f.simplify()
|
||||
< Fraction 2 / 3>
|
||||
>>> for i in f.simplify().explain():
|
||||
... print(i)
|
||||
\\frac{ 6 }{ 9 }
|
||||
\\frac{ 2 \\times 3 }{ 3 \\times 3 }
|
||||
\\frac{ 2 }{ 3 }
|
||||
>>> f = Fraction(0,3)
|
||||
>>> f.simplify()
|
||||
[0]
|
||||
0
|
||||
|
||||
"""
|
||||
steps = []
|
||||
ini_step = [Expression(self.postfix_tokens)]
|
||||
|
||||
if self._num == 0:
|
||||
steps.append(0)
|
||||
return Expression([0])
|
||||
|
||||
return steps
|
||||
|
||||
if self._denom < 0:
|
||||
elif self._denom < 0:
|
||||
n_frac = Fraction(-self._num, -self._denom)
|
||||
steps.append(n_frac)
|
||||
else:
|
||||
n_frac = self
|
||||
ans = n_frac.simplify()
|
||||
ans.steps = ini_step + ans.steps
|
||||
return ans
|
||||
|
||||
gcd_ = gcd(abs(n_frac._num), abs(n_frac._denom))
|
||||
if gcd_ == n_frac._denom:
|
||||
n_frac = n_frac._num // gcd_
|
||||
steps.append(n_frac)
|
||||
gcd_ = gcd(abs(self._num), abs(self._denom))
|
||||
if gcd_ == self._denom:
|
||||
n_frac = self._num // gcd_
|
||||
return Expression([n_frac])
|
||||
|
||||
elif gcd_ != 1:
|
||||
n_frac = Fraction(n_frac._num // gcd_ , n_frac._denom // gcd_)
|
||||
steps.append(Expression([n_frac._num, gcd_, op.mul, n_frac._denom, gcd_, op.mul, op.div ]))
|
||||
n_frac = Fraction(self._num // gcd_ , self._denom // gcd_)
|
||||
ini_step += [Expression([n_frac._num, gcd_, op.mul, n_frac._denom, gcd_, op.mul, op.div ])]
|
||||
|
||||
steps.append(n_frac)
|
||||
n_frac.steps = ini_step + n_frac.steps
|
||||
return n_frac
|
||||
|
||||
return steps
|
||||
else:
|
||||
return self
|
||||
|
||||
@property
|
||||
def postfix(self):
|
||||
def postfix_tokens(self):
|
||||
"""Postfix form of the fraction
|
||||
|
||||
>>> f = Fraction(3, 5)
|
||||
>>> f.postfix
|
||||
>>> f.postfix_tokens
|
||||
[3, 5, '/']
|
||||
|
||||
"""
|
||||
@@ -79,7 +95,7 @@ class Fraction(object):
|
||||
return [self._num, self._denom, op.div]
|
||||
|
||||
def __str__(self):
|
||||
return str(Expression(self.postfix))
|
||||
return str(Expression(self.postfix_tokens))
|
||||
|
||||
def __repr__(self):
|
||||
return "< Fraction {num} / {denom}>".format(num=self._num, denom = self._denom)
|
||||
@@ -95,10 +111,10 @@ class Fraction(object):
|
||||
def __tex__(self):
|
||||
old_render = Expression.get_render()
|
||||
Expression.set_render(tex)
|
||||
_txt = self.__str__()
|
||||
_tex = self.__str__()
|
||||
Expression.set_render(old_render)
|
||||
|
||||
return _txt
|
||||
return _tex
|
||||
|
||||
def __float__(self):
|
||||
return self._num / self._denom
|
||||
@@ -119,18 +135,28 @@ class Fraction(object):
|
||||
>>> f = Fraction(1, 2)
|
||||
>>> g = Fraction(2, 3)
|
||||
>>> f + g
|
||||
[< Expression [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '+']>, < Expression [3, 6, '/', 4, 6, '/', '+']>, < Expression [< Fraction 3 / 6>, < Fraction 4 / 6>, '+']>, < Expression [3, 4, '+', 6, '/']>, < Expression [7, 6, '/']>, < Fraction 7 / 6>]
|
||||
< Fraction 7 / 6>
|
||||
>>> (f+g).steps
|
||||
[< <class 'pymath.expression.Expression'> [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>, '+']]
|
||||
>>> f + 2
|
||||
[< Expression [1, 1, '*', 2, 1, '*', '/', 2, 2, '*', 1, 2, '*', '/', '+']>, < Expression [1, 2, '/', 4, 2, '/', '+']>, < Expression [< Fraction 1 / 2>, < Fraction 4 / 2>, '+']>, < Expression [1, 4, '+', 2, '/']>, < Expression [5, 2, '/']>, < Fraction 5 / 2>]
|
||||
< Fraction 5 / 2>
|
||||
>>> (f+2).steps
|
||||
[< <class 'pymath.expression.Expression'> [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>, '+']]
|
||||
>>> f = Fraction(3, 4)
|
||||
>>> g = Fraction(5, 4)
|
||||
>>> f + g
|
||||
[< Expression [3, 5, '+', 4, '/']>, < Expression [8, 4, '/']>, 2]
|
||||
2
|
||||
>>> (f+g).steps
|
||||
[< <class 'pymath.expression.Expression'> [3, 4, '/', 5, 4, '/', '+'] >, [3, 5, '+', 4, '/'], [8, 4, '/']]
|
||||
>>> f+0
|
||||
< Fraction 3 / 4>
|
||||
>>> (f+0).steps
|
||||
[]
|
||||
|
||||
"""
|
||||
|
||||
if other == 0:
|
||||
return [self]
|
||||
return copy(self)
|
||||
|
||||
number = self.convert2fraction(other)
|
||||
|
||||
@@ -148,14 +174,14 @@ class Fraction(object):
|
||||
|
||||
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])
|
||||
|
||||
with Expression.tmp_render():
|
||||
steps = list(exp.simplify())
|
||||
|
||||
return steps
|
||||
ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.add])
|
||||
ans = exp.simplify()
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __radd__(self, other):
|
||||
if other == 0:
|
||||
return [self]
|
||||
return Expression(self.postfix_tokens)
|
||||
|
||||
number = self.convert2fraction(other)
|
||||
|
||||
@@ -167,11 +193,17 @@ class Fraction(object):
|
||||
>>> f = Fraction(1, 2)
|
||||
>>> g = Fraction(2, 3)
|
||||
>>> f - g
|
||||
[< Expression [1, 3, '*', 2, 3, '*', '/', 2, 2, '*', 3, 2, '*', '/', '-']>, < Expression [3, 6, '/', 4, 6, '/', '-']>, < Expression [< Fraction 3 / 6>, < Fraction 4 / 6>, '-']>, < Expression [3, 4, '-', 6, '/']>, < Expression [-1, 6, '/']>, < Fraction -1 / 6>]
|
||||
< Fraction -1 / 6>
|
||||
>>> (f-g).steps
|
||||
[< <class 'pymath.expression.Expression'> [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>, '-']]
|
||||
>>> f - 0
|
||||
< Fraction 1 / 2>
|
||||
>>> (f-0).steps
|
||||
[]
|
||||
|
||||
"""
|
||||
if other == 0:
|
||||
return [self]
|
||||
return copy(self)
|
||||
|
||||
number = self.convert2fraction(other)
|
||||
|
||||
@@ -189,38 +221,40 @@ class Fraction(object):
|
||||
|
||||
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.sub])
|
||||
|
||||
with Expression.tmp_render():
|
||||
steps = list(exp.simplify())
|
||||
|
||||
return steps
|
||||
ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.sub])
|
||||
ans = exp.simplify()
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __rsub__(self, other):
|
||||
if other == 0:
|
||||
return [self]
|
||||
return copy(self)
|
||||
|
||||
number = self.convert2fraction(other)
|
||||
|
||||
return number - self
|
||||
|
||||
def __neg__(self):
|
||||
""" overload - (as arity 1 operator
|
||||
""" overload - (as arity 1 operator)
|
||||
|
||||
>>> f = Fraction(1, 2)
|
||||
>>> -f
|
||||
[< Fraction -1 / 2>]
|
||||
< Fraction -1 / 2>
|
||||
>>> (-f).steps
|
||||
[]
|
||||
>>> f = Fraction(1, -2)
|
||||
>>> f
|
||||
< Fraction 1 / -2>
|
||||
>>> -f
|
||||
[< Fraction -1 / -2>, < Fraction 1 / 2>]
|
||||
< Fraction 1 / 2>
|
||||
>>> (-f).steps
|
||||
[< <class 'pymath.expression.Expression'> [-1, -2, '/'] >]
|
||||
|
||||
"""
|
||||
f = Fraction(-self._num, self._denom)
|
||||
ans = f.simplify()
|
||||
|
||||
with Expression.tmp_render():
|
||||
steps = [f] + f.simplify()
|
||||
|
||||
return steps
|
||||
return ans
|
||||
|
||||
def __mul__(self, other):
|
||||
""" overload *
|
||||
@@ -228,21 +262,29 @@ class Fraction(object):
|
||||
>>> f = Fraction(1, 2)
|
||||
>>> g = Fraction(2, 3)
|
||||
>>> f*g
|
||||
[< Expression [1, 1, 2, '*', '*', 1, 2, '*', 3, '*', '/']>, < Expression [1, 2, '*', 2, 3, '*', '/']>, < Expression [2, 6, '/']>, < Expression [1, 2, '*', 3, 2, '*', '/']>, < Fraction 1 / 3>]
|
||||
< Fraction 1 / 3>
|
||||
>>> (f*g).steps
|
||||
[< <class 'pymath.expression.Expression'> [1, 2, '/', 2, 3, '/', '*'] >, [1, 1, 2, '*', '*', 1, 2, '*', 3, '*', '/'], [1, 2, '*', 2, 3, '*', '/'], [2, 6, '/'], < <class 'pymath.expression.Expression'> [2, 6, '/'] >, < <class 'pymath.expression.Expression'> [1, 2, '*', 3, 2, '*', '/'] >]
|
||||
>>> f * 0
|
||||
[0]
|
||||
0
|
||||
>>> (f*0).steps
|
||||
[]
|
||||
>>> f*1
|
||||
[< Fraction 1 / 2>]
|
||||
< Fraction 1 / 2>
|
||||
>>> (f*1).steps
|
||||
[]
|
||||
>>> f*4
|
||||
[< Expression [1, 2, '*', 2, '*', 1, 2, '*', '/']>, < Expression [2, 2, '*', 2, '/']>, < Expression [4, 2, '/']>, 2]
|
||||
2
|
||||
>>> (f*4).steps
|
||||
[< <class 'pymath.expression.Expression'> [1, 2, '/', 4, '*'] >, [1, 2, '*', 2, '*', 1, 2, '*', '/'], [2, 2, '*', 2, '/'], [4, 2, '/']]
|
||||
|
||||
"""
|
||||
steps = []
|
||||
|
||||
if other == 0:
|
||||
return [0]
|
||||
return Expression([0])
|
||||
elif other == 1:
|
||||
return [self]
|
||||
return copy(self)
|
||||
|
||||
# TODO: Changer dans le cas où il y a trop de 1 |dim. déc. 28 10:44:10 CET 2014
|
||||
|
||||
@@ -256,6 +298,7 @@ class Fraction(object):
|
||||
denom = [self._denom]
|
||||
|
||||
exp = Expression(num + denom + [op.div])
|
||||
ini_step = Expression(self.postfix_tokens + [other, op.mul])
|
||||
|
||||
else:
|
||||
number = self.convert2fraction(other)
|
||||
@@ -279,28 +322,45 @@ class Fraction(object):
|
||||
|
||||
exp = Expression(num1 + num2 + [ op.mul] + denom1 + denom2 + [op.mul, op.div])
|
||||
|
||||
with Expression.tmp_render():
|
||||
steps = list(exp.simplify())
|
||||
|
||||
return steps
|
||||
ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.mul])
|
||||
ans = exp.simplify()
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __rmul__(self, other):
|
||||
return self * other
|
||||
|
||||
def __truediv__(self, other):
|
||||
""" overload /
|
||||
|
||||
>>> f = Fraction(1,2)
|
||||
>>> g = Fraction(3,4)
|
||||
>>> f / 0
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ZeroDivisionError: division by zero
|
||||
>>> f / 1
|
||||
< Fraction 1 / 2>
|
||||
>>> (f/1).steps
|
||||
[]
|
||||
>>> f / g
|
||||
< Fraction 2 / 3>
|
||||
|
||||
"""
|
||||
if other == 0:
|
||||
raise ZeroDivisionError("division by zero")
|
||||
elif other == 1:
|
||||
return [self]
|
||||
return copy(self)
|
||||
|
||||
number = self.convert2fraction(other)
|
||||
|
||||
steps = []
|
||||
number = Fraction(number._denom, number._num)
|
||||
steps.append(Expression([self, number, op.mul]))
|
||||
steps += self * number
|
||||
ini_step = Expression(self.postfix_tokens + number.postfix_tokens + [op.div])
|
||||
|
||||
return steps
|
||||
number = Fraction(number._denom, number._num)
|
||||
ans = self * number
|
||||
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
number = self.convert2fraction(other)
|
||||
@@ -312,44 +372,51 @@ class Fraction(object):
|
||||
|
||||
>>> f = Fraction(3, 4)
|
||||
>>> f**0
|
||||
[1]
|
||||
1
|
||||
>>> (f**0).steps
|
||||
[]
|
||||
>>> f**1
|
||||
[< Fraction 3 / 4>]
|
||||
< Fraction 3 / 4>
|
||||
>>> (f**1).steps
|
||||
[]
|
||||
>>> f**3
|
||||
[< Expression [3, 3, '^', 4, 3, '^', '/']>, < Expression [27, 64, '/']>, < Fraction 27 / 64>]
|
||||
< Fraction 27 / 64>
|
||||
>>> (f**3).steps
|
||||
[< <class 'pymath.expression.Expression'> [3, 4, '/', 3, '^'] >, [3, 3, '^', 4, 3, '^', '/'], [27, 64, '/'], [27, 64, '/']]
|
||||
>>> f = Fraction(6, 4)
|
||||
>>> f**3
|
||||
[< Expression [6, 3, '^', 4, 3, '^', '/']>, < Expression [216, 64, '/']>, < Expression [27, 8, '*', 8, 8, '*', '/']>, < Fraction 27 / 8>]
|
||||
< Fraction 27 / 8>
|
||||
>>> (f**3).steps
|
||||
[< <class 'pymath.expression.Expression'> [6, 4, '/', 3, '^'] >, [6, 3, '^', 4, 3, '^', '/'], [216, 64, '/'], < <class 'pymath.expression.Expression'> [216, 64, '/'] >, < <class 'pymath.expression.Expression'> [27, 8, '*', 8, 8, '*', '/'] >]
|
||||
|
||||
"""
|
||||
if not type(power) == int:
|
||||
raise ValueError("Can't raise fraction to power {}".format(str(power)))
|
||||
|
||||
if power == 0:
|
||||
return [1]
|
||||
return Expression([1])
|
||||
elif power == 1:
|
||||
return [self]
|
||||
return copy(self)
|
||||
else:
|
||||
ini_step = Expression(self.postfix_tokens + [power, op.pw])
|
||||
exp = Expression([self._num, power, op.pw, self._denom, power, op.pw, op.div])
|
||||
with Expression.tmp_render():
|
||||
steps = list(exp.simplify())
|
||||
return steps
|
||||
|
||||
ans = exp.simplify()
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __xor__(self, power):
|
||||
""" overload ^
|
||||
|
||||
Work like **
|
||||
|
||||
>>> f = Fraction(3, 4)
|
||||
>>> f^0
|
||||
[1]
|
||||
1
|
||||
>>> f^1
|
||||
[< Fraction 3 / 4>]
|
||||
< Fraction 3 / 4>
|
||||
>>> f^3
|
||||
[< Expression [3, 3, '^', 4, 3, '^', '/']>, < Expression [27, 64, '/']>, < Fraction 27 / 64>]
|
||||
>>> f = Fraction(6, 4)
|
||||
>>> f^3
|
||||
[< Expression [6, 3, '^', 4, 3, '^', '/']>, < Expression [216, 64, '/']>, < Expression [27, 8, '*', 8, 8, '*', '/']>, < Fraction 27 / 8>]
|
||||
|
||||
< Fraction 27 / 64>
|
||||
"""
|
||||
|
||||
return self.__pow__(power)
|
||||
@@ -382,17 +449,22 @@ class Fraction(object):
|
||||
""" >= """
|
||||
return float(self) >= float(other)
|
||||
|
||||
def __copy__(self):
|
||||
""" Copying the fraction removing steps where it is from """
|
||||
return Fraction(self._num, self._denom)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#f = Fraction(1, 12)
|
||||
#g = Fraction(1, 12)
|
||||
#h = Fraction(1,-5)
|
||||
#t = Fraction(10,3)
|
||||
#print("---------")
|
||||
#print("1 + ", str(h))
|
||||
#for i in (1 + h):
|
||||
# print(i)
|
||||
f = Fraction(1, 12)
|
||||
g = Fraction(6, 12)
|
||||
for i in g.simplify().explain():
|
||||
print("g = ",i)
|
||||
h = Fraction(1,-5)
|
||||
t = Fraction(10,3)
|
||||
print("---------")
|
||||
for i in (0 + h).explain():
|
||||
print('0 + h = ',i)
|
||||
#print("---------")
|
||||
#print(str(f) , "+", str(t))
|
||||
#for i in (f + t):
|
||||
|
@@ -3,11 +3,13 @@
|
||||
|
||||
|
||||
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
|
||||
from .render import txt
|
||||
from .random_expression import RdExpression
|
||||
from itertools import chain
|
||||
from functools import wraps
|
||||
|
||||
__all__ = ["Polynom"]
|
||||
|
||||
@@ -15,6 +17,7 @@ __all__ = ["Polynom"]
|
||||
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():
|
||||
@@ -25,7 +28,7 @@ def power_cache(fun):
|
||||
return poly_powered
|
||||
return cached_fun
|
||||
|
||||
class Polynom(object):
|
||||
class Polynom(Explicable):
|
||||
|
||||
"""Docstring for Polynom. """
|
||||
|
||||
@@ -41,19 +44,19 @@ class Polynom(object):
|
||||
/!\ variables need to be in brackets {}
|
||||
|
||||
>>> Polynom.random(["{b}", "{a}"]) # doctest:+ELLIPSIS
|
||||
...
|
||||
< Polynom ...
|
||||
>>> Polynom.random(degree = 2) # doctest:+ELLIPSIS
|
||||
...
|
||||
< Polynom ...
|
||||
>>> 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):
|
||||
# Générer assez de lettre pour les coefs
|
||||
coefs_name = map(chr, range(97, 98+degree))
|
||||
coefs_form = ["{" + i + "}" for i in coefs_name].reverse()
|
||||
coefs_form = ["{" + i + "}" for i in coefs_name][::-1]
|
||||
|
||||
form = str(coefs_form)
|
||||
# On créé les valeurs toutes concaténées dans un string
|
||||
@@ -82,6 +85,7 @@ class Polynom(object):
|
||||
>>> Polynom([1, 2, 3], "y")._letter
|
||||
'y'
|
||||
"""
|
||||
super(Polynom, self).__init__()
|
||||
self.feed_coef(coef)
|
||||
self._letter = letter
|
||||
|
||||
@@ -100,9 +104,9 @@ class Polynom(object):
|
||||
|
||||
"""
|
||||
if isNumber(value):
|
||||
postfix_exp = [value if i==self._letter else i for i in self.postfix]
|
||||
postfix_exp = [value if i==self._letter else i for i in self.postfix_tokens]
|
||||
else:
|
||||
postfix_exp = [Expression(value) if i==self._letter else i for i in self.postfix]
|
||||
postfix_exp = [Expression(value) if i==self._letter else i for i in self.postfix_tokens]
|
||||
|
||||
return Expression(postfix_exp)
|
||||
|
||||
@@ -147,11 +151,17 @@ class Polynom(object):
|
||||
return 0
|
||||
|
||||
def __str__(self):
|
||||
return str(Expression(self.postfix))
|
||||
return str(Expression(self.postfix_tokens))
|
||||
|
||||
def __repr__(self):
|
||||
return "< Polynom " + str(self._coef) + ">"
|
||||
|
||||
def __txt__(self):
|
||||
return self.postfix_tokens
|
||||
|
||||
def __tex__(self):
|
||||
return self.postfix_tokens
|
||||
|
||||
def coef_postfix(self, a, i):
|
||||
"""Return the postfix display of a coeficient
|
||||
|
||||
@@ -188,37 +198,45 @@ class Polynom(object):
|
||||
return ans
|
||||
|
||||
@property
|
||||
def postfix(self):
|
||||
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
|
||||
>>> p.postfix_tokens
|
||||
[2, 'x', '*', 1, '+']
|
||||
>>> p = Polynom([1, -2])
|
||||
>>> p.postfix
|
||||
>>> p.postfix_tokens
|
||||
[2, 'x', '*', '-', 1, '+']
|
||||
>>> p = Polynom([1,2,3])
|
||||
>>> p.postfix
|
||||
>>> 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
|
||||
>>> p.postfix_tokens
|
||||
[2, 'x', '*', 3, 'x', '*', '+', 1, '+']
|
||||
>>> p = Polynom([1,[2,-3]])
|
||||
>>> p.postfix
|
||||
>>> p.postfix_tokens
|
||||
[2, 'x', '*', 3, 'x', '*', '-', 1, '+']
|
||||
>>> p = Polynom([1,[-2,-3]])
|
||||
>>> p.postfix
|
||||
>>> 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
|
||||
>>> 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]:
|
||||
@@ -286,7 +304,15 @@ class Polynom(object):
|
||||
return flatten_list(postfix)
|
||||
|
||||
def conv2poly(self, other):
|
||||
"""Convert anything number into a polynom"""
|
||||
"""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):
|
||||
@@ -298,8 +324,23 @@ class Polynom(object):
|
||||
"""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 [< <class 'pymath.expression.Expression'> [1, 2, '+'] >, < <class 'pymath.expression.Expression'> [3, 4, '+', 5, '+'] >, 6]>, < Polynom [< <class 'pymath.expression.Expression'> [1, 2, '+'] >, < <class 'pymath.expression.Expression'> [7, 5, '+'] >, 6]>, < Polynom [3, < <class 'pymath.expression.Expression'> [7, 5, '+'] >, 6]>]
|
||||
"""
|
||||
steps = []
|
||||
|
||||
# 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:
|
||||
@@ -311,20 +352,20 @@ class Polynom(object):
|
||||
coef_exp = Expression(postfix_add)
|
||||
|
||||
with Expression.tmp_render():
|
||||
coef_steps = list(coef_exp.simplify())
|
||||
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())
|
||||
coef_steps = list(coef.simplify().explain())
|
||||
|
||||
#print('\t 2.coef_steps -> ', coef_steps)
|
||||
|
||||
else:
|
||||
try:
|
||||
coef_steps += coef.simplify()
|
||||
coef_steps += coef.simplify().explaine()
|
||||
except AttributeError:
|
||||
coef_steps = [coef]
|
||||
|
||||
@@ -335,9 +376,12 @@ class Polynom(object):
|
||||
#print('\t coefs_steps -> ', coefs_steps)
|
||||
|
||||
# On retourne la matrice
|
||||
ans = []
|
||||
steps = []
|
||||
for coefs in transpose_fill(coefs_steps):
|
||||
ans.append(Polynom(coefs, self._letter))
|
||||
steps.append(Polynom(coefs, self._letter))
|
||||
|
||||
ans, steps = steps[-1], steps[:-1]
|
||||
ans.steps = steps
|
||||
|
||||
return ans
|
||||
|
||||
@@ -375,53 +419,98 @@ class Polynom(object):
|
||||
return 0
|
||||
|
||||
def __add__(self, other):
|
||||
steps = []
|
||||
""" Overload +
|
||||
|
||||
>>> P = Polynom([1,2,3])
|
||||
>>> Q = Polynom([4,5])
|
||||
>>> R = P+Q
|
||||
>>> R
|
||||
< Polynom [5, 7, 3]>
|
||||
>>> R.steps
|
||||
[< <class 'pymath.expression.Expression'> [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 5, 'x', '*', 4, '+', '+'] >, < Polynom [< <class 'pymath.expression.Expression'> [1, 4, '+'] >, < <class 'pymath.expression.Expression'> [2, 5, '+'] >, 3]>, < Polynom [< <class 'pymath.expression.Expression'> [1, 4, '+'] >, < <class 'pymath.expression.Expression'> [2, 5, '+'] >, 3]>]
|
||||
"""
|
||||
o_poly = self.conv2poly(other)
|
||||
|
||||
n_coef = spe_zip(self._coef, o_poly._coef)
|
||||
p = Polynom(n_coef, letter = self._letter)
|
||||
steps.append(p)
|
||||
|
||||
steps += p.simplify()
|
||||
return steps
|
||||
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):
|
||||
return self.__add__(other)
|
||||
o_poly = self.conv2poly(other)
|
||||
return o_poly.__add__(self)
|
||||
|
||||
def __neg__(self):
|
||||
return Polynom([-i for i in self._coef], letter = self._letter)
|
||||
""" overload - (as arity 1 operator)
|
||||
|
||||
>>> P = Polynom([1,2,3])
|
||||
>>> Q = -P
|
||||
>>> Q
|
||||
< Polynom [-1, -2, -3]>
|
||||
>>> Q.steps
|
||||
[< <class 'pymath.expression.Expression'> [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):
|
||||
o_poly = self.conv2poly(other)
|
||||
o_poly = -o_poly
|
||||
""" overload -
|
||||
|
||||
return self.__add__(o_poly)
|
||||
>>> P = Polynom([1,2,3])
|
||||
>>> Q = Polynom([4,5,6])
|
||||
>>> R = P - Q
|
||||
>>> R
|
||||
< Polynom [-3, -3, -3]>
|
||||
>>> R.steps
|
||||
[< <class 'pymath.expression.Expression'> [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', 5, 'x', '*', '+', 4, '+', '-'] >, < <class 'pymath.expression.Expression'> [3, 'x', 2, '^', '*', 2, 'x', '*', '+', 1, '+', 6, 'x', 2, '^', '*', '-', 5, 'x', '*', '-', 4, '-', '+'] >, < Polynom [< <class 'pymath.expression.Expression'> [1, -4, '+'] >, < <class 'pymath.expression.Expression'> [2, -5, '+'] >, < <class 'pymath.expression.Expression'> [3, -6, '+'] >]>, < Polynom [< <class 'pymath.expression.Expression'> [1, -4, '+'] >, < <class 'pymath.expression.Expression'> [2, -5, '+'] >, < <class 'pymath.expression.Expression'> [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)
|
||||
return o_poly.__sub__(self)
|
||||
|
||||
def __mul__(self, other):
|
||||
""" Overload *
|
||||
|
||||
>>> p = Polynom([1,2])
|
||||
>>> p*3
|
||||
[< Polynom [3, < Expression [2, 3, '*']>]>, < Polynom [3, < Expression [2, 3, '*']>]>, < Polynom [3, 6]>]
|
||||
< Polynom [3, 6]>
|
||||
>>> (p*3).steps
|
||||
[[< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 3, '*'] >], < Polynom [3, < <class 'pymath.expression.Expression'> [2, 3, '*'] >]>, < Polynom [3, < <class 'pymath.expression.Expression'> [2, 3, '*'] >]>]
|
||||
>>> q = Polynom([0,0,4])
|
||||
>>> q*3
|
||||
[< Polynom [0, 0, < Expression [4, 3, '*']>]>, < Polynom [0, 0, < Expression [4, 3, '*']>]>, < Polynom [0, 0, 12]>]
|
||||
< Polynom [0, 0, 12]>
|
||||
>>> (q*3).steps
|
||||
[[< <class 'pymath.expression.Expression'> [4, 'x', 2, '^', '*', 3, '*'] >], < Polynom [0, 0, < <class 'pymath.expression.Expression'> [4, 3, '*'] >]>, < Polynom [0, 0, < <class 'pymath.expression.Expression'> [4, 3, '*'] >]>]
|
||||
>>> r = Polynom([0,1])
|
||||
>>> r*3
|
||||
[< Polynom [0, 3]>, < Polynom [0, 3]>]
|
||||
< Polynom [0, 3]>
|
||||
>>> (r*3).steps
|
||||
[[< <class 'pymath.expression.Expression'> ['x', 3, '*'] >]]
|
||||
>>> p*q
|
||||
[< Polynom [0, 0, 4, < Expression [2, 4, '*']>]>, < Polynom [0, 0, 4, < Expression [2, 4, '*']>]>, < Polynom [0, 0, 4, 8]>]
|
||||
< Polynom [0, 0, 4, 8]>
|
||||
>>> (p*q).steps
|
||||
[[< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 4, 'x', 2, '^', '*', '*'] >], < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>, < Polynom [0, 0, 4, < <class 'pymath.expression.Expression'> [2, 4, '*'] >]>]
|
||||
>>> p*r
|
||||
[< Polynom [0, 1, 2]>, < Polynom [0, 1, 2]>]
|
||||
< Polynom [0, 1, 2]>
|
||||
|
||||
"""
|
||||
steps = []
|
||||
# TODO: Je trouve qu'elle grille trop d'étapes... |ven. févr. 27 19:08:44 CET 2015
|
||||
o_poly = self.conv2poly(other)
|
||||
|
||||
coefs = []
|
||||
@@ -444,13 +533,11 @@ class Polynom(object):
|
||||
coefs.append(elem)
|
||||
|
||||
p = Polynom(coefs, letter = self._letter)
|
||||
steps.append(p)
|
||||
ini_step = [Expression(self.postfix_tokens + o_poly.postfix_tokens + [op.mul])]
|
||||
ans = p.simplify()
|
||||
|
||||
steps += p.simplify()
|
||||
|
||||
#print("steps -> \n", "\n".join(["\t {}".format(s.postfix) for s in steps]))
|
||||
|
||||
return steps
|
||||
ans.steps = [ini_step] + ans.steps
|
||||
return ans
|
||||
|
||||
def __rmul__(self, other):
|
||||
o_poly = self.conv2poly(other)
|
||||
@@ -463,39 +550,42 @@ class Polynom(object):
|
||||
|
||||
>>> p = Polynom([0,0,3])
|
||||
>>> p**2
|
||||
[< Polynom [0, 0, 0, 0, < Expression [3, 2, '^']>]>, < Polynom [0, 0, 0, 0, < Expression [3, 2, '^']>]>, < Polynom [0, 0, 0, 0, 9]>, < Polynom [0, 0, 0, 0, 9]>]
|
||||
< Polynom [0, 0, 0, 0, 9]>
|
||||
>>> (p**2).steps
|
||||
[< <class 'pymath.expression.Expression'> [3, 'x', 2, '^', '*', 2, '^'] >, < Polynom [0, 0, 0, 0, < <class 'pymath.expression.Expression'> [3, 2, '^'] >]>, < Polynom [0, 0, 0, 0, < <class 'pymath.expression.Expression'> [3, 2, '^'] >]>]
|
||||
>>> p = Polynom([1,2])
|
||||
>>> p**2
|
||||
[[< Polynom [1, 2]>, < Polynom [1, 2]>, '*'], < Polynom [< Expression [1, 1, '*']>, [< Expression [1, 2, '*']>, < Expression [2, 1, '*']>], < Expression [2, 2, '*']>]>, < Polynom [< Expression [1, 1, '*']>, < Expression [1, 2, '*', 2, 1, '*', '+']>, < Expression [2, 2, '*']>]>, < Polynom [1, < Expression [2, 2, '+']>, 4]>, < Polynom [1, 4, 4]>]
|
||||
< Polynom [1, 4, 4]>
|
||||
>>> (p**2).steps
|
||||
[< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 2, '^'] >, [< <class 'pymath.expression.Expression'> [2, 'x', '*', 1, '+', 2, 'x', '*', 1, '+', '*'] >], < Polynom [1, < <class 'pymath.expression.Expression'> [2, 2, '+'] >, < <class 'pymath.expression.Expression'> [2, 2, '*'] >]>, < Polynom [1, < <class 'pymath.expression.Expression'> [2, 2, '+'] >, < <class 'pymath.expression.Expression'> [2, 2, '*'] >]>]
|
||||
>>> p = Polynom([0,0,1])
|
||||
>>> p**3
|
||||
[< Polynom [0, 0, 0, 0, 0, 0, 1]>]
|
||||
|
||||
< Polynom [0, 0, 0, 0, 0, 0, 1]>
|
||||
|
||||
"""
|
||||
if not type(power):
|
||||
raise ValueError("Can't raise Polynom to {} power".format(str(power)))
|
||||
|
||||
steps = []
|
||||
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)
|
||||
steps.append(p)
|
||||
ans = p
|
||||
else:
|
||||
coefs = [0]*self.degree*power + [Expression([self._coef[self.degree] , power, op.pw])]
|
||||
p = Polynom(coefs, letter = self._letter)
|
||||
steps.append(p)
|
||||
|
||||
steps += p.simplify()
|
||||
ans = p.simplify()
|
||||
else:
|
||||
if power == 2:
|
||||
return [[self, self, op.mul]] + self * self
|
||||
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")
|
||||
|
||||
return steps
|
||||
ans.steps = ini_step + ans.steps
|
||||
return ans
|
||||
|
||||
def __xor__(self, power):
|
||||
return self.__pow__(power)
|
||||
@@ -513,19 +603,19 @@ def test(p,q):
|
||||
print(p, "+", q)
|
||||
for i in (p + q):
|
||||
#print(repr(i))
|
||||
#print("\t", str(i.postfix))
|
||||
#print("\t", str(i.postfix_tokens))
|
||||
print(i)
|
||||
|
||||
print("\n Moins ------")
|
||||
for i in (p - q):
|
||||
#print(repr(i))
|
||||
#print("\t", str(i.postfix))
|
||||
#print("\t", str(i.postfix_tokens))
|
||||
print(i)
|
||||
|
||||
print("\n Multiplier ------")
|
||||
for i in (p * q):
|
||||
#print(repr(i))
|
||||
#print("\t", str(i.postfix))
|
||||
#print("\t", str(i.postfix_tokens))
|
||||
print(i)
|
||||
|
||||
print("\n Evaluer p ------")
|
||||
@@ -539,16 +629,27 @@ def test(p,q):
|
||||
|
||||
if __name__ == '__main__':
|
||||
#from .fraction import Fraction
|
||||
with Expression.tmp_render(txt):
|
||||
p = Polynom([10, -5])
|
||||
q = Polynom([3, -9])
|
||||
print(p-q)
|
||||
for i in p-q:
|
||||
print(i)
|
||||
# with Expression.tmp_render(txt):
|
||||
# p = Polynom([1,2,3])
|
||||
# q = Polynom([0, 2])
|
||||
# for i in (p*q).explain():
|
||||
# print(i)
|
||||
# r = Polynom([0,1])
|
||||
# for i in (r*3).explain():
|
||||
# print(i)
|
||||
# print("q = ", q)
|
||||
# r = q.reduce()
|
||||
# print("r = ", r)
|
||||
# for i in r.explain():
|
||||
# print("q = ", i)
|
||||
# print(p-q)
|
||||
# for i in p-q:
|
||||
# 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()
|
||||
doctest.testmod(optionflags=doctest.ELLIPSIS)
|
||||
|
||||
|
||||
# -----------------------------
|
||||
|
@@ -12,7 +12,7 @@ def str2tokens(exp):
|
||||
>>> str2tokens('2*3+4')
|
||||
[2, 3, '*', 4, '+']
|
||||
>>> str2tokens('2x+4')
|
||||
[2, < Polynom [0, 1]>, '*', 1, '+']
|
||||
[2, < Polynom [0, 1]>, '*', 4, '+']
|
||||
"""
|
||||
in_tokens = str2in_tokens(exp)
|
||||
post_tokens = in2post_fix(in_tokens)
|
||||
|
Reference in New Issue
Block a user