Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Lafrite 2014-12-19 15:26:36 +01:00
commit 450af74a0d
9 changed files with 451 additions and 142 deletions

View File

@ -5,5 +5,16 @@ pymath/arithmetic.py
pymath/expression.py
pymath/fraction.py
pymath/generic.py
pymath/operator.py
pymath/polynom.py
pymath/random_expression.py
pymath/render.py
pymath/str2tokens.py
test/test_arithmetic.py
test/test_expression.py
test/test_fraction.py
test/test_generic.py
test/test_polynom.py
test/test_random_expression.py
test/test_render.py
test/test_str2tokens.py

View File

@ -98,7 +98,7 @@ class Expression(object):
op1 = tokenList[0]
op2 = tokenList[1]
operator = tokenList[2]
res = operator(op1, op2)
tmpTokenList.append(res)

View File

@ -3,71 +3,57 @@
from .generic import flatten_list, isNumber
import types
class Operator(str):
"""The operator class, is a string (representation of the operator) with its arity"""
PRIORITY = {"^": [0, 5], "/": [0, 4], "*" : [0,3], ":": [0,3], "+": [0,1], "-":[2,1], "(":[0,0]}
OPERATIONS = { \
"+": ["", ("__add__","__radd__")],\
"-": ["__neg__", ("__sub__", "__rsub__")], \
"*": ["", ("__mul__", "__rmul__")], \
"/": ["", ("__div__","__rdiv__")], \
"^": ["", ("__pow__", "")], \
"(": ["",""],\
}
TXT = { \
"+": ["", "{op1} + {op2}"] ,\
"-": ["- {op1}", "{op1} - {op2}"] ,\
"*": ["", "{op1} * {op2}"] ,\
"/": ["", "{op1} / {op2}"] ,\
"^": ["", "{op1} ^ {op2}"] ,\
"(": ["",""],\
}
TEX = { \
"+": ["", "{op1} + {op2}"] ,\
"-": ["- {op1}", "{op1} - {op2}"] ,\
"*": ["", "{op1} \\times {op2}"] ,\
"/": ["", "\\frac{{ {op1} }}{{ {op2} }}"] ,\
"^": ["", "{op1}^{{ {op2} }}"] ,\
"(": ["",""],\
}
def __new__(cls, operator, arity = 2):
def __new__(cls, operator = "", name = "", priority = 0, actions = ("",""), txt = "", tex = "", arity = 2):
""" Create an Operator """
#def __new__(cls, operator, arity = 2):
op = str.__new__(cls, operator)
op.operator = operator
op.name = name
op.arity = arity
# TODO: Add op.visibility |sam. nov. 8 17:00:08 CET 2014
op.priority = cls.PRIORITY[operator][arity - 1]
op.actions = cls.OPERATIONS[operator][arity-1]
op._txt = cls.TXT[operator][arity-1]
op._tex = cls.TEX[operator][arity-1]
op.priority = priority
op.actions = actions
op.txt = txt
op.tex = tex
op.isOperator = 1
# TODO: Add self.visibility |sam. nov. 8 17:00:08 CET 2014
return op
def __call__(self, *args):
""" Calling this operator performs the rigth calculus """
return self._call(*args)
def _call(self, *args):
"""Trick to avoid overloading __call__ """
if self.arity == 1:
return getattr(args[0], self.actions)()
elif self.arity == 2:
# C'est moche mais je veux que ça marche...
if str(self) == "/":
# TODO: faudra changer ça c'est pas beau! |ven. nov. 14 16:13:49 CET 2014
from .fraction import Fraction
ans = [Fraction(args[0], args[1])]
ans += ans[0].simplify()
return ans
if type(args[1]) == int:
return getattr(args[0], self.actions[0])(args[1])
else:
if type(args[1]) == int:
return getattr(args[0], self.actions[0])(args[1])
else:
return getattr(args[1], self.actions[1])(args[0])
return getattr(args[1], self.actions[1])(args[0])
def _render(self, link, *args):
"""Global step for __txt__ and __tex__
:param link: the link between operators
:param *args: the operands
:returns: the string with operator and operands
"""
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
ans = link.format(**replacement)
ans = save_mainOp(ans, self)
return ans
def __txt__(self, *args):
"""Txt rendering for the operator
@ -91,11 +77,7 @@ class Operator(str):
>>> op.sub1.__txt__(f)
'- ( 2 + 3 )'
"""
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
ans = self._txt.format(**replacement)
ans = save_mainOp(ans, self)
return ans
return self._render(self.txt, *args)
def __tex__(self, *args):
"""Tex rendering for the operator
@ -119,11 +101,7 @@ class Operator(str):
>>> op.sub1.__tex__(f)
'- ( 2 + 3 )'
"""
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
ans = self._tex.format(**replacement)
ans = save_mainOp(ans, self)
return ans
return self._render(self.tex, *args)
def __p2i__(self, *args):
"""Fix list transformation for the operator
@ -166,6 +144,7 @@ class Operator(str):
if op.mainOp.priority < self.priority:
op = flatten_list(["("] + [op] + [")"])
except AttributeError:
# op has not the attribute priority
try:
if int(op) < 0:
op = ['(', op, ')']
@ -173,18 +152,6 @@ class Operator(str):
pass
return flatten_list([op])
class op(object):
""" List of admited operations """
# TODO: On pourrait peut être le faire plus proprement avec des décorateurs? |mar. nov. 11 20:24:54 CET 2014
add = Operator("+")
sub = Operator("-")
mul = Operator("*")
div = Operator("/")
pw = Operator("^")
sub1 = Operator("-", 1)
par = Operator("(")
def save_mainOp(obj, mainOp):
"""Create a temporary class build over built-in type to stock the main operation of a calculus
@ -201,27 +168,339 @@ def save_mainOp(obj, mainOp):
return Fake(obj)
def operatorize(fun):
"""Transform the answer of the function into an operator
The returned value of the function has to be a dictionnary with those keys
* "operator": the name (Needed!)
* "priority": the priority level
* "actions": mathematics actions of the operator (list of 1 element if the arity is 1, 2 elements if arity is 2)
* "txt": string ready to be formated in txt for with {op1} and/or {op2}
* "tex": string ready to be formated in tex for with {op1} and/or {op2}
* "arity": arity ie number of operands needed
* "_call": action to perform when call the operator
* "_render": action use in __txt__ and __tex__
* "__txt__": txt rendering
* "__tex__": tex rendering
* "add_parenthesis": mechanism to add parenthesis
"""
def mod_fun(self, *args):
ans = fun(self, *args)
new_op = Operator(ans["operator"])
for (attr, value) in ans.items():
if hasattr(value, '__call__'):
setattr(new_op, attr, types.MethodType(value, new_op))
else:
setattr(new_op, attr, value)
return new_op
return mod_fun
class ClassProperty(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, owner_self, owner_cls):
return self.fget(owner_cls)
class op(object):
""" List of admited operations """
_operators = {("+",2): "add",\
("-", 2): "sub",\
("-", 1): "sub1",\
("*", 2): "mul",\
("/", 2): "div",\
("^", 2): "pw",\
("(", 2): "par",\
}
@classmethod
def get_op(cls, op, arity = 2):
"""Return the corresponding operator
:op: symbole of the op
:arity: the arity
>>> op.get_op('+')
'+'
>>> mul = op.get_op('*')
>>> mul.tex
'{op1} \\\\times {op2}'
>>> mul.txt
'{op1} * {op2}'
"""
try:
return getattr(cls, cls._operators[(op, arity)])
except KeyError:
raise KeyError("{theOp} (arity: {arity}) is not available".format(theOp = op, arity = arity))
@classmethod
def can_be_operator(cls, symbole):
""" Tell if the symbole can be an operator """
return symbole in [i[0] for i in cls._operators]
@ClassProperty
@operatorize
def add(cls):
""" The operator +
>>> add = op.add
>>> add
'+'
>>> add(1, 2)
3
>>> add.__tex__('1','2')
'1 + 2'
>>> add.__txt__('1','2')
'1 + 2'
>>> add.__tex__('1','-2')
'1 + (-2)'
"""
caract = {
"operator" : "+", \
"name" : "add",\
"priority" : 1, \
"arity" : 2, \
"actions" : ("__add__","__radd__"), \
"txt" : "{op1} + {op2}",\
"tex" : "{op1} + {op2}",\
}
return caract
@ClassProperty
@operatorize
def sub(self):
""" The operator -
>>> sub = op.sub
>>> sub
'-'
>>> sub(1, 2)
-1
>>> sub.__tex__('1','2')
'1 - 2'
>>> sub.__txt__('1','2')
'1 - 2'
>>> sub.__tex__('1','-2')
'1 - (-2)'
"""
caract = {
"operator" : "-", \
"name" : "sub",\
"priority" : 1, \
"arity" : 2, \
"actions" : ("__sub__","__rsub__"), \
"txt" : "{op1} - {op2}",\
"tex" : "{op1} - {op2}",\
}
return caract
@ClassProperty
@operatorize
def sub1(self):
""" The operator -
>>> sub1 = op.sub1
>>> sub1
'-'
>>> sub1(1)
-1
>>> sub1.__tex__('1')
'- 1'
>>> sub1.__txt__('1')
'- 1'
>>> sub1.__tex__('-1')
'- (-1)'
"""
def add_parenthesis(self, op):
""" Add parenthesis if necessary """
try:
if op.mainOp.priority <= self.priority:
op = flatten_list(["("] + [op] + [")"])
except AttributeError:
# op has not the attribute priority
try:
if int(op) < 0:
op = ['(', op, ')']
except ValueError:
pass
return flatten_list([op])
caract = {
"operator" : "-", \
"name" : "sub1",\
"priority" : 2, \
"arity" : 1, \
"actions" : "__neg__",\
"txt" : "- {op1}",\
"tex" : "- {op1}",\
"add_parenthesis": add_parenthesis,\
}
return caract
@ClassProperty
@operatorize
def mul(self):
""" The operator *
>>> mul = op.mul
>>> mul
'*'
>>> mul(1, 2)
2
>>> mul.__tex__('1','2')
'1 \\times 2'
>>> mul.__txt__('1','2')
'1 * 2'
>>> mul.__tex__('1','-2')
'1 \\times (-2)'
"""
# * can not be display in some cases
def _render(self, link, *args):
replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)}
if not self.visibility or args[1][0] == "(" or \
(type(args[1][0]) == str and args[1][0].isalpha()):
ans = "{op1} {op2}".format(**replacement)
ans = save_mainOp(ans, self)
return ans
else:
ans = link.format(**replacement)
ans = save_mainOp(ans, self)
return ans
caract = {
"operator" : "*", \
"name" : "mul",\
"priority" : 4, \
"arity" : 2, \
"actions" : ("__mul__","__rmul__"), \
"txt" : "{op1} * {op2}",\
"tex" : "{op1} \\times {op2}",\
"visibility": 1,\
"_render": _render
}
return caract
@ClassProperty
@operatorize
def div(self):
""" The operator /
>>> div = op.div
>>> div
'/'
>>> div(1, 2)
< Fraction 1 / 2>
>>> div.__tex__('1','2')
'\\frac{ 1 }{ 2 }'
>>> div.__tex__('1','2')
'\\frac{ -1 }{ 2 }'
>>> div.__txt__('1','2')
'1 / 2'
"""
from .fraction import Fraction
def _call(self, op1, op2):
if op2 == 1:
return op1
else:
return Fraction(op1,op2)
def __tex__(self, *args):
# Pas besoin de parenthèses en plus pour \frac
replacement = {"op"+str(i+1): op for (i,op) in enumerate(args)}
ans = self.tex.format(**replacement)
ans = save_mainOp(ans, self)
return ans
caract = {
"operator" : "/", \
"name" : "div",\
"priority" : 4, \
"arity" : 2, \
"txt" : "{op1} / {op2}",\
"tex" : "\\frac{{ {op1} }}{{ {op2} }}",\
"_call": _call,\
"__tex__":__tex__,\
}
return caract
@ClassProperty
@operatorize
def pw(self):
""" The operator ^
>>> pw = op.pw
>>> pw
'^'
>>> pw(2, 3)
8
>>> pw.__tex__('2','3')
'2^{ 3 }'
>>> pw.__txt__('2','3')
'2 ^ 3'
>>> pw.__txt__('-2','3')
'( -2 ) ^ 3'
"""
def _call(self, op1, op2):
""" Calling this operator performs the rigth calculus """
return getattr(op1, "__pow__")(op2)
caract = {
"operator" : "^", \
"name" : "pw",\
"priority" : 5, \
"arity" : 2, \
"actions" : ("__pow__",""), \
"txt" : "{op1} ^ {op2}",\
"tex" : "{op1}^{{ {op2} }}",\
"_call":_call,\
}
return caract
@ClassProperty
@operatorize
def par(self):
""" The operator ( """
caract = {
"operator" : "(", \
"name" : "par",\
"priority" : 0, \
"arity" : 0, \
}
return caract
if __name__ == '__main__':
op = Operator("+", 2)
print(op.__txt__('1','2'))
mul = Operator("*", 2)
add = Operator("+", 2)
sub1 = Operator("-", 1)
div = Operator("/", 1)
print(mul.__txt__('1','2'))
print(add.__txt__('1','2'))
f = save_mainOp('2 + 3',add)
print(mul.__txt__(f, '4'))
f = save_mainOp('-3',sub1)
print(sub1.__txt__(f))
print(sub1.__txt__('-3'))
f = save_mainOp('2 + 3',add)
print(sub1.__txt__(f))
print(op.add.__tex__('1','2'))
print(op.mul.__tex__('1','2'))
print(op.sub.__tex__('1','2'))
f = save_mainOp('2 + 3',op.add)
print(op.mul.__txt__(f, '4'))
f = save_mainOp('-3',op.sub1)
print(op.sub1.__txt__(f))
print(op.sub1.__txt__('-3'))
f = save_mainOp('2 + 3',op.add)
print(op.sub1.__txt__(f))
from .fraction import Fraction
f = Fraction(1, 2)
print(add.__txt__(f.__txt__(),'2'))
print(add.__tex__(f.__tex__(),'2'))
print(op.add.__txt__(f.__txt__(),'2'))
print(op.add.__tex__(f.__tex__(),'2'))
print("\t op.can_be_operator('+') :" + str(op.can_be_operator('+')))
print("\t op.can_be_operator('t') :" + str(op.can_be_operator('t')))
import doctest

