Remove old files and fix class name in doctest

This commit is contained in:
Bertrand Benjamin 2018-01-21 11:32:17 +03:00
parent a751e346d3
commit 813c1f096e
38 changed files with 4 additions and 7294 deletions

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python
# encoding: utf-8
from .calculus import Expression, Polynom, Fraction, random_str, txt, Equation
from .stat import Dataset, WeightedDataset
from .geometry import random_pythagore
#from .calculus import Expression, Polynom, Fraction, random_str, txt, Equation
#from .stat import Dataset, WeightedDataset
#from .geometry import random_pythagore
# -----------------------------
# Reglages pour 'vim'

View File

@ -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

View File

@ -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

View File

@ -104,7 +104,7 @@ class Tree(object):
>>> t.node
'+'
>>> type(t.left_value)
<class 'calculus.core.tree.Tree'>
<class 'mapytex.calculus.core.tree.Tree'>
>>> t.right_value
2

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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