# TypeError: x0 is not a valid variable trying to solve equation

I'm trying to convert a matrix into a set of equations and then use solve but hitting an error.

from sage.matrix.constructor import matrix
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

# Define the matrix and vector
M = matrix(QQ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
v = vector(QQ, [1, 2, 3])

# Augment the matrix with the vector
Maug = M.augment(v, subdivide=True)

# Create polynomial ring
P = PolynomialRing(QQ, 3, names="x")

# Calculate coefficient equations
coeff_eqns = (M * vector(P.gens())).list()

# Create equations
equations = []
for i in range(len(coeff_eqns)):
eq = coeff_eqns[i] - v[i]
equations.append(eq)

print(equations)
print(P.gens())

# Solve the equations
solution = solve(equations, P.gens())


generates this output

[x0 + 2*x1 + 3*x2 - 1, 4*x0 + 5*x1 + 6*x2 - 2, 7*x0 + 8*x1 + 9*x2 - 3]
(x0, x1, x2)


and this error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [1], line 27
24 print(P.gens())
26 # Solve the equations
---> 27 solution = solve(equations, P.gens())

File /home/sc_serv/sage/src/sage/symbolic/relation.py:1046, in solve(f, *args, **kwds)
1044     for i in x:
1045         if not isinstance(i, Expression):
-> 1046             raise TypeError("%s is not a valid variable." % repr(i))
1047 elif x is None:
1048     vars = f.variables()

TypeError: x0 is not a valid variable.


Any thoughts?

edit retag close merge delete

Sort by ยป oldest newest most voted

There is some difference between "variables" as "expressions" and "variables" as "generators" of a polynomial ring. For instance, everything introduced with var is in the first world, and solve works only for this world. For short, introduce variables via var, build the system, ask solve to solve it.

When dealing with polynomial rings, the world is purely algebraic, so purely algebraic solve methods apply. In this case we are inside algebraic geometry, and the terminology is slightly unexpected. We want the variety of points satisfying the given equations, as generators of an ideal. We have such a computed variety if it is finite only. The code wants exactly so many independent variables as independent equations.

So let us compare the two possibilities...

M = matrix(QQ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
v = vector(QQ, [1, 2, 3])

yvars = var('y0,y1,y2')
yvector = vector(yvars)

solve([eq == val for eq, val in zip(M*yvector, v)], yvars)


which gives the result:

[[y0 == r1 - 1/3, y1 == -2*r1 + 2/3, y2 == r1]]


and as seen, there is not a unique solution for it.
And we obtain a "parametrized solution". (It is not simple or obvious to do "the natural thing" in the polynomial world.)

If we slightly change $M$ into

M = matrix(QQ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 99])


then there is a unique solution:

[[y0 == (-1/3), y1 == (2/3), y2 == 0]]


Doing the same in the variety world leads to an error, so i will slightly change $M$ to be of maximal rank.

M = matrix(QQ, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 99])
v = vector(QQ, [1, 2, 3])

R.<x,y,z> = QQ[]
w = vector([x, y, z])
J = R.ideal(list( M*w - v ))
J.variety()


And this gives:

[{z: 0, y: 2/3, x: -1/3}]


Depending on the application, we can chose the one or the other world, or even the more structural:

sage: M
[ 1  2  3]
[ 4  5  6]
[ 7  8 99]
sage: M^-1 * v
(-1/3, 2/3, 0)


since there is no need to introduce variables.

more

The error message is incomplete, it should say "symbolic variable" instead. Indeed, x0 is not a symbolic variable (an element of the symbolic ring) but a polynomial variable (an element of a polynomial ring).

If you want to use symbolic functionality like solve, you can do the explicit conversions:

solution = solve([SR(eq) for eq in equations], [SR(v) for v in P.gens()])
print(solution)


Output:

[
[x0 == r1 - 1/3, x1 == -2*r1 + 2/3, x2 == r1]
]


For this particular problem one could also use linear algebra functionality directly:

sage: M.solve_right(v)
(-1/3, 2/3, 0)
sage: M.right_kernel().basis()
[
(1, -2, 1)
]


which gives the same information in a different way (in particular, without using symbolic variables).

more

PR #37899 would improve the error message.

( 2024-04-29 13:28:07 +0200 )edit