Home > other >  sin(y) results in "can't convert expression to float" error
sin(y) results in "can't convert expression to float" error

Time:01-04

I created a very simple MWE to illustrate my problem. When I type y**(2), the program works. But when I type sin(y) or cos(y), it results in the error TypeError: can't convert expression to float. I discuss attempts to fix this error below.

    from vpython import *
    from scipy.optimize import fsolve
    import math
    import numpy as np
    import sympy as sp
    from sympy import Eq, Symbol, solve
    import matplotlib.pyplot as plt
    
    y = Symbol('y')
    
    i = input()
    i = ''.join(i).split(',')
    for x in range(0, len(i)):
        i[x] = i[x].strip()
    userMediums = i
    
    def refIndexSize(medium):
       
        def refractiveProfile(y):
                return eval(medium, {'y': y, 'np': np})
           
        lowerProfile = Eq(eval(medium), 1)
        upperProfile = Eq(eval(medium), 1.6)
        bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
                  abs(round(float(solve(upperProfile)[0]),5))]
        lowerBound = np.amin(bounds)
        upperBound = np.amax(bounds)
       
        return lowerProfile
    
    refIndexSize(userMediums[0])

Error:


    sin(y) 1
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    /tmp/ipykernel_48/825631216.py in <module>
         29     return lowerProfile
         30 
    ---> 31 refIndexSize(userMediums[0])
    
    /tmp/ipykernel_48/825631216.py in refIndexSize(medium)
         20             return eval(medium, {'y': y, 'np': np})
         21 
    ---> 22     lowerProfile = eval(medium)
         23     upperProfile = Eq(eval(medium), 1.6)
         24     bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
    
    <string> in <module>
    
    /srv/conda/envs/notebook/lib/python3.7/site-packages/sympy/core/expr.py in __float__(self)
        357         if result.is_number and result.as_real_imag()[1]:
        358             raise TypeError("can't convert complex to float")
    --> 359         raise TypeError("can't convert expression to float")
        360 
        361     def __complex__(self):
    
    TypeError: can't convert expression to float

I've looked at other questions regarding TypeError: can't convert expression to float, such as this and this. As a result, I have tried changing the order of my imports, although I can do nothing to change the wildcard from vpython import *, as it is the only way to import vpython (to my understanding), but this did not work. I've also tried inputting sp.sin(y) after looking at a different SO answer, but this did not help either. Once again, any tips or assistance is appreciated.

CodePudding user response:

Your problem lies in this line:

bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
              abs(round(float(solve(upperProfile)[0]),5))]

Specifically this part:

abs(round(float(solve(upperProfile)[0]),5))

Here the solve() function returns complex solutions in a list. See this:

[1.5707963267949 - 1.04696791500319*I, 1.5707963267949   1.04696791500319*I]

So, when you pick the 0 index it will be a complex result like this one:

1.5707963267949 - 1.04696791500319*I

So, you are trying to cast float() to this solution which results in error. Instead you can remove the bounds for solutions having complex results by using try-except block like this:

try:
  bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
              abs(round(float(solve(upperProfile)[0]),5))]
  lowerBound = np.amin(bounds)
  upperBound = np.amax(bounds)
except:
  print("The solutions are complex. Cant find a result")

Also import like this:

from vpython import *
from scipy.optimize import fsolve
import math
import numpy as np
import sympy as sp
from sympy import *
import matplotlib.pyplot as plt

CodePudding user response:

In an ipython session, with the most relevant imports:

In [1]: import numpy as np
   ...: import sympy as sp
   ...: from sympy import Eq, Symbol, solve

Modify your function to return the bounds as well.

In [2]: def refIndexSize(medium):
   ...: 
   ...:         def refractiveProfile(y):
   ...:                 return eval(medium, {'y': y, 'np': np})
   ...: 
   ...:         lowerProfile = Eq(eval(medium), 1)
   ...:         upperProfile = Eq(eval(medium), 1.6)
   ...:         bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
   ...:                   abs(round(float(solve(upperProfile)[0]),5))]
   ...:         lowerBound = np.amin(bounds)
   ...:         upperBound = np.amax(bounds)
   ...: 
   ...:         return lowerProfile, bounds
   ...: 

Define the symbol, and call the function with a string. In the interactive session I don't need to go through the input complications.

In [3]: y = sp.Symbol('y')

y**2 gives the bounds that you claim in a comment:

In [4]: refIndexSize("y**(2)")
Out[4]: (Eq(y**2, 1), [1.0, 1.26491])

Errors due to sin definition

Using a sin expression gives a NameError. sin hasn't been imported or defined.

In [5]: refIndexSize("sin(y) 1")
Traceback (most recent call last):
  File "<ipython-input-5-30c99485bce7>", line 1, in <module>
    refIndexSize("sin(y) 1")
  File "<ipython-input-2-6fea36c332b7>", line 6, in refIndexSize
    lowerProfile = Eq(eval(medium), 1)
  File "<string>", line 1, in <module>
NameError: name 'sin' is not defined

Import sin from math gives your error:

In [6]: from math import sin
In [7]: refIndexSize("sin(y) 1")
Traceback (most recent call last):
  File "<ipython-input-7-30c99485bce7>", line 1, in <module>
    refIndexSize("sin(y) 1")
  File "<ipython-input-2-6fea36c332b7>", line 6, in refIndexSize
    lowerProfile = Eq(eval(medium), 1)
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/sympy/core/expr.py", line 359, in __float__
    raise TypeError("can't convert expression to float")
TypeError: can't convert expression to float

math.sin expects a float value, so does not work with symbol y.

But import sin from sympy, and it works:

In [8]: from sympy import sin
In [9]: refIndexSize("sin(y) 1")
Out[9]: (Eq(sin(y)   1, 1), [0.0, 0.6435])

Errors due to complex values

Originally your question showed the use of sin(y), which gives the complex error that @Prakash discusses

In [10]: refIndexSize("sin(y)")
Traceback (most recent call last):
  File "<ipython-input-10-d470e7448a68>", line 1, in <module>
    refIndexSize("sin(y)")
  File "<ipython-input-2-6fea36c332b7>", line 9, in refIndexSize
    abs(round(float(solve(upperProfile)[0]),5))]
  File "/usr/local/lib/python3.8/dist-packages/sympy/core/expr.py", line 358, in __float__
    raise TypeError("can't convert complex to float")
TypeError: can't convert complex to float

Let's simplify your function to get rid float call that seems to be giving problems

In [11]: def refIndexSize(medium):
    ...:    lowerProfile = Eq(eval(medium), 1)
    ...:    upperProfile = Eq(eval(medium), 1.6)
    ...:    bounds = [solve(lowerProfile),
    ...:              solve(upperProfile)]
    ...:    return lowerProfile, bounds
    ...: 

Run on sin(y) 1), we get the [0.0, 0.6435] values as before:

In [12]: refIndexSize("sin(y) 1")
Out[12]: (Eq(sin(y)   1, 1), [[0, pi], [0.643501108793284, 2.49809154479651]])

Run on sin(y), we see that the 'raw' bounds includes complex values:

In [13]: refIndexSize("sin(y)")
Out[13]: 
(Eq(sin(y), 1),
 [[pi/2],
  [1.5707963267949 - 1.04696791500319*I,
   1.5707963267949   1.04696791500319*I]])

If you really need a rounded float from such an answer, you need to either extract the real part first, or use abs first:

In [15]: bounds = _[1][1]
In [17]: abs(bounds[0])
Out[17]: 1.88773486361789
  •  Tags:  
  • Related