View File

@ -31,6 +31,19 @@ class RdExpression(object):
@classmethod
def set_form(cls, form):
""" Define whether RdExpression create expression with Expression (nice render) or if it only replace inside {} not taking care or render
>>> form = "{a}*{b}"
>>> exp = RdExpression(form)()
>>> print(type(exp))
<class 'pymath.expression.Expression'>
>>> RdExpression.set_form("raw")
>>> form = "{a}*{b}"
>>> exp = RdExpression(form)()
>>> print(type(exp))
<class 'str'>
"""
cls.FORM = form
@classmethod
@ -189,12 +202,13 @@ if __name__ == '__main__':
rdExp3 = RdExpression(form, cond)
desc_rdExp(rdExp3)
form = "{a + a*10}*4 + {a} + 2*{b}"
form = "{a+a*10}*4 + {a} + 2*{b}"
cond = ["{a-b} + {b} in list(range(20))", "abs({a}) not in [1]", "{b} not in [1]", "gcd({a},{b}) == 1"]
rdExp3 = RdExpression(form, cond)
desc_rdExp(rdExp3)
import doctest
doctest.testmod()

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator
from .generic import Stack, isOperator, isNumber
from pymath.operator import op
def str2tokens(exp):
""" Parse the string into tokens then turn it into postfix form
@ -51,7 +51,7 @@ def str2in_tokens(exp):
tokens.append(int(character))
elif character in "+-*/:^":
tokens.append(Operator(character))
tokens.append(character)
elif character == ")":
tokens.append(character)
@ -60,9 +60,8 @@ def str2in_tokens(exp):
# If "3(", ")("
if isNumber(tokens[-1]) \
or tokens[-1] == ")" :
#tokens.append(Operator("*"))
tokens.append(Operator("*"))
tokens.append(Operator(character))
tokens.append("*")
tokens.append(character)
elif character == ".":
raise ValueError("No float number please")
@ -80,15 +79,11 @@ def in2post_fix(infix_tokens):
@param infix_tokens: the infix list of tokens to transform into postfix form.
@return: the corresponding postfix list of tokens.
>>> a, s, m, d, p = Operator("+"), Operator("-"), Operator("*"), Operator("/"), Operator("^")
>>> s1 = Operator("-", 1)
>>> par = Operator("(")
>>> in2post_fix([par, 2, a, 5, s, 1, ')', d, par, 3, m, 4, ')'])
>>> in2post_fix([op.par, 2, op.add, 5, op.sub, 1, ')', op.div, op.par, 3, op.mul, 4, ')'])
[2, 5, '+', 1, '-', 3, 4, '*', '/']
>>> in2post_fix([s1, par, s1, 2, ')'])
>>> in2post_fix([op.sub1, op.par, op.sub1, 2, ')'])
[2, '-', '-']
>>> in2post_fix([s1, par, s1, 2, a, 3, m, 4, ')'])
>>> in2post_fix([op.sub1, op.par, op.sub1, 2, op.add, 3, op.mul, 4, ')'])
[2, '-', 3, 4, '*', '+', '-']
"""
# Stack where operator will be stocked
@ -101,13 +96,13 @@ def in2post_fix(infix_tokens):
for (pos_token,token) in enumerate(infix_tokens):
## Pour voir ce qu'il se passe dans cette procédure
# Pour voir ce qu'il se passe dans cette procédure
#print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack))
if token == ")":
op = opStack.pop()
while op != "(":
postfix_tokens.append(op)
op = opStack.pop()
next_op = opStack.pop()
while next_op != "(":
postfix_tokens.append(next_op)
next_op = opStack.pop()
# Go back to old arity
arity_Stack.pop()
@ -115,23 +110,22 @@ def in2post_fix(infix_tokens):
arity = arity_Stack.pop()
arity_Stack.push(arity + 1)
elif isOperator(token):
elif op.can_be_operator(token):
if token == "(":
opStack.push(token)
opStack.push(op.get_op(token))
# Set next arity counter
arity_Stack.push(0)
else:
while (not opStack.isEmpty()) and opStack.peek().priority >= token.priority:
op = opStack.pop()
postfix_tokens.append(op)
arity = arity_Stack.pop()
token.arity = arity + 1
opStack.push(token)
# print("--", token, " -> ", str(arity + 1))
token_op = op.get_op(token, arity + 1)
# Reset arity to 0 in case there is other operators (the real operation would be "-op.arity + 1")
arity_Stack.push(0)
while (not opStack.isEmpty()) and opStack.peek().priority >= token_op.priority:
next_op = opStack.pop()
postfix_tokens.append(next_op)
opStack.push(token_op)
#print("--", token, " -> ", str(arity + 1))
else:
postfix_tokens.append(token)
arity = arity_Stack.pop()
@ -141,8 +135,8 @@ def in2post_fix(infix_tokens):
#print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack))
while not opStack.isEmpty():
op = opStack.pop()
postfix_tokens.append(op)
next_op = opStack.pop()
postfix_tokens.append(next_op)
## Pour voir ce qu'il se passe dans cette procédure
#print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack))
@ -161,7 +155,6 @@ if __name__ == '__main__':
#
#print(in2post_fix(in_tokens))
from .operator import op
print(in2post_fix([op.par, 2, op.add, 5, op.sub, 1, ')', op.div, op.par, 3, op.mul, 4, ')']))
print(in2post_fix([op.sub1, op.par, op.sub1, 2, ')']))
print(in2post_fix([op.sub1, op.par, op.sub1, 2, op.add, 3, op.mul, 4, ')']))

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
pyparsing==2.0.3

