web-dev-qa-db-ja.com

何千ものIF ... THEN ... ELSEルールをどのように管理できますか?

私は、何千ものif ... then ... elseステートメントで構成されるアプリケーションの構築を検討しています。アプリケーションの目的は、どのような風景でも牛の動きを予測できるようにすることです。それらは、太陽、風、食料源、突然の出来事などの影響を受けます。

このようなアプリケーションはどのように管理できますか?私は、数百のIFステートメントの後、プログラムがどのように反応し、特定の反応につながるものをデバッグするかが予測不能になるのと同じくらい良いことになると思います。毎回IFステートメントツリー全体をトラバースする必要があるということです。

ルールエンジンについて少し読みましたが、この複雑さをどのように回避するかはわかりません。

215
David

ロジックプログラミング言語のPrologがあなたの探しているものかもしれません。あなたの問題の説明は、私がそれが適切であるかどうかを評価するのに十分具体的ではありませんが、あなたが言うこととはかなり似ています。

Prologプログラムは、適用されるファクトとルールで構成されています。 「牛がお腹が空いていて、新しい場所に古い場所よりも多くの食物がある場合、牛はその場所に移動する」という簡単なルールの例を次に示します。

moves_to(Cow, Location) :-
  hungry(Cow),
  current_location(Cow, OldLoc),
  food_in(OldLoc, OldFood), food_in(Location, NewFood),
  NewFood > OldFood.

大文字で書かれているものはすべて変数です。 Prologは、すべての条件を満たすこれらの変数の値を見つけようとします。このプロセスは、統一と呼ばれる強力なアルゴリズムを使用して行われます。これは、Prologおよび類似のロジックプログラミング環境の中心です。

ルールに加えて、ファクトのデータベースが提供されます。上記のルールを使用する簡単な例は次のようになります。

current_location(white_cow, pasture).

current_location(black_cow, barn).
hungry(black_cow).

current_location(angry_bull, forest).
hungry(angry_bull).

food_in(barn, 3).
food_in(pasture, 5).
food_in(forest, 1).

White_cowや牧草地などは大文字で書かれていないことに注意してください。それらは変数ではなく、原子です。

最後にクエリを作成し、何が起こるかを尋ねます。

?- moves_to(white_cow, Destination).
No.
?- moves_to(black_cow, Destination).
Destination = pasture
?- moves_to(Cow, Destination).
Cow = black_cow, Destination = pasture
Cow = angry_bull, Destination = barn
Cow = angry_bull, Destination = pasture

最初のクエリは、白い牛がどこに移動するかを尋ねます。上記のルールと事実を踏まえると、答えは「いいえ」です。これは、必要に応じて、「わからない」または「動かない」と解釈できます。

2番目のクエリは、黒牛がどこに移動するかを尋ねます。食べるために牧草地に移動します。

最後のクエリは、すべての牛がどこに移動するかを尋ねます。その結果、意味のあるすべての(Cow、Destination)が得られます。この場合、黒牛は予想通りに牧草地に移動します。ただし、怒っている雄牛には、ルールを満たす2つの選択肢があり、牧草地または納屋に移動できます。

注:私が最後にPrologを作成してから数年が経過しました。すべての例が構文的に有効であるとは限りませんが、アイデアは正しいはずです。

73
exDM69

