2016-12-01 79 views
7

ait toplu işlem sürüm yapmak bir toplu işlem sürümNumpy: Dördey çarpma

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)) 

Bu fonksiyon şekli ile quaternion1 ve quaternion0 kolları için aşağıdaki fonksiyonu

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) 

dönüştürülmüş (4?). Şimdi, fonksiyonun (?,?, 4) gibi rastgele sayıları ele alabilmesini istiyorum. Bu nasıl yapılır?

cevap

2

Son eksene göre bölmek için axis-=-1'u np.split'a geçirerek yalnızca sonraki davranışı alabilirsiniz.

Ve diziler beri

, sadece axis=-1 tekrar (son) birlikte bunları arada kullanabilirsiniz can sıkıcı boyutu 1 ziyade, yeni bir boyut boyunca istifleme uzakta Şunu sıkma yerine, boyut sondaki buna sahip:

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) 
Bu yaklaşımla, sadece sen boyutların herhangi sayıda özdeş şekillendirilmiş Dördey yığınlarını çarpabilirsiniz,

Not:

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

Ama aynı zamanda size yani sağlayan güzel yayın olsunboyutları ile uğraşmaktan olmadan tek bir ile kuaterniyonların bir yığın çarpın:

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

Ya asgari işe yaramaz yapmak tek bir satırda iki yığınlar arasındaki tüm çapraz ürünler:

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

Son ekseni öne getirmek için np.rollaxis'dan faydalanabilirsiniz. Bu, 4 diziyi gerçekte bölmeden ayırmamıza yardımcı olur. Gerekli işlemleri gerçekleştiririz ve çıktı dizisi şeklini girişler ile aynı tutmak için nolu ilk ekseni arkaya göndeririz. Böylece, bu yüzden gibi jenerik n boyutlu ndarrays için bir çözüm olurdu -

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) 

Numune koşmak - Neredeyse geldin

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

Kendini kurtarabilecek Bir kopyayı, son boyutu ön tarafa getirmek için 'np.rollaxis' kullanmak yerine diziyi transpoze ederek. –

+0

@ali_m 'np.rollaxis' de görünüm oluşturmuyor mu? – Divakar

+0

Üzgünüm, haklısın (muhtemelen 'np.roll' ile karıştırıyordum). Transpose yine de biraz daha hızlı. –

1

! Biz geçen eksen boyunca bölünmüş ve ardından geçen eksen boyunca geri bitiştirmek için axis=-1 iki kere kullandığınız İşte

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) 

: Sadece nasıl bölmek ve dizinizi bitiştirmek ediyoruz konusunda biraz dikkatli olmak gerekir . Son olarak, doğru olarak gördüğünüz gibi, ikinci-son ekseni sıkıyoruz. Ve çalıştığını göstermek için:

>>> 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) 

Umut ne gerekli olduğunu! Bu, keyfi boyutlarda ve rastgele sayı boyutlarında çalışmalıdır.

Not:np.split listelerinde çalışmıyor. Böylece, yukarıda yaptığım gibi dizileri yalnızca yeni işlevinize geçirebilirsiniz. Listeleri iletebilmek istiyorsanız, işlevinizin yerine

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

'u arayabilirsiniz.

Ayrıca, sınamanız yanlış görünüyor. quaternion0 ve quaternion1 konumlarını değiştirdiğinizi düşünüyorum: Bunları q0 ve q1 test ederken yukarıda değiştirdim.