SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy (talaffuzi sai pie) - bu C va Fortran kutubxonalarini o'z ichiga olgan numpy asosidagi matematika to'plami. SciPy interaktiv Python seansingizni MATLAB, IDL, Octave, R yoki SciLab kabi to'liq ma'lumot faniga aylantiradi.

Ushbu maqolada biz matematik dasturlashning asosiy usullarini ko'rib chiqamiz - scipy.optimize paketi yordamida bir nechta o'zgaruvchilarning skalyar funksiyasi uchun shartli optimallashtirish masalalarini hal qilish. Cheklanmagan optimallashtirish algoritmlari allaqachon muhokama qilingan oxirgi maqola. Scipy funktsiyalari bo'yicha batafsil va dolzarb yordamni har doim help() buyrug'i, Shift+Tab yoki ichidan olish mumkin. rasmiy hujjatlar.

kirish

Scipy.optimize paketidagi shartli va cheklanmagan optimallashtirish muammolarini hal qilish uchun umumiy interfeys funksiya tomonidan taqdim etiladi. minimize(). Biroq, ma'lumki, barcha muammolarni hal qilishning universal usuli yo'q, shuning uchun adekvat usulni tanlash, har doimgidek, tadqiqotchining yelkasiga tushadi.
Tegishli optimallashtirish algoritmi funktsiya argumenti yordamida belgilanadi minimize(..., method="").
Bir nechta o'zgaruvchilar funksiyasini shartli optimallashtirish uchun quyidagi usullarni qo'llash mumkin:

  • trust-constr — ishonchli mintaqada mahalliy minimumni izlash. Wiki maqola, Habré haqidagi maqola;
  • SLSQP — cheklovlar bilan ketma-ket kvadratik dasturlash, Lagranj tizimini yechishning Nyuton usuli. Wiki maqola.
  • TNC - Kesilgan Nyuton Cheklangan, takrorlanishlar soni cheklangan, ko'p sonli mustaqil o'zgaruvchilarga ega chiziqli bo'lmagan funksiyalar uchun yaxshi. Wiki maqola.
  • L-BFGS-B - Broyden-Fletcher-Goldfarb-Shanno jamoasining usuli, Hessian matritsasidan vektorlarning qisman yuklanishi tufayli xotira sarfini kamaytirish bilan amalga oshirildi. Wiki maqola, Habré haqidagi maqola.
  • COBYLA — Lineer yaqinlashish orqali MARE cheklangan optimallashtirish, chiziqli yaqinlashish bilan cheklangan optimallashtirish (gradient hisobisiz). Wiki maqola.

Tanlangan usulga qarab, muammoni hal qilish uchun shartlar va cheklovlar boshqacha o'rnatiladi:

  • sinf ob'ekti Bounds usullari uchun L-BFGS-B, TNC, SLSQP, trust-constr;
  • ro'yxati (min, max) bir xil usullar uchun L-BFGS-B, TNC, SLSQP, trust-constr;
  • ob'ekt yoki ob'ektlar ro'yxati LinearConstraint, NonlinearConstraint COBYLA, SLSQP, trust-constr usullari uchun;
  • lug'at yoki lug'atlar ro'yxati {'type':str, 'fun':callable, 'jac':callable,opt, 'args':sequence,opt} COBYLA, SLSQP usullari uchun.

Maqola tavsifi:
1) Ob'ektlar sifatida belgilangan cheklovlar bilan ishonchli mintaqada shartli optimallashtirish algoritmidan foydalanishni ko'rib chiqing (metod="trust-constr"). Bounds, LinearConstraint, NonlinearConstraint ;
2) Lug'at shaklida ko'rsatilgan cheklovlar bilan eng kichik kvadratlar usuli (metod = "SLSQP") yordamida ketma-ket dasturlashni ko'rib chiqing. {'type', 'fun', 'jac', 'args'};
3) Veb-studiya misolida ishlab chiqarilgan mahsulotlarni optimallashtirish misolini tahlil qiling.

Shartli optimallashtirish usuli = "trust-constr"

Usulni amalga oshirish trust-constr asoslangan EQSQP tenglik shaklidagi cheklovlar bilan bog'liq muammolar uchun va boshqalar TRIP tengsizliklar ko'rinishidagi cheklovlar bilan bog'liq muammolar uchun. Ikkala usul ham ishonchli mintaqada mahalliy minimumni topish algoritmlari bilan amalga oshiriladi va keng ko'lamli muammolar uchun juda mos keladi.

