diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index daeb4c2..f43730b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,6 +11,7 @@ This is a brief guide on using **visma(VISualMAth)** and for making any contribu
* **Integration** - integrate a polynomial expression wrt a chosen variable
* **Differentiation** - differentiate a polynomial expression wrt a chosen variable
* **Plot** - plots an interactive 2D or 3D graph
+* **Matrix Operations** - This feature will allow you to add, subtract, and multiply two matrices. Can also perform various simplifications on an individual matrix.

diff --git a/README.md b/README.md
index bf4b1a5..50ed8fa 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
visma - VISual MAth
-
+
+
A math equation solver and visualizer
diff --git a/main.py b/main.py
index e51e48b..67c46a4 100644
--- a/main.py
+++ b/main.py
@@ -14,7 +14,7 @@ def init():
class VisMa_Prompt(Cmd):
'''This inititates the main VisMa Prompt from where user may move to CLI/GUI'''
- userManual = "|_________________________________________________________________________________________________|\n"\
+ userManual = " _________________________________________________________________________________________________ \n"\
"| gui ->> opens Visma in GUI mode. |\n"\
"| Ctrl + D ->> Closes the prompt. |\n"\
"| exit ->> Closes the prompt. |\n"\
@@ -31,6 +31,10 @@ class VisMa_Prompt(Cmd):
"|-------------------------------------------------------------------------------------------------|\n"\
"| integrate( expression , variable ) ->> Integrates the expression by the given variable. |\n"\
"| differentiate( expression , variable ) ->> Differentiates the expression by the given variable. |\n"\
+ "|-------------------------------------------------------------------------------------------------|\n"\
+ "| Matrices should be input in the following format: |\n"\
+ "| Single: mat_([x00 x01; x10 x11]) |\n"\
+ "| Double: mat_([x00 x01; x10 x11], [y00 y01; y10 y11]) |\n"\
"|_________________________________________________________________________________________________|\n"\
prompt = '>>> '
diff --git a/tests/test_simplify.py b/tests/test_simplify.py
index f6983f6..54f9261 100644
--- a/tests/test_simplify.py
+++ b/tests/test_simplify.py
@@ -10,6 +10,9 @@
def test_simplify():
+ assert quickTest("4 + (3/(3-4)*3)", simplify) == "-5"
+
+
assert quickTest("1 + 2 - 3", simplify) == "0"
assert quickTest("1 + 2 - 4", simplify) == "-1.0"
assert quickTest("0 + 0 + 1", simplify) == "1.0"
diff --git a/visma/functions/structure.py b/visma/functions/structure.py
index 8e389ab..4ef7624 100644
--- a/visma/functions/structure.py
+++ b/visma/functions/structure.py
@@ -1,6 +1,104 @@
import copy
+def tokensToString(tokens):
+ """Converts tokens to text string
+
+ Arguments:
+ tokens {list} -- list of function tokens
+
+ Returns:
+ tokenString {string} -- equation string
+ """
+ # FIXME: tokensToString method
+ # tokenString = ''
+ # for token in tokens:
+ # if isinstance(token, Constant):
+ # if isinstance(token.value, list):
+ # for j, val in token.value:
+ # if token['power'][j] != 1:
+ # tokenString += (str(val) + '^(' + str(token.power[j]) + ')')
+ # else:
+ # tokenString += str(val)
+ # elif isNumber(token.value):
+ # if token.power != 1:
+ # tokenString += (str(token.value) + '^(' + str(token.power) + ')')
+ # else:
+ # tokenString += str(token.value)
+ # elif isinstance(token, Variable):
+ # if token.coefficient == 1:
+ # pass
+ # elif token.coefficient == -1:
+ # tokenString += '-'
+ # else:
+ # tokenString += str(token.coefficient)
+ # for j, val in enumerate(token.value):
+ # if token.power[j] != 1:
+ # tokenString += (str(val) + '^(' + str(token.power[j]) + ')')
+ # else:
+ # tokenString += str(val)
+ # elif isinstance(token, Binary):
+ # tokenString += ' ' + str(token.value) + ' '
+ # elif isinstance(token, Expression):
+ # if token.coefficient != 1:
+ # tokenString += str(token.coefficient) + '*'
+ # tokenString += '('
+ # tokenString += tokensToString(token.tokens)
+ # tokenString += ')'
+ # if token.power != 1:
+ # tokenString += '^(' + str(token.power) + ')'
+ # elif isinstance(token, Sqrt):
+ # tokenString += 'sqrt['
+ # if isinstance(token.power, Constant):
+ # tokenString += tokensToString([token.power])
+ # elif isinstance(token.power, Variable):
+ # tokenString += tokensToString([token.power])
+ # elif isinstance(token.power, Expression):
+ # tokenString += tokensToString(token.power.tokens)
+ # tokenString += ']('
+ # if isinstance(token.operand, Constant):
+ # tokenString += tokensToString([token.operand])
+ # elif isinstance(token.operand, Variable):
+ # tokenString += tokensToString([token.operand])
+ # elif isinstance(token.operand, Expression):
+ # tokenString += tokensToString(token.operand.tokens)
+ # tokenString += ')'
+ # elif isinstance(token, Logarithm):
+ # if token.coefficient == 1:
+ # pass
+ # elif token.coefficient == -1:
+ # tokenString += '-'
+ # else:
+ # tokenString += str(token.coefficient)
+ # if token.operand is not None:
+ # tokenString += token.value
+ # if token.power != 1:
+ # tokenString += "^" + "(" + str(token.power) + ")"
+ # tokenString += "(" + tokensToString([token.operand]) + ")"
+ # elif isinstance(token, Trigonometric):
+ # if token.coefficient == 1:
+ # pass
+ # elif token.coefficient == -1:
+ # tokenString += '-'
+ # else:
+ # tokenString += str(token.coefficient)
+ # if token.operand is not None:
+ # tokenString += token.value
+ # if token.power != 1:
+ # tokenString += "^" + "(" + str(token.power) + ")"
+ # tokenString += "(" + tokensToString([token.operand]) + ")"
+ # elif isinstance(token, Matrix):
+ # tokenString += "["
+ # for i in range(token.dim[0]):
+ # for j in range(token.dim[1]):
+ # tokenString += tokensToString(token.value[i][j])
+ # tokenString += ","
+ # tokenString = tokenString[:-1] + ";"
+ # tokenString = tokenString[:-1] + "]"
+ #
+ # return tokenString
+
+
class Function(object):
"""Basis function class for all functions
diff --git a/visma/gui/cli.py b/visma/gui/cli.py
index 0532e4d..cdf01f6 100644
--- a/visma/gui/cli.py
+++ b/visma/gui/cli.py
@@ -1,6 +1,7 @@
import copy
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QTabWidget, QVBoxLayout
+from PyQt5.QtCore import Qt
from visma.calculus.differentiation import differentiate
from visma.calculus.integration import integrate
from visma.discreteMaths.combinatorics import factorial, combination, permutation
diff --git a/visma/gui/logger.py b/visma/gui/logger.py
index 8f550d4..f4ee87e 100644
--- a/visma/gui/logger.py
+++ b/visma/gui/logger.py
@@ -16,6 +16,7 @@
def logTextBox(workspace):
workspace.logBox = QTextEdit()
workspace.logBox.setReadOnly(True)
+ workspace.logBox.setStyleSheet("background-color: rgb(210, 210, 210)") # colors inside of logger
textLayout = QVBoxLayout()
textLayout.addWidget(workspace.logBox)
return textLayout
diff --git a/visma/gui/plotter.py b/visma/gui/plotter.py
index 562964b..06c7631 100644
--- a/visma/gui/plotter.py
+++ b/visma/gui/plotter.py
@@ -193,6 +193,8 @@ class NavigationCustomToolbar(NavigationToolbar):
layout = QVBoxLayout()
layout.addWidget(workspace.canvas2D)
layout.addWidget(workspace.toolbar2D)
+ workspace.figure2D.set_facecolor("none") # makes color transparent
+ workspace.canvas2D.setStyleSheet("background-color: rgb(210, 210, 210)")
return layout
@@ -216,6 +218,9 @@ class NavigationCustomToolbar(NavigationToolbar):
layout = QVBoxLayout()
layout.addWidget(workspace.canvas3D)
layout.addWidget(workspace.toolbar3D)
+ workspace.figure3D.set_facecolor("none") # makes color transparent
+ workspace.canvas3D.setStyleSheet("background-color: rgb(210, 210, 210)")
+
return layout
@@ -307,6 +312,7 @@ def plot(workspace, tokens=None):
renderPlot(workspace, graphVars, func, variables, tokens)
+
def selectAdditionalVariable(var1):
if var1 == 'z':
var2 = 'a'
diff --git a/visma/gui/qsolver.py b/visma/gui/qsolver.py
index adfccaf..9a6e36f 100644
--- a/visma/gui/qsolver.py
+++ b/visma/gui/qsolver.py
@@ -81,8 +81,7 @@ def qSolveFigure(workspace):
"""
bg = workspace.palette().window().color()
- bgcolor = (bg.redF(), bg.greenF(), bg.blueF())
- workspace.qSolveFigure = Figure(edgecolor=bgcolor, facecolor=bgcolor)
+ workspace.qSolveFigure = Figure(edgecolor="none", facecolor="none") # Make transparent so parent can override background
workspace.solcanvas = FigureCanvas(workspace.qSolveFigure)
workspace.qSolveFigure.clear()
qSolLayout = QtWidgets.QVBoxLayout()
diff --git a/visma/gui/steps.py b/visma/gui/steps.py
index 3adf3a7..e438acb 100644
--- a/visma/gui/steps.py
+++ b/visma/gui/steps.py
@@ -18,9 +18,11 @@ def stepsFigure(workspace):
"""
workspace.stepsfigure = Figure()
workspace.stepscanvas = FigureCanvas(workspace.stepsfigure)
+ workspace.stepsfigure.set_facecolor("none") # make figure transparent so that background of scrollbar is visible
workspace.stepsfigure.clear()
workspace.scroll = QScrollArea()
workspace.scroll.setWidget(workspace.stepscanvas)
+ workspace.scroll.setStyleSheet("background-color: rgb(210, 210, 210)") # color background of scrollbar
stepslayout = QVBoxLayout()
stepslayout.addWidget(workspace.scroll)
return stepslayout
@@ -37,7 +39,7 @@ def showSteps(workspace):
verticalalignment='top', size=qApp.font().pointSize()*workspace.stepsFontSize)
workspace.stepscanvas.draw()
hbar = workspace.scroll.horizontalScrollBar()
- hbar.setValue((hbar.minimum()+hbar.maximum())/2)
+ hbar.setValue((hbar.minimum()+hbar.maximum())//2)
###############
diff --git a/visma/gui/window.py b/visma/gui/window.py
index 8454172..8cb0ebc 100644
--- a/visma/gui/window.py
+++ b/visma/gui/window.py
@@ -35,7 +35,7 @@
from visma.solvers.simulEqn import simulSolver
from visma.transform.factorization import factorize
from visma.gui import logger
-
+from PyQt5.QtGui import QPalette, QColor
class Window(QtWidgets.QMainWindow):
@@ -77,6 +77,8 @@ def initUI(self):
helpMenu = menubar.addMenu('&Help')
helpMenu.addAction(wikiAction)
self.workSpace = WorkSpace()
+ self.setStyleSheet('background-color: rgb(90, 90, 90);')
+ menubar.setStyleSheet("background-color: rgb(210, 210, 210)")
self.setCentralWidget(self.workSpace)
self.GUIwidth = 1300
self.GUIheight = 900
@@ -113,7 +115,7 @@ def loadEquations(self):
class WorkSpace(QWidget):
- inputGreek = ['x', 'y', 'z', '(', ')', '7', '8', '9', 'DEL', 'C', 'f', 'g', 'h', '{', '}', '4', '5', '6', '/', '*', 'sin', 'cos', 'tan', '[', ']', '1', '2', '3', '+', '-', 'log', 'exp', '^', 'i', u'\u03C0', '.', '0', '=', '<', '>']
+ inputGreek = ['x', 'y', 'z', '(', ')', '7', '8', '9', 'DEL', 'C', 'f', 'g', 'h', '{', '}', '4', '5', '6', '/', '*', 'sin', 'cos', 'tan', '[', ']', '1', '2', '3', '+', '-', 'log', 'exp', '^', '<', '>', '.', '0', '=', 'i', 'Ans']
inputLaTeX = ['x', 'y', 'z', '(', ')', '7', '8', '9', 'DEL', 'C', 'f', 'g', 'h', '{', '}', '4', '5', '6', '\\div', '\\times', '\\sin', '\\cos', '\\tan', '[', ']', '1', '2', '3', '+', '-', 'log', 'exp', '^', 'i', '\\pi', '.', '0', '=', '<', '>']
mode = 'interaction'
@@ -164,15 +166,31 @@ def __init__(self):
def initUI(self):
hbox = QHBoxLayout(self)
+ #self.setStyleSheet("border-color: rgb(60, 60, 60);") # changes color of nearly everything to blue
+ #self.setStyleSheet("color: lightblue") # changes color of all text to blue
+ #self.setStyleSheet("border: black") # removes button colors
+ # self.setStyleSheet("""
+ # background-color: rgb(90, 90, 90);
+ # border-color: rgb(90, 90, 90);
+ # """
+ # ) # changes nothing basically
self.equationList = QTabWidget()
self.equationList.tab1 = QWidget()
# self.equationList.tab2 = QWidget()
self.equationList.addTab(self.equationList.tab1, "History")
# self.equationList.addTab(self.equationList.tab2, "favourites")
- self.equationList.tab1.setLayout(self.equationsLayout())
+
+
+ self.equationList.tab1.setStyleSheet("background-color: rgb(120, 120, 120)") # colors border of history widget
+ self.equationList.tab1.setLayout(self.equationsLayout()) # color modified
+ self.myQListWidget.setStyleSheet("background-color: rgb(210, 210, 210);") # colors inside of widget
+ self.clearButton.setStyleSheet("background-color: rgb(210, 210, 210)") # colors button
+
+
self.equationList.tab1.setStatusTip("Track of old equations")
self.equationList.setFixedWidth(300)
+ self.equationList.setDocumentMode(True) # removes white borders
inputSpace = QTabWidget()
inputSpace.tab1 = QWidget()
@@ -183,12 +201,15 @@ def initUI(self):
inputSpace.tab2.setLayout(preferenceLayout(self))
inputSpace.tab1.setStatusTip("Input characters")
inputSpace.setFixedHeight(200)
+ inputSpace.tab1.setStyleSheet("background-color: rgb(120, 120, 120)") # colors border of step by step
+ inputSpace.tab2.setStyleSheet("background-color: rgb(210, 210, 210)") # colors border of logger
+ inputSpace.setDocumentMode(True) # removes white borders
buttonSpace = QWidget()
buttonSpace.setLayout(self.buttonsLayout())
buttonSpace.setFixedWidth(300)
buttonSpace.setStatusTip("Interact")
-
+
self.tabPlot = QTabWidget()
self.tabPlot.tab1 = QWidget()
self.tabPlot.tab2 = QWidget()
@@ -198,6 +219,10 @@ def initUI(self):
self.tabPlot.tab1.setStatusTip("Visualize equation in 2D")
self.tabPlot.tab2.setLayout(plotFigure3D(self))
self.tabPlot.tab2.setStatusTip("Visualize equation in 3D")
+ self.tabPlot.tab1.setStyleSheet("background-color: rgb(120, 120, 120)") # colors 2D plots
+ self.tabPlot.tab2.setStyleSheet("background-color: rgb(120, 120, 120)") # colors 3D plots
+
+ self.tabPlot.setDocumentMode(True) # removes white borders
tabStepsLogs = QTabWidget()
tabStepsLogs.tab1 = QWidget()
@@ -208,6 +233,10 @@ def initUI(self):
tabStepsLogs.tab1.setStatusTip("Step-by-step solver")
tabStepsLogs.tab2.setLayout(logger.logTextBox(self))
tabStepsLogs.tab2.setStatusTip("Logger")
+ tabStepsLogs.tab1.setStyleSheet("background-color: rgb(120, 120, 120)")
+ tabStepsLogs.tab2.setStyleSheet("background-color: rgb(120, 120, 120)")
+
+ tabStepsLogs.setDocumentMode(True) # removes white borders
font = QtGui.QFont()
font.setPointSize(16)
@@ -222,6 +251,7 @@ def initUI(self):
quickSolve.setLayout(qSolveFigure(self))
quickSolve.setFixedHeight(45)
quickSolve.setStatusTip("Quick solver")
+ quickSolve.setStyleSheet("background-color: rgb(150, 150, 150)")
splitter4 = QSplitter(Qt.Vertical)
splitter4.addWidget(self.textedit)
@@ -244,8 +274,21 @@ def initUI(self):
hbox.addWidget(splitter1)
self.setLayout(hbox)
+ self.previousAnswer = ''
+
+ self.textedit.setStyleSheet("background-color: rgb(210, 210, 210)")
+
+ self.setStyleSheet(
+ """
+ background-color: rgb(90, 90, 90);
+ border-color: rgb(90, 90, 90);
+ """
+ )
+
self.logBox.append(logger.info('UI Initialised...'))
+
+
def textChangeTrigger(self):
self.enableInteraction = True
self.clearButtons()
@@ -283,6 +326,7 @@ def clearAll(self):
def equationsLayout(self):
self.myQListWidget = QtWidgets.QListWidget(self)
+
for index, name in self.equations:
myQCustomQWidget = QCustomQWidget()
myQCustomQWidget.setTextUp(index)
@@ -292,6 +336,7 @@ def equationsLayout(self):
self.myQListWidget.addItem(myQListWidgetItem)
self.myQListWidget.setItemWidget(
myQListWidgetItem, myQCustomQWidget)
+ myQCustomQWidget.setStyleSheet("background-color: rgb(210, 210, 210);") # colors border around equations
self.myQListWidget.resize(400, 300)
self.equationListVbox.addWidget(self.myQListWidget)
self.myQListWidget.itemClicked.connect(self.Clicked)
@@ -325,6 +370,7 @@ def clearHistory(self):
self.myQListWidget.setItemWidget(
myQListWidgetItem, myQCustomQWidget)
i += 1
+ myQCustomQWidget.setStyleSheet("background-color: rgb(210, 210, 210);") # colors equation border on every iteration
file.close()
self.myQListWidget.resize(400, 300)
self.myQListWidget.itemClicked.connect(self.Clicked)
@@ -332,6 +378,8 @@ def clearHistory(self):
self.clearButton = QtWidgets.QPushButton('Clear equations')
self.clearButton.clicked.connect(self.clearHistory)
self.equationListVbox.addWidget(self.clearButton)
+ self.myQListWidget.setStyleSheet("background-color: rgb(210, 210, 210);") # colors inside of widget again
+ self.clearButton.setStyleSheet("background-color: rgb(210, 210, 210)") # colors button again
return self.equationListVbox
def Clicked(self, item):
@@ -344,6 +392,7 @@ def buttonsLayout(self):
interactionModeLayout = QVBoxLayout()
self.interactionModeButton = QtWidgets.QPushButton('visma')
self.interactionModeButton.clicked.connect(self.interactionMode)
+ self.interactionModeButton.setEnabled(False)
interactionModeLayout.addWidget(self.interactionModeButton)
interactionModeWidget = QWidget(self)
interactionModeWidget.setLayout(interactionModeLayout)
@@ -357,6 +406,12 @@ def buttonsLayout(self):
self.buttonSplitter.addWidget(topButtonSplitter)
self.buttonSplitter.addWidget(self.bottomButton)
vbox.addWidget(self.buttonSplitter)
+ self.interactionModeButton.setStyleSheet(
+ """
+ background-color: rgb(210, 210, 210);
+ font-size: 16px;
+ """
+ )
return vbox
def interactionMode(self):
@@ -416,12 +471,14 @@ def interactionMode(self):
operations, self.solutionType = checkTypes(lhs, rhs)
if isinstance(operations, list) and showbuttons:
opButtons = []
+ if 'differentiate' in operations:
+ opButtons.append('graph')
if len(operations) > 0:
if len(operations) == 1:
if (operations[0] not in ['integrate', 'differentiate', 'find roots', 'factorize']) and (not self.simul):
- opButtons = ['simplify']
+ opButtons.append('simplify')
else:
- opButtons = ['simplify']
+ opButtons.append('simplify')
for operation in operations:
if operation == '+':
opButtons.append("addition")
@@ -503,6 +560,12 @@ def interactionMode(self):
self.onSolvePress(opButtons[i * 2 + j]))
self.solutionOptionsBox.addWidget(
self.solutionButtons[(i, j)], i, j)
+ self.solutionButtons[(i, j)].setStyleSheet(
+ """
+ background-color: rgb(210, 210, 210);
+ font-size: 16px;
+ """
+ )
else:
self.bottomButton.setParent(None)
self.solutionWidget = QWidget()
@@ -516,6 +579,12 @@ def interactionMode(self):
self.onSolvePress(opButtons[i * 2 + j]))
self.solutionOptionsBox.addWidget(
self.solutionButtons[(i, j)], i, j)
+ self.solutionButtons[(i, j)].setStyleSheet(
+ """
+ background-color: rgb(210, 210, 210);
+ font-size: 16px;
+ """
+ )
self.solutionWidget.setLayout(self.solutionOptionsBox)
self.buttonSplitter.addWidget(self.solutionWidget)
self.buttonSet = True
@@ -523,12 +592,14 @@ def interactionMode(self):
def refreshButtons(self, operations):
if isinstance(operations, list):
opButtons = []
+ if 'differentiate' in operations:
+ opButtons.append('graph')
if len(operations) > 0:
if len(operations) == 1:
if operations[0] == 'solve':
- opButtons = ['simplify']
+ opButtons.append('simplify')
else:
- opButtons = ['simplify']
+ opButtons.append('simplify')
for operation in operations:
if operation == '+':
opButtons.append("addition")
@@ -610,6 +681,7 @@ def addEquation(self):
self.myQListWidget.setItemWidget(
myQListWidgetItem, myQCustomQWidget)
i += 1
+ myQCustomQWidget.setStyleSheet("background-color: rgb(210, 210, 210);")
file.close()
self.myQListWidget.resize(400, 300)
self.myQListWidget.itemClicked.connect(self.Clicked)
@@ -618,6 +690,8 @@ def addEquation(self):
self.clearButton = QtWidgets.QPushButton('Clear equations')
self.clearButton.clicked.connect(self.clearHistory)
self.equationListVbox.addWidget(self.clearButton)
+ self.myQListWidget.setStyleSheet("background-color: rgb(210, 210, 210);") # colors inside of widget
+ self.clearButton.setStyleSheet("background-color: rgb(210, 210, 210)") # colors button
return self.equationListVbox
def inputsLayout(self, loadList="Greek"):
@@ -630,6 +704,7 @@ def inputsLayout(self, loadList="Greek"):
if (i * 10 + j) < len(self.inputGreek):
self.buttons[(i, j)] = QtWidgets.QPushButton(
self.inputGreek[i * 10 + j])
+ self.checkForColorChange(self.buttons[(i, j)]) # color change function
self.buttons[(i, j)].resize(100, 100)
self.buttons[(i, j)].clicked.connect(
self.onInputPress(self.inputGreek[i * 10 + j]))
@@ -647,8 +722,33 @@ def inputsLayout(self, loadList="Greek"):
# inputSplitter.addWidget(inputTypeSplitter)
# inputSplitter.addWidget(inputWidget)
inputLayout.addWidget(inputWidget)
+ inputWidget.setStyleSheet("background-color: rgb(120, 120, 120);") # colors the space around input buttons
+
return inputLayout
+ def checkForColorChange(self, button): # changes button color
+ color = "rgb(210, 210, 210)"
+ bold = "normal"
+ match button.text():
+ case "Ans":
+ color = "green"
+ bold = "bold"
+ case "C" | "DEL":
+ color = "red"
+ bold = "bold"
+ case "+" | "*" | "/" | "-":
+ color = "orange"
+ bold = "bold"
+
+ button.setStyleSheet(f"""
+ background-color: {color};
+ font-weight: {bold};
+ font-size: 16px;
+ """
+ )
+
+
+
def onActivated(self, text):
for i in reversed(range(self.inputBox.count())):
self.inputBox.itemAt(i).widget().setParent(None)
@@ -679,6 +779,8 @@ def calluser():
elif name == 'DEL':
cursor = self.textedit.textCursor()
cursor.deletePreviousChar()
+ elif name == 'Ans':
+ self.textedit.insertPlainText(self.previousAnswer)
else:
self.textedit.insertPlainText(str(name))
return calluser
@@ -761,6 +863,13 @@ def calluser():
variables = getVariables(lhs, rhs)
self.wrtVariableButtons(variables, name)
self.resultOut = False
+ elif name == 'graph':
+ 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)
+ self.showPlotter = True
+ self.previousAnswer = tokenString
else:
"""
This part handles the cases when VisMa is dealing with matrices.
@@ -824,6 +933,7 @@ def calluser():
showSteps(self)
if self.showPlotter is True:
plot(self)
+ self.previousAnswer = tokenString
else:
if self.dualOperandMatrix:
if not self.scalarOperationsMatrix:
@@ -844,6 +954,7 @@ def calluser():
cursor.insertText(tokenString)
if self.showStepByStep is True:
showSteps(self)
+ self.previousAnswer = tokenString
return calluser
def onWRTVariablePress(self, varName, operation):
@@ -881,7 +992,6 @@ def calluser():
self.rTokens = rhs
operations, self.solutionType = checkTypes(lhs, rhs)
self.refreshButtons(operations)
-
else:
if operation == 'solve':
if not self.simul:
@@ -938,10 +1048,10 @@ def __init__(self, parent=None):
self.setLayout(self.allQHBoxLayout)
self.textUpQLabel.setStyleSheet('''
color: black;
- ''')
+ ''') # Colors the text in history tab: the equation number
self.textDownQLabel.setStyleSheet('''
color: black;
- ''')
+ ''') # Colors the text in history tab: the input
def setTextUp(self, text):
self.textUpQLabel.setText(text)
diff --git a/visma/io/checks.py b/visma/io/checks.py
index 5faa405..4486c1a 100644
--- a/visma/io/checks.py
+++ b/visma/io/checks.py
@@ -1,11 +1,13 @@
import math
import copy
from visma.config.values import ROUNDOFF
+from visma.functions.exponential import Logarithm
from visma.functions.structure import Function, Expression
from visma.functions.constant import Constant
+from visma.functions.trigonometry import Trigonometric
from visma.functions.variable import Variable
-from visma.functions.operator import Operator, Binary
-
+from visma.functions.operator import Operator, Binary, Sqrt
+from visma.matrix.structure import Matrix
greek = [u'\u03B1', u'\u03B2', u'\u03B3']
@@ -94,6 +96,105 @@ def isEquation(lTokens, rTokens):
return False
+def tokensToString(tokens):
+ """Converts tokens to text string
+
+ Arguments:
+ tokens {list} -- list of function tokens
+
+ Returns:
+ tokenString {string} -- equation string
+ """
+ # FIXME: tokensToString method
+ tokenString = ''
+ for token in tokens:
+ if isinstance(token, Constant):
+ if isinstance(token.value, list):
+ for j, val in token.value:
+ if token['power'][j] != 1:
+ tokenString += (str(val) + '^(' + str(token.power[j]) + ')')
+ else:
+ tokenString += str(val)
+ elif isNumber(token.value):
+ if token.power != 1:
+ tokenString += (str(token.value) + '^(' + str(token.power) + ')')
+ else:
+ tokenString += str(token.value)
+ elif isinstance(token, Variable):
+ if token.coefficient == 1:
+ pass
+ elif token.coefficient == -1:
+ tokenString += '-'
+ else:
+ tokenString += str(token.coefficient)
+ for j, val in enumerate(token.value):
+ if token.power[j] != 1:
+ tokenString += (str(val) + '^(' + str(token.power[j]) + ')')
+ else:
+ tokenString += str(val)
+ elif isinstance(token, Binary):
+ tokenString += ' ' + str(token.value) + ' '
+ elif isinstance(token, Expression):
+ if token.coefficient != 1:
+ tokenString += str(token.coefficient) + '*'
+ tokenString += '('
+ tokenString += tokensToString(token.tokens)
+ tokenString += ')'
+ if token.power != 1:
+ tokenString += '^(' + str(token.power) + ')'
+ elif isinstance(token, Sqrt):
+ tokenString += 'sqrt['
+ if isinstance(token.power, Constant):
+ tokenString += tokensToString([token.power])
+ elif isinstance(token.power, Variable):
+ tokenString += tokensToString([token.power])
+ elif isinstance(token.power, Expression):
+ tokenString += tokensToString(token.power.tokens)
+ tokenString += ']('
+ if isinstance(token.operand, Constant):
+ tokenString += tokensToString([token.operand])
+ elif isinstance(token.operand, Variable):
+ tokenString += tokensToString([token.operand])
+ elif isinstance(token.operand, Expression):
+ tokenString += tokensToString(token.operand.tokens)
+ tokenString += ')'
+ elif isinstance(token, Logarithm):
+ if token.coefficient == 1:
+ pass
+ elif token.coefficient == -1:
+ tokenString += '-'
+ else:
+ tokenString += str(token.coefficient)
+ if token.operand is not None:
+ tokenString += token.value
+ if token.power != 1:
+ tokenString += "^" + "(" + str(token.power) + ")"
+ tokenString += "(" + tokensToString([token.operand]) + ")"
+ elif isinstance(token, Trigonometric):
+ if token.coefficient == 1:
+ pass
+ elif token.coefficient == -1:
+ tokenString += '-'
+ else:
+ tokenString += str(token.coefficient)
+ if token.operand is not None:
+ tokenString += token.value
+ if token.power != 1:
+ tokenString += "^" + "(" + str(token.power) + ")"
+ tokenString += "(" + tokensToString([token.operand]) + ")"
+ elif isinstance(token, Matrix):
+ tokenString += "["
+ for i in range(token.dim[0]):
+ for j in range(token.dim[1]):
+ tokenString += tokensToString(token.value[i][j])
+ tokenString += ","
+ tokenString = tokenString[:-1] + ";"
+ tokenString = tokenString[:-1] + "]"
+
+ return tokenString
+
+
+
def getVariables(lTokens, rTokens=None, variables=None):
"""Finds all the variables present in the expression
@@ -107,6 +208,7 @@ def getVariables(lTokens, rTokens=None, variables=None):
Returns:
variables {list} -- list of variables
"""
+ #print("Alpha: "+tokensToString(lTokens))
if rTokens is None:
rTokens = []
if variables is None:
@@ -126,6 +228,8 @@ def getVariables(lTokens, rTokens=None, variables=None):
variables.append(val)
elif isinstance(token, Expression):
variables.extend(getVariables(token.tokens, [], variables))
+ #print("Beta: "+str(variables))
+ #print()
return variables
diff --git a/visma/io/parser.py b/visma/io/parser.py
index f6120cc..6bcf94a 100644
--- a/visma/io/parser.py
+++ b/visma/io/parser.py
@@ -36,22 +36,75 @@ def resultLatex(equationTokens, operation, comments, solutionType, simul=False,
else:
finalSteps = 'INPUT: ' + '(Multiple ' + r'$' + ' equations)' + r'$' + '\n'
finalSteps += 'OPERATION: ' + operation + '\n'
- finalSteps += 'OUTPUT: ' + r'$' + equationLatex[-1] + r'$' + 2*'\n'
+ # print(equationLatex[-1])
+ roundedStep = roundEquationLatexOutput(equationLatex, -1, 6)
+ # print(equationLatex[-1])
+ finalSteps += 'OUTPUT: ' + r'$' + roundedStep + r'$' + 2*'\n'
+ # finalSteps += 'OUTPUT: ' + r'$' + equationLatex[-1] + r'$' + 2*'\n'
for i, _ in enumerate(equationLatex):
if comments[i] != [] and equationLatex[i] != '':
finalSteps += '(' + str(comments[i][0]) + ')' + '\n'
- finalSteps += r'$' + equationLatex[i] + r'$' + 2*"\n"
+ if i == len(equationLatex) - 1:
+ # print(equationLatex[i])
+ roundedStep = roundEquationLatexOutput(equationLatex, i, 6)
+ # print(equationLatex[i])
+ pass
+ else:
+ # print(equationLatex[i])
+ roundedStep = roundEquationLatexOutput(equationLatex, i, 2)
+ # print(equationLatex[i])
+ pass
+ finalSteps += r'$' + roundedStep + r'$' + 2*"\n"
+ # finalSteps += '\n' + r'$' + equationLatex[-1] + r'$' + 2*'\n'
elif comments[i] != [] and equationLatex[i] == '':
finalSteps += '\n' + '[' + str(comments[i][0]) + ']' + '\n'
elif comments[i] == [] and equationLatex[i] != '':
- finalSteps += '\n' + r'$' + equationLatex[i] + r'$' + 2*'\n'
+ if i == len(equationLatex) - 1:
+ # print(equationLatex[i])
+ roundedStep = roundEquationLatexOutput(equationLatex, i, 6)
+ # print(equationLatex[i])
+ pass
+ else:
+ # print(equationLatex[i])
+ roundedStep = roundEquationLatexOutput(equationLatex, i, 2)
+ # print(equationLatex[i])
+ pass
+ finalSteps += '\n' + r'$' + roundedStep + r'$' + 2*'\n'
+ # finalSteps += '\n' + r'$' + equationLatex[i] + r'$' + 2*'\n'
if mathError(equationTokens[-1]) and (not simul):
finalSteps += 'Math Error: LHS not equal to RHS' + "\n"
return finalSteps
+def roundEquationLatexOutput(equationLatex, index, roundLength):
+ equationSlice = equationLatex[index][0:]
+ while '{' in equationSlice:
+ openBracketIndex = equationSlice.index("{")
+ closeBracketIndex = equationSlice.index("}")
+ temp_openBracketIndex = openBracketIndex
+ while '{' in equationSlice[temp_openBracketIndex + 1: closeBracketIndex] and closeBracketIndex != len(equationSlice) - 1:
+ temp_openBracketIndex = equationSlice[openBracketIndex + 1: closeBracketIndex].index('{') + openBracketIndex + 1
+ closeBracketIndex = equationSlice[closeBracketIndex + 1:].index('}') + closeBracketIndex + 1
+ # print(equationSlice[openBracketIndex:closeBracketIndex + 1])
+ # print(openBracketIndex, closeBracketIndex)
+ if not equationSlice[closeBracketIndex - 1].isnumeric():
+ value = ''
+ try:
+ value = round(float(equationSlice[:openBracketIndex]), roundLength)
+ except ValueError:
+ pass
+ equationLatex[index] = equationLatex[index][0:equationLatex[index].index(equationSlice)] \
+ + str(value) + equationSlice[openBracketIndex:]
+ equationSlice = equationSlice[closeBracketIndex + 1:]
+ pass
+ else:
+ value = round(float(equationSlice[openBracketIndex + 1:closeBracketIndex]), roundLength)
+ equationLatex[index] = equationLatex[index][0:equationLatex[index].index(equationSlice)] \
+ + equationSlice[0: openBracketIndex] + '{' + str(value) + '}' + equationSlice[closeBracketIndex + 1:]
+ equationSlice = equationSlice[closeBracketIndex + 1:]
+ return equationLatex[index]
def resultStringCLI(equationTokens, operation, comments, solutionType, simul=False, mat=False):
"""Converts tokens to final string format for displaying in terminal in CLI
diff --git a/visma/io/tokenize.py b/visma/io/tokenize.py
index d0a0ac7..49dffbc 100644
--- a/visma/io/tokenize.py
+++ b/visma/io/tokenize.py
@@ -25,7 +25,6 @@
from visma.matrix.structure import Matrix
from visma.matrix.checks import isMatrix
from visma.io.parser import latexToTerms
-# from visma.gui import logger
symbols = ['+', '-', '*', '/', '(', ')', '{', '}', '[', ']', '^', '=', '<', '>', '<=', '>=', ',', ';', '$']
greek = [u'\u03B1', u'\u03B2', u'\u03B3']
@@ -1379,7 +1378,6 @@ def tokenizer(eqnString):
_, tokens = constantConversion(preprocess(eqnString))
return tokens
-
def changeToken(tokens, variables, scope_times=0):
if len(variables) != 0:
diff --git a/visma/simplify/simplify.py b/visma/simplify/simplify.py
index 2b951ac..9ea3253 100644
--- a/visma/simplify/simplify.py
+++ b/visma/simplify/simplify.py
@@ -250,18 +250,21 @@ def expressionSimplification(tokens_now, scope, tokens1):
if len(tokens1[i + 1].tokens) == 1 and isinstance(tokens1[i + 1].tokens[0], Constant):
tokens1[i + 1] = Constant(tokens1[i + 1].tokens[0].calculate(), 1, 1)
if (isinstance(tokens1[i], Binary) and tokens1[i].value == '^') and isinstance(tokens1[i + 1], Constant):
- if float(tokens1[i + 1].calculate()).is_integer():
- rep = int(tokens1[i + 1].calculate())
- for _ in range(rep - 1):
- pfTokens.extend([Binary('*'), tokens1[i - 1]])
- i += 1
- else:
- pfTokens.append(tokens1[i])
+ value = str(tokens1[i - 1])[1:len(str(tokens1[i - 1])) - 1]
+ value = float(value)
+ value **= tokens1[i + 1].calculate()
+ tokens1[i + 1] = Constant(value, 1, 1)
+
+ del pfTokens[len(pfTokens) - 1]
+ pfTokens.append(tokens1[i + 1])
+ del tokens1[i]
+ del tokens1[i - 1]
else:
pfTokens.append(tokens1[i])
else:
pfTokens.append(tokens1[i])
i += 1
+
tokens1 = copy.deepcopy(pfTokens)
animation.append(pfTokens)
comments.append(['Expanding the powers of expressions'])
@@ -440,68 +443,3 @@ def simplifification(tokens):
tokens, animation = postSimplification(tokens, animation)
token_string = tokensToString(tokens)
return tokens, availableOperations, token_string, animation, comments
-
-
-'''
-def defineScopeVariable(variable, scope):
- token = copy.deepcopy(variable)
- local_scope = copy.deepcopy(scope)
- if isinstance(token.value, list):
- for j, val in enumerate(token.value):
- if val.__class__ in [Binary, Variable, Constant, Expression]:
- local_scope_value = copy.deepcopy(local_scope)
- local_scope_value.extend(-1)
- local_scope_value.extend(j)
- val.scope = local_scope_value
-
- if isinstance(token.power, list):
- for j, val in enumerate(token.value):
- if val.__class__ in [Binary, Variable, Constant, Expression]:
- local_scope_value = copy.deepcopy(local_scope)
- local_scope_value.extend(-2)
- local_scope_value.extend(j)
- val.scope = local_scope_value
-
- return token
-
-
-def defineScopeConstant(constant, scope):
- token = copy.deepcopy(constant)
- local_scope = copy.deepcopy(scope)
- if isinstance(token.value, list):
- for j, val in enumerate(token.value):
- if val.__class__ in [Binary, Variable, Constant, Expression]:
- local_scope_value = copy.deepcopy(local_scope)
- local_scope_value.extend(-1)
- local_scope_value.extend(j)
- val.scope = local_scope_value
-
- if isinstance(token.power, list):
- for j, val in enumerate(token.value):
- if val.__class__ in [Binary, Variable, Constant, Expression]:
- local_scope_value = copy.deepcopy(local_scope)
- local_scope_value.extend(-2)
- local_scope_value.extend(j)
- val.scope = local_scope_value
- return token
-
-
-def defineScope(tokens, scope=None):
- if scope is None:
- scope = []
- i = 0
- for token in tokens:
- local_scope = copy.deepcopy(scope)
- local_scope.extend(i)
- token.scope = local_scope
- if isinstance(token, Variable):
- token = defineScopeVariable(token, copy.deepcopy(local_scope))
- elif isinstance(token, Constant):
- token = defineScopeConstant(token, copy.deepcopy(local_scope))
- elif isinstance(token, Expression):
- token.tokens = defineScope(token.tokens, local_scope)
- elif isinstance(token, Binary):
- pass
- i += 1
- return tokens
-'''