JavaScript equation solver library - javascript

Is there a JavaScript library or function that will solve equations for variables?
Such as 9 = 3 + x and solve for x. But it should also solve more advanced equations that include sine, cosine, and tangent.

I'd like to propose nerdamer. It can algebraically solve up to quartic functions and it can numerically solve a range of functions. Another library to consider is Algebrite.
//solve linear equations
var x = nerdamer.solve('(x+1)*3=x-6', 'x');
console.log(x.toString());
//quadratic
var x2 = nerdamer.solve('x^2-8x+15', 'x');
console.log(x2.toString());
//quadratic algebraically
var x3 = nerdamer.solve('x^2-ax+3*b', 'x');
console.log(x3.toString());
//multiple roots
var x4 = nerdamer.solve('x^6+41*x^5+652*x^4+5102*x^3+20581*x^2+40361*x+30030', 'x');
console.log(x4.toString());
//functions - numerically around to zero up to a predefined range
var x5 = nerdamer.solve('cos(x)^2+sin(x-1)', 'x');
console.log(x5.toString());
//solve a system of linear equations
var x6 = nerdamer.solveEquations(['2x+y=7', 'x-y+3z=11', 'y-z=-1']);
console.log(x6.toString());
//solve a system of nonlinear equations
var x7 = nerdamer.solveEquations(['3*x^2/y=2', 'z*x*y-1=35', '5*z^2+7=52']);
console.log(x7.toString());
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/nerdamer.core.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Algebra.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Calculus.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Solve.js"></script>

You can approximate the solution by doing what excel calls "Goal Seek" - testing values for x until both sides of the equation approximately match. You can do this by splitting the equation by the "=" sign, replacing each occurence of x with a value, evaling both sides, and determining if the difference falls below a certain threshold. While relatively simple, there are flaws to this method though (other than the fact that it is an approximation), for example the algorithm may think the two sides are converging when in fact it is just a local min/max and will diverge after the difference falls just below your threshold. You'll also need to test multiple start points to solve equations with more than one solution.
For a program to actually solve an equation as a human would (by rearranging the two sides of the equation and applying inverse functions, derivatives/integrals and whatnot) is far more complex, and somehow feels entirely proprietary ;)

A quick search turns up algebra.js and js-solver. I don't know anything about them, but they seem legit. algebra.js has a nice OOP API, but doesn't appear to handle trigonometric functions.

Look at the script at Newton's Method Program for f(x)=0. It solves the equation using Newton's tangent method.

Ceres.js can find the solution to an array of equations of the form f(x) = 0. It is ported from C++ to JavaScript with Emscripten. The file is a bit large but if you need a really high performance solver this is your best bet. It runs in web-assembly so the speed is high.
Here is an example:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h2>Powell Function</h2>
<p>This is an example of the solution of the powell function using Ceres.js</p>
<textarea id="demo" rows="40" cols="170">
</textarea>
<script type="module">
import {Ceres} from 'https://cdn.jsdelivr.net/gh/Pterodactylus/Ceres.js#master/Ceres-v1.5.3.js'
var fn1 = function f1(x){
return (x[0]+10*x[1]);
}
var fn2 = function f2(x){
return (Math.sqrt(5)*(x[2]-x[3]));
}
var fn3 = function f3(x){
return Math.pow(x[1]-2*x[2],2);
}
var fn4 = function f4(x){
return Math.sqrt(10)*Math.pow(x[0]-x[3],2);
}
let solver = new Ceres()
solver.add_function(fn1) //Add the first equation to the solver.
solver.add_function(fn2) //Add the second equation to the solver.
solver.add_function(fn3) //Add the third equation to the solver.
solver.add_function(fn4) //Add the forth equation to the solver.
//solver.add_callback(c1) //Add the callback to the solver.
//solver.add_lowerbound(0,1.6) //Add a lower bound to the x[0] variable
//solver.add_upperbound(1,1.7) //Add a upper bound to the x[1] variable
solver.promise.then(function(result) {
var x_guess = [1,2,3,4] //Guess the initial values of the solution.
var s = solver.solve(x_guess) //Solve the equation
var x = s.x //assign the calculated solution array to the variable x
document.getElementById("demo").value = s.report //Print solver report
solver.remove() //required to free the memory in C++
})
</script>
</body>
</html>

Related

Equation variable transfer using JavaScript

