I have to make a Lagrange polynomial in Python for a project I'm doing. I'm doing a barycentric style one to avoid using an explicit for-loop as opposed to a Newton's divided difference style one. The problem I have is that I need to catch a division by zero, but Python (or maybe numpy) just makes it a warning instead of a normal exception.
So, what I need to know how to do is to catch this warning as if it were an exception. The related questions to this I found on this site were answered not in the way I needed. Here's my code:
import numpy as np
import matplotlib.pyplot as plt
import warnings
class Lagrange:
def __init__(self, xPts, yPts):
self.xPts = np.array(xPts)
self.yPts = np.array(yPts)
self.degree = len(xPts)-1
self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])
def __call__(self, x):
warnings.filterwarnings("error")
try:
bigNumerator = np.product(x - self.xPts)
numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
return sum(numerators/self.weights*self.yPts)
except Exception, e: # Catch division by 0. Only possible in 'numerators' array
return yPts[np.where(xPts == x)[0][0]]
L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2
L(1) # This should catch an error, then return 1.
When this code is executed, the output I get is:
Warning: divide by zero encountered in int_scalars
That's the warning I want to catch. It should occur inside the list comprehension.
Best Answer
It seems that your configuration is using the
print
option fornumpy.seterr
:This means that the warning you see is not a real warning, but it's just some characters printed to
stdout
(see the documentation forseterr
). If you want to catch it you can:numpy.seterr(all='raise')
which will directly raise the exception. This however changes the behaviour of all the operations, so it's a pretty big change in behaviour.numpy.seterr(all='warn')
, which will transform the printed warning in a real warning and you'll be able to use the above solution to localize this change in behaviour.Once you actually have a warning, you can use the
warnings
module to control how the warnings should be treated:Read carefully the documentation for
filterwarnings
since it allows you to filter only the warning you want and has other options. I'd also consider looking atcatch_warnings
which is a context manager which automatically resets the originalfilterwarnings
function: