This repository has been archived on 2025-01-25. You can view files and clone it, but cannot push or open issues or pull requests.
labvoeding-front/mathobjects.py
2020-07-29 11:45:39 +02:00

763 lines
20 KiB
Python
Executable File

import math
__all__ = [
# value types
'Const',
'Var',
# math functions
'Add',
'Div',
'Round',
'Pow',
'Mod',
'Mul',
'Neg',
'Sub',
'Lt',
'Le',
'Eql',
'NEql',
'Ge',
'Gt',
'Sin',
'Sinh',
'Cos',
'Cosh',
'Tan',
'Tanh',
# other types
'Vec'
]
"""
bracketLevel:
0: never
1: add, sub
2: mul, div
3: always
"""
def addBrackets(f, bl):
s = str(f)
if ( (bl >= 1 and isinstance(f, (Add, Sub)))
or (bl >= 2 and isinstance(f, (Mul, Div)))
or (bl >= 3 and not isinstance(f, (Const, Var)))):
s = "(" + s + ")"
return s
# =================================================================
# == function =====================================================
# =================================================================
class Func:
def __init__(self, left, right):
if isinstance(left, (int, float)):
self.left = Const(left)
else:
self.left = left
if isinstance(right, (int, float)):
self.right = Const(right)
else:
self.right = right
def solve(self, vars):
l = self.left.solve(vars)
r = self.right.solve(vars)
val = self.fn(l, r)
print("solve(): " + str(self.copy()(l, r)) + ' = ' + str(val))
return val
# return self.fn(self.left.solve(vars), self.right.solve(vars))
def simplify(self):
left = self.left.simplify()
right = self.right.simplify()
if isinstance(left, Const) and isinstance(right, Const):
return Const(self.solve({}))
else:
return self.copy()(left, right)
def __add__(self, other): # self + other
return Add(self, other)
def __truediv__(self, other): # self / other
return Div(self, other)
#TODO: change round to floor
def __floordiv__(self, other): # self // other
return Round(Div(self, other))
def __pow__(self, other): # self ** other
return Pow(self, other)
def __mod__(self, other): # self % other
return Mod(self, other)
def __mul__(self, other): # self * other
return Mul(self, other)
def __neg__(self): # -self
return Neg(self)
def __sub__(self, other): # self - other
return Sub(self, other)
def __lt__(self, other): # self < other
return Lt(self, other)
def __le__(self, other): # self <= other
return Le(self, other)
def __eq__(self, other): # self == other
return Eql(self, other)
def __ne__(self, other): # self != other
return NEql(self, other)
def __ge__(self, other): # self >= other
return Ge(self, other)
def __gt__(self, other): # self > other
return Gt(self, other)
def __str__ (self):
s = addBrackets(self.left, self.bracketLevel)
s += ' ' + self.symbol + ' '
s += addBrackets(self.right, self.bracketLevel)
return s
# =================================================================
# == Const ========================================================
# =================================================================
class Const(Func):
def __init__(self, value):
self.value = value
def solve(self, vars):
return self.value
def copy(self):
return Const
def simplify(self): #TODO: return copy of itself
return self
def __str__(self):
return str(self.value)
# =================================================================
# == Var ==========================================================
# =================================================================
class Var(Func):
def __init__ (self, name):
self.name = name
def solve(self, vars):
return vars[self.name]
def copy(self):
return Var
def simplify(self): #TODO: return copy of itself
return self
def __str__(self):
return str(self.name)
# =================================================================
# == Add ==========================================================
# =================================================================
class Add(Func):
symbol = '+'
bracketLevel = 0
def fn(self, a, b):
return a + b
def copy(self):
return Add
# =================================================================
# == Div ==========================================================
# =================================================================
class Div(Func):
symbol = '/'
bracketLevel = 1
def fn(self, a, b):
return a / b
def copy(self):
return Div
# =================================================================
# == Round ==========================================================
# =================================================================
class Round(Func):
def __init__(self, function, p=0):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
self.p = 10**p
def solve(self, vars):
anser = self.function.solve(vars)
anser = float(int(anser*self.p + 0.5)) / self.p
return anser
def copy(self):
return Round
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({})) #TODO: make use of the solved version
else:
return Round(f)
def __str__(self):
return "round(" + str(self.function) + ")"
# =================================================================
# == Pow ==========================================================
# =================================================================
class Pow(Func):
symbol = '^'
bracketLevel = 3
def fn(self, a, b):
return a ** b
def copy(self):
return Pow
# =================================================================
# == Mod ==========================================================
# =================================================================
class Mod(Func):
symbol = '%'
bracketLevel = 3
def fn(self, a, b):
return a % b
def copy(self):
return Mod
# =================================================================
# == Mul ==========================================================
# =================================================================
class Mul(Func):
symbol = '*'
bracketLevel = 1
def fn(self, a, b):
return a * b
def copy(self):
return Mul
# =================================================================
# == Neg ==========================================================
# =================================================================
class Neg(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return -self.function.solve(vars)
def copy(self):
return Neg
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Neg(f)
def __str__(self):
return "-" + addBrackets(self.function, 3)
# =================================================================
# == Sub ==========================================================
# =================================================================
class Sub(Func):
symbol = '-'
bracketLevel = 2
def fn(self, a, b):
return a - b
def copy(self):
return Sub
def __str__ (self):
s = addBrackets(self.left, 0)
s += ' ' + self.symbol + ' '
s += addBrackets(self.right, self.bracketLevel)
return s
# =================================================================
# == Lt ==========================================================
# =================================================================
class Lt(Func):
symbol = '<'
bracketLevel = 3
def fn(self, a, b):
return a < b
def copy(self):
return Lt
# =================================================================
# == Le ==========================================================
# =================================================================
class Le(Func):
symbol = '<='
bracketLevel = 3
def fn(self, a, b):
return a <= b
def copy(self):
return Le
# =================================================================
# == Eql ==========================================================
# =================================================================
class Eql(Func):
symbol = '='
bracketLevel = 0
def fn(self, a, b):
return a == b
def copy(self):
return Eql
def simplify(self):
if ( (isinstance(self.left, self.right.copy())) # same opperation
and (not isinstance(self.left, (Const, Var, Round))) # not const, var or Round
and (self.left.right is self.right.right)): # subthing is the same
return self.copy()(self.left.left.simplify(), self.right.left.simplify())
return self.copy()(self.left.simplify(), self.right.simplify())
# =================================================================
# == NEql ==========================================================
# =================================================================
class NEql(Func):
symbol = '!='
bracketLevel = 3
def fn(self, a, b):
return a != b
def copy(self):
return NEql
# =================================================================
# == Ge ==========================================================
# =================================================================
class Ge(Func):
symbol = '>='
bracketLevel = 3
def fn(self, a, b):
return a >= b
def copy(self):
return Ge
# =================================================================
# == Gt ==========================================================
# =================================================================
class Gt(Func):
symbol = '>'
bracketLevel = 3
def fn(self, a, b):
return a > b
def copy(self):
return Gt
# =================================================================
# == Sin ==========================================================
# =================================================================
class Sin(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.sin(self.function.solve(vars))
def copy(self):
return Sin
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'sin(' + str(self.function) + ')'
# =================================================================
# == Sinh =========================================================
# =================================================================
class Sinh(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.sinh(self.function.solve(vars))
def copy(self):
return Sinh
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'sinh(' + str(self.function) + ')'
# =================================================================
# == Cos ==========================================================
# =================================================================
class Cos(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.Cos(self.function.solve(vars))
def copy(self):
return Cos
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'Cos(' + str(self.function) + ')'
# =================================================================
# == Cosh =========================================================
# =================================================================
class Cosh(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.Cosh(self.function.solve(vars))
def copy(self):
return Cosh
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'Cosh(' + str(self.function) + ')'
# =================================================================
# == Tan ==========================================================
# =================================================================
class Tan(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.tan(self.function.solve(vars))
def copy(self):
return tan
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'tan(' + str(self.function) + ')'
# =================================================================
# == Tanh =========================================================
# =================================================================
class Tanh(Func):
def __init__(self, function):
if isinstance(function, (int, float)):
self.function = Const(function)
else:
self.function = function
def solve(self, vars):
return math.tanh(self.function.solve(vars))
def copy(self):
return tanh
def simplify(self):
f = self.function.simplify()
if isinstance(f, Const):
return Const(self.solve({}))
else:
return Round(f)
def __str__ (self):
return 'tanh(' + str(self.function) + ')'
# =================================================================
# == Vec ==========================================================
# =================================================================
class Vec:
def __init__ (self, x: float, y: float, z: float) -> None:
...
def __init__ (self, x: float, y: float) -> None:
...
def __init__ (self, x: float) -> None:
...
def __init__ (self, x: "Vec") -> None:
...
def __init__ (self) -> None:
...
def __init__ (self, *args) -> None:
if len(args) == 3:
self.cartesian(*args)
elif len(args) == 2:
self.cartesian(*args, 0.0)
elif len(args) == 1:
if(isinstance(args[0], Vec)):
self.cartesian(args[0].getCartasian())
self.cartesian(*args, 0.0, 0.0)
def cartesian(self, x: float, y: float, z: float) -> tuple:
...
def cartesian(self, corts: tuple) -> tuple:
...
def cartesian(self, *args) -> tuple:
if len(args) == 3:
self.x = args[0]
self.y = args[1]
self.z = args[2]
elif len(args) == 1:
self.x = args[0][0]
self.y = args[0][1]
self.z = args[0][2]
return (self.x, self.y, self.z)
def polar(self, a: tuple, l: float) -> None:
...
def polar(self) -> tuple:
...
def polar(self, *args):
if len(args) == 2:
if not isinstance(args[0], (tuple, list)):
raise ValueError('Vec.polar(): first argument must be a tuple or list. ' + str(type(args[0])) + ' given')
if len(args[0]) < 3:
raise ValueError('Vec.polar(): first argument must be at least 3 items long')
if not isinstance(args[1], (int, float)):
raise ValueError('Vec.polar(): second argument must be a int or float. ' + str(type(args[1])) + ' given')
# xy angle xz angle yz angle
self.x = math.sin(args[0][0]) #* math.sin(args[0][1])
self.y = math.cos(args[0][0]) # * math.sin(args[0][2])
self.z = math.cos(args[0][1]) * math.cos(args[0][2])
self.mul(self, args[1])
elif len(args) == 0:
return (
(
math.atan2(self.y, self.x),
math.atan2(self.z, self.x),
0.0
),
self.length(),
)
else:
raise ValueError("Vec.polar(): Wrong number of arguments given. 2 or 0 suported")
def rotate(self, angle):
if not isinstance(angle, (tuple, list)):
raise ValueError('Vec.rotate(): first argument must be a tuple or list')
if len(angle) < 3:
raise ValueError('Vec.rotate(): first argument must be at least 3 items long')
p = self.polar()
a = [p[0][0] + angle[0], p[0][1] + angle[1], p[0][2] + angle[2]]
self.polar(a, p[1])
def length(self, l: float):
...
def length(self):
...
def length(self, *args):
if(len(args) == 0):
l = self.x**2 + self.y**2 + self.z**2
return math.sqrt(l)
else:
m = args[0] / self.length()
return self * m
def __rmul__ (self, other):
return self.mul(other, self)
def __mul__(self, other):
return self.mul(self, other)
def mul(self, a, b=None):
if not isinstance(a, Vec):
# flip a and b
b = a
a = self
if(isinstance(b, Vec)):
result = a.x * b.x
result += a.y * b.y
result += a.z * b.z
return result
elif(isinstance(b, (int, float))):
n = Vec()
n.x = a.x * b
n.y = a.y * b
n.z = a.z * b
return n
else:
print('WARNING: tried to multiply Vec with ' + str(type(b)))
return b
def __neg__(self):
return ~self
def __inv__(self):
return Vec(-self.x, -self.y, -self.z)
#TODO: alow scaler
def __pow__(self, other):
n = Vec()
n.x = self.y * other.z - self.z * other.y
n.y = self.z * other.x - self.x * other.z
n.z = self.x * other.y - self.y * other.x
return n
def __add__(self, other):
if isinstance(other, Vec):
n = Vec()
n.x = self.x + other.x
n.y = self.y + other.y
n.z = self.z + other.z
return n
elif isinstance(other, (tuple, list)):
n = Vec()
n.x = self.x + other[0]
n.y = self.y + other[1]
n.z = self.z + other[2]
return n
elif isinstance(other, (float, int)):
n = Vec(self.cartesian())
n.length(self.length() + other)
return n
else:
print('WARNING: tried to add Vec with ' + str(type(other)))
return other
def __sub__(self, other):
if isinstance(other, Vec):
n = Vec()
n.x = self.x - other.x
n.y = self.y - other.y
n.z = self.z - other.z
return n
elif isinstance(other, (tuple, list)):
n = Vec()
n.x = self.x - other[0]
n.y = self.y - other[1]
n.z = self.z - other[2]
return n
elif isinstance(other, (float, int)):
n = Vec(self.cartesian())
n.length(self.length() - other)
return n
else:
print('WARNING: tried to add Vec with ' + str(type(other)))
return other
def __setitem__(self, index, value):
if(index == 0):
self.x = value
elif(index == 1):
self.y = value
elif(index == 2):
self.z = value
else:
print('ERROR: tried to set index ' + str(index) + ' of a Vec')
def __getitem__(self, index):
if(index == 0):
return self.x
elif(index == 1):
return self.y
elif(index == 2):
return self.z
else:
raise IndexError('tried to get index ' + str(index) + ' of a Vec')
def __str__(self):
return "Vec" + str(self.cartesian())
#TODO: allow compare length of Vec with number
def __lt__(self, other):
return self.length() < other.length()
def __le__(self, other):
return self.length() <= other.length()
def __eq__(self, other):
return self.length() == other.length()
def __ne__(self, other):
return self.length() != other.length()
def __ge__(self, other):
return self.length() >= other.length()
def __gt__(self, other):
return self.length() > other.length()