1

まず、私は数学者であり、コーダーではないと言っておきましょう。線形ソルバーをコーディングしようとしています。私がコード化した10のメソッドがあります。のように、使用したいソルバーをユーザーに選択してもらいたいのですoptions.solver_choice='CG'

これで、10 個のメソッドすべてが 1 つのクラスにコーディングされました。この場合、戦略パターンをどのように使用すればよいですか?

以前は、スイッチケースを使用してメインプログラムで使用していた 10 個の異なる関数ファイルがありました。

if options.solver_choice=='CG'
CG(A,x,b);
if options.solver_choice=='GMRES'
GMRES(A,x,b);
.
.
.
4

4 に答える 4

3

これは最も正確な答えではありませんが、アイデアを得る必要があります。

戦略パターンを使用すると、ソルバー メソッドを実装するソルバー インターフェイスが得られます。

public interface ISolver {

    int Solve();

}

必要に応じて各ソルバー クラスを実装します。

public class Solver1 : ISolver {

    int Solve() {
        return 1;
    }

}

次に、解決を行うときに適切なソルバー クラスを渡します。

public int DoSolve(ISolver solver) {
    return solver.solve();
}

Foo.DoSolve(new Solver1());
于 2013-09-01T00:03:04.337 に答える
1

TL;DR

私は常に戦略パターンを理解しているので、基本的には、実行時にクラスまたはオブジェクトの構成を実行するという考え方です。実装の詳細は言語によって異なりますが、インターフェイスを共有するさまざまなモジュールを「プラグイン」することで、動作の一部を交換できるはずです。ここでは、Ruby での例を示します。

ルビーの例

#action メソッドが一連の結果を返す方法について select a 戦略を使用したいとします。CG および GMRES という名前のいくつかのモジュールを構成することから始めることができます。例えば:

module CG
  def action a, x, b
    { a: a, x: x, b: b }
  end
end

module GMRES
  def action a, x, b
    [a, x, b]
  end
end

次に、オブジェクトをインスタンス化します。

class StrategyPattern
end

my_strategy = StrategyPattern.new

最後に、必要なプラグイン動作でオブジェクトを拡張します。例えば:

my_strategy.extend GMRES
my_strategy.action 'q', nil, 1
#=> ["q", nil, 1]

my_strategy.extend GMRES
my_strategy.action 'q', nil, 1
#=> {:a=>"q", :x=>nil, :b=>1}

戦略パターンは、クラスのインスタンスを拡張するのではなく、クラス レベルで実装する必要があると主張する人もいるかもしれませんが、この方法は従うのが簡単であり、他の戦略を選択する必要がある他のインスタンスを台無しにする可能性が低いと思います。

よりオーソドックスな代替手段は、含めるモジュールの名前をクラス コンストラクターに渡すことです。Russ Olsen のDesign Patterns in Rubyを読んで、より完全な処理とパターンを実装するための追加の方法を確認してください。

于 2013-09-01T00:40:23.707 に答える
0

他の回答はパターンを正しく示していますが、十分に明確ではないと思います。残念ながら、私が提供したリンクは同じことを行うので、戦略の精神、私見が何であるかを実証しようとします.

戦略に関する主なことは、一般的な手順を持ち、その詳細 (動作) の一部を抽象化し、それらを透過的に変更できるようにすることです。

勾配降下最適化アルゴリズムを考えてみましょう。基本的には、次の 3 つのアクションで構成されます。

  • 勾配推定
  • ステップ
  • 目的関数の評価

通常、これらのステップのどれを抽象化して構成可能にする必要があるかを選択します。この例では、目的関数の評価は複数の方法で実行できるものではないようです。常に関数を評価するだけです。

したがって、これは 2 つの異なる戦略 (またはポリシー) ファミリーを導入します。

interface GradientStrategy
{
  double[] CalculateGradient(Function objectiveFunction, double[] point);
}

interface StepStrategy
{
  double[] Step(double[] gradient, double[] point);
}

もちろん、次のFunctionようなものです:

interface Function
{
  double Evaluate(double[] point);
}

interface FunctionWithDerivative : Function
{
  double[] EvaluateDerivative(double[] point);
}

次に、これらすべての戦略を使用するソルバーは次のようになります。

interface Solver
{
  double[] Maximize(Function objectiveFunction);
}

class GradientDescentSolver : Solver
{
  public Solver(GradientStrategy gs, StepStrategy ss)
  {
    this.gradientStrategy = gs;
    this.stepStrategy = ss;
  }

  public double[] Maximize(Function objectiveFunction)
  {
    // choosing starting point could also be abstracted into a strategy
    double[] currentPoint = ChooseStartingPoint(objectiveFunction);
    double[] bestPoint = currentPoint; 
    double bestValue = objectiveFunction.Evaluate(bestPoint);

    while (...) // termination condition could also 
                // be abstracted into a strategy
    {
      double[] gradient = this.gradientStrategy.CalculateGradient(
                            objectiveFunction,
                            currentPoint);

      currentPoint = this.stepStrategy.Step(gradient, currentPoint);

      double currentValue = objectiveFunction.Evaluate(currentPoint);

      if (currentValue > bestValue)
      {
        bestValue = currentValue;
        bestPoint = currentPoint;
      }
      else
      {
        // terminate or step back and reduce step size etc.
        // this could also be abstracted into a strategy
      }
    }

    return bestPoint;
  }

  private GradientStrategy gradientStrategy;
  private StepStrategy stepStrategy;
}

つまり、要点は、アルゴリズムの概要を把握し、このアルゴリズムの特定の一般的な手順を戦略またはポリシーに委任することです。(キャストダウン)GradientStrategyに対してのみ機能するものを実装し、関数の分析導関数を使用して勾配を取得することができます。FunctionWithDerivativeまたは、勾配推定の確率的バージョンを実装する別のものを用意することもできます。メイン ソルバは、勾配がどのように計算されているかを知る必要はなく、勾配だけが必要であることに注意してください。同じことが にも当てはまりますStepStrategy- これは、単一のステップ サイズを持つ典型的なステップ ポリシーである可能性があります。

class SimpleStepStrategy : StepStrategy
{
  public SimpleStepStrategy(double stepSize)
  { 
    this.stepSize = stepSize;
  }

  double[] Step(double[] gradient, double[] point)
  {
    double[] result = new double[point.Length];

    for (int i = 0;i < result.Length;++i)
    {
      result[i] = point[i] + this.stepSize * gradient[i]; 
    }

    return result;
  }

  private double stepSize;
}

、またはそれが進むにつれてステップサイズを調整する複雑なアルゴリズム。

また、コード内のコメントに記載されている動作についても考えてみてください: TerminationStrategy, DeteriorationPolicy.

名前は単なる例です。おそらく最適ではありませんが、意図を伝えてくれることを願っています。また、通常は 1 つのバージョン (戦略またはポリシー) に固執するのが最善です。

于 2013-09-01T08:03:09.927 に答える