restart; RowOpsMaplet := module() ############################################################ # # Elementary Row Operations Maplet # Andrew Martin, University of Kent, England # agm5@kent.ac.uk, agmweb@ilovemaths.co.uk # Date of publication of this code: August 28, 2003 # Version 0.2 # # Structure of code based on: # Step-by-Step Differentiation Problem Solver Maplet # Copyright 2002 Waterloo Maple Inc. # ############################################################ # TODO LIST # Error checking on back substitution, on error that says needs rowreducd matris, pass this error to user # Spell check everything and make nice titles # Sort out unused variable names # sort out why the mathml viewie scrools but the view doenst so one has to scroll down to see it. # change input mechanism so that matrix() bit etc isn't required use fullMatrixStr # write a sheet on how to use this export iniMathML, addMathML, runRowOpsMaplet, startRule, clearSteps: local helpStr: global errorSwitch; errorSwitch:=2; ############################################################ helpStr := "You can apply elementary row operations one at a time to an augmented matrix and view the resulting matrix. Enter a matrix using the usual Maple synatx. Click the 'Start' button to initialize the problem. To apply elementary row operations, enter appropriate values in the boxes and click the corresponding button. You can undo steps by clicking the undo button. When you apply a row operation, the 'Problem Status' box is updated with the result of the row operation. To clear the problem history, click the 'Clear' button. To obtain the matrix in Gaussian form, Gauss-Jordan form (row reduced echelon form) or to perform back substitution on a matrix, click the approproate button. Please report bugs, send comments and suggestions for improvements to Andrew Martin via e-mail agmweb@ilovemaths.co.uk ": ############################################################ ############################################################ iniMathML := proc(iniEqn) global errorSwitch, infoStr; try MathML:-ExportPresentation(iniEqn); catch: infoStr := "MathML conversion error - possibly due to a missing matrix entry"; errorSwitch:=1; end try; end proc: ############################################################ ############################################################ # pre: mathMLStr :: string, in form of Presentation MathML # addEqn :: algebraic expression addMathML := proc(mathMLStr, addEqn) local tree, cmc, child, children, nl, eqnSign; use XMLTools in tree := FromString(mathMLStr); cmc := ContentModelCount(tree); child := FromString(MathML:-ExportPresentation(addEqn)); children := ContentModel(child); nl := FromString(" "); eqnSign := Element("mo","="); tree := AddChild(tree,nl,cmc); tree := AddChild(tree,eqnSign,cmc+1); for child in children do cmc := ContentModelCount(tree); tree := AddChild(tree,child,cmc); end do: tree := MakeElement("mrow", [], ContentModel(tree) ): tree := Element("math", tree): ToString(tree): end use: end proc: ############################################################ clearSteps := proc() global errorSwitch; use Maplets:-Tools in Set('ML'=""): Set('TB'=""): Clear(all): errorSwitch:=2; end use: end proc: # end clearSteps: ############################################################ # TODO # # need to check that the multiply and add boxes have entries in # need to check how big matrix is and adujust pull down list to reflect this. # when matrixExpr is acted on need to change this to try catch stuff. # check spellings startRule := proc() local mlStr, matrixStr, fullMatrixStr: global matrixExpr, errorSwitch, infoStr: use Maplets:-Tools, Maplets:-Elements in clearSteps(): matrixExpr:='matrixExpr'; mlStr :=""; errorSwitch:=0; # by setting errorSwitch to 0 it shows that start has been pressed, if an error occurs it goes to 1. infoStr := "Initializing": Set('TB'=infoStr): matrixStr := Get('TF_fun'): if matrixStr="" then infoStr := "Nothing has been entered": errorSwitch:=1; Set('TB'=infoStr): # error "No matrix has been entered": end if: fullMatrixStr := matrixStr; #cat("matrix(",matrixStr,")"): #matrixExpr := parse(fullMatrixStr): try matrixExpr := parse(fullMatrixStr): catch: infoStr := "Parsing error, enter a valid matrix"; errorSwitch:=1; end try; if errorSwitch<>1 then if type(eval(matrixExpr), matrix) then infoStr := "Apply a row operation"; errorSwitch:=0; #switch this back to 0 upon success don't think this is needed tho else infoStr := "Input not of type matrix"; errorSwitch:=1; fi; fi: if errorSwitch<>1 then mlStr := iniMathML(eval(matrixExpr)): fi: # I guess I should check if the matrix is # already in reduced from or is degenreate # in some way. Set('ML'=mlStr): Set('TB'=infoStr): #Maplets:-Display(Maplet(MessageDialog(mlStr))): #Set('TB'=mlStr): end use: end proc: # end startRule # ######################################################### Xswap := proc(r1,r2) local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[swaprow](eval(matrixExpr),r1,r2); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Interchange row ", r1, " and row ", r2): Set('TB'=infoStr): Set('ML'=mlStr): fi: #Maplets:-Display(Maplet(MessageDialog(mlStr))): #Set('TB'=mlStr): end use: end proc: ######################################################### Xmultiply := proc(r1,expr1) local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[mulrow](eval(matrixExpr),r1,expr1); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Multiply row ", r1, " by ", expr1): Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################### Xadd := proc(r1,r2,expr1) local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[addrow](eval(matrixExpr),r1,r2,expr1); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Add ", expr1, " times row ", r1, " to row ", r2 ): Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################### Xgausselim := proc() local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[gausselim](eval(matrixExpr)); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Gaussian form"): Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################### Xgaussjord := proc() local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[rref](eval(matrixExpr)); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Gauss-Jordon form"): Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################### Xbacksub := proc() local mlStr, infoStr: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then # also need to check that it can be back subsituted, or just trap errors mlStr := Get('ML'): infoStr := Get('TB'): matrixExpr:=linalg[backsub](eval(matrixExpr)); mlStr := addMathML(mlStr,eval(matrixExpr)): infoStr := cat(infoStr, "\n", "Back substituted"): Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################### Xundo := proc() # search infoStr backwards for last \n and then cut so it removes last statement # # Since only a simple matrix is used, we can use the Import command on the parsed presentation MathML # # This is probably not a very good way to allow an undo function but I think it is better than # storing the matrix at each stage, or storing the steps in a way so they can be reversed. # local mlStr, infoStr, revStr, lastMatrixStart, lastMatrixEnd, mlStrRev, lastNewline: global matrixExpr: use Maplets:-Tools, Maplets:-Elements in if noErrors() then # also need to check for other errors mlStr := Get('ML'): infoStr := Get('TB'): #### this code removes the last matrix from the displayed MathML revStr:=StringTools[Reverse](mlStr): lastMatrixStart:=searchtext(StringTools[Reverse](" ="),revStr)+length(" =")-1; lastMatrixEnd:=searchtext(StringTools[Reverse](""),revStr); mlStrRev:=cat(substring(revStr,1..lastMatrixEnd-1), substring(revStr,lastMatrixStart+1..-1)); mlStr:=StringTools[Reverse](mlStrRev); ##### end ##### this code now parses the NEW mlStr (uses the mlStrREv to be more efficient) ## to find the last 'good' matrix and imports it lastMatrixStart:=searchtext(StringTools[Reverse](""),mlStrRev)+length("")-1; lastMatrixEnd:=searchtext(StringTools[Reverse](""),mlStrRev); matrixExpr:=MathML[Import](cat("", StringTools[Reverse](substring(mlStrRev,lastMatrixEnd..lastMatrixStart)), "" )); ##### end ##### now the easy bit, look in the comments string to remove the last comment lastNewline:=searchtext("\n",StringTools[Reverse](infoStr)); infoStr:=substring(infoStr,1..length(infoStr)-lastNewline); ##### #infoStr := cat(infoStr, "\n", "last step undone"): # later change this so that the comment is removed too Set('TB'=infoStr): Set('ML'=mlStr): fi: end use: end proc: ######################################################## noErrors := proc() local mlStr, infoStr: global errorSwitch: use Maplets:-Tools, Maplets:-Elements in if errorSwitch=0 then return true; else startRule(); if errorSwitch=0 then return true; else return false; fi; fi; end use: end proc: ############################################################ runRowOpsMaplet := proc() local maplet, color, lightcolor, darkcolor: color := 'background'="#DDFFFF": lightcolor := 'background'="#EEFFFF": darkcolor := 'background'="#CCFFFF": use Maplets, Maplets:-Elements in maplet := Maplet( 'onstartup'=RunWindow('rowOpsWin'), Font['F1']('family'="Default",italic='true','size'=12), Font['F2']('family'="Default", 'bold'='true', 'size'=14), Window['rowOpsWin']('menubar'='rowOpsMB', 'resizable'='false', 'title'="Row operations Maplet", BoxColumn(color, 'inset'=0, 'spacing'=0, BoxRow(color, 'border'='true','inset'=0,'spacing'=3, 'caption'="Enter a matrix", Label('caption'="Enter a matrix ", 'font'=F2,'background'="#DDFFFF"), TextField['TF_fun']('value'="matrix([[2,-1,-2,2],[-1,2,3,2],[3,5,1,0]])", lightcolor, 'width'=36), Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), Button("Start", 'onclick'='A_start', lightcolor, 'tooltip'="Initialize") ), # end BoxRow BoxRow(color, 'inset'=0,'spacing'=0, BoxColumn(color, 'border'='true', 'inset'=0, 'spacing'=0, 'caption'="Problem Status", BoxRow(color, MathMLViewer['ML'](#'value' = MathML:-ExportPresentation(matrix([[2,-1,-2,2],[-1,2,3,2],[3,5,1,0]])), 'height'=470, 'width'=400, lightcolor) # MathMLViewer['ML']('value' = "2-1-22-12323510",'height'=470, 'width'=400, lightcolor) ) # end BoxRow ), # end BoxColumn BoxColumn(color, 'inset'=0, 'inset'=0, 'spacing'=0, BoxRow(color, 'border'='true', 'caption'="Messages", 'inset'=0, 'spacing'=0, BoxCell( TextBox['TB'](lightcolor, 'editable'='false', 'value'="", 'tooltip'="Messages", 'font'='F1', 'height'=3 ) # end TextBox ) # end BoxCell ), # end BoxRow BoxColumn(color, 'border'='true', 'inset'=0, 'spacing'=0, 'caption'="Row operations", # swap BoxRow(color, 'halign'='left', 'inset'=0, 'spacing'=0, BoxCell('halign'='left', Button['B_swap']("Swap", 'onclick'='A_swap', lightcolor, 'tooltip'="Intercahange rows") ), # BoxCell Label('caption'=" row ", 'font'=F2,'background'="#DDFFFF"), DropDownBox['swapr1'](["1", "2", "3", "4"]), Label('caption'=" and row ", 'font'=F2,'background'="#DDFFFF"), DropDownBox['swapr2'](["1", "2", "3", "4"]) ), # BoxRow # multiply BoxRow(color, 'halign'='left', 'inset'=0, 'spacing'=0, BoxCell('halign'='left', Button['B_multiply']("Multiply", 'onclick'='A_multiply', lightcolor, 'tooltip'="Multiply row by an expression") ), # BoxCell Label('caption'=" row ", 'font'=F2,'background'="#DDFFFF"), DropDownBox['mrow'](["1", "2", "3", "4"]), Label('caption'=" by ", 'font'=F2,'background'="#DDFFFF"), TextField['mexpr'](5, 'value' ="1") ), # BoxRow # add BoxRow(color, 'halign'='left', 'inset'=0, 'spacing'=0, BoxCell('halign'='left', Button['B_add']("Add", 'onclick'='A_add', lightcolor, 'tooltip'="Add a row to another") ), # BoxCell Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), TextField['aexpr'](5, 'value' ="0"), Label('caption'=" times row ", 'font'=F2,'background'="#DDFFFF"), DropDownBox['arow1'](["1", "2", "3", "4"]), Label('caption'=" to row ", 'font'=F2,'background'="#DDFFFF"), DropDownBox['arow2'](["1", "2", "3", "4"]) ) # BoxRow ), # end BoxLayout # gaussian elimination, row reduced, back subsituted A_gauselim, A_gaussjord, A_backsub, BoxColumn(color, 'border'='true', 'inset'=0, 'spacing'=0, # 'caption'="Eliminations", BoxRow(color, 'halign'='left', 'inset'=0, 'spacing'=0, BoxCell('halign'='left', Button['B_el']("G elimin", 'onclick'='A_gausselim', lightcolor, 'tooltip'="Gaussian elimination on a matrix") ), # BoxCell Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), BoxCell('halign'='left', Button['B_el2']("G-J elim", #Gauss-Jordanelimination 'onclick'='A_gaussjord', lightcolor, 'tooltip'="Gauss-Jordan elimination (Reduced row echelon form)") ), # BoxCell Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), BoxCell('halign'='left', Button['B_el3']("Back sub", #Backsubstitution 'onclick'='A_backsub', lightcolor, 'tooltip'="Back substitution on a matrix") ) # BoxCell ) # BoxRow ), # end BoxColumn # clear and close and undo butoons BoxColumn(color, 'border'='true', 'inset'=0, 'spacing'=0, # 'caption'="", BoxRow(color, 'halign'='left', 'inset'=0, 'spacing'=0, BoxCell('halign'='left', Button("Undo", 'onclick'='A_undo', lightcolor, 'tooltip'="Undo the previous operation") ), # BoxCell Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), BoxCell('halign'='left', Button("Clear", 'onclick'='A_clear', lightcolor, 'tooltip'="Clear the problem history") ), # BoxCell Label('caption'=" ", 'font'=F2,'background'="#DDFFFF"), BoxCell('halign'='left', Button("Close", Shutdown(), 'tooltip'="Close the maplet", lightcolor) ) # BoxCell ) # BoxRow ) # end BoxLayout ) # end BoxColumn ) # end BoxRow ) # end BoxColumn ), # end Window ############################################################ MenuBar['rowOpsMB']( Menu("File", MenuItem("Clear", 'onclick'='A_clear'), MenuSeparator(), MenuItem("Close", Shutdown()) ), # end Menu/File Menu("Help", MenuItem("Using this Maplet", 'onclick'=RunWindow('helpWin')) ) # end Menu/Help ), # end MenuBar ############################################################ Window['helpWin']( 'resizable'='false', 'title'="Using the Elementary Row Operations Maplet", BoxColumn(color, 'border'='true', 'inset'=0, 'spacing'=8, BoxCell( TextBox('height'=24, 'width'=40, lightcolor, 'foreground'="#333399", 'editable'='false', 'font'='F2', 'value'=helpStr ) # end TextBox ), # end BoxCell BoxRow(color, 'inset'=0, 'spacing'=0, Button("Close", lightcolor, CloseWindow('helpWin')) ) # end BoxRow ) # end BoxColumn ), # end helpWin ############################################################ Action['A_start']( Evaluate('function'='startRule()') ), # end A_start Action['A_clear']( Evaluate('function'='clearSteps()') ), # end A_clear ############################################################ Action['A_swap']( Evaluate('function'='Xswap(swapr1,swapr2)') ), Action['A_multiply']( Evaluate('function'='Xmultiply(mrow,mexpr)') ), Action['A_add']( Evaluate('function'='Xadd(arow1,arow2,aexpr)') ), Action['A_gausselim']( Evaluate('function'='Xgausselim()') ), Action['A_gaussjord']( Evaluate('function'='Xgaussjord()') ), Action['A_backsub']( Evaluate('function'='Xbacksub()') ), Action['A_undo']( Evaluate('function'='Xundo()') ), ############################################################ Action['A']() ) : # end maplet Maplets[Display](maplet) : end use: # end use end proc: # end runRowOpsMaplet ############################################################ end module: # end RowOpsMaplet() RowOpsMaplet:-runRowOpsMaplet();