multivariable linearization in python: 'Pow' object has no attribute 'sqrt' - python

As a newcomer to Python world, I'm just simply about to linearize the following two variable function:
function
using the fairly routine Newton method:
linearization method
Here is what I've tried so far:
import numpy as np
import math
from sympy import symbols, diff
d = 1.7
def f(arg1, arg2):
return (arg1 - arg2)/(np.power(np.linalg.norm(arg1 - arg2),2) - np.power(d,2))
def linearize_f(f, arg1, arg2, equi_arg1, equi_arg2):
arg1, arg2 = symbols('arg1 arg2', real=True)
der_1 = diff(f(arg1,arg2), arg1)
der_2 = diff(f(arg1,arg2), arg2)
constant_term = f(equi_arg1, equi_arg2)
vars = sympy.symbols('arg1, arg2')
par_term_1 = sympy.evalf(der_1, subs = dict(zip(vars,[equi_arg1, equi_arg2])))
par_term_2 = sympy.evalf(der_2, subs = dict(zip(vars,[equi_arg1, equi_arg2])))
result = constant_term + par_term_1*(arg1-equi_arg1) + par_term_2*(arg2-equi_arg2)
return result
q0, q1 = symbols('q0 q1', real=True)
result = linearize_f(f,q0,q1,0,0)
print(result)
The interpreter returns a 'Pow' object has no attribute 'sqrt'. However, I've never used any sqrt in my code.
Would you please help me to resolve the case?

You have not called sqrt but np.linalg.norm has. The arg1, arg2 arguments are of type sympy.Symbol. The function expects to get an array-like argument. However, it gets a sympy symbol, which it does not know how to handle.
I looked in the np.linalg source code, and it seems that it checks for some known types and tries to find the square root. Otherwise, it relies on the argument itself to know its own square root. sympy.Symbol has no such thing, and hence the error.
There is no way to avoid this. numpy works with numbers, sympy works with (its own) symbols. You are not supposed to mix them. Most likely sympy will have its own functions for handling its own symbols, but, if not, you are out of luck, unless you add them yourself.

I've narrowed your error to this:
q0, q1 = symbols('q0 q1', real=True)
np.linalg.norm(q0 - q1) # Throws the same error
Here's the source code in np.linalg where it threw the error:
2347
2348 # Immediately handle some default, simple, fast, and common cases.
2349 if axis is None:
2350 ndim = x.ndim
2351 if ((ord is None) or
2352 (ord in ('f', 'fro') and ndim == 2) or
2353 (ord == 2 and ndim == 1)):
2354
2355 x = x.ravel(order='K')
2356 if isComplexType(x.dtype.type):
2357 sqnorm = dot(x.real, x.real) + dot(x.imag, x.imag)
2358 else:
2359 sqnorm = dot(x, x)
2360 ret = sqrt(sqnorm)
2361 if keepdims:
2362 ret = ret.reshape(ndim*[1])
2363 return ret
Apparently, after your sympy object has been processed by dot, it became a Pow object, which is a sympy object that np.sqrt has no idea what to do with.
The reason for this apparently is that you cannot use numpy function for sympy objects. Pow is a sympy object and as such numpy.sqrt cannot operate on this object.
After more reasearch, apparently this question from long time ago sympy AttributeError: 'Pow' object has no attribute 'sin' also point to the same reason.

Related

Numba fails to compile np.select based function in nopython mode

