私はいくつかの厄介なものに問題があります。コピーではなく、スライスしたデータのビューとしてスライスを返すことで、異常な動作をするためにnumpy配列が必要です。だからここに私がやりたいことの例があります:
次のような単純な配列があるとします。
a = array([1, 0, 0, 0])
次のような構文を使用して、配列内の連続するエントリを(左から右に移動して)配列からの前のエントリで更新したいと思います。
a[1:] = a[0:3]
これにより、次の結果が得られます。
a = array([1, 1, 1, 1])
またはこのようなもの:
a[1:] = 2*a[:3]
# a = [1,2,4,8]
さらに説明するために、次のような動作が必要です。
for i in range(len(a)):
if i == 0 or i+1 == len(a): continue
a[i+1] = a[i]
numpyのスピードが欲しい以外は。
numpyのデフォルトの動作はスライスのコピーを取得することなので、実際に取得するのは次のとおりです。
a = array([1, 1, 0, 0])
私はすでにこの配列をndarrayのサブクラスとして持っているので、必要に応じてさらに変更を加えることができます。左側のスライスを更新するときに、右側のスライスを継続的に更新する必要があります。
私は夢を見ていますか、それともこの魔法は可能ですか?
更新:これはすべて、ガウス・ザイデル反復を使用して線形代数の問題を多かれ少なかれ解決しようとしているためです。これは調和関数を含む特殊なケースです。これは本当に必要ではなく、さらに混乱する可能性があるため、これに入るのを避けようとしましたが、ここで説明します。
アルゴリズムは次のとおりです。
while not converged:
for i in range(len(u[:,0])):
for j in range(len(u[0,:])):
# skip over boundary entries, i,j == 0 or len(u)
u[i,j] = 0.25*(u[i-1,j] + u[i+1,j] + u[i, j-1] + u[i,j+1])
右?ただし、これは2つの方法で実行できます。Jacobiでは、whileループが循環するまでに既に行った更新を考慮せずに、各要素を隣接する要素で更新します。ループで実行するには、配列をコピーしてから、コピーした配列から1つの配列を更新します。ただし、Gauss-Seidelは、i-1およびj-1エントリごとに更新済みの情報を使用するため、コピーは必要ありません。単一要素の更新ごとに配列が再評価されるため、ループは基本的に「認識」する必要があります。 。つまり、u [i-1、j]やu [i、j-1]のようなエントリを呼び出すたびに、前のループで計算された情報がそこにあります。
この遅くて醜いネストされたループの状況を、numpyslicingを使用した1行のきれいなコードに置き換えたいと思います。
u[1:-1,1:-1] = 0.25(u[:-2,1:-1] + u[2:,1:-1] + u[1:-1,:-2] + u[1:-1,2:])
ただし、結果はJacobiの反復になります。これは、スライスを取得するときに:u [:、-2,1:-1]データをコピーするため、スライスは行われた更新を認識しないためです。今でもnumpyはループしますよね?並列ではなく、Pythonでの並列操作のように見えるループへのより高速な方法です。スライスを取得するときに、コピーではなくポインタを返すようにnumpyをハッキングすることで、この動作を利用したいと思います。右?その後、numpyがループするたびに、そのスライスは「更新」されるか、実際には更新で発生したものを複製します。これを行うには、配列の両側にあるスライスをポインターにする必要があります。
とにかく、本当に賢い人がそこにいるなら、それは素晴らしいですが、私はほとんど自分自身を辞任して、唯一の答えはCでループすることだと信じています。