Mapytex/mapytex/calculus/polynom.py

189 lines
5.5 KiB
Python

#!/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