2016-12-01 5 views
7

私はバッチバージョンnumpyの:四元数の乗算のバッチバージョンを作る

def quat_multiply(self, quaternion0, quaternion1): 
    x0, y0, z0, w0 = np.split(quaternion0, 4, 1) 
    x1, y1, z1, w1 = np.split(quaternion1, 4, 1) 

    result = np.array((
     x1*w0 + y1*z0 - z1*y0 + w1*x0, 
     -x1*z0 + y1*w0 + z1*x0 + w1*y0, 
     x1*y0 - y1*x0 + z1*w0 + w1*z0, 
     -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=np.float64) 
    return np.transpose(np.squeeze(result)) 

この関数は(?、4)形状でquaternion1とquaternion0を扱うには、以下の機能

def quaternion_multiply(quaternion0, quaternion1): 
    """Return multiplication of two quaternions. 

    >>> q = quaternion_multiply([1, -2, 3, 4], [-5, 6, 7, 8]) 
    >>> numpy.allclose(q, [-44, -14, 48, 28]) 
    True 

    """ 
    x0, y0, z0, w0 = quaternion0 
    x1, y1, z1, w1 = quaternion1 
    return numpy.array((
     x1*w0 + y1*z0 - z1*y0 + w1*x0, 
     -x1*z0 + y1*w0 + z1*x0 + w1*y0, 
     x1*y0 - y1*x0 + z1*w0 + w1*z0, 
     -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=numpy.float64) 

を形質転換しました。今私は関数が(?、?、4)のような次元の任意の数を処理できるようにしたい。これを行う方法?

答えて

2

axis-=-1np.splitに最後の軸に沿って分割するだけで、後の動作を得ることができます。

そして、あなたの配列は、その後離れて1つを絞り、むしろ新たな次元に沿って積み重ねよりも、その迷惑なサイズ1末尾の寸法を有しているので、あなたは、単に再び(最後)axis=-1に沿って、それらを連結することができます

def quat_multiply(self, quaternion0, quaternion1): 
    x0, y0, z0, w0 = np.split(quaternion0, 4, axis=-1) 
    x1, y1, z1, w1 = np.split(quaternion1, 4, axis=-1) 
    return np.concatenate(
     (x1*w0 + y1*z0 - z1*y0 + w1*x0, 
     -x1*z0 + y1*w0 + z1*x0 + w1*y0, 
     x1*y0 - y1*x0 + z1*w0 + w1*z0, 
     -x1*x0 - y1*y0 - z1*z0 + w1*w0), 
     axis=-1) 
をこのアプローチでは、だけでなく、あなたが任意の次元数の同一形状四元スタックを掛けることができ、

注:

>>> a = np.random.rand(6, 5, 4) 
>>> b = np.random.rand(6, 5, 4) 
>>> quat_multiply(None, a, b).shape 
(6, 5, 4) 

しかし、あなたはまた、あなたは、IEすることができます素敵な放送を取得寸法をいじることなく、単一のものと四元数のスタックを掛け:

>>> a = np.random.rand(6, 5, 4) 
>>> b = np.random.rand(4) 
>>> quat_multiply(None, a, b).shape 
(6, 5, 4) 

または最小限いじるとは、単一の行に2つのスタック間のすべてのクロス製品の操作を行います。

>>> a = np.random.rand(6, 4) 
>>> b = np.random.rand(5, 4) 
>>> quat_multiply(None, a[:, None], b).shape 
(6, 5, 4) 
3

np.rollaxisを使用して最後の軸を前面に表示すると、4つの配列を実際に分割することなく分割するのに役立ちます。必要な操作を実行し、最後にを最初の軸に戻して出力配列の形状を入力と同じにします。したがって、我々はそうのように、一般的なn次元ndarraysのためのソリューションを持っているでしょう -

def quat_multiply_ndim(quaternion0, quaternion1): 
    x0, y0, z0, w0 = np.rollaxis(quaternion0, -1, 0) 
    x1, y1, z1, w1 = np.rollaxis(quaternion1, -1, 0) 
    result = np.array((
     x1*w0 + y1*z0 - z1*y0 + w1*x0, 
     -x1*z0 + y1*w0 + z1*x0 + w1*y0, 
     x1*y0 - y1*x0 + z1*w0 + w1*z0, 
     -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=np.float64) 
    return np.rollaxis(result,0, result.ndim) 

サンプル実行 - あなたはほとんどそこにいる

In [107]: # N-dim arrays 
    ...: a1 = np.random.randint(0,9,(2,3,2,4)) 
    ...: b1 = np.random.randint(0,9,(2,3,2,4)) 
    ...: 

In [108]: quat_multiply_ndim(a1,b1) # New ndim approach 
Out[108]: 
array([[[[ 154., 48., 55., -57.], 
     [ 31., 81., 29., -95.]], 

     [[ 31., 14., 88., 12.], 
     [ 3., 30., 20., -51.]], 

     [[ 104., 61., 102., -39.], 
     [ 0., 14., 14., -56.]]], 


     [[[ -28., 36., 24., -8.], 
     [ 11., 76., -7., -36.]], 

     [[ 54., 3., -2., -19.], 
     [ 52., 62., 15., -55.]], 

     [[ 76., 28., 28., -60.], <--------| 
     [ 14., 54., 13., 5.]]]])   | 
                | 
In [109]: quat_multiply(a1[1,2],b1[1,2]) # Old 2D approach 
Out[109]:           | 
array([[ 76., 28., 28., -60.], ------------------| 
     [ 14., 54., 13., 5.]]) 
+0

あなたは自分を救うことができます最後の次元を前面に持ってくるために 'np.rollaxis'を使うのではなく、配列を転置するだけでコピーを作成できます。 –

+0

@ali_m 'np.rollaxis'もビューを作成しませんか? – Divakar

+0

申し訳ありませんが、あなたは正しいです(私は恐らく 'np.roll'と混同していたでしょう)。しかし、Transposeはやや速いです。 –

1

! 、我々は最後の軸に沿って分割した後、最後の軸に沿って戻って連結するaxis=-1両方の時間を使っている。ここ

def quat_multiply(quaternion0, quaternion1): 
    x0, y0, z0, w0 = np.split(quaternion0, 4, axis=-1) 
    x1, y1, z1, w1 = np.split(quaternion1, 4, axis=-1) 

    return np.squeeze(np.stack((
     x1*w0 + y1*z0 - z1*y0 + w1*x0, 
     -x1*z0 + y1*w0 + z1*x0 + w1*y0, 
     x1*y0 - y1*x0 + z1*w0 + w1*z0, 
     -x1*x0 - y1*y0 - z1*z0 + w1*w0), axis=-1), axis=-2) 

:あなたはどのように分割すると、あなたの配列を連結しているについて少し注意する必要があります。最後に、正しく気づいたように、2番目から最後までの軸を絞ります。それが動作することを示すために:

>>> q0 = np.array([-5, 6, 7, 8]) 
>>> q1 = np.array([1, -2, 3, 4]) 
>>> q0 = np.tile(q1, (2, 2, 1)) 
>>> q0 
array([[[-5, 6, 7, 8], 
     [-5, 6, 7, 8]], 
     [[-5, 6, 7, 8], 
     [-5, 6, 7, 8]]]) 
>>> q1 = np.tile(q2, (2, 2, 1)) 
>>> q = quat_multiply(q0, q1) 
array([[[-44, -14, 48, 28], 
     [-44, -14, 48, 28]], 
     [[-44, -14, 48, 28], 
     [-44, -14, 48, 28]]]) 
>>> q.shape 
(2, 2, 4) 

あなたが必要としていることを望みます!これは、任意のディメンションと任意のディメンション数で機能するはずです。

注:np.splitはリストには表示されません。したがって、上で行ったように、配列を新しい関数に渡すことしかできません。リストを渡すことができるようにするには、代わりに

np.split(np.asarray(quaternion0), 4, -1) 

と呼んでください。

また、テストケースが間違っているようです。私はあなたがquaternion0quaternion1の位置を交換したと思う:私はq0q1をテストしている間にそれらを上に戻した。