I am attempting to compile what is effectively a piecewise function using numba.njit. The Python function is defined as follows, using Numpy:
(for anyone interested in the Sympy origins of this issue, see the Notes below.)
Minimal Example
from numpy import select, less, nan
def f(t):
condlist = [less(t, 5), less(t, 15), less(t, 20), True]
choicelist = [1, 0, 1, 0]
return select(condlist, choicelist, default=nan)
See below for confirmation that this function works in Python.
The Issue: However, Numba fails to JIT this function in nopython mode:
from numba import njit
jit_f = njit(f)
x = np.linspace(0, 50, 500)
jit_f(x)
---------------------------------------------------------------------------
TypingError Traceback (most recent call last)
Input In [86], in <cell line: 5>()
2 jit_f = njit(f)
4 x = np.linspace(0,50,500)
----> 5 jit_f(x)
File /usr/local/lib/python3.8/site-packages/numba/core/dispatcher.py:468, in _DispatcherBase._compile_for_args(self, *args, **kws)
464 msg = (f"{str(e).rstrip()} \n\nThis error may have been caused "
465 f"by the following argument(s):\n{args_str}\n")
466 e.patch_message(msg)
--> 468 error_rewrite(e, 'typing')
469 except errors.UnsupportedError as e:
470 # Something unsupported is present in the user code, add help info
471 error_rewrite(e, 'unsupported_error')
File /usr/local/lib/python3.8/site-packages/numba/core/dispatcher.py:409, in _DispatcherBase._compile_for_args.<locals>.error_rewrite(e, issue_type)
407 raise e
408 else:
--> 409 raise e.with_traceback(None)
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function select at 0x105f4d310>) found for signature:
>>> select(LiteralList((array(bool, 1d, C), array(bool, 1d, C), array(bool, 1d, C), Literal[bool](True))), list(int64)<iv=[1, 0, 1, 0]>, default=float64)
There are 2 candidate implementations:
- Of which 1 did not match due to:
Overload in function 'np_select': File: numba/np/arraymath.py: Line 4358.
With argument(s): '(Poison<LiteralList((array(bool, 1d, C), array(bool, 1d, C), array(bool, 1d, C), Literal[bool](True)))>, list(int64)<iv=None>, default=float64)':
Rejected as the implementation raised a specific error:
TypingError: Poison type used in arguments; got Poison<LiteralList((array(bool, 1d, C), array(bool, 1d, C), array(bool, 1d, C), Literal[bool](True)))>
raised from /usr/local/lib/python3.8/site-packages/numba/core/types/functions.py:236
- Of which 1 did not match due to:
Overload in function 'np_select': File: numba/np/arraymath.py: Line 4358.
With argument(s): '(LiteralList((array(bool, 1d, C), array(bool, 1d, C), array(bool, 1d, C), Literal[bool](True))), list(int64)<iv=[1, 0, 1, 0]>, default=float64)':
Rejected as the implementation raised a specific error:
NumbaTypeError: condlist must be a List or a Tuple
raised from /usr/local/lib/python3.8/site-packages/numba/np/arraymath.py:4375
During: resolving callee type: Function(<function select at 0x105f4d310>)
During: typing of call at /var/folders/dt/q6vbs0g56s70g4p2kyfj4tvh0000gn/T/ipykernel_61924/130570246.py (5)
File "../../../../../../../../../var/folders/dt/q6vbs0g56s70g4p2kyfj4tvh0000gn/T/ipykernel_61924/130570246.py", line 5:
<source missing, REPL/exec in use?>
I'm not a Numba expert, but my feeling is that there is some syntax error. I've played around passing Numpy arrays and different formats of condlist and choicelist, but no luck so far.
Other Notes
The Python function behaves as expected, in this case giving some binary oscillations and then zero:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 50, 500)
plt.plot(x, f(x))
For any Sympy aficionados, the overlying problem here is with using Numba to JIT compile a lambda generated via Sympy from sympy.Piecewise. A lambda very similar to f(t) in the above example can be autogenerated by sympy.lambdify on a Piecewise function.
Numba does not currently implement all Numpy function and the support is sometimes limited. You can find the list of supported functions in the documentation. For np.select, the documentation states that the support is limited to:
only using homogeneous lists or tuples for the first two arguments, condlist and choicelist. Additionally, these two arguments can only contain arrays (unlike Numpy that also accepts tuples).
The thing is condlist is not homogeneous since the 3 first items of the list are arrays while the last is a boolean value. Additionally, choicelist contains integers while it must contains arrays.
One solution to fix this problem is to use the following code:
def f(t):
condlist = [less(t, 5), less(t, 15), less(t, 20), np.full(t.size, True)]
all_zeros = np.zeros(t.size)
all_ones = np.ones(t.size)
choicelist = [all_ones, all_zeros, all_ones, all_zeros]
return select(condlist, choicelist, default=nan)
However, please do not use this code as it is inefficient. Indeed, it creates many temporary arrays that are slow to create and fill. The code will certainly be memory bound and memory is a scarce resource only slowly improving over the last decades (this is called the "memory wall"). Optimizing such code is hard and Numba is not faster than Numpy for that. In fact, Numpy is already quite efficient to do that since it is implemented in C and most function are carefully optimized. Numba is fast when you use loops and avoid creating (useless) temporary arrays. Put it shortly: Numba likes loops as opposed to Numpy. Here is a much faster solution:
def f(t):
result = np.empty(t.size)
for i in range(t.size):
result[i] = t[i] < 5 or 15 <= t[i] < 20
return result
Note that using a boolean or a short integer (eg. int8) output type should be even faster (floating-point numbers are slow to compute and takes a lot of space in memory).