I've been working with the algebra.js JavaScript library for a while and I can't find an answer to my problem.
I have a number of equations that varies in type;
(Linear, Radical, Quadratic, and Exponential)
And I need to switch the sides of two or more variables.
An example to the solution would be in a linear equation as follows:
x = 2y - 6 ----> y = (x/2) + 3
This simple example works because the x is in the simplest form and the equation is linear. However, when the equation looks like this:
7a + 4b = 9c + 5d
and I want to move the 9c to the left in order for it to look like this:
9c = 7a + 4b - 5d
It can't be done.
Moreover, these are all linear examples which makes them simple to process without using the library. But when it comes to an equation that looks like this:
y = z*(a^x)*b^(1-x)
and I want the left side to be (a^x), it doesn't seem that there is a way to do it.
So, is there any way to transfer a variable or a term to be alone in one side of the equation regardless to solving an equation?
It doesn't have to be algebra.js. It can be any library or code using JavaScript.
Have you read thru algebra.js documentation already? There is a direct statement how to do this -- see solve linear equation chapter, multiple variables subchapter, and its example:
var eq = new Equation(...)
var xAnswer = eq.solveFor("x");
var yAnswer = eq.solveFor("y");
Same solveFor() applies to other equation types as well.

Algorithm which adapt (solve) the complex equations ( implicit function f(x,y) )

I'm trying to adapt some equations (implicit f(x,y)) in order to be able list the Y for corresponding X-Value.
The equations could be e.g. as follows:
y^2 = x^3 + 2x - 3xy
(X^2+y^2-1)^3-x^2y^3=0
X^3+y^3=3xy^2-x-1
X^3+y^2=6xy/sqrt(y/x)
cos(PI*Y) = cos(PI.X)
Below you can see the plotted equations:
Hint, I don't know, but maybe this can be helpful, the following applies:
Y^2 + X^2 =1 ==> Y= sqrt(1-X^2)
The equations are to be adapt (substitution), so that they are expressed by X (not Y).
For y^2=x^3+2x-3xy by means of substitution results:
y1 = (-(-3x) - sqr((-3x)^2 - 4(-1)(x^3+2x)))/2*(-1)
y2 = (-(-3x) + sqr((-3x)^2 - 4(-1)(x^3+2x)))/2*(-1)
By means of adapted equations I will be able to vary X and get the corresponding Y.
See here the solution of Arkadiusz Raszeja-Solution for the equation y^2=x^3+2x-3xyThe solution of "Arkadiusz Raszeja" is for Quadratic equation, but I need an algorithm, so that e.g. all above equations can be solved.
var x,y;
for(var n=0; n<=10; n++) {
x=n;
y = (-(-3*x)-Math.sqrt(((-3*x)*(-3*x)) - 4*(-1)*((x*x*x)+2*x)))/(2*(-1));
alert(y);
}
The above alert(y); will show for Y something like below list:
X= 1 ; Y=0.79
X=2 ; Y=1.58
X=3 ; Y=2.79
X=4 ; Y=4.39
X=5 ; Y=6.33
X=6 ; Y=8.57
X=7 ; Y=11.12
X=8 ; Y=13.92
X=9 ; Y=16.98
X=10 ; Y= 20.29
My question is how can I program an algorithm, which will adapt (solve) the equations like in above example?
(You can also use a JS library like math.js, but not a plot or graph library. The solution should be in javascript)
Thanks in advance.
Hopefully I'm understanding your question correctly. Would nerdamer help? It can help solve algebraically up to a 3rd degree polynomial. The buildFunction method can be called to get a JS function which can be used for graphing. I use it in a somewhat similar manner on the project website in combination with function-plot.js
var solutions = nerdamer('y^2=x^3+2x-3x*y').solveFor('y');
//You'll get back two solutions since it's quadratic wrt to y
console.log(solutions.toString());
//You can then parse the solutions to native javascript function
var f = nerdamer(solutions[0]).buildFunction();
console.log(f.toString());
/* Evaluate */
var solutions = nerdamer('y^3*x^2=(x^2+y^2-1)').solveFor('y');
console.log(solutions.toString());
//You can then parse the solutions again to native javascript function
var f = nerdamer(solutions[0]);
var points = {};
for(var i=1; i<10; i++)
points[i] = f.evaluate({x: i}).text();
console.log(points)
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>
<script src="http://nerdamer.com/js/Algebra.js"></script>
<script src="http://nerdamer.com/js/Calculus.js"></script>
<script src="http://nerdamer.com/js/Solve.js"></script>
You could always just evaluate. This is slower than a pure JS function but it might be what you need. You'll have to probably use a try catch block for division by zero.
I'd like to point out that this problem cannot be solved exactly in general. The cited solution for the quadratic case (y^2) can be extended to the cubic case and quartic case (there are a general complicated solutions). But there is a math theorem (from Galois theory) that states that there is no general solution for the quintic equation (and so on). In your case, maximum degree is 3, so you can use the cubic equation from wikipedia. For the heart graphic write: x^2*y^3 - y^2 -(x^2-1) = 0 and treat x as constant. For the sqrt case, get rid of it. Square both sides of equation, isolate y and you end up with a quartic equation on y, that you can solve using wikipedia's quartic equation knowledge.
Anyway, if you don't have a very strong reason to do this, don't do it, as the computer can solve this numerically for you. Standard approach is to calculate this implicitly, as in the plots you made.
I hope this helps.
There ia a possible solution for the general quintic equation, when you addapt the solutionmethod from Cardano for the general cubic equation and the solutionmethod from Ferrari for the general quartic equation.