View File

@ -121,6 +121,17 @@ class TestFraction(unittest.TestCase):
def test_le(self):
pass
def test_tex(self):
f = Fraction(2, 3)
ans = "\\frac{ 2 }{ 3 }"
self.assertEqual(f.__tex__(), ans)
def test_txt(self):
f = Fraction(2, 3)
ans = "2 / 3"
self.assertEqual(f.__txt__(), ans)
if __name__ == '__main__':
unittest.main()

View File

@ -22,15 +22,15 @@ class TestRandomExpression(unittest.TestCase):
self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a'})
def test_only_form_calc(self):
form = "{a + b} + 2"
form = "{a+b} + 2"
rdExp = RdExpression(form)
self.assertEqual(rdExp._letters, {'a', 'b'})
self.assertEqual(rdExp._2replaced, {'a + b'})
self.assertEqual(rdExp._2replaced, {'a+b'})
rdExp()
self.assertEqual(set(rdExp._gene_varia.keys()), {'a', 'b'})
self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a + b'})
self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a+b'})
def test_only_form_cond(self):
form = "{a} + 2"
@ -78,15 +78,15 @@ class TestRandomExpression(unittest.TestCase):
def test_only_form_calc_cond_calc(self):
form = "{a*3} * {b}"
cond = ["{a + b} == 3"]
cond = ["{a+b} == 3"]
rdExp = RdExpression(form, cond)
self.assertEqual(rdExp._letters, {'a', 'b'})
self.assertEqual(rdExp._2replaced, {'b', 'a*3', 'a + b'})
self.assertEqual(rdExp._2replaced, {'b', 'a*3', 'a+b'})
rdExp()
self.assertEqual(set(rdExp._gene_varia.keys()), {'a', 'b'})
self.assertEqual(set(rdExp._gene_2replaced.keys()), {'b', 'a*3', 'a + b'})
self.assertEqual(set(rdExp._gene_2replaced.keys()), {'b', 'a*3', 'a+b'})
self.assertEqual((rdExp._gene_varia['a'] + rdExp._gene_varia['b']), 3)

