简体   繁体   中英

Combining Sympy with scipy.optimize.least_squares

I'm trying to calculate the value of the variables D and theta for which the function E attains its minimum value.

E = sqrt(x1-Dcos(theta)^2 + (y1-Dsin(theta)^2)) + sqrt(x2-2Dcos(theta)^2 + (y2-2Dsin(theta)^2)) + sqrt(x3-3Dcos(theta)^2 + (y3-3Dsin(theta)^2)) .

Here, (x1,y1), (x2,y2), (x3,y3) are known. Now I calculate the partial derivatives of E wrt to D and theta and set them to zero. Now I have 2 equations and 2 unknowns, so theoretically this system should be exactly solvable. The only issue here is that this is highly non-linear. So analytical solutions are out of the question. I'm using Sympy here to calculate the partial derivatives and generate the equations to be used in least_squares from scipy.optimize. I do get a solution for D and theta but it doesn't make any physical sense. Furthermore, the cost value of least_squares is ~17, so my solutions are not very reliable, right? Could someone help me out here? Here's the code:

import sympy as sym
D, theta = sym.symbols("D, theta")
x1,x2,x3 = 9.0,22.0,24.0 
y1,y2,y3 = 14.0,14.0,14.0

E = ((x1-D*sym.cos(theta))**2 + (y1-D*sym.sin(theta))**2)**0.5 + ((x2-2*D*sym.cos(theta))**2 + (y2-2*D*sym.sin(theta))**2)**0.5 + ((x3-3*D*sym.cos(theta))**2 + (y3-3*D*sym.sin(theta))**2)**0.5

gradient = sym.derive_by_array(E, (D, theta))

from scipy.optimize import least_squares as ls
grad = sym.lambdify((D, theta), gradient)
A = ls(lambda v: grad(v[0],v[1]), (8,0), bounds=([0, -22.5*np.pi/180], [12, 22.5*np.pi/180]))  #theta should be between -22.5 degree and 22.5 degree and D should be between 0 and 12 but ideally not 0.
D2, theta2 = A.x # 0.04561884938833529 -0.3926990816987241

I should also mention that calculating D and theta is part of a problem that involves fitting a line through (x1,y1), (x2,y2), (x3,y3), and (13,2). D is the distance between (13,2) and the first point closest to (x1,y1) on the fitted line, 2D is similarly the distance between (13,2) and the second point closest to (x2,y2), and so on. This analysis has to be done over all the gridpoints on a lat-lon grid of size (21,69). All alternate suggestions to solve this problem are also welcome. Thanks in advance!

You are looking to approximate the sequence 9, 22, 24 with an equidistant sequence like 11,18,25 . This does not have a good fit, so a large residual value is reasonable.

Doing the least square sum manually gives 

(a-d-9)^2 + (a-22)^2 + (a+d-24)^2 = 3*a^2 +2*d^2 - 110*a - 30*d +const

so the optimum is at a = 55/3 = 18+1/3 and d = 15/2 = 7+1/2  

On a second glance, you try to minimize the sum of norms, that is, the sum of distances from points on a line parallel to the x axis to points equidistant on a line through the origin. You can do that without doing any least-squares gradient optimization (which is a strange idea anyway, why not just find the zero location of the gradient with fsolve ?)

x = np.array([ 9.0,22.0,24.0]) 
y = np.array([14.0,14.0,14.0])
K = 1+np.arange(len(x))

target = lambda X,Y: sum(np.hypot(x-K*X, y-K*Y))

from scipy.optimize import fmin, minimize

#U = fmin(lambda u: target(*u), [4,4])
U = minimize(lambda u: target(*u), [4,4])
print(U)
X,Y = U.x
print(X,Y, np.hypot(X,Y), np.arctan2(Y,X))
K = np.arange(1+len(x))
plt.plot(x,y,'o', ms=8); plt.plot(K*X,K*Y, '-s', ms=4); plt.grid(); plt.show()

with the results

fmin:
-----
Optimization terminated successfully.
         Current function value: 16.987937
         Iterations: 49
         Function evaluations: 92

minimize:
---------
      fun: 16.987921401556633
 hess_inv: array([[2.72893764e-08, 6.01803467e-08],
       [6.01803467e-08, 1.53257534e-07]])
      jac: array([ 1.29665709, -0.08849001])
  message: 'Desired error not necessarily achieved due to precision loss.'
     nfev: 740
      nit: 29
     njev: 182
   status: 2
  success: False
        x: array([8.        , 4.66666667])

X: 8.000000, Y: 4.666667, 
D: 9.261629, theta:  0.5280744

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM