
SciPy (hÀÀldatakse nagu sai pai) on numpy'le pÔhinev matemaatikapakett, mis sisaldab ka C- ja Fortran-raamatukogusid. SciPy muudab interaktiivse Python seansi tÀielikuks andmetöötluskeskkonnaks, nagu MATLAB, IDL, Octave, R vÔi SciLab.
Selles artiklis vaatleme matemaatilise programmeerimise pĂ”himeetodeid â tingimustega optimeerimise probleemide lahendamine mitme muutuja skalaarsest funktsioonist scipy.optimize paketi abil. Ilma tingimusteta optimeerimise algoritmid on juba kĂ€sitletud . Ăksikasjalikku ja ajakohast teavet funktsioonide kohta scipy's saab alati kasutada kĂ€su help(), Shift+Tab vĂ”i .
Sissejuhatus
Ăks ĂŒhtne liides tingimustega ja ilma tingimusteta optimeerimise probleemide lahendamiseks scipy.optimize pakendis antakse funktsiooni kaudu minimize(). Siiski on teada, et universaalset viisi kĂ”igi probleemide lahendamiseks ei eksisteeri, seega langeb sobiva meetodi valik alati uurija Ă”lgadele.
Sobiv optimeerimisalgoritm mÀÀratakse funktsiooni argumendi kaudu minimize(..., method="").
Mitme muutuja tingimustega optimeerimise jaoks on saadaval jÀrgmiste meetodite rakendused:
trust-constrâ lokaalse miinimumi otsimine usaldusvÀÀrsuspiirkonnas. , ;SLSQPâ jĂ€rjestikune kvadratiivne programmeerimine piirangutega, Newtoni meetod Lagrange'i sĂŒsteemi lahendamiseks. .TNCâ Truncated Newton Constrained, piiratud iteratsioonide arv, sobiv mitteeline funktsioonide jaoks, millel on palju sĂ”ltumatuid muutujaid. .L-BFGS-Bâ BroydenâFletcherâGoldfarbâShanno meetod, mis on rakendatud vĂ€hendatud mĂ€lu tarbimisega, osalise Hess'i maatriksi vektorite laadimise kaudu. , .COBYLAâ KOBYLA Constrained Optimization By Linear Approximation, piiratud optimeerimine lineaarsest lĂ€henemisest (ilma gradientide arvutamiseta). .
SÔltuvalt valitud meetodist mÀÀratakse tingimused ja piirangud probleemide lahendamiseks erinevalt:
- klassist objekti
Boundsmeetodite jaoks L-BFGS-B, TNC, SLSQP, trust-constr; - loendi
(min, max)nende sama meetodite L-BFGS-B, TNC, SLSQP, trust-constr jaoks; - objekti vÔi objektide loend
LinearConstraint,NonlinearConstraintmeetodite jaoks COBYLA, SLSQP, trust-constr; - sÔnastiku vÔi sÔnastike loendi
{'type':str, 'fun':callable, 'jac':callable,opt, 'args':sequence,opt}meetodite jaoks COBYLA, SLSQP.
Artikli plaan:
1) Uurida tingimuslikku optimeerimisalgoritmi usaldusvÀÀrses valdkonnas (method=»trust-constr») piirangutega, mis on mÀÀratletud objektidena. Bounds, LinearConstraint, NonlinearConstraint ;
2) Uurida jÀrjestikust programmeerimist vÀhenenud ruutude meetodil (method=»SLSQP») piirangutega, mis on mÀÀratletud sÔnastikuna. {'type', 'fun', 'jac', 'args'};
3) AnalĂŒĂŒsida toodangu optimeerimise nĂ€idet veebistuudio nĂ€itel.
Tingimuslik optimeerimine method=»trust-constr»
Meetodi rakendamine trust-constr on pĂ”hinenud vĂ”rdsete piirangutega probleemidele ja ebaĂŒhtsete piirangute probleemidele. MĂ”lemad meetodid on ellu viidud usaldusvÀÀrse piirkonna kohaliku miinimumi otsimise algoritmidega ja sobivad hĂ€sti suurte probleemide lahendamiseks.
Probleemi matemaatiline vorm ĂŒldiselt minimumi leidmiseks:



