def __sub__(self, other): from visma.functions.constant import Constant from visma.functions.variable import Variable from visma.functions.operator import Plus, Minus if isinstance(other, Expression): result = Expression() for tok1 in self.tokens: result.tokens.append(tok1) for _, x in enumerate(other.tokens): if x.value == '+': x.value = '-' elif x.value == '-': x.value = '+' result.tokens.append(Minus()) if (isinstance(other.tokens[0], Constant)): if (other.tokens[0].value < 0): result.tokens[-1] = Plus() other.tokens[0].value = abs(other.tokens[0].value) elif (isinstance(other.tokens[0], Variable)): if (other.tokens[0].coefficient < 0): result.tokens[-1] = Plus() other.tokens[0].coefficient = abs(other.tokens[0].coefficient) return result elif isinstance(other, Constant): result = self result += (Constant(0) - other) return result elif isinstance(other, Variable): result = self a = Constant(0) - other result = a + result return result
def __init__(self, dim): super().__init__() for i in range(0, dim[0]): row = [] for j in range(0, dim[1]): if i == j: row.append(Constant(1)) else: row.append(Constant(0)) self.value.append(row)
def test_Constant(): constant1 = Constant(10) assert constant1.__str__() == "{10}" constant1.differentiate() assert constant1.value == 0 constant2 = Constant(5) constant2.integrate('x') assert isinstance(constant2, Variable) assert constant2.__str__() == "5{x}"
def factorizeTokens(tokens): coeffs, var = getPolyCoeffs(tokens) gcf, roots, polynomial = factor(coeffs) if roots != []: tokens = [] comment = "The real roots of the above polynomial are " for root in roots: comment += r"$" + str(root) + "\ ,\ " + r"$" if gcf != 1: tokens.append(Constant(float(gcf))) tokens.append(Multiply()) for root in roots: expression = Expression() expression.tokens.append(Variable(1, var, 1)) if root > 0: expression.tokens.append(Minus()) expression.tokens.append(Constant(float(root))) elif root < 0: expression.tokens.append(Plus()) expression.tokens.append(Constant(float(-root))) tokens.append(expression) tokens.append(Multiply()) if polynomial != [1]: expression = Expression() degree = len(polynomial) - 1 for i, coeff in enumerate(polynomial): if i == degree: if coeff > 0: expression.tokens.append(Plus()) expression.tokens.append(Constant(float(coeff))) elif coeff < 0: expression.tokens.append(Minus()) expression.tokens.append(Constant(float(-coeff))) elif coeff > 0: expression.tokens.append(Plus()) expression.tokens.append(Variable(coeff, var, degree - i)) elif coeff < 0: expression.tokens.append(Minus()) expression.tokens.append(Variable(-coeff, var, degree - i)) if isinstance(expression.tokens[0], Plus): expression.tokens.pop(0) tokens.append(expression) else: tokens.pop() else: comment = None animation = [tokens] comments = [comment] return tokens, animation, comments
def factorial(tokens): '''Used to get factorial of tokens provided Argument: tokens {list} -- list of tokens Returns: result {list} -- list of result tokens {empty list} token_string {string} -- final result stored in a string animation {list} -- list of equation solving process comments {list} -- list of comments in equation solving process ''' tokens, _, _, _, _ = simplify(tokens) animation = [] comments = [] if (isinstance(tokens[0], Constant) & len(tokens) == 1): value = int(tokens[0].calculate()) if value == 0: result = [Constant(1)] comments += [['Factorial of ZERO is defined to be 1']] animation += [tokenizer('f = ' + str(1))] else: resultString = '' for i in range(1, value + 1): resultString += (str(i) + '*') resultString = resultString[:-1] resultTokens = tokenizer(resultString) comments += [['Expanding the factorial as']] animation += [resultTokens] result, _, _, _, _ = simplify(resultTokens) token_string = tokensToString(result) comments += [['Hence result: ']] animation += [tokenizer('f = ' + token_string)] return result, [], token_string, animation, comments
def scalarDiv(const, mat): """Divides constant terms with Matrix Arguments: const {string}--- constant value mat {visma.matrix.structure.Matrix} -- matrix token Returns: matRes {visma.matrix.structure.Matrix} -- result matrix token """ if const != 0: matRes = Matrix() matRes.empty([mat.dim[0], mat.dim[1]]) for i in range(mat.dim[0]): for j in range(mat.dim[1]): if len(mat.value[i][j]) != 1: matRes.value[i][j].append(Expression(mat.value[i][j])) else: matRes.value[i][j].extend(mat.value[i][j]) matRes.value[i][j].append(Binary('/')) matRes.value[i][j].append(Constant(int(const))) matRes = simplifyMatrix(matRes) return matRes else: logger.error("ZeroDivisionError: Cannot divide matrix by zero")
def scalarSub(const, mat): """ Subtracts constant terms with Matrix Arguments: const {string}--- constant value mat {visma.matrix.structure.Matrix} -- matrix token Returns: matRes {visma.matrix.structure.Matrix} -- subtracted matrix token Note: This scalar addition follows the following equation {mat} - {lambda}{identity mat} """ matRes = Matrix() matRes.empty([mat.dim[0], mat.dim[1]]) for i in range(mat.dim[0]): for j in range(mat.dim[1]): if i != j: matRes.value[i][j].extend(mat.value[i][j]) else: if len(mat.value[i][j]) != 1: matRes.value[i][j].append(Expression(mat.value[i][j])) else: matRes.value[i][j].extend(mat.value[i][j]) matRes.value[i][j].append(Binary('-')) matRes.value[i][j].append(Constant(int(const))) matRes = simplifyMatrix(matRes) return matRes
def differentiate(self, wrtVar): term1 = Constant(-1, 1, 1) term2 = copy.deepcopy(self) term2.__class__ = Sine term2.value = 'sin' result = Expression() result.tokens = [term1, Multiply(), term2] return result
def integrate(self, wrtVar=None): term1 = Constant(-1, 1, 1) term2 = copy.deepcopy(self) term2.__class__ = Cosine term2.value = 'cos' term2.coefficient = 1 result = Expression() result.tokens = [term1, Multiply(), term2] return result
def differentiate(self, wrtVar): term1 = Constant(-1, 1, 1) term2 = copy.deepcopy(self) term2.__class__ = Cosecant term2.value = 'csc' term2.coefficient = 1 term2.power = 2 result = Expression() result.tokens = [term1, Multiply(), term2] return result
def calculate(self): from visma.functions.constant import Constant if isinstance(self.power, int) or isinstance( self.power, float) or isinstance(self.power, Constant): const = Constant() if isinstance(self.power, Constant): self.power = self.power.calculate() const.value = self.coefficient * (self.base**self.power) return const else: return self
def integrate(self, wrtVar): term1 = Constant(-1, 1, 1) term2 = NaturalLog() term3 = Cosine() term3.operand = self.operand term2.operand = term3 term2.power = 1 term2.coefficient = 1 result = Expression() result.tokens = [term1, Multiply(), term2] return result
def differentiate(self, wrtVar): term1 = Constant(-1, 1, 1) term2 = Cosecant() term2.operand = self.operand term2.coefficient = 1 term3 = Cotangent() term3.operand = self.operand term3.coefficient = 1 result = Expression() result.tokens = [term1, Multiply(), term2, Multiply(), term3] return result
def test_isDiagonal(): mat = getTokens("[1, 0; \ 0, z]") assert mat.isDiagonal() mat = getTokens("[1+x, 0+y; \ 0, z]") assert not mat.isDiagonal() mat = getTokens("[1, 2; \ 1, 3; \ 1, 4]") assert not mat.isDiagonal() mat = DiagMat([3, 3], [[Constant(1)], [Constant(5)], [Constant(2)]]) assert mat.isDiagonal() mat = IdenMat([2, 2]) assert mat.isDiagonal()
def __pow__(self, other): from visma.functions.constant import Constant if isinstance(other, Constant): if other.value == -1: one = Constant(1, 1, 1) result = Variable() result.value = self.value result.coefficient = one.calculate() / self.coefficient result.power = [] for pows in self.power: result.power.append(-pows) return result
def __truediv__(self, other): from visma.functions.constant import Constant if isinstance(other, Variable) or isinstance(other, Constant): self = self * (other**Constant(-1, 1, 1)) return self elif isinstance(other, Expression): expression = Expression() self.coefficient /= other.coefficient other.power *= -1 expression.tokens = [self] expression.tokens.extend([Multiply(), other]) self = expression return expression
def __sub__(self, other): from visma.functions.constant import Constant if isinstance(other, Variable): otherValueSorted = sorted(other.value) selfValueSorted = sorted(self.value) if (other.power == self.power) & (selfValueSorted == otherValueSorted): self = self + Constant(-1, 1, 1) * other return self else: expression = Expression() expression.tokens = [self] expression.tokens.extend([Minus(), other]) self = expression return expression elif isinstance(other, Constant): if other.isZero(): return self expression = Expression() expression.tokens = [self] expression.tokens.extend([Minus(), other]) self = expression return expression elif isinstance(other, Expression): expression = Expression() expression.tokens = [self] for i, token in enumerate(other.tokens): if isinstance(token, Variable): tokenValueSorted = sorted(token.value) selfValueSorted = sorted(self.value) if (token.power == self.power) & (tokenValueSorted == selfValueSorted): if other.tokens[i - 1].value == '+' or (i == 0): self.coefficient -= other.tokens[i].coefficient elif other.tokens[i - 1].value == '-': self.coefficient += other.tokens[i].coefficient else: if other.tokens[i - 1].value == '+' or i == 0: expression.tokens.extend([Plus(), Variable(token)]) elif other.tokens[i - 1].value == '-': expression.tokens.extend( [Minus(), Variable(token)]) elif not isinstance(token, Binary): if other.tokens[i - 1].value == '+' or (i == 0): expression.tokens.extend([Minus(), token]) elif other.tokens[i - 1].value == '-': expression.tokens.extend([Plus(), token]) expression.tokens[0] = self self = expression return expression
def integrate(self, wrtVar): term1 = Constant(-1, 1, 1) term2 = NaturalLog() result = Expression() term3 = Cosecant() term3.operand = self.operand term4 = Cotangent() term4.operand = self.operand inExpression = Expression() inExpression.tokens = [term3, Plus(), term4] term2.operand = inExpression term2.power = 1 term2.coefficient = 1 result.tokens = [term1, Multiply(), term2] return result
def __init__(self, dim, diagElem): """ dim {list} -- dimension of matrix diagElem {list} -- list of tokens list """ super().__init__() self.dim = dim for i in range(0, dim[0]): row = [] for j in range(0, dim[1]): if i == j: row.append(diagElem[i]) else: row.append([Constant(0)]) self.value.append(row)
def substituteTokens(initTok, subsTok, givenTok): """Substitute initTok with subsTok in a givenTok. For example: substitute x(initTok) with wyz^2(subsTok) in xyz(givenTok) i.e. final_tok will be wy^2z^3 Arguments: initTok {functions.structure.Function} -- token to be substituted subsTok {functions.structure.Function} -- substitute token givenTok {functions.structure.Function} -- given token Returns: givenTok {functions.structure.Function} -- given token after substitution """ if isinstance(givenTok, Variable): if isinstance(initTok, Variable): power = getPowerRatio(initTok, givenTok) if isinstance(subsTok, Constant): givenTok = removeValues(initTok, givenTok) if len(givenTok.value) == 0: givenTok = Constant( (subsTok.value**power) * givenTok.coefficient) else: givenTok.coefficient *= subsTok.value**power elif isinstance(subsTok, Variable): givenTok.coefficient /= initTok.coefficient**power givenTok.coefficient *= subsTok.coefficient**power givenTok = replaceValues(initTok, subsTok, givenTok, power) elif isinstance(subsTok, Expression): subs_copy = copy.deepcopy(subsTok) givenTok.coefficient /= initTok.coefficient**power givenTok.coefficient *= subs_copy.coefficient**power subs_copy.coefficient = 1 subs_copy.power = power givenTok = removeValues(initTok, givenTok) if len(givenTok.value) == 0: subs_copy.coefficient = givenTok.coefficient givenTok = subs_copy else: givenTok = Expression([givenTok, Multiply(), subs_copy]) elif isinstance(givenTok, Expression): substitute(initTok, subsTok, Expression.toklist) return givenTok
def traceMat(self): """Returns the trace of a square matrix (sum of diagonal elements) Arguments: mat {visma.matrix.structure.Matrix} -- matrix token Returns: trace {visma.matrix.structure.Matrix} -- string token """ from visma.simplify.simplify import simplify trace = [] for i in range(self.dim[0]): trace.extend(self.value[i][i]) trace.append(Binary('+')) trace.append(Constant(0)) trace, _, _, _, _ = simplify(trace) return trace
def determinant(self, mat=None): """Calculates square matrices' determinant Returns: list of tokens forming the determinant """ from visma.simplify.simplify import simplify if mat is None: self.dimension() mat = np.array(self.value) if (mat.shape[0] > 2): ans = [] for i in range(mat.shape[0]): mat1 = SquareMat() mat1.value = np.concatenate((mat[1:, :i], mat[1:, i + 1:]), axis=1).tolist() a, _, _, _, _ = simplify(mat1.determinant()) if (a[0].value != 0 and a != []): a, _, _, _, _ = simplify(a + [Multiply()] + mat[0][i].tolist()) if (i % 2 == 0): if (ans != []): ans, _, _, _, _ = simplify(ans + [Plus()] + a) else: ans = a else: ans, _, _, _, _ = simplify(ans + [Minus()] + a) elif (mat.shape[0] == 2): a = Multiply() b = Minus() mat = mat.tolist() a1, _, _, _, _ = simplify(mat[0][0] + [a] + mat[1][1]) a2, _, _, _, _ = simplify(mat[0][1] + [a] + mat[1][0]) ans, _, _, _, _ = simplify([a1[0], b, a2[0]]) if (isinstance(ans[0], Minus) or isinstance( ans[0], Plus)) and ans[0].value not in ['+', '-']: ans[0] = Constant(ans[0].value) else: ans, _, _, _, _ = simplify(mat[0][0]) if not ans: ans = Zero() return ans
def row_echelon(mat): """ Returns the row echelon form of the given matrix Arguments: mat {visma.matrix.structure.Matrix} -- matrix token Returns: row_echelon {visma.matrix.structure.Matrix} -- result matrix token """ N = mat.dim[0] M = mat.dim[1] for k in range(0, N): if abs(mat.value[k][k][0].value) == 0.0: if k == N - 1: return simplifyMatrix(mat) else: for i in range(0, N): t = mat.value[k][i] mat.value[k][i] = mat.value[k + 1][i] mat.value[k + 1][i] = t else: for i in range(k + 1, N): temp = [] temp.extend(mat.value[i][k]) temp.append(Binary('/')) temp.extend(mat.value[k][k]) temp, _, _, _, _ = simplify(temp) for j in range(k + 1, M): temp2 = [] temp2.extend(mat.value[k][j]) temp2.append(Binary('*')) temp2.extend(temp) temp2, _, _, _, _ = simplify(temp2) mat.value[i][j].append(Binary('-')) mat.value[i][j].extend(temp2) mat.value[i][k].append(Binary('*')) mat.value[i][k].append(Constant(0)) mat = simplifyMatrix(mat) return simplifyMatrix(mat)
def __mul__(self, other): from visma.io.checks import isNumber from visma.functions.constant import Constant if isinstance(other, Variable): for j, var in enumerate(other.value): found = False for k, var2 in enumerate(self.value): self.coefficient *= other.coefficient if var == var2: if isNumber(other.power[j]) and isNumber( self.power[k]): self.power[k] += other.power[j] if self.power[k] == 0: del self.power[k] del self.value[k] found = True break if not found: self.value.append(other.value[j]) self.power.append(other.power[j]) if len(self.value) == 0: result = Constant(self.coefficient) result.scope = self.scope result.power = 1 result.value = self.coefficient self = result return self elif isinstance(other, Constant): self.coefficient *= other.calculate() return self elif isinstance(other, Expression): result = Expression() for _, token in enumerate(other.tokens): if isinstance(token, Variable) or isinstance(token, Constant): c = copy.deepcopy(self) result.tokens.extend([c * token]) else: result.tokens.extend([token]) return result
def ArithemeticMean(sampleSpace): """Implements arithemetic mean Arguments: sampleSpace -- {visma.discreteMaths.statistics.ArithemeticMean} Returns: token_string {string} -- final result stored in a string animation {list} -- list of equation solving process comments {list} -- list of comments in equation solving process """ animations = [] comments = [] if sampleSpace.values is not []: sm = sum(sampleSpace.values) animations += [[]] comments += [[ 'Sum of all the values of the sample space provided by user: '******'' for val in sampleSpace.values: summationString += str(val) + '+' summationString = summationString[:-1] summationTokens = tokenizer(summationString) resultTokens, _, _, _, _ = simplify(summationTokens) if len(resultTokens) == 1 and isinstance(resultTokens[0], Constant): ArithemeticMean = resultTokens[0] / Constant( len(sampleSpace.values)) animations += [[]] comments += [[ 'Considering ' + str(len(sampleSpace.values)) + ' values.' ]] animations += [[tokenizer('mean = ' + str(ArithemeticMean.calculate))]] token_string = tokensToString([ArithemeticMean]) return token_string, animations, comments else: return '', [], []
def scalarMult(const, mat): """Multiplies constant terms with Matrix Arguments: const {string}--- constant value mat {visma.matrix.structure.Matrix} -- matrix token Returns: matRes {visma.matrix.structure.Matrix} -- product matrix token """ matRes = Matrix() matRes.empty([mat.dim[0], mat.dim[1]]) for i in range(mat.dim[0]): for j in range(mat.dim[1]): if len(mat.value[i][j]) != 1: matRes.value[i][j].append(Expression(mat.value[i][j])) else: matRes.value[i][j].extend(mat.value[i][j]) matRes.value[i][j].append(Binary('*')) matRes.value[i][j].append(Constant(int(const))) matRes = simplifyMatrix(matRes) return matRes
def expressionDivision(variables, tokens): removeScopes = [] comments = [] for i, token in enumerate(tokens): if isinstance(token, Binary): if token.value in ['/']: prev = False nxt = False if i != 0: if tokens[i - 1].__class__ in [Variable, Constant]: prev = True if i + 1 < len(tokens): if tokens[i + 1].__class__ in [Variable, Constant]: nxt = True if nxt and prev: if isinstance(tokens[i + 1], Constant) and isinstance(tokens[i - 1], Constant): comments.append("Dividing " + r"$" + tokens[i - 1].__str__() + r"$" + " by " + r"$" + tokens[i + 1].__str__() + r"$") no_1 = False no_2 = False if isNumber(tokens[i - 1].value): no_1 = True if isNumber(tokens[i + 1].value): no_2 = True if no_1 and no_2: tokens[i + 1].value = evaluateConstant( tokens[i - 1]) / evaluateConstant(tokens[i + 1]) tokens[i + 1].power = 1 removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i - 1].scope) elif no_1 and not no_2: value = tokens[i - 1].value power = tokens[i - 1].power tokens[i - 1].value = [value] tokens[i - 1].power = [power] for val in tokens[i + 1].value: tokens[i - 1].value.append(val) for pows in tokens[i + 1].power: tokens[i - 1].power.append(-pows) removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) elif not no_1 and no_2: tokens[i - 1].value.append(tokens[i + 1].value) tokens[i - 1].power.append(-tokens[i + 1].power) removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) elif not no_1 and not no_2: for vals in tokens[i + 1].value: tokens[i - 1].value.append(vals) for pows in tokens[i + 1].power: tokens[i - 1].power.append(pows) removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) return variables, tokens, removeScopes, comments elif isinstance(tokens[i + 1], Variable) and isinstance(tokens[i - 1], Variable): comments.append("Dividing " + r"$" + tokens[i - 1].__str__() + r"$" + " by " + r"$" + tokens[i + 1].__str__() + r"$") for j, var in enumerate(tokens[i + 1].value): found = False for k, var2 in enumerate(tokens[i - 1].value): tokens[i-1].coefficient /= tokens[i+1].coefficient if var == var2: if isNumber(tokens[i + 1].power[j]) and isNumber(tokens[i - 1].power[k]): tokens[i - 1].power[k] -= tokens[i + 1].power[j] if tokens[i - 1].power[k] == 0: del tokens[i - 1].power[k] del tokens[i - 1].value[k] found = True break if not found: tokens[i - 1].value.append(tokens[i + 1].value[j]) tokens[i - 1].power.append(-tokens[i + 1].power[j]) if len(tokens[i - 1].value) == 0: constant = Constant() constant.scope = tokens[i - 1].scope constant.power = 1 constant.value = tokens[i - 1].coefficient tokens[i - 1] = constant removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) return variables, tokens, removeScopes, comments elif (isinstance(tokens[i + 1], Variable) and isinstance(tokens[i - 1], Constant)): comments.append("Dividing " + r"$" + tokens[i - 1].__str__() + r"$" + " by " + r"$" + tokens[i + 1].__str__() + r"$") val = evaluateConstant(tokens[i - 1]) scope = tokens[i - 1].scope tokens[i - 1] = Variable() tokens[i - 1].value = tokens[i + 1].value tokens[i - 1].coefficient = val / \ tokens[i + 1].coefficient tokens[i - 1].power = [] tokens[i - 1].scope = scope for pows in tokens[i + 1].power: tokens[i - 1].power.append(-pows) removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) return variables, tokens, removeScopes, comments elif (isinstance(tokens[i - 1], Variable) and isinstance(tokens[i + 1], Constant)): comments.append("Dividing " + r"$" + tokens[i - 1].__str__() + r"$" + " by " + r"$" + tokens[i + 1].__str__() + r"$") tokens[i - 1].coefficient /= evaluateConstant(tokens[i + 1]) removeScopes.append(tokens[i].scope) removeScopes.append(tokens[i + 1].scope) return variables, tokens, removeScopes, comments return variables, tokens, removeScopes, comments
def __rsub__(self, other): from visma.functions.constant import Constant return Constant(0, 1, 1) - self + other
def __init__(self, dim): super().__init__(dim, [[Constant(1)]] * dim[0]) for i in range(0, dim[0]): self.value[i][i] = Constant(1)
def division_constants(constant1, constant2, coeff): no_1 = False no_2 = False constant = Constant() if isNumber(constant1.value): no_1 = True if isNumber(constant2.value): no_2 = True if no_1 and no_2: constant.value = (evaluateConstant( constant1) / evaluateConstant(constant2)) * coeff constant.power = 1 # removeScopes.append(tokens[i].scope) # removeScopes.append(tokens[i-1].scope) elif no_1 and not no_2: constant.value = [constant1.value] constant.power = [constant1.power] for i, val in enumerate(constant2.value): done = False for j, val2 in enumerate(constant.value): if val == val2: constant.power[j] -= constant2.power[i] done = True break if not done: constant.value.append(val) constant.power.append(-constant2.power[i]) constant.value.append(coeff) constant.power.append(1) # removeScopes.append(tokens[i].scope) # removeScopes.append(tokens[i-1].scope) elif not no_1 and no_2: constant.value = constant1.value constant.power = constant1.power done = False for i, val in enumerate(constant.value): if val == constant2.value: constant.power[i] -= constant2.power done = True break if not done: constant.value.append(constant2.value) constant.power.append(-constant2.power) constant.value.append(coeff) constant.power.append(1) # removeScopes.append(tokens[i].scope) # removeScopes.append(tokens[i+1].scope) elif not no_1 and not no_2: constant.value = constant1.value constant.power = constant1.power for i, val in enumerate(constant2.value): done = False for j, val2 in enumerate(constant.value): if val == val2: constant.power[j] -= constant2.power[i] done = True break if not done: constant.value.append(val) constant.power.append(-constant2.power[i]) constant.value.append(coeff) constant.power.append(1) # removeScopes.append(tokens[i].scope) # removeScopes.append(tokens[i-1].scope) return constant