4

Suppose I have the following factors:

(1+3x)(1+x)(1+2x)

Expanded to a polynomial, it looks like:

1 + 6x + 11x^2 + 6x^3

The coefficients of this polynomial would be

c0 = 1
c1 = 6
c2 = 11
c3 = 6

I'm trying to figure out how to calculate these rapidly (for any set of factors). The ideal output would be an array of the coefficients, like

var coeff = [c0,c1,c2,c3];

What I'm trying to do is find a way to quickly go from the factors to the array of coefficients. Any suggestions on how to rapidly handle this in javascript? And for the sake of clarity, I'm trying to figure out how to do this for any set of n factors, not just this particular scenario.

Jonathan
  • 680
  • 1
  • 9
  • 24
  • Where do you get the factors? – DamiToma Mar 28 '17 at 16:17
  • Are you asking how to go from the original equation to the polynomial using Javascript? Start with an array of pairs like `[[1, 3], [1, 1], [1, 2]]`. Then use algebra to calculate the polynomial from it. – Barmar Mar 28 '17 at 16:19
  • The factors come from a number of other sources. This is one example, but there are countless scenarios. @Barmar do you have a suggestion of a formula that would work for n factors? That's what I've been trying to figure out. – Jonathan Mar 28 '17 at 16:22
  • @Jonathan How did you figure out the coefficients yourself when you wrote the question? Just turn what you did into a computer algorithm. – Barmar Mar 28 '17 at 16:25
  • If you don't know how to do the math, the proper place to ask is math.stackexchange.com. – Barmar Mar 28 '17 at 16:26
  • @Barmar I did it manually, by hand. I've been reseraching this a lot, and I came across this link (http://math.stackexchange.com/questions/1690156/is-there-a-way-to-mathematically-express-the-sum-of-all-combinations-of-a-set-of) that I think explains the theory of what I'm trying to do, but I can't figure out how to interpret it into javascript. I just tried to simplify this to see if anyone has any suggestions on how to handle this simply. – Jonathan Mar 28 '17 at 16:28
  • http://algorithm.cs.nthu.edu.tw/~course/Extra_Info/Divide%20and%20Conquer_supplement.pdf Here you can find general algorithm for multiplying two polynomials of any degree. I would start by implementing the given algorithms in this link and then optimize based on the specific form of your problem. In the simplest, you could loop over the number of terms in your problem and use convolution to incrementally calculate the final result. – jrook Mar 28 '17 at 16:33
  • The algorithm at the site that @jrook linked to can probably be simplified if you know the inputs are all of the form `(a + bx)` rather than more general polynomials. But it should get you going. – Barmar Mar 28 '17 at 16:36
  • @jrook Thanks for pointing that one out, I think that could work. – Jonathan Mar 28 '17 at 16:39
  • @Barmar, I hear you. If we make the assumption they're all of that format, I may be able to work something out of this. Stay posted. – Jonathan Mar 28 '17 at 16:39

4 Answers4

3

You could use the factors as vector and use a cross product for the result.

function multiply(a1, a2) {
    var result = [];
    a1.forEach(function (a, i) {
        a2.forEach(function (b, j) {
            result[i + j] = (result[i + j] || 0) + a * b;
        });
    });
    return result;
}

var data = [[1, 3], [1, 1], [1, 2]], // (1+3x)(1+x)(1+2x)
    result = data.reduce(multiply);
    
console.log(result);                 // [1, 6, 11, 6] = 1x^0 + 6x^1 + 11x^2 + 6x^3
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

Well I found a method to do what you want from start to finish even without the need for any treatment in the original factors. Although I had to use a Math library. I found there is at least a library that does what you want: Nerdamer

As you can see from the code below the coeficients are correctly calculated from the factors you gave.

var factors = '(1+3x)(1+x)(1+2x)';
console.log('original factors: ' + factors);
var y = nerdamer('expand(' + factors + ')');
var polynomialform = y.toString();
console.log('polynomial form: ' + polynomialform);
var coef = polynomialform.split('+').map(v=>v.trim()).map(v=>v.split('x')[0]).map(v=>v.replace(/^\*+|\*+$/g, ''));
console.log('coeficients: ' + coef);
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>

Notice that coefs var is an array.

Obviously, by the way I otained the coeficients, the operation may fail in different factor cases. This has to be adapted for minus characters and edge cases. You can create some kind of loop and put failed calculations in an array to check for edge cases to adapt the code for the full dataset. I can improve the answer if you provide a larger test dataset.

Hope it helps you.