if web問題に取り組むには、特定の各ルールが個別にコーディングされているルールエンジンを作成できます。これをさらに改善するには、ドメイン固有言語(DSL)を作成してルールを作成しますが、DSLだけでは、問題を1つのコードベース(メイン)から別のコードベース(DSL)に置き換えるだけです。構造がないと、DSLはネイティブ言語(Java、C#など)よりもうまく機能しません。そのため、構造的なアプローチの改善を見つけた後、DSLに戻ります。

基本的な問題は、モデル化の問題があることです。このような組み合わせの状況に遭遇したときはいつでも、その状況を説明するモデルの抽象化が粗すぎることは明らかです。ほとんどの場合、単一のエンティティー内の異なるモデルに属するはずの要素を組み合わせます。

モデルを分解し続けると、最終的にこの組み合わせ効果が完全に解消されます。ただし、この道を進むと、設計で迷子になり、さらに大きな混乱が生じやすくなります。ここでの完璧主義は、必ずしもあなたの友人ではありません。

有限状態機械とルールエンジンは、この問題を分解して管理しやすくする方法のほんの一例です。ここでの主なアイデアは、このような組み合わせの問題を取り除く良い方法は、多くの場合、システムが十分に機能するまでデザインを作成し、ネストされた抽象化レベルでそれを繰り返すであるということです。フラクタルを使用して複雑なパターンを作成する方法に似ています。顕微鏡で観察する場合も、鳥瞰図で観察する場合も、ルールは同じです。

これをドメインに適用する例。

あなたは、牛が地形をどのように移動しているかをモデル化しようとしています。あなたの質問には詳細がありませんが、あなたの大量のifにはif cow.isStanding then cow.canRun = trueなどの決定フラグメントが含まれていると思いますが、たとえば地形の詳細を追加すると、行き詰まってしまいます。したがって、実行したいすべてのアクションについて、考えられるすべての側面をチェックし、次の可能なアクションのためにこれらの検証を繰り返す必要があります。

まず、再現可能な設計が必要です。この場合、シミュレーションの変化する状態をモデル化するFSMになります。したがって、私が最初に行うことは、参照FSMを実装し、stateインターフェース、transitionインターフェース、そしておそらく他の2つが利用できる共有情報を含むことができる遷移context。基本的なFSM実装は、コンテキストに関係なく、ある遷移から別の遷移に切り替わります。これがルールエンジンの出番です。ルールエンジンは、遷移が発生する場合に満たす必要がある条件を明確にカプセル化します。ここでのルールエンジンは、ブール値を返す評価関数を持つルールのリストのように単純にすることができます。遷移が発生するかどうかを確認するには、ルールのリストを反復処理し、それらのいずれかがfalseと評価された場合、遷移は発生しません。遷移自体には、FSM(および他の可能なタスク)の現在の状態を変更するbehaviouralコードが含まれます。

ここで、GODレベルで単一の大きなFSMとしてシミュレーションを実装し始めると、可能な状態、遷移などのLOTがたくさん発生します。if-elseの混乱は、修正されているように見えますが、実際には広がっています。各IFはここで、コンテキストの特定の情報(この時点ではほとんどすべてを含んでいます)に対してテストを実行するルールと、各IF本体が遷移コードのどこかにあります。

フラクタルの内訳を入力します。最初のステップは、状態が牛自身の内部状態(立っている、走っている、歩いている、放牧など)である各牛のFSMを作成することであり、それらの間の遷移は環境の影響を受けます。グラフが完全ではない可能性があります。たとえば、放牧は立っている状態からのみアクセス可能です。他の遷移はモデルに存在しないため、破棄されます。ここでは、牛と地形の2つの異なるモデルでデータを効果的に分離します。それぞれ独自のプロパティセットがあります。この内訳により、エンジン設計全体を簡素化できます。すべてを決定する単一のルールエンジンを使用する代わりに、非常に具体的な詳細を決定する複数のより単純なルールエンジン(遷移ごとに1つ)があります。多くのゲーム会社は、このような有限状態機械を使用して、そのような側面を決定しています。

FSMと同じコードを再利用しているため、これは基本的にFSMの構成です先ほどDSLについて言及したときのことを覚えていますか?これは、多くのルールと遷移を記述する必要がある場合に、DSLが多くのメリットを発揮できる場所です。

より深く行く

現在、GODは牛の内部状態の管理に関するすべての複雑さに対処する必要はありませんが、さらにプッシュすることができます。たとえば、地形の管理には依然として多くの複雑さが伴います。ここで、内訳で十分かどうかを判断します。たとえば、GODで地形ダイナミクス(長い草、泥、乾いた泥、短い草など)を管理する場合、同じパターンを繰り返すことができます。すべてのテレインステート(ロンググラス、ショートグラス、マ​​ディ、ドライなど)を新しいテレインFSMに抽出することにより、そのようなロジックをテレイン自体に埋め込むことを妨げるものは何もありません。たとえば、濁った状態になるには、ルールエンジンがコンテキストをチェックして液体を見つける必要があります。そうでない場合は不可能です。 GODはさらにシンプルになりました。

FSMのシステムを自律させることで完成させ、それぞれにスレッドを与えることができます。この最後の手順は必須ではありませんが、意思決定を委任する方法を調整することにより、システムの相互作用を動的に変更できます(特殊なFSMを起動するか、事前に決定された状態を返すだけです)。

トランジションが「他の可能なタスク」も実行できると私たちが述べた方法を覚えていますか?異なるモデル(FSM)が相互に通信する可能性を追加して、それを探求してみましょう。イベントのセットを定義して、各FSMがこれらのイベントにリスナーを登録できるようにすることができます。したがって、たとえば牛が地形ヘクスに進入した場合、ヘクスは遷移の変化についてリスナーを登録できます。ここで、各FSMは、それが持つ特定のドメインについての知識なしに非常に高いレベルで実装されるため、少し注意が必要です。しかし、牛にイベントのリストを公開させることでこれを実現でき、セルは、反応できるイベントを検出した場合に登録できます。ここでのイベントファミリーの適切な階層は、優れた投資です。したがって、牛が放牧を開始すると、地形のパッチが放牧時間を記録し、しばらくすると長い草から短い草に移行し、牛に信号を送ることができます。

草の栄養レベルと成長サイクルをモデル化することで、さらに深く押すことができます。それを推測しました...地形パッチの独自のモデルに埋め込まれた草FSM。

アイデアを十分にプッシュすると、すべての側面がほぼ自己管理されるため、GODはほとんど何もすることができず、より敬虔なことに費やす時間を解放できます。

要約

上で述べたように、ここのFSMは解決策ではなく、そのような問題の解決策は、言うまでもなくコードではなく、問題をモデル化する方法で見つかることを示す手段にすぎません。可能性のある他の解決策が最もありそうであり、おそらく私のFSMの提案よりはるかに優れています。ただし、「フラクタル」アプローチは、この困難を管理するための良い方法であり続けます。正しく実行すれば、重要な部分に深いレベルを動的に割り当て、重要度の低い部分に単純なモデルを割り当てることができます。変更をキューに入れ、リソースが利用可能になったときにそれらを適用できます。アクションシーケンスでは、牛から牧草地への栄養素の移動を計算することはそれほど重要ではない場合があります。ただし、これらの遷移を記録し、後で変更を適用するか、単にルールエンジンを置き換えるか、FSM実装を、直接フィールドにない要素の単純な単純なバージョンで置き換えることにより、経験に基づいた推測で近似することができます。関心(フィールドの反対側にいるその牛)に焦点を当て、より詳細なやり取りを可能にして、より多くのリソースを共有します。システム全体を再検討することなく、これらすべてが可能です。各パーツは十分に分離されているため、モデルの深さを制限したり拡張したりするドロップイン交換を作成するのが簡単になります。標準設計を使用することにより、それに基づいて構築し、DSLなどのアドホックツールへの投資を最大化して、ルールまたはイベントの標準ボキャブラリを定義し、再び非常に高いレベルから開始し、必要に応じて改良を加えることができます。

私はコード例を提供しますが、これは私が今できる余裕があるすべてです。

140
Newtopian

あなたが話しているこれらすべての条件文は、実際にはプログラム自体の一部ではなく、プログラムを構成するデータである必要があるようです。それらをそのように扱うことができる場合は、モデルを改善するたびにコードを変更して再コンパイルする必要がなく、構成を変更するだけでプログラムの動作を自由に変更できます。

問題の性質に応じて、実世界をモデル化する方法はたくさんあります。さまざまな条件が、シミュレーションに適用されるルールまたは制約になる場合があります。次のようなコードの代わりに:

if (sunLevel > 0.75) {
   foreach(cow in cows) {
       cow.desireForShade += 0.5;
   }
}
if (precipitation > 0.2) {
   foreach(cow in cows) {
       cow.desireForShelter += 0.8;
   }
}

代わりに、次のようなコードを使用できます。

foreach(rule in rules) {
   foreach (cow in cows) {
      cow.apply(rule);
   }
}

または、いくつかの入力を与えられた牛の行動をモデル化する線形プログラムを開発できる場合、各制約は連立方程式の線になる可能性があります。次に、それを反復可能なマルコフモデルに変換します。

状況に応じた適切なアプローチを言うのは難しいですが、制約がコードではなくプログラムへの入力であると考えると、はるかに楽になると思います。

90
Caleb

誰もこれについて言及しなかったので、私はそれを明示的に言うと思いました:

数千の「If .. Then .. Else」ルールは、不適切に設計されたアプリケーションの兆候です。

ドメイン固有のデータ表現はこれらのルールのように見えるかもしれませんが、実装はドメイン固有の表現に似ているべきだと確信していますか?

45
blueberryfields

タスクに適したソフトウェア/コンピューター言語を使用してください。 Matlab は、文字通り何千もの条件が存在する可能性がある複雑なシステムをモデル化するために非常に頻繁に使用されます。 if/then/else句を使用せず、数値分析による。 [〜#〜] r [〜#〜] は、同じことを行うためのツールとパッケージで満たされたオープンソースのコンピューター言語です。ただし、これはモデルをより数学的に表現し直す必要があることを意味します。そのため、モデルに主要な影響と影響間の相互作用の両方を含めることができます。

まだ行っていない場合は、モデリングとシミュレーションに関するコースに従ってください。あなたがすべき最後のことは、if-then-elseに関してそのようなモデルを書くことを検討することです。モンテカルロマルコフチェーン、サポートベクターマシン、ニューラルネットワーク、潜在変数分析などがあります。利用可能なモデリングツールの豊富さを無視して、100年前に戻らないでください。

17
Joris Meys

If/thenルールが非常に多い場合は、ユーザーがプログラミング言語を知らなくても編集できるプログラム外の1か所にすべてをまとめることが役立つため、ルールエンジンが役立つ場合があります。また、視覚化ツールが利用できる場合があります。

ロジックプログラミングソリューション(Prologなど)も確認できます。 if/thenステートメントのリストをすばやく変更して、入力の任意の組み合わせが特定の結果につながるかどうかを調べるなどの処理を行うことができます。また、手続き型コード(またはオブジェクト指向コード)。

13
psr

それは突然私に夜明けになりました:

Decision Learning Tree (ID3アルゴリズム)を使用する必要があります。

誰かがあなたの言語で実装した可能性が高いです。そうでない場合は、既存のライブラリを移植できます

11
Darknight

これはコミュニティWikiの回答の詳細であり、他の回答によって提案されたさまざまなモデリングツールを集約したものです。リソースへのリンクを追加しました。

ハードコーディングされた何千ものif/elseステートメントに対して異なるアプローチを使用する必要があることを改めて述べる必要はないと思います。

11
ocodo

すべての大規模なアプリケーションには、何千ものif-then-elseステートメント。他のフロー制御は含まれません。これらのアプリケーションは、その複雑さにもかかわらず、デバッグおよび維持されます。

また、ステートメントの数によってフローが予測不能になることはありません。非同期プログラミングが行います。確定的アルゴリズムを同期的に使用すると、毎回100%予測可能な動作になります。

あなたはおそらくもっとよく説明スタックオーバーフローまたは Code Review で何をしようとしているのか人々が正確なリファクタリング手法を提案できるように使用します。また、「ifステートメントをネストしすぎないようにするには<コードの一部>を指定する>」のように、より正確な質問をすることもできます。

9

ルールエンジンを使用することをお勧めします。 Javaの場合、jBPMまたはOracle BPMが役立ちます。ルールエンジンでは、基本的にXMLを使用してアプリケーションを構成できます。

2
Sid

この問題は、「if-then」手続き型コードで記述されていても、ビジネスアプリケーション用に考案された多数のルールソリューションで記述されていても、「ルール」では十分に解決されません。機械学習は、このようなシナリオをモデル化するためのいくつかのメカニズムを提供します。

基本的には、「システム」に影響を与える要因(たとえば、太陽、風、食料源、突然の出来事など)を個別に表現するためのスキームを策定する必要があります(牧草地の牛など)。離散とは対照的に、実際の値の関数表現を作成できるという誤った信念にもかかわらず、現実の世界(人間の神経系を含む)には、実際の値に基づいた、または実際の値に基づいて計算するコンピューターはありません。

関連する要素の数値表現を取得したら、いくつかの数学モデルのいずれかを構築できます。 1セットのノードが牛を表し、もう1セットが牧草地のいくつかの単位面積を表す2部グラフを提案します。どのような場合でも、牛は牧草地のいくつかの単位面積を占めます。各牛について、現在および他のすべての牧草地に関連する効用値が存在します。モデルが、牛がその牧草地のユニットの効用値を最適化しようとすることを前提としている場合(牛にとってそのようなものは何でも)、牛はユニットからユニットへ移動して最適化を図ります。

セルラー自動化は、モデルの実行に適しています。牛の移動を動機付ける実際の価値ある数学の世界の基礎となる数学は、場の勾配モデルです。牛は、ユーティリティ価値が低いと認識されている位置から、ユーティリティ値が高いと認識されている位置に移動します。

システムに環境の変化を注入した場合、それは牛の位置の定常状態の解決策に移行しません。また、ゲーム理論の側面を適用できるモデルにもなります。そのようなことが必ずしもこの場合に多くを追加するというわけではありません。

ここでの利点は、モデルの実行中に「牛」セルを2部グラフに差し引いて追加することで、牛の屠殺や新しい牛の取得を簡単に管理できることです。

2
charles

アプリケーションを適切に設計して、管理しやすくします。さまざまなビジネスロジックを個別のクラス/モジュールに分割して、アプリケーションを設計します。これらのクラス/モジュールを個別にテストする単体テストを作成します。これは非常に重要であり、ビジネスロジックが期待どおりに実装されていることを確認するのに役立ちます。

2
Bernard

問題から抜け出す方法を設計する単一の方法はおそらくないでしょうが、ifステートメントの大きなブロックを記述してソリューションを適用することに気づくさまざまな領域を分離しようとする場合、その複雑さを少しずつ管理できますそれらの小さな問題のそれぞれに。

で説明されているルールのようなテクニックを見てくださいリファクタリング 大きな条件を扱いやすいチャンクに分割する方法-共通のインターフェースを持つ複数のクラスは、例えば、caseステートメントを置き換えることができます。

早期終了も大きな助けです。エラー状態がある場合は、関数を開始するときに、例外をスローするか、入れ子にする代わりに戻ることで、エラー状態を解消してください。

条件を述語関数に分割すると、それらを追跡しやすくなります。また、それらを標準形式に変換できる場合は、ハードコードされたデータ構造ではなく、動的に構築されたデータ構造でそれらを取得できる可能性があります。

2
Dan Monego

If-elseステートメントをそれほど多く定義する必要はないと思います。私の観点から見ると、問題には複数の要素があります。

  • 性格や構成が異なる複数の牛がいるため、非同期またはマルチスレッドにする必要があります。それぞれの牛は、次の動きの前にどちらの方向に進むべきかを自問します。私の意見では、同期コードはこの問題の貧弱なツールです。

  • 決定木の構成は常に変化します。実際の牛の位置、天候、時間、地形などによって異なります。複雑なif-elseツリーを構築する代わりに、問題を wind rose に減らす必要があると思います。 =または方向-重み関数: figure 1 図1-方向-一部のルールの重み関数

    牛は常に合計体重が最大になる方向に移動する必要があります。したがって、大きな決定木を構築する代わりに、各牛に一連のルール(異なる方向-体重関数)を追加し、方向を尋ねるたびに結果を処理するだけで済みます。これらのルールは、位置の変更ごと、または時間の経過によって再構成できます。または、これらの詳細をパラメーターとして追加すると、すべてのルールで取得できます。これは実装の決定です。方向を取得する最も簡単な方法は、1°ステップで0°から360°までの単純なループを追加することです。その後、各360方向の重みの合計をカウントし、max()関数を実行して適切な方向を取得できます。

  • これを行うのに必ずしもニューラルネットワークは必要ありません。ルールごとに1つのクラス、牛用、おそらく地形用など1つのクラスと、シナリオ用の1つのクラス(たとえば、ルールが異なる3つの牛と1つの特定の地形)。 figure2 図2-牛のアプリ非同期決定ノードと接続

    • メッセージング方向の赤-ルールによるウェイトマップ
    • 意思決定後の向きと位置の更新は青
    • 方向と位置の更新後の入力更新の場合は緑色
    • 入力を取得するための黒

    注:このようなものを実装するには、おそらくメッセージングフレームワークが必要になります

    したがって、学習牛の作成が問題の一部でない場合は、ニューラルネットワークや遺伝的アルゴリズムは必要ありません。私はAIの専門家ではありませんが、牛を実際の牛に適合させたい場合は、遺伝的アルゴリズムと適切な一連のルールを使用するだけで実行できます。私がよく理解しているのなら、ランダムなルール設定の牛の母集団が必要です。その後、実際の牛の行動とモデル母集団の行動を比較し、実際の牛に最も近い経路を歩く10%を維持できます。その後、保持した10%に基づいて牛の工場に新しいルール構成制約を追加し、母集団に新しいランダムな牛を追加するなどして、実際の牛と同じように動作するモデル牛を取得します...

1
inf3rno

あなたが本当にthousands of IF ... THENルールを持っているなら、あなたは過剰に指定しているかもしれないというケースかもしれないと付け加えます。価値があるのは、私が参加したニューラルネットワークモデリングの講演では、「単純な一連のルール」を使用して、かなり複雑で合理的に現実に一致する動作(実際のニューロンの動作)を生成する方法を説明することから始めます。それで、あなたはsure何千もの条件が必要ですか?つまり、天気、食料源の場所、突然の出来事、群れ、そして地形の4-5の側面に加えて、あなたは本当にもっと多くの変数を持つつもりですか?確かに、これらの条件を組み合わせるすべての可能な置換を行おうとすると、何千ものルールを簡単に持つことができますが、それは正しいアプローチではありません。たぶんファジーロジックスタイルのアプローチでは、さまざまな要因が各牛の位置に偏りをもたらし、全体的な決定に結びつくため、これをはるかに少ないルールで実行できます。

また、プログラムを変更せずにルールセットを簡単に調整できるように、ルールセットをコードの一般的なフローから分離する必要があることにも同意します。競合するルールセットを考え出し、それらが実際の牛の動きのデータに対してどのように機能するかを確認することもできます。楽しそう。

0
Chelonian

AIの領域であるエキスパートシステムについて説明しました。これらについて少し拡張するために、 推論エンジン を読むと、これが役立つ場合があります。 Google検索の方が使いやすいかもしれません-DSLを書くのは簡単な部分です。GoldParserのようなパーサーでこれを簡単に行うことができます。難しい部分は、決定のツリーを構築し、効率的に実行することです。

英国の NHS Directウェブサイト など、多くの医療システムはすでにこれらのエンジンを使用しています。

あなたが.NET'erなら、 Infer.NET が役立つかもしれません。

0
Chris S

牛の動きを見ていると360度方向に動けなくなってしまいます(牛は飛べません)。これはベクトルとして定義できます。

次に、太陽の位置、丘の傾斜、大きな騒音などをどのように処理しますか?

学位のそれぞれは、その方向に行きたいという欲求を表す変数です。 twigが牛の右に90度スナップします(牛が0度を向いていると仮定)。)と言います。牛が方向に移動したいという欲求への影響を追加または減算するすべての刺激を通過します。すべての刺激が適用されると、牛は最高の欲望の方向に移動します。

グラデーションを適用して、刺激がバイナリである必要がないようにすることもできます。たとえば、丘は一方向にまっすぐではありません。たぶん、牛は谷間または丘の上の道にあり、45 *やや上り坂、90 *やや下り坂でまっすぐ前に平らでした。 180 *急な丘で。

次に、イベントの重みと、影響の方向を調整できます。 if thensのリストではなく、最大値を探す1つのテストがあります。また、刺激を追加したい場合は、テストの前にそれを適用するだけでよく、ますます複雑さを追加することに対処する必要はありません。

牛は360方向に進むと言うのではなく、36方向に分割してみましょう。それぞれ10度

牛は360方向に進むと言うのではなく、36方向に分割してみましょう。それぞれ10度です。どれだけ具体的になる必要があるかによります。

0
Zero