Tehete range vĂ”rdsuse puhul seotakse alumine piir ĂŒlemise kĂŒlge.
.
Ăhepoolse piirangu korral seatakse ĂŒlemine vĂ”i alumine piir np.inf vastava mĂ€rgiga.
Oletame, et tuleb leida miinimum tuntud Rosenbrocki funktsioonist, mis sÔltub kahest muutuja:

Sellel on mÀÀratud jÀrgmised piirangud selle mÀÀramispiirkonnale:






Meie juhul on olemas ainus lahendus punktis
, kus kehtivad ainult esimene ja neljas piirang.
Liigume piirangute kaudu alt ĂŒles ja uurime, kuidas neid scipy-s ĂŒles kirjutada.
Piirangud
ja
mÀÀra objekti Bounds abil.
from scipy.optimize import Bounds
bounds = Bounds ([0, -0.5], [1.0, 2.0])Piirangud
ja
kirjutame lineaarse vormina:

MÀÀrame need piirangud objekti LinearConstraint kujul:
import numpy as np
from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint ([[1, 2], [2, 1]], [-np.inf, 1], [1, 1])Ja lÔpuks mitte-lineaarne piirang maatriksivormis:

MÀÀrame selle piirangu jaoks Jakobian ja Hesse maatriksi lineaarse kombinatsiooni suvalise vektoriga.
:


