7

As a newcomer to Python world, I'm just simply about to linearize the following two variable function:

function

enter image description here

using the fairly routine Newton method:

linearization method

enter image description here

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?

htshame
  • 6,599
  • 5
  • 36
  • 56
  • Verified. It seem to work fine if `arg1` and `arg2` are both numeric, same error when they're symbols. – Rocky Li Nov 23 '18 at 15:04
  • Can I ask what `arg1` and `arg2` is? Are they arrays or single number? – Rocky Li Nov 23 '18 at 15:14
  • @RockyLi: The arguments are "points". In other words, each one of them is a list with two elements like `x` and `y`. –  Nov 23 '18 at 15:17
  • The pictures of formulas seem irrelevant to the problem. As long as the code is sufficient to reproduce the bug, it doesn't matter what the source formula actually was. It's a bit of waste of reader's time forcing them to decipher the handwriting, when it's not essential. Other than that - nice question. – BartoszKP Nov 23 '18 at 15:28
  • Passing `sympy` objects to `numpy` functions often doesn't work. `numpy` does `np.asarray(arg)`, since the function is designed to work with `ndarray`. That's likely to produce an `object dtype` array. `np.sqrt(obj_array)` tries to perform `x.sqrt()` for each element of the array. That works if the element happens to have that method, and your error if it doesn't. – hpaulj Nov 23 '18 at 16:35
  • To be useful in this `sympy` code, your `f` has to be written as a `sympy` function, without any use of `numpy`. – hpaulj Nov 23 '18 at 16:45

2 Answers2

3

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.

blue_note
  • 27,712
  • 9
  • 72
  • 90
2

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.

Rocky Li
  • 5,641
  • 2
  • 17
  • 33
  • 1
    Thanks for pinpointing the source of issue, but can you exactly explain how can I resolve the issue? There is a way to do this, isn't it?! –  Nov 23 '18 at 15:35
  • You can maybe instead of using `np.linalg.norm`, use `sympy` function like `(args1-args2).norm()`? `norm` is a sympy function according to docs, you may also need to change `np.power` to `sympy.core.power` – Rocky Li Nov 23 '18 at 15:41
  • Doing this ends up with a `'add' object has no attribute norm` which I think means even the operation `(args1-args2)` is not known by sympy! https://docs.sympy.org/0.7.2/modules/matrices/matrices.html –  Nov 23 '18 at 15:59
  • Another sympy/numpy link, https://stackoverflow.com/questions/52619874/sympy-numpy-integration-exists-where-is-it-documented – hpaulj Nov 23 '18 at 16:41