View File

@ -6,7 +6,7 @@ import unittest
from pymath.render import tex, txt,p2i
from pymath.fraction import Fraction
from pymath.operator import Operator
from pymath.operator import op
@ -23,29 +23,29 @@ class TestTexRender(unittest.TestCase):
self.assertEqual(tex([Fraction(1,2)]), "\\frac{ 1 }{ 2 }")
def test_mult_interger(self):
exps = [ [2, 3, Operator("*", 2)], [2, -3, Operator("*", 2)], [-2, 3, Operator("*", 2)]]
exps = [ [2, 3, op.get_op("*", 2)], [2, -3, op.get_op("*", 2)], [-2, 3, op.get_op("*", 2)]]
wanted_render = [ "2 \\times 3", "2 \\times ( -3 )", "-2 \\times 3"]
for (i,e) in enumerate(exps):
rend = tex(e)
self.assertEqual(rend, wanted_render[i])
def test_mult_letter(self):
exps = [ [2, "a", Operator("*", 2)], ["a", 3, Operator("*", 2)], [-2, "a", Operator("*", 2)], ["a", -2, Operator("*", 2)]]
exps = [ [2, "a", op.get_op("*", 2)], ["a", 3, op.get_op("*", 2)], [-2, "a", op.get_op("*", 2)], ["a", -2, op.get_op("*", 2)]]
wanted_render = [ "2 a", "a \\times 3", "-2 a", "a \\times ( -2 )"]
for (i,e) in enumerate(exps):
rend = tex(e)
self.assertEqual(rend, wanted_render[i])
def test_mult_fraction(self):
exps = [ [2, Fraction(1,2), Operator("*", 2)], [Fraction(1,2), 3, Operator("*", 2)]]
exps = [ [2, Fraction(1,2), op.get_op("*", 2)], [Fraction(1,2), 3, op.get_op("*", 2)]]
wanted_render = [ "2 \\times \\frac{ 1 }{ 2 }", "\\frac{ 1 }{ 2 } \\times 3"]
for (i,e) in enumerate(exps):
rend = tex(e)
self.assertEqual(rend, wanted_render[i])
def test_parentheses(self):
mul = Operator("*", 2)
add = Operator("+", 2)
mul = op.get_op("*", 2)
add = op.get_op("+", 2)
exps = [\
[ 2, 3, add, 4, mul],\
[ 2, 3, mul, 4, add],\
@ -81,35 +81,35 @@ class TesttxtRender(unittest.TestCase):
self.assertEqual(txt([Fraction(1,2)]), "1 / 2")
def test_mult_interger(self):
exps = [ [2, 3, Operator("*", 2)], \
[2, -3, Operator("*", 2)], \
[-2, 3, Operator("*", 2)]]
exps = [ [2, 3, op.get_op("*", 2)], \
[2, -3, op.get_op("*", 2)], \
[-2, 3, op.get_op("*", 2)]]
wanted_render = [ "2 * 3", "2 * ( -3 )", "-2 * 3"]
for (i,e) in enumerate(exps):
rend = txt(e)
self.assertEqual(rend, wanted_render[i])
def test_mult_letter(self):
exps = [ [2, "a", Operator("*", 2)], \
["a", 3, Operator("*", 2)], \
[-2, "a", Operator("*", 2)], \
["a", -2, Operator("*", 2)]]
exps = [ [2, "a", op.get_op("*", 2)], \
["a", 3, op.get_op("*", 2)], \
[-2, "a", op.get_op("*", 2)], \
["a", -2, op.get_op("*", 2)]]
wanted_render = [ "2 a", "a * 3", "-2 a", "a * ( -2 )"]
for (i,e) in enumerate(exps):
rend = txt(e)
self.assertEqual(rend, wanted_render[i])
def test_mult_fraction(self):
exps = [ [2, Fraction(1,2), Operator("*", 2)], \
[Fraction(1,2), 3, Operator("*", 2)]]
exps = [ [2, Fraction(1,2), op.get_op("*", 2)], \
[Fraction(1,2), 3, op.get_op("*", 2)]]
wanted_render = [ "2 * 1 / 2", "1 / 2 * 3"]
for (i,e) in enumerate(exps):
rend = txt(e)
self.assertEqual(rend, wanted_render[i])
def test_parentheses(self):
mul = Operator("*", 2)
add = Operator("+", 2)
mul = op.get_op("*", 2)
add = op.get_op("+", 2)
exps = [\
[ 2, 3, add, 4, mul],\
[ 2, 3, mul, 4, add],\