SciPy (вымаўляецца як сай пай) - гэта заснаваны на numpy матэматычны пакет, які ўключае ў сябе таксама бібліятэкі на C і Fortran. З SciPy інтэрактыўны сеанс Python ператвараецца ў такое ж паўнавартаснае асяроддзе апрацоўкі дадзеных, як MATLAB, IDL, Octave, R ці SciLab.
У гэтым артыкуле разгледзім асноўныя прыёмы матэматычнага праграмавання - рашэнні задач умоўнай аптымізацыі для скалярнай функцыі некалькіх зменных з дапамогай пакета scipy.optimize. Алгарытмы безумоўнай аптымізацыі ўжо разгледжаны ў мінулым артыкуле. Больш падрабязную і актуальную даведку па функцый scipy заўсёды можна атрымаць з дапамогай каманды help(), Shift+Tab або ў афіцыйнай дакументацыі.
Увядзенне
Агульны інтэрфейс для рашэння задач як умоўнай, так і безумоўнай аптымізацыі ў пакеце scipy.optimize падаецца функцыяй minimize(). Аднак вядома, што ўніверсальнага спосабу для рашэння ўсіх задач не існуе, таму выбар адэкватнага метаду як заўсёды кладзецца на плечы даследніка.
Падыходны алгарытм аптымізацыі задаецца з дапамогай аргументу функцыі minimize(..., method="").
Для ўмоўнай аптымізацыі функцыі некалькіх зменных даступныя рэалізацыі наступных метадаў:
SLSQP - паслядоўнае квадратычнае праграмаванне з абмежаваннямі, ньютанаўскі метад рашэння сістэмы Лагранжа. Артыкул на вікі.
TNC - Truncated Newton Constrained, абмежаваны лік ітэрацый, добры для нелінейных функцый з вялікім лікам незалежных зменных. Артыкул на wiki.
L-BFGS-B - метад ад чацвёркі Broyden-Fletcher-Goldfarb-Shanno, рэалізаваны з паменшаным спажываннем памяці за кошт частковай загрузкі вектараў з матрыцы Гесэ. Артыкул на wiki, артыкул на хабры.
COBYLA - Кабыла Constrained Optimization By Linear Approximation, абмежаваная аптымізацыя з лінейнай апраксімацыяй (без вылічэння градыенту). Артыкул на wiki.
У залежнасці ад абранага метаду, па-рознаму задаюцца ўмовы і абмежаванні для рашэння задачы:
аб'ектам класа Bounds для метадаў L-BFGS-B, TNC, SLSQP, trust-constr;
спісам (min, max) для гэтых жа метадаў L-BFGS-B, TNC, SLSQP, trust-constr;
аб'ектам або спісам аб'ектаў LinearConstraint, NonlinearConstraint для метадаў COBYLA, SLSQP, trust-constr;
слоўнікам або спісам слоўнікаў {'type':str, 'fun':callable, 'jac':callable,opt, 'args':sequence,opt} для метадаў COBYLA, SLSQP.
План артыкула:
1) Разгледзець прымяненне алгарытму ўмоўнай аптымізацыі ў давернай вобласці (method = "trust-constr") з абмежаваннямі, зададзенымі ў выглядзе аб'ектаў Bounds, LinearConstraint, NonlinearConstraint ;
2) Разгледзець паслядоўнае праграмаванне метадам найменшых квадратаў (method = "SLSQP") з абмежаваннямі, зададзенымі ў выглядзе слоўніка {'type', 'fun', 'jac', 'args'};
3) Разабраць прыклад аптымізацыі выпускаемай прадукцыі на прыкладзе вэб-студыі.
Умоўная аптымізацыя method=»trust-constr»
Рэалізацыя метаду trust-constr заснавана на EQSQP для задач з абмежаваннямі віду роўнасці і на TRIP для задач з абмежаваннямі ў выглядзе няроўнасцей. Абодва метаду рэалізаваны алгарытмамі пошуку лакальнага мінімуму ў давернай вобласці і добра падыходзяць для буйнамаштабных задач.
Матэматычная пастаноўка задачы пошуку мінімуму ў агульным выглядзе:
Для абмежаванняў строгай роўнасці ніжняя мяжа ўсталёўваецца роўнай верхняй .
Для аднабаковага абмежавання верхняя ці ніжняя мяжа усталёўваецца np.inf з адпаведным знакам.
Няхай неабходна знайсці мінімум вядомай функцыю Розенброка ад двух зменных:
Пры гэтым зададзены наступныя абмежаванні на яе вобласць азначэння:
У нашым выпадку ёсць адзінае рашэнне ў кропцы , для якой справядлівыя толькі першае і чацвёртае абмежаванні.
Пройдземся па абмежаваннях знізу ўверх і разгледзім, як можна іх запісаць у scipy.
Абмежаванні и вызначым з дапамогай аб'екта Bounds.
Матрыцу Якобі для абмежаванняў таксама можна вылічыць з дапамогай канчатковых рознасцяў. Аднак, у гэтым выпадку матрыцу Гесэ з дапамогай канчатковых рознасцяў ужо не вылічыць. Гесіян павінен быць вызначаны ў выглядзе функцыі або з дапамогай класа HessianUpdateStrategy.
Альтэрнатыўна, першая і другая вытворныя аптымізуемай функцыі могуць быць вылічаны набліжана. Напрыклад, гесіяна можа быць апраксімаваны з дапамогай функцыі SR1 (квазі-Ньютанаўскага набліжэння). Градыент можа быць апраксімаваны канчатковымі рознасцямі.
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)
Умоўная аптымізацыя method="SLSQP"
Метад SLSQP прызначаны для рашэння задач мінімізацыі функцыі ў выглядзе:
Дзе и - Мноствы індэксаў выразаў, якія апісваюць абмежаванні ў выглядзе роўнасцяў або няроўнасцяў. - Мноствы ніжніх і верхніх межаў для вобласці вызначэння функцыі.
Лінейныя і нелінейныя абмежаванні апісваюцца ў выглядзе слоўнікаў з ключамі 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])
}
Optimization terminated successfully. (Exit mode 0)
Current function value: 0.34271757499419825
Iterations: 4
Function evaluations: 5
Gradient evaluations: 4
[0.41494475 0.1701105 ]
Прыклад аптымізацыі
У сувязі з пераходам да пятага тэхналагічнага ўкладу, разгледзім аптымізацыю вытворчасці на прыкладзе вэб-студыі, якая прыносіць нам невялікі, але стабільны даход. Прадстаўляльны сябе дырэктарам галеры, на якой вырабляецца тры выгляду прадукцыі:
x0 - якія прадаюць лендынг, ад 10 т.р.
x1 - карпаратыўныя сайты, ад 20 т.р.
x2 - інтэрнэт крамы, ад 30 т.р.
Наш дружны працоўны калектыў уключае ў сябе чатырох джунаў, двух мідлаў і аднаго сеньёра. Фонд іх працоўнага часу на месяц:
джуны: 4 * 150 = 600 чел * час,
мідлы: 2 * 150 = 300 чел * час,
сеньёр: 150 чел * час.
Хай на распрацоўку і дэплой аднаго сайта тыпу (x0, x1, x2) першы які трапіў джуніёр павінен выдаткаваць (10, 20, 30) гадзін, мидл - (7, 15, 20), сеньёр - (5, 10, 15) гадзін лепшага часу свайго жыцця.
Як любому нармальнаму дырэктару, нам хочацца максымізаваць штомесячны прыбытак. Першы крок да поспеху - запісваем мэтавую функцыю value як суму даходаў ад вырабленай за месяц прадукцыі:
І нарэшце самае вясёлкавае дапушчэнне - з-за нізкай цаны і высокай якасці да нас пастаянна выстройваецца чарга з задаволеных кліентаў. Мы можам самі выбіраць штомесячныя аб'ёмы вытворчасці прадукцыі, зыходзячы з рашэння задачы ўмоўнай аптымізацыі з scipy.optimize:
Нястрога акруглім да цэлых і палічым месячную загрузку весляроў пры аптымальным раскладзе прадукцыі. x = (8, 6, 3) :
джуны: 8 * 10 + 6 * 20 + 3 * 30 = 290 чел * час;
мідлы: 8 * 7 + 6 * 15 + 3 * 20 = 206 чел * час;
сеньёр: 8 * 5 + 6 * 10 + 3 * 15 = 145 чел * час.
Выснова: каб дырэктар атрымліваў свой заслужаны максімум, аптымальна рабіць у месяц па 8 лендынгаў, 6 сярэдніх сайтаў і 3 крамы. Сеньёр пры гэтым павінен араць не адрываючыся ад станка, загрузка мідлаў складзе прыкладна 2/3, джунаў менш за палову.
Заключэнне
У артыкуле выкладзены асноўныя прыёмы працы з пакетам scipy.optimize, якія выкарыстоўваюцца для вырашэння задач умоўнай мінімізацыі. Асабіста я выкарыстоўваю scipy чыста ў акадэмічных мэтах, таму прыведзены прыклад носіць такі жартоўны характар.
Шмат тэорыі і винрарных прыкладаў можна знайсці, напрыклад, у кнізе І.Л.Акуліча "Матэматычнае праграмаванне ў прыкладах і задачах". Больш хардкорнае ўжыванне scipy.optimize для пабудовы 3D структуры па наборы малюнкаў (артыкул на хабры) можна паглядзець у scipy-cookbook.
Асноўная крыніца інфармацыі - docs.scipy.org, якія жадаюць пакантрыб'юціць у пераклад гэтага і іншых раздзелаў scipy сардэчна запрашаем на GitHub.
Дзякуй mephistopheies за ўдзел у падрыхтоўцы публікацыі.