求解パラメータ中の許容エラーは、スラック変数範囲です。
スラック変数とは、OR(オペレーションズリサーチ)用語です。学術用語なので、少し難しいです。ググると不等式制約を等式制約に変換するときの変数と言う風に説明されるのですが、なんのことか分からない方が大半だと思います。
スケジュールナースでは、不等式制約においてどこまでをソフト制約とするか、その範囲を決める、との説明をしているのですが、OR的には、スラック変数範囲を規定する、ということになります。
夜勤Yとして、その範囲をRHS[Min,Max]とすると、
ΣY=RHS[Min:Max]
と表現できます。例えば、夜勤3回以上4回以下のハード制約とするなら、
ΣY=RHS[3:4]
となります。ところが、この制約は、満足できるかどうか分かりません。MIPソルバにおいても、解が無い場合は、Infeasibleとなり、その原因は、全く分からなくなってしまいます。なので、一般に、スラック変数Xを導入して3回未満でも解がない、ということがないように
ΣY+X>=3
Xの範囲は、X=[0:∞] とすれば、(実際には、[0:3]の範囲で十分)、解がないという事態は、必ず防げます。Xが0でない場合にソフトエラーが発生した、(ただし連続変数)という風に解釈できます。Xの値にコストを付加すれば、コスト最小となるように(目的関数値が最小となるように)ソルバは動作します。
同様に、
ΣYーZ<=4
というスラック変数Zを導入して、Z=[0:∞] とすれば、解がないという事態は絶対起こりません。
線形ソルバにとって、スラック変数の負担は、SATソルバに比べれば非常に軽いです。加えて、その変数範囲[0:∞]という、連続変数の幅の大きさはソルバ負担にほぼなりません。なので、MIPソルバによる定式化の場合は、スラック変数付で、定式化することが定石です。つまり、数を数える制約は、全て∞幅のソフト制約にするのが基本です。
SATソルバでは、そもそも∞という定式化は存在しません。何某かの有限な整数幅でしか定義できません。この辺、線形ソルバと0:1変数のみ扱うSATソルバの決定的かつ本質的な違いです。幅の大きさはソルバ負担に直に効いてきます。この幅をスケジュールナースでは、許容エラー数と表現しています。
この辺、新しいアルゴリズムでは、ラフに設定しても解がないということがないように、自動設定するモードを付加する予定です。MCPでもコントロールできるようにします。
MCP Pythonでの求解パラメータは、次のようなクラスで表現しています。このクラスを操作することで、求解パラメータを操作できるようになります。これは、C#クラスからGoogleAIモードで生成させたモデルです。例えば、SwIntのuseは、上図、適用のチェックの有無に対応します。weightが重みに対応します。
ほぼ、C#クラスにあるコメントを踏襲していますが、SwIntクラスのValueに着目してください。(スラック変数)実は、この”スラック変数”は、C#クラスのコメントにはありません。LLMが勝手に付け足した言葉です。
LLMの理解力が、如何に優れているかを知った、次第です。
class SwInt(BaseModel):
"""
ソルバの制約許容数や重み(ウェイト)を定義するモデルです。
"""
use: bool = Field(
default=False,
description="有効(true)か無効(false)かを示すフラグ。"
)
value: int = Field(
default=0,
description="1制約あたりのCARDINALS許容エラー数(スラック変数)。"
)
total_max_errors: int = Field(
default=0,
description="現在使用されていません(0: 最小化を意味します)。"
)
weight: int = Field(
default=1,
description=(
"ソフト制約の重み(自然数、1-10推奨)。"
"※ソフトレベル(1-7のインデックス)とは異なる「実際の重み係数」です。"
)
)class SolvingParameters(BaseModel):
"""
ソルバの求解パラメータ、ソフト制約レベルごとの重み設定、
および外部Python制約などを管理するクラスです。
"""
name: str = Field(
default="SolvingParameters",
frozen=True,
description="オブジェクト名。常に 'SolvingParameters' 固定です。"
)
# Dictionary> solving_map を再現
# 外側のキー(int)はソフト制約レベル(1-7など)、内側のキー(str)は制約名
solving_map: dict[int, dict[str, SwInt]] = Field(
default_factory=dict,
description="ソフトレベルおよび制約名ごとの詳細設定マップ。"
)
# Pythonによる制約記述
external_constraint_python: str = Field(
default="",
description="Pythonスクリプトによる外部制約記述。"
)
# プロジェクトコメント
comment: str = Field(
default="",
description="プロジェクトの変更履歴やメモ用コメント。"
)
# 求解パラメータ Dictionary
parameters: dict[str, int] = Field(
default_factory=dict,
description="ソルバの各種数値パラメータ(イテレーション回数等)。"
)
# 現在使用されていない、または内部用のフィールド
aws_parameters: dict[str, str] = Field(
default_factory=dict,
description="AWS関連パラメータ(現在未使用)。"
)
external_constraint: str = Field(
default="",
description="言語制約記述(現在未使用)。"
)
python_property_file: str = Field(
default="",
description="内部用プロパティファイルパス(編集不可)。"
)
python_property_file_post: str = Field(
default="",
description="内部用プロパティファイルパス(後処理、編集不可)。"
)
0 件のコメント:
コメントを投稿