def test_getVariables(): varA = getTokens("x") assert getVariables([varA]) == ['x'] varB = getTokens("xy+ xy^2 +yz^3") assert getVariables(varB) == ['x', 'y', 'z']
def test_getVariables(): varA = getTokens("x") assert getVariables([varA]) == ['x'] varB = getTokens("xy+ xy^2 +yz^3") assert getVariables(varB) == ['x', 'y', 'z'] varC = getTokens("x + sin(x) + cos(y) + tan(2*z)*2 + tanh(z) + e^2") # FIXME: getVariables() in visma.io.checks # varC = getTokens("x + sin(x) + cos(y) + tan(2*z)*2 + tanh(z) + e^2") # assert getVariables(varC) == ['x', 'y', 'z'] assert getVariables(varC) == ['x']
def plot(workspace, tokens=None): """When called from window.py it initiates rendering of equations. Arguments: workspace {QtWidgets.QWidget} -- main layout """ from visma.io.tokenize import tokenizer workspace.figure2D.clear() workspace.figure3D.clear() if tokens is None: tokens = workspace.eqToks[-1] eqType = getTokensType(tokens) LHStok, RHStok = getLHSandRHS(tokens) variables = sorted(getVariables(LHStok, RHStok)) dim = len(variables) graphVars, func, variables = graphPlot(workspace, False, tokens) renderPlot(workspace, graphVars, func, variables, tokens) if (dim == 1): var2, var3 = selectAdditionalVariable(variables[0]) if tokens is None: workspace.eqToks[-1] += tokenizer("0" + var2 + "+" + "0" + var3) else: tokens += tokenizer("0" + var2 + "+" + "0" + var3) if (((dim == 2) or (dim == 1)) & (eqType == 'equation')): graphVars, func, variables = graphPlot(workspace, True, tokens) renderPlot(workspace, graphVars, func, variables, tokens)
def graphPlot(workspace): """Function for plotting graphs in 2D and 3D space 2D graphs are plotted for expression in one variable and equations in two variables. 3D graphs are plotted for expressions in two variables and equations in three variables. Arguments: workspace {QtWidgets.QWidget} -- main layout Returns: graphVars {list} -- variables to be plotted on the graph func {numpy.array(2D)/function(3D)} -- equation converted to compatible data type for plotting variables {list} -- variables in given equation Note: The func obtained from graphPlot() funtion is of different type for 2D and 3D plots. For 2D, func is a numpy array, and for 3D, func is a function. """ tokens = workspace.eqToks[-1] axisRange = workspace.axisRange eqType = getTokensType(tokens) LHStok, RHStok = getLHSandRHS(tokens) variables = sorted(getVariables(LHStok, RHStok)) dim = len(variables) if (dim == 1 and eqType == "expression") or ((dim == 2) and eqType == "equation"): graphVars, func = plotIn2D(LHStok, RHStok, variables, axisRange) if dim == 1: variables.append('f(' + variables[0] + ')') elif (dim == 2 and eqType == "expression") or ((dim == 3) and eqType == "equation"): graphVars, func = plotIn3D(LHStok, RHStok, variables, axisRange) if dim == 2: variables.append('f(' + variables[0] + ',' + variables[1] + ')') else: return [], None, None return graphVars, func, variables
def getPowerRatio(initTok, givenTok): """Returns ratio of power of given token to power of token to be substituted Arguments: initTok {functions.structure.Function} -- token to be substituted givenTok {functions.structure.Function} -- given token Returns: ratio {float} -- ratio of givenTok.power to initTok.power """ if isinstance(initTok, Variable) and isinstance(givenTok, Variable): varA = getVariables([initTok]) varB = getVariables([givenTok]) if all(var in varB for var in varA): ratios = [] for i, valA in enumerate(initTok.value): for j, valB in enumerate(givenTok.value): if valA == valB: ratios.append(givenTok.power[j]/initTok.power[i]) break if all(ratio == ratios[0] for ratio in ratios): return ratios[0] return 1
def plot(workspace): """When called from window.py it initiates rendering of equations. Arguments: workspace {QtWidgets.QWidget} -- main layout """ workspace.figure2D.clear() workspace.figure3D.clear() tokens = workspace.eqToks[-1] eqType = getTokensType(tokens) LHStok, RHStok = getLHSandRHS(tokens) variables = sorted(getVariables(LHStok, RHStok)) dim = len(variables) graphVars, func, variables = graphPlot(workspace, False) renderPlot(workspace, graphVars, func, variables) # Handles case when a equation (like x^2 + y^2 = 5) can be rendered in 2D as well as 3D. if ((dim == 2) and eqType == "equation"): graphVars, func, variables = graphPlot(workspace, True) renderPlot(workspace, graphVars, func, variables)
def calluser(): availableOperations = [] tokenString = '' equationTokens = [] self.resultOut = True if name == 'addition': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = addition( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = additionEquation( self.lTokens, self.rTokens, True) elif name == 'subtraction': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = subtraction( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = subtractionEquation( self.lTokens, self.rTokens, True) elif name == 'multiplication': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = multiplication( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = multiplicationEquation( self.lTokens, self.rTokens, True) elif name == 'division': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = division( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = divisionEquation( self.lTokens, self.rTokens, True) elif name == 'simplify': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = simplify( self.tokens) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = simplifyEquation( self.lTokens, self.rTokens) elif name == 'factorize': self.tokens, availableOperations, tokenString, equationTokens, comments = factorize( self.tokens) elif name == 'find roots': self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = quadraticRoots( self.lTokens, self.rTokens) elif name == 'solve': lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) self.wrtVariableButtons(variables, name) self.resultOut = False elif name == 'integrate': lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) self.wrtVariableButtons(variables, name) self.resultOut = False elif name == 'differentiate': lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) self.wrtVariableButtons(variables, name) self.resultOut = False if self.resultOut: self.eqToks = equationTokens self.output = resultLatex(name, equationTokens, comments) if len(availableOperations) == 0: self.clearButtons() else: self.refreshButtons(availableOperations) if self.mode == 'normal': self.textedit.setText(tokenString) elif self.mode == 'interaction': cursor = self.textedit.textCursor() cursor.insertText(tokenString) if self.showStepByStep is True: showSteps(self) if self.showPlotter is True: plot(self)
def cubicRoots(lTokens, rTokens): '''Used to get roots of a cubic equation This functions also translates roots {list} into final result of solution Argument: lTokens {list} -- list of LHS tokens rTokens {list} -- list of RHS tokens Returns: lTokens {list} -- list of LHS tokens rTokens {list} -- list of RHS 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 ''' from visma.solvers.polynomial.roots import getCoefficients animations = [] comments = [] lTokens, rTokens, _, token_string, animNew1, commentNew1 = simplifyEquation( lTokens, rTokens) animations.extend(animNew1) comments.extend(commentNew1) if len(rTokens) > 0: lTokens, rTokens = moveRTokensToLTokens(lTokens, rTokens) coeffs = getCoefficients(lTokens, rTokens, 3) var = getVariables(lTokens) roots, animNew2, commentNew2 = getRootsCubic(coeffs) animations.extend(animNew2) comments.extend(commentNew2) tokens1 = [] expression1 = Expression(coefficient=1, power=3) variable = Variable(1, var[0], 1) tokens1.append(variable) if roots[0][1] == 0: binary = Binary() if roots[0][0] < 0: roots[0][0] *= -1 binary.value = '+' else: binary.value = '-' tokens1.append(binary) constant = Constant(round(roots[0][0], ROUNDOFF), 1) tokens1.append(constant) expression1.tokens = tokens1 lTokens = [expression1, Binary('*')] if len(roots) > 1: expression1.power = 1 for _, root in enumerate(roots[1:]): tokens2 = [] expression2 = Expression(coefficient=1, power=1) variable = Variable(1, var[0], 1) tokens2.append(variable) binary = Binary() if root[1] == 0: if root[0] < 0: root[0] *= -1 binary.value = '+' else: binary.value = '-' tokens2.append(binary) constant = Constant(round(root[0], ROUNDOFF), 1) tokens2.append(constant) else: binary.value = '-' tokens2.append(binary) expressionResult = Expression(coefficient=1, power=1) tokensResult = [] real = Constant(round(root[0], ROUNDOFF), 1) tokensResult.append(real) imaginary = Constant(round(root[1], ROUNDOFF), 1) if imaginary.value < 0: tokensResult.append(Minus()) imaginary.value = abs(imaginary.value) tokensResult.append(imaginary) else: tokensResult.extend([Plus(), imaginary]) sqrt = Sqrt(Constant(2, 1), Constant(-1, 1)) tokensResult.append(Binary('*')) tokensResult.append(sqrt) expressionResult.tokens = tokensResult tokens2.append(expressionResult) expression2.tokens = tokens2 lTokens.extend([expression2, Binary('*')]) lTokens.pop() rTokens = [Zero()] tokenToStringBuilder = copy.deepcopy(lTokens) tokLen = len(lTokens) equalTo = Binary() equalTo.scope = [tokLen] equalTo.value = '=' tokenToStringBuilder.append(equalTo) tokenToStringBuilder.extend(rTokens) token_string = tokensToString(tokenToStringBuilder) animations.append(copy.deepcopy(tokenToStringBuilder)) comments.append([]) return lTokens, rTokens, [], token_string, animations, comments
def calluser(): availableOperations = [] tokenString = '' equationTokens = [] self.resultOut = True if not self.matrix: """ This part handles the cases when VisMa is NOT dealing with matrices. Boolean flags used in code below: simul -- {True} when VisMa is dealing with simultaneous equations & {False} in all other cases """ if name == 'addition': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = addition( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = additionEquation( self.lTokens, self.rTokens, True) elif name == 'subtraction': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = subtraction( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = subtractionEquation( self.lTokens, self.rTokens, True) elif name == 'multiplication': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = multiplication( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = multiplicationEquation( self.lTokens, self.rTokens, True) elif name == 'division': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = division( self.tokens, True) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = divisionEquation( self.lTokens, self.rTokens, True) elif name == 'simplify': if self.solutionType == 'expression': self.tokens, availableOperations, tokenString, equationTokens, comments = simplify(self.tokens) else: self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = simplifyEquation(self.lTokens, self.rTokens) elif name == 'factorize': self.tokens, availableOperations, tokenString, equationTokens, comments = factorize(self.tokens) elif name == 'find roots': self.lTokens, self.rTokens, availableOperations, tokenString, equationTokens, comments = rootFinder(self.lTokens, self.rTokens) elif name == 'solve': if not self.simul: lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) else: variables = getVariableSim(self.tokens) self.wrtVariableButtons(variables, name) self.resultOut = False elif name == 'factorial': self.tokens, availableOperations, tokenString, equationTokens, comments = factorial(self.tokens) elif name == 'combination': nTokens = self.tokens[0] rTokens = self.tokens[1] self.tokens, _, _, equationTokens, comments = combination(nTokens, rTokens) elif name == 'permutation': nTokens = self.tokens[0] rTokens = self.tokens[1] self.tokens, _, _, equationTokens, comments = permutation(nTokens, rTokens) elif name == 'integrate': lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) self.wrtVariableButtons(variables, name) self.resultOut = False elif name == 'differentiate': lhs, rhs = getLHSandRHS(self.tokens) variables = getVariables(lhs, rhs) self.wrtVariableButtons(variables, name) self.resultOut = False else: """ This part handles the cases when VisMa is dealing with matrices. Boolean flags used in code below: dualOperand -- {True} when the matrix operations require two operands (used in operations like addition, subtraction etc) nonMatrixResult -- {True} when the result after performing operations on the Matrix is not a Matrix (in operations like Determinant, Trace etc.) scalarOperations -- {True} when one of the operand in a scalar (used in operations like Scalar Addition, Scalar Subtraction etc.) """ # TODO: use latex tools like /amsmath for displaying matrices if self.dualOperandMatrix: Matrix1_copy = copy.deepcopy(self.Matrix1) Matrix2_copy = copy.deepcopy(self.Matrix2) else: Matrix0_copy = copy.deepcopy(self.Matrix0) if name == 'Addition': MatrixResult = addMatrix(self.Matrix1, self.Matrix2) elif name == 'Subtraction': MatrixResult = subMatrix(self.Matrix1, self.Matrix2) elif name == 'Multiply': MatrixResult = multiplyMatrix(self.Matrix1, self.Matrix2) elif name == 'Simplify': MatrixResult = simplifyMatrix(self.Matrix0) elif name == 'Trace': sqMatrix = SquareMat() sqMatrix.value = self.Matrix0.value result = sqMatrix.traceMat() elif name == 'Determinant': sqMatrix = SquareMat() sqMatrix.value = self.Matrix0.value result = sqMatrix.determinant() elif name == 'Inverse': sqMatrix = SquareMat() sqMatrix.value = self.Matrix0.value MatrixResult = SquareMat() MatrixResult = sqMatrix.inverse() if name in ['Addition', 'Subtraction', 'Multiply']: self.dualOperandMatrix = True else: self.dualOperandMatrix = False if name in ['Determinant', 'Trace']: self.nonMatrixResult = True else: self.nonMatrixResult = False if self.resultOut: if not self.matrix: self.eqToks = equationTokens self.output = resultLatex(equationTokens, name, comments, self.solutionType) if (mathError(self.eqToks[-1])): self.output += 'Math Error: LHS not equal to RHS' + '\n' if len(availableOperations) == 0: self.clearButtons() else: self.refreshButtons(availableOperations) if self.mode == 'normal': self.textedit.setText(tokenString) elif self.mode == 'interaction': cursor = self.textedit.textCursor() cursor.insertText(tokenString) if self.showStepByStep is True: showSteps(self) if self.showPlotter is True: plot(self) else: if self.dualOperandMatrix: if not self.scalarOperationsMatrix: self.output = resultMatrixStringLatex(operation=name, operand1=Matrix1_copy, operand2=Matrix2_copy, result=MatrixResult) else: # TODO: Implement Scalar Matrices operations. pass # finalCLIstring = resultMatrix_Latex(operation=name, operand1=scalarTokens_copy, operand2=Matrix2_copy, result=MatrixResult) else: if self.nonMatrixResult: self.output = resultMatrixStringLatex(operation=name, operand1=Matrix0_copy, nonMatrixResult=True, result=result) else: self.output = resultMatrixStringLatex(operation=name, operand1=Matrix0_copy, result=MatrixResult) if self.mode == 'normal': self.textedit.setText(tokenString) elif self.mode == 'interaction': cursor = self.textedit.textCursor() cursor.insertText(tokenString) if self.showStepByStep is True: showSteps(self)
def quadraticRoots(lTokens, rTokens): '''Used to get quadratic roots of an equation Argument: lTokens {list} -- list of LHS tokens rTokens {list} -- list of RHS tokens Returns: lTokens {list} -- list of LHS tokens rTokens {list} -- list of RHS 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 ''' from visma.solvers.polynomial.roots import getCoefficients animations = [] comments = [] lTokens, rTokens, _, token_string, animNew1, commentNew1 = simplifyEquation(lTokens, rTokens) animations.extend(animNew1) comments.extend(commentNew1) if len(rTokens) > 0: lTokens, rTokens = moveRTokensToLTokens(lTokens, rTokens) coeffs = getCoefficients(lTokens, rTokens, 2) var = getVariables(lTokens) roots, animNew2, commentNew2 = getRootsQuadratic(coeffs) animations.extend(animNew2) comments.extend(commentNew2) if len(roots) == 1: tokens = [] expression = Expression(coefficient=1, power=2) variable = Variable(1, var[0], 1) tokens.append(variable) binary = Binary() if roots[0] < 0: roots[0] *= -1 binary.value = '+' else: binary.value = '-' tokens.append(binary) constant = Constant(round(roots[0], ROUNDOFF), 1) tokens.append(constant) expression.tokens = tokens lTokens = [expression] elif len(roots) == 2: tokens = [] expression = Expression(coefficient=1, power=1) variable = Variable(1, var[0], 1) tokens.append(variable) binary = Binary() if roots[0] < 0: roots[0] *= -1 binary.value = '+' else: binary.value = '-' tokens.append(binary) constant = Constant(round(roots[0], ROUNDOFF), 1) tokens.append(constant) expression.tokens = tokens tokens2 = [] expression2 = Expression(coefficient=1, power=1) tokens2.append(variable) binary2 = Binary() if roots[1] < 0: roots[1] *= -1 binary2.value = '+' else: binary2.value = '-' tokens2.append(binary2) constant2 = Constant(round(roots[1], ROUNDOFF), 1) tokens2.append(constant2) expression2.tokens = tokens2 binary3 = Binary() binary3.value = '*' lTokens = [expression, binary3, expression2] elif len(roots) == 3: binary4 = Binary() if roots[0] < 0: roots[0] *= -1 binary4.value = '+' else: binary4.value = '-' constant3 = Constant(round(roots[0], ROUNDOFF), 1) binary5 = Binary() binary5.value = '*' constant2 = Constant(round(roots[2], ROUNDOFF), 1) tokens = [] expression = Expression(coefficient=1, power=1) variable = Variable(1, var[0], 1) tokens.extend([variable, binary4, constant3]) binary = Binary() binary.value = '+' tokens.extend([binary, constant2, binary5]) constant = Constant(round(roots[1], ROUNDOFF), 1) sqrt = Sqrt(Constant(2, 1), constant) tokens.append(sqrt) expression.tokens = tokens tokens2 = [] expression2 = Expression(coefficient=1, power=1) variable2 = Variable(1, var[0], 1) tokens2.extend([variable2, binary4, constant3]) binary2 = Binary() binary2.value = '-' tokens2.extend([binary2, constant2, binary5, sqrt]) expression2.tokens = tokens2 binary3 = Binary() binary3.value = '*' lTokens = [expression, binary3, expression2] zero = Zero() rTokens = [zero] comments.append([]) tokenToStringBuilder = copy.deepcopy(lTokens) tokLen = len(lTokens) equalTo = Binary() equalTo.scope = [tokLen] equalTo.value = '=' tokenToStringBuilder.append(equalTo) tokenToStringBuilder.extend(rTokens) animations.append(copy.deepcopy(tokenToStringBuilder)) token_string = tokensToString(tokenToStringBuilder) return lTokens, rTokens, [], token_string, animations, comments