Compare commits
5 Commits
cbcead48f7
...
dev
Author | SHA1 | Date | |
---|---|---|---|
60ee751e91 | |||
d6e3f774fa | |||
1347c30b92 | |||
bf55470467 | |||
78ce8f767a |
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from .calculus import Expression, Integer, Decimal, random_list, render, Polynomial
|
||||
from .calculus import Expression, Integer, Decimal, random_list, render, Polynomial, Fraction
|
||||
|
||||
# Expression.set_render('tex')
|
||||
|
||||
|
@@ -123,11 +123,11 @@ x^7
|
||||
- 2x^2 + 7x - 6
|
||||
"""
|
||||
|
||||
from .renders import render
|
||||
from .expression import Expression
|
||||
from .tokens import Token
|
||||
from .tokens.polynomial import Polynomial
|
||||
from .tokens.number import Integer, Decimal, Fraction
|
||||
from .renders import render
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -309,15 +309,15 @@ class Expression(object):
|
||||
|
||||
comp_exp = opt_exp._compute()
|
||||
|
||||
if typed_exp == comp_exp:
|
||||
typed_exp.set_ancestor(self._ancestor)
|
||||
return typed_exp
|
||||
else:
|
||||
if typed_exp != comp_exp:
|
||||
comp_exp.set_ancestor(self)
|
||||
return comp_exp._simplify(optimize=optimize)
|
||||
|
||||
typed_exp.set_ancestor(self._ancestor)
|
||||
return typed_exp
|
||||
|
||||
def simplify(self, optimize=True):
|
||||
""" Compute as much as possible the expression
|
||||
""" Simplify the expression, keep the history and factory child
|
||||
|
||||
:param optimize: bool to optimize tree when it's possible
|
||||
:return: an expression
|
||||
|
@@ -29,6 +29,10 @@ class Render(object):
|
||||
else:
|
||||
raise ValueError("This render name already exists")
|
||||
|
||||
@property
|
||||
def render_name(self):
|
||||
return self._render
|
||||
|
||||
@property
|
||||
def render(self):
|
||||
return self.renders[self._render]
|
||||
|
@@ -141,7 +141,7 @@ class Decimal(Token):
|
||||
|
||||
class Fraction(Token):
|
||||
|
||||
""" Token representing a fraction
|
||||
""" Token representing a fraction of numbers
|
||||
|
||||
:example:
|
||||
>>> Fraction("3/4")
|
||||
@@ -269,7 +269,58 @@ class Fraction(Token):
|
||||
>>> f.decimal
|
||||
<Decimal 0.3333333333333333333333333333>
|
||||
"""
|
||||
return Decimal(_Decimal(self._mo.numerator._value) / _Decimal(self._mo.denominator._value))
|
||||
return Decimal(self._mo._value)
|
||||
|
||||
@property
|
||||
def simplified(self):
|
||||
""" Get the irreductible version of self
|
||||
|
||||
:example:
|
||||
>>> f = Fraction("3/4")
|
||||
>>> f.simplified
|
||||
<Fraction 3 / 4>
|
||||
>>> f = Fraction("12/9")
|
||||
>>> f.simplified
|
||||
<Fraction 4 / 3>
|
||||
>>> f = Fraction("12/4")
|
||||
>>> f.simplified
|
||||
<Integer 3>
|
||||
|
||||
"""
|
||||
simplified = self._mo.simplified()
|
||||
|
||||
if isinstance(simplified, MOnumber):
|
||||
return Integer(simplified)
|
||||
|
||||
return Fraction(simplified)
|
||||
|
||||
def simplify(self):
|
||||
""" Itself or its simplified version
|
||||
|
||||
:example:
|
||||
>>> f = Fraction("12/8")
|
||||
>>> fs = f.simplify()
|
||||
>>> for i in fs.explain():
|
||||
... print(i)
|
||||
12 / 8
|
||||
3 / 2
|
||||
>>> f = Fraction("5/8")
|
||||
>>> fs = f.simplify()
|
||||
>>> for i in fs.explain():
|
||||
... print(i)
|
||||
5 / 8
|
||||
"""
|
||||
simplified = self.simplified
|
||||
try:
|
||||
if self.numerator == simplified.numerator:
|
||||
return self
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
simplified._ancestor = self
|
||||
return simplified
|
||||
|
||||
|
||||
|
||||
|
||||
# -----------------------------
|
||||
|
@@ -148,7 +148,11 @@ class Linear(Polynomial):
|
||||
>>> P.differentiate()
|
||||
<Integer 2>
|
||||
>>> P.roots
|
||||
[<Fraction - 2 / 1>]
|
||||
[<Integer - 2>]
|
||||
>>> for i in P.roots[0].explain():
|
||||
... print(i)
|
||||
- 2 / 1
|
||||
- 2
|
||||
|
||||
"""
|
||||
|
||||
@@ -190,9 +194,20 @@ class Linear(Polynomial):
|
||||
>>> from ...core.MO.polynomial import MOpolynomial, MOMonomial
|
||||
>>> P = Linear(MOpolynomial('x', [1, 2]))
|
||||
>>> P.roots
|
||||
[<Fraction - 2 / 1>]
|
||||
>>> #P = Linear(MOpolynomial('x', [1, -2]))
|
||||
>>> #P.roots
|
||||
[<Integer - 2>]
|
||||
>>> P = Linear(MOpolynomial('x', [2, 1]))
|
||||
>>> P.roots
|
||||
[<Fraction - 1 / 2>]
|
||||
>>> for i in P.roots[0].explain():
|
||||
... print(i)
|
||||
- 1 / 2
|
||||
>>> P = Linear(MOpolynomial('x', [10, 6]))
|
||||
>>> P.roots
|
||||
[<Fraction - 3 / 5>]
|
||||
>>> for i in P.roots[0].explain():
|
||||
... print(i)
|
||||
- 6 / 10
|
||||
- 3 / 5
|
||||
"""
|
||||
|
||||
try:
|
||||
|
@@ -54,10 +54,16 @@ class Token(object):
|
||||
yield self
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {render(self._mo, 'txt')}>"
|
||||
try:
|
||||
return f"<{self.__class__.__name__} {render(self._mo._tree, 'txt')}>"
|
||||
except AttributeError:
|
||||
return f"<{self.__class__.__name__} {render(self._mo, 'txt')}>"
|
||||
|
||||
def __str__(self):
|
||||
return render(self._mo)
|
||||
try:
|
||||
return render(self._mo._tree)
|
||||
except AttributeError:
|
||||
return render(self._mo)
|
||||
|
||||
@property
|
||||
def raw(self):
|
||||
|
@@ -30,7 +30,7 @@ Expression is the classe wich handle all calculus. It can randomly generate or i
|
||||
|
||||
"""
|
||||
|
||||
from .API import Expression, Integer, Decimal, render, Polynomial
|
||||
from .API import Expression, Integer, Decimal, render, Polynomial, Fraction
|
||||
from .core import random_list
|
||||
from decimal import getcontext
|
||||
#getcontext().prec = 2
|
||||
|
@@ -9,6 +9,8 @@
|
||||
from mapytex.calculus.core.tree import Tree
|
||||
from .mo import Molecule, MO
|
||||
from .atoms import MOnumber
|
||||
from decimal import Decimal
|
||||
from ..arithmetic import gcd
|
||||
|
||||
__all__ = ["MOFraction"]
|
||||
|
||||
@@ -70,6 +72,10 @@ class MOFraction(Molecule):
|
||||
def denominator(self):
|
||||
return self._denominator
|
||||
|
||||
@property
|
||||
def _value(self):
|
||||
return Decimal(self._numerator._value) / Decimal(self._denominator._value)
|
||||
|
||||
def inverse(self):
|
||||
""" return the inverse fraction """
|
||||
return MOFraction(self._denominator, self._numerator, self.negative)
|
||||
@@ -90,6 +96,37 @@ class MOFraction(Molecule):
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
def simplified(self):
|
||||
""" Simplified version of self
|
||||
|
||||
:examplex
|
||||
>>> f = MOFraction(2, 3)
|
||||
>>> f
|
||||
<MOFraction 2 / 3>
|
||||
>>> f.simplified()
|
||||
<MOFraction 2 / 3>
|
||||
>>> f = MOFraction(2, 6)
|
||||
>>> f
|
||||
<MOFraction 2 / 6>
|
||||
>>> f.simplified()
|
||||
<MOFraction 1 / 3>
|
||||
>>> f = MOFraction(32, 24)
|
||||
>>> f.simplified()
|
||||
<MOFraction 4 / 3>
|
||||
>>> f = MOFraction(32, 8)
|
||||
>>> f.simplified()
|
||||
<MOnumber 4>
|
||||
"""
|
||||
frac_gcd = gcd(self.numerator._value, self.denominator._value)
|
||||
new_num = self.numerator._value / frac_gcd
|
||||
new_denom = self.denominator._value / frac_gcd
|
||||
|
||||
if new_denom == 1:
|
||||
return MOnumber(new_num)
|
||||
|
||||
return MOFraction(new_num, new_denom)
|
||||
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# Reglages pour 'vim'
|
||||
|
@@ -132,7 +132,7 @@ class MOstrPower(Molecule):
|
||||
|
||||
class MOMonomial(Molecule):
|
||||
|
||||
""" Monomial math object"""
|
||||
""" Monomial math object : ax^n"""
|
||||
|
||||
MAINOP = "*"
|
||||
|
||||
|
@@ -18,7 +18,7 @@ __all__ = ["MOpolynomial"]
|
||||
|
||||
class MOpolynomial(Molecule):
|
||||
|
||||
""" MO polynomial"""
|
||||
""" MO polynomial: ax^n + ... + z (can't be a monomial)"""
|
||||
|
||||
MAINOP = "+"
|
||||
|
||||
@@ -39,6 +39,14 @@ class MOpolynomial(Molecule):
|
||||
<MOpolynomial 4x^3 + 1>
|
||||
>>> MOpolynomial('x', {0: 1, 3: 1})
|
||||
<MOpolynomial x^3 + 1>
|
||||
>>> MOpolynomial('x', [0, 0, 3])
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: A MOpolynomial can't be monomial it has to have more than one coefficient.
|
||||
>>> MOpolynomial('x', {3: 1})
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: A MOpolynomial can't be monomial it has to have more than one coefficient.
|
||||
|
||||
"""
|
||||
_variable = MO.factory(variable)
|
||||
@@ -58,6 +66,9 @@ class MOpolynomial(Molecule):
|
||||
raise TypeError("Coefs needs to be a dictionnary or a list")
|
||||
self._coefs = _coefs
|
||||
|
||||
if len(self._coefs) == 1:
|
||||
raise TypeError("A MOpolynomial can't be monomial it has to have more than one coefficient.")
|
||||
|
||||
monomials = OrderedDict()
|
||||
for deg in sorted(self._coefs.keys()):
|
||||
coef = self._coefs[deg]
|
||||
|
@@ -11,11 +11,11 @@ Add MO with typing
|
||||
"""
|
||||
|
||||
from multipledispatch import Dispatcher
|
||||
from ..tree import Tree
|
||||
from ..MO import MO, MOnumber, MOstr
|
||||
from ..MO import MOnumber, MOstr
|
||||
from ..MO.monomial import MOstrPower, MOMonomial
|
||||
from ..MO.polynomial import MOpolynomial
|
||||
from ..MO.fraction import MOFraction
|
||||
from ..compute.filters import special_case
|
||||
|
||||
add_doc = """ Add MOs
|
||||
|
||||
@@ -27,8 +27,26 @@ add_doc = """ Add MOs
|
||||
|
||||
add = Dispatcher("add", doc=add_doc)
|
||||
|
||||
def add_filter(left, right):
|
||||
""" Special cases for add MO (adding 0)
|
||||
|
||||
:param left: MO
|
||||
:param right: MO
|
||||
:returns: MO if it is a special case, nothing other wise
|
||||
"""
|
||||
try:
|
||||
if left == 0:
|
||||
return right
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
if right == 0:
|
||||
return left
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
@add.register((MOnumber, MOFraction), MOstr)
|
||||
@special_case(add_filter)
|
||||
def moscalar_mostr(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -39,11 +57,15 @@ def moscalar_mostr(left, right):
|
||||
>>> a = MOFraction(1, 5)
|
||||
>>> add(a, b)
|
||||
<MOpolynomial x + 1 / 5>
|
||||
>>> a = MOnumber(0)
|
||||
>>> add(a, b)
|
||||
<MOstr x>
|
||||
"""
|
||||
return MOpolynomial(right, [left, 1])
|
||||
|
||||
|
||||
@add.register(MOstr, (MOnumber, MOFraction))
|
||||
@special_case(add_filter)
|
||||
def mostr_moscalar(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -54,11 +76,15 @@ def mostr_moscalar(left, right):
|
||||
>>> b = MOFraction(1, 5)
|
||||
>>> add(a, b)
|
||||
<MOpolynomial x + 1 / 5>
|
||||
>>> b = MOnumber(0)
|
||||
>>> add(a, b)
|
||||
<MOstr x>
|
||||
"""
|
||||
return MOpolynomial(left, [right, 1])
|
||||
|
||||
|
||||
@add.register((MOnumber, MOFraction), MOstrPower)
|
||||
@special_case(add_filter)
|
||||
def moscalar_mostrpower(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -74,6 +100,7 @@ def moscalar_mostrpower(left, right):
|
||||
|
||||
|
||||
@add.register(MOstrPower, (MOnumber, MOFraction))
|
||||
@special_case(add_filter)
|
||||
def mostrpower_moscalar(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -89,6 +116,7 @@ def mostrpower_moscalar(left, right):
|
||||
|
||||
|
||||
@add.register((MOnumber, MOFraction), MOMonomial)
|
||||
@special_case(add_filter)
|
||||
def moscalar_momonomial(left, right):
|
||||
""" add a scalar with a MOMonomial to create a MOpolynomial
|
||||
|
||||
@@ -99,11 +127,17 @@ def moscalar_momonomial(left, right):
|
||||
>>> a = MOFraction(1, 5)
|
||||
>>> add(a, b)
|
||||
<MOpolynomial 3x^4 + 1 / 5>
|
||||
|
||||
>>> a = MOnumber(0)
|
||||
>>> b = MOMonomial(2, 'x', 4)
|
||||
>>> add(a, b)
|
||||
<MOMonomial 2x^4>
|
||||
"""
|
||||
return MOpolynomial(right.variable, {right.power: right.coefficient, 0: left})
|
||||
|
||||
|
||||
@add.register(MOMonomial, (MOnumber, MOFraction))
|
||||
@special_case(add_filter)
|
||||
def momonial_moscalar(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -115,11 +149,17 @@ def momonial_moscalar(left, right):
|
||||
>>> add(a, b)
|
||||
<MOpolynomial 3x^4 + 1 / 5>
|
||||
|
||||
>>> a = MOMonomial(2, 'x', 4)
|
||||
>>> b = MOnumber(0)
|
||||
>>> add(a, b)
|
||||
<MOMonomial 2x^4>
|
||||
|
||||
"""
|
||||
return MOpolynomial(left.variable, {0: right, left.power: left.coefficient})
|
||||
|
||||
|
||||
@add.register((MOnumber, MOFraction), MOpolynomial)
|
||||
@special_case(add_filter)
|
||||
def moscalar_mopolynomial(left, right):
|
||||
""" add a scalar with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -143,6 +183,7 @@ def moscalar_mopolynomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOpolynomial, (MOnumber, MOFraction))
|
||||
@special_case(add_filter)
|
||||
def mopolynomial_moscalar(left, right):
|
||||
""" add a scalar with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -164,6 +205,7 @@ def mopolynomial_moscalar(left, right):
|
||||
|
||||
|
||||
@add.register(MOstr, MOstr)
|
||||
@special_case(add_filter)
|
||||
def mostr_mostr(left, right):
|
||||
""" add 2 mostr
|
||||
|
||||
@@ -178,6 +220,7 @@ def mostr_mostr(left, right):
|
||||
|
||||
|
||||
@add.register(MOstr, MOstrPower)
|
||||
@special_case(add_filter)
|
||||
def mostr_mostrpower(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -195,6 +238,7 @@ def mostr_mostrpower(left, right):
|
||||
|
||||
|
||||
@add.register(MOstrPower, MOstr)
|
||||
@special_case(add_filter)
|
||||
def mostrpower_mostr(left, right):
|
||||
""" add a scalar with a letter to create a MOpolynomial
|
||||
|
||||
@@ -212,6 +256,7 @@ def mostrpower_mostr(left, right):
|
||||
|
||||
|
||||
@add.register(MOstrPower, MOstrPower)
|
||||
@special_case(add_filter)
|
||||
def mostrpower_mostrpower(left, right):
|
||||
""" add 2 mostrpower
|
||||
|
||||
@@ -231,6 +276,7 @@ def mostrpower_mostrpower(left, right):
|
||||
|
||||
|
||||
@add.register(MOstr, MOpolynomial)
|
||||
@special_case(add_filter)
|
||||
def mostr_mopolynomial(left, right):
|
||||
""" add a str with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -249,6 +295,7 @@ def mostr_mopolynomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOpolynomial, MOstr)
|
||||
@special_case(add_filter)
|
||||
def mopolynomial_mostr(left, right):
|
||||
""" add a str with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -266,6 +313,7 @@ def mopolynomial_mostr(left, right):
|
||||
|
||||
|
||||
@add.register(MOstrPower, MOpolynomial)
|
||||
@special_case(add_filter)
|
||||
def mostrpower_mopolynomial(left, right):
|
||||
""" add a strPower with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -284,6 +332,7 @@ def mostrpower_mopolynomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOpolynomial, MOstrPower)
|
||||
@special_case(add_filter)
|
||||
def mopolynomial_mostrpower(left, right):
|
||||
""" add a strPower with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -301,6 +350,7 @@ def mopolynomial_mostrpower(left, right):
|
||||
|
||||
|
||||
@add.register(MOMonomial, MOpolynomial)
|
||||
@special_case(add_filter)
|
||||
def momonomial_mopolynomial(left, right):
|
||||
""" add a Monomial with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -319,6 +369,7 @@ def momonomial_mopolynomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOpolynomial, MOMonomial)
|
||||
@special_case(add_filter)
|
||||
def mopolynomial_momonomial(left, right):
|
||||
""" add a Monomial with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -336,6 +387,7 @@ def mopolynomial_momonomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOpolynomial, MOpolynomial)
|
||||
@special_case(add_filter)
|
||||
def mopolynomial_mopolynomial(left, right):
|
||||
""" add a polynomial with a MOpolynomial to create a MOpolynomial
|
||||
|
||||
@@ -355,6 +407,7 @@ def mopolynomial_mopolynomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOstr, MOMonomial)
|
||||
@special_case(add_filter)
|
||||
def mostr_monomial(left, right):
|
||||
""" add a mostr with a MOMonomial to create a MOpolynomial
|
||||
|
||||
@@ -370,6 +423,7 @@ def mostr_monomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOMonomial, MOstr)
|
||||
@special_case(add_filter)
|
||||
def monomial_mostr(left, right):
|
||||
""" add a mostr with a MOMonomial to create a MOpolynomial
|
||||
|
||||
@@ -385,6 +439,7 @@ def monomial_mostr(left, right):
|
||||
|
||||
|
||||
@add.register(MOstrPower, MOMonomial)
|
||||
@special_case(add_filter)
|
||||
def mostrpower_monomial(left, right):
|
||||
""" add a mostrPower with a MOMonomial to create a MOpolynomial
|
||||
|
||||
@@ -402,6 +457,7 @@ def mostrpower_monomial(left, right):
|
||||
|
||||
|
||||
@add.register(MOMonomial, MOstrPower)
|
||||
@special_case(add_filter)
|
||||
def monomial_mostrpower(left, right):
|
||||
""" add a mostrPower with a MOMonomial to create a MOpolynomial
|
||||
|
||||
@@ -419,6 +475,7 @@ def monomial_mostrpower(left, right):
|
||||
|
||||
|
||||
@add.register(MOMonomial, MOMonomial)
|
||||
@special_case(add_filter)
|
||||
def monomial_momonomial(left, right):
|
||||
""" add a moMonomial with a MOMonomial to create a MOpolynomial
|
||||
|
||||
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
31
test/calculus/core/test_render.py
Normal file
31
test/calculus/core/test_render.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import mapytex
|
||||
|
||||
def test_default_render():
|
||||
assert mapytex.render.render_name == "txt"
|
||||
|
||||
def test_default_rending():
|
||||
e = mapytex.Expression("2*3")
|
||||
assert str(e) == "2*3"
|
||||
|
||||
def test_changing_render():
|
||||
assert mapytex.render.render_name == "txt"
|
||||
mapytex.render.set_render("tex")
|
||||
assert mapytex.render.render_name == "tex"
|
||||
mapytex.render.set_render("txt")
|
||||
assert mapytex.render.render_name == "txt"
|
||||
|
||||
|
||||
def test_changing_rending():
|
||||
e = mapytex.Expression.from_str("2*3")
|
||||
f = mapytex.Fraction("2/3")
|
||||
assert str(e) == "2 * 3"
|
||||
assert str(f) == "2 / 3"
|
||||
mapytex.render.set_render("tex")
|
||||
assert str(e) == "2 \\times 3"
|
||||
assert str(f) == "\\dfrac{2}{3}"
|
||||
mapytex.render.set_render("txt")
|
||||
assert str(e) == "2 * 3"
|
||||
assert str(f) == "2 / 3"
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user