jiggzson / nerdamer

a symbolic math expression evaluator for javascript
http://www.nerdamer.com
MIT License
514 stars 82 forks source link

Accessing polynomial coefficients #604

Closed szoshi closed 3 years ago

szoshi commented 3 years ago

Hello, this is not really an issue, more of a support request.

There is an example to extract coefficients of a polynomial to a vector. The example displays this vector directly as a string. How do I work with individual coefficients? I can get the string as vector.elements[n].toString() Is there a way to get this as a number natively? Can I do any manipulation of the symbol directly? What I am doing right now is converting the string to a nerdamer expression and working with it. It works fine, I just wanted to know if there is another way to do it? Thanks for the great library!

jiggzson commented 3 years ago

Can I do any manipulation of the symbol directly?

You can. Although I'd prefer you use the each method. The current structure of the Expression class, which nerdamer currently returns, is guaranteed to change with the next major version so it would require you to update your code should you decide to update. I doubt I'll remove the each method, at least not without plenty of warning.

It works fine, I just wanted to know if there is another way to do it?

The preferred way would be

var coeffs = nerdamer.coeffs('a*x^2+b*x+c', 'x');
coeffs.each(_coeff => {
    var coeff = _coeff.toString();
    // Do something with the coeff here
    console.log(coeff);
});

Notice that I recommend using toString instead of interacting with nerdamer's (not the JS built-in) Symbol class directly. This too will more than likely go away in the future.

Thanks for the great library!

You're welcome and thank you.

szoshi commented 3 years ago

Just out of curiosity, can I find the coefficient of a certain power? Can I do further operations on it? It would be great if you could provide a simple example.

jiggzson commented 3 years ago

@szoshi,

It is possible but it requires you to dig in a little and interact with nerdamer's Symbol class. As I mentioned above, this may require you to rewrite some of your code when I decide to write v2.0. That being said, you can do something like this.

// Disregard this example. See below
/* 
var terms = nerdamer('5x^2-3x+7').symbol.collectSymbols(null, null, null, true);

// You can sort them in descending powers. 
// You can read about the grouping logic here (https://nerdamer.com/digging_deeper.html). 
// Grouping worked great with JS when the library was small but it's becoming cumbersome 
// and will go away in v2.0 in favor of something more conventional. Besides JS has gotten
// much better now.
terms.sort(function(a, b) {
    if(a.power == b.power) {
        return b.group - a.group;
    }
    return b.power - a.power;
});

// You can loop over them
terms.forEach(function(term) {
    console.log(`The terms is: ${term}`);
    // Note that to get symbolic coefficients you'll need a little more work
    console.log(`The coefficient is: ${term.multiplier}`);
    // Because they're not polynomial terms but rather groups, numbers have a power of one.
    // We need to check for this and correct.
    console.log(`The power is: ${term.power - (term.isConstant() ? 1 : 0)}`);
    console.log('================');
});
*/

If you need any more guidance, please feel free to reach out.

szoshi commented 3 years ago

Thanks for the example. How can I test if a coefficient is positive or negative? Is there a way the multiplier can be interpreted as a regular number? I am currently comparing the sign flags of the numerators and denominators as a workaround but am not sure how stable it will be. Are all numbers Fracs?

jiggzson commented 3 years ago

@szoshi,

I apologize. Disregard the example above. Use this example instead. The coeffs function already takes care of both symbolic and numeric coefficients. This answers the sign question as well.

Is there a way the multiplier can be interpreted as a regular number?

Yes. Just wrap in in Number to convert it to a JS number. (see below) It will return NaN if it's a variable coefficient.

var variable = 'x';
var coeffs = nerdamer.coeffs('8/3*x^3+12*x^2+14*x-b', variable);

coeffs.each(function(coeff, i) {
    console.log(`The numeric value is ${Number(coeff)}`);
    console.log(`${coeff}*${variable}^${i-1}`);
    console.log(`The sign is ${coeff.sign()}`);
    console.log('================================');
});
/* 
result:
The numeric value is NaN
-b*x^0
The sign is -1
================================
The numeric value is 14
14*x^1
The sign is 1
================================
The numeric value is 12
12*x^2
The sign is 1
================================
The numeric value is 2.6666666666666665
8/3*x^3
The sign is 1
================================
*/
szoshi commented 3 years ago

Hi, precisely what I was looking for. Thanks a lot. I will close this now and get back if there are any further questions.