refactoring op but tests are not passed yet
This commit is contained in:
parent
fa393ef65e
commit
8ed382bbe2
@ -1,646 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
#from debug.tools import report
|
|
||||||
|
|
||||||
from .generic import flatten_list, isNumber
|
|
||||||
from functools import wraps
|
|
||||||
import types
|
|
||||||
|
|
||||||
class Operator(str):
|
|
||||||
|
|
||||||
"""The operator class, is a string (representation of the operator) with its arity"""
|
|
||||||
|
|
||||||
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
|
|
||||||
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:
|
|
||||||
#if type(args[1]) == int:
|
|
||||||
if issubclass(type(args[1]),int):
|
|
||||||
return getattr(args[0], self.actions[0])(args[1])
|
|
||||||
else:
|
|
||||||
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
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self.arity == 1:
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
ans = link.format(op1 = op1)
|
|
||||||
|
|
||||||
elif self.arity == 2:
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = self.r_parenthesis(args[1], True)
|
|
||||||
ans = link.format(op1 = op1, op2 = op2)
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def __txt__(self, *args):
|
|
||||||
"""Txt rendering for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: String with operator and his operands
|
|
||||||
|
|
||||||
>>> op.mul.__txt__('1','2')
|
|
||||||
'1 * 2'
|
|
||||||
>>> op.add.__txt__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> f = save_mainOp('2 + 3',op.add)
|
|
||||||
>>> op.mul.__txt__(f, '4')
|
|
||||||
'( 2 + 3 ) * 4'
|
|
||||||
>>> f = save_mainOp('-3',op.sub1)
|
|
||||||
>>> op.sub1.__txt__(f)
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> op.sub1.__txt__('-3')
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> f = save_mainOp('2 + 3',op.add)
|
|
||||||
>>> op.sub1.__txt__(f)
|
|
||||||
'- ( 2 + 3 )'
|
|
||||||
"""
|
|
||||||
return self._render(self.txt, *args)
|
|
||||||
|
|
||||||
def __tex__(self, *args):
|
|
||||||
"""Tex rendering for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: String with operator and his operands
|
|
||||||
|
|
||||||
>>> op.mul.__tex__('1','2')
|
|
||||||
'1 \\\\times 2'
|
|
||||||
>>> op.add.__tex__('1','2')
|
|
||||||
'1 + 2'
|
|
||||||
>>> f = save_mainOp('2 + 3',op.add)
|
|
||||||
>>> op.mul.__tex__(f, '4')
|
|
||||||
'( 2 + 3 ) \\\\times 4'
|
|
||||||
>>> f = save_mainOp('-3',op.sub1)
|
|
||||||
>>> op.sub1.__tex__(f)
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> op.sub1.__tex__('-3')
|
|
||||||
'- ( -3 )'
|
|
||||||
>>> f = save_mainOp('2 + 3',op.add)
|
|
||||||
>>> op.sub1.__tex__(f)
|
|
||||||
'- ( 2 + 3 )'
|
|
||||||
"""
|
|
||||||
return self._render(self.tex, *args)
|
|
||||||
|
|
||||||
def __p2i__(self, *args):
|
|
||||||
"""Fix list transformation for the operator
|
|
||||||
|
|
||||||
:*args: Operands for this operation
|
|
||||||
:returns: list with the operator surrounded by operands
|
|
||||||
|
|
||||||
>>> op.mul.__p2i__(1,2)
|
|
||||||
[1, '*', 2]
|
|
||||||
>>> f = save_mainOp([2, op.add, 3],op.add)
|
|
||||||
>>> op.mul.__p2i__(f, 4)
|
|
||||||
['(', 2, '+', 3, ')', '*', 4]
|
|
||||||
>>> f = save_mainOp([op.sub1, 3],op.sub1)
|
|
||||||
>>> op.sub1.__p2i__(f)
|
|
||||||
['-', '(', '-', 3, ')']
|
|
||||||
>>> op.sub1.__p2i__(-3)
|
|
||||||
['-', '(', -3, ')']
|
|
||||||
>>> f = save_mainOp([2, op.add, 3],op.add)
|
|
||||||
>>> op.sub1.__p2i__(f)
|
|
||||||
['-', '(', 2, '+', 3, ')']
|
|
||||||
"""
|
|
||||||
if self.arity == 1:
|
|
||||||
op1 = self.l_parenthesis(args[0])
|
|
||||||
ans = flatten_list([self, op1])
|
|
||||||
|
|
||||||
elif self.arity == 2:
|
|
||||||
op1 = self.l_parenthesis(args[0])
|
|
||||||
op2 = self.r_parenthesis(args[1])
|
|
||||||
ans = flatten_list([op1, self, op2])
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def l_parenthesis(self, opl, str_join=False):
|
|
||||||
""" Add parenthesis for left operand if necessary """
|
|
||||||
ans = opl
|
|
||||||
try:
|
|
||||||
# TODO: Je pige pas pourquoi quand on enlève .name ça marche plus... |lun. avril 27 19:07:24 CEST 2015
|
|
||||||
if opl.mainOp.name == op.sub1.name:
|
|
||||||
ans = opl
|
|
||||||
elif opl.mainOp.priority < self.priority:
|
|
||||||
ans = flatten_list(["(", opl, ")"])
|
|
||||||
except AttributeError as e:
|
|
||||||
# op has not the attribute priority
|
|
||||||
pass
|
|
||||||
|
|
||||||
ans = flatten_list([ans])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def r_parenthesis(self, op, str_join=False):
|
|
||||||
""" Add parenthesis for rigth operand 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
|
|
||||||
ans = flatten_list([op])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def save_mainOp(obj, mainOp):
|
|
||||||
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
|
||||||
|
|
||||||
:obj: the object to add the attribute
|
|
||||||
:mainOp: the main operator
|
|
||||||
:returns: the same object with the main operation attribute
|
|
||||||
"""
|
|
||||||
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': 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
|
|
||||||
* "l_parenthesis": mechanism to add parenthesis for left operande
|
|
||||||
* "r_parenthesis": mechanism to add parenthesis for rigth operande
|
|
||||||
"""
|
|
||||||
@wraps(fun)
|
|
||||||
def mod_fun(self, *args):
|
|
||||||
ans = fun(self, *args)
|
|
||||||
|
|
||||||
def _eq(op1, op2):
|
|
||||||
""" op1 == op2 """
|
|
||||||
return op1.name == op2.name == name and op1.arity == op2.arity
|
|
||||||
|
|
||||||
ans["__eq__"] = _eq
|
|
||||||
|
|
||||||
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",\
|
|
||||||
}
|
|
||||||
|
|
||||||
@ClassProperty
|
|
||||||
@operatorize
|
|
||||||
def add(cls):
|
|
||||||
""" The operator +
|
|
||||||
|
|
||||||
For doctest see test/test_operator.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
"""
|
|
||||||
if args[1][0] == "-":
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = self.r_parenthesis(args[1][1:], True)
|
|
||||||
ans = link.replace('+','-').format(op1 = op1, op2 = op2)
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
else:
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = self.r_parenthesis(args[1], True)
|
|
||||||
ans = link.format(op1 = op1, op2 = op2)
|
|
||||||
|
|
||||||
ans = save_mainOp(ans, self)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
caract = {
|
|
||||||
"operator" : "+", \
|
|
||||||
"name" : "add",\
|
|
||||||
"priority" : 1, \
|
|
||||||
"arity" : 2, \
|
|
||||||
"actions" : ("__add__","__radd__"), \
|
|
||||||
"txt" : "{op1} + {op2}",\
|
|
||||||
"tex" : "{op1} + {op2}",\
|
|
||||||
"_render": _render,\
|
|
||||||
}
|
|
||||||
|
|
||||||
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)'
|
|
||||||
>>> sub.__tex__('-1','2')
|
|
||||||
'-1 - 2'
|
|
||||||
"""
|
|
||||||
def l_parenthesis(self, op, str_join=False):
|
|
||||||
return op
|
|
||||||
|
|
||||||
def r_parenthesis(self, op, str_join=False):
|
|
||||||
try:
|
|
||||||
if op.mainOp.priority <= self.priority:
|
|
||||||
op = flatten_list(["(", op, ")"])
|
|
||||||
elif op[0] == '-':
|
|
||||||
op = flatten_list(["(", op, ")"])
|
|
||||||
except AttributeError:
|
|
||||||
# op has not the attribute priority
|
|
||||||
try:
|
|
||||||
if int(op) < 0:
|
|
||||||
op = ['(', op, ')']
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
ans = flatten_list([op])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
caract = {
|
|
||||||
"operator" : "-", \
|
|
||||||
"name" : "sub",\
|
|
||||||
"priority" : 2, \
|
|
||||||
"arity" : 2, \
|
|
||||||
"actions" : ("__sub__","__rsub__"), \
|
|
||||||
"txt" : "{op1} - {op2}",\
|
|
||||||
"tex" : "{op1} - {op2}",\
|
|
||||||
"l_parenthesis": l_parenthesis,\
|
|
||||||
"r_parenthesis": r_parenthesis,\
|
|
||||||
}
|
|
||||||
|
|
||||||
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 l_parenthesis(self, op, str_join=False):
|
|
||||||
""" 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
|
|
||||||
|
|
||||||
ans = flatten_list([op])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
caract = {
|
|
||||||
"operator" : "-", \
|
|
||||||
"name" : "sub1",\
|
|
||||||
"priority" : 3, \
|
|
||||||
"arity" : 1, \
|
|
||||||
"actions" : "__neg__",\
|
|
||||||
"txt" : "- {op1}",\
|
|
||||||
"tex" : "- {op1}",\
|
|
||||||
"l_parenthesis": l_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.__tex__('2','a')
|
|
||||||
'2 a'
|
|
||||||
>>> mul.__txt__('1','2')
|
|
||||||
'1 * 2'
|
|
||||||
>>> mul.__txt__('2','a')
|
|
||||||
'2 a'
|
|
||||||
>>> mul.__txt__('a','2')
|
|
||||||
'a * 2'
|
|
||||||
>>> mul.__tex__('1','-2')
|
|
||||||
'1 \\times (-2)'
|
|
||||||
"""
|
|
||||||
# * can not be display in some cases
|
|
||||||
def is_visible(self, op1, op2):
|
|
||||||
""" Tells whether self has to be visible or not
|
|
||||||
|
|
||||||
:param op1: left operande
|
|
||||||
:param op2: rigth operande
|
|
||||||
|
|
||||||
"""
|
|
||||||
# TODO: À finir!!! |lun. mars 9 00:03:40 CET 2015
|
|
||||||
if type(op2) == int:
|
|
||||||
# op2 est maintenant une chaine de caractères
|
|
||||||
return True
|
|
||||||
elif op2.isdecimal():
|
|
||||||
return True
|
|
||||||
elif op2.isalpha():
|
|
||||||
return False
|
|
||||||
elif op2[0].isdecimal():
|
|
||||||
return True
|
|
||||||
elif op2[0] == "(" and not ("+" in op2 or "-" in op2[3:]):
|
|
||||||
return True
|
|
||||||
# Giga bricolage...
|
|
||||||
elif "frac" in op2:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _render(self, link, *args):
|
|
||||||
|
|
||||||
op1 = self.l_parenthesis(args[0], True)
|
|
||||||
op2 = self.r_parenthesis(args[1], True)
|
|
||||||
|
|
||||||
if not self.is_visible(op1, op2):
|
|
||||||
ans = "{op1} {op2}".format(op1 = op1, op2 = op2)
|
|
||||||
else:
|
|
||||||
ans = link.format(op1 = op1, op2 = op2)
|
|
||||||
|
|
||||||
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,\
|
|
||||||
"is_visible": is_visible,\
|
|
||||||
}
|
|
||||||
|
|
||||||
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" : 5, \
|
|
||||||
"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)
|
|
||||||
|
|
||||||
def l_parenthesis(self, opl, str_join=False):
|
|
||||||
""" Add parenthesis for left operand if necessary """
|
|
||||||
ans = opl
|
|
||||||
try:
|
|
||||||
if opl.mainOp.priority < self.priority:
|
|
||||||
ans = flatten_list(["(", opl, ")"])
|
|
||||||
except AttributeError as e:
|
|
||||||
# op has not the attribute priority
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if int(opl) < 0:
|
|
||||||
ans = ["(", opl, ")"]
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
ans = flatten_list([ans])
|
|
||||||
if str_join:
|
|
||||||
ans = ' '.join([str(i) for i in ans])
|
|
||||||
return ans
|
|
||||||
|
|
||||||
caract = {
|
|
||||||
"operator" : "^", \
|
|
||||||
"name" : "pw",\
|
|
||||||
"priority" : 6, \
|
|
||||||
"arity" : 2, \
|
|
||||||
"actions" : ("__pow__",""), \
|
|
||||||
"txt" : "{op1} ^ {op2}",\
|
|
||||||
"tex" : "{op1}^{{ {op2} }}",\
|
|
||||||
"l_parenthesis": l_parenthesis,\
|
|
||||||
"_call":_call,\
|
|
||||||
}
|
|
||||||
|
|
||||||
return caract
|
|
||||||
|
|
||||||
@ClassProperty
|
|
||||||
@operatorize
|
|
||||||
def par(self):
|
|
||||||
""" The operator ( """
|
|
||||||
caract = {
|
|
||||||
"operator" : "(", \
|
|
||||||
"name" : "par",\
|
|
||||||
"priority" : 0, \
|
|
||||||
"arity" : 0, \
|
|
||||||
}
|
|
||||||
return caract
|
|
||||||
|
|
||||||
@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 """
|
|
||||||
if type(symbole) == str:
|
|
||||||
return symbole in [i[0] for i in cls._operators]
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
#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(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')))
|
|
||||||
|
|
||||||
print("op.sub.__dict__ -> ", op.sub.__dict__)
|
|
||||||
print(op.sub == op.sub1)
|
|
||||||
#import doctest
|
|
||||||
#doctest.testmod()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Reglages pour 'vim'
|
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
||||||
# cursor: 16 del
|
|
12
pymath/calculus/operator/__init__.py
Normal file
12
pymath/calculus/operator/__init__.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator_set import op
|
||||||
|
from .operator import save_mainOp
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
50
pymath/calculus/operator/add.py
Normal file
50
pymath/calculus/operator/add.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
from .operator import Operator, save_mainOp
|
||||||
|
|
||||||
|
class Add(Operator):
|
||||||
|
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "+", \
|
||||||
|
"name" : "add",\
|
||||||
|
"priority" : 1, \
|
||||||
|
"arity" : 2, \
|
||||||
|
"actions" : ("__add__","__radd__"), \
|
||||||
|
"txt" : "{op1} + {op2}",\
|
||||||
|
"tex" : "{op1} + {op2}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Add Operator """
|
||||||
|
super(Add, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
"""
|
||||||
|
if args[1][0] == "-":
|
||||||
|
op1 = self.l_parenthesis(args[0], True)
|
||||||
|
op2 = self.r_parenthesis(args[1][1:], True)
|
||||||
|
ans = link.replace('+','-').format(op1 = op1, op2 = op2)
|
||||||
|
|
||||||
|
ans = save_mainOp(ans, self)
|
||||||
|
return ans
|
||||||
|
else:
|
||||||
|
op1 = self.l_parenthesis(args[0], True)
|
||||||
|
op2 = self.r_parenthesis(args[1], True)
|
||||||
|
ans = link.format(op1 = op1, op2 = op2)
|
||||||
|
|
||||||
|
ans = save_mainOp(ans, self)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
54
pymath/calculus/operator/div.py
Normal file
54
pymath/calculus/operator/div.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
from .operator import Operator, save_mainOp
|
||||||
|
|
||||||
|
class Div(Operator):
|
||||||
|
|
||||||
|
""" 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'
|
||||||
|
"""
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "/", \
|
||||||
|
"name" : "div",\
|
||||||
|
"priority" : 5, \
|
||||||
|
"arity" : 2, \
|
||||||
|
"txt" : "{op1} / {op2}",\
|
||||||
|
"tex" : "\\frac{{ {op1} }}{{ {op2} }}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Div Operator """
|
||||||
|
super(Div, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
def __call__(self, op1, op2):
|
||||||
|
if op2 == 1:
|
||||||
|
return op1
|
||||||
|
else:
|
||||||
|
from ..fraction import Fraction
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
92
pymath/calculus/operator/mul.py
Normal file
92
pymath/calculus/operator/mul.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator import Operator, save_mainOp
|
||||||
|
|
||||||
|
class Mul(Operator):
|
||||||
|
|
||||||
|
""" The operator *
|
||||||
|
|
||||||
|
>>> mul = op.mul
|
||||||
|
>>> mul
|
||||||
|
'*'
|
||||||
|
>>> mul(1, 2)
|
||||||
|
2
|
||||||
|
>>> mul.__tex__('1','2')
|
||||||
|
'1 \\times 2'
|
||||||
|
>>> mul.__tex__('2','a')
|
||||||
|
'2 a'
|
||||||
|
>>> mul.__txt__('1','2')
|
||||||
|
'1 * 2'
|
||||||
|
>>> mul.__txt__('2','a')
|
||||||
|
'2 a'
|
||||||
|
>>> mul.__txt__('a','2')
|
||||||
|
'a * 2'
|
||||||
|
>>> mul.__tex__('1','-2')
|
||||||
|
'1 \\times (-2)'
|
||||||
|
"""
|
||||||
|
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "*", \
|
||||||
|
"name" : "mul",\
|
||||||
|
"priority" : 4, \
|
||||||
|
"arity" : 2, \
|
||||||
|
"actions" : ("__mul__","__rmul__"), \
|
||||||
|
"txt" : "{op1} * {op2}",\
|
||||||
|
"tex" : "{op1} \\times {op2}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Mul Operator """
|
||||||
|
super(Mul, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
# TODO: Add self.visibility |sam. nov. 8 17:00:08 CET 2014
|
||||||
|
self.visibility = 1
|
||||||
|
|
||||||
|
def is_visible(self, op1, op2):
|
||||||
|
""" Tells whether self has to be visible or not
|
||||||
|
|
||||||
|
:param op1: left operande
|
||||||
|
:param op2: rigth operande
|
||||||
|
|
||||||
|
"""
|
||||||
|
# TODO: À finir!!! |lun. mars 9 00:03:40 CET 2015
|
||||||
|
if type(op2) == int:
|
||||||
|
# op2 est maintenant une chaine de caractères
|
||||||
|
return True
|
||||||
|
elif op2.isdecimal():
|
||||||
|
return True
|
||||||
|
elif op2.isalpha():
|
||||||
|
return False
|
||||||
|
elif op2[0].isdecimal():
|
||||||
|
return True
|
||||||
|
elif op2[0] == "(" and not ("+" in op2 or "-" in op2[3:]):
|
||||||
|
return True
|
||||||
|
# Giga bricolage...
|
||||||
|
elif "frac" in op2:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _render(self, link, *args):
|
||||||
|
|
||||||
|
op1 = self.l_parenthesis(args[0], True)
|
||||||
|
op2 = self.r_parenthesis(args[1], True)
|
||||||
|
|
||||||
|
if not self.is_visible(op1, op2):
|
||||||
|
ans = "{op1} {op2}".format(op1 = op1, op2 = op2)
|
||||||
|
else:
|
||||||
|
ans = link.format(op1 = op1, op2 = op2)
|
||||||
|
|
||||||
|
ans = save_mainOp(ans, self)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
236
pymath/calculus/operator/operator.py
Normal file
236
pymath/calculus/operator/operator.py
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
#from debug.tools import report
|
||||||
|
|
||||||
|
from ..generic import flatten_list, isNumber
|
||||||
|
from functools import wraps
|
||||||
|
import types
|
||||||
|
|
||||||
|
class Operator():
|
||||||
|
|
||||||
|
"""The operator class, is a string (representation of the operator) with its arity"""
|
||||||
|
|
||||||
|
def __init__(self, operator = "", name = "", priority = 0, actions = ("",""), txt = "", tex = "", arity = 2, **kwrds):
|
||||||
|
""" Create an Operator """
|
||||||
|
self.operator = operator
|
||||||
|
self.name = name
|
||||||
|
self.arity = arity
|
||||||
|
self.priority = priority
|
||||||
|
self.actions = actions
|
||||||
|
self.txt = txt
|
||||||
|
self.tex = tex
|
||||||
|
|
||||||
|
self.isOperator = 1
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
""" Calling this operator performs the rigth calculus """
|
||||||
|
if self.arity == 1:
|
||||||
|
return getattr(args[0], self.actions)()
|
||||||
|
|
||||||
|
elif self.arity == 2:
|
||||||
|
#if type(args[1]) == int:
|
||||||
|
if issubclass(type(args[1]),int):
|
||||||
|
return getattr(args[0], self.actions[0])(args[1])
|
||||||
|
else:
|
||||||
|
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
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.arity == 1:
|
||||||
|
op1 = self.l_parenthesis(args[0], True)
|
||||||
|
ans = link.format(op1 = op1)
|
||||||
|
|
||||||
|
elif self.arity == 2:
|
||||||
|
op1 = self.l_parenthesis(args[0], True)
|
||||||
|
op2 = self.r_parenthesis(args[1], True)
|
||||||
|
ans = link.format(op1 = op1, op2 = op2)
|
||||||
|
|
||||||
|
ans = save_mainOp(ans, self)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.operator
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.operator)
|
||||||
|
|
||||||
|
def __txt__(self, *args):
|
||||||
|
"""Txt rendering for the operator
|
||||||
|
|
||||||
|
:*args: Operands for this operation
|
||||||
|
:returns: String with operator and his operands
|
||||||
|
|
||||||
|
>>> op.mul.__txt__('1','2')
|
||||||
|
'1 * 2'
|
||||||
|
>>> op.add.__txt__('1','2')
|
||||||
|
'1 + 2'
|
||||||
|
>>> f = save_mainOp('2 + 3',op.add)
|
||||||
|
>>> op.mul.__txt__(f, '4')
|
||||||
|
'( 2 + 3 ) * 4'
|
||||||
|
>>> f = save_mainOp('-3',op.sub1)
|
||||||
|
>>> op.sub1.__txt__(f)
|
||||||
|
'- ( -3 )'
|
||||||
|
>>> op.sub1.__txt__('-3')
|
||||||
|
'- ( -3 )'
|
||||||
|
>>> f = save_mainOp('2 + 3',op.add)
|
||||||
|
>>> op.sub1.__txt__(f)
|
||||||
|
'- ( 2 + 3 )'
|
||||||
|
"""
|
||||||
|
return self._render(self.txt, *args)
|
||||||
|
|
||||||
|
def __tex__(self, *args):
|
||||||
|
"""Tex rendering for the operator
|
||||||
|
|
||||||
|
:*args: Operands for this operation
|
||||||
|
:returns: String with operator and his operands
|
||||||
|
|
||||||
|
>>> op.mul.__tex__('1','2')
|
||||||
|
'1 \\\\times 2'
|
||||||
|
>>> op.add.__tex__('1','2')
|
||||||
|
'1 + 2'
|
||||||
|
>>> f = save_mainOp('2 + 3',op.add)
|
||||||
|
>>> op.mul.__tex__(f, '4')
|
||||||
|
'( 2 + 3 ) \\\\times 4'
|
||||||
|
>>> f = save_mainOp('-3',op.sub1)
|
||||||
|
>>> op.sub1.__tex__(f)
|
||||||
|
'- ( -3 )'
|
||||||
|
>>> op.sub1.__tex__('-3')
|
||||||
|
'- ( -3 )'
|
||||||
|
>>> f = save_mainOp('2 + 3',op.add)
|
||||||
|
>>> op.sub1.__tex__(f)
|
||||||
|
'- ( 2 + 3 )'
|
||||||
|
"""
|
||||||
|
return self._render(self.tex, *args)
|
||||||
|
|
||||||
|
def __p2i__(self, *args):
|
||||||
|
"""Fix list transformation for the operator
|
||||||
|
|
||||||
|
:*args: Operands for this operation
|
||||||
|
:returns: list with the operator surrounded by operands
|
||||||
|
|
||||||
|
>>> op.mul.__p2i__(1,2)
|
||||||
|
[1, '*', 2]
|
||||||
|
>>> f = save_mainOp([2, op.add, 3],op.add)
|
||||||
|
>>> op.mul.__p2i__(f, 4)
|
||||||
|
['(', 2, '+', 3, ')', '*', 4]
|
||||||
|
>>> f = save_mainOp([op.sub1, 3],op.sub1)
|
||||||
|
>>> op.sub1.__p2i__(f)
|
||||||
|
['-', '(', '-', 3, ')']
|
||||||
|
>>> op.sub1.__p2i__(-3)
|
||||||
|
['-', '(', -3, ')']
|
||||||
|
>>> f = save_mainOp([2, op.add, 3],op.add)
|
||||||
|
>>> op.sub1.__p2i__(f)
|
||||||
|
['-', '(', 2, '+', 3, ')']
|
||||||
|
"""
|
||||||
|
if self.arity == 1:
|
||||||
|
op1 = self.l_parenthesis(args[0])
|
||||||
|
ans = flatten_list([self, op1])
|
||||||
|
|
||||||
|
elif self.arity == 2:
|
||||||
|
op1 = self.l_parenthesis(args[0])
|
||||||
|
op2 = self.r_parenthesis(args[1])
|
||||||
|
ans = flatten_list([op1, self, op2])
|
||||||
|
|
||||||
|
ans = save_mainOp(ans, self)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def l_parenthesis(self, opl, str_join=False):
|
||||||
|
""" Add parenthesis for left operand if necessary """
|
||||||
|
ans = opl
|
||||||
|
try:
|
||||||
|
# TODO: Je pige pas pourquoi quand on enlève .name ça marche plus... |lun. avril 27 19:07:24 CEST 2015
|
||||||
|
if opl.mainOp.name == "sub1":
|
||||||
|
ans = opl
|
||||||
|
elif opl.mainOp.priority < self.priority:
|
||||||
|
ans = flatten_list(["(", opl, ")"])
|
||||||
|
except AttributeError as e:
|
||||||
|
# op has not the attribute priority
|
||||||
|
pass
|
||||||
|
|
||||||
|
ans = flatten_list([ans])
|
||||||
|
if str_join:
|
||||||
|
ans = ' '.join([str(i) for i in ans])
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def r_parenthesis(self, op, str_join=False):
|
||||||
|
""" Add parenthesis for rigth operand 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
|
||||||
|
ans = flatten_list([op])
|
||||||
|
if str_join:
|
||||||
|
ans = ' '.join([str(i) for i in ans])
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def uniq_desc(self):
|
||||||
|
""" Return the uniq description of the operator
|
||||||
|
:returns: (self.name, self.arity)
|
||||||
|
|
||||||
|
"""
|
||||||
|
return (self.operator, self.arity)
|
||||||
|
|
||||||
|
def __eq__(self, op2):
|
||||||
|
""" op1 == op2 """
|
||||||
|
return self.name == op2.name and self.arity == op2.arity
|
||||||
|
|
||||||
|
def save_mainOp(obj, mainOp):
|
||||||
|
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
||||||
|
|
||||||
|
:obj: the object to add the attribute
|
||||||
|
:mainOp: the main operator
|
||||||
|
:returns: the same object with the main operation attribute
|
||||||
|
"""
|
||||||
|
# TODO: À mettre avec render? |mar. févr. 23 09:45:22 EAT 2016
|
||||||
|
# TODO: On pourrait mettre un try avant de créer une nouvelle classe |mar. févr. 23 09:44:45 EAT 2016
|
||||||
|
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': mainOp})
|
||||||
|
|
||||||
|
return Fake(obj)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
#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(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')))
|
||||||
|
|
||||||
|
print("op.sub.__dict__ -> ", op.sub.__dict__)
|
||||||
|
print(op.sub == op.sub1)
|
||||||
|
#import doctest
|
||||||
|
#doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
81
pymath/calculus/operator/operator_set.py
Normal file
81
pymath/calculus/operator/operator_set.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
import types
|
||||||
|
from .add import Add
|
||||||
|
from .div import Div
|
||||||
|
from .mul import Mul
|
||||||
|
from .par import Par
|
||||||
|
from .pw import Pw
|
||||||
|
from .sub import Sub
|
||||||
|
from .sub1 import Sub1
|
||||||
|
|
||||||
|
|
||||||
|
class Operator_set(object):
|
||||||
|
""" Class for sets of operators"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate the operator_set """
|
||||||
|
self._operators = {}
|
||||||
|
|
||||||
|
def get_op(self, op, arity = 2):
|
||||||
|
"""Return the corresponding operator
|
||||||
|
|
||||||
|
:op: symbole of the op
|
||||||
|
:arity: the arity
|
||||||
|
|
||||||
|
>>> op = Operator_set()
|
||||||
|
>>> op.get_op('+')
|
||||||
|
'+'
|
||||||
|
>>> mul = op.get_op('*')
|
||||||
|
>>> mul.tex
|
||||||
|
'{op1} \\\\times {op2}'
|
||||||
|
>>> mul.txt
|
||||||
|
'{op1} * {op2}'
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return getattr(self, self._operators[(op, arity)])
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError("{theOp} (arity: {arity}) is not available".format(theOp = op, arity = arity))
|
||||||
|
|
||||||
|
def can_be_operator(cls, symbole):
|
||||||
|
""" Tell if the symbole can be an operator """
|
||||||
|
if type(symbole) == str:
|
||||||
|
return symbole in [i[0] for i in cls._operators]
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def store_operator(self, operator):
|
||||||
|
""" Save the operator as a method and
|
||||||
|
|
||||||
|
:param operator: the operator (the class) (it will be accessible through .name method name.
|
||||||
|
"""
|
||||||
|
# TODO: faire une vérif si on peut utiliser operator_name |mar. févr. 23 09:09:44 EAT 2016
|
||||||
|
self._operators[operator.uniq_desc()] = operator.name
|
||||||
|
setattr(self, operator.name, operator)
|
||||||
|
|
||||||
|
|
||||||
|
op = Operator_set()
|
||||||
|
op.store_operator(Add())
|
||||||
|
op.store_operator(Div())
|
||||||
|
op.store_operator(Mul())
|
||||||
|
op.store_operator(Par())
|
||||||
|
op.store_operator(Pw())
|
||||||
|
op.store_operator(Sub())
|
||||||
|
op.store_operator(Sub1())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
28
pymath/calculus/operator/par.py
Normal file
28
pymath/calculus/operator/par.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator import Operator
|
||||||
|
|
||||||
|
class Par(Operator):
|
||||||
|
|
||||||
|
""" The operator ( """
|
||||||
|
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "(", \
|
||||||
|
"name" : "par",\
|
||||||
|
"priority" : 0, \
|
||||||
|
"arity" : 0, \
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Par Operator """
|
||||||
|
super(Par, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
67
pymath/calculus/operator/pw.py
Normal file
67
pymath/calculus/operator/pw.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator import Operator
|
||||||
|
from ..generic import flatten_list
|
||||||
|
|
||||||
|
class Pw(Operator):
|
||||||
|
|
||||||
|
""" 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'
|
||||||
|
"""
|
||||||
|
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "^", \
|
||||||
|
"name" : "pw",\
|
||||||
|
"priority" : 6, \
|
||||||
|
"arity" : 2, \
|
||||||
|
"actions" : ("__pow__",""), \
|
||||||
|
"txt" : "{op1} ^ {op2}",\
|
||||||
|
"tex" : "{op1}^{{ {op2} }}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Pw Operator """
|
||||||
|
super(Pw, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
def __call__(self, op1, op2):
|
||||||
|
""" Calling this operator performs the rigth calculus """
|
||||||
|
return getattr(op1, "__pow__")(op2)
|
||||||
|
|
||||||
|
def l_parenthesis(self, opl, str_join=False):
|
||||||
|
""" Add parenthesis for left operand if necessary """
|
||||||
|
ans = opl
|
||||||
|
try:
|
||||||
|
if opl.mainOp.priority < self.priority:
|
||||||
|
ans = flatten_list(["(", opl, ")"])
|
||||||
|
except AttributeError as e:
|
||||||
|
# op has not the attribute priority
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
if int(opl) < 0:
|
||||||
|
ans = ["(", opl, ")"]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
ans = flatten_list([ans])
|
||||||
|
if str_join:
|
||||||
|
ans = ' '.join([str(i) for i in ans])
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
70
pymath/calculus/operator/sub.py
Normal file
70
pymath/calculus/operator/sub.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator import Operator
|
||||||
|
from ..generic import flatten_list
|
||||||
|
|
||||||
|
class Sub(Operator):
|
||||||
|
|
||||||
|
""" 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)'
|
||||||
|
>>> sub.__tex__('-1','2')
|
||||||
|
'-1 - 2'
|
||||||
|
"""
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "-", \
|
||||||
|
"name" : "sub",\
|
||||||
|
"priority" : 2, \
|
||||||
|
"arity" : 2, \
|
||||||
|
"actions" : ("__sub__","__rsub__"), \
|
||||||
|
"txt" : "{op1} - {op2}",\
|
||||||
|
"tex" : "{op1} - {op2}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Sub Operator """
|
||||||
|
super(Sub, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
def l_parenthesis(self, op, str_join=False):
|
||||||
|
return op
|
||||||
|
|
||||||
|
def r_parenthesis(self, op, str_join=False):
|
||||||
|
try:
|
||||||
|
if op.mainOp.priority <= self.priority:
|
||||||
|
op = flatten_list(["(", op, ")"])
|
||||||
|
elif op[0] == '-':
|
||||||
|
op = flatten_list(["(", op, ")"])
|
||||||
|
except AttributeError:
|
||||||
|
# op has not the attribute priority
|
||||||
|
try:
|
||||||
|
if int(op) < 0:
|
||||||
|
op = ['(', op, ')']
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
ans = flatten_list([op])
|
||||||
|
if str_join:
|
||||||
|
ans = ' '.join([str(i) for i in ans])
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
61
pymath/calculus/operator/sub1.py
Normal file
61
pymath/calculus/operator/sub1.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from .operator import Operator
|
||||||
|
from ..generic import flatten_list
|
||||||
|
|
||||||
|
class Sub1(Operator):
|
||||||
|
|
||||||
|
""" The operator -
|
||||||
|
|
||||||
|
>>> sub1 = op.sub1
|
||||||
|
>>> sub1
|
||||||
|
'-'
|
||||||
|
>>> sub1(1)
|
||||||
|
-1
|
||||||
|
>>> sub1.__tex__('1')
|
||||||
|
'- 1'
|
||||||
|
>>> sub1.__txt__('1')
|
||||||
|
'- 1'
|
||||||
|
>>> sub1.__tex__('-1')
|
||||||
|
'- (-1)'
|
||||||
|
"""
|
||||||
|
|
||||||
|
_CARACT = {
|
||||||
|
"operator" : "-", \
|
||||||
|
"name" : "sub1",\
|
||||||
|
"priority" : 3, \
|
||||||
|
"arity" : 1, \
|
||||||
|
"actions" : "__neg__",\
|
||||||
|
"txt" : "- {op1}",\
|
||||||
|
"tex" : "- {op1}",\
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Initiate Sub1 Operator """
|
||||||
|
super(Sub1, self).__init__(**self._CARACT)
|
||||||
|
|
||||||
|
def l_parenthesis(self, op, str_join=False):
|
||||||
|
""" 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
|
||||||
|
|
||||||
|
ans = flatten_list([op])
|
||||||
|
if str_join:
|
||||||
|
ans = ' '.join([str(i) for i in ans])
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
21
pymath/calculus/operator/test/test_add.py
Normal file
21
pymath/calculus/operator/test/test_add.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from pymath.calculus.operator.add import Add
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_render_tex():
|
||||||
|
assert Add().__tex__('1', '2') == '1 + 2'
|
||||||
|
assert Add().__tex__('1', '-2') == '1 - 2'
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_render_txt():
|
||||||
|
assert Add().__txt__('1', '2') == '1 + 2'
|
||||||
|
assert Add().__txt__('1', '-2') == '1 - 2'
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
Loading…
Reference in New Issue
Block a user