Числовой якобиан для ipopt (cyipopt) с использованием numdifftools
Я использую ipopt (через cyipopt) для задачи оптимизации, но в рамках моей задачи оптимизации у меня нет аналитической формулировки моих ограничений. Можно ли использовать числовое определение ограничений через numdifftools для обратного вызова Якобиана? Или есть другой модуль Python, который лучше подходит для этого?
Я также не уверен в синтаксисе, который я должен использовать для использования numdifftools в качестве моего обратного вызова для вычисления якобиана. Ниже показан мой фрагмент кода для решения Hock Schittkowski #40 с использованием числового якобиана через numdifftools.
# -*- coding: utf-8 -*-
"""
cyipot: Python wrapper for the Ipopt optimization package, written in Cython.
"""
#
# Test the "ipopt" Python interface on the Hock & Schittkowski test problem
#40
#
from __future__ import print_function, unicode_literals
import numpy as np
import scipy.sparse as sps
import ipopt
import numdifftools as nd
def explode():
raise ValueError('bum')
class hs040(object):
def __init__(self):
self.counter = 0
def objective(self, x):
#
# The callback for calculating the objective
#
self.counter += 1
if self.counter > 100:
explode()
return -x[0]*x[1]*x[2]*x[3]
def gradient(self, x):
#
# The callback for calculating the gradient
#
return np.array([-x[1]*x[2]*x[3], -x[0]*x[2]*x[3], -x[0]*x[1]*x[3], -x[0]*x[1]*x[2]])
def constraints(self, x):
#
# The callback for calculating the constraints
#
return np.array([x[0] ** 3.0 + x[1] ** 2.0,
x[0] ** 2.0 * x[3] - x[2],
x[3] ** 2.0 - x[1]])
def jacobian(self, x):
#
# The callback for calculating the Jacobian
#
return nd.Jacobian(self.constraints(x))
def intermediate(
self,
alg_mod,
iter_count,
obj_value,
inf_pr,
inf_du,
mu,
d_norm,
regularization_size,
alpha_du,
alpha_pr,
ls_trials
):
#
# Example for the use of the intermediate callback.
#
print("Objective value at iteration #%d is - %g" % (iter_count, obj_value))
def main():
x0 = [0.8, 0.8, 0.8, 0.8]
cl = [1.0, 0.0, 0.0]
cu = [1.0, 0.0, 0.0]
nlp = ipopt.problem(n=len(x0), m = len(cl), problem_obj=hs040(), cl=cl, cu=cu)
#
# Set solver options
#
nlp.addOption(b'mu_strategy', b'adaptive')
nlp.addOption(b'linear_solver', b'ma57')
nlp.addOption(b'tol', 1e-7)
#
# Scale the problem (Just for demonstration purposes)
#
nlp.setProblemScaling(
obj_scaling=2,
x_scaling=[1, 1, 1, 1]
)
nlp.addOption(b'nlp_scaling_method', b'user-scaling')
#
# Solve the problem
#
x, info = nlp.solve(x0)
print("Solution of the primal variables: x=%s\n" % repr(x))
print("Solution of the dual variables: lambda=%s\n" % repr(info['mult_g']))
print("Objective=%s\n" % repr(info['obj_val']))
if __name__ == '__main__':
main()
Этот фрагмент кода возвращает следующую ошибку:
TypeError: float() argument must be a string or a number
Exception TypeError: 'float() argument must be a string or a number' in 'cyipopt.jacobian_cb' ignored
что, я думаю, означает, что якобиан не оценивается.