New render seems to be ok some debuging still have to be done
This commit is contained in:
parent
41aa8dfb11
commit
2132c2ba59
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from .generic import Stack, flatten_list, expand_list
|
from .generic import Stack, flatten_list, expand_list, isNumber, isOperator
|
||||||
from .renders import txt, post2in_fix, tex
|
from .renders import txt, post2in_fix, tex
|
||||||
from .str2tokens import str2tokens, isNumber, isOperator
|
from .str2tokens import str2tokens
|
||||||
|
|
||||||
__all__ = ['Expression']
|
__all__ = ['Expression']
|
||||||
|
|
||||||
|
@ -60,6 +60,15 @@ class Fraction(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "< Fraction " + self.__str__() + ">"
|
return "< Fraction " + self.__str__() + ">"
|
||||||
|
|
||||||
|
def __txt__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __tex__(self):
|
||||||
|
if self._denom == 1:
|
||||||
|
return str(self._num)
|
||||||
|
else:
|
||||||
|
return "\\frac{{ {a} }}{{ {b} }}".format(a = self._num, b = self._denom)
|
||||||
|
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
return self._num / self._denom
|
return self._num / self._denom
|
||||||
|
|
||||||
|
@ -243,6 +243,37 @@ def convolution_dict(D1, D2, op = lambda x,y:x*y,\
|
|||||||
|
|
||||||
return new_dict
|
return new_dict
|
||||||
|
|
||||||
|
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 type(exp) == int:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
from .fraction import Fraction
|
from .fraction import Fraction
|
||||||
from .generic import flatten_list
|
from .generic import flatten_list, isNumber
|
||||||
|
|
||||||
class Operator(str):
|
class Operator(str):
|
||||||
|
|
||||||
@ -75,25 +75,23 @@ class Operator(str):
|
|||||||
>>> add = Operator("+", 2)
|
>>> add = Operator("+", 2)
|
||||||
>>> sub1 = Operator("-", 1)
|
>>> sub1 = Operator("-", 1)
|
||||||
>>> div = Operator("/", 1)
|
>>> div = Operator("/", 1)
|
||||||
>>> mul.__txt__(1,2)
|
>>> mul.__txt__('1','2')
|
||||||
'1 * 2'
|
'1 * 2'
|
||||||
>>> add.__txt__(1,2)
|
>>> add.__txt__('1','2')
|
||||||
'1 + 2'
|
'1 + 2'
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
>>> f = save_mainOp('2 + 3',add)
|
||||||
>>> mul.__txt__(f, 4)
|
>>> mul.__txt__(f, '4')
|
||||||
'( 2 + 3 ) * 4'
|
'( 2 + 3 ) * 4'
|
||||||
>>> f = save_mainOp('-3',sub1)
|
>>> f = save_mainOp('-3',sub1)
|
||||||
>>> sub1.__txt__(f)
|
>>> sub1.__txt__(f)
|
||||||
'- ( -3 )'
|
'- ( -3 )'
|
||||||
>>> sub1.__txt__(-3)
|
>>> sub1.__txt__('-3')
|
||||||
'- ( -3 )'
|
'- ( -3 )'
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
>>> f = save_mainOp('2 + 3',add)
|
||||||
>>> sub1.__txt__(f)
|
>>> sub1.__txt__(f)
|
||||||
'- ( 2 + 3 )'
|
'- ( 2 + 3 )'
|
||||||
"""
|
"""
|
||||||
|
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
|
||||||
#vive le inline? ...
|
|
||||||
replacement = {"op"+str(i+1): ' '.join([str(o) if type(o)==int else o for o in self.add_parenthesis(op)]) for (i,op) in enumerate(args)}
|
|
||||||
|
|
||||||
ans = self._txt.format(**replacement)
|
ans = self._txt.format(**replacement)
|
||||||
ans = save_mainOp(ans, self)
|
ans = save_mainOp(ans, self)
|
||||||
@ -109,23 +107,23 @@ class Operator(str):
|
|||||||
>>> add = Operator("+", 2)
|
>>> add = Operator("+", 2)
|
||||||
>>> sub1 = Operator("-", 1)
|
>>> sub1 = Operator("-", 1)
|
||||||
>>> div = Operator("/", 1)
|
>>> div = Operator("/", 1)
|
||||||
>>> mul.__tex__(1,2)
|
>>> mul.__tex__('1','2')
|
||||||
'1 \\\\times 2'
|
'1 \\\\times 2'
|
||||||
>>> add.__tex__(1,2)
|
>>> add.__tex__('1','2')
|
||||||
'1 + 2'
|
'1 + 2'
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
>>> f = save_mainOp('2 + 3',add)
|
||||||
>>> mul.__tex__(f, 4)
|
>>> mul.__tex__(f, '4')
|
||||||
'( 2 + 3 ) \\\\times 4'
|
'( 2 + 3 ) \\\\times 4'
|
||||||
>>> f = save_mainOp('-3',sub1)
|
>>> f = save_mainOp('-3',sub1)
|
||||||
>>> sub1.__tex__(f)
|
>>> sub1.__tex__(f)
|
||||||
'- ( -3 )'
|
'- ( -3 )'
|
||||||
>>> sub1.__tex__(-3)
|
>>> sub1.__tex__('-3')
|
||||||
'- ( -3 )'
|
'- ( -3 )'
|
||||||
>>> f = save_mainOp('2 + 3',add)
|
>>> f = save_mainOp('2 + 3',add)
|
||||||
>>> sub1.__tex__(f)
|
>>> sub1.__tex__(f)
|
||||||
'- ( 2 + 3 )'
|
'- ( 2 + 3 )'
|
||||||
"""
|
"""
|
||||||
replacement = {"op"+str(i+1): ' '.join([str(o) if type(o)==int else o for o in self.add_parenthesis(op)]) for (i,op) in enumerate(args)}
|
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
|
||||||
|
|
||||||
ans = self._tex.format(**replacement)
|
ans = self._tex.format(**replacement)
|
||||||
ans = save_mainOp(ans, self)
|
ans = save_mainOp(ans, self)
|
||||||
@ -174,13 +172,15 @@ class Operator(str):
|
|||||||
if op.mainOp.priority < self.priority:
|
if op.mainOp.priority < self.priority:
|
||||||
op = flatten_list(["("] + [op] + [")"])
|
op = flatten_list(["("] + [op] + [")"])
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if type(op) == int and op < 0:
|
try:
|
||||||
|
if int(op) < 0:
|
||||||
op = ['(', op, ')']
|
op = ['(', op, ')']
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
return flatten_list([op])
|
return flatten_list([op])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save_mainOp(obj, mainOp):
|
def save_mainOp(obj, mainOp):
|
||||||
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
||||||
|
|
||||||
@ -198,21 +198,27 @@ def save_mainOp(obj, mainOp):
|
|||||||
return Fake(obj)
|
return Fake(obj)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#op = Operator("+", 2)
|
op = Operator("+", 2)
|
||||||
#print(op.__txt__(1,2))
|
print(op.__txt__('1','2'))
|
||||||
#mul = Operator("*", 2)
|
mul = Operator("*", 2)
|
||||||
#add = Operator("+", 2)
|
add = Operator("+", 2)
|
||||||
#sub1 = Operator("-", 1)
|
sub1 = Operator("-", 1)
|
||||||
#div = Operator("/", 1)
|
div = Operator("/", 1)
|
||||||
#print(mul.__txt__(1,2))
|
print(mul.__txt__('1','2'))
|
||||||
#print(add.__txt__(1,2))
|
print(add.__txt__('1','2'))
|
||||||
#f = save_mainOp('2 + 3',add)
|
f = save_mainOp('2 + 3',add)
|
||||||
#print(mul.__txt__(f, 4))
|
print(mul.__txt__(f, '4'))
|
||||||
#f = save_mainOp('-3',sub1)
|
f = save_mainOp('-3',sub1)
|
||||||
#print(sub1.__txt__(f))
|
print(sub1.__txt__(f))
|
||||||
#print(sub1.__txt__(-3))
|
print(sub1.__txt__('-3'))
|
||||||
#f = save_mainOp('2 + 3',add)
|
f = save_mainOp('2 + 3',add)
|
||||||
#print(sub1.__txt__(f))
|
print(sub1.__txt__(f))
|
||||||
|
|
||||||
|
from .fraction import Fraction
|
||||||
|
f = Fraction(1, 2)
|
||||||
|
print(add.__txt__(f.__txt__(),'2'))
|
||||||
|
print(add.__tex__(f.__tex__(),'2'))
|
||||||
|
|
||||||
|
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
@ -38,13 +38,36 @@ class Render(object):
|
|||||||
# Switch op1 and op2 to respect order
|
# Switch op1 and op2 to respect order
|
||||||
operandeStack.push(self.render(token)(op2, op1))
|
operandeStack.push(self.render(token)(op2, op1))
|
||||||
else:
|
else:
|
||||||
operandeStack.push(token)
|
operandeStack.push(self.render(token)())
|
||||||
|
|
||||||
return operandeStack.pop()
|
return operandeStack.pop()
|
||||||
|
|
||||||
txt = Render(lambda x:x.__txt__)
|
def txt_render(token):
|
||||||
tex = Render(lambda x:x.__tex__)
|
def render(*args):
|
||||||
p2i = Render(lambda x:x.__p2i__)
|
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 list(token)
|
||||||
|
return render
|
||||||
|
p2i = Render(p2i_render)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from .operator import Operator
|
from .operator import Operator
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
from .render import Render
|
|
||||||
from .fraction import Fraction
|
|
||||||
from .generic import first_elem, last_elem
|
|
||||||
|
|
||||||
__all__ = ['post2in_fix', 'tex', 'txt']
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# A infix to postfix list convertor
|
|
||||||
|
|
||||||
p2i_infix = {"+": "+", "-": "-", "*": "*", "/" : "/", ":": ":", "^":"^"}
|
|
||||||
p2i_postfix = {}
|
|
||||||
p2i_other = {"(": "(", ")": ")"}
|
|
||||||
|
|
||||||
post2in_fix = Render(p2i_infix, p2i_postfix, p2i_other, join = False)
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# A console render
|
|
||||||
|
|
||||||
def txtMult(op1,op2):
|
|
||||||
""" Tex render for *
|
|
||||||
Cases where \\times won't be displayed
|
|
||||||
* nbr letter
|
|
||||||
* nbr (
|
|
||||||
* )(
|
|
||||||
"""
|
|
||||||
first_nbr = type(op1) in [int, Fraction]
|
|
||||||
seg_letter = type(op2) == str and op2.isalpha()
|
|
||||||
first_par = (first_elem(op2) == "(")
|
|
||||||
seg_par = (last_elem(op1) == ")")
|
|
||||||
|
|
||||||
if (first_nbr and (seg_letter or seg_par)) \
|
|
||||||
or (first_par and seg_par):
|
|
||||||
return [op1, op2]
|
|
||||||
else:
|
|
||||||
return [op1, "*", op2]
|
|
||||||
|
|
||||||
txt_infix = {"+": "+", "-": "-", "*": txtMult, "/" : "/", ":":":", "^":"^"}
|
|
||||||
txt_postfix = {}
|
|
||||||
txt_other = {"(": "(", ")": ")"}
|
|
||||||
|
|
||||||
txt = Render(txt_infix, txt_postfix, txt_other)
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# A latex render
|
|
||||||
|
|
||||||
def texSlash(op1, op2):
|
|
||||||
""" Tex render for / """
|
|
||||||
if not Render.isNumerande(op1) and op1[0] == "(" and op1[-1] == ")":
|
|
||||||
op1 = op1[1:-1]
|
|
||||||
if not Render.isNumerande(op2) and op2[0] == "(" and op2[-1] == ")":
|
|
||||||
op2 = op2[1:-1]
|
|
||||||
return ["\\frac{" , op1 , "}{" , op2 , "}"]
|
|
||||||
|
|
||||||
def texFrac(frac):
|
|
||||||
""" Tex render for Fractions"""
|
|
||||||
return ["\\frac{" , str(frac._num) , "}{" , str(frac._denom) , "}"]
|
|
||||||
|
|
||||||
def texMult(op1,op2):
|
|
||||||
""" Tex render for *
|
|
||||||
Cases where \\times won't be displayed
|
|
||||||
* nbr letter
|
|
||||||
* nbr (
|
|
||||||
* )(
|
|
||||||
"""
|
|
||||||
first_nbr = type(op1) in [int, Fraction]
|
|
||||||
seg_letter = type(op2) == str and op2.isalpha()
|
|
||||||
first_par = (first_elem(op2) == "(")
|
|
||||||
seg_par = (last_elem(op1) == ")")
|
|
||||||
|
|
||||||
if (first_nbr and (seg_letter or seg_par)) \
|
|
||||||
or (first_par and seg_par):
|
|
||||||
return [op1, op2]
|
|
||||||
else:
|
|
||||||
return [op1, "\\times", op2]
|
|
||||||
|
|
||||||
tex_infix = {"+": " + ", "-": " - ", "*": texMult , ":": ":", "^":"^"}
|
|
||||||
tex_postfix = {"/": texSlash}
|
|
||||||
tex_other = {"(": "(", ")": ")"}
|
|
||||||
tex_type_render = {str:str, int: str, Fraction: texFrac}
|
|
||||||
|
|
||||||
tex = Render(tex_infix, tex_postfix, tex_other, type_render = tex_type_render)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
#exp = [2, 5, '^', 1, '-', 3, 4, '*', ':']
|
|
||||||
#print(txt(exp))
|
|
||||||
#exp = [2, 5, '^', 1, '-', 3, 4, '*', '/', 3, 5, '/', ':']
|
|
||||||
exp = [2, -3, "*"]
|
|
||||||
print(tex(exp))
|
|
||||||
#exp = [2, 5, '^', 1, '-', 3, 4, '*', '/', 3, '+']
|
|
||||||
#print(post2in_fix(exp))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
@ -2,7 +2,7 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from .operator import Operator
|
from .operator import Operator
|
||||||
from .generic import Stack
|
from .generic import Stack, isOperator, isNumber
|
||||||
|
|
||||||
def str2tokens(exp):
|
def str2tokens(exp):
|
||||||
""" Parse the string into tokens then turn it into postfix form
|
""" Parse the string into tokens then turn it into postfix form
|
||||||
@ -147,36 +147,6 @@ def in2post_fix(infix_tokens):
|
|||||||
return postfix_tokens
|
return postfix_tokens
|
||||||
|
|
||||||
|
|
||||||
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 type(exp) == int:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#a, s, m, d, p = Operator("+"), Operator("-"), Operator("*"), Operator("/"), Operator("^")
|
#a, s, m, d, p = Operator("+"), Operator("-"), Operator("*"), Operator("/"), Operator("^")
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from pymath.renders import tex, txt
|
from pymath.render import tex, txt,p2i
|
||||||
from pymath.fraction import Fraction
|
from pymath.fraction import Fraction
|
||||||
from pymath.operator import Operator
|
from pymath.operator import Operator
|
||||||
|
|
||||||
@ -43,8 +43,24 @@ class TestTexRender(unittest.TestCase):
|
|||||||
rend = tex(e)
|
rend = tex(e)
|
||||||
self.assertEqual(rend, wanted_render[i])
|
self.assertEqual(rend, wanted_render[i])
|
||||||
|
|
||||||
def test_mult_exp(self):
|
def test_parentheses(self):
|
||||||
pass
|
mul = Operator("*", 2)
|
||||||
|
add = Operator("+", 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 ) \\times 4',\
|
||||||
|
'2 \\times 3 + 4',\
|
||||||
|
'2 + 3 \\times 4',\
|
||||||
|
'2 + 3 + 4',\
|
||||||
|
]
|
||||||
|
for (i,e) in enumerate(exps):
|
||||||
|
rend = tex(e)
|
||||||
|
self.assertEqual(rend, wanted_render[i])
|
||||||
|
|
||||||
def test_slash(self):
|
def test_slash(self):
|
||||||
pass
|
pass
|
||||||
@ -91,8 +107,24 @@ class TesttxtRender(unittest.TestCase):
|
|||||||
rend = txt(e)
|
rend = txt(e)
|
||||||
self.assertEqual(rend, wanted_render[i])
|
self.assertEqual(rend, wanted_render[i])
|
||||||
|
|
||||||
def test_mult_exp(self):
|
def test_parentheses(self):
|
||||||
pass
|
mul = Operator("*", 2)
|
||||||
|
add = Operator("+", 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):
|
def test_slash(self):
|
||||||
pass
|
pass
|
Loading…
Reference in New Issue
Block a user