'scipy.minimize messes up my constraint function

I am trying to run a minimization problem in python with scipy. The goal is to minimize the distance in meters between different coordinates.

#dependencies
pip install haversine

import scipy.optimize as spo
import haversine as hs
from haversine import Unit

hs.haversine returns the distance in meters between two pairs of coordinates (latitude, longitude). For example:

a = (41.160716, -8.582416)
b = (41.150537, -8.586245)
hs.haversine(a, b, unit = Unit.METERS)

1176.3758242489466 (meters)

hs.haversine is then used in my objective function and constraint like this:

def objFunction(X, M):
    sum = 0
    for i in X:
        for j in M:
            sum += hs.haversine(i, j, unit = Unit.METERS)
    return sum
def constraint1(X):
    for i in range(len(X)-1):
        for j in range(i + 1, len(X)):
                return hs.haversine(X[i], X[j], unit = Unit.METERS) - 40

The objective and constraint function both work fine on their own, but when I try to use minimize() it gives me an error.

I give my minimize() the following initial input x0 ('x_init') and a tuple of coordinates ('metro_stops') that I want to minimize the distance to:

x_init = ((41, -8), (41.5, -8.5))
metro_stops = ((41.160716, -8.582416), (41.150537, -8.586245))

con1 = {'type': 'ineq', 'fun': constraint1}
cons = [con1]

sol = spo.minimize(fun = objFunction, x0 = x_init, args = (metro_stops), method = 'SLSQP', constraints = (cons))

I get an error saying that the constraint function "cannot unpack a non-iterable numpy object". I can't understand why since the constraint function works fine when used outside of minimize().

Full error:

TypeError                                 Traceback (most recent call last)
<ipython-input-61-b414e685be2c> in <module>
----> 1 sol = spo.minimize(fun = objFunction, x0 = x_init, args = (metro_stops,), method = 'SLSQP', constraints = (cons))

~\anaconda3\lib\site-packages\scipy\optimize\_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    625         return _minimize_cobyla(fun, x0, args, constraints, **options)
    626     elif meth == 'slsqp':
--> 627         return _minimize_slsqp(fun, x0, args, jac, bounds,
    628                                constraints, callback=callback, **options)
    629     elif meth == 'trust-constr':

~\anaconda3\lib\site-packages\scipy\optimize\slsqp.py in _minimize_slsqp(func, x0, args, jac, bounds, constraints, maxiter, ftol, iprint, disp, eps, callback, finite_diff_rel_step, **unknown_options)
    328     meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
    329               for c in cons['eq']]))
--> 330     mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
    331                for c in cons['ineq']]))
    332     # m = The total number of constraints

~\anaconda3\lib\site-packages\scipy\optimize\slsqp.py in <listcomp>(.0)
    328     meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
    329               for c in cons['eq']]))
--> 330     mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args']))
    331                for c in cons['ineq']]))
    332     # m = The total number of constraints

<ipython-input-57-127f2f6960a1> in constraint1(X)
      2     for i in range(len(X)-1):
      3         for j in range(i + 1, len(X)):
----> 4                 return hs.haversine(X[i], X[j], unit = Unit.METERS) - 40

~\anaconda3\lib\site-packages\haversine\haversine.py in haversine(point1, point2, unit)
     86 
     87     # unpack latitude/longitude
---> 88     lat1, lng1 = point1
     89     lat2, lng2 = point2
     90 

TypeError: cannot unpack non-iterable numpy.float64 object

Thankful for any tips



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source