関数を使った上下限指定 (dynamic_bounds_fun)

警告

これは開発中の機能です。将来のバージョンでは動作と使い方が変更される可能性があります。

サンプルファイル

注釈

この機能を使った完全なサンプルは pipe_dynamic_bounds.py です。 pipe.femprj を Femtet で開いた状態でお試しください。

dynamic_bounds_fun とは

dynamic_bounds_fun は、通常の拘束条件の代替として使える機能で、 「ある変数の上下限が他の変数の関数で表せる」 場合に利用できます。

pyfemtet では、通常の拘束関数は以下の流れで処理されます:

  • 変数を提案

  • 拘束違反か判定

  • 違反していれば再提案

拘束が厳しい場合は 2→3 が何度も繰り返されます。 dynamic_bounds_fun を使うと 不可能な提案がそもそも出ない ため、この無駄が発生しません。

注釈

dynamic_bounds_fun は拘束関数を高速化する機能ではなく、拘束関数が変数の上下限の形で書ける場合に限り、拘束そのものを置き換える機能です。

注釈

initial_value は常に上下限の範囲に入っている必要があります。

dynamic_bounds_fun を使うタイミング

  • ある変数の下限・上限が他の変数の関数として書ける場合

  • それ以外の拘束は通常通り add_constraint を使います(dynamic_bounds_fun と通常の拘束関数は併用可能)。

dynamic_bounds_fun が利用可能な例

問題

  • 変数 a: 下限 0, 上限 10

  • 変数 b: 下限 0, 上限 10

  • 拘束関数: a + b < 10

この拘束関数は次のように書けます:

  • 変数 a: 下限 0, 上限 10

  • 変数 b: 下限 0, 上限 10 - a

dynamic_bounds_fun の定義

まず、上下限を計算する関数を定義します。

def dynamic_bounds_of_b(opt) -> tuple[float, float]:
    """Return the dynamic lower and upper bounds of b."""
    params = opt.get_variables()
    return 0, 10. - params['a']

注釈

動的な上下限を計算する関数は、引数として opt: AbstractOptimizer を取り、戻り値として下限・上限を表す ふたつの数値 を返さなければなりません。

変数登録

次に、変数追加時にその関数を登録します。

femopt.add_parameter(name='a', initial_value=0, lower_bound=0, upper_bound=10)
femopt.add_parameter(
    name='b', initial_value=0,
    properties={
        'dynamic_bounds_fun': dynamic_bounds_of_b
    }
)

これにより、b の上下限は常に (0, 10 - a) となり、 a + b < 10 を満たさない組合せは最初から提案されなくなります。

警告

dynamic_boundsを計算する 関数の中では、その上下限を適用する変数より前に add_parameter された変数しか参照してはいけません。

そうしない場合、エラーや警告なく前回の試行の変数値が参照されてしまいます。

# OK:
add_parameter('a', ...)
add_parameter('b', properties={"dynamic_bounds_fun": fun_using_a})

# NG:
add_parameter('b', properties={"dynamic_bounds_fun": fun_using_a})
add_parameter('a', ...)