Solving simulataneous equations with Coffeequate

I'm looking for a Computer Algebra System to run in a browser, with a particular interest in finding roots to systems of equations.
I'm currently evaluating Coffeequate.
The simplest non-trivial system I came up with that wasn't on the demo page was a system of two simultaneous linear equations:
var exp1 = CQ('x = 2 * y + 6');
var exp2 = CQ('x - y = 10');
exp2.sub({x: exp1.solve('x')})
.solve('y');
Unfortunately, this hangs at the sub call.
What I would like to obtain is the value for all unknowns (i.e. x and y) that are knowable – there is guaranteed to be a solution in this case.
What am I doing wrong here?
CQ().solve returns an array of solutions (in case there are multiple solutions). However, things that you want to substitute in using CQ().sub have to be integers or CQ() objects themselves. The following code works:
var exp1 = CQ('x = 2 * y + 6');
var exp2 = CQ('x - y = 10');
exp2.sub({x: exp1.solve('x')[0]}).solve('y'); // 4
The fact that it actually hangs instead of erroring when you pass in an array is a bug; I'll patch that.
(Disclaimer: I wrote Coffeequate)

JS: Resolve a Formula for x

I have a formula with several components, let's say w = x * y / z^2 + c. Now I have an input-field for each variable. My goal is, to calculate the missing one as soon, as all the others were entered. Difficulty is, that you can choose which fields you fill and which you want to leave free.
The easy (naive) way would of course be to resolve it for each variable by hand, detect the missing var, and have seperate js functions for each case. But I even have linked formulas (like x in the above formula is x = a + b, too) as well and the options are almost infinitive. Is there any option in JS to solve a formula by a specified variable? I could then replace each variable string with the assigned value and then eval the string.
First I thought Nerdamer would be the thing, but it turned out that it can only evaluate expressions and can't handle equations.
Is this possible? Any better idea?
Thanks in advance!
P.S.: My actual set of formula is:
dR = c * I^2 / A
R = L * dR
P = I * U
DV = R * I
DW = DV * I
It's for calculating losses in a cable due to ohm's resistance. Each Variable has a corresponding input field.
The following solution can be built for finding "R" using nerdamer. The logic can be extended to solve for the remaining variables. Do keep in mind that the current limitation is that nerdamer can currently only solve up to cubic functions algebraically. Higher order functions will be solved numerically.
//You can then take care of the non linear containing I. I is quadratic
var dR = nerdamer('R=L*dR').solveFor('dR');
var I = nerdamer('dR=c*I^2/A').sub('dR', dR).solveFor('I');
//You can first start by reducing the first few equations since they are linear and you can solve them as a linear system
var solutions = nerdamer.solveEquations(['P = I * U', 'DV = R * I', 'DW = DV * I'], ['I', 'DW', 'P']);
//the solutions come back as an array arrays in the form of [variable, value]
//you can see what they look like. In your case all your solutions will be in terns of DV & U since these are the only actual knowns
//You can see what the solutions look like
solutions.map(function(x) {
console.log('-'+x[0]+' = '+x[1]);
});
console.log('------------------ R ----------------');
var R = nerdamer.setEquation(I[0], solutions[0][1]).solveFor('R');
//I will have 3 solutions since it's cubic. You can console.log them below
R.map(function(x) {
console.log('R = '+x.toString());
});
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/nerdamer.core.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Algebra.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Calculus.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Extra.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Solve.js"></script>

