Mathy

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import functools as _functools
import math as _math
import operator as _operator
_direct_operators = {'add': _operator.add, 'sub': _operator.sub, 'mul': _operator.mul,
'div': _operator.div, 'mod': _operator.mod, 'pow': _operator.pow,
'truediv': _operator.truediv, 'floordiv': _operator.floordiv,
}
_reflected_operators = {'radd': _operator.add, 'rsub': _operator.sub, 'rmul': _operator.mul,
'rdiv': _operator.div, 'rmod': _operator.mod, 'rpow': _operator.pow,
'rtruediv': _operator.truediv, 'rfloordiv': _operator.floordiv,
}
_unary_operators = {'neg': _operator.neg, 'pos': _operator.pos, 'abs': _operator.abs,
'invert': _operator.invert,
}
_repr_strings = {'add': '%s + %s', 'sub': '%s - %s', 'mul': '(%s) * %s',
'div': '%s / %s', 'mod': '%s %% %s', 'pow': '(%s) ** %s',
'truediv': '%s / %s', 'floordiv': '%s // %s',
'neg': '-%s', 'pos': '+%s', 'invert': '~%s',
}
def _generate_direct(op_func):
def generated(self, other):
return Expression(op_func, self, other)
return generated
def _generate_reflected(op_func):
def generated(self, other):
return Expression(op_func, other, self)
return generated
def _generate_unary(op_func):
def generated(self, other):
return Expression(op_func, self, None)
return generated
class _AddOperators(type):
def __new__(cls, name, bases, attrs):
new_class = type.__new__(cls, name, bases, attrs)
new_class.add_operators_to_class(_direct_operators, _generate_direct)
new_class.add_operators_to_class(_reflected_operators, _generate_reflected)
new_class.add_operators_to_class(_unary_operators, _generate_unary)
return new_class
def add_operators_to_class(cls, operators, generator):
for op_name, op_func in operators.iteritems():
op_defined = generator(op_func)
setattr(cls, '__%s__' % op_name, op_defined)
class Expression(object):
__metaclass__ = _AddOperators
def __init__(self, function, *args):
self.function = function
self.args = args
self.has_variable = any(getattr(arg, 'has_variable', False) for arg in args)
if not self.has_variable:
self.cache = self()
def calculate_arg(self, arg, kwargs):
return arg(**kwargs) if isinstance(arg, Expression) else arg
def __call__(self, **kwargs):
if hasattr(self, 'cache'):
return self.cache
args = (self.calculate_arg(arg, kwargs) for arg in self.args)
return self.function(*args)
def __repr__(self):
f_name = self.function.__name__
if f_name in _repr_strings:
args = tuple('(%s)' % arg if isinstance(arg, Expression) and \
not isinstance(arg, Variable) else arg for arg in self.args)
return _repr_strings[f_name] % args
f_module = self.function.__module__
return '%s.%s(%s)' % (f_module, f_name, ', '.join(repr(arg) for arg in self.args))
class Variable(Expression):
has_variable = True
def __init__(self, name):
self.name = name
def __call__(self, **kwargs):
if self.name in kwargs:
return kwargs[self.name]
raise ValueError('Variable `%s` is not defined in the expression.' % self.name)
def __repr__(self):
return self.name
mathycate = lambda function: _functools.partial(Expression, function)
e = _math.e
pi = _math.pi
acos = mathycate(_math.acos)
asin = mathycate(_math.asin)
atan = mathycate(_math.atan)
atan2 = mathycate(_math.atan2)
ceil = mathycate(_math.ceil)
cos = mathycate(_math.cos)
cosh = mathycate(_math.cosh)
degrees = mathycate(_math.degrees)
exp = mathycate(_math.exp)
fabs = mathycate(_math.fabs)
floor = mathycate(_math.floor)
fmod = mathycate(_math.fmod)
frexp = mathycate(_math.frexp)
hypot = mathycate(_math.hypot)
ldexp = mathycate(_math.ldexp)
log = mathycate(_math.log)
log10 = mathycate(_math.log10)
modf = mathycate(_math.modf)
pow = mathycate(_math.pow)
radians = mathycate(_math.radians)
sin = mathycate(_math.sin)
sinh = mathycate(_math.sinh)
sqrt = mathycate(_math.sqrt)
tan = mathycate(_math.tan)
tanh = mathycate(_math.tanh)