// 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