NĂŒĂŒd saame mitte-lineaarse piirangu mÀÀrata objekti 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)Kui suurus on suur, saab maatriseid mÀÀrata ka hÔredas vormis:
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)vÔi objekti LinearOperator:
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)Kui Hessian-matriisi arvutamine
nÔuab suurt ressursikasutust, saab kasutada klassi . Saadaval on jÀrgmised strateegiad: BFGS ja SR1.
scipy.optimize import BFGS
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=BFGS())Hessianti saab samuti arvutada lÔplike erinevuste abil:
nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = cons_J, hess = '2-point')Piirangute Jakobianit saab samuti arvutada lÔplike erinevuste abil. Kuid sel juhul ei saa Hessiani enam lÔplike erinevuste abil arvutada. Hessian peab olema mÀÀratletud funktsioonina vÔi lÀbi klassi HessianUpdateStrategy.
nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = '2-point', hess = BFGS ())Optimeerimisprobleemi lahendus on jÀrgmine:
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` lÔpetamise tingimus on tÀidetud.
Iteratsioonide arv: 12, funktsioonide hindamised: 8, CG iteratsioonid: 7, optimaalne: 2.99e-09, piirangute rikkumine: 1.11e-16, tÀitmise aeg: 0.033 s.
[0.41494531 0.17010937]Vajadusel saab Hessiani arvutamise funktsiooni mÀÀrata klassi LinearOperator abil
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)vÔi Hessiani ja suvalise vektori korrutamine parametri 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)Alternatiivselt saab optimeeritava funktsiooni esimesi ja teisi tuletusi ligikaudselt arvutada. NÀiteks saab Hessiani approximiseerida funktsiooni SR1 (kvasi-Newtoni lÀhenemine). Gradienti saab ligikaudselt arvutada lÔplike erinevustega.
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)Konventsionaalne optimeerimine method=»SLSQP»
SLSQP meetod on mÔeldud funktsiooni minimeerimise probleemide lahendamiseks kujul:




Kus
ja
â hulk indekseid, mis kirjeldavad piiranguid vĂ”rduste vĂ”i ebavĂ”rdsuste kujul.
â hulk alumisi ja ĂŒlemisi piire funktsiooni mÀÀramispiirkonnale.
Lineaarseid ja mitte-lineaarseid piiranguid kirjeldatakse sÔnaraamatutena, millel on vÔtmed type, lÔbu ja 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])
}Minimeerimise protseduur toimub jÀrgmiselt:
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)Optimeerimine lĂ”petati edukalt. (VĂ€ljamineku reĆŸiim 0)
Praegune funktsiooni vÀÀrtus: 0.34271757499419825
Iteratsioonid: 4
Funktsiooni hindamised: 5
Gradientide hindamised: 4
[0.41494475 0.1701105 ]Optimeerimise nÀide
Seoses viienda tehnoloogilise tsĂŒkli ĂŒleminekuga vaatleme tootmise optimeerimist veebistuudio nĂ€itel, mis toob meile vĂ€ikese, kuid stabiilse tulu. Kujutame ette, et oleme galerii direktor, kus toodetakse kolme tĂŒĂŒpi tooteid:
- x0 â mĂŒĂŒvad landindid, alates 10 t. r.
- x1 â ettevĂ”tte veebilehed, alates 20 t. r.
- x2 â internetipoed, alates 30 t. r.
Meie sĂ”bralik töörĂŒhm koosneb neljast algajatest, kahest keskastme töötajast ja ĂŒhest kogenud spetsialistist. Nende tööaja fond kuus:
- algajad:
4 * 150 = 600 inimene * tund, - keskastme töötajad:
2 * 150 = 300 inimene * tund, - kogenud spetsialist:
150 inimene * tund.
Oletame, et ĂŒhe tĂŒĂŒpi veebilehe (x0, x1, x2) arendamiseks ja juurutamiseks peab esimene juba tekkiv algaja kulutama (10, 20, 30) tundi, keskastme töötaja â (7, 15, 20), kogenud spetsialist â (5, 10, 15) parima ajaga oma elust.
Nagu igale normaalsele direktorile, soovime maksimeerida igakuist kasumit. Esimene samm edusammudeks â kirjutame sihtfunktsiooni value kui kuu jooksul toodetud toodete tulu summana:
def value(x):
return - 10*x[0] - 20*x[1] - 30*x[2]See ei ole viga; sihtfunktsiooni maksimeerimisel minimeeritakse see vastupidise mÀrgiga.
JĂ€rgmine samm â keelame oma töötajatel ĂŒletunde ja kehtestame piirangud tööaja fondile:

Mis on ekvivalentne:

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]])
}Formaalne piirang on see, et toodang peab olema ainult positiivne:
bnds = Bounds ([0, 0, 0], [np.inf, np.inf, np.inf])Ja lĂ”puks kĂ”ige roosilisem eeldus â madala hinna ja kĂ”rge kvaliteedi tĂ”ttu seisavad meie juures pidevalt rahulolevate klientide read. Saame ise valida kuukohustused toodangute tootmisel, lĂ€htudes tingimuslikust optimeerimisĂŒlesandest. 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]Ămmardame ligikaudu tĂ€isarvudeni ja arvutame kuukoormuse optimiseeritud toodangu korral. x = (8, 6, 3) :
- algajad:
8 * 10 + 6 * 20 + 3 * 30 = 290 inimest * tund; - keskastme töötajad:
8 * 7 + 6 * 15 + 3 * 20 = 206 inimest * tund; - kogenud spetsialist:
8 * 5 + 6 * 10 + 3 * 15 = 145 inimest * tund.
JÀreldus: et direktor saaks oma teenitud maksimumi, on optimaalne kuus teha 8 maandumist, 6 keskmist veebilehte ja 3 poodi. Seniors peab samal ajal tÔeliselt vaeva nÀgema, loaderite koormus jÀÀb umbes 2/3, juniorite vÀhem kui pool.
KokkuvÔte
Artiklis on esitatud pĂ”hitehnikad paketi scipy.optimize, mida kasutatakse tingimuslikku minimeerimise ĂŒlesannete lahendamiseks. Isiklikult kasutan ma scipy puhas akadeemiliste eesmĂ€rkide nimel, seega on antud nĂ€ide naljakas.
Palju teooriat ja haruldasi nĂ€iteid saab leida nĂ€iteks I.L. Akulichi raamatust "Matemaatiline programmeerimine nĂ€idete ja ĂŒlesannetega". Kaheldamatum rakendus scipy.optimize 3D struktuuri loomine pildigruppide pĂ”hjal () on nĂŒĂŒd vĂ”imalik nĂ€ha .
Peamine teabe allikas on , kes soovivad panustada tÔlkesesse ja teistesse osadesse, scipy teretulemast .
AitÀh osalemise eest vÀljaande ettevalmistamisel.
Allikas: habr.com