odeint -(TypeError: can't convert expression to float ) - Importing expression into a function to perform odeint

This is the error I get
Traceback (most recent call last):
File "C:\Users\user\.spyder-py3\Numerical Methods Problems\FreeFall.py", line 40, in <module>
ans=odeint(vel,0,t)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\odepack.py", line 245, in odeint
int(bool(tfirst)))
File "C:\ProgramData\Anaconda3\lib\site-packages\sympy\core\expr.py", line 325, in __float__
raise TypeError("can't convert expression to float")
TypeError: can't convert expression to float
And Here is my code - I am pretty new to coding and am learning to use it for numerical computation:
from scipy.integrate import odeint
from sympy import *
import numpy as np
import math
def diff_cd(re_no):
Re=Symbol('Re')
expr=(24/Re)+(6/(1+(Re**0.5)))+0.4
ans=diff(expr,Re).subs(Re,re_no)
return ans
def diff_re(k,u_no):
u=Symbol('u')
expr=k*u
ans=diff(expr,u).subs(u,u_no)
return ans
ans = [diff_cd(20),diff_re(11,15)]
rhog=1.2
mug=1.872*(10**(-5))
a=0.3
u=Symbol('u')
pi=math.pi
k=(2*rhog*a/mug)
Re=k*u
p1=(rhog*pi*(a**2)*u*Re*((24/Re)+(6/(1+(Re**0.5)))+0.4))+(0.5*rhog*pi*(a**2)*(u**2)*diff_cd(Re)*diff_re(k,u))
ansfu=p1*(-1/24)
def vel(y,t):
dudt = ansfu
return dudt
t=np.linspace(1,100,100)
ans=odeint(vel,0,t)
print(ans)
I just need is to get an answer without this error. Also is there a way to do all this in a single function
If I add a print(vel(0,0)) before the ode call I get
-271.868595022194*u**2*(-3.97723522060237e-7*u**(-0.5)/(u**0.5 +
0.00509901951359279)**2 - 1.6224e-8/u**2) -
543.737190044387*u**2*(0.4 + 6/(196.116135138184*u**0.5 + 1) + 0.000624/u)
That is, a sympy expression, not a number. odeint cannot work with that!
u is defined as Symbol, and thus any python expression using it will also be a sympy expression.
Especially if you are new to coding, you should stick with one package or the other. If defining the function symbolically, then use sympy and its own solvers. But if a numeric solution of the kind that scipy produces is important, then define the function with python/numpy. Don't try to mix sympy and numpy (without a lot more experience).
Old question but it seems you could've solved this problem using sympy's lambdify function. You'd do it like this:
f = lambdify(x, x**2, modules=['scipy'])
now f is a lambda that you can use with scipy.

Foobar - Test cases not passing - Disorderly escape

