小能豆

使用 Python Gekko 解决全局最小值与局部最小值问题

py

一个简单的优化示例在(0,0,8)目标为936.0(7,0,0)目标为处有 2 个局部最小值。在 Python Gekko ( , , ) 中使用局部优化器来找到全局解决方案951.0的技巧有哪些?APOPT``BPOPT``IPOPT

from gekko import GEKKO
m = GEKKO(remote=False)
x = m.Array(m.Var,3,lb=0)
x1,x2,x3 = x
m.Minimize(1000-x1**2-2*x2**2-x3**2-x1*x2-x1*x3)
m.Equations([8*x1+14*x2+7*x3==56,
             x1**2+x2**2+x3**2>=25])
m.solve(disp=False)
res=[print(f'x{i+1}: {xi.value[0]}') for i,xi in enumerate(x)]
print(f'Objective: {m.options.objfcnval:.2f}')

这产生了一个局部最小值:

x1: 7.0
x2: 0.0
x3: 0.0
Objective: 951.00

有用于全局优化的求解器,例如BARONCOCOSGlobSol、、和,但有哪些快速策略可以与局部优化器一起使用来搜索全局解决方案?一些工业应用具有高度非线性的模型,尚未在控制和ICOS设计方面对全局解决方案进行全面测试。该策略可以在 Python 中并行化吗?LGO``LINGO``OQNLP


阅读 12

收藏
2024-12-11

共1个答案

小能豆

多起点方法(使用随机起点)可能很有用。虽然不能保证全局最优,但至少可以在一定程度上防止出现一些令人尴尬的糟糕局部解决方案。一些本地 NLP 求解器内置了此功能(例如 Knitro)。

以下是使用多启动方法获取全局解决方案的示例 Python 代码。它使用多线程来并行化搜索。

import numpy as np
import threading
import time, random
from gekko import GEKKO

class ThreadClass(threading.Thread):
    def __init__(self, id, xg):
        s = self
        s.id = id
        s.m = GEKKO(remote=False)
        s.xg = xg
        s.objective = float('NaN')

        # initialize variables
        s.m.x = s.m.Array(s.m.Var,3,lb=0)
        for i in range(3):
            s.m.x[i].value = xg[i]
        s.m.x1,s.m.x2,s.m.x3 = s.m.x

        # Equations
        s.m.Equation(8*s.m.x1+14*s.m.x2+7*s.m.x3==56)
        s.m.Equation(s.m.x1**2+s.m.x2**2+s.m.x3**2>=25)

        # Objective
        s.m.Minimize(1000-s.m.x1**2-2*s.m.x2**2-s.m.x3**2
                     -s.m.x1*s.m.x2-s.m.x1*s.m.x3)

        # Set solver option
        s.m.options.SOLVER = 1

        threading.Thread.__init__(s)

    def run(self):
        print('Running application ' + str(self.id) + '\n')
        self.m.solve(disp=False,debug=0) # solve
        # Retrieve objective if successful
        if (self.m.options.APPSTATUS==1):
            self.objective = self.m.options.objfcnval
        else:
            self.objective = float('NaN')
        self.m.cleanup()

# Optimize at mesh points
x1_ = np.arange(0.0, 10.0, 3.0)
x2_ = np.arange(0.0, 10.0, 3.0)
x3_ = np.arange(0.0, 10.0, 3.0)
x1,x2,x3 = np.meshgrid(x1_,x2_,x3_)

threads = [] # Array of threads

# Load applications
id = 0
for i in range(x1.shape[0]):
    for j in range(x1.shape[1]):
        for k in range(x1.shape[2]):
            xg = (x1[i,j,k],x2[i,j,k],x3[i,j,k])
            # Create new thread
            threads.append(ThreadClass(id, xg))
            # Increment ID
            id += 1

# Run applications simultaneously as multiple threads
# Max number of threads to run at once
max_threads = 8
for t in threads:
    while (threading.activeCount()>max_threads):
        # check for additional threads every 0.01 sec
        time.sleep(0.01)
    # start the thread
    t.start()

# Check for completion
mt = 10.0 # max time (sec)
it = 0.0  # time counter
st = 1.0  # sleep time (sec)
while (threading.active_count()>=3):
    time.sleep(st)
    it = it + st
    print('Active Threads: ' + str(threading.active_count()))
    # Terminate after max time
    if (it>=mt):
        break

# Initialize array for objective
obj = np.empty_like(x1)

# Retrieve objective results
id = 0
id_best = 0; obj_best = 1e10
for i in range(x1.shape[0]):
    for j in range(x1.shape[1]):
        for k in range(x1.shape[2]):
            obj[i,j,k] = threads[id].objective
            if obj[i,j,k]<obj_best:
                id_best = id
                obj_best = obj[i,j,k]
            id += 1

print(obj)
print(f'Best objective {obj_best}')
print(f'Solution {threads[id_best].m.x}')

它产生了全局解决方案:

Best objective 936.0
Solution [[0.0] [0.0] [8.0]]
2024-12-11