Processing math: 0%

モデルベースの導関数フリー最適化

nAG Library for Python Example集

このページは、nAGライブラリのJupyterノートブックExampleの日本語翻訳版です。オリジナルのノートブックはインタラクティブに操作することができます。

モデルベースの導関数フリー最適化

以下の形式の問題を想定します min

ここで f は非線形の滑らかな目的関数であり、以下の特性を持つ可能性があります: - 導関数が不明なブラックボックス - 評価に高コストがかかる - ノイズを含む可能性がある

このような問題には、DFOソルバーが最適です。導関数が利用可能で計算が容易な場合は、導関数ベースの手法を優先すべきことに注意してください。

DFOアルゴリズムにはいくつかの種類がありますが、ここではモデルベースの手法に焦点を当てます。これらは、補間点の集合上で目的関数 f の値に一致する二次モデルと、モデルが正確とみなされる領域を監視し収束を保証する信頼領域法に基づいています。このようなアルゴリズムの簡単な説明は以下の通りです:

  • 初期化
    • 初期反復点と、その周りの初期信頼領域を選択
    • 信頼領域内に補間点の集合を選択
    • 信頼領域内で二次補間モデルを構築
  • 収束に達するまでループ
    • 信頼領域内でモデルを最小化
    • 新しい点で目的関数を評価
    • モデルが目的関数の減少を正しく予測した場合:
      • 遠くにある補間点を新しい点で置き換え
      • 新しい点の周りに信頼領域を移動
    • そうでない場合
      • 補間点の幾何学的配置が良くない場合は一部の補間点を置き換える
      • または信頼領域を縮小する

以下のアニメーションは、モデルベースDFOアルゴリズムの2回の反復を示しています

import io
import base64
from IPython.display import HTML
video = io.open('animation.mp4', 'r+b').read()
encoded = base64.b64encode(video)
HTML(data='''<video alt="test" controls>
                <source src="data:video/mp4;base64,{0}" type="video/mp4" />
             </video>'''.format(encoded.decode('ascii')))

有限差分法による勾配推定を用いた微分ベースのソルバーとDFOの比較

DFOは関数評価の回数がやや少なく、ノイズに対してより頑健であるはずです。CUTEstテストセットから4つの関数を使ってこれらの点を説明しましょう: - HART6 - ENGVAL2 - HATFLDC

まず問題の特性を定義することから始めます:

def problem_char(pname):
    n = None
    xstart = None
    target = None
    # 問題名 pname から、以下を返します:
    # 変数の数、開始点、目的関数の最適値、下限、上限
    if pname == 'HART6':
        n = 6
        xstart = [0.2]*n
        target = -3.32288689
        xl = [0.0]*n
        xu = [1.0]*n
        
    elif pname == 'ENGVAL2':
        n = 3
        xstart = [1.0, 2.0, 0.0]
        target = 0.0
        xl = [-1.0e20]*n
        xu = [1.0e20]*n
    
    elif pname == 'HATFLDC':
        n = 25
        xstart = [0.9]*n
        target = 0.0
        xl = [0.0]*n
        xu = [10.0]*n
        
    else:
        print('problem name not known')
    return n, xstart, target, xl, xu

乱数生成器(RNG)を初期化し、ソルバーの進行を記録するユーザーデータを設定し、目的関数のコールバックを定義します:

# nAGの乱数生成器を初期化する
seed = [42]
genid = 1
statecomm = rand.init_repeat(genid, seed)
class usr_data:
    def __init__(self, fun, statecomm=None, target=0.0, tol = 1.0e-08):
        self.fun = fun
        self.nf = 0
        self.noiselev = 0.0
        self.statecomm = statecomm
        self.pdata = None
        self.tol = tol
        self.nf = 0
        self.ok = False
        self.target = target
        self.sol = 1.0e20
        
        
class hart6_data:
    def __init__(self):
        self.c = [1.0, 1.2, 3.0, 3.2]
        self.a = [[10.0, 0.05, 3.0, 17.0],
                  [0.05, 10.0, 3.5, 8.0],
                  [17.0, 17.0, 1.7, 0.05],
                  [3.5, 0.1, 10.0, 10.0],
                  [1.7, 8.0, 17.0, 0.1],
                  [8.0, 14.0, 8.0, 14.0]]
        self.p = [[0.1312, 0.2329, 0.2348, 0.4047],
                  [0.1696, 0.4135, 0.1451, 0.8828],
                  [0.5569, 0.8307, 0.3522, 0.8732],
                  [0.0124, 0.3736, 0.2883, 0.5743],
                  [0.8283, 0.1004, 0.3047, 0.1091],
                  [0.5886, 0.9991, 0.665, 0.0381]]

目的関数のコールバックを定義します。解かれる関数はユーザーデータ構造内で定義されています。

def objfun(x, inform, data=None):
    inform = 0
    n = len(x)
    obj = 0.0
    
    # 目的関数を計算する
    if data.fun == 'HART6':
        c = data.pdata.c
        a = data.pdata.a
        p = data.pdata.p
        for i in range(len(c)):
            aux = 0.0
            for j in range(len(a)):
                aux -= a[j][i] * (x[j] - p[j][i])**2
            obj -= c[i]*np.exp(aux)
            
    elif data.fun == 'ENGVAL2':
        obj = (x[0]**2 + x[1]**2 + x[2]**2 - 1)**2 + \
        (x[0]**2 + x[1]**2 + (x[2]-2)**2 - 1)**2 + \
        (x[0] + x[1] + x[2] - 1)**2 +\
        (x[0] + x[1] - x[2] + 1)**2 +\
        (3*x[1]**2 + x[0]**3 +\
        (5*x[2] - x[0] + 1)**2 - 36)**2
        
    elif data.fun == 'HATFLDC':
        obj = (x[0]-1)**2
        for i in range(1, n-1):
            obj += (x[i+1] - x[i]**2)**2
        obj += (x[n-1]-1)**2

    else:
        print('Unknown objective function')
        inform = -1
        
    # 必要に応じてノイズを追加する
    if data.noiselev > 0.0:
        noise = rand.dist_uniform(1,-data.noiselev, data.noiselev, data.statecomm)
        obj += noise[0]
        
    # まだ解決していない場合の評価回数をカウントする
    # print(abs(obj-target), obj, target)
    if not data.ok and abs(obj-data.target) < data.tol:
        data.ok = True
        data.sol = obj
        data.nf += 1
        inform = -2
    elif not data.ok:
        data.nf +=1
        
    return (obj, inform) 

