// James Brink 11/18/2021) // Note: This program allows 1, 2, or 3 variables. To keep things // simple, for 1 variable, dirivatives are called jacobians. let can; let rightMiddle; let fLabel = []; let fInput = []; let f = []; // function strings let fApprox = []; // let fVal = [] // function values let deltaLabel = []; let deltaInput = []; let delta = []; let jacobianLabel = []; let jacobianInput = []; let jacobian = []; // Jacobian strings let jacobianVal = []; // Jacobian matrix value let fDefined = []; let allFDefined = true; let variables = ["x", "y", "z"]; let initValues = []; // initial values of x and y (string) let initValueLabel = []; // used to display x, y, and z let initValueInput = []; let secondValueLabel = []; // only used for the secant method let secondValueInput = []; let secondValueDiv; let allValuesDefined; // refers to initial values of x and y let value = []; // current values of x and y let secondValue = []; // second initial string for secant method let secValue = []; // second initial value for secant method let valueLabel = []; let valueInput = []; // used to display current value of variables let x, y; // current values of value, used for evaluation let iterateBtn, solveBtn; let iterateList = []; let iterateNum = 0; let converged = false; let numberFunctions; let radioBtns; let modeBtns; let change = []; // change iterate values let differences = []; // magnitudes of last 3 changes let s1a let num_f = 2; let mode = 0; const NEWTON_MODE = 0; const APPROX_MODE = 1; const SECANT_MODE = 2; const MAX_FUNCTIONS = 3; // Examples: let example = []; let exampleRadio; // radio buttons for the examples // not used let examplesRadio = [] const EXAMPLE_NAME = 19; // location of the name function setup() { // initialize names for divisions p5left = document.getElementById("p5-left"); p5right = document.getElementById("p5-right"); rightTop = document.getElementById("rightTop"); rightMiddle = document.getElementById("rightMiddle"); rightBottom = document.getElementById("rightBottom"); can = createCanvas(300, 400); can.parent(p5left); // mode buttons let s0 = createSpan("Mode:
"); s0.parent(rightTop); modeBtns = HTMLforRadioButton("mode", "Newton's method", "getMode()", true, NEWTON_MODE); newtonRadioBtn = displayHTMLElements(modeBtns, rightTop, "inline-block"); modeBtns = HTMLforRadioButton("mode", "Approximate Newton's", "getMode()", false, APPROX_MODE); approxRadioBtn = displayHTMLElements(modeBtns, rightTop, "inline-block"); modeBtns = HTMLforRadioButton("mode", "Secant method", "getMode()", false, SECANT_MODE); secantRadioBtn = displayHTMLElements(modeBtns, rightTop, "inline-block"); // number of functions buttons let s0a = createSpan("

