# How can I easily create and handle polynomials with symbolic coefficients?

I would like to create polynomial functions with symbolic (yet unknown) coefficients, like:

p(x)=a*x^5 + b*x^4 + c*x^3 + d*x^2+e*x+f


Then I would like to experiment with the degree and thus the number of coefficients, for example:

p(x)=a*x^7 + b*x^6 + c*x^5 + d*x^4+e*x^3+f*x^2+g*x+h


The problem is I always have to explicitely declare the coefficients, as variables, like:

var("a b c d e f g h")


So I should always have to enumerate them by hand.

Isn't exist some automatism to do this? For example:

Polynomial(x,degree=7)


and it would return

c0*x^7 + c1*x^6 + c2*x^5 + c3*x^4+c4*x^3+c5*x^2+c6*x+c7


Sometimes I also would like to query the coefficients, to solve an equation system, which contains those coefficients:

p(x)=a*x^7 + b*x^6 + c*x^5 + d*x^4+e*x^3+f*x^2+g*x+h
eq=[
derivative(p(x),x).subs(x=0)==0,
derivative(p(x),x,2).subs(x=0)==0,
p(x=0)==0,
p(x=x0)==1,
p(x=1)==1+z,
derivative(p(x),x).subs(x=1)==0,
derivative(p(x),x,2).subs(x=1)==0,
derivative(p(x),x).subs(x=x0)==1
]
s=solve(eq,a,b,c,d,e,f,g,h)


Again, when calling solve(), I have to explicitly enumerate the coefficients again, instead of some shortcut, like:

s=solve(eq,p(x).coefficients())


When I try to experiment with the degree of my polynomial p(x), to try out a higher or lower degree, and with more or less equations in the system, I always have to declare my coefficients as vars again and again, which is very annoying.

Furthermore when I tried to query coefficients by, eg.:

p.coefficient(x)


or

p.coefficient(x^3)


The first returns "g" as the coefficient, which is good. But how can I access or query the "free" coefficient, "h" which isn't multiplied by x?

p.coefficient(0)


Doesn't return anything. If it would return the free coeff, then I could get the coefficients by calling a map() with lambda function.

edit retag close merge delete

Sort by » oldest newest most voted

Polynomials over the symbolic ring can help here.

There is also a way to get a large sequence of indexed variables.

Below we use monomials a_i*x^i rather than a_i*x^j with i + j = degree(p).

Define a polynomial ring in x over the symbolic ring:

sage: R.<x> = SR[]


Define a bunch of indexed symbolic variables:

sage: a = SR.var('a', 100)


Define a polynomial of degree 7, look at it, check the coefficient of x^5 and of x^0:

sage: p = sum(a[k]*x^k for k in range(8))

sage: p
a_7*x^7 + a_6*x^6 + a_5*x^5 + a_4*x^4 + a_3*x^3 + a_2*x^2 + a_1*x + a_0

sage: p[5]
a_5

sage: p[0]
a_0


Another way to create the same polynomial:

sage: p = R(a[:8])


Define two more symbolic variables:

sage: x0 = SR.var('x0')
sage: z = SR.var('z')


Define the equations specifying values of p and its derivatives at 0, 1 and x0:

sage: eq = [p(0) == 0,
....:       p.diff(1)(0) == 0,
....:       p.diff(2)(0) == 0,
....:       p(1) == 1 + z,
....:       p.diff(1)(1) == 0,
....:       p.diff(2)(1) == 0,
....:       p(x0) == 1,
....:       p.diff(1)(x0) == 1,
....:      ]


Solve the equation, getting the answers as a list of dictionaries:

sage: s = solve(eq, a[:8], solution_dict=True)

sage: s
[{a_0: 0,
a_1: 0,
a_2: 0,
a_3: (10*x0^7 - 28*x0^6 + 21*x0^5 + x0^2 + (10*x0^7 - 28*x0^6 + 21*x0^5)*z
- 8*x0 + 4)/(x0^7 - 4*x0^6 + 6*x0^5 - 4*x0^4 + x0^3),
a_4: -(15*x0^8 - 24*x0^7 - 21*x0^6 + 42*x0^5 + 3*x0^3 - 23*x0^2
+ 3*(5*x0^8 - 8*x0^7 - 7*x0^6 + 14*x0^5)*z + 5*x0
+ 3)/(x0^8 - 4*x0^7 + 6*x0^6 - 4*x0^5 + x0^4),
a_5: 3*(2*x0^8 + 4*x0^7 - 21*x0^6 + 14*x0^5 + 7*x0^4 + x0^3 - 7*x0^2
+ (2*x0^8 + 4*x0^7 - 21*x0^6 + 14*x0^5 + 7*x0^4)*z - 3*x0
+ 3)/(x0^8 - 4*x0^7 + 6*x0^6 - 4*x0^5 + x0^4),
a_6: -(12*x0^7 - 21*x0^6 - 14*x0^5 + 35*x0^4 + x0^3 - 5*x0^2
+ (12*x0^7 - 21*x0^6 - 14*x0^5 + 35*x0^4)*z - 17*x0
+ 9)/(x0^8 - 4*x0^7 + 6*x0^6 - 4*x0^5 + x0^4),
a_7: (6*x0^6 - 18*x0^5 + 15*x0^4 + x0^2
+ 3*(2*x0^6 - 6*x0^5 + 5*x0^4)*z - 7*x0
+ 3)/(x0^8 - 4*x0^7 + 6*x0^6 - 4*x0^5 + x0^4)}]

more

Interestingly, when doing:

a = var('a', 100)


I get an error message:

AttributeError: 'sage.rings.integer.Integer' object has no attribute 'strip'

( 2021-12-26 05:57:00 +0100 )edit

Sorry, we need a = SR.var('a', 100). I edited my answer.

( 2021-12-26 06:34:03 +0100 )edit

Alternatively, you can do a=var("a", n=100). Yet another small inconsistency between Sage methods and their functional wrappers...

BTW, I'd rather use A=SR.var("a", 100) to get a better visual distinction between the symbolic variables and their collection.

( 2021-12-26 08:34:41 +0100 )edit