# 微分ベースのソルバーの目的関数
def objfun_bob(x, data):
    inform = 0
    obj, inform = objfun(x, inform, data)
    return obj

ソルバー bounds_quasi_func_easy を呼び出す関数。有限差分による勾配推定に基づいています。

def solve_fd(pname, noiselevel=0.0, statecomm=None , tol=1.0e-08):
    
    n, xstart, target, xl, xu = problem_char(pname)
    data = usr_data(pname, target=target, statecomm=statecomm, tol=tol)
    if pname == 'HART6':
        h6dat = hart6_data()
        data.pdata = h6dat
    data.fun = pname
    data.noiselev = noiselevel
    print(data.fun)
    try:
        _ = opt.bounds_quasi_func_easy(ibound, objfun_bob, xl, xu, xstart, data=data)
    except utils.NagValueError as e:
        if e.errno == 2 and not data.ok:
            print('Maximum number of evaluations exceeded:', 400*n)
        elif e.errno != 2:
            print('error number not expected: ', e.errno)
    if data.ok:
        print('Final objective value', data.sol)
        print('objective evaluations', data.nf, '\n')
    else:
        print('solution not within the tolerance', data.tol, 'of the solution\n')

微分を使わないソルバーを呼び出す関数 handle_solve_dfno

warnings.simplefilter('error', utils.NagCallbackTerminateWarning)

def solve_dfo(pname, noiselevel=0.0, statecomm=None, options=None, tol=1.0e-08):
    iom = utils.FileObjManager(locus_in_output=False)
    # ユーザーデータを問題名、ノイズレベル、収束許容値で初期化する
    n, xstart, target, xl, xu = problem_char(pname)
    data = usr_data(pname, statecomm=statecomm, target=target, tol=tol)
    if pname == 'HART6':
        h6dat = hart6_data()
        data.pdata = h6dat
    data.fun = pname
    data.noiselev = noiselevel
    # nAGハンドルのデータ構造を初期化する
    handle = opt.handle_init(n)
    # モデルに非線形目的関数を定義する
    opt.handle_set_nlnobj(handle, idxfd=list(range(1, n+1)))
    # 変数の範囲を定義する 
    opt.handle_set_simplebounds(handle, xl, xu)
    # オプションを設定する
    for optstr in options:
        opt.handle_opt_set(handle, optstr)
    # ソルバーを呼び出す
    try:
        _ = opt.handle_solve_dfno(handle, xstart, objfun=objfun, data=data, io_manager=iom)
    except utils.NagCallbackTerminateWarning as _e:
        pass
    # 結果を表示
    print(pname)
    print('Final objective value', data.sol)
    print('Objective evaluations', data.nf)
    print()
    opt.handle_free(handle)

関数評価にランダムノイズがない場合

まず、これら4つの問題をノイズなしで、導関数ベースのソルバーbounds_quasi_func_easyを使用して解きます。ソルバーが実際の解から108以内の点を見つけた場合、問題は解決されたとみなされます。

print('No noise, derivative based solver')
print('---------------------------------')
ibound = 0

solve_fd('HART6')
solve_fd('ENGVAL2')
solve_fd('HATFLDC')
No noise, derivative based solver
---------------------------------
HART6
Final objective value -3.3228868913265734
objective evaluations 115 

ENGVAL2
Final objective value 1.5541394508620684e-09
objective evaluations 136 

HATFLDC
Final objective value 8.298144029725037e-09
objective evaluations 372 

ノイズがない場合、ソルバーは正しく最小値に収束します。

次に、DFOソルバーhandle_solve_dfnoを使って同じことをやってみましょう:

warnings.simplefilter('ignore', utils.NagAlgorithmicMajorWarning)
warnings.simplefilter('ignore', utils.NagAlgorithmicWarning)
options = ['Print file = -1',
           'DFO Max Objective Calls = 5000',
           'DFO Maximum Slow Steps = 1000']

print('No noise, derivative free solver')
print('--------------------------------')

solve_dfo('HART6', options=options)
solve_dfo('ENGVAL2', options=options)
solve_dfo('HATFLDC', options=options)
No noise, derivative free solver
--------------------------------
HART6
Final objective value -3.322886885382111
Objective evaluations 91

ENGVAL2
Final objective value 3.130098898053424e-09
Objective evaluations 119

HATFLDC
Final objective value 9.685746116160138e-09
Objective evaluations 373

関数評価に一様ノイズを加えた最小化

ここで同じ問題を解きますが、関数評価が要求されるたびに、[-10^{-08}, 10^{-08}]の範囲で一様に選ばれたランダムな値が加えられます。ノイズに対応するため、許容誤差は少し緩和されています。

導関数ベースのソルバーの結果は以下の通りです:

noiselev = 1.0e-08
tol = 1.0e-06 # relax the tolerance to be lower than the noise

solve_fd('HART6', noiselevel=noiselev, statecomm=statecomm, tol=tol)
solve_fd('ENGVAL2', noiselevel=noiselev, statecomm=statecomm, tol=tol)
solve_fd('HATFLDC', noiselevel=noiselev, statecomm=statecomm, tol=tol)
    
HART6
Maximum number of evaluations exceeded: 2400
solution not within the tolerance 1e-06 of the solution

ENGVAL2
Maximum number of evaluations exceeded: 1200
solution not within the tolerance 1e-06 of the solution

