New render seems to be ok some debuging still have to be done

This commit is contained in:
lafrite 2014-11-09 12:06:31 +01:00
parent 41aa8dfb11
commit 2132c2ba59
8 changed files with 144 additions and 176 deletions

View File

@ -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']

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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("^")

View File

@ -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