2

アプリケーションでカスタム Matrix クラスを使用しており、複数の行列を頻繁に追加しています。

Matrix result = a + b + c + d; // a, b, c and d are also Matrices

ただし、これにより、加算操作ごとに中間行列が作成されます。これは単純な加算であるため、中間オブジェクトを回避し、4 つの行列すべての要素を一度に加算して結果を作成することができます。どうすればこれを達成できますか?

Add3Matrices(a, b, c)注: 、 などの複数の関数を定義できることはわかっていますがAdd4Matrices(a, b, c, d)、 の優雅さを維持したいと考えていresult = a + b + c + dます。

4

11 に答える 11

8

遅延評価を使用して、単一の小さな中間体に制限することができます。何かのようなもの

public class LazyMatrix
{
    public static implicit operator Matrix(LazyMatrix l)
    {
        Matrix m = new Matrix();
        foreach (Matrix x in l.Pending)
        {
            for (int i = 0; i < 2; ++i)
                for (int j = 0; j < 2; ++j)
                    m.Contents[i, j] += x.Contents[i, j];
        }

        return m;
    }

    public List<Matrix> Pending = new List<Matrix>();
}

public class Matrix
{
    public int[,] Contents = { { 0, 0 }, { 0, 0 } };

    public static LazyMatrix operator+(Matrix a, Matrix b)
    {
        LazyMatrix l = new LazyMatrix();
        l.Pending.Add(a);
        l.Pending.Add(b);
        return l;
    }

    public static LazyMatrix operator+(Matrix a, LazyMatrix b)
    {
        b.Pending.Add(a);
        return b;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Matrix a = new Matrix();
        Matrix b = new Matrix();
        Matrix c = new Matrix();
        Matrix d = new Matrix();

        a.Contents[0, 0] = 1;
        b.Contents[1, 0] = 4;
        c.Contents[0, 1] = 9;
        d.Contents[1, 1] = 16;

        Matrix m = a + b + c + d;

        for (int i = 0; i < 2; ++i)
        {
            for (int j = 0; j < 2; ++j)
            {
                System.Console.Write(m.Contents[i, j]);
                System.Console.Write("  ");
            }
            System.Console.WriteLine();
        }

        System.Console.ReadLine();
    }
}
于 2008-09-22T13:49:02.900 に答える
3

C ++では、テンプレートメタプログラムを使用できます。また、ここでは、テンプレートを使用してこれを正確に実行できます。ただし、テンプレートのプログラミングは簡単ではありません。同様の手法がC#で利用できるかどうかはわかりませんが、おそらくそうではありません。

このテクニックは、C ++で、あなたが望むことを正確に実行します。欠点は、何かが正しくない場合、コンパイラのエラーメッセージが数ページに及ぶ傾向があり、解読することがほとんど不可能であるということです。

そのようなテクニックがなければ、Add3Matricesなどの関数に制限されていると思います。

ただし、C#の場合、このリンクはまさに​​必要なものである可能性があります。C++テンプレート式とは少し異なる動作をするように見えますが、C#での効率的なマトリックスプログラミング。

于 2008-09-22T13:34:38.023 に答える
3

少なくともの痛みを回避する何か

Matrix Add3Matrices(a,b,c) //and so on 

だろう

Matrix AddMatrices(Matrix[] matrices)
于 2008-09-22T13:37:43.037 に答える
3

中間オブジェクトの作成は避けられません。

ただし、ここで説明する式テンプレートを使用して、それらを最小化し、テンプレートの派手な遅延評価を行うことができます。

最も単純なレベルでは、式テンプレートは、複数の行列への参照を格納し、割り当て時にAdd3Matrices()などの適切な関数を呼び出すオブジェクトである可能性があります。最も高度なレベルでは、式テンプレートは、要求に応じて怠惰な方法で最小量の情報を計算するなどのことを行います。

于 2008-09-22T13:40:42.953 に答える
2

