Remove old files and fix class name in doctest
This commit is contained in:
parent
a751e346d3
commit
813c1f096e
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from .calculus import Expression, Polynom, Fraction, random_str, txt, Equation
|
#from .calculus import Expression, Polynom, Fraction, random_str, txt, Equation
|
||||||
from .stat import Dataset, WeightedDataset
|
#from .stat import Dataset, WeightedDataset
|
||||||
from .geometry import random_pythagore
|
#from .geometry import random_pythagore
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Reglages pour 'vim'
|
# Reglages pour 'vim'
|
||||||
|
@ -1,754 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .explicable import Explicable
|
|
||||||
from .expression import Expression
|
|
||||||
from .step import Step
|
|
||||||
from .renderable import Renderable
|
|
||||||
from .operator import op
|
|
||||||
from .generic import spe_zip, isNumber, transpose_fill, flatten_list, isPolynom, postfix_op
|
|
||||||
from functools import wraps
|
|
||||||
|
|
||||||
|
|
||||||
def power_cache(fun):
|
|
||||||
"""Decorator which cache calculated powers of polynoms """
|
|
||||||
cache = {}
|
|
||||||
|
|
||||||
@wraps(fun)
|
|
||||||
def cached_fun(self, power):
|
|
||||||
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'
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Remove 0 at the end of the coefs
|
|
||||||
while coefs[-1] == 0:
|
|
||||||
coefs = coefs[:-1]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if coefs == []:
|
|
||||||
coefs = [0]
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
pstf_tokens = self.compute_postfix_tokens()
|
|
||||||
super(AbstractPolynom, self).__init__(pstf_tokens)
|
|
||||||
|
|
||||||
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 isinstance(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 "< {cls} {letter} {coefs}>".format(
|
|
||||||
cls = str(self.__class__).split('.')[-1][:-2],
|
|
||||||
letter = str(self._letter),
|
|
||||||
coefs = str(self._coef))
|
|
||||||
|
|
||||||
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, ^]
|
|
||||||
|
|
||||||
"""
|
|
||||||
if a == [0]:
|
|
||||||
ans = []
|
|
||||||
elif i == 0:
|
|
||||||
ans = a
|
|
||||||
elif i == 1:
|
|
||||||
ans = a * (a not in [[1], [-1]]) + \
|
|
||||||
[self._letter] + \
|
|
||||||
[op.mul] * (a not in [[1], [-1]]) + \
|
|
||||||
[op.sub1] * (a == [-1])
|
|
||||||
else:
|
|
||||||
ans = a * (a not in [[1], [-1]]) + \
|
|
||||||
[self._letter, i, op.pw] + \
|
|
||||||
[op.mul] * (a not in [[1], [-1]]) + \
|
|
||||||
[op.sub1] * (a == [-1])
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def coefs_postifx(self):
|
|
||||||
""" Return list of postfix coef with the the right power letter
|
|
||||||
|
|
||||||
>>> p = AbstractPolynom([1, 2])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [2, 'x', *]]
|
|
||||||
>>> p = AbstractPolynom([1, -2])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [-2, 'x', *]]
|
|
||||||
>>> p = AbstractPolynom([1,2,3])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [2, 'x', *], [3, 'x', 2, ^, *]]
|
|
||||||
>>> p = AbstractPolynom([1])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1]]
|
|
||||||
>>> p = AbstractPolynom([0])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[0]]
|
|
||||||
>>> p = AbstractPolynom([0, 1, 1, 0])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[['x'], ['x', 2, ^]]
|
|
||||||
>>> p = AbstractPolynom([1,[2,3]])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [3, 'x', *], [2, 'x', *]]
|
|
||||||
>>> p = AbstractPolynom([1,[2,-3]])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [-3, 'x', *], [2, 'x', *]]
|
|
||||||
>>> p = AbstractPolynom([1,[-2,-3]])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [-3, 'x', *], [-2, 'x', *]]
|
|
||||||
>>> p = AbstractPolynom([1,[-2,0]])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [-2, 'x', *]]
|
|
||||||
>>> from mapytex.calculus.expression import Expression
|
|
||||||
>>> from mapytex.calculus.operator import op
|
|
||||||
>>> e = Expression([2,3,op.add])
|
|
||||||
>>> p = AbstractPolynom([1,e])
|
|
||||||
>>> p.coefs_postifx()
|
|
||||||
[[1], [2, 3, +, 'x', *]]
|
|
||||||
"""
|
|
||||||
if not [i for i in self._coef if i!= 0]:
|
|
||||||
return [[0]]
|
|
||||||
|
|
||||||
raw_coefs = []
|
|
||||||
for (pw, coef) in enumerate(self._coef):
|
|
||||||
if isinstance(coef, list):
|
|
||||||
for c in coef[::-1]:
|
|
||||||
try:
|
|
||||||
raw_coefs.append(self.coef_postfix(c.postfix_tokens, pw))
|
|
||||||
except AttributeError:
|
|
||||||
raw_coefs.append(self.coef_postfix([c], pw))
|
|
||||||
elif coef != 0:
|
|
||||||
try:
|
|
||||||
raw_coefs.append(self.coef_postfix(coef.postfix_tokens, pw))
|
|
||||||
except AttributeError:
|
|
||||||
raw_coefs.append(self.coef_postfix([coef], pw))
|
|
||||||
|
|
||||||
|
|
||||||
return [i for i in raw_coefs if i != []]
|
|
||||||
|
|
||||||
def compute_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 mapytex.calculus.expression import Expression
|
|
||||||
>>> from mapytex.calculus.operator import op
|
|
||||||
>>> e = Expression([2,3,op.add])
|
|
||||||
>>> p = AbstractPolynom([1,e])
|
|
||||||
>>> p.postfix_tokens
|
|
||||||
[2, 3, +, 'x', *, 1, +]
|
|
||||||
|
|
||||||
"""
|
|
||||||
raw_coefs = self.coefs_postifx()
|
|
||||||
|
|
||||||
pstfx = postfix_op(raw_coefs[::-1], op.add)
|
|
||||||
return flatten_list(pstfx)
|
|
||||||
|
|
||||||
def conv2poly(self, other):
|
|
||||||
"""Convert anything number into a polynom
|
|
||||||
|
|
||||||
>>> P = AbstractPolynom([1,2,3])
|
|
||||||
>>> P.conv2poly(1)
|
|
||||||
< AbstractPolynom x [1]>
|
|
||||||
>>> P.conv2poly(0)
|
|
||||||
< AbstractPolynom x [0]>
|
|
||||||
>>> Q = AbstractPolynom([3, 2, 1], 'x')
|
|
||||||
>>> P.conv2poly(Q)
|
|
||||||
< AbstractPolynom x [3, 2, 1]>
|
|
||||||
>>> Q = AbstractPolynom([3, 2, 1], 'y')
|
|
||||||
>>> P.conv2poly(Q)
|
|
||||||
< AbstractPolynom x [< AbstractPolynom y [3, 2, 1]>]>
|
|
||||||
"""
|
|
||||||
if (isNumber(other) and not isPolynom(other)) or \
|
|
||||||
(isPolynom(other) and self._letter != other._letter):
|
|
||||||
#ans = self.__class__([other], letter=self._letter)
|
|
||||||
ans = AbstractPolynom([other], letter=self._letter)
|
|
||||||
ans.steal_history(other)
|
|
||||||
return ans
|
|
||||||
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 x [1, 2, 3]>
|
|
||||||
>>> Q.steps
|
|
||||||
[< Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +]>, < Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +]>]
|
|
||||||
>>> P = AbstractPolynom([[1,2], [3,4,5], 6])
|
|
||||||
>>> Q = P.reduce()
|
|
||||||
>>> Q
|
|
||||||
< AbstractPolynom x [3, 12, 6]>
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
6 x^{ 2 } + 3 x + 4 x + 5 x + 1 + 2
|
|
||||||
6 x^{ 2 } + ( 3 + 4 + 5 ) x + 1 + 2
|
|
||||||
6 x^{ 2 } + ( 7 + 5 ) x + 3
|
|
||||||
6 x^{ 2 } + 12 x + 3
|
|
||||||
>>> Q.steps
|
|
||||||
[< Step [6, 'x', 2, ^, *, 3, 'x', *, +, 4, 'x', *, +, 5, 'x', *, +, 1, +, 2, +]>, < Step [6, 'x', 2, ^, *, 3, 4, +, 5, +, 'x', *, +, 1, 2, +, +]>, < Step [6, 'x', 2, ^, *, 7, 5, +, 'x', *, +, 3, +]>, < Step [6, 'x', 2, ^, *, 12, 'x', *, +, 3, +]>]
|
|
||||||
>>> P = AbstractPolynom([[1,2], [3,4,5], 6], 'y')
|
|
||||||
>>> Q = P.reduce()
|
|
||||||
>>> Q
|
|
||||||
< AbstractPolynom y [3, 12, 6]>
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
6 y^{ 2 } + 3 y + 4 y + 5 y + 1 + 2
|
|
||||||
6 y^{ 2 } + ( 3 + 4 + 5 ) y + 1 + 2
|
|
||||||
6 y^{ 2 } + ( 7 + 5 ) y + 3
|
|
||||||
6 y^{ 2 } + 12 y + 3
|
|
||||||
>>> P = AbstractPolynom([1,2])
|
|
||||||
>>> Q = AbstractPolynom([P,3], 'y')
|
|
||||||
>>> Q
|
|
||||||
< AbstractPolynom y [< AbstractPolynom x [1, 2]>, 3]>
|
|
||||||
>>> Q = Q.reduce()
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
3 y + 2 x + 1
|
|
||||||
>>> P = AbstractPolynom([1,2])
|
|
||||||
>>> Q = AbstractPolynom([[P,1],3], 'y')
|
|
||||||
>>> Q
|
|
||||||
< AbstractPolynom y [[< AbstractPolynom x [1, 2]>, 1], 3]>
|
|
||||||
>>> Q = Q.reduce()
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
3 y + 2 x + 1 + 1
|
|
||||||
3 y + 2 x + 2
|
|
||||||
"""
|
|
||||||
smpl_coef = []
|
|
||||||
for coef in self._coef:
|
|
||||||
|
|
||||||
if isinstance(coef, list):
|
|
||||||
coef_exp = AbstractPolynom.smpl_coef_list(coef)
|
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
coef_exp = coef.simplify()
|
|
||||||
except AttributeError:
|
|
||||||
coef_exp = coef
|
|
||||||
|
|
||||||
smpl_coef.append(coef_exp)
|
|
||||||
|
|
||||||
ans = AbstractPolynom(smpl_coef, self._letter)
|
|
||||||
|
|
||||||
ini_step = [Step(self)]
|
|
||||||
for s in Explicable.merge_history(smpl_coef):
|
|
||||||
ini_step.append(Step(AbstractPolynom(s, self._letter)))
|
|
||||||
|
|
||||||
ans.this_append_before(
|
|
||||||
ini_step
|
|
||||||
#AbstractPolynom(s)
|
|
||||||
#for s in Expression.develop_steps(smpl_coef)
|
|
||||||
)
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def simplify(self):
|
|
||||||
"""Same as reduce """
|
|
||||||
if isNumber(self._letter):
|
|
||||||
return self.replace_letter(self._letter).simplify()
|
|
||||||
return self.reduce()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def smpl_coef_list(cls, coef_list):
|
|
||||||
""" Simplify the coef when it is a list
|
|
||||||
|
|
||||||
:param coef_list: the list discribing the coef
|
|
||||||
:returns: the simplify coef
|
|
||||||
|
|
||||||
>>> c = AbstractPolynom.smpl_coef_list([1, 2, 3])
|
|
||||||
>>> c
|
|
||||||
6
|
|
||||||
>>> c.steps
|
|
||||||
[< Step [1, 2, +, 3, +]>, < Step [1, 2, +, 3, +]>, < Step [3, 3, +]>, < Step [3, 3, +]>, < Step [6]>]
|
|
||||||
>>> c = AbstractPolynom.smpl_coef_list([Expression('2*2'), 3])
|
|
||||||
>>> c
|
|
||||||
7
|
|
||||||
>>> c.steps
|
|
||||||
[< Step [2, 2, *, 3, +]>, < Step [4, 3, +]>, < Step [4, 3, +]>, < Step [7]>]
|
|
||||||
>>> c = AbstractPolynom.smpl_coef_list([0, 2, 0])
|
|
||||||
>>> c
|
|
||||||
2
|
|
||||||
>>> c.steps
|
|
||||||
[< Step [2]>]
|
|
||||||
"""
|
|
||||||
# Simplify each element before adding them
|
|
||||||
smpl_elem = []
|
|
||||||
for c in coef_list:
|
|
||||||
try:
|
|
||||||
smpl_c = c.simplify()
|
|
||||||
except AttributeError:
|
|
||||||
smpl_c = c
|
|
||||||
smpl_elem.append(smpl_c)
|
|
||||||
|
|
||||||
pstfx_add = postfix_op(
|
|
||||||
[i for i in smpl_elem if i != 0],
|
|
||||||
op.add
|
|
||||||
)
|
|
||||||
|
|
||||||
steps = Expression.develop_steps(pstfx_add)
|
|
||||||
|
|
||||||
ans = Expression(pstfx_add).simplify()
|
|
||||||
ans.this_append_before(steps)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def replace_letter(self, letter):
|
|
||||||
r""" Replace the letter in the expression
|
|
||||||
|
|
||||||
:param letter: the new letter.
|
|
||||||
:returns: The expression with the new letter.
|
|
||||||
|
|
||||||
>>> A = AbstractPolynom([1, 2])
|
|
||||||
>>> A
|
|
||||||
< AbstractPolynom x [1, 2]>
|
|
||||||
>>> B = A.replace_letter("y")
|
|
||||||
>>> B
|
|
||||||
< Expression [2, < Polynom y [0, 1]>, *, 1, +]>
|
|
||||||
>>> C = A.replace_letter(2)
|
|
||||||
>>> C
|
|
||||||
< Expression [2, 2, *, 1, +]>
|
|
||||||
>>> e = Expression('2+3').simplify()
|
|
||||||
>>> D = A.replace_letter(e)
|
|
||||||
>>> D
|
|
||||||
< Expression [2, 5, *, 1, +]>
|
|
||||||
>>> for i in D.explain():
|
|
||||||
... print(i)
|
|
||||||
2 ( 2 + 3 ) + 1
|
|
||||||
2 \times 5 + 1
|
|
||||||
|
|
||||||
"""
|
|
||||||
exp_to_replace = Expression(letter)
|
|
||||||
exp_to_replace.steal_history(letter)
|
|
||||||
|
|
||||||
postfix_exp = [
|
|
||||||
exp_to_replace if i == self._letter
|
|
||||||
else i
|
|
||||||
for i in self.postfix_tokens
|
|
||||||
]
|
|
||||||
ini_step = Expression.develop_steps(postfix_exp)
|
|
||||||
|
|
||||||
ans = Expression(postfix_exp)
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
|
|
||||||
return 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 x [5, 7, 3]>
|
|
||||||
>>> for i in R.explain():
|
|
||||||
... print(i)
|
|
||||||
3 x^{ 2 } + 2 x + 1 + 5 x + 4
|
|
||||||
3 x^{ 2 } + 2 x + 5 x + 1 + 4
|
|
||||||
3 x^{ 2 } + ( 2 + 5 ) x + 1 + 4
|
|
||||||
3 x^{ 2 } + 7 x + 5
|
|
||||||
>>> R.steps
|
|
||||||
[< Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +, 5, 'x', *, 4, +, +]>, < Step [3, 'x', 2, ^, *, 2, 'x', *, +, 5, 'x', *, +, 1, +, 4, +]>, < Step [3, 'x', 2, ^, *, 2, 5, +, 'x', *, +, 1, 4, +, +]>, < Step [3, 'x', 2, ^, *, 7, 'x', *, +, 5, +]>]
|
|
||||||
>>> Q = AbstractPolynom([4,5], letter = 'y')
|
|
||||||
>>> R = P+Q
|
|
||||||
>>> R
|
|
||||||
< AbstractPolynom x [< AbstractPolynom y [5, 5]>, 2, 3]>
|
|
||||||
>>> for i in R.explain():
|
|
||||||
... print(i)
|
|
||||||
3 x^{ 2 } + 2 x + 1 + 5 y + 4
|
|
||||||
3 x^{ 2 } + 2 x + 5 y + 1 + 4
|
|
||||||
3 x^{ 2 } + 2 x + 5 y + 5
|
|
||||||
|
|
||||||
"""
|
|
||||||
o_poly = self.conv2poly(other)
|
|
||||||
|
|
||||||
n_coef = spe_zip(self._coef, o_poly._coef)
|
|
||||||
p = AbstractPolynom(n_coef, letter=self._letter)
|
|
||||||
|
|
||||||
ini_step = [Step([self, o_poly, op.add])]
|
|
||||||
|
|
||||||
ans = p.simplify()
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
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 x [-1, -2, -3]>
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
- ( 3 x^{ 2 } + 2 x + 1 )
|
|
||||||
-3 x^{ 2 } - 2 x - 1
|
|
||||||
>>> Q.steps
|
|
||||||
[< Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +, -]>, < Step [-3, 'x', 2, ^, *, -2, 'x', *, +, -1, +]>, < Step [-3, 'x', 2, ^, *, -2, 'x', *, +, -1, +]>]
|
|
||||||
"""
|
|
||||||
ini_step = [Step(self.postfix_tokens + [op.sub1])]
|
|
||||||
ans = AbstractPolynom([-i for i in self._coef],
|
|
||||||
letter=self._letter).simplify()
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
""" overload -
|
|
||||||
|
|
||||||
>>> P = AbstractPolynom([1,2,3])
|
|
||||||
>>> Q = AbstractPolynom([4,5,6])
|
|
||||||
>>> R = P - Q
|
|
||||||
>>> R
|
|
||||||
< AbstractPolynom x [-3, -3, -3]>
|
|
||||||
>>> 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 x^{ 2 } - 6 x^{ 2 } + 2 x - 5 x + 1 - 4
|
|
||||||
( 3 - 6 ) x^{ 2 } + ( 2 - 5 ) x + 1 - 4
|
|
||||||
-3 x^{ 2 } - 3 x - 3
|
|
||||||
>>> R.steps
|
|
||||||
[< Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +, 6, 'x', 2, ^, *, 5, 'x', *, +, 4, +, -]>, < Step [3, 'x', 2, ^, *, 2, 'x', *, +, 1, +, -6, 'x', 2, ^, *, -5, 'x', *, +, -4, +, +]>, < Step [3, 'x', 2, ^, *, -6, 'x', 2, ^, *, +, 2, 'x', *, +, -5, 'x', *, +, 1, +, -4, +]>, < Step [3, -6, +, 'x', 2, ^, *, 2, -5, +, 'x', *, +, 1, -4, +, +]>, < Step [-3, 'x', 2, ^, *, -3, 'x', *, +, -3, +]>]
|
|
||||||
"""
|
|
||||||
o_poly = self.conv2poly(other)
|
|
||||||
ini_step = [Step(self.postfix_tokens +
|
|
||||||
o_poly.postfix_tokens + [op.sub])]
|
|
||||||
o_poly = -o_poly
|
|
||||||
|
|
||||||
ans = self + o_poly
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __rsub__(self, other):
|
|
||||||
o_poly = self.conv2poly(other)
|
|
||||||
|
|
||||||
return o_poly.__sub__(self)
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
r""" Overload *
|
|
||||||
|
|
||||||
>>> p = AbstractPolynom([1,2])
|
|
||||||
>>> p*3
|
|
||||||
< AbstractPolynom x [3, 6]>
|
|
||||||
>>> for i in (p*3).explain():
|
|
||||||
... print(i)
|
|
||||||
( 2 x + 1 ) \times 3
|
|
||||||
2 \times 3 x + 3
|
|
||||||
6 x + 3
|
|
||||||
>>> (p*3).steps
|
|
||||||
[< Step [2, 'x', *, 1, +, 3, *]>, < Step [2, 3, *, 'x', *, 3, +]>, < Step [2, 3, *, 'x', *, 3, +]>, < Step [6, 'x', *, 3, +]>]
|
|
||||||
>>> q = AbstractPolynom([0,0,4])
|
|
||||||
>>> q*3
|
|
||||||
< AbstractPolynom x [0, 0, 12]>
|
|
||||||
>>> for i in (q*3).explain():
|
|
||||||
... print(i)
|
|
||||||
4 x^{ 2 } \times 3
|
|
||||||
4 \times 3 x^{ 2 }
|
|
||||||
12 x^{ 2 }
|
|
||||||
>>> (q*3).steps
|
|
||||||
[< Step [4, 'x', 2, ^, *, 3, *]>, < Step [4, 3, *, 'x', 2, ^, *]>, < Step [4, 3, *, 'x', 2, ^, *]>, < Step [12, 'x', 2, ^, *]>]
|
|
||||||
>>> r = AbstractPolynom([0,1])
|
|
||||||
>>> r*3
|
|
||||||
< AbstractPolynom x [0, 3]>
|
|
||||||
>>> (r*3).steps
|
|
||||||
[< Step ['x', 3, *]>, < Step [3, 'x', *]>, < Step [3, 'x', *]>]
|
|
||||||
>>> p*q
|
|
||||||
< AbstractPolynom x [0, 0, 4, 8]>
|
|
||||||
>>> (p*q).steps
|
|
||||||
[< Step [2, 'x', *, 1, +, 4, 'x', 2, ^, *, *]>, < Step [2, 4, *, 'x', 3, ^, *, 4, 'x', 2, ^, *, +]>, < Step [2, 4, *, 'x', 3, ^, *, 4, 'x', 2, ^, *, +]>, < Step [8, 'x', 3, ^, *, 4, 'x', 2, ^, *, +]>]
|
|
||||||
>>> for i in (p*q).explain():
|
|
||||||
... print(i)
|
|
||||||
( 2 x + 1 ) \times 4 x^{ 2 }
|
|
||||||
2 \times 4 x^{ 3 } + 4 x^{ 2 }
|
|
||||||
8 x^{ 3 } + 4 x^{ 2 }
|
|
||||||
>>> p*r
|
|
||||||
< AbstractPolynom x [0, 1, 2]>
|
|
||||||
>>> P = AbstractPolynom([1,2,3])
|
|
||||||
>>> Q = AbstractPolynom([4,5,6])
|
|
||||||
>>> P*Q
|
|
||||||
< AbstractPolynom x [4, 13, 28, 27, 18]>
|
|
||||||
"""
|
|
||||||
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 isinstance(coefs[i + j], list):
|
|
||||||
coefs[i + j] += [elem]
|
|
||||||
else:
|
|
||||||
coefs[i + j] = [coefs[i + j], elem]
|
|
||||||
|
|
||||||
p = AbstractPolynom(coefs, letter=self._letter)
|
|
||||||
ini_step = [Step(self.postfix_tokens +
|
|
||||||
o_poly.postfix_tokens + [op.mul])]
|
|
||||||
ans = p.simplify()
|
|
||||||
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __rmul__(self, other):
|
|
||||||
o_poly = self.conv2poly(other)
|
|
||||||
|
|
||||||
return o_poly.__mul__(self)
|
|
||||||
|
|
||||||
def __truediv__(self, other):
|
|
||||||
r""" Overload /
|
|
||||||
|
|
||||||
>>> P = AbstractPolynom([1, 2, 4])
|
|
||||||
>>> P / 2
|
|
||||||
< AbstractPolynom x [< Fraction 1 / 2>, 1, 2]>
|
|
||||||
>>> for i in (P/2).explain():
|
|
||||||
... print(i)
|
|
||||||
\frac{ 4 x^{ 2 } + 2 x + 1 }{ 2 }
|
|
||||||
\frac{ 4 }{ 2 } x^{ 2 } + \frac{ 2 }{ 2 } x + \frac{ 1 }{ 2 }
|
|
||||||
2 x^{ 2 } + x + \frac{ 1 }{ 2 }
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
ans_coefs = [Expression([c, other, op.div]) if c != 0
|
|
||||||
else 0
|
|
||||||
for c in self._coef
|
|
||||||
]
|
|
||||||
|
|
||||||
ans = AbstractPolynom(ans_coefs, letter=self._letter)
|
|
||||||
ini_step = [Step(
|
|
||||||
self.postfix_tokens +
|
|
||||||
[other, op.div]
|
|
||||||
)]
|
|
||||||
|
|
||||||
ans = ans.simplify()
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
@power_cache
|
|
||||||
def __pow__(self, power):
|
|
||||||
r""" Overload **
|
|
||||||
|
|
||||||
>>> p = AbstractPolynom([0,0,3])
|
|
||||||
>>> p**2
|
|
||||||
< AbstractPolynom x [0, 0, 0, 0, 9]>
|
|
||||||
>>> (p**2).steps
|
|
||||||
[< Step [3, 'x', 2, ^, *, 2, ^]>, < Step [3, 2, ^, 'x', 4, ^, *]>, < Step [3, 2, ^, 'x', 4, ^, *]>, < Step [9, 'x', 4, ^, *]>]
|
|
||||||
>>> for i in (p**2).explain():
|
|
||||||
... print(i)
|
|
||||||
( 3 x^{ 2 } )^{ 2 }
|
|
||||||
3^{ 2 } x^{ 4 }
|
|
||||||
9 x^{ 4 }
|
|
||||||
>>> p = AbstractPolynom([1,2])
|
|
||||||
>>> p**2
|
|
||||||
< AbstractPolynom x [1, 4, 4]>
|
|
||||||
>>> (p**2).steps
|
|
||||||
[< Step [2, 'x', *, 1, +, 2, ^]>, < Step [2, 'x', *, 1, +, 2, 'x', *, 1, +, *]>, < Step [2, 2, *, 'x', 2, ^, *, 2, 'x', *, +, 2, 'x', *, +, 1, +]>, < Step [2, 2, *, 'x', 2, ^, *, 2, 2, +, 'x', *, +, 1, +]>, < Step [4, 'x', 2, ^, *, 4, 'x', *, +, 1, +]>]
|
|
||||||
>>> for i in (p**2).explain():
|
|
||||||
... print(i)
|
|
||||||
( 2 x + 1 )^{ 2 }
|
|
||||||
( 2 x + 1 ) ( 2 x + 1 )
|
|
||||||
2 \times 2 x^{ 2 } + 2 x + 2 x + 1
|
|
||||||
2 \times 2 x^{ 2 } + ( 2 + 2 ) x + 1
|
|
||||||
4 x^{ 2 } + 4 x + 1
|
|
||||||
>>> p = AbstractPolynom([0,0,1])
|
|
||||||
>>> p**3
|
|
||||||
< AbstractPolynom x [0, 0, 0, 0, 0, 0, 1]>
|
|
||||||
>>> p = AbstractPolynom([1,2,3])
|
|
||||||
>>> p**2
|
|
||||||
< AbstractPolynom x [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 = [Step(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.this_append_before(ini_step)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __xor__(self, power):
|
|
||||||
return self.__pow__(power)
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['gcd']
|
|
||||||
|
|
||||||
|
|
||||||
def gcd(a, b):
|
|
||||||
"""Compute gcd(a,b)
|
|
||||||
|
|
||||||
:param a: first number
|
|
||||||
:param b: second number
|
|
||||||
:returns: the gcd
|
|
||||||
|
|
||||||
"""
|
|
||||||
pos_a, _a = (a >= 0), abs(a)
|
|
||||||
pos_b, _b = (b >= 0), abs(b)
|
|
||||||
|
|
||||||
gcd_sgn = (-1 + 2 * (pos_a or pos_b))
|
|
||||||
|
|
||||||
if _a > _b:
|
|
||||||
c = _a % _b
|
|
||||||
else:
|
|
||||||
c = _b % _a
|
|
||||||
|
|
||||||
if c == 0:
|
|
||||||
return gcd_sgn * min(_a, _b)
|
|
||||||
elif _a == 1:
|
|
||||||
return gcd_sgn * _b
|
|
||||||
elif _b == 1:
|
|
||||||
return gcd_sgn * _a
|
|
||||||
else:
|
|
||||||
return gcd_sgn * gcd(min(_a, _b), c)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print(gcd(3, 15))
|
|
||||||
print(gcd(3, 15))
|
|
||||||
print(gcd(-15, -3))
|
|
||||||
print(gcd(-3, -12))
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -104,7 +104,7 @@ class Tree(object):
|
|||||||
>>> t.node
|
>>> t.node
|
||||||
'+'
|
'+'
|
||||||
>>> type(t.left_value)
|
>>> type(t.left_value)
|
||||||
<class 'calculus.core.tree.Tree'>
|
<class 'mapytex.calculus.core.tree.Tree'>
|
||||||
>>> t.right_value
|
>>> t.right_value
|
||||||
2
|
2
|
||||||
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from functools import wraps
|
|
||||||
|
|
||||||
def no_repetition(equals=lambda x,y: x == y, old = ""):
|
|
||||||
""" Remove yield values which has already been yield
|
|
||||||
|
|
||||||
:param equals: test for equality
|
|
||||||
:param old: initiate form of data.
|
|
||||||
:returns: same generator with no repetitions
|
|
||||||
|
|
||||||
>>> norep = no_repetition()
|
|
||||||
>>> def str_gene(string):
|
|
||||||
... for i in string:
|
|
||||||
... yield i
|
|
||||||
>>> norep_str_gene = norep(str_gene)
|
|
||||||
>>> [i for i in norep_str_gene("aaabraabbbere")]
|
|
||||||
['a', 'b', 'r', 'a', 'b', 'e', 'r', 'e']
|
|
||||||
|
|
||||||
"""
|
|
||||||
def wrapper(fun):
|
|
||||||
@wraps(fun)
|
|
||||||
def dont_repeat(*args, **kwrds):
|
|
||||||
gen = fun(*args, **kwrds)
|
|
||||||
old_s = old
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
new_s = next(gen)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if not equals(new_s, old_s):
|
|
||||||
old_s = new_s
|
|
||||||
yield new_s
|
|
||||||
|
|
||||||
return dont_repeat
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,306 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .explicable import Explicable
|
|
||||||
from .expression import Expression
|
|
||||||
from .step import Step
|
|
||||||
from .decorators import no_repetition
|
|
||||||
from .polynom import Polynom
|
|
||||||
from .fraction import Fraction
|
|
||||||
|
|
||||||
from .random_expression import RdExpression
|
|
||||||
|
|
||||||
__all__ = ['Equation']
|
|
||||||
|
|
||||||
def equals(new, old):
|
|
||||||
print("new -> ", new)
|
|
||||||
print("old -> ", old)
|
|
||||||
return new, old
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Equation(object):
|
|
||||||
"""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=2, val_max=30):
|
|
||||||
"""Create a random expression from form and with conditions
|
|
||||||
|
|
||||||
:param form: the form of the expression (/!\ variables need to be in brackets {})
|
|
||||||
:param conditions: condition on variables (/!\ variables need to be in brackets {})
|
|
||||||
:param val_min: min value for generate variables
|
|
||||||
:param val_max: max value for generate variables
|
|
||||||
|
|
||||||
>>> Equation.random("{a}x + {b} = 0") # doctest:+ELLIPSIS
|
|
||||||
< Equation [..., 0]>
|
|
||||||
>>> Equation.random("{a}x + {b} = _", conditions = ["{a}==2"]) # doctest:+ELLIPSIS
|
|
||||||
< Equation [2 x ...]>
|
|
||||||
|
|
||||||
"""
|
|
||||||
random_generator = RdExpression(form, conditions)
|
|
||||||
return Equation(random_generator(val_min, val_max))
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, exp_str = "", left_poly = Expression([0]), right_poly = Expression([0])):
|
|
||||||
"""Create the equation
|
|
||||||
|
|
||||||
:param exp_str: the equality string which represent the equation
|
|
||||||
:param left_poly: the left polynom of the equation
|
|
||||||
:param right_poly: the right polynom of the equation
|
|
||||||
|
|
||||||
>>> e = Equation("2x+3 = 4x+5")
|
|
||||||
>>> e
|
|
||||||
< Equation [2 x + 3, 4 x + 5]>
|
|
||||||
>>> Pl = Polynom([1, 2])
|
|
||||||
>>> Pr = Polynom([3, 4])
|
|
||||||
>>> e = Equation(left_poly = Pl)
|
|
||||||
>>> e
|
|
||||||
< Equation [2 x + 1, 0]>
|
|
||||||
>>> e = Equation(right_poly = Pr)
|
|
||||||
>>> e
|
|
||||||
< Equation [0, 4 x + 3]>
|
|
||||||
>>> e = Equation(left_poly = Pl, right_poly = Pr)
|
|
||||||
>>> e
|
|
||||||
< Equation [2 x + 1, 4 x + 3]>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if exp_str:
|
|
||||||
l_part, r_part = exp_str.split("=")
|
|
||||||
self.l_exp = Expression(l_part)
|
|
||||||
self.r_exp = Expression(r_part)
|
|
||||||
else:
|
|
||||||
self.l_exp = left_poly
|
|
||||||
self.r_exp = right_poly
|
|
||||||
|
|
||||||
self.smpl_each_part()
|
|
||||||
|
|
||||||
def smpl_each_part(self):
|
|
||||||
""" Simplify left and right part, transform them into polynom and stock them in smpl_*_exp
|
|
||||||
"""
|
|
||||||
self.smpl_l_exp = self.l_exp.simplify()
|
|
||||||
self.smpl_l_exp.steal_history(self.l_exp)
|
|
||||||
self.smpl_r_exp = self.r_exp.simplify()
|
|
||||||
self.smpl_r_exp.steal_history(self.r_exp)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.smpl_r_exp = self.smpl_l_exp.conv2poly(self.smpl_r_exp)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.smpl_l_exp = self.smpl_r_exp.conv2poly(self.smpl_l_exp)
|
|
||||||
except AttributeError:
|
|
||||||
raise EquationError("None of left and right parts are polynoms. \
|
|
||||||
Can't use it to make an equation.")
|
|
||||||
|
|
||||||
# TODO: On pourrait rajouter des tests sur les inconnues |mar. mars 22 10:17:12 EAT 2016
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.l_exp) + " = " + str(self.r_exp)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "< {cls} [{l}, {r}]>".format(
|
|
||||||
cls = str(self.__class__).split('.')[-1][:-2],
|
|
||||||
l = self.l_exp,
|
|
||||||
r = self.r_exp,
|
|
||||||
)
|
|
||||||
|
|
||||||
@no_repetition(lambda x, y: (x[0] == y[0]) & (x[1] == y[1]), ['',''])
|
|
||||||
def solve(self):
|
|
||||||
r"""Solve the equation but yielding each steps
|
|
||||||
|
|
||||||
>>> e = Equation("x + 123 = 0")
|
|
||||||
>>> for i in e.solve():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
x + 123 = 0
|
|
||||||
x + 123 - 123 = 0 - 123
|
|
||||||
x + 123 - 123 = -123
|
|
||||||
x = -123
|
|
||||||
>>> e = Equation("2x = x + 2")
|
|
||||||
>>> for i in e.solve():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
2 x = x + 2
|
|
||||||
2 x - x = x + 2 - x
|
|
||||||
( 2 - 1 ) x = x - x + 2
|
|
||||||
x = ( 1 - 1 ) x + 2
|
|
||||||
x = 2
|
|
||||||
>>> e = Equation("2x = 1")
|
|
||||||
>>> for i in e.solve():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
2 x = 1
|
|
||||||
\frac{ 2 x }{ 2 } = \frac{ 1 }{ 2 }
|
|
||||||
\frac{ 2 }{ 2 } x = \frac{ 1 }{ 2 }
|
|
||||||
x = \frac{ 1 }{ 2 }
|
|
||||||
>>> e = Equation("2x + 1 = 4x + 2")
|
|
||||||
>>> for i in e.solve():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
2 x + 1 = 4 x + 2
|
|
||||||
2 x + 1 - 1 = 4 x + 2 - 1
|
|
||||||
2 x = 4 x + 1
|
|
||||||
2 x - 4 x = 4 x + 1 - 4 x
|
|
||||||
( 2 - 4 ) x = 4 x - 4 x + 1
|
|
||||||
-2 x = ( 4 - 4 ) x + 1
|
|
||||||
-2 x = 1
|
|
||||||
\frac{ -2 x }{ -2 } = \frac{ 1 }{ -2 }
|
|
||||||
\frac{ -2 }{ -2 } x = \frac{ -1 }{ 2 }
|
|
||||||
x = \frac{ -1 }{ 2 }
|
|
||||||
>>> e = Equation("2x + 3x + 1 = 4x + 2")
|
|
||||||
>>> for i in e.solve():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
2 x + 3 x + 1 = 4 x + 2
|
|
||||||
( 2 + 3 ) x + 1 = 4 x + 2
|
|
||||||
5 x + 1 = 4 x + 2
|
|
||||||
5 x + 1 - 1 = 4 x + 2 - 1
|
|
||||||
5 x = 4 x + 1
|
|
||||||
5 x - 4 x = 4 x + 1 - 4 x
|
|
||||||
( 5 - 4 ) x = 4 x - 4 x + 1
|
|
||||||
x = ( 4 - 4 ) x + 1
|
|
||||||
x = 1
|
|
||||||
"""
|
|
||||||
yield from self.gene_smpl_steps()
|
|
||||||
|
|
||||||
if self.smpl_l_exp._coef[0] != 0:
|
|
||||||
eq = Equation(
|
|
||||||
left_poly = self.smpl_l_exp - self.smpl_l_exp._coef[0],
|
|
||||||
right_poly = self.smpl_r_exp - self.smpl_l_exp._coef[0]
|
|
||||||
)
|
|
||||||
yield from eq.solve()
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
poly_r_part = Polynom([0, self.smpl_r_exp._coef[1]])
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if self.smpl_r_exp._coef[1] != 0:
|
|
||||||
yield from Equation(
|
|
||||||
left_poly = self.smpl_l_exp - poly_r_part,
|
|
||||||
right_poly = self.smpl_r_exp - poly_r_part
|
|
||||||
).solve()
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.smpl_l_exp._coef[1] != 1:
|
|
||||||
yield from Equation(
|
|
||||||
left_poly = self.smpl_l_exp / self.smpl_l_exp._coef[1],
|
|
||||||
right_poly = self.smpl_r_exp / self.smpl_l_exp._coef[1]
|
|
||||||
).solve()
|
|
||||||
return
|
|
||||||
|
|
||||||
@no_repetition()
|
|
||||||
def gene_smpl_steps(self):
|
|
||||||
r"""Generate simplification steps of the equation
|
|
||||||
|
|
||||||
>>> e = Equation("2x + 3x + 1 = 4x + 2")
|
|
||||||
>>> e.gene_smpl_steps() # doctest:+ELLIPSIS
|
|
||||||
<generator object Equation.gene_smpl_steps at ...>
|
|
||||||
>>> for i in e.gene_smpl_steps():
|
|
||||||
... print(i)
|
|
||||||
[< Step [2, 'x', *, 3, 'x', *, +, 1, +]>, < Step [4, 'x', *, 2, +]>]
|
|
||||||
[< Step [2, 3, +, 'x', *, 1, +]>, < Step [4, 'x', *, 2, +]>]
|
|
||||||
[< Step [5, 'x', *, 1, +]>, < Step [4, 'x', *, 2, +]>]
|
|
||||||
>>> e = Equation("2x + 3x + 1 = 4x + 2")
|
|
||||||
>>> for i in e.gene_smpl_steps():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
2 x + 3 x + 1 = 4 x + 2
|
|
||||||
( 2 + 3 ) x + 1 = 4 x + 2
|
|
||||||
5 x + 1 = 4 x + 2
|
|
||||||
>>> e = Equation("3x / 3 = 5 / 3")
|
|
||||||
>>> for i in e.gene_smpl_steps():
|
|
||||||
... print(" = ".join([str(j) for j in i]))
|
|
||||||
3 \times \frac{ x }{ 3 } = \frac{ 5 }{ 3 }
|
|
||||||
\frac{ x }{ 3 } \times 3 = \frac{ 5 }{ 3 }
|
|
||||||
\frac{ x \times 3 }{ 1 \times 3 } = \frac{ 5 }{ 3 }
|
|
||||||
\frac{ x }{ 1 } = \frac{ 5 }{ 3 }
|
|
||||||
x = \frac{ 5 }{ 3 }
|
|
||||||
|
|
||||||
"""
|
|
||||||
#yield [Step(self.l_exp), Step(self.r_exp)]
|
|
||||||
|
|
||||||
for s in Explicable.merge_history(
|
|
||||||
[self.smpl_l_exp, self.smpl_r_exp]
|
|
||||||
):
|
|
||||||
yield s
|
|
||||||
|
|
||||||
def solution(self):
|
|
||||||
"""Return the solution of the equation
|
|
||||||
|
|
||||||
:returns: the solution
|
|
||||||
|
|
||||||
>>> e = Equation("2x + 1 = x + 2")
|
|
||||||
>>> e.solution()
|
|
||||||
1
|
|
||||||
>>> e = Equation("2x + 1 = 1")
|
|
||||||
>>> e.solution()
|
|
||||||
0
|
|
||||||
>>> e = Equation("1 = 2x + 1")
|
|
||||||
>>> e.solution()
|
|
||||||
0
|
|
||||||
>>> e = Equation("3x = 2x")
|
|
||||||
>>> e.solution()
|
|
||||||
0
|
|
||||||
>>> e = Equation("3x + 1 = 0")
|
|
||||||
>>> e.solution()
|
|
||||||
< Fraction -1 / 3>
|
|
||||||
>>> e = Equation("6x + 2 = 0")
|
|
||||||
>>> e.solution()
|
|
||||||
< Fraction -1 / 3>
|
|
||||||
|
|
||||||
"""
|
|
||||||
num = self.smpl_r_exp._coef[0] - self.smpl_l_exp._coef[0]
|
|
||||||
|
|
||||||
try:
|
|
||||||
denom = self.smpl_l_exp._coef[1]
|
|
||||||
except IndexError:
|
|
||||||
denom = 0
|
|
||||||
try:
|
|
||||||
denom -= self.smpl_r_exp._coef[1]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if denom == 0 and num == 0:
|
|
||||||
raise EquationError("All number are solution")
|
|
||||||
elif denom == 0:
|
|
||||||
raise NoSolutionError("This equation has no solution")
|
|
||||||
|
|
||||||
return Fraction(num, denom).simplify()
|
|
||||||
|
|
||||||
def is_solution(self, num):
|
|
||||||
""" Tell if a number is a solution.
|
|
||||||
|
|
||||||
:param num: the number to test
|
|
||||||
|
|
||||||
>>> e = Equation("2x + 1 = x + 2")
|
|
||||||
>>> e.is_solution(2)
|
|
||||||
False
|
|
||||||
>>> e.is_solution(1)
|
|
||||||
True
|
|
||||||
>>> e = Equation("3x = 2x")
|
|
||||||
>>> e.is_solution(1)
|
|
||||||
False
|
|
||||||
>>> e.is_solution(0)
|
|
||||||
True
|
|
||||||
>>> e = Equation("3x + 1 = 0")
|
|
||||||
>>> e.is_solution(0)
|
|
||||||
False
|
|
||||||
>>> e.is_solution(Fraction(-1, 3))
|
|
||||||
True
|
|
||||||
>>> e.is_solution(Fraction(-2, 6))
|
|
||||||
True
|
|
||||||
|
|
||||||
"""
|
|
||||||
l_part = self.smpl_l_exp.replace_letter(num).simplify()
|
|
||||||
r_part = self.smpl_r_exp.replace_letter(num).simplify()
|
|
||||||
return l_part == r_part
|
|
||||||
|
|
||||||
class EquationError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class NoSolutionError(EquationError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,259 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .renderable import Renderable
|
|
||||||
from .step import Step
|
|
||||||
from decimal import Decimal
|
|
||||||
from .generic import transpose_fill
|
|
||||||
from .decorators import no_repetition
|
|
||||||
|
|
||||||
|
|
||||||
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, pstf_tokens):
|
|
||||||
super(Explicable, self).__init__(pstf_tokens)
|
|
||||||
self.steps = []
|
|
||||||
self.explained = 0
|
|
||||||
|
|
||||||
def explain(self):
|
|
||||||
r""" Generate and render steps which leed to itself
|
|
||||||
|
|
||||||
After beening explained, the Explicable become amnesiac. It will return itself in a list.
|
|
||||||
See 'history_generator' to explain it once again.
|
|
||||||
|
|
||||||
>>> action = Explicable(['42'])
|
|
||||||
>>> from .expression import Expression
|
|
||||||
>>> action.this_append_before([Expression('2+10*4'), Expression('2+40')])
|
|
||||||
>>> for i in action.explain():
|
|
||||||
... print(i)
|
|
||||||
2 + 10 \times 4
|
|
||||||
2 + 40
|
|
||||||
42
|
|
||||||
>>> # Now action is amnesiac
|
|
||||||
>>> for i in action.explain():
|
|
||||||
... print(i)
|
|
||||||
42
|
|
||||||
>>> action = Explicable(['42'])
|
|
||||||
>>> for i in action.explain():
|
|
||||||
... print(i)
|
|
||||||
42
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self.explained:
|
|
||||||
return self.self_generator()
|
|
||||||
else:
|
|
||||||
self.explained = 1
|
|
||||||
return self.history_generator()
|
|
||||||
|
|
||||||
def self_generator(self):
|
|
||||||
""" Generator which yield itself rendered """
|
|
||||||
yield self.STR_RENDER(self.postfix_tokens)
|
|
||||||
|
|
||||||
@no_repetition()
|
|
||||||
def history_generator(self):
|
|
||||||
r""" Generator for rendered steps which leed to itself
|
|
||||||
|
|
||||||
This is the called method in explain which create the generator.
|
|
||||||
It create a new generator at each call.
|
|
||||||
|
|
||||||
>>> action = Explicable(['42'])
|
|
||||||
>>> from .expression import Expression
|
|
||||||
>>> for i in action.history_generator():
|
|
||||||
... print(i)
|
|
||||||
42
|
|
||||||
>>> action.this_append_before([Expression('2+10*4'), Expression('2+40')])
|
|
||||||
>>> for i in action.history_generator():
|
|
||||||
... print(i)
|
|
||||||
2 + 10 \times 4
|
|
||||||
2 + 40
|
|
||||||
42
|
|
||||||
>>> for i in action.history_generator():
|
|
||||||
... print(i)
|
|
||||||
2 + 10 \times 4
|
|
||||||
2 + 40
|
|
||||||
42
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
for s in self.steps:
|
|
||||||
try:
|
|
||||||
new_s = self.STR_RENDER(s.postfix_tokens)
|
|
||||||
except AttributeError:
|
|
||||||
new_s = self.STR_RENDER(s)
|
|
||||||
yield new_s
|
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# if noself:
|
|
||||||
new_s = self.STR_RENDER(self.postfix_tokens)
|
|
||||||
yield new_s
|
|
||||||
|
|
||||||
def this_append_before(self, steps):
|
|
||||||
""" Add steps at the beginning of self.steps
|
|
||||||
|
|
||||||
:param steps: list of steps that append before
|
|
||||||
|
|
||||||
>>> e = Explicable(['Actions'])
|
|
||||||
>>> s = ['eat', 'sleep']
|
|
||||||
>>> e.this_append_before(s)
|
|
||||||
>>> print(e.steps)
|
|
||||||
['eat', 'sleep']
|
|
||||||
>>> s0 = ['cook']
|
|
||||||
>>> e.this_append_before(s0)
|
|
||||||
>>> print(e.steps)
|
|
||||||
['cook', 'eat', 'sleep']
|
|
||||||
"""
|
|
||||||
self.steps = list(steps) + self.steps
|
|
||||||
|
|
||||||
def steal_history(self, arg1):
|
|
||||||
""" Steal the history of arg1 for itself
|
|
||||||
|
|
||||||
:param arg1: a potential Explicable
|
|
||||||
|
|
||||||
>>> e = Explicable(['Actions'])
|
|
||||||
>>> s = [Step(['eat']), Step(['sleep'])]
|
|
||||||
>>> e.this_append_before(s)
|
|
||||||
>>> f = Explicable(['Stolen actions'])
|
|
||||||
>>> f.steal_history(e)
|
|
||||||
>>> for i in e.explain():
|
|
||||||
... print(i)
|
|
||||||
Actions
|
|
||||||
>>> for i in f.explain():
|
|
||||||
... print(i)
|
|
||||||
eat
|
|
||||||
sleep
|
|
||||||
Actions
|
|
||||||
Stolen actions
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with Step.tmp_render():
|
|
||||||
self.this_append_before(list(arg1.explain()))
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def merge_history(cls, explicables):
|
|
||||||
r""" Take a list of Explicable objects, explain where they are from and merge their history
|
|
||||||
|
|
||||||
This method try to use 'explain' method from Explicable. This means that after using this method, those objects will become amnesiac.
|
|
||||||
|
|
||||||
:param explicables: list
|
|
||||||
:returns: the list of steps
|
|
||||||
|
|
||||||
>>> from .expression import Expression
|
|
||||||
>>> action1 = Explicable(['42'])
|
|
||||||
>>> action1.this_append_before([['2 + 4 * 10'], ['2 + 40']])
|
|
||||||
>>> action2 = Explicable(['24'])
|
|
||||||
>>> action2.this_append_before([['12 * 2']])
|
|
||||||
>>> m_history = Explicable.merge_history([action1, action2])
|
|
||||||
>>> m_history
|
|
||||||
<generator object transpose_fill ...>
|
|
||||||
>>> for i in m_history:
|
|
||||||
... print(i)
|
|
||||||
[< Step ['2 + 4 * 10']>, < Step ['12 * 2']>]
|
|
||||||
[< Step ['2 + 40']>, < Step ['24']>]
|
|
||||||
[< Step ['42']>, < Step ['24']>]
|
|
||||||
>>> # Now they are amnesiac
|
|
||||||
>>> for i in action1.explain():
|
|
||||||
... print(i)
|
|
||||||
42
|
|
||||||
>>> m_history = Explicable.merge_history([action1, action2])
|
|
||||||
>>> for i in m_history:
|
|
||||||
... print(i)
|
|
||||||
[< Step ['42']>, < Step ['24']>]
|
|
||||||
>>> action1 = Explicable(['42'])
|
|
||||||
>>> action1.this_append_before([['2+10*4'], ['2+40']])
|
|
||||||
>>> m_history = Explicable.merge_history([action1, 12])
|
|
||||||
>>> m_history
|
|
||||||
<generator object transpose_fill ...>
|
|
||||||
>>> for i in m_history:
|
|
||||||
... print(i)
|
|
||||||
[< Step ['2+10*4']>, < Step [12]>]
|
|
||||||
[< Step ['2+40']>, < Step [12]>]
|
|
||||||
[< Step ['42']>, < Step [12]>]
|
|
||||||
>>> action1 = Explicable(['42'])
|
|
||||||
>>> action1.this_append_before([['2+10*4'], ['2+40']])
|
|
||||||
>>> action2 = Explicable(['24'])
|
|
||||||
>>> action2.this_append_before([['2*12']])
|
|
||||||
>>> action3 = Explicable(['0'])
|
|
||||||
>>> action3.this_append_before([['3-3']])
|
|
||||||
>>> m_history = Explicable.merge_history([action1, action2, action3])
|
|
||||||
>>> for i in m_history:
|
|
||||||
... print(i)
|
|
||||||
[< Step ['2+10*4']>, < Step ['2*12']>, < Step ['3-3']>]
|
|
||||||
[< Step ['2+40']>, < Step ['24']>, < Step ['0']>]
|
|
||||||
[< Step ['42']>, < Step ['24']>, < Step ['0']>]
|
|
||||||
>>> m_history = Explicable.merge_history([1,2,3])
|
|
||||||
>>> for i in m_history:
|
|
||||||
... print(i)
|
|
||||||
[< Step [1]>, < Step [2]>, < Step [3]>]
|
|
||||||
"""
|
|
||||||
steps = []
|
|
||||||
for expl in explicables:
|
|
||||||
try:
|
|
||||||
with Step.tmp_render():
|
|
||||||
steps.append(list(expl.explain()))
|
|
||||||
except AttributeError:
|
|
||||||
steps.append([Step([expl])])
|
|
||||||
|
|
||||||
return transpose_fill(steps)
|
|
||||||
|
|
||||||
|
|
||||||
class Explicable_int(int, Explicable):
|
|
||||||
|
|
||||||
""" An Explicable_int is an int which can be explain """
|
|
||||||
|
|
||||||
isNumber = True
|
|
||||||
|
|
||||||
def __init__(self, val):
|
|
||||||
super(Explicable_int, self).__init__(val)
|
|
||||||
self._val = val
|
|
||||||
self.postfix_tokens = [self]
|
|
||||||
self.steps = []
|
|
||||||
|
|
||||||
def simplify(self):
|
|
||||||
return Explicable_int(self._val)
|
|
||||||
|
|
||||||
def __txt__(self):
|
|
||||||
return str(self._val)
|
|
||||||
|
|
||||||
def __tex__(self):
|
|
||||||
return str(self._val)
|
|
||||||
|
|
||||||
|
|
||||||
class Explicable_Decimal(Decimal, Explicable):
|
|
||||||
|
|
||||||
""" An Explicable_Decimal is an decimal which can be explain """
|
|
||||||
|
|
||||||
isNumber = True
|
|
||||||
|
|
||||||
def __init__(self, val):
|
|
||||||
super(Explicable_Decimal, self).__init__(val)
|
|
||||||
self._val = val
|
|
||||||
self.postfix_tokens = [self]
|
|
||||||
self.steps = []
|
|
||||||
|
|
||||||
def simplify(self):
|
|
||||||
return Explicable_Decimal(self._val)
|
|
||||||
|
|
||||||
def __txt__(self):
|
|
||||||
return str(self._val)
|
|
||||||
|
|
||||||
def __tex__(self):
|
|
||||||
return str(self._val)
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,338 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
# debuging
|
|
||||||
# from debug.tools import report
|
|
||||||
|
|
||||||
from .generic import flatten_list, expand_list, isOperator, isNumerand
|
|
||||||
from .str2tokens import str2tokens
|
|
||||||
from .operator import op
|
|
||||||
from .explicable import Explicable, Explicable_int, Explicable_Decimal
|
|
||||||
from .step import Step
|
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
:param form: the form of the expression (/!\ variables need to be in brackets {})
|
|
||||||
:param conditions: condition on variables (/!\ variables need to be in brackets {})
|
|
||||||
:param val_min: min value for generate variables
|
|
||||||
:param val_max: max value for generate variables
|
|
||||||
|
|
||||||
"""
|
|
||||||
random_generator = RdExpression(form, conditions)
|
|
||||||
return Expression(random_generator(val_min, val_max))
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, exp):
|
|
||||||
"""Create Expression objects
|
|
||||||
|
|
||||||
:param exp: the expression. It can be a string or a list of postfix tokens.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if isinstance(exp, str):
|
|
||||||
pstf_tokens = str2tokens(exp)
|
|
||||||
|
|
||||||
elif isinstance(exp, list):
|
|
||||||
# Ici on ne peut convertir les "+-*/..." en opérateur que s'ils sont
|
|
||||||
# d'arité 2.
|
|
||||||
exp_mod_op = [
|
|
||||||
op.get_op(i) if op.can_be_operator(i) else i for i in exp
|
|
||||||
]
|
|
||||||
pstf_tokens = flatten_list(
|
|
||||||
[tok.postfix_tokens if Expression.isExpression(tok)
|
|
||||||
else tok
|
|
||||||
for tok in exp_mod_op
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
elif isinstance(exp, Expression):
|
|
||||||
pstf_tokens = exp.postfix_tokens
|
|
||||||
|
|
||||||
elif isNumerand(exp):
|
|
||||||
pstf_tokens = [exp]
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise ValueError(
|
|
||||||
"Can't build Expression with {} object".format(
|
|
||||||
type(exp)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
super(Expression, self).__init__(pstf_tokens)
|
|
||||||
self._isExpression = 1
|
|
||||||
|
|
||||||
def simplify(self):
|
|
||||||
""" Compute entirely the expression and return the result with .steps attribute """
|
|
||||||
try:
|
|
||||||
self.compute_exp()
|
|
||||||
except ComputeError:
|
|
||||||
try:
|
|
||||||
self.simplified = self.postfix_tokens[0].simplify()
|
|
||||||
except AttributeError:
|
|
||||||
if isinstance(self.postfix_tokens[0], int):
|
|
||||||
self.simplified = Explicable_int(self.postfix_tokens[0])
|
|
||||||
elif isinstance(self.postfix_tokens[0], Decimal):
|
|
||||||
self.simplified = Explicable_Decimal(self.postfix_tokens[0])
|
|
||||||
else:
|
|
||||||
self.simplified = self
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.simplified = self.child.simplify()
|
|
||||||
self.simplified.this_append_before(self.child.steps)
|
|
||||||
return self.simplified
|
|
||||||
|
|
||||||
def compute_exp(self):
|
|
||||||
""" Create self.child with and stock steps in it """
|
|
||||||
if len(self.postfix_tokens) == 1:
|
|
||||||
raise ComputeError("Nothing to compute in {}".format(self.postfix_tokens))
|
|
||||||
else:
|
|
||||||
ini_step = Step(self.postfix_tokens)
|
|
||||||
|
|
||||||
tokenList = self.postfix_tokens.copy()
|
|
||||||
tmpTokenList = []
|
|
||||||
|
|
||||||
while len(tokenList) > 2:
|
|
||||||
# on va chercher les motifs du genre A B +, quand l'operateur est
|
|
||||||
# d'arité 2, pour les calculer
|
|
||||||
if isNumerand(tokenList[0]) and isNumerand(tokenList[1]) \
|
|
||||||
and isOperator(tokenList[2]) and tokenList[2].arity == 2:
|
|
||||||
|
|
||||||
# S'il y a une opération à faire
|
|
||||||
op1 = tokenList[0]
|
|
||||||
op2 = tokenList[1]
|
|
||||||
operator = tokenList[2]
|
|
||||||
|
|
||||||
res = operator(op1, op2)
|
|
||||||
|
|
||||||
tmpTokenList.append(res)
|
|
||||||
|
|
||||||
# Comme on vient de faire le calcul, on peut détruire aussi les
|
|
||||||
# deux prochains termes
|
|
||||||
del tokenList[0:3]
|
|
||||||
|
|
||||||
# Et les motifs du gens A -, quand l'operateur est d'arité 1
|
|
||||||
elif isNumerand(tokenList[0]) \
|
|
||||||
and isOperator(tokenList[1]) and tokenList[1].arity == 1:
|
|
||||||
|
|
||||||
# S'il y a une opération à faire
|
|
||||||
op1 = tokenList[0]
|
|
||||||
operator = tokenList[1]
|
|
||||||
|
|
||||||
res = operator(op1)
|
|
||||||
|
|
||||||
tmpTokenList.append(res)
|
|
||||||
|
|
||||||
# Comme on vient de faire le calcul, on peut détruire aussi les
|
|
||||||
# deux prochains termes
|
|
||||||
del tokenList[0:2]
|
|
||||||
|
|
||||||
else:
|
|
||||||
tmpTokenList.append(tokenList[0])
|
|
||||||
|
|
||||||
del tokenList[0]
|
|
||||||
|
|
||||||
if len(tokenList) == 2 and isNumerand(tokenList[0]) \
|
|
||||||
and isOperator(tokenList[1]) and tokenList[1].arity == 1:
|
|
||||||
# S'il reste deux éléments dont un operation d'arité 1
|
|
||||||
op1 = tokenList[0]
|
|
||||||
operator = tokenList[1]
|
|
||||||
|
|
||||||
res = operator(op1)
|
|
||||||
|
|
||||||
tmpTokenList.append(res)
|
|
||||||
|
|
||||||
# Comme on vient de faire le calcul, on peut détruire aussi les
|
|
||||||
# deux prochains termes
|
|
||||||
del tokenList[0:2]
|
|
||||||
|
|
||||||
tmpTokenList += tokenList
|
|
||||||
self.child = Expression(tmpTokenList)
|
|
||||||
|
|
||||||
steps = Expression.develop_steps(tmpTokenList)
|
|
||||||
|
|
||||||
if self.child.postfix_tokens == ini_step.postfix_tokens:
|
|
||||||
self.child.steps = steps
|
|
||||||
else:
|
|
||||||
self.child.this_append_before([ini_step] + steps)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def develop_steps(cls, tokenList):
|
|
||||||
r"""
|
|
||||||
From a list of tokens, it develops steps of each tokens and transpose it into steps respecting the stucture of the tokenList.
|
|
||||||
|
|
||||||
It try to use 'explain' method for every tokens. After using this methode, tokens becom amnesiac.
|
|
||||||
|
|
||||||
>>> e = Expression('1+2')
|
|
||||||
>>> e1 = e.simplify()
|
|
||||||
>>> f = Expression('3*4+5')
|
|
||||||
>>> f1 = f.simplify()
|
|
||||||
>>> dev_steps = Expression.develop_steps([e1, f1, op.add])
|
|
||||||
>>> dev_steps
|
|
||||||
[< Step [1, 2, +, 3, 4, *, 5, +, +]>, < Step [3, 12, 5, +, +]>, < Step [3, 17, +]>]
|
|
||||||
>>> for i in dev_steps:
|
|
||||||
... print(i)
|
|
||||||
1 + 2 + 3 \times 4 + 5
|
|
||||||
3 + 12 + 5
|
|
||||||
3 + 17
|
|
||||||
>>> e = Expression('1+2')
|
|
||||||
>>> e1 = e.simplify()
|
|
||||||
>>> f = Expression('3*4+5')
|
|
||||||
>>> f1 = f.simplify()
|
|
||||||
>>> g = Expression('6+7')
|
|
||||||
>>> g1 = g.simplify()
|
|
||||||
>>> Expression.develop_steps([e1, f1, op.add, g1, op.mul])
|
|
||||||
[< Step [1, 2, +, 3, 4, *, 5, +, +, 6, 7, +, *]>, < Step [3, 12, 5, +, +, 13, *]>, < Step [3, 17, +, 13, *]>]
|
|
||||||
"""
|
|
||||||
with Step.tmp_render():
|
|
||||||
tmp_steps = list(Explicable.merge_history(tokenList))
|
|
||||||
|
|
||||||
steps = [Step(s) for s in tmp_steps]
|
|
||||||
return steps
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def isExpression(cls, other):
|
|
||||||
try:
|
|
||||||
other._isExpression
|
|
||||||
except AttributeError:
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# -----------
|
|
||||||
# Expression act as container from self.postfix_tokens
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
return self.postfix_tokens[index]
|
|
||||||
|
|
||||||
def __setitem__(self, index, value):
|
|
||||||
self.postfix_tokens[index] = value
|
|
||||||
|
|
||||||
# -----------
|
|
||||||
# Some math manipulations
|
|
||||||
|
|
||||||
def operate(self, other, operator):
|
|
||||||
if isinstance(other, Expression):
|
|
||||||
return Expression(
|
|
||||||
self.postfix_tokens +
|
|
||||||
other.postfix_tokens +
|
|
||||||
[operator])
|
|
||||||
elif isinstance(other, list):
|
|
||||||
return Expression(self.postfix_tokens + other + [operator])
|
|
||||||
else:
|
|
||||||
return Expression(self.postfix_tokens + [other] + [operator])
|
|
||||||
|
|
||||||
def roperate(self, other, operator):
|
|
||||||
if isinstance(other, Expression):
|
|
||||||
return Expression(
|
|
||||||
other.postfix_tokens +
|
|
||||||
self.postfix_tokens +
|
|
||||||
[operator])
|
|
||||||
elif isinstance(other, list):
|
|
||||||
return Expression(other + self.postfix_tokens + [operator])
|
|
||||||
else:
|
|
||||||
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 __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 __rtruediv__(self, other):
|
|
||||||
return self.roperate(other, op.div)
|
|
||||||
|
|
||||||
def __pow__(self, other):
|
|
||||||
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])
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ComputeError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,558 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .arithmetic import gcd
|
|
||||||
from .generic import isNumber, postfix_op
|
|
||||||
from .operator import op
|
|
||||||
from .expression import Expression
|
|
||||||
from .explicable import Explicable
|
|
||||||
from .step import Step
|
|
||||||
from copy import copy
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['Fraction']
|
|
||||||
|
|
||||||
|
|
||||||
class Fraction(Explicable):
|
|
||||||
"""Fractions!"""
|
|
||||||
|
|
||||||
def __init__(self, num, denom=1):
|
|
||||||
"""To initiate a fraction we need a numerator and a denominator
|
|
||||||
|
|
||||||
:param num: the numerator
|
|
||||||
:param denom: the denominator
|
|
||||||
|
|
||||||
"""
|
|
||||||
self._num = num
|
|
||||||
if denom == 0:
|
|
||||||
raise ZeroDivisionError("Can't create Fraction: division by zero")
|
|
||||||
self._denom = denom
|
|
||||||
|
|
||||||
self.isNumber = 1
|
|
||||||
pstf_tokens = self.compute_postfix_tokens()
|
|
||||||
super(Fraction, self).__init__(pstf_tokens)
|
|
||||||
|
|
||||||
def simplify(self):
|
|
||||||
"""Simplify the fraction
|
|
||||||
|
|
||||||
:returns: steps to simplify the fraction or the fraction if there is nothing to do
|
|
||||||
|
|
||||||
>>> f = Fraction(3, 6)
|
|
||||||
>>> f.simplify()
|
|
||||||
< 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>
|
|
||||||
>>> f.simplify().steps
|
|
||||||
[< Step [6, 9, /]>, < Step [2, 3, *, 3, 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
|
|
||||||
|
|
||||||
"""
|
|
||||||
ini_step = [Step(self.postfix_tokens)]
|
|
||||||
|
|
||||||
if self._num == 0:
|
|
||||||
return Expression([0]).simplify()
|
|
||||||
|
|
||||||
elif isinstance(self._num, Fraction) or isinstance(self._denom, Fraction):
|
|
||||||
return self._num / self._denom
|
|
||||||
|
|
||||||
elif self._denom < 0:
|
|
||||||
n_frac = Fraction(-self._num, -self._denom)
|
|
||||||
ans = n_frac.simplify()
|
|
||||||
ans.this_append_before(ini_step)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
gcd_ = gcd(abs(self._num), abs(self._denom))
|
|
||||||
if gcd_ == self._denom:
|
|
||||||
n_frac = self._num // gcd_
|
|
||||||
return Expression([n_frac]).simplify()
|
|
||||||
|
|
||||||
elif gcd_ != 1:
|
|
||||||
n_frac = Fraction(self._num // gcd_, self._denom // gcd_)
|
|
||||||
ini_step += [Step([
|
|
||||||
n_frac._num, gcd_, op.mul,
|
|
||||||
n_frac._denom, gcd_, op.mul,
|
|
||||||
op.div
|
|
||||||
])]
|
|
||||||
|
|
||||||
n_frac.this_append_before(ini_step)
|
|
||||||
return n_frac
|
|
||||||
|
|
||||||
else:
|
|
||||||
return copy(self)
|
|
||||||
|
|
||||||
def compute_postfix_tokens(self):
|
|
||||||
"""Postfix form of the fraction
|
|
||||||
|
|
||||||
>>> f = Fraction(3, 5)
|
|
||||||
>>> f.postfix_tokens
|
|
||||||
[3, 5, /]
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self._denom == 1:
|
|
||||||
return [self._num]
|
|
||||||
else:
|
|
||||||
return [self._num, self._denom, op.div]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(Expression(self.postfix_tokens))
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "< Fraction {num} / {denom}>".format(
|
|
||||||
num=self._num, denom=self._denom)
|
|
||||||
|
|
||||||
def __float__(self):
|
|
||||||
return self._num / self._denom
|
|
||||||
|
|
||||||
def convert2fraction(self, other):
|
|
||||||
""" Convert a other into a fraction """
|
|
||||||
if isinstance(other, Fraction):
|
|
||||||
# cool
|
|
||||||
number = other
|
|
||||||
else:
|
|
||||||
number = Fraction(other)
|
|
||||||
|
|
||||||
return number
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
""" overload +
|
|
||||||
|
|
||||||
>>> f = Fraction(1, 2)
|
|
||||||
>>> g = Fraction(2, 3)
|
|
||||||
>>> f + g
|
|
||||||
< Fraction 7 / 6>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f+g).steps]))
|
|
||||||
< Step [1, 2, /, 2, 3, /, +]>
|
|
||||||
< Step [1, 3, *, 2, 3, *, /, 2, 2, *, 3, 2, *, /, +]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, +]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, +]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, +]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, +]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, +]>
|
|
||||||
< Step [3, 4, +, 6, /]>
|
|
||||||
< Step [7, 6, /]>
|
|
||||||
>>> f + 2
|
|
||||||
< Fraction 5 / 2>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f+2).steps]))
|
|
||||||
< Step [1, 2, /, 2, +]>
|
|
||||||
< Step [1, 1, *, 2, 1, *, /, 2, 2, *, 1, 2, *, /, +]>
|
|
||||||
< Step [1, 2, /, 4, 2, /, +]>
|
|
||||||
< Step [1, 2, /, 4, 2, /, +]>
|
|
||||||
< Step [1, 2, /, 4, 2, /, +]>
|
|
||||||
< Step [1, 2, /, 4, 2, /, +]>
|
|
||||||
< Step [1, 2, /, 4, 2, /, +]>
|
|
||||||
< Step [1, 4, +, 2, /]>
|
|
||||||
< Step [5, 2, /]>
|
|
||||||
>>> f = Fraction(3, 4)
|
|
||||||
>>> g = Fraction(5, 4)
|
|
||||||
>>> f + g
|
|
||||||
2
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f+g).steps]))
|
|
||||||
< Step [3, 4, /, 5, 4, /, +]>
|
|
||||||
< Step [3, 5, +, 4, /]>
|
|
||||||
< Step [8, 4, /]>
|
|
||||||
< Step [8, 4, /]>
|
|
||||||
< Step [8, 4, /]>
|
|
||||||
>>> f+0
|
|
||||||
< Fraction 3 / 4>
|
|
||||||
>>> (f+0).steps
|
|
||||||
[]
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if other == 0:
|
|
||||||
return copy(self)
|
|
||||||
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
if self._denom == number._denom:
|
|
||||||
com_denom = self._denom
|
|
||||||
num1 = self._num
|
|
||||||
num2 = number._num
|
|
||||||
|
|
||||||
exp = Expression([num1, num2, op.add, com_denom, op.div])
|
|
||||||
|
|
||||||
else:
|
|
||||||
gcd_denom = gcd(self._denom, number._denom)
|
|
||||||
coef1 = number._denom // gcd_denom
|
|
||||||
coef2 = self._denom // gcd_denom
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
ans = exp.simplify()
|
|
||||||
ini_step = Step(self.postfix_tokens +
|
|
||||||
number.postfix_tokens + [op.add])
|
|
||||||
ans.this_append_before([ini_step])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __radd__(self, other):
|
|
||||||
if other == 0:
|
|
||||||
return Expression(self.postfix_tokens)
|
|
||||||
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
return number + self
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
""" overload -
|
|
||||||
|
|
||||||
>>> f = Fraction(1, 2)
|
|
||||||
>>> g = Fraction(2, 3)
|
|
||||||
>>> f - g
|
|
||||||
< Fraction -1 / 6>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f-g).steps]))
|
|
||||||
< Step [1, 2, /, 2, 3, /, -]>
|
|
||||||
< Step [1, 3, *, 2, 3, *, /, 2, 2, *, 3, 2, *, /, -]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, -]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, -]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, -]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, -]>
|
|
||||||
< Step [3, 6, /, 4, 6, /, -]>
|
|
||||||
< Step [3, 4, -, 6, /]>
|
|
||||||
< Step [-1, 6, /]>
|
|
||||||
>>> f - 0
|
|
||||||
< Fraction 1 / 2>
|
|
||||||
>>> (f-0).steps
|
|
||||||
[]
|
|
||||||
|
|
||||||
"""
|
|
||||||
if other == 0:
|
|
||||||
return copy(self)
|
|
||||||
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
if self._denom == number._denom:
|
|
||||||
com_denom = self._denom
|
|
||||||
num1 = self._num
|
|
||||||
num2 = number._num
|
|
||||||
|
|
||||||
exp = Expression([num1, num2, op.sub, com_denom, op.div])
|
|
||||||
|
|
||||||
else:
|
|
||||||
gcd_denom = gcd(self._denom, number._denom)
|
|
||||||
coef1 = number._denom // gcd_denom
|
|
||||||
coef2 = self._denom // gcd_denom
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
ini_step = Step(self.postfix_tokens +
|
|
||||||
number.postfix_tokens + [op.sub])
|
|
||||||
ans = exp.simplify()
|
|
||||||
ans.this_append_before([ini_step])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __rsub__(self, other):
|
|
||||||
if other == 0:
|
|
||||||
return copy(self)
|
|
||||||
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
return number - self
|
|
||||||
|
|
||||||
def __neg__(self):
|
|
||||||
""" overload - (as arity 1 operator)
|
|
||||||
|
|
||||||
>>> f = Fraction(1, 2)
|
|
||||||
>>> -f
|
|
||||||
< Fraction -1 / 2>
|
|
||||||
>>> (-f).steps
|
|
||||||
[]
|
|
||||||
>>> f = Fraction(1, -2)
|
|
||||||
>>> f
|
|
||||||
< Fraction 1 / -2>
|
|
||||||
>>> -f
|
|
||||||
< Fraction 1 / 2>
|
|
||||||
>>> (-f).steps
|
|
||||||
[< Step [-1, -2, /]>]
|
|
||||||
|
|
||||||
"""
|
|
||||||
f = Fraction(-self._num, self._denom)
|
|
||||||
ans = f.simplify()
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
""" overload *
|
|
||||||
|
|
||||||
>>> f = Fraction(1, 2)
|
|
||||||
>>> g = Fraction(2, 3)
|
|
||||||
>>> f*g
|
|
||||||
< Fraction 1 / 3>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f*g).steps]))
|
|
||||||
< Step [1, 2, /, 2, 3, /, *]>
|
|
||||||
< Step [1, 2, *, 2, 3, *, /]>
|
|
||||||
< Step [1, 3, /]>
|
|
||||||
< Step [1, 3, /]>
|
|
||||||
>>> f * 0
|
|
||||||
0
|
|
||||||
>>> (f*0).steps
|
|
||||||
[< Step [1, 2, /, 0, *]>]
|
|
||||||
>>> f*1
|
|
||||||
< Fraction 1 / 2>
|
|
||||||
>>> (f*1).steps
|
|
||||||
[< Step [1, 2, /, 1, *]>]
|
|
||||||
>>> f*4
|
|
||||||
2
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f*4).steps]))
|
|
||||||
< Step [1, 2, /, 4, *]>
|
|
||||||
< Step [1, 2, *, 2, *, 1, 2, *, /]>
|
|
||||||
< Step [1, 2, *, 1, /]>
|
|
||||||
< Step [2, 1, /]>
|
|
||||||
< Step [2, 1, /]>
|
|
||||||
< Step [2]>
|
|
||||||
|
|
||||||
"""
|
|
||||||
steps = [Step([self, other, op.mul])]
|
|
||||||
|
|
||||||
if other == 0:
|
|
||||||
exp = Expression([0])
|
|
||||||
elif other == 1:
|
|
||||||
exp = copy(self)
|
|
||||||
|
|
||||||
elif isinstance(other, int):
|
|
||||||
gcd1 = gcd(other, self._denom)
|
|
||||||
if gcd1 != 1:
|
|
||||||
num_s = [self._num] + \
|
|
||||||
[int(other / gcd1), op.mul] * (int(other / gcd1) != 1) + \
|
|
||||||
[gcd1, op.mul]
|
|
||||||
denom_s = [int(self._denom / gcd1), gcd1, op.mul]
|
|
||||||
steps.append(Step(num_s + denom_s + [op.div]))
|
|
||||||
|
|
||||||
num = [self._num] + [int(other / gcd1), op.mul] * (int(other / gcd1) != 1)
|
|
||||||
denom = [int(self._denom / gcd1)]
|
|
||||||
else:
|
|
||||||
num = [self._num, other, op.mul]
|
|
||||||
denom = [self._denom]
|
|
||||||
|
|
||||||
exp = Expression(num + denom + [op.div])
|
|
||||||
|
|
||||||
else:
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
gcd1 = gcd(self._num, number._denom)
|
|
||||||
if gcd1 != 1:
|
|
||||||
num1_s = [gcd1] + [int(self._num / gcd1), op.mul] * (int(self._num / gcd1) != 1)
|
|
||||||
denom2_s = [gcd1] + [int(number._denom / gcd1), op.mul] * (int(number._denom / gcd1) != 1)
|
|
||||||
|
|
||||||
num1 = [int(self._num / gcd1)] * (int(self._num / gcd1) != 1)
|
|
||||||
denom2 = [int(number._denom / gcd1)] * (int(self._denom / gcd1) != 1)
|
|
||||||
else:
|
|
||||||
num1_s = [self._num]
|
|
||||||
denom2_s = [number._denom]
|
|
||||||
|
|
||||||
num1 = [self._num]
|
|
||||||
denom2 = [number._denom]
|
|
||||||
|
|
||||||
gcd2 = gcd(self._denom, number._num)
|
|
||||||
if gcd2 != 1:
|
|
||||||
num2_s = [gcd2] + [int(number._num / gcd2), op.mul] * (int(number._num / gcd2) != 1)
|
|
||||||
denom1_s = [gcd2] + [int(self._denom / gcd2), op.mul] * (int(self._denom / gcd2) != 1)
|
|
||||||
|
|
||||||
num2 = [int(number._num / gcd2)] * (int(number._num / gcd2) != 1)
|
|
||||||
denom1 = [int(self._denom / gcd2)] * (int(number._denom / gcd2) != 1)
|
|
||||||
else:
|
|
||||||
num2_s = [number._num]
|
|
||||||
denom1_s = [self._denom]
|
|
||||||
|
|
||||||
num2 = [number._num]
|
|
||||||
denom1 = [self._denom]
|
|
||||||
|
|
||||||
steps.append(Step(num1_s + num2_s + [op.mul] +
|
|
||||||
denom1_s + denom2_s + [op.mul, op.div]))
|
|
||||||
|
|
||||||
exp = Expression(postfix_op(num1 + num2, op.mul, 1) +
|
|
||||||
postfix_op(denom1 + denom2, op.mul, 1) +
|
|
||||||
[op.div])
|
|
||||||
|
|
||||||
ans = exp.simplify()
|
|
||||||
ans.steps = steps + 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 copy(self)
|
|
||||||
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
ini_step = Step(self.postfix_tokens +
|
|
||||||
number.postfix_tokens + [op.div])
|
|
||||||
|
|
||||||
number = Fraction(number._denom, number._num)
|
|
||||||
ans = self * number
|
|
||||||
|
|
||||||
ans.this_append_before([ini_step])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __rtruediv__(self, other):
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
return number / self
|
|
||||||
|
|
||||||
def __pow__(self, power):
|
|
||||||
""" overload **
|
|
||||||
|
|
||||||
>>> f = Fraction(3, 4)
|
|
||||||
>>> f**0
|
|
||||||
1
|
|
||||||
>>> (f**0).steps
|
|
||||||
[< Step [3, 4, /, 0, ^]>]
|
|
||||||
>>> f**1
|
|
||||||
< Fraction 3 / 4>
|
|
||||||
>>> (f**1).steps
|
|
||||||
[< Step [3, 4, /, 1, ^]>]
|
|
||||||
>>> f**3
|
|
||||||
< Fraction 27 / 64>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f**3).steps]))
|
|
||||||
< Step [3, 4, /, 3, ^]>
|
|
||||||
< Step [3, 3, ^, 4, 3, ^, /]>
|
|
||||||
< Step [27, 64, /]>
|
|
||||||
< Step [27, 64, /]>
|
|
||||||
< Step [27, 64, /]>
|
|
||||||
>>> f = Fraction(6, 4)
|
|
||||||
>>> f**3
|
|
||||||
< Fraction 27 / 8>
|
|
||||||
>>> print("\\n".join([repr(i) for i in (f**3).steps]))
|
|
||||||
< Step [6, 4, /, 3, ^]>
|
|
||||||
< Step [6, 3, ^, 4, 3, ^, /]>
|
|
||||||
< Step [216, 64, /]>
|
|
||||||
< Step [216, 64, /]>
|
|
||||||
< Step [216, 64, /]>
|
|
||||||
< Step [216, 64, /]>
|
|
||||||
< Step [27, 8, *, 8, 8, *, /]>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not isinstance(power, int):
|
|
||||||
raise ValueError(
|
|
||||||
"Can't raise fraction to power {}".format(
|
|
||||||
str(power)))
|
|
||||||
|
|
||||||
ini_step = Step([self, power, op.pw])
|
|
||||||
if power == 0:
|
|
||||||
exp = Expression([1])
|
|
||||||
elif power == 1:
|
|
||||||
exp = copy(self)
|
|
||||||
else:
|
|
||||||
exp = Expression([
|
|
||||||
self._num, power, op.pw,
|
|
||||||
self._denom, power, op.pw,
|
|
||||||
op.div
|
|
||||||
])
|
|
||||||
|
|
||||||
ans = exp.simplify()
|
|
||||||
ans.this_append_before([ini_step])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __xor__(self, power):
|
|
||||||
""" overload ^
|
|
||||||
|
|
||||||
Work like **
|
|
||||||
|
|
||||||
>>> f = Fraction(3, 4)
|
|
||||||
>>> f^0
|
|
||||||
1
|
|
||||||
>>> f^1
|
|
||||||
< Fraction 3 / 4>
|
|
||||||
>>> f^3
|
|
||||||
< Fraction 27 / 64>
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__pow__(power)
|
|
||||||
|
|
||||||
def __abs__(self):
|
|
||||||
return Fraction(abs(self._num), abs(self._denom))
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
""" == """
|
|
||||||
if isNumber(other):
|
|
||||||
number = self.convert2fraction(other)
|
|
||||||
|
|
||||||
return self._num * number._denom == self._denom * number._num
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
|
||||||
""" < """
|
|
||||||
return float(self) < float(other)
|
|
||||||
|
|
||||||
def __le__(self, other):
|
|
||||||
""" <= """
|
|
||||||
return float(self) <= float(other)
|
|
||||||
|
|
||||||
def __gt__(self, other):
|
|
||||||
""" > """
|
|
||||||
return float(self) > float(other)
|
|
||||||
|
|
||||||
def __ge__(self, other):
|
|
||||||
""" >= """
|
|
||||||
return float(self) >= float(other)
|
|
||||||
|
|
||||||
def __copy__(self):
|
|
||||||
""" Copying the fraction removing steps where it is from """
|
|
||||||
return Fraction(self._num, self._denom)
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,399 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from itertools import zip_longest, chain
|
|
||||||
|
|
||||||
|
|
||||||
class Stack(object):
|
|
||||||
"""Docstring for Stack """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.items = []
|
|
||||||
|
|
||||||
def pushFromList(self, list):
|
|
||||||
"""Push the list in the stack
|
|
||||||
|
|
||||||
:param list: a list
|
|
||||||
"""
|
|
||||||
for i in list[::-1]:
|
|
||||||
self.push(i)
|
|
||||||
|
|
||||||
def isEmpty(self):
|
|
||||||
""" Says if the stack is empty
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.items == []
|
|
||||||
|
|
||||||
def push(self, item):
|
|
||||||
"""Push an item in the stack
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.items.append(item)
|
|
||||||
|
|
||||||
def pop(self):
|
|
||||||
"""Getting the last item and remove it
|
|
||||||
:returns: last item
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.items.pop()
|
|
||||||
|
|
||||||
def peek(self, posi=0):
|
|
||||||
"""Getting the last item
|
|
||||||
:param posi: which item to peek 0 (last) 1 (the onebefore the last)...
|
|
||||||
:returns: the item
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.items[-1 - posi]
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.items)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.items) + " -> "
|
|
||||||
|
|
||||||
def __add__(self, addList):
|
|
||||||
return self.items + addList
|
|
||||||
|
|
||||||
|
|
||||||
def flatten_list(a, result=None):
|
|
||||||
"""Flattens a nested list.
|
|
||||||
|
|
||||||
>>> flatten_list([ [1, 2, [3, 4] ], [5, 6], 7])
|
|
||||||
[1, 2, 3, 4, 5, 6, 7]
|
|
||||||
"""
|
|
||||||
if result is None:
|
|
||||||
result = []
|
|
||||||
|
|
||||||
for x in a:
|
|
||||||
if isinstance(x, list):
|
|
||||||
flatten_list(x, result)
|
|
||||||
else:
|
|
||||||
result.append(x)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def first_elem(ll):
|
|
||||||
"""Get the first element in imbricates lists
|
|
||||||
# TODO: Fonction pourrie mais j'ai pas le temps de faire mieux! |mar. janv. 28 22:32:22 CET 2014
|
|
||||||
|
|
||||||
:param list: list of lists of lists...
|
|
||||||
:returns: the first element
|
|
||||||
|
|
||||||
>>> first_elem(1)
|
|
||||||
1
|
|
||||||
>>> first_elem([1,2])
|
|
||||||
1
|
|
||||||
>>> first_elem([["abc"]])
|
|
||||||
'a'
|
|
||||||
>>> first_elem("abc")
|
|
||||||
'a'
|
|
||||||
>>> first_elem([[[1,2],[3,4]], [5,6]])
|
|
||||||
1
|
|
||||||
>>> first_elem([[["ab",2],[3,4]], [5,6]])
|
|
||||||
'a'
|
|
||||||
|
|
||||||
"""
|
|
||||||
if hasattr(ll, '__contains__'):
|
|
||||||
if len(ll) == 1 and isinstance(ll, str):
|
|
||||||
return ll[0]
|
|
||||||
else:
|
|
||||||
return first_elem(ll[0])
|
|
||||||
else:
|
|
||||||
return ll
|
|
||||||
|
|
||||||
|
|
||||||
def last_elem(ll):
|
|
||||||
"""Get the last element in imbricates lists
|
|
||||||
# TODO: Fonction pourrie mais j'ai pas le temps de faire mieux! |mar. janv. 28 22:32:22 CET 2014
|
|
||||||
|
|
||||||
:param list: list of lists of lists...
|
|
||||||
:returns: the last element
|
|
||||||
|
|
||||||
>>> last_elem(1)
|
|
||||||
1
|
|
||||||
>>> last_elem([1,2])
|
|
||||||
2
|
|
||||||
>>> last_elem([["abc"]])
|
|
||||||
'c'
|
|
||||||
>>> last_elem("abc")
|
|
||||||
'c'
|
|
||||||
>>> last_elem([[[1,2],[3,4]], [5,6]])
|
|
||||||
6
|
|
||||||
>>> last_elem([[["ab",2],[3,4]], [5,6]])
|
|
||||||
6
|
|
||||||
|
|
||||||
"""
|
|
||||||
if hasattr(ll, '__contains__'):
|
|
||||||
if len(ll) == 1 and isinstance(ll, str):
|
|
||||||
return ll[-1]
|
|
||||||
else:
|
|
||||||
return last_elem(ll[-1])
|
|
||||||
else:
|
|
||||||
return ll
|
|
||||||
|
|
||||||
|
|
||||||
def add_in_dict(dict1, dict2):
|
|
||||||
"""Merge dictionary keys and add the content from dict1 and dict2
|
|
||||||
|
|
||||||
:param dict1: first dictionary
|
|
||||||
:param dict2: second dictionary
|
|
||||||
:returns: merged and added dictionary
|
|
||||||
|
|
||||||
>>> add_in_dict({'a':1, 'b':2}, {'c':3, 'd': 4}) == {'d': 4, 'a': 1, 'c': 3, 'b': 2}
|
|
||||||
True
|
|
||||||
>>> add_in_dict({'a':1, 'b':2}, {'a':3, 'b': 4}) == {'a': 4, 'b': 6}
|
|
||||||
True
|
|
||||||
>>> add_in_dict({'a':1, 'b':2}, {'a':3, 'c': 4}) == {'a': 4, 'b': 2, 'c': 4}
|
|
||||||
True
|
|
||||||
|
|
||||||
"""
|
|
||||||
new_dict = {}
|
|
||||||
new_dict.update(dict1)
|
|
||||||
for (k, v) in dict2.items():
|
|
||||||
if k in new_dict.keys():
|
|
||||||
new_dict[k] += v
|
|
||||||
else:
|
|
||||||
new_dict[k] = v
|
|
||||||
|
|
||||||
return new_dict
|
|
||||||
|
|
||||||
|
|
||||||
def remove_in_dict(d, value=0):
|
|
||||||
""" In a dictionary, remove keys which have certain value
|
|
||||||
|
|
||||||
:param d: the dictionary
|
|
||||||
:param value: value to remove
|
|
||||||
:returns: new dictionary whithout unwanted value
|
|
||||||
|
|
||||||
>>> remove_in_dict({'b': 1, 'a': 0}) == {'b': 1}
|
|
||||||
True
|
|
||||||
>>> remove_in_dict({'b': 1, 'a': 0}, 1) == {'a': 0}
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
new_dict = {}
|
|
||||||
for (k, v) in d.items():
|
|
||||||
if v != value:
|
|
||||||
new_dict[k] = v
|
|
||||||
return new_dict
|
|
||||||
|
|
||||||
|
|
||||||
def convolution_dict(D1, D2, op=lambda x, y: x * y,
|
|
||||||
op_key=lambda x, y: x + y,
|
|
||||||
commutative=True, op_twice=lambda x, y: x + y):
|
|
||||||
"""Convolution of two dictionaries
|
|
||||||
|
|
||||||
:param D1: First dictionary
|
|
||||||
:param D2: Second dictionary
|
|
||||||
:param op: Operation of perform in value
|
|
||||||
:param commutative: keys are commutative?
|
|
||||||
:param op_twice: operation on value if the key appear twice
|
|
||||||
|
|
||||||
>>> convolution_dict({"a": 1, "b":3}, {"a":2, "":4}) == {"aa":2, "a": 4, "ba":6, "b":12}
|
|
||||||
True
|
|
||||||
>>> convolution_dict({"a": 1, "b":3}, {"a":2, "b":4}) == {"aa":2, "ab":10, "bb":12}
|
|
||||||
True
|
|
||||||
>>> convolution_dict({"a": 1, "b":3}, {"a":2, "b":4}, commutative = False) == {"aa":2, "ab":10, "bb":12}
|
|
||||||
False
|
|
||||||
>>> convolution_dict({"a": 1, "b":3}, {"a":2, "b":4}, commutative = False) == {"aa":2, "ab":4,"ba":6, "bb":12}
|
|
||||||
True
|
|
||||||
>>> convolution_dict({"a": 1, "b":3}, {"a":2, "b":4}, \
|
|
||||||
op_twice = lambda x,y:[x,y]) == {"aa":2, "ab":[4,6], "bb":12}
|
|
||||||
True
|
|
||||||
|
|
||||||
"""
|
|
||||||
new_dict = {}
|
|
||||||
|
|
||||||
for k1 in sorted(D1.keys()):
|
|
||||||
for k2 in sorted(D2.keys()):
|
|
||||||
if op_key(k1, k2) in new_dict.keys():
|
|
||||||
key = op_key(k1, k2)
|
|
||||||
new_dict[key] = op_twice(new_dict[key], op(D1[k1], D2[k2]))
|
|
||||||
|
|
||||||
elif op_key(k2, k1) in new_dict.keys() and commutative:
|
|
||||||
key = op_key(k2, k1)
|
|
||||||
new_dict[key] = op_twice(new_dict[key], op(D1[k1], D2[k2]))
|
|
||||||
|
|
||||||
else:
|
|
||||||
key = op_key(k1, k2)
|
|
||||||
new_dict[key] = op(D1[k1], D2[k2])
|
|
||||||
|
|
||||||
return new_dict
|
|
||||||
|
|
||||||
|
|
||||||
def spe_zip(l1, l2):
|
|
||||||
"""Zip two lists, if a list is longer, only it's element are taken
|
|
||||||
|
|
||||||
>>> spe_zip([1,2], [3,4])
|
|
||||||
[[1, 3], [2, 4]]
|
|
||||||
>>> spe_zip([1,2], [3,4,5])
|
|
||||||
[[1, 3], [2, 4], 5]
|
|
||||||
"""
|
|
||||||
tmp = list(zip_longest(l1, l2))
|
|
||||||
ans = []
|
|
||||||
for i in tmp:
|
|
||||||
if None in i:
|
|
||||||
j = [a for a in i if a is not None][-1]
|
|
||||||
else:
|
|
||||||
j = list(i)
|
|
||||||
ans.append(j)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
def expand_list(list_list):
|
|
||||||
"""Expand list of list
|
|
||||||
|
|
||||||
>>> expand_list([1,2,[3,4],5,[6,7,8]])
|
|
||||||
[[1, 2, 3, 5, 6], [1, 2, 4, 5, 7], [1, 2, 4, 5, 8]]
|
|
||||||
>>> expand_list([1,2,4,5,6,7,8])
|
|
||||||
[[1, 2, 4, 5, 6, 7, 8]]
|
|
||||||
|
|
||||||
"""
|
|
||||||
list_in_list = [
|
|
||||||
i if isinstance(i,list)
|
|
||||||
else [i]
|
|
||||||
for i in list_list
|
|
||||||
]
|
|
||||||
|
|
||||||
return list(transpose_fill(list_in_list))
|
|
||||||
|
|
||||||
|
|
||||||
def transpose_fill(list_lists):
|
|
||||||
"""Transpose a list of list and if inside list have not the same length, fill with last token
|
|
||||||
|
|
||||||
:list_lists: a list of list to transpose
|
|
||||||
:returns: generator which generate lines of the transposed matrix
|
|
||||||
|
|
||||||
>>> list(transpose_fill([[1], [2, 3], [4, 5, 6]]))
|
|
||||||
[[1, 2, 4], [1, 3, 5], [1, 3, 6]]
|
|
||||||
"""
|
|
||||||
for i in range(max([len(l) for l in list_lists])):
|
|
||||||
col = []
|
|
||||||
for l in list_lists:
|
|
||||||
try:
|
|
||||||
col.append(l[i])
|
|
||||||
except IndexError:
|
|
||||||
col.append(l[-1])
|
|
||||||
|
|
||||||
yield col
|
|
||||||
|
|
||||||
|
|
||||||
def postfix_op(numbers, operator, neutral = 0):
|
|
||||||
"""Convert a list of numbers into a postfix addition
|
|
||||||
|
|
||||||
:numbers: list of numbers
|
|
||||||
:operator: the operator to join with
|
|
||||||
:neutral: default value if the list is empty
|
|
||||||
:returns: Postfix list of succecive attition of number
|
|
||||||
|
|
||||||
>>> from .operator import op
|
|
||||||
>>> postfix_op([1], op.add)
|
|
||||||
[1]
|
|
||||||
>>> postfix_op([1, 2], op.add)
|
|
||||||
[1, 2, +]
|
|
||||||
>>> postfix_op([1, 2, 3], op.add)
|
|
||||||
[1, 2, +, 3, +]
|
|
||||||
>>> postfix_op([1, 2, 3], op.mul)
|
|
||||||
[1, 2, *, 3, *]
|
|
||||||
>>> postfix_op(1, op.add)
|
|
||||||
[1]
|
|
||||||
>>> postfix_op([], op.add)
|
|
||||||
[0]
|
|
||||||
>>> postfix_op([], op.mul, 1)
|
|
||||||
[1]
|
|
||||||
"""
|
|
||||||
if not isinstance(numbers, list):
|
|
||||||
return [numbers]
|
|
||||||
elif numbers == []:
|
|
||||||
return [neutral]
|
|
||||||
else:
|
|
||||||
ans = [[a, operator] if i != 0 else [a]
|
|
||||||
for (i, a) in enumerate(numbers)]
|
|
||||||
return list(chain.from_iterable(ans))
|
|
||||||
|
|
||||||
def isOperator(exp):
|
|
||||||
"""Check if the expression is an opération in "+-*/:^"
|
|
||||||
|
|
||||||
:param exp: an expression
|
|
||||||
:returns: boolean
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# return (type(exp) == str and exp in "+-*/:^")
|
|
||||||
try:
|
|
||||||
exp.isOperator
|
|
||||||
except AttributeError:
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def isNumber(exp):
|
|
||||||
"""Check if the expression can be a number
|
|
||||||
|
|
||||||
:param exp: an expression
|
|
||||||
:returns: True if the expression can be a number and false otherwise
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
exp.isNumber
|
|
||||||
except AttributeError:
|
|
||||||
if isinstance(exp, int):
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def isPolynom(exp):
|
|
||||||
"""Check if the expression can be a polynom
|
|
||||||
|
|
||||||
:param exp: an expression
|
|
||||||
:returns: True if the expression can be a polynom and false otherwise
|
|
||||||
|
|
||||||
>>> from mapytex.calculus.polynom import Polynom
|
|
||||||
>>> p = Polynom([1,2])
|
|
||||||
>>> isPolynom(p)
|
|
||||||
1
|
|
||||||
>>> isPolynom(1)
|
|
||||||
0
|
|
||||||
>>> isPolynom("a")
|
|
||||||
0
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
exp._isPolynom
|
|
||||||
except AttributeError:
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def isNumerand(exp):
|
|
||||||
"""Check is the expression is something we can compute with
|
|
||||||
|
|
||||||
>>> isNumerand(1)
|
|
||||||
1
|
|
||||||
>>> from mapytex.calculus.polynom import Polynom
|
|
||||||
>>> p = Polynom([1,2])
|
|
||||||
>>> isNumerand(p)
|
|
||||||
1
|
|
||||||
>>> from mapytex.calculus.fraction import Fraction
|
|
||||||
>>> f = Fraction(12)
|
|
||||||
>>> isNumerand(f)
|
|
||||||
1
|
|
||||||
>>> isNumerand("a")
|
|
||||||
0
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
return isNumber(exp) or isPolynom(exp)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import doctest
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator_set import op
|
|
||||||
from .operator import save_mainOp
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,70 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .operator import Operator, save_mainOp
|
|
||||||
|
|
||||||
|
|
||||||
class Add(Operator):
|
|
||||||
r""" The operator +
|
|
||||||
|
|
||||||
>>> add = Add()
|
|
||||||
>>> add
|
|
||||||
+
|
|
||||||
>>> add(1, 2)
|
|
||||||
3
|
|
||||||
>>> add.__tex__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> add.__tex__('-1','2')
|
|
||||||
'-1 + 2'
|
|
||||||
>>> add.__tex__('1','-2')
|
|
||||||
'1 - 2'
|
|
||||||
>>> add.__txt__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> add.__txt__('-1','2')
|
|
||||||
'-1 + 2'
|
|
||||||
>>> add.__txt__('1','-2')
|
|
||||||
'1 - 2'
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "+",
|
|
||||||
"name": "add",
|
|
||||||
"priority": 1,
|
|
||||||
"arity": 2,
|
|
||||||
"actions": ("__add__", "__radd__"),
|
|
||||||
"txt": "{op1} + {op2}",
|
|
||||||
"tex": "{op1} + {op2}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Add Operator """
|
|
||||||
super(Add, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,61 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .operator import Operator, save_mainOp
|
|
||||||
|
|
||||||
|
|
||||||
class Div(Operator):
|
|
||||||
r""" The operator /
|
|
||||||
|
|
||||||
>>> div = Div()
|
|
||||||
>>> div
|
|
||||||
/
|
|
||||||
>>> div(1, 2)
|
|
||||||
< Fraction 1 / 2>
|
|
||||||
>>> div.__tex__('1','2')
|
|
||||||
'\\frac{ 1 }{ 2 }'
|
|
||||||
>>> div.__tex__('-1','2')
|
|
||||||
'\\frac{ -1 }{ 2 }'
|
|
||||||
>>> div.__tex__('1','-2')
|
|
||||||
'\\frac{ 1 }{ -2 }'
|
|
||||||
>>> div.__txt__('1','2')
|
|
||||||
'1 / 2'
|
|
||||||
>>> div.__txt__('-1','2')
|
|
||||||
'-1 / 2'
|
|
||||||
>>> div.__txt__('1','-2')
|
|
||||||
'1 / ( -2 )'
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "/",
|
|
||||||
"name": "div",
|
|
||||||
"priority": 5,
|
|
||||||
"arity": 2,
|
|
||||||
"txt": "{op1} / {op2}",
|
|
||||||
"tex": "\\frac{{ {op1} }}{{ {op2} }}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Div Operator """
|
|
||||||
super(Div, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
def __call__(self, op1, op2):
|
|
||||||
if op2 == 1:
|
|
||||||
return op1
|
|
||||||
else:
|
|
||||||
from ..fraction import Fraction
|
|
||||||
return Fraction(op1, op2)
|
|
||||||
|
|
||||||
def __tex__(self, *args):
|
|
||||||
# Pas besoin de parenthèses en plus pour \frac
|
|
||||||
replacement = {"op"+str(i+1): op for (i, op) in enumerate(args)}
|
|
||||||
|
|
||||||
ans = self.tex.format(**replacement)
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,121 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator import Operator, save_mainOp
|
|
||||||
|
|
||||||
|
|
||||||
class Mul(Operator):
|
|
||||||
r""" The operator *
|
|
||||||
|
|
||||||
>>> mul = Mul()
|
|
||||||
>>> mul
|
|
||||||
*
|
|
||||||
>>> mul(1, 2)
|
|
||||||
2
|
|
||||||
>>> mul.__tex__('1','2')
|
|
||||||
'1 \\times 2'
|
|
||||||
>>> mul.__tex__('2','a')
|
|
||||||
'2 a'
|
|
||||||
>>> mul.__tex__('1','-2')
|
|
||||||
'1 \\times ( -2 )'
|
|
||||||
|
|
||||||
>>> mul.__txt__('1','2')
|
|
||||||
'1 * 2'
|
|
||||||
>>> mul.__txt__('2','a')
|
|
||||||
'2 a'
|
|
||||||
>>> mul.__txt__('a','2')
|
|
||||||
'a * 2'
|
|
||||||
>>> mul.__txt__('1','-2')
|
|
||||||
'1 * ( -2 )'
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "*",
|
|
||||||
"name": "mul",
|
|
||||||
"priority": 4,
|
|
||||||
"arity": 2,
|
|
||||||
"actions": ("__mul__", "__rmul__"),
|
|
||||||
"txt": "{op1} * {op2}",
|
|
||||||
"tex": "{op1} \\times {op2}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Mul Operator """
|
|
||||||
super(Mul, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
# TODO: Add self.visibility |sam. nov. 8 17:00:08 CET 2014
|
|
||||||
self.visibility = 1
|
|
||||||
|
|
||||||
def is_visible(self, op1, op2):
|
|
||||||
""" Tells whether self has to be visible or not
|
|
||||||
|
|
||||||
:param op1: left operande
|
|
||||||
:param op2: rigth operande
|
|
||||||
|
|
||||||
|
|
||||||
>>> m = Mul()
|
|
||||||
>>> m.is_visible(2, 3)
|
|
||||||
True
|
|
||||||
>>> m.is_visible(2, -3)
|
|
||||||
True
|
|
||||||
>>> m.is_visible(-2, 3)
|
|
||||||
True
|
|
||||||
>>> m.is_visible('a', 2)
|
|
||||||
True
|
|
||||||
>>> m.is_visible('(2a + 1)', 2)
|
|
||||||
True
|
|
||||||
>>> m.is_visible(2, '(-2)')
|
|
||||||
True
|
|
||||||
>>> m.is_visible(2, '2a')
|
|
||||||
True
|
|
||||||
>>> m.is_visible(2, '(-2a)')
|
|
||||||
True
|
|
||||||
>>> m.is_visible(2, '(-2abc)')
|
|
||||||
True
|
|
||||||
|
|
||||||
>>> m.is_visible(2, 'a')
|
|
||||||
False
|
|
||||||
>>> m.is_visible(2, '(2a + 1)')
|
|
||||||
False
|
|
||||||
>>> m.is_visible('(3x - 1)', '(2a + 1)')
|
|
||||||
False
|
|
||||||
>>> m.is_visible(2, '(-2x + 1)(3x + 2)')
|
|
||||||
False
|
|
||||||
"""
|
|
||||||
# TODO: À finir!!! |lun. mars 9 00:03:40 CET 2015
|
|
||||||
if type(op2) == int:
|
|
||||||
# op2 est maintenant une chaine de caractères
|
|
||||||
return True
|
|
||||||
elif op2.isdecimal():
|
|
||||||
return True
|
|
||||||
elif op2.isalpha():
|
|
||||||
return False
|
|
||||||
elif op2[0].isdecimal():
|
|
||||||
return True
|
|
||||||
elif op2[0] == "(" and not ("+" in op2 or "-" in op2[3:]):
|
|
||||||
return True
|
|
||||||
# Giga bricolage...
|
|
||||||
elif "frac" in op2:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _render(self, link, *args):
|
|
||||||
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = self.r_parenthesis(args[1], True)
|
|
||||||
|
|
||||||
if not self.is_visible(op1, op2):
|
|
||||||
ans = "{op1} {op2}".format(op1=op1, op2=op2)
|
|
||||||
else:
|
|
||||||
ans = link.format(op1=op1, op2=op2)
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,234 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
# from debug.tools import report
|
|
||||||
|
|
||||||
from ..generic import flatten_list
|
|
||||||
|
|
||||||
|
|
||||||
class Operator():
|
|
||||||
|
|
||||||
"""The operator class, is a string (representation of the operator) with its arity"""
|
|
||||||
|
|
||||||
def __init__(self, operator="", name="", priority=0, actions=("", ""), txt="", tex="", arity=2, **kwrds):
|
|
||||||
""" Create an Operator """
|
|
||||||
self.operator = operator
|
|
||||||
self.name = name
|
|
||||||
self.arity = arity
|
|
||||||
self.priority = priority
|
|
||||||
self.actions = actions
|
|
||||||
self.txt = txt
|
|
||||||
self.tex = tex
|
|
||||||
|
|
||||||
self.isOperator = 1
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
""" Calling this operator performs the rigth calculus """
|
|
||||||
if self.arity == 1:
|
|
||||||
return getattr(args[0], self.actions)()
|
|
||||||
|
|
||||||
elif self.arity == 2:
|
|
||||||
if issubclass(type(args[1]), int):
|
|
||||||
return getattr(args[0], self.actions[0])(args[1])
|
|
||||||
else:
|
|
||||||
return getattr(args[1], self.actions[1])(args[0])
|
|
||||||
|
|
||||||
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 self.arity == 1:
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
ans = link.format(op1=op1)
|
|
||||||
|
|
||||||
elif self.arity == 2:
|
|
||||||
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
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return str(self.operator)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.operator)
|
|
||||||
|
|
||||||
def __txt__(self, *args):
|
|
||||||
"""Txt rendering for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: String with operator and his operands
|
|
||||||
|
|
||||||
>>> from .mul import Mul
|
|
||||||
>>> mul= Mul()
|
|
||||||
>>> from .add import Add
|
|
||||||
>>> add = Add()
|
|
||||||
>>> from .sub import Sub
|
|
||||||
>>> sub = Sub()
|
|
||||||
>>> from .sub1 import Sub1
|
|
||||||
>>> sub1 = Sub1()
|
|
||||||
>>> mul.__txt__('1','2')
|
|
||||||
'1 * 2'
|
|
||||||
>>> add.__txt__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
|
||||||
>>> mul.__txt__(f, '4')
|
|
||||||
'( 2 + 3 ) * 4'
|
|
||||||
>>> f = save_mainOp('-3',sub1)
|
|
||||||
>>> sub1.__txt__(f)
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> sub1.__txt__('-3')
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
|
||||||
>>> sub1.__txt__(f)
|
|
||||||
'- ( 2 + 3 )'
|
|
||||||
"""
|
|
||||||
return self._render(self.txt, *args)
|
|
||||||
|
|
||||||
def __tex__(self, *args):
|
|
||||||
"""Tex rendering for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: String with operator and his operands
|
|
||||||
|
|
||||||
>>> from .mul import Mul
|
|
||||||
>>> mul= Mul()
|
|
||||||
>>> from .add import Add
|
|
||||||
>>> add = Add()
|
|
||||||
>>> from .sub import Sub
|
|
||||||
>>> sub = Sub()
|
|
||||||
>>> from .sub1 import Sub1
|
|
||||||
>>> sub1 = Sub1()
|
|
||||||
>>> mul.__tex__('1','2')
|
|
||||||
'1 \\\\times 2'
|
|
||||||
>>> add.__tex__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
|
||||||
>>> mul.__tex__(f, '4')
|
|
||||||
'( 2 + 3 ) \\\\times 4'
|
|
||||||
>>> f = save_mainOp('-3',sub1)
|
|
||||||
>>> sub1.__tex__(f)
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> sub1.__tex__('-3')
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
|
||||||
>>> sub1.__tex__(f)
|
|
||||||
'- ( 2 + 3 )'
|
|
||||||
"""
|
|
||||||
return self._render(self.tex, *args)
|
|
||||||
|
|
||||||
def __p2i__(self, *args):
|
|
||||||
"""Fix list transformation for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: list with the operator surrounded by operands
|
|
||||||
|
|
||||||
>>> from .mul import Mul
|
|
||||||
>>> mul= Mul()
|
|
||||||
>>> from .add import Add
|
|
||||||
>>> add = Add()
|
|
||||||
>>> from .sub import Sub
|
|
||||||
>>> sub = Sub()
|
|
||||||
>>> from .sub1 import Sub1
|
|
||||||
>>> sub1 = Sub1()
|
|
||||||
>>> mul.__p2i__(1,2)
|
|
||||||
[1, *, 2]
|
|
||||||
>>> f = save_mainOp([2, add, 3],add)
|
|
||||||
>>> mul.__p2i__(f, 4)
|
|
||||||
['(', 2, +, 3, ')', *, 4]
|
|
||||||
>>> f = save_mainOp([sub1, 3],sub1)
|
|
||||||
>>> sub1.__p2i__(f)
|
|
||||||
[-, '(', -, 3, ')']
|
|
||||||
>>> sub1.__p2i__(-3)
|
|
||||||
[-, '(', -3, ')']
|
|
||||||
>>> f = save_mainOp([2, add, 3],add)
|
|
||||||
>>> sub1.__p2i__(f)
|
|
||||||
[-, '(', 2, +, 3, ')']
|
|
||||||
"""
|
|
||||||
if self.arity == 1:
|
|
||||||
op1 = self.l_parenthesis(args[0])
|
|
||||||
ans = flatten_list([self, op1])
|
|
||||||
|
|
||||||
elif self.arity == 2:
|
|
||||||
op1 = self.l_parenthesis(args[0])
|
|
||||||
op2 = self.r_parenthesis(args[1])
|
|
||||||
ans = flatten_list([op1, self, op2])
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def l_parenthesis(self, opl, str_join=False):
|
|
||||||
""" Add parenthesis for left operand if necessary """
|
|
||||||
ans = opl
|
|
||||||
try:
|
|
||||||
if opl.mainOp.name == "sub1":
|
|
||||||
ans = opl
|
|
||||||
elif opl.mainOp.priority < self.priority:
|
|
||||||
ans = flatten_list(["(", opl, ")"])
|
|
||||||
except AttributeError:
|
|
||||||
# op has not the attribute priority
|
|
||||||
pass
|
|
||||||
|
|
||||||
ans = flatten_list([ans])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def r_parenthesis(self, opr, str_join=False):
|
|
||||||
""" Add parenthesis for rigth operand if necessary """
|
|
||||||
ans = opr
|
|
||||||
try:
|
|
||||||
if opr.mainOp.priority < self.priority or \
|
|
||||||
(opr.mainOp.name == 'mul' and opr[0] == '-'):
|
|
||||||
ans = flatten_list(["(", ans, ")"])
|
|
||||||
except AttributeError:
|
|
||||||
# op has not the attribute priority
|
|
||||||
try:
|
|
||||||
if int(ans) < 0:
|
|
||||||
ans = ['(', ans, ')']
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
ans = flatten_list([ans])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def uniq_desc(self):
|
|
||||||
""" Return the uniq description of the operator
|
|
||||||
:returns: (self.name, self.arity)
|
|
||||||
|
|
||||||
"""
|
|
||||||
return (self.operator, self.arity)
|
|
||||||
|
|
||||||
def __eq__(self, op2):
|
|
||||||
""" op1 == op2 """
|
|
||||||
try:
|
|
||||||
return self.name == op2.name and self.arity == op2.arity
|
|
||||||
except AttributeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def save_mainOp(obj, mainOp):
|
|
||||||
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
|
||||||
|
|
||||||
:obj: the object to add the attribute
|
|
||||||
:mainOp: the main operator
|
|
||||||
:returns: the same object with the main operation attribute
|
|
||||||
"""
|
|
||||||
# TODO: À mettre avec render? |mar. févr. 23 09:45:22 EAT 2016
|
|
||||||
# TODO: On pourrait mettre un try avant de créer une nouvelle classe |mar. févr. 23 09:44:45 EAT 2016
|
|
||||||
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': mainOp})
|
|
||||||
|
|
||||||
return Fake(obj)
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,129 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .add import Add
|
|
||||||
from .div import Div
|
|
||||||
from .mul import Mul
|
|
||||||
from .par import Par
|
|
||||||
from .pw import Pw
|
|
||||||
from .sub import Sub
|
|
||||||
from .sub1 import Sub1
|
|
||||||
from .operator import Operator
|
|
||||||
|
|
||||||
|
|
||||||
class Operator_set(object):
|
|
||||||
""" Class for sets of operators"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate the operator_set """
|
|
||||||
self._operators = {}
|
|
||||||
|
|
||||||
def get_op(self, op, arity=2):
|
|
||||||
r"""Return the corresponding operator
|
|
||||||
|
|
||||||
:op: symbole of the op
|
|
||||||
:arity: the arity (default is 2)
|
|
||||||
|
|
||||||
>>> op = Operator_set()
|
|
||||||
>>> op.store_operator(Add())
|
|
||||||
>>> op.get_op('+')
|
|
||||||
+
|
|
||||||
>>> mul = op.get_op('*')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
KeyError: '* (arity: 2) is not available'
|
|
||||||
>>> op.store_operator(Mul())
|
|
||||||
>>> mul = op.get_op('*')
|
|
||||||
>>> mul.tex
|
|
||||||
'{op1} \\times {op2}'
|
|
||||||
>>> mul.txt
|
|
||||||
'{op1} * {op2}'
|
|
||||||
>>> op.store_operator(Sub1())
|
|
||||||
>>> sub1 = op.get_op('-')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
KeyError: '- (arity: 2) is not available'
|
|
||||||
>>> sub1 = op.get_op('-', 1)
|
|
||||||
>>> sub1.tex
|
|
||||||
'- {op1}'
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return getattr(self, self._operators[(op, arity)])
|
|
||||||
except KeyError:
|
|
||||||
raise KeyError("{theOp} (arity: {arity}) is not available".format(theOp=op, arity=arity))
|
|
||||||
|
|
||||||
def available_op(self):
|
|
||||||
""" Get the set of available operators strings
|
|
||||||
|
|
||||||
>>> op = Operator_set()
|
|
||||||
>>> op.available_op()
|
|
||||||
set()
|
|
||||||
>>> op.store_operator(Add())
|
|
||||||
>>> '+' in op.available_op()
|
|
||||||
True
|
|
||||||
>>> '*' in op.available_op()
|
|
||||||
False
|
|
||||||
>>> op.store_operator(Mul())
|
|
||||||
>>> '*' in op.available_op()
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
return set([i[0] for i in self._operators])
|
|
||||||
|
|
||||||
def can_be_operator(cls, symbole):
|
|
||||||
r"""Tell if the symbole can be an operator
|
|
||||||
|
|
||||||
>>> op = Operator_set()
|
|
||||||
>>> op.can_be_operator("+")
|
|
||||||
False
|
|
||||||
>>> op.store_operator(Add())
|
|
||||||
>>> op.can_be_operator("+")
|
|
||||||
True
|
|
||||||
|
|
||||||
"""
|
|
||||||
if type(symbole) == str:
|
|
||||||
return symbole in [i[0] for i in cls._operators]
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def store_operator(self, operator):
|
|
||||||
""" Save the operator as a method and
|
|
||||||
|
|
||||||
:param operator: the operator (the class) (it will be accessible through .name method name.
|
|
||||||
|
|
||||||
>>> op = Operator_set()
|
|
||||||
>>> op._operators
|
|
||||||
{}
|
|
||||||
>>> op.store_operator(Add())
|
|
||||||
>>> op._operators
|
|
||||||
{('+', 2): 'add'}
|
|
||||||
>>> a = op.add
|
|
||||||
>>> a
|
|
||||||
+
|
|
||||||
>>> a.tex
|
|
||||||
'{op1} + {op2}'
|
|
||||||
>>> op.store_operator("+")
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: + is not en Operator it's a <class 'str'>
|
|
||||||
"""
|
|
||||||
if isinstance(operator, Operator):
|
|
||||||
self._operators[operator.uniq_desc()] = operator.name
|
|
||||||
setattr(self, operator.name, operator)
|
|
||||||
else:
|
|
||||||
raise ValueError("{} is not en Operator it's a {}".format(operator, type(operator)))
|
|
||||||
|
|
||||||
|
|
||||||
op = Operator_set()
|
|
||||||
op.store_operator(Add())
|
|
||||||
op.store_operator(Div())
|
|
||||||
op.store_operator(Mul())
|
|
||||||
op.store_operator(Par())
|
|
||||||
op.store_operator(Pw())
|
|
||||||
op.store_operator(Sub())
|
|
||||||
op.store_operator(Sub1())
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator import Operator
|
|
||||||
|
|
||||||
|
|
||||||
class Par(Operator):
|
|
||||||
|
|
||||||
""" The operator ( """
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "(",
|
|
||||||
"name": "par",
|
|
||||||
"priority": 0,
|
|
||||||
"arity": 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Par Operator """
|
|
||||||
super(Par, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,87 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator import Operator
|
|
||||||
from ..generic import flatten_list
|
|
||||||
|
|
||||||
|
|
||||||
class Pw(Operator):
|
|
||||||
|
|
||||||
""" The operator ^
|
|
||||||
|
|
||||||
>>> pw = Pw()
|
|
||||||
>>> pw
|
|
||||||
^
|
|
||||||
>>> pw(2, 3)
|
|
||||||
8
|
|
||||||
>>> pw.__tex__('2','3')
|
|
||||||
'2^{ 3 }'
|
|
||||||
>>> pw.__tex__('2','-3')
|
|
||||||
'2^{ -3 }'
|
|
||||||
>>> pw.__tex__('-2','3')
|
|
||||||
'( -2 )^{ 3 }'
|
|
||||||
>>> pw.__txt__('2','3')
|
|
||||||
'2 ^ 3'
|
|
||||||
>>> pw.__txt__('-2','3')
|
|
||||||
'( -2 ) ^ 3'
|
|
||||||
>>> pw.__txt__('2','-3')
|
|
||||||
'2 ^ ( -3 )'
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "^",
|
|
||||||
"name": "pw",
|
|
||||||
"priority": 6,
|
|
||||||
"arity": 2,
|
|
||||||
"actions": ("__pow__", ""),
|
|
||||||
"txt": "{op1} ^ {op2}",
|
|
||||||
"tex": "{op1}^{{ {op2} }}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Pw Operator """
|
|
||||||
super(Pw, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
def __call__(self, op1, op2):
|
|
||||||
""" Calling this operator performs the rigth calculus """
|
|
||||||
return getattr(op1, "__pow__")(op2)
|
|
||||||
|
|
||||||
def l_parenthesis(self, opl, str_join=False):
|
|
||||||
""" Add parenthesis for left operand if necessary """
|
|
||||||
ans = opl
|
|
||||||
try:
|
|
||||||
if opl.mainOp.priority < self.priority:
|
|
||||||
ans = flatten_list(["(", opl, ")"])
|
|
||||||
except AttributeError:
|
|
||||||
# op has not the attribute priority
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if int(opl) < 0:
|
|
||||||
ans = ["(", opl, ")"]
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
ans = flatten_list([ans])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __tex__(self, *args):
|
|
||||||
"""Tex rendering for ^
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: String with operator and his operands
|
|
||||||
|
|
||||||
"""
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = args[1]
|
|
||||||
ans = self.tex.format(op1=op1, op2=op2)
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,69 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator import Operator
|
|
||||||
from ..generic import flatten_list
|
|
||||||
|
|
||||||
|
|
||||||
class Sub(Operator):
|
|
||||||
|
|
||||||
""" The operator -
|
|
||||||
|
|
||||||
>>> sub = Sub()
|
|
||||||
>>> sub
|
|
||||||
-
|
|
||||||
>>> sub(1, 2)
|
|
||||||
-1
|
|
||||||
>>> sub.__tex__('1','2')
|
|
||||||
'1 - 2'
|
|
||||||
>>> sub.__tex__('1','-2')
|
|
||||||
'1 - ( -2 )'
|
|
||||||
>>> sub.__tex__('-1','2')
|
|
||||||
'-1 - 2'
|
|
||||||
>>> sub.__txt__('1','2')
|
|
||||||
'1 - 2'
|
|
||||||
>>> sub.__txt__('1','-2')
|
|
||||||
'1 - ( -2 )'
|
|
||||||
>>> sub.__txt__('-1','2')
|
|
||||||
'-1 - 2'
|
|
||||||
"""
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "-",
|
|
||||||
"name": "sub",
|
|
||||||
"priority": 2,
|
|
||||||
"arity": 2,
|
|
||||||
"actions": ("__sub__", "__rsub__"),
|
|
||||||
"txt": "{op1} - {op2}",
|
|
||||||
"tex": "{op1} - {op2}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Sub Operator """
|
|
||||||
super(Sub, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
def l_parenthesis(self, op, str_join=False):
|
|
||||||
return op
|
|
||||||
|
|
||||||
def r_parenthesis(self, op, str_join=False):
|
|
||||||
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:
|
|
||||||
if int(op) < 0:
|
|
||||||
op = ['(', op, ')']
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
ans = flatten_list([op])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .operator import Operator
|
|
||||||
from ..generic import flatten_list
|
|
||||||
|
|
||||||
|
|
||||||
class Sub1(Operator):
|
|
||||||
|
|
||||||
""" The operator -
|
|
||||||
|
|
||||||
>>> sub1 = Sub1()
|
|
||||||
>>> sub1
|
|
||||||
-
|
|
||||||
>>> sub1(1)
|
|
||||||
-1
|
|
||||||
>>> sub1.__tex__('1')
|
|
||||||
'- 1'
|
|
||||||
>>> sub1.__tex__('-1')
|
|
||||||
'- ( -1 )'
|
|
||||||
>>> sub1.__txt__('1')
|
|
||||||
'- 1'
|
|
||||||
>>> sub1.__txt__('-1')
|
|
||||||
'- ( -1 )'
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CARACT = {
|
|
||||||
"operator": "-",
|
|
||||||
"name": "sub1",
|
|
||||||
"priority": 3,
|
|
||||||
"arity": 1,
|
|
||||||
"actions": "__neg__",
|
|
||||||
"txt": "- {op1}",
|
|
||||||
"tex": "- {op1}",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initiate Sub1 Operator """
|
|
||||||
super(Sub1, self).__init__(**self._CARACT)
|
|
||||||
|
|
||||||
def l_parenthesis(self, op, str_join=False):
|
|
||||||
""" Add parenthesis if necessary """
|
|
||||||
try:
|
|
||||||
if op.mainOp.priority <= self.priority:
|
|
||||||
op = flatten_list(["("] + [op] + [")"])
|
|
||||||
except AttributeError:
|
|
||||||
# op has not the attribute priority
|
|
||||||
try:
|
|
||||||
if int(op) < 0:
|
|
||||||
op = ['(', op, ')']
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
ans = flatten_list([op])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,188 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from .expression import Expression
|
|
||||||
from .operator import op
|
|
||||||
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 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
|
|
||||||
|
|
||||||
|
|
||||||
class Polynom(AbstractPolynom):
|
|
||||||
|
|
||||||
"""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
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def random(
|
|
||||||
self,
|
|
||||||
coefs_form=[],
|
|
||||||
conditions=[],
|
|
||||||
letter="x",
|
|
||||||
degree=0,
|
|
||||||
name="P"):
|
|
||||||
""" Create a random polynom from coefs_form and conditions
|
|
||||||
|
|
||||||
:param coefs_form: list of forms (one by coef) (ascending degree sorted)
|
|
||||||
:param conditions: condition on variables
|
|
||||||
:param letter: the letter for the polynom
|
|
||||||
:param degree: degree of the polynom (can't be used with coefs_form, it will be overwrite) - can't be higher than 26 (number of letters in alphabet)
|
|
||||||
|
|
||||||
/!\ variables need to be in brackets {}
|
|
||||||
|
|
||||||
>>> Polynom.random(["{b}", "{a}"]) # doctest:+ELLIPSIS
|
|
||||||
< Polynom x ...
|
|
||||||
>>> Polynom.random(degree = 2) # doctest:+ELLIPSIS
|
|
||||||
< Polynom_deg2 x ...>
|
|
||||||
>>> Polynom.random(degree = 3) # doctest:+ELLIPSIS
|
|
||||||
< Polynom x ...>
|
|
||||||
>>> Polynom.random(degree = 2, conditions=["{b**2-4*a*c}>0"]) # Polynom deg 2 with positive Delta (ax^2 + bx + c)
|
|
||||||
< Polynom_deg2 x ...>
|
|
||||||
>>> Polynom.random(["{c}", "{b}", "{a}"], conditions=["{b**2-4*a*c}>0"]) # Same as above
|
|
||||||
< Polynom_deg2 x ...>
|
|
||||||
|
|
||||||
"""
|
|
||||||
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][::-1]
|
|
||||||
|
|
||||||
form = str(coefs_form)
|
|
||||||
# On créé les valeurs toutes concaténées dans un string
|
|
||||||
coefs = RdExpression(form, conditions)()
|
|
||||||
# On "parse" ce string pour créer les coefs
|
|
||||||
coefs = [eval(i) if isinstance(i, str) else i for i in eval(coefs)]
|
|
||||||
# Création du polynom
|
|
||||||
return Polynom(coefs=coefs, letter=letter, name=name)
|
|
||||||
|
|
||||||
def __init__(self, coefs=[1], letter="x", name="P", poly=0):
|
|
||||||
"""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 = Polynom([1, 2, 3])
|
|
||||||
>>> P.mainOp
|
|
||||||
+
|
|
||||||
>>> P.name
|
|
||||||
'P'
|
|
||||||
>>> P._letter
|
|
||||||
'x'
|
|
||||||
>>> Polynom([1]).mainOp
|
|
||||||
*
|
|
||||||
>>> Polynom([0, 0, 3]).mainOp
|
|
||||||
*
|
|
||||||
>>> Polynom([1, 2, 3])._letter
|
|
||||||
'x'
|
|
||||||
>>> Polynom([1, 2, 3], "y")._letter
|
|
||||||
'y'
|
|
||||||
>>> 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):
|
|
||||||
""" Evaluate the polynom in value
|
|
||||||
|
|
||||||
:returns: Expression ready to be simplify
|
|
||||||
|
|
||||||
>>> P = Polynom([1, 2, 3])
|
|
||||||
>>> P(2)
|
|
||||||
17
|
|
||||||
>>> for i in P(2).explain():
|
|
||||||
... print(i)
|
|
||||||
3 \\times 2^{ 2 } + 2 \\times 2 + 1
|
|
||||||
3 \\times 4 + 4 + 1
|
|
||||||
12 + 4 + 1
|
|
||||||
16 + 1
|
|
||||||
17
|
|
||||||
>>> Q = P("1+h")
|
|
||||||
>>> print(Q)
|
|
||||||
3 h^{ 2 } + 8 h + 6
|
|
||||||
>>> R = P(Q)
|
|
||||||
"""
|
|
||||||
eval_exp = self.replace_letter(value)
|
|
||||||
|
|
||||||
return eval_exp.simplify()
|
|
||||||
|
|
||||||
def derivate(self):
|
|
||||||
""" Return the derivated polynom
|
|
||||||
|
|
||||||
>>> P = Polynom([1, 2, 3])
|
|
||||||
>>> Q = P.derivate()
|
|
||||||
>>> Q
|
|
||||||
< Polynom x [2, 6]>
|
|
||||||
>>> print(Q.name)
|
|
||||||
P'
|
|
||||||
>>> for i in Q.explain():
|
|
||||||
... print(i)
|
|
||||||
2 \\times 3 x + 1 \\times 2
|
|
||||||
6 x + 2
|
|
||||||
"""
|
|
||||||
derv_coefs = []
|
|
||||||
for (i, c) in enumerate(self._coef):
|
|
||||||
derv_coefs += [Expression([i, c, op.mul])]
|
|
||||||
|
|
||||||
ans = Polynom(derv_coefs[1:]).simplify()
|
|
||||||
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))
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,248 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .polynom import Polynom
|
|
||||||
from .expression import Expression
|
|
||||||
from .fraction import Fraction
|
|
||||||
from .operator import op
|
|
||||||
from .random_expression import RdExpression
|
|
||||||
|
|
||||||
from sympy import sqrt, latex
|
|
||||||
# from sympy.fractions import Fraction as sp.Fraction
|
|
||||||
|
|
||||||
__all__ = ["Polynom_deg2"]
|
|
||||||
|
|
||||||
|
|
||||||
class Polynom_deg2(Polynom):
|
|
||||||
|
|
||||||
""" Degree 2 polynoms
|
|
||||||
Child of Polynom with some extra tools
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def random(
|
|
||||||
self,
|
|
||||||
coefs_form=[
|
|
||||||
"{c}",
|
|
||||||
"{b}",
|
|
||||||
"{a}"],
|
|
||||||
conditions=[],
|
|
||||||
letter="x",
|
|
||||||
name="P"):
|
|
||||||
""" Create a 2nd degree poly from coefs_form ans conditions
|
|
||||||
|
|
||||||
:param coefs_form: list of forms (one by coef) (ascending degree sorted)
|
|
||||||
:param conditions: condition on variables
|
|
||||||
:param letter: the letter for the polynom
|
|
||||||
|
|
||||||
"""
|
|
||||||
if len(coefs_form) != 3:
|
|
||||||
raise ValueError(
|
|
||||||
"Polynom_deg2 have to be degree 2 polynoms, they need 3 coefficients, {} are given".format(
|
|
||||||
len(coefs_form)))
|
|
||||||
|
|
||||||
form = str(coefs_form)
|
|
||||||
# On créé les valeurs toutes concaténées dans un string
|
|
||||||
coefs = RdExpression(form, conditions)()
|
|
||||||
# On "parse" ce string pour créer les coefs
|
|
||||||
coefs = [eval(i) if isinstance(i, str) else i for i in eval(coefs)]
|
|
||||||
# Création du polynom
|
|
||||||
return Polynom_deg2(coefs=coefs, letter=letter, name=name)
|
|
||||||
|
|
||||||
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:
|
|
||||||
raise ValueError(
|
|
||||||
"Polynom_deg2 have to be degree 2 polynoms, coefficient of x^2 can't be 0")
|
|
||||||
Polynom.__init__(self, coefs, letter, name=name)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def a(self):
|
|
||||||
return self._coef[2]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def b(self):
|
|
||||||
return self._coef[1]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def c(self):
|
|
||||||
return self._coef[0]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def delta(self):
|
|
||||||
"""Compute the discriminant expression
|
|
||||||
:returns: discriminant expression
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([1,2,3])
|
|
||||||
>>> P.delta
|
|
||||||
-8
|
|
||||||
>>> for i in P.delta.explain():
|
|
||||||
... print(i)
|
|
||||||
2^{ 2 } - 4 \\times 3 \\times 1
|
|
||||||
4 - 4 \\times 3
|
|
||||||
4 - 12
|
|
||||||
-8
|
|
||||||
"""
|
|
||||||
|
|
||||||
return Expression([self.b, 2, op.pw, 4, self.a,
|
|
||||||
self.c, op.mul, op.mul, op.sub]).simplify()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def alpha(self):
|
|
||||||
""" Compute alpha the abcisse of the extremum
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([1,2,3])
|
|
||||||
>>> P.alpha
|
|
||||||
< Fraction -1 / 3>
|
|
||||||
>>> for i in P.alpha.explain():
|
|
||||||
... print(i)
|
|
||||||
\\frac{ - 2 }{ 2 \\times 3 }
|
|
||||||
\\frac{ -2 }{ 6 }
|
|
||||||
\\frac{ -1 \\times 2 }{ 3 \\times 2 }
|
|
||||||
\\frac{ -1 }{ 3 }
|
|
||||||
"""
|
|
||||||
return Expression([self.b, op.sub1, 2, self.a,
|
|
||||||
op.mul, op.div]).simplify()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def beta(self):
|
|
||||||
r""" Compute beta the extremum of self
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([1,2,3])
|
|
||||||
>>> P.beta
|
|
||||||
< 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 } + \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{ -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)
|
|
||||||
|
|
||||||
def roots(self, after_coma=2):
|
|
||||||
""" Compute roots of the polynom
|
|
||||||
|
|
||||||
/!\ 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
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([1, 1, 1])
|
|
||||||
>>> P.roots()
|
|
||||||
[]
|
|
||||||
>>> P = Polynom_deg2([1, 2, 1])
|
|
||||||
>>> P.roots()
|
|
||||||
[-1]
|
|
||||||
>>> P = Polynom_deg2([-1, 0, 1])
|
|
||||||
>>> P.roots()
|
|
||||||
['-1', '1']
|
|
||||||
>>> P = Polynom_deg2([1, 4, 1])
|
|
||||||
>>> P.roots()
|
|
||||||
['-2 - \\\\sqrt{3}', '-2 + \\\\sqrt{3}']
|
|
||||||
"""
|
|
||||||
if self.delta > 0:
|
|
||||||
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 = [Fraction(-self.b, 2 * self.a).simplify()]
|
|
||||||
else:
|
|
||||||
self._roots = []
|
|
||||||
return self._roots
|
|
||||||
|
|
||||||
def tbl_sgn_header(self):
|
|
||||||
""" Return header of the sign line for tkzTabLine"""
|
|
||||||
if self.delta > 0:
|
|
||||||
return "{$-\\infty$, $" + str(min(self.roots())) + \
|
|
||||||
"$ , $" + str(max(self.roots())) + "$ , $+\\infty$}"
|
|
||||||
elif self.delta == 0:
|
|
||||||
return "{$-\\infty$, $" + str(self.roots()[0]) + "$ , $+\\infty$}"
|
|
||||||
else:
|
|
||||||
return "{$-\\infty$, $+\\infty$}"
|
|
||||||
|
|
||||||
def tbl_sgn(self):
|
|
||||||
""" Return the sign line for tkzTabLine
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([2, 5, 2])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, +, z, -, z , +,}
|
|
||||||
>>> P = Polynom_deg2([2, 1, -2])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, -, z, +, z , -,}
|
|
||||||
>>> P = Polynom_deg2([1, 2, 1])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, +, z, +,}
|
|
||||||
>>> P = Polynom_deg2([0, 0, -2])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, -, z, -,}
|
|
||||||
>>> P = Polynom_deg2([1, 0, 1])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, +,}
|
|
||||||
>>> P = Polynom_deg2([-1, 0, -1])
|
|
||||||
>>> print(P.tbl_sgn())
|
|
||||||
\\tkzTabLine{, -,}
|
|
||||||
"""
|
|
||||||
if self.delta > 0:
|
|
||||||
if self.a > 0:
|
|
||||||
return "\\tkzTabLine{, +, z, -, z , +,}"
|
|
||||||
else:
|
|
||||||
return "\\tkzTabLine{, -, z, +, z , -,}"
|
|
||||||
elif self.delta == 0:
|
|
||||||
if self.a > 0:
|
|
||||||
return "\\tkzTabLine{, +, z, +,}"
|
|
||||||
else:
|
|
||||||
return "\\tkzTabLine{, -, z, -,}"
|
|
||||||
else:
|
|
||||||
if self.a > 0:
|
|
||||||
return "\\tkzTabLine{, +,}"
|
|
||||||
else:
|
|
||||||
return "\\tkzTabLine{, -,}"
|
|
||||||
|
|
||||||
def tbl_variation(self, limits=False):
|
|
||||||
"""Return the variation line for tkzTabVar
|
|
||||||
|
|
||||||
:param limit: Display or not limits in tabular
|
|
||||||
|
|
||||||
>>> P = Polynom_deg2([1,2,3])
|
|
||||||
>>> print(P.tbl_variation())
|
|
||||||
\\tkzTabVar{+/{}, -/{$\\frac{ 2 }{ 3 }$}, +/{}}
|
|
||||||
>>> print(P.tbl_variation(limits = True))
|
|
||||||
\\tkzTabVar{+/{$+\\infty$}, -/{$\\frac{ 2 }{ 3 }$}, +/{$+\\infty$}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
beta = self.beta
|
|
||||||
if limits:
|
|
||||||
if self.a > 0:
|
|
||||||
return "\\tkzTabVar{+/{$+\\infty$}, -/{$" + \
|
|
||||||
str(beta) + "$}, +/{$+\\infty$}}"
|
|
||||||
else:
|
|
||||||
return "\\tkzTabVar{-/{$-\\infty$}, +/{$" + \
|
|
||||||
str(beta) + "$}, -/{$-\\infty$}}"
|
|
||||||
else:
|
|
||||||
if self.a > 0:
|
|
||||||
return "\\tkzTabVar{+/{}, -/{$" + str(beta) + "$}, +/{}}"
|
|
||||||
else:
|
|
||||||
return "\\tkzTabVar{-/{}, +/{$" + str(beta) + "$}, -/{}}"
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,161 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from random import randint
|
|
||||||
import re
|
|
||||||
import pyparsing
|
|
||||||
from .generic import flatten_list
|
|
||||||
|
|
||||||
# Below import are needed for conditions in varia generation.
|
|
||||||
from .arithmetic import gcd
|
|
||||||
|
|
||||||
|
|
||||||
def random_str(form, conditions=[], val_min=-10, val_max=10):
|
|
||||||
""" Create a random string using RdExpression class """
|
|
||||||
random_str_generator = RdExpression(form, conditions)
|
|
||||||
return random_str_generator(val_min, val_max)
|
|
||||||
|
|
||||||
|
|
||||||
class RdExpression(object):
|
|
||||||
"""
|
|
||||||
|
|
||||||
A generator of random expression builder
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, form, conditions=[]):
|
|
||||||
"""Initiate the generator
|
|
||||||
|
|
||||||
:param form: the form of the expression (/!\ variables need to be in brackets {})
|
|
||||||
:param conditions: condition on variables (/!\ variables need to be in brackets {})
|
|
||||||
|
|
||||||
"""
|
|
||||||
self._form = self.mod_underscores(form)
|
|
||||||
self._conditions = conditions
|
|
||||||
|
|
||||||
self._letters = self.get_letters()
|
|
||||||
self._gene_varia = {}
|
|
||||||
self._gene_2replaced = {}
|
|
||||||
|
|
||||||
def get_2replaced(self):
|
|
||||||
"""Get elements of self._form which will have to be replaced
|
|
||||||
:returns: set for elements which have to be replaced
|
|
||||||
|
|
||||||
"""
|
|
||||||
# TODO: Bug with varia with spaces |dim. nov. 23 10:44:34 CET 2014
|
|
||||||
varia_form = flatten_list([eval(str(i[0])) for i in pyparsing.nestedExpr(
|
|
||||||
'{', '}').searchString(self._form)])
|
|
||||||
varia_form = set(varia_form)
|
|
||||||
|
|
||||||
varia_cond = set()
|
|
||||||
for c in self._conditions:
|
|
||||||
c_varia_cond = flatten_list(
|
|
||||||
[eval(str(i[0])) for i in pyparsing.nestedExpr('{', '}').searchString(c)])
|
|
||||||
varia_cond = varia_cond | set(c_varia_cond)
|
|
||||||
|
|
||||||
self._2replaced = varia_cond | varia_form
|
|
||||||
|
|
||||||
return self._2replaced
|
|
||||||
|
|
||||||
def get_letters(self):
|
|
||||||
"""Find letters in the form
|
|
||||||
:returns: list of letters
|
|
||||||
|
|
||||||
"""
|
|
||||||
v2replaced = self.get_2replaced()
|
|
||||||
varia = set()
|
|
||||||
|
|
||||||
pattern = "([a-zA-Z]+)"
|
|
||||||
for v in v2replaced:
|
|
||||||
lvar = set(re.findall(pattern, v))
|
|
||||||
varia = varia | lvar
|
|
||||||
|
|
||||||
return varia
|
|
||||||
|
|
||||||
def mod_underscores(self, form):
|
|
||||||
""" Transform underscores of string to {...} forme with capital letters
|
|
||||||
|
|
||||||
:param form: the form string with _ to replace
|
|
||||||
:returns: the string with _ replaced
|
|
||||||
|
|
||||||
"""
|
|
||||||
i = 64
|
|
||||||
new_form = form
|
|
||||||
while "_" in new_form:
|
|
||||||
i += 1
|
|
||||||
new_form = new_form.replace("_", "{" + chr(i) + "}", 1)
|
|
||||||
|
|
||||||
return new_form
|
|
||||||
|
|
||||||
def __call__(self, val_min=-10, val_max=10):
|
|
||||||
"""RdExpression once it is initiate act like a function which create random expressions.
|
|
||||||
|
|
||||||
:param val_min: minimum value random generation
|
|
||||||
:param val_max: maximum value random generation
|
|
||||||
:returns: an formated random expression
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.raw_str(val_min, val_max)
|
|
||||||
|
|
||||||
def raw_str(self, val_min=-10, val_max=10):
|
|
||||||
"""Return raw string (don't use Expression for rendering or parsing)
|
|
||||||
|
|
||||||
:param val_min: minimum value random generation
|
|
||||||
:param val_max: maximum value random generation
|
|
||||||
:returns: an random Expression object
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.gene_varia(val_min, val_max)
|
|
||||||
|
|
||||||
while not(self.val_conditions()):
|
|
||||||
self.gene_varia(val_min, val_max)
|
|
||||||
|
|
||||||
exp = self._form.format(**self._gene_2replaced)
|
|
||||||
|
|
||||||
return exp
|
|
||||||
|
|
||||||
def gene_varia(self, val_min=-10, val_max=10):
|
|
||||||
"""Randomly generates variables/letters
|
|
||||||
|
|
||||||
Varia can't be equal to 0
|
|
||||||
|
|
||||||
"""
|
|
||||||
for l in self._letters:
|
|
||||||
self._gene_varia[l] = randint(val_min, val_max)
|
|
||||||
while self._gene_varia[l] == 0:
|
|
||||||
self._gene_varia[l] = randint(val_min, val_max)
|
|
||||||
|
|
||||||
for e in self._2replaced:
|
|
||||||
self._gene_2replaced[e] = eval(e, globals(), self._gene_varia)
|
|
||||||
|
|
||||||
def val_conditions(self):
|
|
||||||
"""Tells whether or not conditions are validates
|
|
||||||
:returns: boolean
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self._conditions != []:
|
|
||||||
return eval(
|
|
||||||
" and ".join(
|
|
||||||
self._conditions).format(
|
|
||||||
**self._gene_2replaced))
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def desc_rdExp(rdExp):
|
|
||||||
print("--------------------")
|
|
||||||
print("form: ", rdExp._form)
|
|
||||||
print("Conditions: ", rdExp._conditions)
|
|
||||||
print("Letters: ", rdExp._letters)
|
|
||||||
print("2replaced: ", rdExp._2replaced)
|
|
||||||
print("Call : ", rdExp())
|
|
||||||
print("type: ", type(rdExp()))
|
|
||||||
print("Gene varia: ", rdExp._gene_varia)
|
|
||||||
print("Gene 2replaced: ", rdExp._gene_2replaced)
|
|
||||||
print('')
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,99 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .generic import Stack, isOperator
|
|
||||||
|
|
||||||
__all__ = ['txt', 'tex', 'p2i']
|
|
||||||
|
|
||||||
|
|
||||||
class Render(object):
|
|
||||||
""" Create functions which know how to render postfix tokens lists """
|
|
||||||
|
|
||||||
def __init__(self, render):
|
|
||||||
"""Initiate the render
|
|
||||||
|
|
||||||
:param render: function which take an operator and return a function to render the operator with his operands
|
|
||||||
"""
|
|
||||||
self.render = render
|
|
||||||
|
|
||||||
def __call__(self, postfix_tokens):
|
|
||||||
"""Make the object acting like a function
|
|
||||||
|
|
||||||
:param postfix_tokens: the list of postfix tokens to be render
|
|
||||||
:returns: the render string
|
|
||||||
|
|
||||||
"""
|
|
||||||
operandeStack = Stack()
|
|
||||||
for token in postfix_tokens:
|
|
||||||
|
|
||||||
if isOperator(token):
|
|
||||||
if token.arity == 1:
|
|
||||||
|
|
||||||
op1 = operandeStack.pop()
|
|
||||||
|
|
||||||
operandeStack.push(self.render(token)(op1))
|
|
||||||
elif token.arity == 2:
|
|
||||||
op1 = operandeStack.pop()
|
|
||||||
op2 = operandeStack.pop()
|
|
||||||
# Switch op1 and op2 to respect order
|
|
||||||
operandeStack.push(self.render(token)(op2, op1))
|
|
||||||
else:
|
|
||||||
operandeStack.push(self.render(token)())
|
|
||||||
|
|
||||||
if len(operandeStack) > 1:
|
|
||||||
raise ValueError("This postfix_tokens is not a valid expression")
|
|
||||||
else:
|
|
||||||
return operandeStack.pop()
|
|
||||||
|
|
||||||
|
|
||||||
def txt_render(token):
|
|
||||||
def render(*args):
|
|
||||||
try:
|
|
||||||
return getattr(token, '__txt__')(*args)
|
|
||||||
except AttributeError:
|
|
||||||
return str(token)
|
|
||||||
return render
|
|
||||||
|
|
||||||
txt = Render(txt_render)
|
|
||||||
|
|
||||||
|
|
||||||
def tex_render(token):
|
|
||||||
def render(*args):
|
|
||||||
try:
|
|
||||||
return getattr(token, '__tex__')(*args)
|
|
||||||
except AttributeError:
|
|
||||||
return str(token)
|
|
||||||
return render
|
|
||||||
tex = Render(tex_render)
|
|
||||||
|
|
||||||
|
|
||||||
def p2i_render(token):
|
|
||||||
def render(*args):
|
|
||||||
try:
|
|
||||||
return getattr(token, '__p2i__')(*args)
|
|
||||||
except AttributeError:
|
|
||||||
return token
|
|
||||||
return render
|
|
||||||
p2i = Render(p2i_render)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
from .operator import op
|
|
||||||
from itertools import permutations
|
|
||||||
from mapytex import Polynom
|
|
||||||
from mapytex import Expression
|
|
||||||
from mapytex import Fraction
|
|
||||||
coefs_p = [[(i - 2), (j - 2)] for i, j in permutations(range(5), 2)]
|
|
||||||
coefs_q = [[2 * (i - 2), 2 * (j - 2)]
|
|
||||||
for i, j in permutations(range(5), 2)]
|
|
||||||
l_p = [Polynom(i) for i in coefs_p]
|
|
||||||
l_q = [Fraction(i, j) for i, j in coefs_q if j != 0]
|
|
||||||
operations = [Expression([l_p[i], l_q[j], op.mul])
|
|
||||||
for i, j in permutations(range(len(l_q)), 2)]
|
|
||||||
for i in operations:
|
|
||||||
print(i)
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,116 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .render import tex, txt
|
|
||||||
|
|
||||||
__all__ = ['Renderable']
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@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
|
|
||||||
>>> from .explicable import Explicable
|
|
||||||
>>> 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{ 3 }{ 5 } \\times 2
|
|
||||||
\\frac{ 3 \\times 2 }{ 5 }
|
|
||||||
\\frac{ 6 }{ 5 }
|
|
||||||
>>> with Explicable.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):
|
|
||||||
self.old_render = Renderable.get_render()
|
|
||||||
Renderable.set_render(render)
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
Renderable.set_render(self.old_render)
|
|
||||||
return TmpRenderEnv()
|
|
||||||
|
|
||||||
def __init__(self, pstf_tokens):
|
|
||||||
"""Initiate the renderable objet
|
|
||||||
|
|
||||||
:param pstf_tokens: the postfix list of tokens
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.postfix_tokens = pstf_tokens
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""
|
|
||||||
Overload str
|
|
||||||
|
|
||||||
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 "< {cls} {pstf_tokens}>".format(
|
|
||||||
cls = str(self.__class__).split('.')[-1][:-2],
|
|
||||||
pstf_tokens = str(self.postfix_tokens)
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def __txt__(self):
|
|
||||||
try:
|
|
||||||
return txt(self.postfix_tokens)
|
|
||||||
except AttributeError:
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __tex__(self):
|
|
||||||
try:
|
|
||||||
return tex(self.postfix_tokens)
|
|
||||||
except AttributeError:
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,90 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .renderable import Renderable
|
|
||||||
|
|
||||||
__all__ = ['Step']
|
|
||||||
|
|
||||||
class Step(Renderable):
|
|
||||||
"""
|
|
||||||
A step is a Renderable which his only goal is to be render.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tmp_render(cls):
|
|
||||||
""" Create a container in which the method explain return only Step object.
|
|
||||||
|
|
||||||
>>> 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{ 3 }{ 5 } \\times 2
|
|
||||||
\\frac{ 3 \\times 2 }{ 5 }
|
|
||||||
\\frac{ 6 }{ 5 }
|
|
||||||
>>> with Step.tmp_render():
|
|
||||||
... for i in exp.simplify().explain():
|
|
||||||
... print(repr(i))
|
|
||||||
< Step [2, 3, 5, /, *]>
|
|
||||||
< Step [3, 5, /, 2, *]>
|
|
||||||
< Step [3, 2, *, 5, /]>
|
|
||||||
< Step [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 }
|
|
||||||
|
|
||||||
"""
|
|
||||||
return super(Step, cls).tmp_render(Step)
|
|
||||||
|
|
||||||
def __init__(self, exp):
|
|
||||||
"""Initiate the renderable objet
|
|
||||||
|
|
||||||
:param pstf_tokens: the postfix list of tokens
|
|
||||||
|
|
||||||
>>> s = Step([2, 3, '+'])
|
|
||||||
>>> s
|
|
||||||
< Step [2, 3, '+']>
|
|
||||||
>>> s1 = Step([s, 5, '*'])
|
|
||||||
>>> s1
|
|
||||||
< Step [2, 3, '+', 5, '*']>
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(exp, Renderable):
|
|
||||||
self.postfix_tokens = exp.postfix_tokens
|
|
||||||
elif isinstance(exp, list):
|
|
||||||
self.postfix_tokens = []
|
|
||||||
for t in exp:
|
|
||||||
try:
|
|
||||||
self.postfix_tokens += t.postfix_tokens
|
|
||||||
except AttributeError:
|
|
||||||
self.postfix_tokens.append(t)
|
|
||||||
else:
|
|
||||||
raise ValueError(
|
|
||||||
"Can't initiate Step with {}".format(
|
|
||||||
exp
|
|
||||||
))
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
try:
|
|
||||||
if self.postfix_tokens == other.postfix_tokens:
|
|
||||||
return True
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
if str(self).replace(' ', '') == str(other).replace(' ',''):
|
|
||||||
return True
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,277 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .generic import Stack, isNumber, isPolynom
|
|
||||||
from .operator import op
|
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
import logging
|
|
||||||
# logging.basicConfig(filename='str2tokens_debug.log',level=logging.DEBUG)
|
|
||||||
|
|
||||||
|
|
||||||
def str2tokens(exp):
|
|
||||||
""" Parse the string into tokens then turn it into postfix form
|
|
||||||
|
|
||||||
>>> str2tokens('2+3*4')
|
|
||||||
[2, 3, 4, *, +]
|
|
||||||
>>> str2tokens('2*3+4')
|
|
||||||
[2, 3, *, 4, +]
|
|
||||||
>>> str2tokens('2x+4')
|
|
||||||
[2, < Polynom x [0, 1]>, *, 4, +]
|
|
||||||
"""
|
|
||||||
in_tokens = str2in_tokens(exp)
|
|
||||||
post_tokens = in2post_fix(in_tokens)
|
|
||||||
|
|
||||||
return post_tokens
|
|
||||||
|
|
||||||
|
|
||||||
def str2in_tokens(exp):
|
|
||||||
""" Parse the expression, ie tranform a string into a list of tokens
|
|
||||||
|
|
||||||
:param exp: The expression (a string)
|
|
||||||
:returns: list of token
|
|
||||||
|
|
||||||
>>> str2in_tokens('2+3*4')
|
|
||||||
[2, '+', 3, '*', 4]
|
|
||||||
>>> str2in_tokens('2*3+4')
|
|
||||||
[2, '*', 3, '+', 4]
|
|
||||||
>>> str2in_tokens('12*3+4')
|
|
||||||
[12, '*', 3, '+', 4]
|
|
||||||
>>> str2in_tokens('2.3*3+4')
|
|
||||||
[Decimal('2.3'), '*', 3, '+', 4]
|
|
||||||
>>> str2in_tokens('a*3+4')
|
|
||||||
[< Polynom a [0, 1]>, '*', 3, '+', 4]
|
|
||||||
"""
|
|
||||||
tokens = ['', '']
|
|
||||||
|
|
||||||
for character in exp:
|
|
||||||
if character.isdigit():
|
|
||||||
tokens += feed_digit(character, tokens.pop(), tokens[-1])
|
|
||||||
|
|
||||||
elif character == "(":
|
|
||||||
tokens += hidden_meaning_time(tokens[-1])
|
|
||||||
tokens.append("(")
|
|
||||||
|
|
||||||
elif character in op.available_op():
|
|
||||||
tokens.append(character)
|
|
||||||
|
|
||||||
elif character == ")":
|
|
||||||
tokens.append(character)
|
|
||||||
|
|
||||||
elif character.isalpha():
|
|
||||||
tokens += hidden_meaning_time(tokens[-1])
|
|
||||||
tokens.append(feed_alpha(character))
|
|
||||||
|
|
||||||
elif character == ".":
|
|
||||||
tokens.append(feed_dot(tokens.pop()))
|
|
||||||
|
|
||||||
elif character != " ":
|
|
||||||
raise ValueError("{} is an unvalid character".format(character))
|
|
||||||
|
|
||||||
return tokens[2:]
|
|
||||||
|
|
||||||
|
|
||||||
def feed_digit(character, tok_b, tok_bb):
|
|
||||||
""" Feed token when a digit is detected
|
|
||||||
|
|
||||||
:param character: the character
|
|
||||||
:param tok_b: the token before
|
|
||||||
:param tok_bb: the token before before
|
|
||||||
:returns: list of token to replace
|
|
||||||
|
|
||||||
>>> feed_digit(1, '-', 2)
|
|
||||||
['-', 1]
|
|
||||||
>>> feed_digit(1, '', '')
|
|
||||||
['', 1]
|
|
||||||
>>> feed_digit(1, 2, '')
|
|
||||||
[21]
|
|
||||||
>>> feed_digit(1, Decimal(2), '')
|
|
||||||
[Decimal('2.1')]
|
|
||||||
>>> feed_digit(1, Decimal('2.3'), '')
|
|
||||||
[Decimal('2.31')]
|
|
||||||
>>> feed_digit(1, -2, '')
|
|
||||||
[-21]
|
|
||||||
>>> feed_digit(1, Decimal('-2'), '')
|
|
||||||
[Decimal('-2.1')]
|
|
||||||
>>> feed_digit(1, '-', '')
|
|
||||||
[-1]
|
|
||||||
>>> feed_digit(1, '-', '+')
|
|
||||||
[-1]
|
|
||||||
>>> feed_digit(1, '-', '(')
|
|
||||||
[-1]
|
|
||||||
>>> feed_digit(1, '-', 2)
|
|
||||||
['-', 1]
|
|
||||||
>>> from mapytex.calculus.polynom import Polynom
|
|
||||||
>>> feed_digit(1, '-', Polynom([0,1]))
|
|
||||||
['-', 1]
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(tok_b, int):
|
|
||||||
return [tok_b * 10 + int(tok_b/abs(tok_b)) * int(character)]
|
|
||||||
|
|
||||||
elif isinstance(tok_b, Decimal):
|
|
||||||
return [tok_b + int(tok_b/abs(tok_b)) * int(character) * Decimal('10') ** (tok_b.as_tuple().exponent - 1)]
|
|
||||||
|
|
||||||
# TODO: WTF!!! |sam. févr. 27 17:11:53 EAT 2016
|
|
||||||
elif tok_b == "-" and (str(tok_bb) in op.available_op() or str(tok_bb) == ""):
|
|
||||||
return [- int(character)]
|
|
||||||
else:
|
|
||||||
return [tok_b, int(character)]
|
|
||||||
|
|
||||||
|
|
||||||
def hidden_meaning_time(tok_b):
|
|
||||||
""" Return a "*" character if it is hidden meaning
|
|
||||||
|
|
||||||
:param tok_b: the token before
|
|
||||||
|
|
||||||
>>> hidden_meaning_time(4)
|
|
||||||
['*']
|
|
||||||
>>> hidden_meaning_time(')')
|
|
||||||
['*']
|
|
||||||
>>> from mapytex.calculus.polynom import Polynom
|
|
||||||
>>> hidden_meaning_time(Polynom([0,1]))
|
|
||||||
['*']
|
|
||||||
>>> hidden_meaning_time("+")
|
|
||||||
[]
|
|
||||||
>>> hidden_meaning_time("*")
|
|
||||||
[]
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isNumber(tok_b) \
|
|
||||||
or tok_b == ")" \
|
|
||||||
or isPolynom(tok_b):
|
|
||||||
return ["*"]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def feed_alpha(character):
|
|
||||||
""" Feed token when an alpha character is detected
|
|
||||||
|
|
||||||
:param character: the alpha character
|
|
||||||
:param tok_b: the token before
|
|
||||||
:returns: tokens to add
|
|
||||||
|
|
||||||
"""
|
|
||||||
from mapytex.calculus.polynom import Polynom
|
|
||||||
return Polynom([0, 1], letter=character)
|
|
||||||
|
|
||||||
|
|
||||||
def feed_dot(tok_b):
|
|
||||||
r""" Build Decimal with the previous token
|
|
||||||
|
|
||||||
:param tok_b: the previous token
|
|
||||||
:returns: the Decimal
|
|
||||||
|
|
||||||
>>> feed_dot(2)
|
|
||||||
Decimal('2')
|
|
||||||
>>> feed_dot(Decimal('2.3'))
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: A number has 2 points...! We have 2.3 before the dot
|
|
||||||
>>> feed_dot('+')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Try to make decimal but + before the dot
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(tok_b, int):
|
|
||||||
return Decimal(tok_b)
|
|
||||||
elif isinstance(tok_b, Decimal):
|
|
||||||
raise ValueError("A number has 2 points...! We have {} before the dot".format(tok_b))
|
|
||||||
else:
|
|
||||||
raise ValueError("Try to make decimal but {} before the dot".format(tok_b))
|
|
||||||
|
|
||||||
|
|
||||||
def in2post_fix(infix_tokens):
|
|
||||||
""" From the infix_tokens list compute the corresponding postfix_tokens list
|
|
||||||
|
|
||||||
@param infix_tokens: the infix list of tokens to transform into postfix form.
|
|
||||||
@return: the corresponding postfix list of tokens.
|
|
||||||
|
|
||||||
>>> in2post_fix(['(', 2, '+', 5, '-', 1, ')', '/', '(', 3, '*', 4, ')'])
|
|
||||||
[2, 5, 1, -, +, 3, 4, *, /]
|
|
||||||
>>> in2post_fix(['-', '(', '-', 2, ')'])
|
|
||||||
[2, -, -]
|
|
||||||
>>> in2post_fix(['-', '(', '-', 2, '+', 3, '*', 4, ')'])
|
|
||||||
[2, -, 3, 4, *, +, -]
|
|
||||||
"""
|
|
||||||
logging.debug("New start with {}".format(infix_tokens))
|
|
||||||
# Stack where operator will be stocked
|
|
||||||
opStack = Stack()
|
|
||||||
# final postfix list of tokens
|
|
||||||
postfix_tokens = []
|
|
||||||
# stack with the nbr of tokens still to compute in postfix_tokens
|
|
||||||
arity_Stack = Stack()
|
|
||||||
arity_Stack.push(0)
|
|
||||||
|
|
||||||
for (pos_token, token) in enumerate(infix_tokens):
|
|
||||||
|
|
||||||
logging.debug(str(postfix_tokens) +
|
|
||||||
" | " + str(opStack) +
|
|
||||||
" | " + str(infix_tokens[(pos_token+1):]) +
|
|
||||||
" | " + str(arity_Stack)
|
|
||||||
)
|
|
||||||
if token == ")":
|
|
||||||
next_op = opStack.pop()
|
|
||||||
while next_op != op.par:
|
|
||||||
postfix_tokens.append(next_op)
|
|
||||||
next_op = opStack.pop()
|
|
||||||
|
|
||||||
# Go back to old arity
|
|
||||||
arity_Stack.pop()
|
|
||||||
# Raise the arity
|
|
||||||
arity = arity_Stack.pop()
|
|
||||||
arity_Stack.push(arity + 1)
|
|
||||||
|
|
||||||
elif op.can_be_operator(token):
|
|
||||||
if token == "(":
|
|
||||||
opStack.push(op.get_op(token, 0))
|
|
||||||
# Set next arity counter
|
|
||||||
arity_Stack.push(0)
|
|
||||||
else:
|
|
||||||
arity = arity_Stack.pop()
|
|
||||||
token_op = op.get_op(token, arity + 1)
|
|
||||||
# Reset arity to 0 in case there is other operators (the real
|
|
||||||
# operation would be "-op.arity + 1")
|
|
||||||
arity_Stack.push(0)
|
|
||||||
while (not opStack.isEmpty()) and opStack.peek(
|
|
||||||
).priority >= token_op.priority:
|
|
||||||
next_op = opStack.pop()
|
|
||||||
postfix_tokens.append(next_op)
|
|
||||||
|
|
||||||
opStack.push(token_op)
|
|
||||||
logging.debug("--" + token + " -> " + str(arity + 1))
|
|
||||||
else:
|
|
||||||
postfix_tokens.append(token)
|
|
||||||
arity = arity_Stack.pop()
|
|
||||||
arity_Stack.push(arity + 1)
|
|
||||||
|
|
||||||
logging.debug(str(postfix_tokens) +
|
|
||||||
" | " + str(opStack) +
|
|
||||||
" | " + str(infix_tokens[(pos_token+1):]) +
|
|
||||||
" | " + str(arity_Stack)
|
|
||||||
)
|
|
||||||
|
|
||||||
while not opStack.isEmpty():
|
|
||||||
next_op = opStack.pop()
|
|
||||||
postfix_tokens.append(next_op)
|
|
||||||
|
|
||||||
logging.debug(str(postfix_tokens) +
|
|
||||||
" | " + str(opStack) +
|
|
||||||
" | " + str(infix_tokens[(pos_token+1):]) +
|
|
||||||
" | " + str(arity_Stack)
|
|
||||||
)
|
|
||||||
|
|
||||||
if arity_Stack.peek() != 1:
|
|
||||||
raise ValueError(
|
|
||||||
"Unvalid expression. The arity Stack is ",
|
|
||||||
str(arity_Stack))
|
|
||||||
|
|
||||||
logging.debug("Fini!")
|
|
||||||
return postfix_tokens
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
File diff suppressed because it is too large
Load Diff
@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from mapytex.calculus import arithmetic
|
|
||||||
|
|
||||||
|
|
||||||
def test_gcd_commu():
|
|
||||||
assert arithmetic.gcd(3, 15) == arithmetic.gcd(15, 3)
|
|
||||||
|
|
||||||
|
|
||||||
def test_gcd1():
|
|
||||||
assert arithmetic.gcd(3, 15) == 3
|
|
||||||
|
|
||||||
|
|
||||||
def test_gcd2():
|
|
||||||
assert arithmetic.gcd(14, 21) == 7
|
|
||||||
|
|
||||||
|
|
||||||
def test_gcd_prem():
|
|
||||||
assert arithmetic.gcd(14, 19) == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_gcd_neg():
|
|
||||||
assert arithmetic.gcd(3, -15) == 3
|
|
||||||
assert arithmetic.gcd(-3, -15) == -3
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,86 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
""" Testing Expression """
|
|
||||||
|
|
||||||
|
|
||||||
from mapytex.calculus.expression import Expression
|
|
||||||
from mapytex.calculus.operator import op
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_from_str():
|
|
||||||
exp = Expression("2 + 3")
|
|
||||||
assert exp.postfix_tokens == [2, 3, op.add]
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_from_exp():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_list():
|
|
||||||
exp = Expression([2, 3, "+"])
|
|
||||||
assert exp.postfix_tokens == [2, 3, op.add]
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_one_element_int_from_str():
|
|
||||||
exp = Expression("1")
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_one_element_int_from_list():
|
|
||||||
exp = Expression([1])
|
|
||||||
|
|
||||||
# def test_init_one_element_str_from_str():
|
|
||||||
# exp = Expression("x")
|
|
||||||
#
|
|
||||||
# def test_init_one_element_str_from_list():
|
|
||||||
# exp = Expression(["x"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_simplify_exp():
|
|
||||||
exp = Expression("1 + 2 * 3")
|
|
||||||
simplified = exp.simplify()
|
|
||||||
ans = Expression("7")
|
|
||||||
assert ans == simplified
|
|
||||||
|
|
||||||
# def test_simplify_frac():
|
|
||||||
# exp = Expression("1/2 - 4")
|
|
||||||
# simplified = exp.simplify()
|
|
||||||
# ans = Expression("-7/2")
|
|
||||||
# assert simplified == ans
|
|
||||||
#
|
|
||||||
# def test_explain_frac():
|
|
||||||
# exp = Expression("1/2 - 4")
|
|
||||||
# simplified = exp.simplify()
|
|
||||||
#
|
|
||||||
# steps = ['\\frac{ 1 }{ 2 } - 4', \
|
|
||||||
# '\\frac{ 1 \\times 1 }{ 2 \\times 1 } - \\frac{ 4 \\times 2 }{ 1 \\times 2 }',\
|
|
||||||
# '\\frac{ 1 }{ 2 } - \\frac{ 8 }{ 2 }',\
|
|
||||||
# '\\frac{ 1 - 8 }{ 2 }',\
|
|
||||||
# '\\frac{ -7 }{ 2 }']
|
|
||||||
# assert simplified.steps == list(exp.simplify())
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_exp():
|
|
||||||
e = Expression("12- 4")
|
|
||||||
f = Expression("4 + 1")
|
|
||||||
g = e + f
|
|
||||||
assert g.postfix_tokens == [12, 4, op.sub, 4, 1, op.add, op.add]
|
|
||||||
|
|
||||||
|
|
||||||
def test_mul_exp():
|
|
||||||
e = Expression("12- 4")
|
|
||||||
f = Expression("4 + 1")
|
|
||||||
g = e * f
|
|
||||||
assert g.postfix_tokens == [12, 4, op.sub, 4, 1, op.add, op.mul]
|
|
||||||
|
|
||||||
|
|
||||||
def test_neg_exp():
|
|
||||||
e = Expression("12- 4")
|
|
||||||
g = -e
|
|
||||||
assert g.postfix_tokens == [12, 4, op.sub, op.sub1]
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,104 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus.fraction import Fraction
|
|
||||||
|
|
||||||
|
|
||||||
class TestFraction(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.Fraction"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.listFrom = [Fraction(1, 3), 1]
|
|
||||||
self.listAgainst = [Fraction(1, 3),
|
|
||||||
Fraction(2, 3),
|
|
||||||
Fraction(4, 5),
|
|
||||||
Fraction(-1, 3),
|
|
||||||
Fraction(1, -3),
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_add(self):
|
|
||||||
ans = [
|
|
||||||
[
|
|
||||||
Fraction(
|
|
||||||
2, 3), 1, Fraction(
|
|
||||||
17, 15), 0, 0, Fraction(
|
|
||||||
4, 3)], [
|
|
||||||
Fraction(
|
|
||||||
4, 3), Fraction(
|
|
||||||
5, 3), Fraction(
|
|
||||||
9, 5), Fraction(
|
|
||||||
2, 3), Fraction(
|
|
||||||
2, 3), 2]]
|
|
||||||
|
|
||||||
for (i, f1) in enumerate(self.listFrom):
|
|
||||||
for (j, f2) in enumerate(self.listAgainst):
|
|
||||||
res = f1 + f2
|
|
||||||
self.assertEqual(res, ans[i][j])
|
|
||||||
|
|
||||||
def test_sub(self):
|
|
||||||
ans = [[0, Fraction(-1, 3), Fraction(-7, 15), Fraction(2, 3), Fraction(2, 3), Fraction(-2, 3)],
|
|
||||||
[Fraction(2, 3), Fraction(1, 3), Fraction(1, 5), Fraction(4, 3), Fraction(4, 3), 0]
|
|
||||||
]
|
|
||||||
|
|
||||||
for (i, f1) in enumerate(self.listFrom):
|
|
||||||
for (j, f2) in enumerate(self.listAgainst):
|
|
||||||
res = f1 - f2
|
|
||||||
self.assertEqual(res, ans[i][j])
|
|
||||||
|
|
||||||
def test_neg(self):
|
|
||||||
ans = [Fraction(-1, 3),
|
|
||||||
Fraction(-2, 3),
|
|
||||||
Fraction(-4, 5),
|
|
||||||
Fraction(1, 3),
|
|
||||||
Fraction(1, 3),
|
|
||||||
-1
|
|
||||||
]
|
|
||||||
for (j, f) in enumerate(self.listAgainst):
|
|
||||||
res = -f
|
|
||||||
self.assertEqual(res, ans[j])
|
|
||||||
|
|
||||||
def test_mul(self):
|
|
||||||
ans = [[Fraction(1, 9), Fraction(2, 9), Fraction(4, 15), Fraction(-1, 9), Fraction(-1, 9), Fraction(
|
|
||||||
1, 3)], [Fraction(1, 3), Fraction(2, 3), Fraction(4, 5), Fraction(-1, 3), Fraction(1, -3), 1]]
|
|
||||||
|
|
||||||
for (i, f1) in enumerate(self.listFrom):
|
|
||||||
for (j, f2) in enumerate(self.listAgainst):
|
|
||||||
res = f1 * f2
|
|
||||||
self.assertEqual(res, ans[i][j])
|
|
||||||
|
|
||||||
def test_truediv(self):
|
|
||||||
ans = [[1, Fraction(1, 2), Fraction(5, 12), -1, -1, Fraction(1, 3)],
|
|
||||||
[3, Fraction(3, 2), Fraction(5, 4), -3, -3, 1]
|
|
||||||
]
|
|
||||||
|
|
||||||
for (i, f1) in enumerate(self.listFrom):
|
|
||||||
for (j, f2) in enumerate(self.listAgainst):
|
|
||||||
res = f1 / f2
|
|
||||||
self.assertEqual(res, ans[i][j])
|
|
||||||
|
|
||||||
def test_lt(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_le(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_tex(self):
|
|
||||||
f = Fraction(2, 3)
|
|
||||||
ans = "\\frac{ 2 }{ 3 }"
|
|
||||||
self.assertEqual(f.__tex__(), ans)
|
|
||||||
|
|
||||||
def test_txt(self):
|
|
||||||
f = Fraction(2, 3)
|
|
||||||
ans = "2 / 3"
|
|
||||||
self.assertEqual(f.__txt__(), ans)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,74 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus import generic
|
|
||||||
|
|
||||||
|
|
||||||
class TestGeneric(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.generic"""
|
|
||||||
|
|
||||||
def test_flatten_list1(self):
|
|
||||||
l = [1, [2, 3], [[4, 5], 6], 7]
|
|
||||||
flat_l = generic.flatten_list(l)
|
|
||||||
|
|
||||||
true_flat = list(range(1, 8))
|
|
||||||
|
|
||||||
self.assertEqual(flat_l, true_flat)
|
|
||||||
|
|
||||||
def test_flatten_list2(self):
|
|
||||||
l = list(range(10))
|
|
||||||
flat_l = generic.flatten_list(l)
|
|
||||||
|
|
||||||
true_flat = list(range(10))
|
|
||||||
|
|
||||||
self.assertEqual(flat_l, true_flat)
|
|
||||||
|
|
||||||
def test_first_elem_simple_iter(self):
|
|
||||||
""" For simple iterable """
|
|
||||||
l = range(10)
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(0, first)
|
|
||||||
|
|
||||||
s = "plopplop"
|
|
||||||
first = generic.first_elem(s)
|
|
||||||
self.assertAlmostEqual("p", first)
|
|
||||||
|
|
||||||
def test_first_elem_iter_in_iter(self):
|
|
||||||
""" Interable in iterable """
|
|
||||||
l = [[1, 2], [4, 5, [6, 7, 8]], 9]
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(first, 1)
|
|
||||||
|
|
||||||
l = [[[1]]]
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(first, 1)
|
|
||||||
|
|
||||||
l = ["abc"]
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(first, "a")
|
|
||||||
|
|
||||||
l = ["abc", [4, 5, [6, 7, 8]], 9]
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(first, "a")
|
|
||||||
|
|
||||||
l = [["abc", 1], [4, 5, [6, 7, 8]], 9]
|
|
||||||
first = generic.first_elem(l)
|
|
||||||
|
|
||||||
self.assertAlmostEqual(first, "a")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,190 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus.polynom import Polynom
|
|
||||||
from mapytex.calculus.fraction import Fraction
|
|
||||||
from mapytex.calculus.expression import Expression
|
|
||||||
from mapytex.calculus.render import txt
|
|
||||||
from mapytex.calculus.operator import op
|
|
||||||
|
|
||||||
|
|
||||||
class TestPolynom(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.polynom"""
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
Expression.set_render(txt)
|
|
||||||
|
|
||||||
def test_init(self):
|
|
||||||
p = Polynom([1, 2, 3], "x")
|
|
||||||
|
|
||||||
def test_init_multi(self):
|
|
||||||
p = Polynom([1, [2, 3], 4], "x")
|
|
||||||
|
|
||||||
# def test_init_arith(self):
|
|
||||||
# p = Polynom([1, [2, 3, "+"], 4], "x")
|
|
||||||
|
|
||||||
# def test_init_arith_2(self):
|
|
||||||
# p = Polynom([1, [[2, 3, "*"],3], 4], "x")
|
|
||||||
|
|
||||||
def test_deg(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_eval_base(self):
|
|
||||||
p = Polynom([1, 2])
|
|
||||||
self.assertEqual(p(3), 7)
|
|
||||||
|
|
||||||
def test_eval_const(self):
|
|
||||||
p = Polynom([1])
|
|
||||||
self.assertEqual(p(3), 1)
|
|
||||||
|
|
||||||
def test_eval_const_neg(self):
|
|
||||||
p = Polynom([-1])
|
|
||||||
self.assertEqual(p(3), -1)
|
|
||||||
|
|
||||||
def test_eval_poly(self):
|
|
||||||
p = Polynom([1, 2])
|
|
||||||
self.assertEqual(p("h+1"), Polynom([3, 2], "h"))
|
|
||||||
|
|
||||||
def test_postfix(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
ans = [3, 'x', 2, op.pw, op.mul, 2, 'x', op.mul, op.add, 1, op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_monom(self):
|
|
||||||
p = Polynom([0, 2])
|
|
||||||
ans = [2, "x", op.mul]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_0_coef(self):
|
|
||||||
p = Polynom([0, 2, 0, 4])
|
|
||||||
ans = [4, 'x', 3, op.pw, op.mul, 2, 'x', op.mul, op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_1_coef(self):
|
|
||||||
p = Polynom([0, 1, 1])
|
|
||||||
ans = ["x", 2, op.pw, "x", op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_neg_coef(self):
|
|
||||||
p = Polynom([-1, -2, -3])
|
|
||||||
ans = [-3, 'x', 2, op.pw, op.mul, -2, 'x', op.mul, op.add, -1, op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_multi_coef(self):
|
|
||||||
p = Polynom([1, [2, 3], 4])
|
|
||||||
ans = [4, 'x', 2, op.pw, op.mul, 2, 'x', op.mul, op.add, 3, 'x', op.mul, op.add, 1, op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_postfix_exp_coef(self):
|
|
||||||
p = Polynom([1, Expression([2, 3, "+"]), 4])
|
|
||||||
ans = [4, 'x', 2, op.pw, op.mul, 2, 3, op.add, 'x', op.mul, op.add, 1, op.add]
|
|
||||||
self.assertEqual(ans, p.postfix_tokens)
|
|
||||||
|
|
||||||
def test_str(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
ans = '3 x^{ 2 } + 2 x + 1'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_monom(self):
|
|
||||||
p = Polynom([0, 2])
|
|
||||||
ans = '2 x'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_0_coef(self):
|
|
||||||
p = Polynom([0, 2, 0, 4])
|
|
||||||
ans = '4 x^{ 3 } + 2 x'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_1_coef(self):
|
|
||||||
p = Polynom([0, 1, 1])
|
|
||||||
ans = 'x^{ 2 } + x'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_neg_coef(self):
|
|
||||||
p = Polynom([-1, -2, -3])
|
|
||||||
ans = '-3 x^{ 2 } - 2 x - 1'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_multi_coef(self):
|
|
||||||
p = Polynom([1, [2, 3], 4])
|
|
||||||
ans = '4 x^{ 2 } + 2 x + 3 x + 1'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_str_exp_coef(self):
|
|
||||||
p = Polynom([1, Expression([2, 3, "+"]), 4])
|
|
||||||
ans = '4 x^{ 2 } + ( 2 + 3 ) x + 1'
|
|
||||||
self.assertEqual(ans, str(p))
|
|
||||||
|
|
||||||
def test_reduce_nilpo(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
self.assertEqual(p, p.reduce())
|
|
||||||
|
|
||||||
def test_reduce(self):
|
|
||||||
p = Polynom([1, [2, 3], 4])
|
|
||||||
ans = '4 x^{ 2 } + 5 x + 1'
|
|
||||||
self.assertEqual(str(p.reduce()), ans)
|
|
||||||
|
|
||||||
def test_add_int(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
q = p + 2
|
|
||||||
ans = '3 x^{ 2 } + 2 x + 3'
|
|
||||||
self.assertEqual(str(q), ans)
|
|
||||||
|
|
||||||
def test_add_frac(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
f = Fraction(1, 2)
|
|
||||||
q = p + f
|
|
||||||
ans = '3 x^{ 2 } + 2 x + \\frac{ 3 }{ 2 }'
|
|
||||||
self.assertEqual(str(q), ans)
|
|
||||||
|
|
||||||
def test_add_poly(self):
|
|
||||||
p = Polynom([1, 0, 3])
|
|
||||||
q = Polynom([0, 2, 3])
|
|
||||||
r = p + q
|
|
||||||
ans = '6 x^{ 2 } + 2 x + 1'
|
|
||||||
self.assertEqual(str(r), ans)
|
|
||||||
|
|
||||||
def test_sub_int(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
q = p - 2
|
|
||||||
ans = '3 x^{ 2 } + 2 x - 1'
|
|
||||||
self.assertEqual(str(q), ans)
|
|
||||||
|
|
||||||
def test_sub_frac(self):
|
|
||||||
p = Polynom([1, 2, 3])
|
|
||||||
f = Fraction(1, 2)
|
|
||||||
q = p - f
|
|
||||||
ans = '3 x^{ 2 } + 2 x + \\frac{ 1 }{ 2 }'
|
|
||||||
self.assertEqual(str(q), ans)
|
|
||||||
|
|
||||||
def test_sub_poly(self):
|
|
||||||
p = Polynom([1, 0, 2])
|
|
||||||
q = Polynom([0, 2, 3])
|
|
||||||
r = p - q
|
|
||||||
ans = '- x^{ 2 } - 2 x + 1'
|
|
||||||
self.assertEqual(str(r), ans)
|
|
||||||
|
|
||||||
def test_pow_monome(self):
|
|
||||||
p = Polynom([0, -2])
|
|
||||||
r = p**3
|
|
||||||
ans = '-8 x^{ 3 }'
|
|
||||||
self.assertEqual(str(r), ans)
|
|
||||||
|
|
||||||
def test_pow2_monome(self):
|
|
||||||
p = Polynom([0, -2])
|
|
||||||
r = p ^ 3
|
|
||||||
ans = '-8 x^{ 3 }'
|
|
||||||
self.assertEqual(str(r), ans)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus.polynomDeg2 import Polynom_deg2
|
|
||||||
|
|
||||||
|
|
||||||
class TestPolynomDeg2(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.polynomDeg2"""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,108 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
from mapytex.calculus.random_expression import RdExpression
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form():
|
|
||||||
form = "{a} + 2"
|
|
||||||
rdExp = RdExpression(form)
|
|
||||||
|
|
||||||
assert rdExp._letters == {'a'}
|
|
||||||
assert rdExp._2replaced == {'a'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()) == {'a'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()) == {'a'}
|
|
||||||
|
|
||||||
|
|
||||||
def test_form_with_underscores():
|
|
||||||
form = "_ + 2*_"
|
|
||||||
rdExp = RdExpression(form)
|
|
||||||
|
|
||||||
assert rdExp._letters == {'A', 'B'}
|
|
||||||
assert rdExp._2replaced == {'A', 'B'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()) == {'A', 'B'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()) == {'A', 'B'}
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form_calc():
|
|
||||||
form = "{a+b} + 2"
|
|
||||||
rdExp = RdExpression(form)
|
|
||||||
|
|
||||||
assert rdExp._letters, {'a' == 'b'}
|
|
||||||
assert rdExp._2replaced == {'a+b'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()), {'a' == 'b'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()) == {'a+b'}
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form_cond():
|
|
||||||
form = "{a} + 2"
|
|
||||||
cond = ["{a} == 3"]
|
|
||||||
rdExp = RdExpression(form, cond)
|
|
||||||
|
|
||||||
assert rdExp._letters == {'a'}
|
|
||||||
assert rdExp._2replaced == {'a'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()) == {'a'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()) == {'a'}
|
|
||||||
|
|
||||||
assert rdExp._gene_varia['a'] == 3
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form_conds():
|
|
||||||
form = "{a} + 2"
|
|
||||||
cond = ["{a} in list(range(5))", "{a} % 2 == 1"]
|
|
||||||
rdExp = RdExpression(form, cond)
|
|
||||||
|
|
||||||
assert rdExp._letters == {'a'}
|
|
||||||
assert rdExp._2replaced == {'a'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()) == {'a'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()) == {'a'}
|
|
||||||
|
|
||||||
assert rdExp._gene_varia['a'] in list(range(5))
|
|
||||||
assert rdExp._gene_varia['a'] % 2 == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form_calc_cond():
|
|
||||||
form = "{a*3} * {b}"
|
|
||||||
cond = ["{a} == 3"]
|
|
||||||
rdExp = RdExpression(form, cond)
|
|
||||||
|
|
||||||
assert rdExp._letters, {'a' == 'b'}
|
|
||||||
assert rdExp._2replaced, {'a', 'b' == 'a*3'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()), {'a' == 'b'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()), {'a', 'b' == 'a*3'}
|
|
||||||
|
|
||||||
assert rdExp._gene_varia['a'] == 3
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_form_calc_cond_calc():
|
|
||||||
form = "{a*3} * {b}"
|
|
||||||
cond = ["{a+b} == 3"]
|
|
||||||
rdExp = RdExpression(form, cond)
|
|
||||||
|
|
||||||
assert rdExp._letters, {'a' == 'b'}
|
|
||||||
assert rdExp._2replaced, {'b', 'a*3' == 'a+b'}
|
|
||||||
|
|
||||||
rdExp()
|
|
||||||
assert set(rdExp._gene_varia.keys()), {'a' == 'b'}
|
|
||||||
assert set(rdExp._gene_2replaced.keys()), {'b', 'a*3' == 'a+b'}
|
|
||||||
|
|
||||||
assert (rdExp._gene_varia['a'] + rdExp._gene_varia['b']) == 3
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,310 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus.render import tex, txt
|
|
||||||
from mapytex.calculus.fraction import Fraction
|
|
||||||
from mapytex.calculus.polynom import Polynom
|
|
||||||
from mapytex.calculus.operator import op
|
|
||||||
from mapytex.calculus.expression import Expression
|
|
||||||
|
|
||||||
from itertools import permutations
|
|
||||||
|
|
||||||
|
|
||||||
def mass_poly_test(operation, rg=5):
|
|
||||||
""" @todo
|
|
||||||
|
|
||||||
:op: the operation
|
|
||||||
:rg: number of potential values for coefs
|
|
||||||
:returns: @todo
|
|
||||||
"""
|
|
||||||
coefs_p = [[(i - 2), (j - 2)] for i, j in permutations(range(rg), 2)]
|
|
||||||
coefs_q = [[2 * (i - 2), 2 * (j - 2)]
|
|
||||||
for i, j in permutations(range(rg), 2)]
|
|
||||||
l_p = [Polynom(i) for i in coefs_p]
|
|
||||||
l_q = [Polynom(i) for i in coefs_q]
|
|
||||||
return [Expression([l_p[i], l_q[j], op.get_op(operation)])
|
|
||||||
for i, j in permutations(range(len(coefs_p)), 2)]
|
|
||||||
|
|
||||||
|
|
||||||
class TestTexRender(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.renders.tex"""
|
|
||||||
|
|
||||||
def test_type_render_int(self):
|
|
||||||
self.assertEqual(tex([2]), "2")
|
|
||||||
|
|
||||||
def test_type_render_str(self):
|
|
||||||
self.assertEqual(tex(["a"]), "a")
|
|
||||||
|
|
||||||
def test_type_render_float(self):
|
|
||||||
self.assertEqual(tex([12.345]), "12.345")
|
|
||||||
|
|
||||||
def test_type_render_fraction(self):
|
|
||||||
self.assertEqual(tex([Fraction(1, 2)]), "\\frac{ 1 }{ 2 }")
|
|
||||||
|
|
||||||
def test_type_render_poly(self):
|
|
||||||
P = Polynom([1, 2, 3])
|
|
||||||
self.assertEqual(tex([P]), "3 x^{ 2 } + 2 x + 1")
|
|
||||||
|
|
||||||
def test_add_interger(self):
|
|
||||||
exps = [[2, 3, op.add],
|
|
||||||
[2, -3, op.add],
|
|
||||||
[-2, 3, op.add],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 + 3",
|
|
||||||
"2 - 3",
|
|
||||||
"-2 + 3",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mass_add(self):
|
|
||||||
permu = mass_poly_test("+", 5)
|
|
||||||
from .mass_test import POLY_ADD_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(tex(v), POLY_ADD_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
def test_mass_sub(self):
|
|
||||||
permu = mass_poly_test("-", 5)
|
|
||||||
from .mass_test import POLY_SUB_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(tex(v), POLY_SUB_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
def test_mass_mul(self):
|
|
||||||
permu = mass_poly_test("*", 5)
|
|
||||||
from .mass_test import TEX_POLY_MUL_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(tex(v), TEX_POLY_MUL_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
def test_add_letter(self):
|
|
||||||
exps = [[2, "a", op.add],
|
|
||||||
["a", 3, op.add],
|
|
||||||
[-2, "a", op.add],
|
|
||||||
["a", -2, op.add],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 + a",
|
|
||||||
"a + 3",
|
|
||||||
"-2 + a",
|
|
||||||
"a - 2",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_add_fraction(self):
|
|
||||||
exps = [[2, Fraction(1, 2), op.add],
|
|
||||||
[Fraction(1, 2), 3, op.add],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 + \\frac{ 1 }{ 2 }",
|
|
||||||
"\\frac{ 1 }{ 2 } + 3",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_add_poly(self):
|
|
||||||
exps = [[2, Polynom([1, 2, 3]), op.mul],
|
|
||||||
[Polynom([1, 2, 3]), 2, op.mul],
|
|
||||||
[Polynom([1, 2, 3]), Polynom([4, 5, 6]), op.mul],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 ( 3 x^{ 2 } + 2 x + 1 )",
|
|
||||||
"( 3 x^{ 2 } + 2 x + 1 ) \\times 2",
|
|
||||||
"( 3 x^{ 2 } + 2 x + 1 ) ( 6 x^{ 2 } + 5 x + 4 )",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_interger(self):
|
|
||||||
exps = [[2, 3, op.mul],
|
|
||||||
[2, -3, op.mul],
|
|
||||||
[-2, 3, op.mul],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 \\times 3",
|
|
||||||
"2 \\times ( -3 )",
|
|
||||||
"-2 \\times 3",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_letter(self):
|
|
||||||
exps = [[2, "a", op.mul],
|
|
||||||
["a", 3, op.mul],
|
|
||||||
[-2, "a", op.mul],
|
|
||||||
["a", -2, op.mul],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 a", "a \\times 3", "-2 a", "a \\times ( -2 )"]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_fraction(self):
|
|
||||||
exps = [[2, Fraction(1, 2), op.mul], [Fraction(1, 2), 3, op.mul]]
|
|
||||||
wanted_render = [
|
|
||||||
"2 \\times \\frac{ 1 }{ 2 }",
|
|
||||||
"\\frac{ 1 }{ 2 } \\times 3"]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_poly(self):
|
|
||||||
exps = [[2, Polynom([1, 2, 3]), op.mul],
|
|
||||||
[Polynom([1, 2, 3]), 2, op.mul],
|
|
||||||
[Polynom([1, 2, 3]), Polynom([4, 5, 6]), op.mul],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 ( 3 x^{ 2 } + 2 x + 1 )",
|
|
||||||
"( 3 x^{ 2 } + 2 x + 1 ) \\times 2",
|
|
||||||
"( 3 x^{ 2 } + 2 x + 1 ) ( 6 x^{ 2 } + 5 x + 4 )",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_parentheses_int(self):
|
|
||||||
exps = [
|
|
||||||
[2, 3, op.add, 4, op.mul],
|
|
||||||
[2, 3, op.mul, 4, op.add],
|
|
||||||
[2, 3, 4, op.mul, op.add],
|
|
||||||
[2, 3, 4, op.add, op.add],
|
|
||||||
[2, 3, 4, op.add, op.sub],
|
|
||||||
]
|
|
||||||
wanted_render = [
|
|
||||||
'( 2 + 3 ) \\times 4',
|
|
||||||
'2 \\times 3 + 4',
|
|
||||||
'2 + 3 \\times 4',
|
|
||||||
'2 + 3 + 4',
|
|
||||||
'2 - ( 3 + 4 )',
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_parentheses_poly(self):
|
|
||||||
P = Polynom([1, 2, 3])
|
|
||||||
Q = Polynom([4, 5, 6])
|
|
||||||
exps = [
|
|
||||||
[2, P, op.add],
|
|
||||||
[2, P, op.sub],
|
|
||||||
[2, P, P, op.mul, op.sub],
|
|
||||||
[Q, P, op.add],
|
|
||||||
[Q, P, op.sub],
|
|
||||||
]
|
|
||||||
wanted_render = [
|
|
||||||
'2 + 3 x^{ 2 } + 2 x + 1',
|
|
||||||
'2 - ( 3 x^{ 2 } + 2 x + 1 )',
|
|
||||||
'2 - ( 3 x^{ 2 } + 2 x + 1 ) ( 3 x^{ 2 } + 2 x + 1 )',
|
|
||||||
'6 x^{ 2 } + 5 x + 4 + 3 x^{ 2 } + 2 x + 1',
|
|
||||||
'6 x^{ 2 } + 5 x + 4 - ( 3 x^{ 2 } + 2 x + 1 )',
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = tex(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_slash(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TesttxtRender(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.renders.txt"""
|
|
||||||
|
|
||||||
def test_type_render_int(self):
|
|
||||||
self.assertEqual(txt([2]), "2")
|
|
||||||
|
|
||||||
def test_type_render_str(self):
|
|
||||||
self.assertEqual(txt(["a"]), "a")
|
|
||||||
|
|
||||||
def test_type_render_float(self):
|
|
||||||
self.assertEqual(txt([12.345]), "12.345")
|
|
||||||
|
|
||||||
def test_type_render_fraction(self):
|
|
||||||
self.assertEqual(txt([Fraction(1, 2)]), "1 / 2")
|
|
||||||
|
|
||||||
def test_mult_interger(self):
|
|
||||||
exps = [[2, 3, op.mul],
|
|
||||||
[2, -3, op.mul],
|
|
||||||
[-2, 3, op.mul]]
|
|
||||||
wanted_render = ["2 * 3", "2 * ( -3 )", "-2 * 3"]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = txt(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_letter(self):
|
|
||||||
exps = [[2, "a", op.mul],
|
|
||||||
["a", 3, op.mul],
|
|
||||||
[-2, "a", op.mul],
|
|
||||||
["a", -2, op.mul],
|
|
||||||
["a", -2, op.mul, -2, op.mul],
|
|
||||||
["a", -2, op.mul, "a", op.mul],
|
|
||||||
]
|
|
||||||
wanted_render = ["2 a",
|
|
||||||
"a * 3",
|
|
||||||
"-2 a",
|
|
||||||
"a * ( -2 )",
|
|
||||||
"a * ( -2 ) * ( -2 )",
|
|
||||||
"a * ( -2 ) a",
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = txt(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_mult_fraction(self):
|
|
||||||
exps = [[2, Fraction(1, 2), op.mul],
|
|
||||||
[Fraction(1, 2), 3, op.mul]]
|
|
||||||
wanted_render = ["2 * 1 / 2", "1 / 2 * 3"]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = txt(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_parentheses(self):
|
|
||||||
mul = op.get_op("*", 2)
|
|
||||||
add = op.get_op("+", 2)
|
|
||||||
exps = [
|
|
||||||
[2, 3, add, 4, mul],
|
|
||||||
[2, 3, mul, 4, add],
|
|
||||||
[2, 3, 4, mul, add],
|
|
||||||
[2, 3, 4, add, add],
|
|
||||||
]
|
|
||||||
wanted_render = [
|
|
||||||
'( 2 + 3 ) * 4',
|
|
||||||
'2 * 3 + 4',
|
|
||||||
'2 + 3 * 4',
|
|
||||||
'2 + 3 + 4',
|
|
||||||
]
|
|
||||||
for (i, e) in enumerate(exps):
|
|
||||||
rend = txt(e)
|
|
||||||
self.assertEqual(rend, wanted_render[i])
|
|
||||||
|
|
||||||
def test_slash(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_mass_add(self):
|
|
||||||
permu = mass_poly_test("+", 5)
|
|
||||||
from .mass_test import POLY_ADD_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(txt(v), POLY_ADD_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
def test_mass_sub(self):
|
|
||||||
permu = mass_poly_test("-", 5)
|
|
||||||
from .mass_test import POLY_SUB_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(txt(v), POLY_SUB_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
def test_mass_mul(self):
|
|
||||||
permu = mass_poly_test("*", 5)
|
|
||||||
from .mass_test import TXT_POLY_MUL_VALID_RESULTS
|
|
||||||
for (i, v) in enumerate(permu):
|
|
||||||
self.assertEqual(txt(v), TXT_POLY_MUL_VALID_RESULTS[i])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -1,83 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mapytex.calculus.str2tokens import str2tokens, str2in_tokens, in2post_fix
|
|
||||||
from mapytex.calculus.polynom import Polynom
|
|
||||||
from mapytex.calculus.operator import op
|
|
||||||
|
|
||||||
|
|
||||||
class TestStr2tokens(unittest.TestCase):
|
|
||||||
"""Testing functions from mapytex.calculus.str2tokens"""
|
|
||||||
|
|
||||||
def test_str2in_tokens(self):
|
|
||||||
ans = str2in_tokens("2+3*4")
|
|
||||||
self.assertEqual(ans, [2, "+", 3, "*", 4])
|
|
||||||
|
|
||||||
ans = str2in_tokens("2*3+4")
|
|
||||||
self.assertEqual(ans, [2, "*", 3, "+", 4])
|
|
||||||
|
|
||||||
from decimal import Decimal
|
|
||||||
ans = str2in_tokens("2.34")
|
|
||||||
self.assertEqual(ans, [Decimal('2.34')])
|
|
||||||
|
|
||||||
def test_in2post_fix(self):
|
|
||||||
in_tokens = str2in_tokens("2+3*4")
|
|
||||||
ans = in2post_fix(in_tokens)
|
|
||||||
self.assertEqual(ans, [2, 3, 4, op.mul, op.add])
|
|
||||||
|
|
||||||
in_tokens = str2in_tokens("2*3+4")
|
|
||||||
ans = in2post_fix(in_tokens)
|
|
||||||
self.assertEqual(ans, [2, 3, op.mul, 4, op.add])
|
|
||||||
|
|
||||||
def test_str2in_tokens_big_num(self):
|
|
||||||
exp = "123 + 3"
|
|
||||||
tok = str2in_tokens(exp)
|
|
||||||
self.assertEqual(tok, [123, "+", 3])
|
|
||||||
|
|
||||||
def test_str2in_tokens_beg_minus(self):
|
|
||||||
exp = "-123 + 3"
|
|
||||||
tok = str2in_tokens(exp)
|
|
||||||
self.assertEqual(tok, [-123, "+", 3])
|
|
||||||
|
|
||||||
def test_str2in_tokens_time_lack(self):
|
|
||||||
exp = "(-3)(2)"
|
|
||||||
tok = str2in_tokens(exp)
|
|
||||||
self.assertEqual(tok, ["(", -3, ")", "*", "(", 2, ")"])
|
|
||||||
|
|
||||||
def test_str2tokens_poly(self):
|
|
||||||
exp = "2x + 4"
|
|
||||||
post = str2in_tokens(exp)
|
|
||||||
self.assertEqual(post, [2, "*", Polynom([0, 1]), '+', 4])
|
|
||||||
|
|
||||||
def test_str2tokens_poly_double_x(self):
|
|
||||||
exp = "xx + 4"
|
|
||||||
post = str2in_tokens(exp)
|
|
||||||
self.assertEqual(post, [Polynom([0, 1]), "*", Polynom([0, 1]), '+', 4])
|
|
||||||
|
|
||||||
def test_str2tokens_poly_par(self):
|
|
||||||
exp = "x(2+1) + 4"
|
|
||||||
post = str2in_tokens(exp)
|
|
||||||
self.assertEqual(post, [Polynom([0, 1]), "*",
|
|
||||||
"(", 2, "+", 1, ')', '+', 4])
|
|
||||||
|
|
||||||
def test_str2in_tokens_time_lack2(self):
|
|
||||||
exp = "-3(2)"
|
|
||||||
tok = str2in_tokens(exp)
|
|
||||||
self.assertEqual(tok, [-3, "*", "(", 2, ")"])
|
|
||||||
|
|
||||||
def test_str2tokens_error(self):
|
|
||||||
exp = "1 + $"
|
|
||||||
self.assertRaises(ValueError, str2tokens, exp)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
Loading…
Reference in New Issue
Block a user