Detecting a Fist with Leap Motion SDK V2

I want to check if a Hand in a Leap Motion Frame is currently a Fist.
The usually suggested method is to look for hand.grabStrength with a value of 1. The problem is that the value jumps to 1 even with a "Claw-Like" Hand, or anything else with very slightly curled fingers.
Another approach would be to check on each finger if it is extended. But this has a similiar issue, Fingers only count as extended if they are completely straight. So even if i check for all fingers to be not extended, the same issue as above occurs (claw-like hands get recognized as grabbed).
Combining these two methods also does not solve the issue, which is not surprising given that they both suffer from the same problems.
Now, we do have all the bones of each finger available, with positions and everything. But I have no idea where to start with the math to detect if a finger is curled.
Basically I have this setup for now:
var controller = Leap.loop(function(frame){
if(frame.hands.length>0){
//we only look at the first available hand
var hand = frame.hands[0];
//we get the index finger only, but later on we should look at all 5 fingers.
var index = hands.fingers[1];
//after that we get the positions of the joints between the bones in a hand
//the position of the metacarpal bone (i.e. the base of your hand)
var carp = index.carpPosition;
//the position of the joint on the knuckle of your hand
var mcp = index.mcpPosition;
//the position of the following joint, between the proximal and the intermediate bones
var pip = index.pipPosition;
//the position of the distal bone (the very tip of your finger)
var dip = index.dipPosition;
//and now we need the angle between each of those positions, which is where i'm stuck
}
});
So, how do I get the angle between two of those positions (carp to mcp, mcp to pip, pip to dip)? Any ideas?
Alright, I think I found a sort of working approach to detect an actual fist, and not a claw.
First off, instead of the positions of the joints, we need the distance Vectors for each Bone.
Then we calculate the Dot product between the Metacarpal and the Proximal bone, as well as the dot Product between the Proximal and the Intermediate Bone. We can ignore the Distal bone, it doesn't change the result too much.
We sum all the calculated dot products (10 in total) and calculate the average out (we divide by 10). This will give us a value between 0 and 1. A Fist is beneath 0.5 and everything above that is basically not a fist.
Additionally you might also want to check for the amount of extended fingers on a Hand and check if it is 0. This will ensure that a "Thumbs-up" and similiar 1-digit poses do not get recognized as a Fist.
Here is my implementation:
const minValue = 0.5;
var controller = Leap.loop(function(frame){
if(frame.hands.length>0)
{
var hand = frame.hands[0];
var isFist = checkFist(hand);
}
});
function getExtendedFingers(hand){
var f = 0;
for(var i=0;i<hand.fingers.length;i++){
if(hand.fingers[i].extended){
f++;
}
}
return f;
}
function checkFist(hand){
var sum = 0;
for(var i=0;i<hand.fingers.length;i++){
var finger = hand.fingers[i];
var meta = finger.bones[0].direction();
var proxi = finger.bones[1].direction();
var inter = finger.bones[2].direction();
var dMetaProxi = Leap.vec3.dot(meta,proxi);
var dProxiInter = Leap.vec3.dot(proxi,inter);
sum += dMetaProxi;
sum += dProxiInter
}
sum = sum/10;
if(sum<=minValue && getExtendedFingers(hand)==0){
return true;
}else{
return false;
}
}
While this works like it should, I doubt that this is the correct and best approach to detect a Fist. So please, if you know of a better way, post it.
Solution works perfect, any chance you could explain why you divide by 10 and why the minValue is 0.5? Thanks!
Well, it doesn't work that good, to be honest. I'll soon start to work on a little project that has the goal to improve the detection of fists with Leap Motion.
Regarding your questions, We divide the sum by 10 because we have 2 Bone Joints per finger, with 5 fingers. We want the average value from the sum of all those calculations, because not all fingers will be angled in the same way. So we want some value that encompasses all of these values into a single one: the average value. Given that we have 10 calculations in total (2 per each finger, 5 fingers), we divide the sum of those calculations and there we go. We will get a value between 0 and 1.
Regarding the minValue: Trial&Error. In a project of mine, I used a value of 0.6 instead.
This is another problem of this approach: ideally a flat hand should be a value of nearly 0, while a fist should be 1.
I know it is an old topic but if you guys still around the answer could be simpler just by using sphereRadius() ;
I found "grabStrength" is good

Categories