Nelson Teixeira
  • 6,297
  • 5
  • 36
  • 73
  • That's a good idea of how to get to there from the string. Any suggestions on how to get to the string though? There's a formula here that's evading me. – Jonathan Mar 28 '17 at 16:24
  • Well... that's as people are asking you in the question. How do you get to the polynomial ? or at least in what form is it ? We can't answer if we don't know how to start. Post the code of the polynomial being created and I'll improve the answer. – Nelson Teixeira Mar 28 '17 at 16:27
  • I got to the polynomial by expanding the factors at the start of the post, and I just did it by hand. The system I'm building punches out sets of factors like that. In the example provided, there are 3 factors, however in reality, there may be as many as 30-40. Expanding a polynomial from 30-40 factors isn't a task I'm ready to handle manually, so I'm trying to work out the generic answer in javascript to do the calculation for me. – Jonathan Mar 28 '17 at 16:32
  • Now I think it's better. – Nelson Teixeira Mar 28 '17 at 19:45
  • btw, i get the following error: `"Array.prototype.map: argument is not a Function object` with edge. – Nina Scholz Mar 28 '17 at 19:54
  • It's working for me in FF. Tested in Chrome and got an error. Verifying. Can't test Edge. I'm on Linux. – Nelson Teixeira Mar 28 '17 at 20:02
  • @NinaScholz please test it now – Nelson Teixeira Mar 28 '17 at 20:05
1

Here's my take based on the fact that when you multiply (1+ax) by (1+b_1*x+b_2*x^2+...+b_nx^n), in the resulting polynomial (of degree n+1), the first term's coefficient will be one and its last term's coefficient will be a*b_n.

I think it is a bit simpler than the accepted answer, but still quadratic in time. To make this more efficient, you will need more advanced techniques.

function multOne(a, b) {
  var n = b.length;
  var r = [1];  //The first term is always 1
  r[n] = a * b[n - 1]; //The last term is always a*b_n-1
  for (var i = 1; i < n; i++)
    r[i] = b[i] + a * b[i - 1];
  return r;
}

function solve(c) {
  var result = [1, c[0]];  //use result as an accumulator
  for (var j = 1; j < c.length; j++)
    result = multOne(c[j], result);
  return result;
}

console.log(solve([3, 1, 2]));  //You don't need to pass 1s either. Just pass the varying coefficients
jrook
  • 3,459
  • 1
  • 16
  • 33
0

I needed something similar (to calculate permutations via exponential generating functions) so I wrote a version that works when some terms missing, by using objects as the base instead. I also needed it not not calculate anything over a certain power, so that's also an option

/**
 * Calculates the result of multiplying many polynomials together
 * @example 
 *   polynomials = [{0: 1, 1: 10, 2:1}, {0: 0, 1: 5, 2: 0, 3: 0.5}]
 *   limit = 4;
 *   polynomialMultiplication(polynomials, limit);
 * @param {Array.<Object.<number,number>>} polynomials an array of polynomials,
 * each expressed as an array of term coefficients
 * @param {number} limit the maximum term to calculate
 * @returns the resultant polynomial from multiplying all polynomials together
 */
function polynomialMultiplication(polynomials, limit) {
  const length = limit ?? polynomials.reduce((sum, poly) => sum += Math.max(...Object.keys(poly)), 0)
  // make an object to hold the result in
  // which is prepopulated by zeros
  const template = { ...Array.from({
      length
    }).fill(0)
  };
  return polynomials.reduce((memo, poly, polyIndex) => {
    const tempCopy = { ...template};
    if (polyIndex === 0) return { ...poly };
    for (let termIndex = 0; termIndex < length && termIndex <= Math.max(...Object.keys(poly)); termIndex++) {
      for (let memoIndex = 0;
        (memoIndex + termIndex) <= length && memoIndex <= Math.max(...Object.keys(memo)); memoIndex++) {
        const addition = (memo[memoIndex] ?? 0) * (poly[termIndex] ?? 0);
        const copyIndex = memoIndex + termIndex;
        tempCopy[copyIndex] = (tempCopy[copyIndex] ?? 0) + addition;
      }
    }
    return tempCopy;
  }, template)
}

console.log('(1+3x)(1+x)(1+2x)');
const polynomials = [{
  0: 1,
  1: 3
}, {
  0: 1,
  1: 1
}, {
  0: 1,
  1: 2
}];
console.log(polynomialMultiplication(polynomials));

const morePolynomials = [{
  0: 1,
  1: 0,
  2: 5
}, {
  0: 0,
  1: 6
}, {
  0: 1,
  1: 2,
  2: 0
}];
console.log('(1+5x^2)(6x)(1+2x) up to x^2')
console.log(polynomialMultiplication(morePolynomials, 2));
AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173