Minimumni topish masalasini umumiy shaklda matematik shakllantirish:

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

Qattiq tenglik cheklovlari uchun pastki chegara yuqori chegaraga tenglashtiriladi SciPy, sharoitlar bilan optimallashtirish.
Bir tomonlama cheklov uchun yuqori yoki pastki chegara o'rnatiladi np.inf tegishli belgi bilan.
Ikki o'zgaruvchining ma'lum Rosenbrok funktsiyasining minimalini topish kerak bo'lsin:

SciPy, sharoitlar bilan optimallashtirish

Bunday holda, uning ta'rif sohasiga quyidagi cheklovlar qo'yiladi:

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

Bizning holatda, nuqtada o'ziga xos yechim mavjud SciPy, sharoitlar bilan optimallashtirish, ular uchun faqat birinchi va to'rtinchi cheklovlar amal qiladi.
Keling, cheklovlarni pastdan yuqoriga qarab ko'rib chiqamiz va ularni scipy-da qanday yozishni ko'rib chiqamiz.
Cheklovlar SciPy, sharoitlar bilan optimallashtirish и SciPy, sharoitlar bilan optimallashtirish uni Bounds obyekti yordamida aniqlaymiz.

from scipy.optimize import Bounds
bounds = Bounds ([0, -0.5], [1.0, 2.0])

Cheklovlar SciPy, sharoitlar bilan optimallashtirish и SciPy, sharoitlar bilan optimallashtirish Uni chiziqli shaklda yozamiz:

SciPy, sharoitlar bilan optimallashtirish

Keling, ushbu cheklovlarni LinearConstraint obyekti sifatida belgilaymiz:

import numpy as np
from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint ([[1, 2], [2, 1]], [-np.inf, 1], [1, 1])

Va nihoyat, matritsa ko'rinishidagi chiziqli bo'lmagan cheklov:

SciPy, sharoitlar bilan optimallashtirish

Biz ushbu cheklov uchun Yakobiy matritsasi va Gessian matritsasining ixtiyoriy vektor bilan chiziqli birikmasini aniqlaymiz. SciPy, sharoitlar bilan optimallashtirish:

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

Endi biz chiziqli bo'lmagan cheklovni ob'ekt sifatida belgilashimiz mumkin NonlinearConstraint:

from scipy.optimize import NonlinearConstraint

def cons_f(x):
     return [x[0]**2 + x[1], x[0]**2 - x[1]]

def cons_J(x):
     return [[2*x[0], 1], [2*x[0], -1]]

def cons_H(x, v):
     return v[0]*np.array([[2, 0], [0, 0]]) + v[1]*np.array([[2, 0], [0, 0]])

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=cons_H)

Agar o'lcham katta bo'lsa, matritsalar siyrak shaklda ham ko'rsatilishi mumkin:

from scipy.sparse import csc_matrix

def cons_H_sparse(x, v):
     return v[0]*csc_matrix([[2, 0], [0, 0]]) + v[1]*csc_matrix([[2, 0], [0, 0]])

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                            jac=cons_J, hess=cons_H_sparse)

yoki ob'ekt sifatida LinearOperator:

from scipy.sparse.linalg import LinearOperator

def cons_H_linear_operator(x, v):
    def matvec(p):
        return np.array([p[0]*2*(v[0]+v[1]), 0])
    return LinearOperator((2, 2), matvec=matvec)

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                jac=cons_J, hess=cons_H_linear_operator)

Hessian matritsasini hisoblashda SciPy, sharoitlar bilan optimallashtirish ko'p harakat talab qiladi, siz sinfdan foydalanishingiz mumkin HessianUpdateStrategy. Quyidagi strategiyalar mavjud: BFGS и SR1.

from scipy.optimize import BFGS

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=BFGS())

Hessianni chekli farqlar yordamida ham hisoblash mumkin:

nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = cons_J, hess = '2-point')

Cheklovlar uchun Yakobiy matritsasi cheklangan farqlar yordamida ham hisoblanishi mumkin. Biroq, bu holda Hessian matritsasi cheklangan farqlar yordamida hisoblab bo'lmaydi. Hessian funksiya sifatida aniqlanishi yoki HessianUpdateStrategy sinfidan foydalanishi kerak.

nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = '2-point', hess = BFGS ())

Optimallashtirish muammosining yechimi quyidagicha ko'rinadi:

