319 lines
8.7 KiB
Python
319 lines
8.7 KiB
Python
#!/usr/bin/env python
|
|
# encoding: utf-8
|
|
|
|
|
|
from pymath.fraction import Fraction
|
|
from pymath.expression import Expression
|
|
from pymath.generic import mix_list, sum_postfix, expand_list
|
|
|
|
__all__ = ["Polynom"]
|
|
|
|
|
|
class Polynom(object):
|
|
|
|
"""Docstring for Polynom. """
|
|
|
|
def __init__(self, coef = [1], letter = "x" ):
|
|
"""Initiate the polynom
|
|
|
|
:param coef: coefficients of the polynom (ascending degree sorted) - can be a list of list of coefficients.
|
|
3 possibles type of list:
|
|
- [a,b,..] simple list of coefficients. [1,2] designate 1 + 2x
|
|
- [a, [c,b],...] list of coefficients with x^i repeated. [1,[2,3],4) designate 1 + 2x + 3x + 4x^2
|
|
- [a, [b,c,"+"],...] list of coefficients with arithmetic expression (postfix form) in. [1, [2,3,"+"], 4] designate 1 + (2+3)x + 4x^2
|
|
:param letter: the string describing the unknown
|
|
|
|
"""
|
|
self.feed_coef(coef)
|
|
self._letter = letter
|
|
|
|
|
|
if self.is_monom():
|
|
self.mainOp = "*"
|
|
else:
|
|
self.mainOp = "+"
|
|
|
|
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
|
|
|
|
"""
|
|
return len(self._coef) - 1
|
|
|
|
def is_monom(self):
|
|
"""is the polynom a monom (only one coefficent)
|
|
:returns: 1 if yes 0 otherwise
|
|
"""
|
|
if len([i for i in self._coef if i != 0])==1:
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
def __str__(self):
|
|
# TODO: Voir si on peut utiliser un render |sam. juin 14 08:56:16 CEST 2014
|
|
from .renders import txt
|
|
return txt(self.get_postfix())
|
|
|
|
def __repr__(self):
|
|
return "< Polynom " + str(self._coef) + ">"
|
|
|
|
def coef_postfix(self, a, i):
|
|
"""Return the postfix display of a coeficient
|
|
|
|
:param a: value for the coeficient (/!\ as a list)
|
|
:param i: power
|
|
:returns: postfix tokens of coef
|
|
|
|
"""
|
|
ans =[]
|
|
if a == 0:
|
|
return ans
|
|
if i == 0:
|
|
ans = a
|
|
elif i == 1:
|
|
ans = a * (a!=[1]) + [self._letter] + ["*"] * (a!=[1])
|
|
else:
|
|
ans = a * (a!=[1]) + [self._letter, i, "^"] + ["*"] * (a!=[1])
|
|
|
|
return ans
|
|
|
|
def get_postfix(self):
|
|
"""Return the postfix form of the polynom
|
|
|
|
:returns: the postfix list of polynom's tokens
|
|
|
|
"""
|
|
self._postfix = []
|
|
first_elem = 1
|
|
for (i,a) in list(enumerate(self._coef))[::-1]:
|
|
if type(a) == list and str(a[-1]) in "+-*^/":
|
|
# case coef is an arithmetic expression
|
|
self._postfix += self.coef_postfix(a,i)
|
|
if not first_elem:
|
|
self._postfix.append("+")
|
|
first_elem = 0
|
|
|
|
elif type(a) == list and str(a[-1]) not in "+-*^/":
|
|
# case need to repeat the x^i
|
|
for b in a:
|
|
if type(b) == list:
|
|
self._postfix += self.coef_postfix(b,i)
|
|
else:
|
|
self._postfix += self.coef_postfix([b],i)
|
|
if not first_elem:
|
|
self._postfix.append("+")
|
|
first_elem = 0
|
|
|
|
elif a != 0:
|
|
self._postfix += self.coef_postfix([a],i)
|
|
if not first_elem:
|
|
self._postfix.append("+")
|
|
first_elem = 0
|
|
|
|
return self._postfix
|
|
|
|
def convert_into_poly(self, other):
|
|
"""Convert anything (int and fract) into a polynom """
|
|
if type(other) in [int, Fraction]:
|
|
return Polynom([other])
|
|
elif type(other) == Polynom:
|
|
return other
|
|
else:
|
|
raise ValueError(type(other) + " can't be converted into a polynom")
|
|
|
|
def reduce(self):
|
|
"""Compute coefficients which have same degree
|
|
|
|
:returns: new Polynom with numbers coefficients
|
|
"""
|
|
steps = []
|
|
for a in self._coef:
|
|
coef_steps = []
|
|
if type(a) == list and str(a[-1]) in "+-*^":
|
|
# case coef is an arithmetic expression
|
|
exp = Expression(a)
|
|
coef_steps = list(exp.simplify(render = lambda x:x))
|
|
|
|
steps.append(coef_steps)
|
|
elif type(a) == list and str(a[-1]) not in "+-*^":
|
|
# case need to repeat the x^i
|
|
if [i for i in a if type(i) == list] != []:
|
|
# first we simplify arithmetic exp
|
|
# Et hop un coup de sorcelerie!
|
|
elem = [list(Expression(i).simplify(render = lambda x:self.list_or_num(x))) if type(i) == list else i for i in a ]
|
|
|
|
elem = expand_list(elem)
|
|
coef_steps += elem
|
|
exp = elem[-1]
|
|
|
|
else:
|
|
exp = a
|
|
|
|
exp = sum_postfix(exp)
|
|
exp = Expression(exp)
|
|
|
|
coef_steps += list(exp.simplify(render = lambda x:x))
|
|
|
|
steps.append(coef_steps)
|
|
else:
|
|
steps.append(a)
|
|
|
|
steps = expand_list(steps)
|
|
|
|
return [Polynom(s) for s in steps]
|
|
|
|
@staticmethod
|
|
def list_or_num(x):
|
|
if len(x) == 1:
|
|
return x[0]
|
|
else:
|
|
return x
|
|
|
|
|
|
def simplify(self):
|
|
"""Same as reduce """
|
|
return self.reduce()
|
|
|
|
|
|
def __eq__(self, other):
|
|
if type(other) in [int, Fraction, Polynom] or other.isnumeric():
|
|
o_poly = self.convert_into_poly(other)
|
|
|
|
return self._coef == o_poly._coef
|
|
else:
|
|
return 0
|
|
|
|
def __add__(self, other):
|
|
steps = []
|
|
|
|
o_poly = self.convert_into_poly(other)
|
|
|
|
n_coef = mix_list(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):
|
|
o_poly = self.convert_into_poly(other)
|
|
o_poly = -o_poly
|
|
|
|
return self.__add__(o_poly)
|
|
|
|
def __rsub__(self, other):
|
|
o_poly = self.convert_into_poly(other)
|
|
|
|
return o_poly.__sub__(-self)
|
|
|
|
def __mul__(self, other):
|
|
steps = []
|
|
o_poly = self.convert_into_poly(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 = [a, b, "*"]
|
|
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):
|
|
o_poly = self.convert_into_poly(other)
|
|
|
|
return o_poly.__mul__(self)
|
|
|
|
def __div__(self, other):
|
|
pass
|
|
|
|
def __truediv__(self, other):
|
|
pass
|
|
|
|
|
|
def test(p,q):
|
|
print("---------------------")
|
|
print("---------------------")
|
|
print("p : ",p)
|
|
print("q : ",q)
|
|
|
|
print("\n Plus ------")
|
|
for i in (p + q):
|
|
#print(repr(i))
|
|
#print("\t", str(i.get_postfix()))
|
|
print(i)
|
|
|
|
print("\n Moins ------")
|
|
for i in (p - q):
|
|
#print(repr(i))
|
|
#print("\t", str(i.get_postfix()))
|
|
print(i)
|
|
|
|
print("\n Multiplier ------")
|
|
for i in (p * q):
|
|
#print(repr(i))
|
|
#print("\t", str(i.get_postfix()))
|
|
print(i)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
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, "*"],3], 4], "x")
|
|
#print(repr(p))
|
|
#for i in p.simplify():
|
|
# print(repr(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))
|
|
|
|
|
|
# -----------------------------
|
|
# Reglages pour 'vim'
|
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
# cursor: 16 del
|