Результаты scipy.optimize.minimize различаются между Python 2.x-3.x

По сути, у меня есть нелинейная проблема с ограничениями, использующая решатель SLSQP в scipy.optimize.minimize. К сожалению, проблема (один и тот же файл, один и тот же код) возвращает разные результаты на разных компьютерах (один Windows, один Linux). Версия scipy такая же (1.2.1). Вот мой код:

import numpy as np
from scipy.optimize import minimize

class OptimalAcc():
    def __init__(self, v0, tg, tr, D0, sgr, l, t0, a0, b0, 
                       rho_t=0.5, rho_u=0.5, vM=15, vm=2.78, aM=2.5, am=-2.9):

        # Problem constants
        self.v0 = v0
        self.D0 = D0
        self.sgr = sgr
        self.l = l
        self.T = tg + tr
        self.D = tg / self.T
        self.t0 = t0
        self.a0 = a0
        self.b0 = b0        
        self.rho_t = rho_t
        self.rho_u = rho_u
        self.vM = vM
        self.vm = vm
        self.aM = aM
        self.am = am

    def cost_fn(self, x):

        # Acceleration profile variables
        t = x[:1]
        a = x[1:2]
        b = x[2:3]

        # Objective function
        f = self.rho_t*x[:1]+self.rho_u*(a**2*t**3/3 +
                                         a*b*t**2 +
                                         b**2*t)
        return f

    def solve(self):

        # Inequality constraints
        ineq = ({'type':'ineq',
             'fun':lambda x: np.array([self.aM - x[2],
                                       x[2]-self.am,
                                       x[0],
                                       self.vM - (self.v0 + x[2]*x[0] + 0.5*x[1]*x[0]**2),
                                       self.v0 + x[2]*x[0] + 0.5*x[1]*x[0]**2 - self.vm,
                                       np.sin(np.pi*self.D - np.pi/2)-
                                       np.sin(2*np.pi*(x[0] -((self.D0*self.T)/abs(self.sgr-2)))/self.T + 3*np.pi/2 - np.pi*self.D)])})

        # Equality constraints
        eq = ({'type':'eq',
               'fun':lambda x: np.array([x[1]*x[0] + x[2],
                                         self.v0*x[0] + 0.5*x[2]*x[0]**2 + x[1]*x[0]**3/6 - self.l])})

        # Starting points
        x0 = np.array([self.t0, self.a0, self.b0])

        # Solve optimization problem
        res = minimize(self.cost_fn, 
                       x0=x0,
                       constraints=[ineq,eq],
                       options={'disp': True})

        return res

if __name__== "__main__":
    v0 = 1
    tg = 20
    tr = 20
    D0 = 1
    sgr = 1
    l = 70
    t0 = 10
    a0 = -0.1
    b0 = 1.5

    # Create instance of optimization problem class
    obj = OptimalAcc(v0, tg, tr, D0, sgr, l, t0, a0, b0)

    # Solve problem and return optimal profile
    u_t = obj.solve().x
    print('x_1:',u_t[0])
    print('x_2:',u_t[1])
    print('x_3:',u_t[2])

Машина Windows дает:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 8.696191258640086
            Iterations: 7
            Function evaluations: 35
            Gradient evaluations: 7
x_1: 13.508645429307041
x_2: -0.06874922875473621
x_3: 0.9287089606820067

Я считаю, что эти результаты локально оптимальны, и я могу проверить тот же результат с помощью fmincon в MATLAB.

Однако машина Linux дает:

Positive directional derivative for linesearch    (Exit mode 8)
            Current function value: 14.4116342889
            Iterations: 17
            Function evaluations: 147
            Gradient evaluations: 13
x_1: 7.65875894797259
x_2: -0.241800477348664
x_3: 2.5000000000000053

Очевидно, что оптимизатор застревает на компьютере с Linux. Что может быть причиной этого? Мое единственное предположение состоит в том, что в numpy есть некоторая точность, которая отбрасывает числа.


person Backstrom    schedule 14.05.2019    source источник
comment
Невозможно воспроизвести результат; запуск его в Ubuntu 18.04 дает мне те же результаты, что и для окон (запуск scipy 1.1.0 и numpy 1.15.1). Какую версию питона вы используете?   -  person Cleb    schedule 14.05.2019
comment
Компьютер с Linux работает под управлением 2.7, Windows - 3.6. Но я предполагаю, что Python здесь не виноват?   -  person Backstrom    schedule 14.05.2019
comment
А, может, это и в самом деле. В Python 2 a**2*t**3/3 может вызвать проблему, если все значения являются целыми числами, то есть все дроби, в которых вы используете целые числа вместо чисел с плавающей запятой. Не могли бы вы добавить from __future__ import division вверху и посмотреть, решит ли это проблему?   -  person Cleb    schedule 14.05.2019
comment
Ты прав! Сейчас у меня нет доступа к машине с Linux, но я реплицировал все на виртуальную машину Linux на свой компьютер с Windows и получил оба результата после добавления from __future__ import division. Огромное спасибо!   -  person Backstrom    schedule 15.05.2019
comment
Это урок отладки: машина A — Linux/Python 2.7, B — Win/Python 3.6. Просто констатируйте эти факты, не спешите с предположением, что это должны быть операционные системы. Кроме того, сравните яблоки с яблоками: запустите его на обеих платформах 3.6 (!). Кроме того, к настоящему времени существует множество руководств по миграции/методов тестирования при миграции с 2 на 3, прочтите их и напишите несколько тестовых случаев.   -  person smci    schedule 16.05.2019
comment
Я отредактировал ваш заголовок, чтобы убрать предположение, что это должна быть операционка. и на самом деле это даже не scipy.optimize.minimize, это просто разница Python 2.x-3.x в вашем коде.   -  person smci    schedule 16.05.2019


Ответы (1)


Как обсуждалось в комментариях, проблема, скорее всего, связана не с Windows и Linux, а скорее с Python 2 и Python 3. Например, термин

a**2*t**3/3

может выглядеть по-разному между Python 2 и 3, поскольку могут быть задействованы только целые числа (в вашем коде есть больше подобных примеров).

Простое исправление может состоять в том, чтобы включить

from __future__ import division

в верхней части вашего скрипта, который позаботится о различиях в том, как выполняются деления в Python 2 и 3.

person Cleb    schedule 15.05.2019