# !/usr/bin/env python
# 密なQP問題を解くための例(e04nf/qp_solve使用)
# https://www.nag.com/numeric/nl/nagdoc_27.3/flhtml/e04/e04nff.html#example で定義された密なQP問題を解く
from naginterfaces.library import opt
from naginterfaces.base import utils
import numpy as np
print('naginterfaces.library.opt.qp_dense_solve Python Example Results.')
print('Solve a small dense QP problem.')
infty = 1.0E+25
# 問題のサイズ
n = 7
# 線形制約の数
nclin = 7
# コストベクトル
cvec = np.array([-0.02, -0.20, -0.20, -0.20, -0.20, 0.04, 0.04])
h = np.array([
[2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,],
[0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0,],
[0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0,],
[0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0,],
[0.0, 0.0, 0.0, 0.0, 0.0, -2.0, -2.0,],
[0.0, 0.0, 0.0, 0.0, 0.0, -2.0, -2.0 ] ])
# 線形制約のブロック(行列A)
a = np.array([
[ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00,],
[ 0.15, 0.04, 0.02, 0.04, 0.02, 0.01, 0.03,],
[ 0.03, 0.05, 0.08, 0.02, 0.06, 0.01, 0.00,],
[ 0.02, 0.04, 0.01, 0.02, 0.02, 0.00, 0.00,],
[ 0.02, 0.03, 0.00, 0.00, 0.01, 0.00, 0.00,],
[ 0.70, 0.75, 0.80, 0.75, 0.80, 0.97, 0.00,],
[ 0.02, 0.06, 0.08, 0.12, 0.02, 0.01, 0.97 ] ])
# 線形制約の境界
bl = np.array([-0.01, -0.10,-0.01,-0.04,-0.10, -0.01, -0.01, -0.13, -infty, -infty, -infty, -infty, -9.92E-2,-3.0E-3])
bu = np.array([ 0.01, 0.15, 0.03, 0.02, 0.05, infty, infty, -0.13, -4.9E-3, -6.4E-3, -3.7E-3, -1.2E-3, infty, 2.0E-3])
# 初期推定
x = np.array([-0.01, -0.03, 0.00, -0.01, -0.10, 0.02, 0.01])
# ソルバーを初期化
comm = opt.nlp1_init('lp_solve')
# 印刷の詳細度を上げる
opt.lp_option_string('Print Level = 2', comm)
# ファイル I/O マネージャー
iom = utils.FileObjManager(locus_in_output=False)
# qphessに関する注意:
# 注意: この引数がNoneの場合、nAGが提供する機能が使用されます。
# 一般的に、qphessのバージョンを提供する必要はありません。
# しかしながら、qp_dense_solveのアルゴリズムはHの積のみを必要とします
# または HTH と ベクトル x; そして場合によっては効率が向上する可能性があります
# 要素を定義する必要を避けるqphessのバージョンを提供することによって
# 行列HまたはHTHを明示的に計算する必要はありません。
# 問題を解く
ret = opt.qp_dense_solve(bl, bu, h, x, comm, a=a, cvec=cvec, qphess=None, istate=None, data=None, io_manager=None)
# 正しく解けた場合は、解とラグランジュ乗数を報告してください
print('id V Value Lagr Mult')
for id in range(n):
print('{:5} {: 9.3e} {: 9.3e}'.format(id+1, ret.x[id], ret.clamda[id]))
print('id LC Value Lagr Mult')
for id in range(nclin):
print('{:5} {: 9.3e} {: 9.3e}'.format(n+id+1, ret.ax[id], ret.clamda[n+id]))
print('Objective value at solution {:0.5f}'.format(ret.obj))
print('Exit from problem afte {:6} iterations.'.format(ret.itera))