pythonnumpysympympmathmpc

Python: AttributeError: 'mpc' (or 'mpf') object has no attribute 'arcsin'


I was trying to use Jacobi elliptical function from mpmath, but getting the error for the simple code given below:

import numpy as np
import scipy.integrate as spi
from scipy import special as sp
import matplotlib.pyplot as plt
from math import sqrt, pow, log
from mpmath import ellipfun

sn = ellipfun('sn')
y=sn(0.5,-1)
print y

y1=y.real
print y1, np.arcsin(y), np.arcsin(y1)

I am getting the error even when I pass only the real part of the function sn(0.5,-1). I don't know whether I am making a mistake. Kindly help. Thanks in advance.


Solution

  • y is an mpc object, and y.real is an mpf object. numpy knows nothing about such objects, so when you call np.arcsin(y), the numpy code checks to see if the argument has an arcsin() method (that is, it looks for y.arcsin()). If it does, it will call that function to compute the arcsin. The mpc and mpf objects do not have such a method, which results in the error that you see. (It would be nice if the error message said something like "numpy does not know how to compute the arcsin of an mpf object".)

    Here's the same behavior demonstrated with a different object:

    In [10]: class Foo:
        ...:     pass
        ...: 
    
    In [11]: f = Foo()
    
    In [12]: np.arcsin(f)
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-12-aa4b1a80cd4e> in <module>()
    ----> 1 np.arcsin(f)
    
    AttributeError: Foo instance has no attribute 'arcsin'
    

    As pointed out in a comment by Hannebambel, you could use mpmath.asin instead of np.arcsin:

    In [6]: import mpmath
    
    In [7]: y = sn(0.5, -1)
    
    In [8]: mpmath.asin(y)
    Out[8]: mpc(real='0.52001273608158616', imag='0.0')
    

    To use the numpy arcsin function, first convert to a plain floating point or complex by passing the mpc and mpf objects through the builtin functions complex() and float(), respectively:

    In [19]: y
    Out[19]: mpc(real='0.49689119041931196', imag='0.0')
    
    In [20]: np.arcsin(float(y.real))
    Out[20]: 0.52001273608158627
    
    In [21]: np.arcsin(complex(y))
    Out[21]: (0.52001273608158616+0j)
    

    Or use math.asin instead of numpy.arcsin:

    In [25]: import math
    
    In [26]: math.asin(y.real)
    Out[26]: 0.5200127360815863