Sympy ValueError: First variable cannot be a number (in a function)

38 Views Asked by At

Here is a simple code for Newton equation solving meant to find complex roots.

The code meant to work like this:

Importing Libraries: The code imports the sympy library to handle symbolic mathematics.

Defining the Polynomial: It defines the polynomial equation p(x)=x5+11x4−21x3−10x2−21x−5 using the sympy library.

Newton's Method Function: The newton_method function implements Newton's method to find roots of a function within a given tolerance.

Finding Real Roots: It uses a loop to apply Newton's method with different initial guesses to find real roots of the polynomial equation.

Reducing Polynomial: The reduce_polynomial function divides the polynomial by (x−root) to reduce the degree of the polynomial.

Finding Complex Roots: It utilizes the obtained real roots to reduce the polynomial and find any complex roots by solving the reduced polynomials.

Output: Finally, it prints the real roots and complex roots found using the Newton's method and the reduction technique.

This code utilizes Newton's method to find real roots and subsequently reduces the polynomial to find any complex roots based on the obtained real roots. Adjusting the tolerance and initial guesses can affect the accuracy and convergence of the method for different polynomials.

import sympy as sp

# Define the variable
x = sp.symbols('x')

# Define the polynomial
p = x**5 + 11*x**4 - 21*x**3 - 10*x**2 - 21*x - 5

# Find the real roots using Newton's method
tolerance = 1e-5  # Tolerance for approximation
roots = []

# Function for Newton's method
def newton_method(f, x0, tol, max_iter=100):
    x = x0
    iteration = 0
    while iteration < max_iter:
        x_next = x - f.subs(x, x) / f.diff(x).subs(x, x)
        if abs(x - x_next) < tol:
            return x_next
        x = x_next
        iteration += 1
    return None

# Find real roots
for i in range(5):
    root = newton_method(p, i, tolerance)
    if root is not None:
        roots.append(root)

print("Real roots:", roots)

# Reduce the polynomial to a lower degree
# This reduces the polynomial by dividing it by (x - root)
def reduce_polynomial(poly, root):
    return sp.simplify(poly / (x - root))

# Find complex roots
complex_roots = []
for root in roots:
    reduced_poly = reduce_polynomial(p, root)
    complex_root = sp.solve(reduced_poly, x)
    complex_roots.extend(complex_root)

print("Complex roots:", complex_roots)

**However, I got this common error: **

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-beb367549ec5> in <cell line: 27>()
     26 # Find real roots
     27 for i in range(5):
---> 28     root = newton_method(p, i, tolerance)
     29     if root is not None:
     30         roots.append(root)

3 frames
<ipython-input-3-beb367549ec5> in newton_method(f, x0, tol, max_iter)
     17     iteration = 0
     18     while iteration < max_iter:
---> 19         x_next = x - f.subs(x, x) / f.diff(x).subs(x, x)
     20         if abs(x - x_next) < tol:
     21             return x_next

/usr/local/lib/python3.10/dist-packages/sympy/core/expr.py in diff(self, *symbols, **assumptions)
   3584     def diff(self, *symbols, **assumptions):
   3585         assumptions.setdefault("evaluate", True)
-> 3586         return _derivative_dispatch(self, *symbols, **assumptions)
   3587 
   3588     ###########################################################################

/usr/local/lib/python3.10/dist-packages/sympy/core/function.py in _derivative_dispatch(expr, *variables, **kwargs)
   1907         from sympy.tensor.array.array_derivatives import ArrayDerivative
   1908         return ArrayDerivative(expr, *variables, **kwargs)
-> 1909     return Derivative(expr, *variables, **kwargs)
   1910 
   1911 

/usr/local/lib/python3.10/dist-packages/sympy/core/function.py in __new__(cls, expr, *variables, **kwargs)
   1294             if isinstance(v, Integer):
   1295                 if i == 0:
-> 1296                     raise ValueError("First variable cannot be a number: %i" % v)
   1297                 count = v
   1298                 prev, prevcount = variable_count[-1]

ValueError: First variable cannot be a number: 0```


I searched for value error in other post but problem unsolved.
1

There are 1 best solutions below

1
mugiseyebrows On

x is a top level variable containig sympy.symbol, but inside newton_method x is redeclared as local variable containing float value x = x0, so it's not a symbol anymore, so f.subs(x, x) can not possibly work and f.diff(x).subs(x, x) cannot also.

Here's correct version of this function (assuming everything else is correct):

def newton_method(f, x0, tol, max_iter=100):
    iteration = 0
    while iteration < max_iter:
        x_next = (x0 - f.subs(x, x0) / f.diff(x).subs(x, x0)).evalf()
        if abs(x0 - x_next) < tol:
            return x_next
        x0 = x_next
        iteration += 1
    return None