from scipy.optimize import minimize
from scipy.optimize import rosen, rosen_der, rosen_hess, rosen_hess_prod

x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess,
                constraints=[linear_constraint, nonlinear_constraint],
                options={'verbose': 1}, bounds=bounds)
print(res.x)

`gtol` termination condition is satisfied.
Number of iterations: 12, function evaluations: 8, CG iterations: 7, optimality: 2.99e-09, constraint violation: 1.11e-16, execution time: 0.033 s.
[0.41494531 0.17010937]

Agar kerak bo'lsa, Hessianni hisoblash funktsiyasi LinearOperator klassi yordamida aniqlanishi mumkin.

def rosen_hess_linop(x):
    def matvec(p):
        return rosen_hess_prod(x, p)
    return LinearOperator((2, 2), matvec=matvec)

res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess_linop,
                 constraints=[linear_constraint, nonlinear_constraint],
                 options={'verbose': 1}, bounds=bounds)

print(res.x)

yoki parametr orqali Hessian va ixtiyoriy vektorning mahsuloti hessp:

res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hessp=rosen_hess_prod,
                constraints=[linear_constraint, nonlinear_constraint],
                options={'verbose': 1}, bounds=bounds)
print(res.x)

Shu bilan bir qatorda optimallashtirilayotgan funksiyaning birinchi va ikkinchi hosilalarini taxminan hisoblash mumkin. Masalan, Hessian funksiyasi yordamida taxminiy hisoblanishi mumkin SR1 (kvazi-Nyuton yaqinlashuvi). Gradientni chekli farqlar bilan taxmin qilish mumkin.

from scipy.optimize import SR1
res = minimize(rosen, x0, method='trust-constr',  jac="2-point", hess=SR1(),
               constraints=[linear_constraint, nonlinear_constraint],
               options={'verbose': 1}, bounds=bounds)
print(res.x)

Shartli optimallashtirish usuli = "SLSQP"

SLSQP usuli funktsiyani quyidagi shaklda minimallashtirish muammolarini hal qilish uchun mo'ljallangan:

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

SciPy, sharoitlar bilan optimallashtirish

Qaerda SciPy, sharoitlar bilan optimallashtirish и SciPy, sharoitlar bilan optimallashtirish — tenglik yoki tengsizlik koʻrinishidagi cheklovlarni tavsiflovchi iboralar koʻrsatkichlari toʻplami. SciPy, sharoitlar bilan optimallashtirish — funksiyani aniqlash sohasi uchun pastki va yuqori chegaralar to‘plami.

Chiziqli va chiziqli bo'lmagan cheklovlar kalitli lug'atlar ko'rinishida tasvirlangan type, fun и jac.

ineq_cons = {'type': 'ineq',
             'fun': lambda x: np.array ([1 - x [0] - 2 * x [1],
                                          1 - x [0] ** 2 - x [1],
                                          1 - x [0] ** 2 + x [1]]),
             'jac': lambda x: np.array ([[- 1.0, -2.0],
                                          [-2 * x [0], -1.0],
                                          [-2 * x [0], 1.0]])
            }

eq_cons = {'type': 'eq',
           'fun': lambda x: np.array ([2 * x [0] + x [1] - 1]),
           'jac': lambda x: np.array ([2.0, 1.0])
          }

Minimalni qidirish quyidagicha amalga oshiriladi:

x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='SLSQP', jac=rosen_der,
               constraints=[eq_cons, ineq_cons], options={'ftol': 1e-9, 'disp': True},
               bounds=bounds)

print(res.x)

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 0.34271757499419825
            Iterations: 4
            Function evaluations: 5
            Gradient evaluations: 4
[0.41494475 0.1701105 ]

Optimallashtirish misoli

Beshinchi texnologik tuzilmaga o'tish munosabati bilan, bizga kichik, ammo barqaror daromad keltiradigan veb-studiya misolida ishlab chiqarishni optimallashtirishni ko'rib chiqaylik. Keling, o'zimizni uchta turdagi mahsulotlarni ishlab chiqaradigan oshxona direktori sifatida tasavvur qilaylik:

  • x0 - ochilish sahifalarini sotish, 10 tr dan.
  • x1 - korporativ veb-saytlar, 20 tr dan.
  • x2 - onlayn-do'konlar, 30 tr dan.

