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, អត្ថបទអំពី Habre.
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 для задач с ограничениями вида равенства и на ទ្រី для задач с ограничениями в виде неравенств. Оба метода реализованы алгоритмами поиска локального минимума в доверительной области и хорошо подходят для крупномасштабных задач.
Математическая постановка задачи поиска минимума в общем виде:
Для ограничений строгого равенства нижняя граница устанавливается равной верхней .
Для одностороннего ограничения верхняя или нижняя граница устанавливается 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 структуры по набору изображений (អត្ថបទអំពី Habre) можно посмотреть в scipy-cookbook.
Основной источник информации — docs.scipy.org, желающие поконтрибьютить в перевод этого и других разделов scipy добро пожаловать на GitHub.
ស្ទ្រីម mephistopheies за участие в подготовке публикации.