12

さて、sympyオブジェクト(式)の多次元のnumpy配列がいくつかあります。例えば:

A = array([[1.0*cos(z0)**2 + 1.0, 1.0*cos(z0)],
          [1.0*cos(z0), 1.00000000000000]], dtype=object)

等々。

私がやりたいのは、einsumを使用してこれらの配列のいくつかを乗算することです。これは、以前に行っていた数値計算からその構文をすでに持っているためです。問題は、私が次のようなことをしようとすると

einsum('ik,jkim,j', A, B, C)

タイプエラーが発生します:

TypeError: invalid data type for einsum

確かに、グーグルで簡単に検索すると、einsumはおそらくこれを行うことができないことがわかりますが、理由はわかりません。特に、これらの配列でnumpy.dot()関数とnumpy.tensordot()関数を呼び出すと、魅力のように機能します。テンソルドットを使用して必要なことを行うことはできますが、上記のような50個ほどのアインテンの合計(インデックスの順序が非常に重要な場合)をネストされたテンソルドット呼び出しに置き換える必要があると考えると、脳が痛くなります。さらに悪夢のようなのは、そのコードをデバッグして、誤って配置された1つのインデックススワップを探す必要があるということです。

簡単に言えば、tensordotがオブジェクトで機能するのに、einsumが機能しない理由を誰かが知っていますか?回避策に向けた提案はありますか?そうでない場合は、ネストされたテンソルドット呼び出しに独自のラッパーを作成する方法について、einsum表記にいくらか似ています(文字ではなく数字で構いません)。

4

3 に答える 3

4

Einsumは基本的にtensordotに取って代わります(ドットは通常最適化された線形代数パッケージを使用しているため、ドットではありません)。コード的には完全に異なります。

これはオブジェクトeinsumで、テストされていません(より複雑なものの場合)が、機能するはずです... Cで同じことを行うと、実際のeinsum関数からループ自体以外のすべてを盗むことができるため、おそらくさらに簡単です。それで、あなたがそれのように感じるならば、それを実行して、より多くの人々を幸せにしてください...

https://gist.github.com/seberg/5236560

特に奇妙なコーナーケースについては、私は何も保証しません。もちろん、einsum表記をtensordot表記に変換することもできます。確かに、ループはほとんどCで終わるため、これはおそらく少し高速です...

于 2013-03-25T11:38:57.110 に答える
4

興味深いことに、追加optimize="optimal"は私のために働いた

einsum('ik,jkim,j', A, B, C)エラーが発生しますが

einsum('ik,jkim,j', A, B, C, optimize="optimal")sympyで完璧に動作します。

于 2021-02-28T13:55:00.233 に答える
2

einsumこれは、を複数のに分割するはるかに単純な実装ですtensordot

def einsum(string, *args):
    index_groups = map(list, string.split(','))
    assert len(index_groups) == len(args)
    tensor_indices_tuples = zip(index_groups, args)
    return reduce(einsum_for_two, tensor_indices_tuples)[1]

def einsum_for_two(tensor_indices1, tensor_indices2):
    string1, tensor1 = tensor_indices1
    string2, tensor2 = tensor_indices2
    sum_over_indices = set(string1).intersection(set(string2))
    new_string = string1 + string2
    axes = ([], [])
    for i in sum_over_indices:
        new_string.remove(i)
        new_string.remove(i)
        axes[0].append(string1.index(i))
        axes[1].append(string2.index(i))
    return new_string, np.tensordot(tensor1, tensor2, axes)

まずeinsum、(インデックス、テンソル)のタプルで引数を区切ります。次に、リストを次のように減らします。

  • 最初の2つのタプルを取得し、einsum_for_twoそれらの単純なものを評価します。また、新しいインデックス署名を出力します。
  • の値はeinsum_for_two、リスト内の次のタプルでの新しい引数として使用されeinsum_for_twoます。
  • タプルだけが残るまで続きます。インデックスの署名は破棄され、テンソルのみが返されます。

それはおそらく遅いです(しかしとにかくあなたは使用していますobject dtype)。入力に対して多くの正確性チェックを行いません。

@sebergが指摘したように、私のコードはテンソルの痕跡に対しては機能しません。

于 2013-03-25T16:26:59.807 に答える