def mod(self, a, b): if isinstance(a, float): if isinstance(b, float): if not (a.is_integer() and b.is_integer()): raise ComputorException('Illegal operation: ' + str(a) + ' % ' + str(b)) return a % b elif isinstance(b, Complex): raise ComputorException('Illegal operation: Rational % Complex') elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Rational % Matrix') elif isinstance(a, Complex): if isinstance(b, float): raise ComputorException('Illegal operation: Complex % Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Complex % Complex') elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex % Matrix') elif isinstance(a, Matrix): if isinstance(b, float): raise ComputorException('Illegal operation: Matrix % Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix % Complex') elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Matrix % Matrix') raise ComputorException('Computor.mul(): something bad happened 🤷')
def deg(self, radians): if isinstance(radians, float): return radians * 180 / Computor.pi elif isinstance(radians, Complex): raise ComputorException('Illegal operation: deg(Complex)') elif isinstance(radians, Matrix): raise ComputorException('Illegal operation: deg(Matrix)') raise ComputorException('Computor.deg(): something bad happened 🤷')
def tan(self, radians): if isinstance(radians, float): return tan(radians) elif isinstance(radians, Complex): raise ComputorException('Illegal operation: tan(Complex)') elif isinstance(radians, Matrix): raise ComputorException('Illegal operation: tan(Matrix)') raise ComputorException('Computor.tan(): something bad happened 🤷')
def transp(self, a): if isinstance(a, float): raise ComputorException('Illegal operation: transp(Rational)') elif isinstance(a, Complex): raise ComputorException('Illegal operation: transp(Complex)') elif isinstance(a, Matrix): return a.get_transpose() raise ComputorException('Computor.inv(): something bad happened 🤷')
def rad(self, degrees): if isinstance(degrees, float): return degrees * Computor.pi / 180 elif isinstance(degrees, Complex): raise ComputorException('Illegal operation: rad(Complex)') elif isinstance(degrees, Matrix): raise ComputorException('Illegal operation: rad(Matrix)') raise ComputorException('Computor.rad(): something bad happened 🤷')
def sqrt(self, a): if isinstance(a, float): if a >= 0: return a ** 0.5 else: return Complex(0, (-a) ** 0.5) elif isinstance(a, Complex): raise ComputorException('Illegal operation: sqrt(Complex)') elif isinstance(a, Matrix): raise ComputorException('Illegal operation: sqrt(Matrix)') raise ComputorException('Computor.sqrt(): something bad happened 🤷')
def pow(self, base, power): if not (isinstance(power, float) and power.is_integer() and int(power) >= 0): raise ComputorException('Exponent ' + Fore.RED + str(power) + Fore.RESET + ' must be a non-negative integer') power = int(power) if isinstance(base, float): return base ** power elif isinstance(base, Complex): return Complex.pow(base, power) elif isinstance(base, Matrix): return Matrix.pow(base, power) raise ComputorException('Computor.pow(): something bad happened 🤷')
def pow(base, power): if base.shape[0] != base.shape[1]: raise ComputorException('Invalid Matrix shape: M' + str(base.shape) + ' ^ ' + str(power)) product = Matrix.__identity(base.shape[0]) for _ in range(power): product = Matrix.mat_mul(product, base) return product
def add(a, b): if a.shape != b.shape: raise ComputorException('Invalid Matrix shapes: M' + str(a.shape) + ' + M' + str(b.shape)) data = [] for i in range(a.shape[0]): data.append(list(map(lambda x, y: x + y, a.data[i], b.data[i]))) return Matrix(data)
def inv(self, a): if isinstance(a, float): return self.div(1.0, a) elif isinstance(a, Complex): return self.div(1.0, a) elif isinstance(a, Matrix): return a.get_inverse() raise ComputorException('Computor.inv(): something bad happened 🤷')
def neg(self, a): if isinstance(a, float): return -a elif isinstance(a, Complex): return Complex.neg(a) elif isinstance(a, Matrix): return Matrix.neg(a) raise ComputorException('Computor.neg(): something bad happened 🤷')
def __init__(self, data): rows = len(data) cols = len(data[0]) self.shape = (rows, cols) self.data = data for row in self.data: if len(row) != cols: raise ComputorException('Invalid matrix shape')
def validate_func(self, func_name, num_args): func_name_lc = func_name.lower() # check name matches if func_name_lc in self.__funcs: function = self.__funcs[func_name_lc] # check number of args match if len(function.local_vars) == num_args: return raise ComputorException('No such function: ' + Fore.BLUE + func_name + Fore.RESET)
def div(a, b): if b.__is_zero(): raise ComputorException('Division by zero') conjugate = b.__get_conjugate() numerator = Complex.mul(a, conjugate) denominator = Complex.mul(b, conjugate) assert denominator.imag == 0.0 return Complex(numerator.real / denominator.real, numerator.imag / denominator.real)
def mat_mul(a, b): if a.shape[1] != b.shape[0]: raise ComputorException('Invalid Matrix shapes: M' + str(a.shape) + ' ** M' + str(b.shape)) data = [] for i in range(a.shape[0]): data.append( [None] * b.shape[1] ) for j in range(b.shape[1]): data[i][j] = sum([ a.data[i][k] * b.data[k][j] for k in range(a.shape[1]) ]) return Matrix(data)
def get_var(self, var_name): var_name_lc = var_name.lower() # Search in stack of local variables for local_var in reversed(self.__local_vars): if local_var[0].lower() == var_name_lc: return local_var[1] # Search in dictionary of global variables if var_name_lc in self.__vars: return self.__vars[var_name_lc].value raise ComputorException('Variable \'' + Fore.BLUE + var_name + Fore.RESET + '\' is not defined')
def show_func(self, func_name, args): func_name = func_name.lower() # check if func_name matches if func_name in self.__funcs: function = self.__funcs[func_name] # check if args match if len(function.local_vars) == len(args) and \ all([ x.lower() == y.lower() for x, y in zip(function.local_vars, args) ]): print(function) return raise ComputorException('No such function: ' + Fore.BLUE + func_name + '(' + ', '.join(args) + ')' + Fore.RESET)
def __init__(self): if Computor.instance is None: Computor.instance = self self.__parser = Parser() self.__simplifier = Simplifier() self.__evaluator = evaluator.Evaluator() self.__solver = Solver() self.__vars = {} self.__funcs = {} self.__local_vars = [] # list of tuple (name, value), to be used as stack else: raise ComputorException('Computor.instance already instantiated')
def resolve_var(self, var_name): var_name_lc = var_name.lower() # Search in stack of local variables # if found, return the variable name as string for local_var in reversed(self.__local_vars): if local_var[0].lower() == var_name_lc: return var_name # Search in dictionary of global variables # if found, return the variable's value if var_name_lc in self.__vars: return self.__vars[var_name_lc].value raise ComputorException('Variable \'' + Fore.BLUE + var_name + Fore.RESET + '\' is not defined')
def div(self, a, b): if isinstance(a, float): if isinstance(b, float): if b == 0: raise ComputorException('Division by zero') return a / b elif isinstance(b, Complex): return Complex.div(Complex(a), b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Rational / Matrix') elif isinstance(a, Complex): if isinstance(b, float): return Complex.div(a, Complex(b)) elif isinstance(b, Complex): return Complex.div(a, b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex / Matrix') elif isinstance(a, Matrix): if isinstance(b, float): if b == 0: raise ComputorException('Division by zero') return Matrix.scalar_mul(1 / b, a) elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix / Complex') elif isinstance(b, Matrix): return Matrix.mat_mul(a, b.get_inverse()) raise ComputorException('Computor.div(): something bad happened 🤷')
def get_inverse(self): # Check if it is square matrix if self.shape[0] != self.shape[1]: raise ComputorException('M' + str(self.shape) + ' is not invertible') # 1 x 1 Matrix if self.shape[0] == 1: if self.data[0][0] == 0: raise ComputorException('Matrix is singular') else: data = [[ 1 / self.data[0][0] ]] return Matrix(data) # Check determinant determinant = self.__get_determinant() if determinant == 0: raise ComputorException('Matrix is singular') # 2 x 2 Matrix # inv = 1/determinant * [[d, -b], [-c, a]] if self.shape[0] == 2: data = [[ 1 / determinant * self.data[1][1], -1 / determinant * self.data[0][1] ], [ -1 / determinant * self.data[1][0], 1 / determinant * self.data[0][0] ]] return Matrix(data) # 3 x 3 or Bigger Matrix cofactors = [] for r in range(self.shape[0]): cofactor_row = [] for c in range(self.shape[0]): minor = self.__get_minor(r, c) cofactor_row.append( ((-1)**(r+c)) * minor.__get_determinant() ) cofactors.append(cofactor_row) inv = Matrix(cofactors).get_transpose() for r in range(inv.shape[0]): for c in range(inv.shape[0]): inv.data[r][c] /= determinant return inv
def add(self, a, b): if isinstance(a, float): if isinstance(b, float): return a + b elif isinstance(b, Complex): return Complex.add(Complex(a), b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Rational + Matrix') elif isinstance(a, Complex): if isinstance(b, float): return Complex.add(a, Complex(b)) elif isinstance(b, Complex): return Complex.add(a, b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex + Matrix') elif isinstance(a, Matrix): if isinstance(b, float): raise ComputorException('Illegal operation: Matrix + Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix + Complex') elif isinstance(b, Matrix): return Matrix.add(a, b) raise ComputorException('Computor.add(): something bad happened 🤷')
def sub(self, a, b): if isinstance(a, float): if isinstance(b, float): return a - b elif isinstance(b, Complex): return Complex.sub(Complex(a), b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Rational - Matrix') elif isinstance(a, Complex): if isinstance(b, float): return Complex.sub(a, Complex(b)) elif isinstance(b, Complex): return Complex.sub(a, b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex - Matrix') elif isinstance(a, Matrix): if isinstance(b, float): raise ComputorException('Illegal operation: Matrix - Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix - Complex') elif isinstance(b, Matrix): return Matrix.sub(a, b) raise ComputorException('Computor.sub(): something bad happened 🤷')
def mul(self, a, b): if isinstance(a, float): if isinstance(b, float): return a * b elif isinstance(b, Complex): return Complex.mul(Complex(a), b) elif isinstance(b, Matrix): return Matrix.scalar_mul(a, b) elif isinstance(a, Complex): if isinstance(b, float): return Complex.mul(a, Complex(b)) elif isinstance(b, Complex): return Complex.mul(a, b) elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex * Matrix') elif isinstance(a, Matrix): if isinstance(b, float): return Matrix.scalar_mul(b, a) elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix * Complex') elif isinstance(b, Matrix): return Matrix.element_mul(a, b) raise ComputorException('Computor.mul(): something bad happened 🤷')
def mat_mul(self, a, b): if isinstance(a, float): if isinstance(b, float): raise ComputorException('Illegal operation: Rational ** Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Rational ** Complex') elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Rational ** Matrix') elif isinstance(a, Complex): if isinstance(b, float): raise ComputorException('Illegal operation: Complex ** Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Complex ** Complex') elif isinstance(b, Matrix): raise ComputorException('Illegal operation: Complex ** Matrix') elif isinstance(a, Matrix): if isinstance(b, float): raise ComputorException('Illegal operation: Matrix ** Rational') elif isinstance(b, Complex): raise ComputorException('Illegal operation: Matrix ** Complex') elif isinstance(b, Matrix): return Matrix.mat_mul(a, b) raise ComputorException('Computor.mat_mul(): something bad happened 🤷')
def eval_function(self, func_name, args): function = self.get_func(func_name) if len(function.local_vars) != len(args): raise ComputorException('Invalid parameters for ' + str(function)) # push local variables on stack for var_name, value in zip(function.local_vars, args): self.__local_vars.append((var_name, value)) # evaluate # result = self.__parser.parse(function.expr) result = self.__evaluator.eval(function.expr) # pop local variables from stack for _ in self.__local_vars: self.__local_vars.pop() return result
def mat_mul(self, a, b): if isinstance(a, Matrix) and isinstance(b, Matrix): return Matrix.mat_mul(a, b) else: raise ComputorException('**: both operands must be Matrix')
def build_term_var(self, var_name): value = computor.Computor.instance.get_var(var_name) if not isinstance(value, float): raise ComputorException('Variables must be rational') return [ Term(value, 0) ]
def parse_func(self, token): func_name = token.value function = computor.Computor.instance.get_func(func_name) if not (len(function.local_vars) == 1 and function.local_vars[0].upper() == 'X'): raise ComputorException('Invalid function: ' + str(function)) return function
def get_func(self, func_name): func_name_lc = func_name.lower() if func_name_lc in self.__funcs: return (self.__funcs[func_name_lc]) else: raise ComputorException('Function \'' + Fore.GREEN + func_name + Fore.RESET + '\' is not defined')