Number of functions:   "); s0a.parent(rightTop); radioBtns = HTMLforRadioButton("numFunctions", '1  ' , "getNumFunctions()", false, 1); oneRadioBtns = displayHTMLElements(radioBtns, rightTop, "inline-block"); radioBtns = HTMLforRadioButton("numFunctions", '2  ', "getNumFunctions()", true, 2); twoRadioBtns = displayHTMLElements(radioBtns, rightTop, "inline-block"); radioBtns = HTMLforRadioButton("numFunctions", '3  ', "getNumFunctions()", false, 3); threeRadioBtns = displayHTMLElements(radioBtns, rightTop, "inline-block"); // initialize f and jacobians in case they not defined // before save and show examples operations for (let i = 0; i < MAX_FUNCTIONS; i++) { f[i] = ""; value[i] = ""; jacobianInput[i] = []; jacobian[i] = []; deltaInput[i] = []; for (let j = 0; j < MAX_FUNCTIONS; j++) { jacobianInput[i][j] = createInput(""); // required for user input jacobianInput[i][j].parent(rightMiddle); jacobian[i][j] = ""; } secondValue[i] = ""; } setupFunctions(); // create buttons for displaying and reading examples showExampleDataBtn = createButton("Show current setup"); showExampleDataBtn.parent(p5right); showExampleDataBtn.mousePressed(showExampleData); saveExampleBtn = createButton("Save as a temp example"); saveExampleBtn.parent(p5right); saveExampleBtn.mousePressed(saveExample); // finally, initialize the examples setupExamples(); displayExamples(); } // setup function draw() { background(220); fill("black"); switch (num_f) { case 1: text(" \t" + myFormat("x", 17), 10, 20); break; case 2: text(" \t" + myFormat("x", 17) + " " + myFormat("y", 17), 10, 20); break; case 3: text(" \t" + myFormat("x", 11) + " " + myFormat("y", 11) + " " + myFormat("z", 11), 10, 20); } let line = 0; for (let i = max(0, iterateNum - 18); i < iterateNum; i++) { if (i == iterateNum - 1 && converged) { fill("red"); } else { fill("black"); } if (num_f == 1) { text(i + "\t" + myFormat(iterateList[0][i],17), 10, 20 * line + 40); } else if (num_f == 2) { text(i + "\t" + myFormat(iterateList[0][i],17) + " " + myFormat(iterateList[1][i],17), 10, 20 * line + 40); } else { text(i + "\t" + myFormat(iterateList[0][i], 11) + " " + myFormat(iterateList[1][i], 11) + " " + myFormat(iterateList[2][i], 11), 10, 20 * line + 40); } line++; } } // draw function getMode() { mode = int(getRadioValue("mode")); setupFunctions(); if (mode == APPROX_MODE) { for (let i = 0; i < num_f; i++) { deltaInput[i].value(".0001"); } } reset(); } // getMode function getNumFunctions() { num_f = int(getRadioValue("numFunctions")); setupFunctions(); // make sure functions and jacobians are blank. for (let i = 0; i < num_f; i++) { fInput[i].value(""); initValueInput[i].value(""); for (let j = 0; j < num_f; j++) { jacobianInput[i][j].value(""); } } reset(); iterateNum = 0; } // getNumFunctions function setupFunctions() { // used to create much of the inputs rightMiddle.innerHTML = ""; // establish double subscripts for (let i = 0; i < MAX_FUNCTIONS; i++) { jacobianLabel[i] = []; jacobianInput[i] = []; // jacobianInput[i] = []; // this was done in setup jacobianVal[i] = []; iterateList[i] = []; } switch (num_f) { case 1: params = "x"; break; case 2: params ="x, y"; break; case 3: params = "x, y, z"; break; } // create blanks for functions for (let i = 0; i < MAX_FUNCTIONS; i++) { if (num_f == 1) { fLabel[i] = createSpan("
f(x)       "); } else { fLabel[i] = createSpan("
f" + i + "(" + params + ") "); } fLabel[i].parent(rightMiddle); fInput[i] = createInput(f[i]); fInput[i].parent(rightMiddle); fInput[i].changed(inputF); // set up on change fInput[i].size(350); } // start with partials let s1 = createSpan("
"); s1.parent(rightMiddle); // Blanks for deltas and partials are created in both cases // in order to simplify switching between modes. // Create blanks for a deltas for (let i = 0; i < MAX_FUNCTIONS; i++) { deltaLabel[i] = createSpan("
Δ" + variables[i] + "   "); deltaLabel[i].parent(rightMiddle); deltaInput[i] = createInput(delta[i]); deltaInput[i].parent(rightMiddle); deltaInput[i].changed(inputF); deltaInput[i].size(70); if (i >= num_f || mode != APPROX_MODE) { deltaLabel[i].hide(); deltaInput[i].hide(); } // Create blanks for partials (Jacobian) for (let j = 0; j < MAX_FUNCTIONS; j++) { if (num_f == 1 && i == 0 && j == 0) { jacobianLabel[0][j] = createSpan("
df(x)/dx     "); } else { jacobianLabel[i][j] = createSpan("
δf" + i + "(" + params + ")/δ" + variables[j]); } jacobianLabel[i][j].parent(rightMiddle); jacobianInput[i][j] = createInput(jacobian[i][j]); jacobianInput[i][j].parent(rightMiddle); jacobianInput[i][j].changed(inputF); // set up on change jacobianInput[i][j].size(330); if (mode == APPROX_MODE && i >= num_f) { jacobianLabel[i][j].hide(); jacobianInput[i][j].hide(); } } } // create blanks for initial values let s2 = createSpan("