0/10 test cases are passing.
Here is the challenge description:
(to keep formatting nice - i put the description in a paste bin)
Link to challenge description: https://pastebin.com/UQM4Hip9
Here is my trial code - PYTHON - (0/10 test cases passed)
from math import factorial
from collections import Counter
from fractions import gcd
def cycle_count(c, n):
cc=factorial(n)
for a, b in Counter(c).items():
cc//=(a**b)*factorial(b)
return cc
def cycle_partitions(n, i=1):
yield [n]
for i in range(i, n//2 + 1):
for p in cycle_partitions(n-i, i):
yield [i] + p
def solution(w, h, s):
grid=0
for cpw in cycle_partitions(w):
for cph in cycle_partitions(h):
m=cycle_count(cpw, w)*cycle_count(cph, h)
grid+=m*(s**sum([sum([gcd(i, j) for i in cpw]) for j in cph]))
return grid//(factorial(w)*factorial(h))
print(solution(2, 2, 2)) #Outputs 7
This code works in my python compiler on my computer but not on the foobar challenge??
Am I losing accuracy or something?
NOT HELPFUL
Just a guess: wrong types of the return values of the functions? str vs. int?
Improved Answer
First a more detailed explanation for the 'type of values' thing:
In python, values are typed also if you do not have to declare a type. E.g.:
>>> i = 7
>>> s = '7'
>>> print(i, s, type(i), type(s), i == s)
7 7 <class 'int'> <class 'str'> False
I do not know the exact tests that are applied to the code, but typically those involve some equality test with ==. If the type of the expected value and those value returned does not match, the equality fails. Perhaps Elegant ways to support equivalence ("equality") in Python classes might help.
The instruction to the challenge (see pastebin) also explicitly mentions the expected return types: the returned values must be string (see line 41 / 47).
In addtion, the instruction also states that one should 'write a function answer(w, h, s)' (line 6). The posted solution implements a function solution.
I was also stuck on this problem.
The error is because of data type mismatch i.e your function returns an integer but the question specifically asked for a string.
Wrapping the return statement in str() will solve the problem.
Your return type is an integer. Convert it to a string, and it will work.
return str(grid//(factorial(w)*factorial(h)))

Have trouble using numba atomic operation functions (cuda.atomic.compare_and_swap)

I am trying to use Numba to write cuda kernels for my code. And somehow I wanna use the atomic operation in part of my code and I wrote a test kernel to see how cuda.atomic.compare_and_swap works. On the documentation it says this:
enter image description here
from numba import cuda
import numpy as np
#cuda.jit
def atomicCAS(N,out1):
idx = cuda.threadIdx.x + cuda.blockIdx.x * cuda.blockDim.x
if idx >= N:
return
A = out1[idx:]
cuda.atomic.compare_and_swap(A,idx,0)
N = 1024
out1 = np.arange(N)
out1 = np.zeros(N)
dout1 = cuda.to_device(out1)
tpb = 32
bpg = int(np.ceil(N/tpb))
atomicCAS[bpg,tpb](N,dout1)
hout1 = dout1.copy_to_host()
Then I got this error:
TypingError: Invalid use of Function(<class 'numba.cuda.stubs.atomic.compare_and_swap'>) with argument(s) of type(s): (array(float64, 1d, A), int64, Literal[int](0))
* parameterized
In definition 0:
All templates rejected with literals.
In definition 1:
All templates rejected without literals.
This error is usually caused by passing an argument of a type that is unsupported by the named function.
[1] During: resolving callee type: Function(<class 'numba.cuda.stubs.atomic.compare_and_swap'>)
[2] During: typing of call at /home/qinyu/test.py (20)
This is a pretty naive code and I think I feed in the write type of variables but I got this typingerror. It worked pretty well with the other atomic operations in Numba. This is the only one that does not work for me. Can somebody help me figure out the problem or is there another alternative ways to do this? Thanks!
The key in the error message is this:
array(float64, 1d, A), int64, Literal[int](0))
CUDA atomicCAS only supports integer types. You cannot pass a floating point type.

mpmath laplace inverse function in python

I am trying to find the laplace inverse of an expression for which all but one variable are already defined at the time of declaration:
from numpy import *
import mpmath as mp
p0 = 1
E = 2
c= 3
L = 4
x = 2.5
t = linspace(1,5,10)
ulaplace = []
def U(s):
return(c*p0*(-exp(L*s/c) + exp(s*(L + 2*x)/c))*exp(-s*x/c)/(E*s**2*(exp(2*L*s/c) + 1)))
for ti in t:
ulaplace.append(mp.invertlaplace(U, ti, method='talbot'))
But I am getting this error:
Traceback (most recent call last):
File "D:\TEMP\IDLEscripts\CompareAnalyticalSolutions2.py", line 46, in <module>
ulaplace.append(mp.invertlaplace(U, ti, method='talbot'))
File "C:\Python35\lib\site-packages\mpmath\calculus\inverselaplace.py", line 805, in invertlaplace
fp = [f(p) for p in rule.p]
File "C:\Python35\lib\site-packages\mpmath\calculus\inverselaplace.py", line 805, in <listcomp>
fp = [f(p) for p in rule.p]
File "D:\TEMP\IDLEscripts\CompareAnalyticalSolutions2.py", line 43, in U
return(c*p0*(-exp(L*s/c) + exp(s*(L + 2*x)/c))*exp(-s*x/c)/(E*s**2*(exp(2*L*s/c) + 1)))
TypeError: attribute of type 'int' is not callable
I also tried the lambda function format suggested by the doc website but still got the same error.
Does the mpmath.invertlaplace function require that everything be in numerical termsat the time of definition? I am asking because this worked:
>>> import mpmath as mp
>>> def F(s):
return 1/s
>>> mp.invertlaplace(F,5, method = 'talbot')
mpf('1.0')
If so, I need to be able to circumvent this. The whole point for me is to play around with the other variables and see how they affect the inverse laplacian. Furthermore one would think that the function gets evaluated before it is passed on to mpmath.
If not, then what on earth is going on here?
Allright I got it. Basically the function that mp.invertlaplace needs to itself only use mpmath defined functions. In the code provided in the original question I am using exp from the numpy library. So exp(x) is really numpy.exp(x). To make the code work it needs to call the mpmath.exp function as follows:
def U(s):
return -p0*mp.exp(s*x/c)/(E*s*(-s*mp.exp(L*s/c)/c - s*mp.exp(-L*s/c)/c)) + p0*mp.exp(-s*x/c)/(E*s*(-s*mp.exp(L*s/c)/c - s*mp.exp(-L*s/c)/c))
I have not tested the above on the reduced example I provided in the original question, since it is a subset of the more general script. However it should work and this appears to be the root of the problem.

Categories

Resources