これは最もクリーンな解決策ではありませんが、評価の順序がわかっている場合は、次のようにすることができます。

result = MatrixAdditionCollector() << a + b + c + d

(または別の名前の同じもの)。次に、MatrixCollector は + を += として実装します。つまり、未定義のサイズの 0 行列から開始し、最初の + が評価されるとサイズを取り、すべてを加算します (または、最初の行列をコピーします)。
これにより、中間オブジェクトの量が 1 に減少します ( MatrixCollectorがすぐに結果を含む/含む可能性があるため、適切な方法で代入を実装する場合は 0 になります)。より良いハック。特定の利点は、何が起こっているのかが明らかであることです。

于 2008-09-22T13:53:01.783 に答える
2

StringBuilder のように動作する MatrixAdder をお勧めします。マトリックスを MatrixAdder に追加してから、遅延実装で追加を行う ToMatrix() メソッドを呼び出します。これにより、必要な結果が得られ、あらゆる種類の LazyEvaluation に拡張できますが、コードの他のメンテナーを混乱させる可能性のある巧妙な実装も導入されません。

于 2008-09-22T14:09:18.360 に答える
2

必要なアドインプレース動作を明示的にするだけでよいと思いました。

Matrix result = a;
result += b;
result += c;
result += d;

しかし、この投稿のコメントで Doug が指摘したように、このコードはコンパイラによって、私が書いたかのように扱われます。

Matrix result = a;
result = result + b;
result = result + c;
result = result + d;

そのため、一時的なものは引き続き作成されます。

この回答を削除するだけですが、他の人も同じ誤解をしているようですので、これを反例と考えてください。

于 2008-09-22T14:01:38.097 に答える
1

Bjarne Stroustrup は、 Abstraction, libraries, and efficiency in C++という短い論文を発表しており、探しているものを実現するために使用される手法について言及しています。具体的には、科学計算用のライブラリであるBlitz++ライブラリや、行列の効率的な演算を行うライブラリ、およびその他の興味深いライブラリについて言及しています。また、artima.com で Bjarne Stroustrup との会話を読むことをお勧めします。

于 2008-09-22T14:30:22.740 に答える
0

演算子を使用することはできません。

于 2008-09-22T13:31:17.187 に答える
0

私の最初の解決策は、この行に沿ったものです(可能であれば Matrix クラスに追加するため):

static Matrix AddMatrices(Matrix[] lMatrices) // or List<Matrix> lMatrices
{
    // Check consistency of matrices

    Matrix m = new Matrix(n, p);

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            foreach (Maxtrix mat in lMatrices)
                m[i, j] += mat[i, j];

    return m;
}

マトリックスの実装が変更された場合に関数に役立つ可能性のあるプライベートメソッドとプロパティに依存できるため、マトリックスクラスでそれを持っていました(たとえば、大きな二重配列ではなく、空でないノードのリンクリスト)。

もちろん、 のエレガントさは失われresult = a + b + c + dます。しかし、あなたはの線に沿って何かを持っているでしょうresult = Matrix.AddMatrices(new Matrix[] { a, b, c, d });.

于 2008-09-22T14:00:58.677 に答える
0

これを実現するために遅延評価を実装する方法はいくつかあります。ただし、コンパイラが常に最適なコードを取得できるとは限らないことを覚えておくことが重要です。

私はすでに GCC でうまく機能する実装を作成しており、従来の複数の For unreadable コードのパフォーマンスに取って代わるものさえありました。これは、コンパイラがデータ セグメント間にエイリアスがないことを確認するように導くためです (どこにもない配列で把握するのが難しいもの)。しかし、それらのいくつかは MSVC で完全に失敗し、他の実装ではその逆でした。残念ながら、ここに投稿するには長すぎます (数千行のコードがここに収まるとは思わないでください)。

科学計算用の Blitz++ ライブラリは、この分野に組み込まれた優れた知識を備えた非常に複雑なライブラリです。

于 2008-09-30T12:29:05.107 に答える