Bizning do'stona ishchi jamoamiz to'rtta kichik, ikkita o'rta va bitta katta yoshlilardan iborat. Ularning oylik ish vaqti fondi:

  • Iyun: 4 * 150 = 600 чел * час,
  • o'rtalari: 2 * 150 = 300 чел * час,
  • senor: 150 чел * час.

Birinchi mavjud bo'lgan o'smirlar (x0, x1, x2), o'rta - (10, 20, 30), kattalar - (7, 15, 20) turdagi saytlarni ishlab chiqish va joylashtirishga (5, 10, 15) soat sarflashlariga ruxsat bering. ) hayotingizdagi eng yaxshi vaqt soatlari.

Har qanday oddiy direktor singari, biz oylik daromadni maksimal darajada oshirishni xohlaymiz. Muvaffaqiyatga erishish uchun birinchi qadam maqsad funktsiyasini yozishdir value oyiga ishlab chiqarilgan mahsulotdan olingan daromad miqdori sifatida:

def value(x):
    return - 10*x[0] - 20*x[1] - 30*x[2]

Bu xato emas, maksimalni qidirishda maqsad funktsiyasi qarama-qarshi belgi bilan minimallashtiriladi.

Keyingi qadam - xodimlarimizga ortiqcha ishlashni taqiqlash va ish vaqtiga cheklovlarni joriy etish:

SciPy, sharoitlar bilan optimallashtirish

Ekvivalent nima:

SciPy, sharoitlar bilan optimallashtirish

ineq_cons = {'type': 'ineq',
             'fun': lambda x: np.array ([600 - 10 * x [0] - 20 * x [1] - 30 * x[2],
                                         300 - 7  * x [0] - 15 * x [1] - 20 * x[2],
                                         150 - 5  * x [0] - 10 * x [1] - 15 * x[2]])
            }

Rasmiy cheklov shundan iboratki, mahsulot chiqishi faqat ijobiy bo'lishi kerak:

bnds = Bounds ([0, 0, 0], [np.inf, np.inf, np.inf])

Va nihoyat, eng qizg'in taxmin shuki, past narx va yuqori sifat tufayli biz uchun qoniqarli mijozlar navbati doimiy ravishda paydo bo'ladi. Biz cheklangan optimallashtirish muammosini hal qilish asosida oylik ishlab chiqarish hajmlarini o'zimiz tanlashimiz mumkin scipy.optimize:

x0 = np.array([10, 10, 10])
res = minimize(value, x0, method='SLSQP', constraints=ineq_cons, bounds=bnds)
print(res.x)

[7.85714286 5.71428571 3.57142857]

Keling, butun sonlargacha yaxlitlashamiz va mahsulotlarni optimal taqsimlash bilan eshkakchilarning oylik yukini hisoblaymiz. x = (8, 6, 3) :

  • Iyun: 8 * 10 + 6 * 20 + 3 * 30 = 290 чел * час;
  • o'rtalari: 8 * 7 + 6 * 15 + 3 * 20 = 206 чел * час;
  • senor: 8 * 5 + 6 * 10 + 3 * 15 = 145 чел * час.

Xulosa: direktor o'zining munosib maksimalini olishi uchun oyiga 8 ta ochilish sahifasi, 6 ta o'rta o'lchamli sayt va 3 ta do'kon yaratish maqbuldir. Bunday holda, kattalar mashinadan bosh ko'tarmasdan haydashlari kerak, o'rtalarning yuki taxminan 2/3, kichiklar esa yarmidan kam bo'ladi.

xulosa

Maqolada paket bilan ishlashning asosiy usullari ko'rsatilgan scipy.optimize, shartli minimallashtirish masalalarini hal qilish uchun ishlatiladi. Shaxsan men foydalanaman scipy faqat ilmiy maqsadlar uchun, shuning uchun berilgan misol juda kulgili xususiyatga ega.

Ko'pgina nazariya va virtual misollarni, masalan, I.L.Akulichning "Matematik dasturlash misollar va muammolarda" kitobida topish mumkin. Ko'proq qattiq dastur scipy.optimize tasvirlar to'plamidan 3D tuzilmani qurish (Habré haqidagi maqola) ichida ko'rish mumkin scipy-oshpaz kitobi.

Asosiy ma'lumot manbai docs.scipy.orgushbu va boshqa bo'limlarni tarjima qilishga hissa qo'shishni xohlovchilar scipy Ga Xush kelibsiz GitHub.

Rahmat mefistofelar nashrni tayyorlashda ishtirok etgani uchun.

Manba: www.habr.com

a Izoh qo'shish