HATFLDC
Maximum number of evaluations exceeded: 10000
solution not within the tolerance 1e-06 of the solution

わずかなノイズを加えただけでも、ソルバーは収束しないか、はるかに多くの関数評価を必要とするようになりました。

DFOソルバーで同じ実験を行うと、以下のようになります:

options = ['Print File = -1',
           'DFO Maximum Slow Steps = 1000',
           'DFO Max Objective Calls = 1500']

solve_dfo('HART6', noiselevel=noiselev, statecomm=statecomm, options=options, tol=tol)
solve_dfo('ENGVAL2', noiselevel=noiselev, statecomm=statecomm, options=options, tol=tol)
solve_dfo('HATFLDC', noiselevel=noiselev, statecomm=statecomm, options=options, tol=tol)
HART6
Final objective value -3.3228862436423685
Objective evaluations 84

ENGVAL2
Final objective value 4.481337367997389e-07
Objective evaluations 122

HATFLDC
Final objective value 9.396936939416362e-07
Objective evaluations 294

ソルバーは、関数評価回数の点でわずかなコストで、ノイズの範囲内の関数値に収束し続けています

help(opt.handle_solve_dfno)

handle_solve_dfnoに関する関数のヘルプ(naginterfaces.library.optモジュール内):

handle_solve_dfno(handle, x, objfun=None, monit=None, data=None, io_manager=None)
    境界付き変数を持つ非線形目的関数に対する直接通信の導関数フリー(DFO)ソルバー。
    
    注意: この関数はオプションのアルゴリズムパラメータを使用します。以下も参照してください:
    ``handle_opt_set``, ``handle_opt_get``.
    
    ``handle_solve_dfno``は、nAG最適化モデリングスイート(DFNO)からの前方通信導関数フリー
    最適化(DFO)ソルバーで、境界制約付きの小規模から中規模の非線形問題に対応します。
    
    詳細な情報については、e04jdに関するnAGライブラリドキュメントを参照してください
    
    https://www.nag.com/numeric/nl/nagdoc_27.1/flhtml/e04/e04jdf.html
    
    パラメータ
    ----------
    handle : Handle
        問題へのハンドル。初期化されている必要があり(例:``handle_init``による)、
        ``handle_solve_dfno``と互換性のある問題定式化を保持している必要があります。
        nAG最適化モデリングスイートの呼び出し間で変更してはいけません。
    
    x : float, array-like, shape (nvar)
        x_0、変数xの初期推定値。
    
    objfun : None または呼び出し可能 (fx, inform) = objfun(x, inform,
        data=None), オプション
        注意: この引数がNoneの場合、nAG提供の機能が使用されます。
    
        `objfun`は、指定された点xにおける目的関数f(x)の値を計算します。
    
        非線形目的関数がない場合(例:``handle_set_linobj``
        または``handle_set_quadobj``が線形または二次目的関数を定義するために
        呼び出された場合)、`objfun`は``handle_solve_dfno``によって
        呼び出されることはなく、Noneでも構いません。
    
        パラメータ
        ~~~~~~~~~~
        x : float, ndarray, shape (nvar)
            x、目的関数を評価する変数値のベクトル。
    
        inform : int
            非負の値。
    
        data : 任意, オプション, その場で変更可能
            コールバック関数用のユーザー通信データ。
    
        戻り値
        ~~~~~~~
        fx : float
            xにおける目的関数の値。
    
        inform : int
            要求された目的関数値が計算できなかったことを示すために使用できます。
            具体的には、負の値に設定できます:
    
            `inform` = -1
    
                ソルバーはレスキュー手順を試み、代替点を要求します。
                レスキュー手順が失敗した場合、ソルバーは`errno` = 17で終了します。
    
            `inform` = -2
    
                ソルバーは`errno` = 20でクリーンに終了し、利用可能な最良の点と
                解決統計を返します。
    
    monit : None または呼び出し可能 monit(x, rinfo, stats, data=None), オプション
        注意: この引数がNoneの場合、nAG提供の機能が使用されます。
    
        `monit`は、最適化の進行状況を監視できるようにするために提供されています。
    
        これは、i回目の反復の終わりに呼び出されます。ここでiは
        'DFO Monitor Frequency'によって与えられます(デフォルトは0で、`monit`は呼び出されません呼び出されます)。

        モニタリングが不要な場合、`monit` は None でも構いません。

        パラメータ
        ~~~~~~~~~~
        x : float, ndarray, shape (nvar)
            x、現在の反復における決定変数のベクトル。

        rinfo : float, ndarray, shape (100)
            メイン引数 `rinfo` で説明されているように、現在の反復の終了時のエラー測定値と様々な指標。

        stats : float, ndarray, shape (100)
            モニタリングステップまたは現在の反復の終了時のソルバー統計(値はメイン引数 `stats` で説明されているとおり)。

        data : 任意, オプション, その場で変更可能
            コールバック関数用のユーザーコミュニケーションデータ。

    data : 任意, オプション
        コールバック関数用のユーザーコミュニケーションデータ。

    io_manager : FileObjManager, オプション
        このルーチンでの I/O 管理者。

    戻り値
    -------
    x : float, ndarray, shape (nvar)
        変数 x の最終値。

    rinfo : float, ndarray, shape (100)
        モニタリングステップまたは最終反復の終了時の最適目的関数値と様々な指標。測定値は以下の表に示されています:

        [表省略]

    stats : float, ndarray, shape (100)
        モニタリングステップまたは最終反復の終了時のソルバー統計。以下の表に示されています:

        [表省略]

    その他のパラメータ
    ----------------
    'Defaults' : 値なし
        このキーワードを使用すると、すべてのオプションをデフォルト値にリセットできます。
        このキーワードに与えられた値は無視されます。

    'DFNO Detect Unbounded' : str
        デフォルト = 'YES'

        ソルバーは問題が無限大かどうかを検出しようとします。
        このオプションでは、無限大検出ヒューリスティックをオンまたはオフにできます。

        制約: 'DFNO Detect Unbounded' = 'YES' または 'NO'。

    'DFNO Objective Limit' : float
        デフォルト = - 無限大

        このオプションは追加の収束基準を設定します。
        ソルバーは、関数値がこのパラメータより小さい点を見つけた場合に停止します。

    'DFO Maximum Slow Steps' : int
        デフォルト = 20

        'DFO Maximum Slow Steps' > 0 の場合、この引数は許容される連続する遅い反復の最大数 n_slow を定義します。
        遅い反復検出を無効にするには、'DFO Maximum Slow Steps' = 0 に設定します。
        アルゴリズムは2つの状況で停止する可能性があります:

        (i) n_slow > 'DFO Maximum Slow Steps' かつ rho < 'DFO Trust
            Region Slow Tol' で `errno` = 50、

        (#) n_slow > 5*'DFO Maximum Slow Steps' で `errno` = 24。

        制約: 'DFO Maximum Slow Steps' >= 0。

    'DFO Max Objective Calls' : int
        デフォルト = 500

        ソルバーが計算を許可される目的関数評価の回数の制限。
        制限に達すると、ソルバーは `errno` = 21 で停止します。

        制約: 'DFO Max Objective Calls' >= 1。

    'DFO Max Soft Restarts' : intデフォルト = 5
    
        目的関数がノイズありと宣言された場合('DFO Noisy Problem' = 'YES')に
        実行できるソフトリスタートの最大総数。
    
        制約条件: 'DFO Max Soft Restarts' >= 1.
    
    'DFO Max Unsucc Soft Restarts' : int
        デフォルト = 3
    
        目的関数がノイズありと宣言された場合('DFO Noisy Problem' = 'YES')に
        実行できる連続した失敗したソフトリスタートの最大数。
    
        制約条件: 'DFO Max Unsucc Soft Restarts' >= 1.
    
    'DFO Monitor Frequency' : int
        デフォルト = 0
    
        'DFO Monitor Frequency' > 0 の場合、モニタリング目的で
        i番目のステップの終わりごとに `monit` が呼び出されます。
    
        制約条件: 'DFO Monitor Frequency' >= 0.
    
    'DFO Noise Level' : float
        デフォルト = 0.0
    
        'DFO Noisy Problem' = 'YES' の場合、目的関数を評価する際に
        予想されるノイズレベルを示します。
    
        制約条件: 'DFO Noise Level' >= 0.0.
    
    'DFO Noisy Problem' : str
        デフォルト = 'NO'
    
        ソルバーに提供される関数評価がノイズを含むかどうかを示します。
        'DFO Noisy Problem' = 'YES' の場合、いくつかのアルゴリズム機能が
        有効になります:
    
        (i) 信頼領域の更新が遅くなり、目的関数値の信頼性低下を反映します。
    
        (#) アルゴリズムがノイズによって行き詰まらないようにするため、
            ソフトリスタートを実行できます(リスタートの特性を制御するには
            'DFO Max Soft Restarts'、'DFO Max Unsucc Soft Restarts'、
            'DFO Number Soft Restarts Pts' を参照してください)。
    
        (#) さらに、'DFO Noise Level' > 0.0 の場合、すべての関数値が
            ノイズレベル内にある場合、ソルバーはソフトリスタートを
            トリガーします。
    
    'DFO Number Interp Points' : int
        デフォルト = 0
    
        残差の線形モデルを構築するために使用される Y_k (9) の
        補間点の最大数。
        'DFO Number Interp Points' = 0 の場合、ポイント数は
        n_r+1 に選択されます。ここで n_r は固定されていない変数の数です。
    
        制約条件: 'DFO Number Interp Points' >= 0.
    
        一貫性制約、満たされない場合はソルバーが `errno` = 6 で停止します:
    
            n_r+1 <= 'DFO Number Interp Points' <= (n_r+1)*(n_r+2)/2.
    
    'DFO Number Soft Restarts Pts' : int
        デフォルト = 3
    
        ソフトリスタート中に置き換えられる補間点の数。
    
        制約条件: 'DFO Number Soft Restarts Pts' >= 1.
    
    'DFO Print Frequency' : int
        デフォルト = 1
    
        'DFO Print Frequency' > 0 の場合、ソルバーは i番目のステップの
        終わりごとに反復ログを適切なユニットに出力します。
    
        制約条件: 'DFO Print Frequency' >= 0.
    
    'DFO Random Seed' : int
        デフォルト = -1
    
        初期モデルを構築するために使用されるランダムポイントを
        生成するためのランダムシード。
        'DFO Random Seed' < 0 の場合、ランダムシードはリアルタイムクロックから
        取得した値に基づいて設定され、潜在的に異なる実行結果をもたらす可能性があります。ソルバーは実行するたびに異なる経路をたどります。
        完全に再現可能な実行を得るには、正の値に設定してください。
    
        制約条件: 'DFO Print Frequency' >= -1.
    
    'DFO Starting Trust Region' : float
        デフォルト = 0.1
    
        rho_beg、初期信頼領域半径。
        この引数は、変数に対する最大の予想される全体的な変化の約10分の1に設定する必要があります:
        初期の二次モデルは、初期xから各座標方向にrho_beg長の
        ステップを取ることで構築されます。
        デフォルト値は、変数が1のオーダーであることを想定しています。
    
        制約条件: 'DFO Starting Trust Region' > epsilon.
    
        一貫性制約、満たされない場合、ソルバーは `errno` = 5 で停止します:
    
            'DFO Starting Trust Region' <= 'DFO Trust Region Tolerance'.
    
            'DFO Starting Trust Region' <= 1/2min_i(u_x(i)-l_x(i)).
    
    'DFO Trust Region Slow Tol' : float
        デフォルト = epsilon^0.25
    
        解が許容可能であると宣言されるための最小許容信頼領域半径。
        ソルバーは以下の場合に停止します:
    
            n_slow > 'DFO Maximum Slow Steps' かつ rho_k < 'DFO Trust
            Region Slow Tol'.
    
        制約条件: 'DFO Trust Region Slow Tol' > epsilon.
    
        一貫性制約、満たされない場合、ソルバーは `errno` = 5 で停止します:
    
            'DFO Trust Region Slow Tol' > 'DFO Trust Region Tolerance'.
    
    'DFO Trust Region Tolerance' : float
        デフォルト = epsilon^0.37
    
        rho_end、要求される信頼領域半径。
        アルゴリズムは信頼領域半径がこの制限に達したとき収束を宣言します。
        これは変数の最終値に必要な絶対精度を示すべきです。
    
        制約条件: 'DFO Trust Region Tolerance' > epsilon.
    
        一貫性制約、満たされない場合、ソルバーは `errno` = 5 で停止します:
    
            'DFO Starting Trust Region' > 'DFO Trust Region Tolerance'.
    
            'DFO Trust Region Slow Tol' > 'DFO Trust Region Tolerance'.
    
    'Infinite Bound Size' : float
        デフォルト = 10^20
    
        これは問題制約の定義における'無限'境界bigbndを定義します。
        bigbnd以上の上限は+無限として扱われます(同様に、-bigbnd以下の
        下限は-無限として扱われます)。
        このオプションの変更は、既に定義された制約には影響しません;
        変更後に定式化された制約のみが影響を受けます。
    
        制約条件: 'Infinite Bound Size' >= 1000.
    
    'Monitoring File' : int
        デフォルト = -1
    
        i >= 0の場合、二次(モニタリング)出力のユニット番号。
        'Monitoring File' = -1の場合、二次出力は提供されません。
        このユニットに出力される情報は'Monitoring Level'によって制御されます。
    
        制約条件: 'Monitoring File' >= -1.
    
    'Monitoring Level' : int
        デフォルト = 4
    
        この引数は、出力される情報の詳細度を設定しますソルバーによって二次出力に出力されます。
        レベルの意味は「Print Level」と同じです。
    
        制約: 0 <= 'Monitoring Level' <= 5
    
    'Print File' : int
        デフォルト = アドバイザリーメッセージユニット番号
    
        i >= 0の場合、ソルバーの主要出力のユニット番号。
        'Print File' = -1の場合、他の設定に関係なく主要出力は
        完全にオフになります。デフォルト値は、オプションの
        初期化時、例えばハンドルの初期化時のアドバイザリー
        メッセージユニット番号です。このユニットへの情報出力は
        'Print Level'によって制御されます。
    
        制約: 'Print File' >= -1
    
    'Print Level' : int
        デフォルト = 2
    
        この引数は、ソルバーが主要出力と二次出力に
        どの程度詳細な情報を出力するかを定義します。
    
        [表省略]
    
        制約: 0 <= 'Print Level' <= 5
    
    'Print Options' : str
        デフォルト = 'YES'
    
        'Print Options' = 'YES'の場合、オプションのリストが
        主要出力に出力され、常に二次出力にも出力されます。
    
        制約: 'Print Options' = 'YES' または 'NO'
    
    'Print Solution' : str
        デフォルト = 'NO'
    
        'Print Solution' = 'YES'の場合、解が主要出力と
        二次出力に出力されます。
    
        制約: 'Print Solution' = 'YES' または 'NO'
    
    'Task' : str
        デフォルト = 'MINIMIZE'
    
        この引数は、最適化の必要な方向を指定します。
        'Task' = 'FEASIBLE POINT'の場合、目的関数(設定されている場合)は
        無視され、与えられた許容誤差に関して実行可能点が
        見つかり次第アルゴリズムは停止します。
    
        制約: 'Task' = 'MINIMIZE'、'MAXIMIZE' または 'FEASIBLE POINT'
    
    'Stats Time' : str
        デフォルト = 'NO'
    
        この引数は、アルゴリズムの様々な部分の時間計測をオンにし、
        時間の大部分がどこで費やされているかをより良く把握できるようにします。
        これは、異なる解法アプローチの選択に役立つかもしれません。
        CPUタイムと壁時計時間のどちらかを選択できます。
        'YES'の選択は'WALL CLOCK'と同等です。
    
        制約: 'Stats Time' = 'YES'、'NO'、'CPU' または 'WALL CLOCK'
    
    'Time Limit' : float
        デフォルト = 10^6
    
        ソルバーが1つの問題を解くのに使用できる秒数の制限。
        収束チェック中にこの制限を超えた場合、
        ソルバーは `errno` = 23 で終了します。
    
        制約: 'Time Limit' > 0
    
    例外
    ------
    NagValueError
        (`errno` 1)
            `handle` が初期化されていません。
    
        (`errno` 1)
            `handle` はnAG最適化モデリングスイートに属していないか、
            適切に初期化されていないか、破損しています。
    
        (`errno` 1)
            `handle` が適切に初期化されていないか、破損しています。
    
        (`errno` 2)
            このソルバーは、ハンドルで定義されたモデルをサポートしていません。
    
        (`errno` 2)
            問題はすでに解決中です。        

(errno 4) 入力時、nvar = 、期待値 =

            制約:nvarは`handle`内のモデルの現在の変数数と一致する必要があります。
    
        (`errno` 5)
            オプション'DFO Trust Region Tolerance' rho_endと
            'DFO Starting Trust Region' rho_begが矛盾しています。
    
            制約:rho_end < rho_beg。
    
            ``handle_opt_set``を使用して互換性のあるオプション値を設定してください。
    
        (`errno` 5)
            オプション'DFO Trust Region Tolerance' rho_endと
            'DFO Trust Region Slow Tol' rho_tolが矛盾しています。
    
            制約:rho_end < rho_tol。
    
            ``handle_opt_set``を使用して互換性のあるオプション値を設定してください。
    
        (`errno` 5)
            オプション'DFO Starting Trust Region' rho_beg = *<value>*、
            l_x(i) = *<value>*、u_x(i) = *<value>*、i = *<value>*。
    
            制約:座標iでl_x(i) != u_x(i)の場合、
            u_x(i)-l_x(i) >= 2*rho_beg。
    
            ``handle_opt_set``を使用して互換性のあるオプション値を設定してください。
    
        (`errno` 6)
            不等な境界がn_r = *<value>*個あり、オプション
            'DFO Number Interp Points' npt = *<value>*。
    
            制約:n_r+1 <= npt <= (n_r+1)*(n_r+2)/2。
    
            ``handle_opt_set``を使用して互換性のあるオプション値を設定してください。
    
        (`errno` 6)
            初期補間点の数が'DFO Number Interp Points'で設定された
            総数と異なります。
    
            このソルバーでは補間セットの拡大はサポートされていません。
    
        (`errno` 7)
            適切な`objfun`関数を提供してください。
    
    警告
    -----
    NagAlgorithmicWarning
        (`errno` 50)
            問題は*<value>*回連続のスロー反復後に
            許容可能なレベルまで解決されました。
    
            オプション'DFO Maximum Slow Steps'を使用して、
            許容されるスロー反復の最大数を変更できます。
    
    NagAlgorithmicMajorWarning
        (`errno` 17)
            レスキューに失敗:一部の関数評価が提供できなかった後、
            信頼領域をさらに縮小できませんでした。目的関数の仕様を
            確認し、スケーリングが必要かどうか検討してください。
            異なる初期`x`を試してください。
    
        (`errno` 17)
            一部の初期補間点を提供できませんでした。
            この段階ではレスキューを試みることができません。
    
            目的関数の仕様を確認し、スケーリングが必要かどうか
            検討してください。異なる初期`x`を試してください。
    
        (`errno` 18)
            信頼領域ステップでの予測された減少が非正でした。
            目的関数の仕様を確認し、スケーリングが必要かどうか
            検討してください。異なる初期`x`を試してください。
    
        (`errno` 19)
            ソルバーはモデル構築フェーズで失敗し、
            最大再起動回数に達しました。目的関数の仕様を確認し、
            スケーリングが必要かどうか検討してください。
            異なる初期`x`を試してください。
    
        (`errno` 20)
            目的関数の呼び出し後、ユーザーが終了を要求しました。        

(errno 21) 関数評価の最大回数を超過しました。

        (`errno` 23)
            許容された最大時間を超過したため、ソルバーが終了しました。
    
        (`errno` 24)
            進展なし、*<value>* 回連続でスローステップが続いたため、
            ソルバーが停止しました。
    
            'DFO Maximum Slow Steps' オプションを使用して、
            許容されるスローステップの最大回数を変更できます。
    
        (`errno` 54)
            問題が無限解を持つ可能性があります。
    
            無限解検出のヒューリスティックは、'DFNO Detect Unbounded' 
            オプションでオフにできます。
    
    NagCallbackTerminateWarning
        (`errno` 20)
            モニタリングステップ中にユーザーが終了を要求しました。
    
    注意
    -----
    ``handle_solve_dfno`` は、境界制約付きの非線形目的関数を最小化することを
    目的としています:
    
        [表省略]
    
    ここで f は滑らかな非線形関数であり、l_x と u_x は
    変数の境界を定義する n 次元ベクトルです。
    
    ``handle_solve_dfno`` は、ハンドルとして格納された互換性のある問題の
    ソルバーとして機能します。
    ハンドルは、問題を定義し、nAG 最適化モデリングスイートの関数間の
    通信手段として機能する内部データ構造を指します。
    互換性のある問題ハンドルを定義するには、``handle_init`` を呼び出し、
    続いて ``handle_set_nlnobj`` を呼び出して初期化し、オプションで
    ``handle_set_simplebounds`` を呼び出して変数の境界を定義する必要があります。
    ``handle_set_simplebounds`` が呼び出されない場合、すべての変数は
    ソルバーによってフリーとみなされます。
    ``handle_solve_dfno`` は常に目的関数の勾配が密であると仮定するため、
    ``handle_set_nlnobj`` の呼び出しで残差のスパース構造を定義しても
    効果がないことに注意してください。
    nAG 最適化モデリングスイートの詳細については、[E04 の紹介]を参照してください。
    
    ソルバーは、境界の定義により変数を固定することができます。
    ただし、ソルバーを呼び出すためには、以下の制約を満たす必要があります:
    
        固定されていないすべての変数 x_i について、u_x(i)-l_x(i) の値は
        開始信頼領域半径の少なくとも2倍でなければなりません(オプション
        'DFO Starting Trust Region' の一貫性制約を参照)。
    
    ソルバーは、導関数を使用しない信頼領域フレームワークに基づいています。
    この種の方法は、導関数が利用できないか計算が容易でない場合、
    および/または関数評価が高価またはノイズの多い小規模から中規模の問題
    (約100変数)に適しています。
    アルゴリズムの詳細な説明については、[アルゴリズムの詳細]を参照してください。
    
    アルゴリズムの動作とソルバー戦略は、様々なオプション([その他のパラメータ]参照)
    によって変更できます。これらのオプションは、``handle_init`` によるハンドルの
    初期化とソルバーの呼び出しの間のいつでも、``handle_opt_set`` と
    ``handle_opt_set_file`` によって設定できます。
    このソルバーに特有のオプション名は、接頭辞 DFO(導関数を使用しない最適化)
    または DFNO(導関数を使用しない非線形最適化)のいずれかで始まります。
    これらのオプションのデフォルト値は、ほとんどの場合に一般的な場合ですが、特定の問題に合わせてチューニングすることをお勧めします。
    特に、目的関数にノイズがあることがわかっている場合は、
    オプション 'DFO Noisy Problem' を 'YES' に設定することを強くお勧めします。
    ソルバーが終了したら、次の解決のためにオプションを変更することができます。
    ソルバーは、さまざまな開始点やオプションで繰り返し呼び出すことができます。
    
    ``handle_solve_dfno`` に実装されている基本的なアルゴリズムは、
    ``handle_solve_dfno_rcomm`` で使用されているものと同じです。
    ``handle_solve_dfno`` は、非線形目的関数に対する導関数フリーソルバーへの
    フォワードコミュニケーションインターフェースとして機能します。
    
    参考文献
    ----------
    Cartis, C, Fiala, J, Marteau, B and Roberts, L, 2018, `モデルベースの導関数フリー
    最適化ソルバーの柔軟性と堅牢性の向上`, 技術報告書, オックスフォード大学
    
    Conn, A R, Scheinberg, K and Vicente, L N, 2009, `導関数フリー最適化入門,
    MPS-SIAM最適化シリーズ第8巻`, MPS/SIAM, フィラデルフィア
    
    Powell, M J D, 2009, `導関数を用いない境界制約付き最適化のためのBOBYQAアルゴリズム`,
    レポート DAMTP 2009/NA06, ケンブリッジ大学,
    https://www.damtp.cam.ac.uk/user/na/NA_papers/NA2009_06.pdf
    
    関連項目
    --------
    :meth:`naginterfaces.library.examples.opt.handle_solve_dfno_ex.main`    
help(opt.bounds_quasi_func_easy)

naginterfaces.library.optモジュールのbounds_quasi_func_easy関数に関するヘルプ:

bounds_quasi_func_easy(ibound, funct1, bl, bu, x, liw=None, lw=None, data=None) 関数値のみを使用した準ニュートン法アルゴリズムによる、境界制約付き最小化(使いやすいバージョン)。

`bounds_quasi_func_easy`は、独立変数x_1,x_2,...,x_nの固定された上限と下限の制約の下で、
関数F(x_1,x_2,...,x_n)の最小値を見つけるための、使いやすい準ニュートン法アルゴリズムです。
関数値のみを使用します。

この関数は、連続で、連続な一次および二次導関数を持つ関数を対象としています
(ただし、導関数に時折不連続性がある場合でも通常は機能します)。

詳細については、e04jyに関するnAGライブラリドキュメントを参照してください

https://www.nag.com/numeric/nl/nagdoc_27.1/flhtml/e04/e04jyf.html

パラメータ
----------
ibound : int
    特殊な形式の境界を扱う機能を使用するかどうかを示します。

    以下のいずれかの値に設定する必要があります:

    `ibound` = 0

        すべてのl_jとu_jを個別に提供する場合。

    `ibound` = 1

        x_jに境界がない場合。

    `ibound` = 2

        すべての境界が0 <= x_jの形式の場合。

    `ibound` = 3

        l_1 = l_2 = ... = l_nかつu_1 = u_2 = ... = u_nの場合。

funct1 : callable fc = funct1(xc, data=None)
    任意の点xにおける関数F(x)の値を計算するために`funct1`を提供する必要があります。

    `bounds_quasi_func_easy`で使用する前に、個別にテストする必要があります
    ([E04イントロダクション]を参照)。

    パラメータ
    ~~~~~~~~~~
    xc : float, ndarray, shape (n)
        関数値が必要な点x。

    data : 任意, オプション, その場で変更可能
        コールバック関数用のユーザー通信データ。

    戻り値
    ~~~~~~~
    fc : float
        現在の点xにおける関数Fの値。

bl : float, array-like, shape (n)
    下限l_j。

    `ibound`が0に設定されている場合、j = 1,2,...,nに対して`bl`[j-1]をl_jに設定する必要があります。
    (特定のx_jに下限が指定されていない場合、対応する`bl`[j-1]を-10^6に設定する必要があります。)

    `ibound`が3に設定されている場合、`bl`[0]をl_1に設定する必要があります;
    `bounds_quasi_func_easy`は`bl`の残りの要素を`bl`[0]と等しく設定します。

bu : float, array-like, shape (n)
    上限u_j。

    `ibound`が0に設定されている場合、j = 1,2,...,nに対して`bu`[j-1]をu_jに設定する必要があります。
    (特定のx_jに上限が指定されていない場合、対応する`bu`[j-1]を10^6に設定する必要があります。)

    `ibound`が3に設定されている場合、`bu`[0]をu_1に設定する必要があります;
    `bounds_quasi_func_easy`は`bu`の残りの要素を`bu`[0]と等しく設定します。

x : float, array-like, shape (n)
    j = 1,2,...,nに対して、`x`[j-1]を最小値の位置のj番目の成分の推定値に設定する必要があります。

liw : None または int, オプション注意: この引数がNoneの場合、デフォルト値が使用されます。
        以下のように決定されます: n+2。
    
        配列 `iw` の次元。
    
    lw : None または int, オプション
        注意: この引数がNoneの場合、デフォルト値が使用されます。
        以下のように決定されます: max(n*(n-1)/2+12*n, 13)。
    
        配列 `w` の次元。
    
    data : 任意, オプション
        コールバック関数用のユーザー通信データ。
    
    戻り値
    -------
    bl : float, ndarray, 形状 (n)
        ``bounds_quasi_func_easy`` で実際に使用される下限。
    
    bu : float, ndarray, 形状 (n)
        ``bounds_quasi_func_easy`` で実際に使用される上限。
    
    x : float, ndarray, 形状 (n)
        計算中に見つかった最小点。したがって、終了時に例外や警告が発生しない場合、
        `x`[j-1] は最小値の位置のj番目の成分です。
    
    f : float
        `x` に格納された最終点に対応する F(x) の値。
    
    iw : int, ndarray, 形状 (`liw`)
        関数が正常に終了するか、`errno` が 3 または 5 の場合、
        `iw` の最初の n 要素には、どの変数が現在境界上にあり、
        どの変数が自由であるかについての情報が含まれます。
        具体的には、x_i が:
    
        -   上限に固定されている場合、`iw`[i-1] は -1 です。
    
        -   下限に固定されている場合、`iw`[i-1] は -2 です。
    
        -   実質的に定数の場合(つまり、l_j = u_j)、`iw`[i-1] は -3 です。
    
        -   自由な場合、`iw`[i-1] は自由変数のシーケンスにおけるその位置を示します。
    
        さらに、`iw`[n] には自由変数の数(つまり、n_z)が含まれます。
    
        配列の残りの部分はワークスペースとして使用されます。
    
    w : float, ndarray, 形状 (`lw`)
        関数が正常に終了するか、`errno` が 3 または 5 の場合、`w`[i-1] には
        射影された勾配ベクトル g_z の i 番目の要素の有限差分近似が含まれます(i = 1,2,...,n)。
        さらに、`w`[n] には射影されたヘッセ行列の条件数の推定値(つまり、k)が含まれます。
        配列の残りの部分はワークスペースとして使用されます。
    
    例外
    ------
    NagValueError
        (`errno` 1)
            入力時、n = *<値>*。
    
            制約: n >= 1。
    
        (`errno` 1)
            入力時、`ibound` = *<値>*。
    
            制約: 0 <= `ibound` <= 3。
    
        (`errno` 1)
            入力時、`lw` = *<値>*。
    
            制約: `lw` >= *<値>*。
    
        (`errno` 1)
            入力時、`liw` = *<値>*。
    
            制約: `liw` >= *<値>*。
    
        (`errno` 1)
            入力時、`ibound` = 0 かつ一部の j に対して `bl`[j-1] > `bu`[j-1]、
            または `ibound` = 3 かつ `bl`[0] > `bu`[0]。
    
        (`errno` 2)
            `funct1` への呼び出しが 400*n 回行われました。
    
        (`errno` 4)
            計算中にオーバーフローが発生しました。
    
        (`errno` 9)
            変数の絶対値が非常に大きくなりました。`funct1` にミスがあるか、
            問題に有限の解がないか、または問題のスケーリングが必要かもしれません。
    
        (`errno` 10)前方差分の1つが負でした。

警告

NagAlgorithmicWarning (errno 3) 最小値の条件がすべて満たされていませんが、 より低い点が見つからず、アルゴリズムが失敗しました。

(`errno` 5)
    局所最小値が見つかった可能性が高いですが、
    保証することはできません。

(`errno` 6)
    局所最小値が見つかった可能性が高いですが、
    保証することはできません。

(`errno` 7)
    局所最小値が見つかった可能性は低いです。

(`errno` 8)
    局所最小値が見つかった可能性は非常に低いです。

注意

このルーチンに相当する従来のCインターフェースは nAGライブラリには存在しません。

bounds_quasi_func_easyは以下の形式の問題に適用可能です:

F(x_1,x_2,...,x_n)を最小化する。ただし、l_j <= x_j <= u_j, j =
1,2,...,nの制約条件がある

F(x)の導関数が利用できない場合。

x_jに実際に制限がない問題、非負制約のみの問題、 l_1 = l_2 = … = l_nかつu_1 = u_2 = … = u_nの問題に対して 特別な対応がなされています。 任意の点xにおけるF(x)の値を計算する関数を提供する必要があります。

あなたが提供した開始点から、F(x)の勾配と曲率の推定に基づいて、 制約付き関数の局所最小値に収束することを意図した 実行可能な点の列が生成されます。 最終点が最小値であることを検証する試みがなされます。

典型的な反復は、現在の点xから始まります。ここでn_z個(仮に)の 変数が両方の境界から自由です。 自由変数に関するF(x)の導関数の有限差分近似である 射影勾配ベクトルg_zが既知です。 単位下三角行列Lと対角行列D(どちらもn_z次元)も保持されており、 LDL^Tは自由変数に関する2次導関数行列(つまり、射影ヘッセ行列)の 正定値近似です。 以下の方程式を解いて探索方向p_zを求めます:

LDL^Tp_z = -g_z

p_zは適切な0要素を挿入してn次元ベクトルpに拡張されます。 次に、F(x+alpha p)がalphaに関して(固定境界に従って) おおよそ最小になるようなalphaを見つけます。xはx+alpha pに置き換えられ、 行列LとDは、ステップalpha pによって推定勾配に生じた変化と 一致するように更新されます。 pに沿った探索中に実際に変数が境界に達した場合、 その変数は固定され、次の反復でn_zが減少します。 ほとんどの反復ではg_zを前方差分で計算しますが、 必要と思われる場合は中心差分を使用します。

2セットの収束基準があります - 弱いものと強いものです。 弱い基準が満たされるたびに、すべてのアクティブな制約に対して ラグランジュ乗数が推定されます。 ラグランジュ乗数の推定値が著しく負の場合、 負のラグランジュ乗数に関連する変数の1つが推定値は拘束から解放され、拡張された部分空間で次の探索方向が 計算されます(つまり、n_zが増加します)。 そうでない場合、実行可能である限り、現在の部分空間での最小化が 続行されます。 それが実行不可能な場合、または強力な収束基準が すでに満たされている場合、1つ以上のラグランジュ乗数 推定値がゼロに近い場合、対応する変数の値に わずかな摂動が加えられ、より低い関数 値が得られるまで順次行われます。 その後、摂動を加えた点から通常のアルゴリズムが再開されます。

鞍点が疑われる場合、鞍点から 離れるための局所探索が実行されます。 制約付き最小値と考えられる点が見つかった場合にも 局所探索が実行されます。

参考文献

Gill, P E and Murray, W, 1976, 変数に境界がある場合の最小化, NPL Report NAC 72, National Physical Laboratory

関連情報
MENU
© 日本ニューメリカルアルゴリズムズグループ株式会社 2025
Privacy Policy  /  Trademarks