Mapytex/pymath/polynom.py

363 lines
9.7 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# encoding: utf-8
2014-11-11 15:52:30 +00:00
from .expression import Expression
2014-11-11 20:00:45 +00:00
from .operator import op
from .generic import spe_zip, expand_list, isNumber, transpose_fill, flatten_list
#from .generic import spe_zip, sum_postfix, expand_list, isNumber
2014-11-11 15:52:30 +00:00
from .render import txt
2014-12-19 16:17:25 +00:00
from .random_expression import RdExpression
2014-11-11 20:00:45 +00:00
from itertools import chain
__all__ = ["Polynom"]
class Polynom(object):
"""Docstring for Polynom. """
2014-12-19 16:17:25 +00:00
@classmethod
def random(self, coefs_form=[], conditions=[], letter = "x"):
""" 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
/!\ variables need to be in brackets {}
"""
form = str(coefs_form)
coefs = RdExpression(form, conditions)()
2014-12-19 16:29:12 +00:00
coefs = [eval(i) if type(i)==str else i for i in eval(coefs)]
return Polynom(coef = coefs, letter = letter)
2014-12-19 16:17:25 +00:00
def __init__(self, coef = [1], letter = "x" ):
"""Initiate the polynom
2014-11-11 15:52:30 +00:00
: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
2014-11-11 20:00:45 +00:00
>>> Polynom([1,2,3]).mainOp
'+'
>>> Polynom([1]).mainOp
'*'
>>> Polynom([1,2, 3])._letter
'x'
>>> Polynom([1, 2, 3], "y")._letter
'y'
"""
self.feed_coef(coef)
self._letter = letter
if self.is_monom():
self.mainOp = "*"
else:
self.mainOp = "+"
2014-11-11 20:00:45 +00:00
self._isPolynom = 1
2014-11-11 15:52:30 +00:00
def feed_coef(self, l_coef):
"""Feed coef of the polynom. Manage differently whether it's a number or an expression
:l_coef: list of coef
"""
self._coef = []
for coef in l_coef:
if type(coef) == list and len(coef)==1:
self._coef.append(coef[0])
else:
self._coef.append(coef)
def get_degree(self):
"""Getting the degree fo the polynom
:returns: the degree of the polynom
2014-11-11 20:00:45 +00:00
>>> Polynom([1, 2, 3]).get_degree()
2
>>> Polynom([1]).get_degree()
0
"""
return len(self._coef) - 1
def is_monom(self):
"""is the polynom a monom (only one coefficent)
2014-11-11 20:00:45 +00:00
:returns: 1 if yes 0 otherwise
2014-11-11 20:00:45 +00:00
>>> Polynom([1, 2, 3]).is_monom()
0
>>> Polynom([1]).is_monom()
1
"""
if len([i for i in self._coef if i != 0])==1:
return 1
else:
return 0
def __str__(self):
2014-11-11 20:00:45 +00:00
return txt(self.postfix)
def __repr__(self):
return "< Polynom " + str(self._coef) + ">"
def coef_postfix(self, a, i):
"""Return the postfix display of a coeficient
2014-11-11 20:00:45 +00:00
:param a: value for the coeficient (/!\ as a postfix list)
:param i: power
:returns: postfix tokens of coef
"""
2014-11-11 15:52:30 +00:00
# TODO: Couille certaine avec txt à qui il fait donner des opérateurs tout beau! |mar. nov. 11 13:08:35 CET 2014
ans =[]
if a == [0]:
pass
elif i == 0:
ans = a
elif i == 1:
2014-11-11 20:00:45 +00:00
ans = a * (a!=[1]) + [self._letter] + [op.mul] * (a!=[1])
else:
2014-11-11 20:00:45 +00:00
ans = a * (a!=[1]) + [self._letter, i, op.pw] + [op.mul] * (a!=[1])
return ans
2014-11-11 20:00:45 +00:00
@property
def postfix(self):
"""Return the postfix form of the polynom
:returns: the postfix list of polynom's tokens
"""
2014-11-11 20:00:45 +00:00
postfix = []
for (i,a) in list(enumerate(self._coef))[::-1]:
2014-11-11 20:00:45 +00:00
if type(a) == Expression:
# case coef is an arithmetic expression
c = self.coef_postfix(a.postfix_tokens,i)
if c != []:
postfix.append(c)
2014-11-11 20:00:45 +00:00
elif type(a) == list:
# case need to repeat the x^i
for b in a:
c = self.coef_postfix([b],i)
if c != []:
postfix.append(c)
elif a != 0:
c = self.coef_postfix([a],i)
if c != []:
postfix.append(c)
2014-11-11 20:00:45 +00:00
return flatten_list(self.postfix_add(postfix))
2014-11-11 15:52:30 +00:00
def conv2poly(self, other):
"""Convert anything number into a polynom"""
if isNumber(other) and not self.isPolynom(other):
return Polynom([other])
2014-11-11 15:52:30 +00:00
elif self.isPolynom(other):
return other
else:
raise ValueError(type(other) + " can't be converted into a polynom")
2014-11-11 15:52:30 +00:00
def isPolynom(self, other):
try:
other._isPolynom
2014-11-11 15:52:30 +00:00
except AttributeError:
return 0
return 1
def reduce(self):
"""Compute coefficients which have same degree
:returns: new Polynom with numbers coefficients
"""
steps = []
2014-11-11 20:00:45 +00:00
# gather steps for every coeficients
coefs_steps = []
for coef in self._coef:
coef_steps = []
2014-11-11 20:00:45 +00:00
if type(coef) != Expression:
# On converti en postfix avec une addition
postfix_add = self.postfix_add(coef)
# On converti en Expression
coef_exp = Expression(postfix_add)
else:
coef_exp = coef
2014-11-11 20:00:45 +00:00
# On fait réduire l'expression puis on ajoute dans steps
2014-11-21 14:49:43 +00:00
Expression.set_render(lambda _,x:Expression(x))
coef_steps = list(coef_exp.simplify())
Expression.set_df_render()
2014-11-11 20:00:45 +00:00
# On ajoute toutes ces étapes
coefs_steps.append(coef_steps)
2014-11-11 20:00:45 +00:00
# On retourne la matrice
ans = []
2014-11-11 20:00:45 +00:00
for coefs in transpose_fill(coefs_steps):
ans.append(Polynom(coefs, self._letter))
return ans
@staticmethod
2014-11-11 20:00:45 +00:00
def postfix_add(numbers):
"""Convert a list of numbers into a postfix addition
:numbers: list of numbers
:returns: Postfix list of succecive attition of number
>>> Polynom.postfix_add([1])
[1]
>>> Polynom.postfix_add([1, 2])
[1, 2, '+']
>>> Polynom.postfix_add([1, 2, 3])
[1, 2, '+', 3, '+']
>>> Polynom.postfix_add(1)
[1]
"""
if not type(numbers) == list:
return [numbers]
else:
2014-11-11 20:00:45 +00:00
ans = [[a, op.add] if i!=0 else [a] for (i,a) in enumerate(numbers)]
return list(chain.from_iterable(ans))
def simplify(self):
"""Same as reduce """
return self.reduce()
def __eq__(self, other):
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
return self._coef == o_poly._coef
def __add__(self, other):
steps = []
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
2014-11-11 15:52:30 +00:00
n_coef = spe_zip(self._coef, o_poly._coef)
p = Polynom(n_coef)
steps.append(p)
steps += p.simplify()
return steps
def __radd__(self, other):
return self.__add__(other)
def __neg__(self):
return Polynom([-i for i in self._coef], letter = self._letter)
def __sub__(self, other):
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
o_poly = -o_poly
return self.__add__(o_poly)
def __rsub__(self, other):
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
return o_poly.__sub__(-self)
def __mul__(self, other):
steps = []
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
coefs = []
for (i,a) in enumerate(self._coef):
for (j,b) in enumerate(o_poly._coef):
if a == 0 or b == 0:
elem = 0
else:
elem = Expression([a, b, op.mul])
try:
if coefs[i+j]==0:
coefs[i+j] = elem
elif elem != 0:
coefs[i+j] = [coefs[i+j], elem]
except IndexError:
coefs.append(elem)
p = Polynom(coefs)
steps.append(p)
steps += p.simplify()
return steps
def __rmul__(self, other):
2014-11-11 15:52:30 +00:00
o_poly = self.conv2poly(other)
return o_poly.__mul__(self)
def test(p,q):
print("---------------------")
print("---------------------")
print("p : ",p)
print("q : ",q)
print("\n Plus ------")
for i in (p + q):
#print(repr(i))
2014-11-11 20:00:45 +00:00
#print("\t", str(i.postfix))
print(i)
print("\n Moins ------")
for i in (p - q):
#print(repr(i))
2014-11-11 20:00:45 +00:00
#print("\t", str(i.postfix))
print(i)
print("\n Multiplier ------")
for i in (p * q):
#print(repr(i))
#print("\t", str(i.postfix))
print(i)
if __name__ == '__main__':
2014-11-11 20:00:45 +00:00
from .fraction import Fraction
p = Polynom([1, -2 ])
q = Polynom([4, 7])
test(p,q)
q = Polynom([0, Fraction(1,2), 0, Fraction(-4,3)])
test(p,q)
#p = Polynom([1, 1, 1 ])
#print(p)
#print("-- Poly étrange --")
#p = Polynom([1, [2, 3], 4], "x")
#print(repr(p))
#for i in p.simplify():
# print(i)
#print("-- Poly étrange --")
#p = Polynom([1, [[2, 3, "*"], [4,5,"*"]], 4], "x")
#print(repr(p))
#print(p)
#for i in p.simplify():
# print(repr(i))
2014-12-19 16:17:25 +00:00
print("\n")
2014-12-19 16:29:12 +00:00
poly = Polynom.random(["[{a**2}, {a}]", "{2*a*b}", "{b**2}"])
for i in poly.simplify():
print(i)
2014-12-19 16:17:25 +00:00
2014-11-11 20:00:45 +00:00
import doctest
doctest.testmod()
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del