Initial Values of Variables
"); s2.parent(rightMiddle); for (let i = 0; i < MAX_FUNCTIONS; i++) { initValueLabel[i] = createSpan("   " + variables[i] + " "); initValueLabel[i].parent(rightMiddle); initValueInput[i] = createInput(initValues[i]); /////// initValueInput[i].parent(rightMiddle); initValueInput[i].changed(inputInitValue); initValueInput[i].size(80); } // blanks and panel for second starting values for secant method secondValueDiv = createDiv(""); secondValueDiv.parent(rightMiddle); s1a = createSpan("
Second Initial Values of Variables for" + " Secant Method
"); s1a.parent(secondValueDiv); for (let i = 0; i < MAX_FUNCTIONS; i++) { secondValueLabel[i] = createSpan("   " + variables[i] + " "); secondValueLabel[i].parent(secondValueDiv); secondValueInput[i] = createInput(secondValue[i]); secondValueInput[i].parent(secondValueDiv); secondValueInput[i].changed(inputInitValue); // handle change in value secondValueInput[i].size(80); if (mode != SECANT_MODE) { secondValueDiv.hide(); } } // create reset button let s2a = createSpan('

' + "Click after changing any of the above or to repeat. "); s2a.parent(rightMiddle); iterateBtn = createButton("Reset"); iterateBtn.parent(rightMiddle); iterateBtn.mousePressed(reset); // Iterate and solve buttons in right bottom. First clear it. rightBottom.innerHTML = ""; iterateBtn = createButton("Iterate"); iterateBtn.parent(rightBottom); iterateBtn.mousePressed(iterate); let s3a = createSpan("     "); s3a.parent(rightBottom); solveBtn = createButton("Solve"); solveBtn.parent(rightBottom); solveBtn.mousePressed(solve); // create blanks for current values let s4 = createSpan("
Current Values of Variables
"); s4.parent(rightBottom); for (let i = 0; i < MAX_FUNCTIONS; i++) {//[2] will be hidden if num_f == 3 valueLabel[i] = createSpan("   " + variables[i] + " "); valueLabel[i].parent(rightBottom); valueInput[i] = createInput(); valueInput[i].parent(rightBottom); valueInput[i].size(80); } // hide unneeded blanks for (let i = num_f; i < MAX_FUNCTIONS; i++) { fLabel[i].hide(); fInput[i].hide(); initValueLabel[i].hide(); initValueInput[i].hide(); secondValueInput[i]; valueLabel[i].hide(); valueInput[i].hide(); secondValueLabel[i].hide(); secondValueInput[i].hide(); } for (let i = 0; i < MAX_FUNCTIONS; i++) { for (let j = 0; j < MAX_FUNCTIONS; j++) { if (i >= num_f || j >= num_f || mode != NEWTON_MODE) { jacobianLabel[i][j].hide(); jacobianInput[i][j].hide(); } } } } // setupFunctions function inputF() { // called by setup and everytime a function is changed allFDefined = true; // look at inputs for f for (let i = 0; i < num_f; i++) { f[i] = trim(fInput[i].value()); } // in the approximation mode, check inputs for delta if (mode == APPROX_MODE) { // set approximate jacabian for (let i = 0; i < num_f; i++) { delta[i] = trim(deltaInput[i].value()); } } else if (mode == NEWTON_MODE) { for (let i = 0; i < num_f; i++) { for (let j = 0; j < num_f; j++) { jacobian[i][j] = trim(jacobianInput[i][j].value()); } } } converged = false; // fill(0); // reset the color } // inputf function inputInitValue() { allValuesDefined = true; for (let i = 0; i < num_f; i++) { initValues[i] = trim(initValueInput[i].value()); if (initValues[i] == '') { allValuesDefined = false; } else { // initial value was specified try { if (initValues[i] != "") { value[i] = eval(initValues[i]); } } catch (err) { alert("Cannot evaluate an initial value"); return; } iterateList[i][0] = value[i]; iterateNum = 1; if (mode == SECANT_MODE) { secondValue[i] = trim(secondValueInput[i].value()); if (secondValue[i] == '') { allValuesDefined = false; } else { try { if (secondValue[i] != "") { secValue[i] = eval(secondValue[i]); } } catch (err) { alert("Cannot evaluate a second value"); return; } iterateList[i][1] = secValue[i]; iterateNum = 2; } // Interchange secValue and values because the rest of the program // assumes that values is the most recent value. let temp = secValue[i]; secValue[i] = value[i]; value[i] = temp; } // end of mode == SECANT_MODE } // end of all initial imput value are specified } // end for (let i } //inputInitValues function approximateJacobian() { // assume x, y, and z already have values for (let i = 0; i < num_f; i++) { for (let j = 0; j < num_f; j++) { let newDelta = float(delta[j]); // make sure adding delta[j] as float switch (j) { case 0: x = value[j] + newDelta; break; case 1: y = value[j] + newDelta; break; case 2: z = value[j] + newDelta; break; } let ff = eval(f[i]); switch (j) { case 0: x = value[j]; break; case 1: y = value[j]; break; case 2: z = value[j]; break; } let approxDer = (ff - fVal[i]) / delta[j]; //approx partial derivative jacobianVal[i][j] = approxDer; } } } // approximateJacobian function handleSecantMode() { // Creates a jacobian based on the last two iterates // Assume x, y, and z already have values // Similar to approximateJacobian except it uses difference of last two // iterates for (let i = 0; i < num_f; i++) { for (let j = 0; j < num_f; j++) { let newDelta = secValue[j] - value[j]; // alert ("i: " + i + " j: " + j + " value[j]: " + value[j] + " secValue[j]: " + secValue[j] + " newDelta: " + newDelta); switch (j) { case 0: x = secValue[j]; break; case 1: y = secValue[j]; break; case 2: z = secValue[j]; break; } let ff = eval(f[i]); // alert("i: " + i + " j: " + j +" old x: " + x + " y:" + y +" ff: " + ff + " fVal[i]: " + fVal[i]); switch (j) { case 0: x = value[j]; break; case 1: y = value[j]; break; case 2: z = value[j]; break; } fVal[i][j] = eval(f[i]); // alert("i: " + i + " j: " +j + " new x: " + x + " fVal[i]: " + fVal[i] + "(ff - fVal[i]: " + (ff - fVal[i])); let approxDer = (ff - fVal[i]) / newDelta; //approx partial derivative jacobianVal[i][j] = approxDer; // alert("i: " + i + " j: " +j + " jacobianVal[i][j]: " + jacobianVal[i][j]); } } // alert("jac[0][0] jac[0][1]: " + jacobianVal[0][0] + " " +jacobianVal[0][1] // + "\n" +"jac[1][0] jac[1][1]: " + jacobianVal[1][0] + " " +jacobianVal[1][1]); // move the current value to the previous value for (let i = 0; i < num_f; i++) { secValue[i] = value[i]; } } // handleSecondMode function evaluateJacobianAndChange() { // evaluate fVal if (allValuesDefined && allFDefined){ x = value[0]; y = value[1]; z = value[2]; try { for (let i = 0; i < num_f; i++) { fVal[i] = eval(f[i]); } } catch (err) { alert("Cannot evaluate a function"); return false; } } if (mode == APPROX_MODE) { approximateJacobian(); } else if (mode == SECANT_MODE) { handleSecantMode(); // creates a "jacobian" for this mode } else { // evalute jacobian try { for (let i = 0; i < num_f; i++) { for (let j = 0; j < num_f; j++) { jacobianVal[i][j] = eval(jacobian[i][j]); } } } catch (err) { alert("Cannot evaluate a partial derivative"); return false; } } // augment jacobianVal with fVal and find inverseJacobian * fVal for (let i = 0; i < num_f; i++) { jacobianVal[i][num_f] = fVal[i]; } solveLinearSystem(jacobianVal, num_f, 1); // copy the differences in the third column into change for (let i = 0; i < num_f; i++) { change[i] = jacobianVal[i][num_f]; } return true; } // evaluateJacobianAndChange function iterate() { // check to make sure all functions and initial values are defined for (let i = 0; i < num_f; i++) { if (fInput[i].value() == "") { alert("Warning:\nYou must define all functions before iterating."); return false; } } if (mode == NEWTON_MODE) { if (num_f == 1) { if (jacobian[0][0] == "") { alert("Warning:\nYou must define the derivative before iterating."); return false; } } else { for (let i = 0; i < num_f; i++) { for (let j = 0; j < num_f; j++) { if (jacobian[i][j] == "") { alert("Warning:" + "\nYou must define all the partials before iterating."); return false; } } } } } for (let i = 0; i < num_f; i++) { if (initValueInput[i].value() == "") { alert("Warning:\nYou must supply initial values for all variables before" + " iterating."); return false; } if (mode == SECANT_MODE && secondValueInput[i].value() == "") { alert("Warning:\nYou must supply the second set of initial values for" + " all variables before iterating."); return false; } } converged = false; if (!evaluateJacobianAndChange()) { return false; } // test for convergence and calculate next iterate let maxChange = 0; let magnitude = 0; let tolerance = 0.0000000001; if (mode == APPROX_MODE) { tolerance = 0.0000000000001; } else if (mode == SECANT_MODE) { tolerance = 0.00000000000001; } for (let i = 0; i < num_f; i++) { value[i] = value[i] - change[i]; // calculate next iterate valueInput[i].value(value[i]); // display iterate in valueInput if (abs(value[i]) < tolerance) { valueInput[i].value(0.0); // make sure really small values show as 0 } maxChange += abs(change[i]); magnitude += abs(value[i]); iterateList[i][iterateNum] = value[i]; } if (maxChange < tolerance * magnitude || magnitude < tolerance) { converged = true; } differences[0] = differences[1]; // keep track of last 3 changes differences[1] = differences[2]; // so convergence rate can be checked differences[2] = maxChange; fill(0); iterateNum++; return true; } // iterate function solve() { let cont; while (!converged) { if (iterateNum <= 20) { cont = iterate(); if (!cont) { return; } } else if (differences[1] < differences[0] && differences[2] < differences[1]) { alert("Warning:\nThe iterations may be converging slowly.\n" + "You can iterate some more, if desired."); return; } else { alert("Warning:\nThe iterations do not seem to converge."); return; } } } // solve function reset() { iterateNum = 1; converged = false; fill(0); // reset the color for (let i = 0; i < num_f; i++) { valueInput[i].value(""); // clear the current values } iterateNum = 0; inputF(); inputInitValue(); } // reset function outputInfo() { let s = "Functions: "; for (let i = 0; i < num_f; i++) { s += "\n" + f[i]; } s += "\nJacobian:"; for (let i = 0; i < num_f; i++) { s += "\n"; for (let j = 0; j < num_f; j++) { s += jacobian[i][j] + "\t" } } s += "\nInverse jacobian:"; for (let i = 0; i < num_f; i++) { s += "\n"; for (let j = 0; j < num_f; j++) { s += invJacobian[i][j] + "\t" } } s += "\nCurrent x and y values:"; for (let i = 0; i < num_f; i++) { s += "\n" + value[i]; } s += "\nFunction values: "; for (let i = 0; i < num_f; i++) { s += "\n" + fVal[i]; } s += "\nJacobian values:"; for (let i = 0; i < num_f; i++) { s += "\n"; for (let j = 0; j < num_f; j++) { s += jacobianVal[i][j] + "\t" } } s += "\nInverse jacobian values:"; for (let i = 0; i < num_f; i++) { s += "\n"; for (let j = 0; j < num_f; j++) { s += invJacobianVal[i][j] + "\t"; } } alert(s); } // outputInfo function myReplaceAll(st, from, to) { // replaces every occurance of "from" in st with "to" and // returns the result. let array = st.split(from); let s = array[0]; for (let i = 1; i < array.length; i++) { s += to + array[i]; } return s; } // myReplaceAll // an alert with data needed for an example // based on the current graph function showExampleData() { let s = " example[??] = [" for (let i = 0; i < MAX_FUNCTIONS; i++) { s += '"' + fInput[i].value() + '",'; } for (let i = 0; i < MAX_FUNCTIONS; i++) { s += '\n '; for (let j = 0; j < MAX_FUNCTIONS; j++) { s += '"' + jacobianInput[i][j].value() + '",'; } } s += '\n'; for (let i = 0; i < MAX_FUNCTIONS; i++) { s += initValueInput[i].value() + ","; } for (let i = 0; i < MAX_FUNCTIONS; i++) { s += secondValueInput[i].value() + ","; } s += '\n' + num_f + ","; s += '\n"???? Example name ????"];'; s += '\n\n'; s += 'You can copy the above and paste it into setupExamples().\n' + 'Replace the example number [??] and example name appropriately.\n' + 'Examples are printed in the order of the example numbers [].'; var r = confirm('If you the want to setup to be sent to a file, click' + ' "OK". If you click "Cancel" the setup will be sent to a' + ' regular alert box. If your browser allows copying from the' + ' alert box, this is the easier method'); if (r) { const writer = createWriter("showSetup.txt"); writer.print(s); writer.close(); writer.clear(); alert('The setup was writen to "showSetup.txt"'); } else { alert(s); } } // showExampleData function saveExample() { // copies current data in order to make a new temporary example let newName = prompt("What do you want the setup to be called?"); if (newName == "" ||newName == null) { return; } let ex = example.length; example[ex] = []; for (let i = 0; i < MAX_FUNCTIONS; i++) { example[ex][i] = fInput[i].value(); } let k = MAX_FUNCTIONS; for (let i = 0; i < MAX_FUNCTIONS; i++) { for (let j = 0; j < MAX_FUNCTIONS; j++) { example[ex][k] = jacobianInput[i][j].value(); k++; } } for (let i = 0; i < MAX_FUNCTIONS; i++) { example[ex][k] = initValueInput[i].value(); k++; } for (let i = 0; i < MAX_FUNCTIONS; i++) { example[ex][k] = secondValueInput[i].value(); k++; } example[ex][EXAMPLE_NAME - 1] = num_f; example[ex][EXAMPLE_NAME] = newName; let radio = HTMLforRadioButton("examplesResult", '' + example[ex][EXAMPLE_NAME] +'', "getRadioValueExamples()", true, ex); displayAnExample(ex); useExample(ex); } // saveExample function setupExamples() { // Examples must be numbered consecutively starting 0 // When there are only 2 functions, use "" for unneed functions and values // The format of the example[i] vector: // [0] .. [2]: functions f0, f1, f2 (strings) (f2 unused if num funct = 2) // [3] .. [11]: partial functions f0x, f0y, f0z, f1x, f1y, f1z, ... (string) // [12] .. [14]: x, y and z (number or string) // [15] .. [17]: x, y and z (number or string) 2nd values for secant method // [18] Number of functions ( EXAMPLE_NAME - 1] // [19]: display title (string) ( EXAMPLE_NAME = 19 ) example[0] = ["x**2 - 4", "", "", "2 * x", "", "", "", "", "", "", "", "", 4, "", "", 3.5, "", "", 1, "Parabola y = x**2 - 4, Solutions: x = ±2"], example[1] = ["x**2 + y**2 - 1","x + 2 * y", "", "2 * x","2 * y","","1","2","","","","", 1, -.5,"", .9, -.45, "", 2, "Circle and line (One solution:" + "
x: 0.8944271909999159," + "
y: -0.4472135954999579)"]; example[2] = ["x**2 + 2 * x + y**2 + 2 * y - 2", "x**2 - 2 * x + y**2 - 2 * y - 2", "", "2 * x + 2","2 * y + 2","", "2 * x - 2","2 * y - 2","", "","","", 1,-2,"", ".8", "-1.2", "", 2, "Two circles centered at (1,1) and (-1, -1)" + "
Solutions: (-1,1) and (1,-1)"]; example[3] = ["y - x**2", "x - y**2","", "-2 * x", "1", "","1", "-2 * y","","","","", 2, 2, "", 1.5, 1.3, "", 2, "2 parabolas, solutions (1,1) and (0, 0)"]; example[4] = ["x","y","", "1","0","", "0","1","", "","","", 2,5,"", 1, 4, "", 2, "Straight lines through origin.
Only solution: (0, 0)"]; example[5] = ["y - sin(x)","x**2 + y**2 - 1","", "-cos(x)","1","", "2 * x ","2 * y ","", "","","", 1,1,"", 0.5, 0.7, "", 2, "Unit circle and sin x, Solutions:
" + " x = ±0.7390851332151607,
" + " y = ±0.6736120291832148
(slightly slow convergence)"]; example[6] = ["y - log(x)","x**2 + y**2 - 1","", "-1/x","1","", "2 * x ","2 * y ","", "","","", .1,-1,"", 0.2, -0.98, "", 2, "Unit circle and natual log(x): Solutions:
" + "(1, 0) and x = 0.3998912742866619,
" + "              " + "   y = -0.9165625831056982"]; example[7] = ["3 * x - cos(y * z) - .5", "x**2 - 81 * (y + 0.1)**2 + sin(z) + 1.06", "exp(-x * y) + 20 * z + (10 * PI -3)/3", "3", "z * sin(y * z)", "y * sin(y * z)", "2 * x", "-162 * (y + 0.1)", "cos(z)", "-y * exp(-x * y)", "-x * exp(-x * y)", "20", 0.1, 0.1, -0.1, 0.2, 0.05, -0.2, 3, "3D with trig and exp
Solution: (0.5, 0, -0.52359877)"]; example[8] = ["x**2 + y**2 - 4","y - 1","z - 1", "2 * x","2 * y","0", "0","1","0", "0","0","1", 7,2,3, 3.8, 1.5, 1.8, 3, "3D with cylinder and 2 planes:
" + "Solution3: (±1.7320508076, 1, 1)"]; example[9] = ["x**2 + y**2 +z**2 - 14","x**2 + y**2 - 5","y**2 + z**2 - 13", "2 * x","2 * y","2 * z", "2 * x","2 * y","0", "0","2 * y","2 * z", 2,3,5, 1.3, 2.2, 3.4, 3, "3D: sphere and 2 parabolic surfaces" + "
8 solutions: (±1, ±2, ±3)"]; example[10] = ["x**2 - 2 * x + 0.9999","","", "2 * x - 2","","", "","","", "","","", 1.5,,,1.2,,, 1, "Parabola with almost a double root.
" + "Some numerical calculation problems.
" + "Solutions: 1.1, 0.9"]; } // setupExamples function displayExamples() { let heading = createElement("h3","Examples"); heading.parent(p5left); let radio; for (let i = 0; i < example.length; i++) { displayAnExample(i); } } // displayExamples function displayAnExample(i) { let modeColor; switch (example[i][EXAMPLE_NAME - 1]) { case 1: modeColor = "red"; break; case 2: modeColor = "blue"; break; case 3: modeColor = "green"; break; } radio = HTMLforRadioButton("examplesResult", '' + example[i][EXAMPLE_NAME] +'', "getRadioValueExamples()", false, i); examplesRadio[i] = displayHTMLElements(radio, p5left, "block"); } // displayAnExample function useExample(ex) { num_f = example[ex][EXAMPLE_NAME - 1]; // 18 = EXAMPLE_NAME - 1 setupFunctions(); if (num_f == 1) { oneRadioBtns.checked = true; } else if (num_f == 2) { twoRadioBtns.checked = true; } else { threeRadioBtns.checked = true; } reset(); for (let i = 0; i < MAX_FUNCTIONS; i++) { if (i < num_f) { fInput[i].value(myReplaceAll(example[ex][i], "^$", ",")); } } let k = 3; for (let i = 0; i < num_f; i++) { deltaInput[i].value(0.0001); for (let j = 0; j < MAX_FUNCTIONS; j++) { if (i < num_f && j < num_f) { // because of how other parts works, both of these are needed jacobianInput[i][j].value(myReplaceAll(example[ex][k], "^$", ",")); jacobian[i][j] = myReplaceAll(example[ex][k], "^$", ","); } k++; } } k = 12; for (let i = 0; i < MAX_FUNCTIONS; i++) { initValueInput[i].value(example[ex][k]); k++; } for (let i = 0; i < MAX_FUNCTIONS; i++) { secondValueInput[i].value(example[ex][k]); secondValue[i] = example[ex][k]; k++; } // numPtsInput.value(example[ex][EXAMPLE_NAME]); // the name is not displayed anywhere except in example list inputF(); inputInitValue(); loop(); } // useExample function getRadioValueExamples() { let ex = int(getRadioValue("examplesResult")); useExample(ex); } // getRadioValueExamples function myFormat(v, n) { // returns a string of width 16 containing v formatted to n digits // unless v is not a number. It then returns v as a string. // If abs(v) < 1 then n-1 decimal digits are returned. // Expanded version of myNumberFormat. let display; try { if (typeof v != "number") { if (num_f <= 2) { display = "_________" + v + "________"; } else { display = "______" + v + "_____"; return display; } } else if (abs(v) < 1) { // its a small number display = v.toFixed(n-1); } else { display = v.toPrecision(n);// it is a number >= 1 } display = " " + display; return display.substr(display.length - (n + 2), (n + 2)); } catch(e) { } } // myFormat