diff --git a/symboCalc.py b/symboCalc.py index fb8f50cb6b1be339f5cda2fdf9fdbbe4428e4f60..e1980018403235629f43f4b9e3e2ceed7a67786e 100644 --- a/symboCalc.py +++ b/symboCalc.py @@ -1,10 +1,10 @@ # Jack Eckert # dependencies -from abc import ABC, abstractmethod import math +from typing import Any -# abstract base class for functions +# base class for functions # arg is the argument of the function, which by default is the identity function represented # by the string 'x'. Any string will work and acts as a marker to allow the program to identify @@ -12,7 +12,7 @@ import math # coef is the coefficient of the function, should always be an integer or float and by default # is one. -class BaseFunction(ABC): +class BaseFunction(): def __init__(self, coef=None, arg=None): if coef == None: self.__coefficient = 1 @@ -40,9 +40,19 @@ class BaseFunction(ABC): def integrateCoef(self, k): self.__coefficient *= k + def __neg__(self): + return type(self)(-self.getCoef(), self.getArg()) + + def __eq__(self, other): + if not(isinstance(other, type(self))): + return False + return (self.getArg() == other.getArg() and self.getCoef() == other.getCoef()) + def __str__(self): if self.getCoef() == 1: coefficientString = '' + elif self.getCoef() == -1: + coefficientString = '-' else: coefficientString = round(self.getCoef(), 3) return coefficientString @@ -50,9 +60,11 @@ class BaseFunction(ABC): def __repr__(self): return str(self) - @abstractmethod - def derive(self): - pass + def derive(self, shell): + if isinstance(self.getArg(), str): + return shell + else: + return [shell.getArg().derive(), shell] # power function, i.e. a function raised to a constant power. class Power(BaseFunction): @@ -66,6 +78,15 @@ class Power(BaseFunction): def setExp(self): return self.__exponent + def __neg__(self): + return type(self)(-self.getCoef(), self.getArg(), self.getExp()) + + def __eq__(self, other): + return (super().__eq__(other) and self.getExp() == other.getExp()) + + def __ne__(self, other): + return not(self.__eq__(other)) + def __str__(self): coefficientString = super().__str__() @@ -88,13 +109,8 @@ class Power(BaseFunction): else: shell = Power(self.getCoef() * self.getExp(), self.getArg(), self.getExp() - 1) - # base derivative, or chain rule if the argument is a different function - if isinstance(self.getArg(), str): - return shell - else: - return (self.getArg().derive(), shell) - - + # derivation + return super().derive(shell) # exponential function, i.e. a constant raised to a function power. class Exponential(BaseFunction): @@ -113,26 +129,126 @@ class Exponential(BaseFunction): def setBase(self, new): self.__base = new + def __neg__(self): + return type(self)(-self.getCoef(), self.getArg(), self.getBase()) + def __str__(self): coefficientString = super().__str__() return f"{coefficientString}exp({self.getArg()})" + def __eq__(self, other): + return (super().__eq__(other) and self.getBase() == other.getBase()) + def derive(self): - if isinstance(self.getArg(), str): - return self - else: - return (self.getArg().derive(), self) - -class Sin(): + shell = self + return super().derive(shell) + +# sine function +class Sine(BaseFunction): + def __init__(self, coef=None, arg=None): + super().__init__(coef, arg) + + def __str__(self): + coefficientString = super().__str__() + return f"{coefficientString}sin({self.getArg()})" + def derive(self): + shell = Cosine(self.getCoef(), self.getArg()) + return super().derive(shell) +# cosine function +class Cosine(BaseFunction): + def __init__(self, coef=None, arg=None): + super().__init__(coef, arg) + + def __str__(self): + coefficientString = super().__str__() + return f"{coefficientString}cos({self.getArg()})" + + def derive(self): + shell = -Sine(self.getCoef(), self.getArg()) + return super().derive(shell) -# TODO class Equation(): def __init__(self, eqList): + self.__eqList = eqList + for i, term in enumerate(self.__eqList): + if not(isinstance(term, list)): + self.__eqList[i] = [term] + + def __iter__(self): + self.index = -1 + return self + + def __next__(self): + if self.index < len(self.__eqList) - 1: + self.index += 1 + return self.__eqList[self.index] + else: + raise StopIteration + + def getEqList(self): + return self.__eqList + + def setEqList(self, new): + self.__eqList = new + + def __getitem__(self, i): + return self.__eqList[i] + + def __setitem__(self, i, new): + self.__eqList[i] = new + + def addTerm(self, new): + if not(isinstance(new, list)): + new = [new] + self.__eqList.append(new) + + def removeAt(self, i): + del self.__eqList[i] + + def __str__(self): + strList = [] + for term in self: + termString = '' + for seg in term: + termString += f"({seg})" + strList.append(termString) + return " + ".join(strList) + + def __mul__(self, k): + copy = Equation(self.__eqList) + for term in copy: + term.insert(0, k) + return copy + + def __rmul__(self, k): + copy = Equation(self.__eqList) + for term in copy: + term.insert(0, k) + return copy + + def __add__(self, k): + copy = Equation(self.__eqList) + copy.addTerm(k) + return copy + + def __radd__(self, k): + copy = Equation(self.__eqList) + copy.addTerm(k) + return copy + + def __sub__(self, k): + return self + -k + + def __rsub__(self, k): + return -self + k + + #TODO + def simplify(self): pass # Testing if __name__ == "__main__": - eq1 = Exponential(arg=Power(exp=2)) - print(eq1.derive()) \ No newline at end of file + eq1 = Equation([[Power(exp=2), Cosine()], Sine()]) + print(eq1 - Cosine()) \ No newline at end of file