2

I want to use power series to approximate some PDEs. The first step I need to generate symbolic multivariate polynomials, given a numpy ndarray.

Consider the polynomial below:

enter image description here

I want to take a m dimensional ndarray of D=[d1,...,dm] where djs are non-negative integers, and generate a symbolic multivariate polynomial in the form of symbolic expression. The symbolic expression consists of monomials of the form:

enter image description here

Fo example if D=[2,3] the output should be

enter image description here

For this specific case I could nest two for loops and add the expressions. But I don't know what to do for Ds with arbitrary length. If I could generate the D dimensional ndarrays of A and X without using for loops, then I could use np.sum(np.multiply(A,X)) as Frobenius inner product to get what I need.

Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193
  • [similar question here on Quora](https://www.quora.com/How-does-one-generate-algorithmically-all-the-terms-of-a-multivariate-polynomial) – Foad S. Farimani Aug 04 '18 at 10:40

1 Answers1

2

I would use symarray and itertools.product for this:

from sympy import *
import itertools
D = (3, 4, 2, 3)
a = symarray("a", D)
x = symarray("x", len(D))
prod_iterator = itertools.product(*map(range, D))
result = Add(*[a[p]*Mul(*[v**d for v, d in zip(x, p)]) for p in prod_iterator])

The result being

a_0_0_0_0 + a_0_0_0_1*x_3 + a_0_0_0_2*x_3**2 + a_0_0_1_0*x_2 + a_0_0_1_1*x_2*x_3 + a_0_0_1_2*x_2*x_3**2 + a_0_1_0_0*x_1 + a_0_1_0_1*x_1*x_3 + a_0_1_0_2*x_1*x_3**2 + a_0_1_1_0*x_1*x_2 + a_0_1_1_1*x_1*x_2*x_3 + a_0_1_1_2*x_1*x_2*x_3**2 + a_0_2_0_0*x_1**2 + a_0_2_0_1*x_1**2*x_3 + a_0_2_0_2*x_1**2*x_3**2 + a_0_2_1_0*x_1**2*x_2 + a_0_2_1_1*x_1**2*x_2*x_3 + a_0_2_1_2*x_1**2*x_2*x_3**2 + a_0_3_0_0*x_1**3 + a_0_3_0_1*x_1**3*x_3 + a_0_3_0_2*x_1**3*x_3**2 + a_0_3_1_0*x_1**3*x_2 + a_0_3_1_1*x_1**3*x_2*x_3 + a_0_3_1_2*x_1**3*x_2*x_3**2 + a_1_0_0_0*x_0 + a_1_0_0_1*x_0*x_3 + a_1_0_0_2*x_0*x_3**2 + a_1_0_1_0*x_0*x_2 + a_1_0_1_1*x_0*x_2*x_3 + a_1_0_1_2*x_0*x_2*x_3**2 + a_1_1_0_0*x_0*x_1 + a_1_1_0_1*x_0*x_1*x_3 + a_1_1_0_2*x_0*x_1*x_3**2 + a_1_1_1_0*x_0*x_1*x_2 + a_1_1_1_1*x_0*x_1*x_2*x_3 + a_1_1_1_2*x_0*x_1*x_2*x_3**2 + a_1_2_0_0*x_0*x_1**2 + a_1_2_0_1*x_0*x_1**2*x_3 + a_1_2_0_2*x_0*x_1**2*x_3**2 + a_1_2_1_0*x_0*x_1**2*x_2 + a_1_2_1_1*x_0*x_1**2*x_2*x_3 + a_1_2_1_2*x_0*x_1**2*x_2*x_3**2 + a_1_3_0_0*x_0*x_1**3 + a_1_3_0_1*x_0*x_1**3*x_3 + a_1_3_0_2*x_0*x_1**3*x_3**2 + a_1_3_1_0*x_0*x_1**3*x_2 + a_1_3_1_1*x_0*x_1**3*x_2*x_3 + a_1_3_1_2*x_0*x_1**3*x_2*x_3**2 + a_2_0_0_0*x_0**2 + a_2_0_0_1*x_0**2*x_3 + a_2_0_0_2*x_0**2*x_3**2 + a_2_0_1_0*x_0**2*x_2 + a_2_0_1_1*x_0**2*x_2*x_3 + a_2_0_1_2*x_0**2*x_2*x_3**2 + a_2_1_0_0*x_0**2*x_1 + a_2_1_0_1*x_0**2*x_1*x_3 + a_2_1_0_2*x_0**2*x_1*x_3**2 + a_2_1_1_0*x_0**2*x_1*x_2 + a_2_1_1_1*x_0**2*x_1*x_2*x_3 + a_2_1_1_2*x_0**2*x_1*x_2*x_3**2 + a_2_2_0_0*x_0**2*x_1**2 + a_2_2_0_1*x_0**2*x_1**2*x_3 + a_2_2_0_2*x_0**2*x_1**2*x_3**2 + a_2_2_1_0*x_0**2*x_1**2*x_2 + a_2_2_1_1*x_0**2*x_1**2*x_2*x_3 + a_2_2_1_2*x_0**2*x_1**2*x_2*x_3**2 + a_2_3_0_0*x_0**2*x_1**3 + a_2_3_0_1*x_0**2*x_1**3*x_3 + a_2_3_0_2*x_0**2*x_1**3*x_3**2 + a_2_3_1_0*x_0**2*x_1**3*x_2 + a_2_3_1_1*x_0**2*x_1**3*x_2*x_3 + a_2_3_1_2*x_0**2*x_1**3*x_2*x_3**2

Remarks:

  1. symarray depends on NumPy, but this does not seem to be an issue for you. If it was, I would create symbols one by one using itertools.product
  2. The format Add(*[...]) is more efficient than sum([...]) for forming symbolic sums with a large number of terms, see SymPy issue 13945.
Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193
  • great. I'm gonna check it out and come back. in the meantime others are also offering solutions [here](https://gist.github.com/celliern/c715151a247dbb3c8caec15aeb9af83d) and [here](https://groups.google.com/forum/#!topic/sympy/V4KRzA-3doI). you may like to see them too. – Foad S. Farimani Aug 01 '18 at 14:31
  • From [here](https://stackoverflow.com/a/51636453/4999991) I found the `product(*map(range, D))` which seems to be faster than `product(*[range(d) for d in D])`. How do you think? – Foad S. Farimani Aug 01 '18 at 20:55
  • 1
    Sure, that's a nicer way. Won't make a noticeable difference for the overall thing, because the formation of `prod_iterator` is not the bottleneck here. –  Aug 01 '18 at 21:04
  • I would appreciate if you could take a loo at my follow up question [here](https://cs.stackexchange.com/questions/95886/algorithm-for-using-power-series-to-numerically-solve-a-partial-differential-equ) – Foad S. Farimani Aug 02 '18 at 11:56