Perkalian Quaternions


13

Tulis fungsi atau program bernama yang menghitung produk angka empat dari dua angka empat. Gunakan sesedikit mungkin byte.

Pertanyaan

Kuota adalah perpanjangan dari bilangan real yang selanjutnya memperluas bilangan kompleks. Daripada satu unit imajiner tunggal i, angka empat menggunakan tiga unit imajiner i,j,kyang memuaskan hubungan.

i*i = j*j = k*k = -1
i*j =  k
j*i = -k
j*k =  i
k*j = -i
k*i =  j
i*k = -j

(Ada juga tabel ini di halaman Wikipedia .)

Dalam kata-kata, setiap unit imajiner kuadratkan -1, dan produk dari dua unit imajiner yang berbeda adalah yang ketiga tersisa dengan +/-tergantung pada apakah urutan siklik (i,j,k)dihormati (yaitu, aturan tangan kanan ). Jadi, urutan perkalian penting.

Angka empat umum adalah kombinasi linear dari bagian nyata dan tiga unit imajiner. Jadi, ini dijelaskan oleh empat bilangan real (a,b,c,d).

x = a + b*i + c*j + d*k

Jadi, kita dapat mengalikan dua angka empat menggunakan properti distributif, berhati-hati untuk mengalikan unit dalam urutan yang benar, dan mengelompokkan istilah seperti dalam hasil.

(a + b*i + c*j + d*k) * (e + f*i + g*j + h*k)
= (a*e - b*f - c*g - d*h)    +
  (a*f + b*e + c*h - d*g)*i  +
  (a*g - b*h + c*e + d*f)*j  +
  (a*h + b*g - c*f + d*e)*k

Dilihat dengan cara ini, perkalian angka empat dapat dilihat sebagai peta dari sepasang 4-tupel menjadi 4-tupel tunggal, yang diminta untuk diterapkan.

Format

Anda harus menulis fungsi program atau bernama . Suatu program harus mengambil input dari STDIN dan mencetak hasilnya. Suatu fungsi harus menerima input fungsi dan mengembalikan (tidak mencetak) output.

Format input dan output fleksibel. Input adalah delapan bilangan real (koefisien untuk dua angka empat), dan output terdiri dari empat bilangan real. Input mungkin delapan angka, dua daftar empat angka, matriks 2x4, dll. Format input / output tidak harus sama. Pengurutan (1,i,j,k)koefisien terserah Anda.

Koefisien bisa negatif atau tidak keseluruhan. Jangan khawatir tentang ketepatan nyata atau meluap.

Dilarang: Fungsi atau tipe khusus untuk angka empat atau setara.

Uji kasus

Ini dalam (1,i,j,k)format koefisien.

[[12, 54, -2, 23], [1, 4, 6, -2]] 
 [-146, -32, 270, 331]

[[1, 4, 6, -2], [12, 54, -2, 23]] 
 [-146, 236, -130, -333]

[[3.5, 4.6, -0.24, 0], [2.1, -3, -4.3, -12]] 
 [20.118, 2.04, 39.646, -62.5]

Implementasi Referensi

Dalam Python, sebagai fungsi:

#Input quaternions: [a,b,c,d], [e,f,g,h]
#Coeff order: [1,i,j,k]

def mult(a,b,c,d,e,f,g,h):
    coeff_1 = a*e-b*f-c*g-d*h
    coeff_i = a*f+b*e+c*h-d*g
    coeff_j = a*g-b*h+c*e+d*f
    coeff_k = a*h+b*g-c*f+d*e

    result = [coeff_1, coeff_i, coeff_j, coeff_k]
    return result

Jawaban:


4

CJam, 49 45 39 byte

"cM-^\M-^G-^^KM-zP"256bGbq~m*f{=:*}4/{:-W*}/W*]`

Di atas menggunakan tanda caret dan M, karena kode mengandung karakter yang tidak patut.

Dengan mengorbankan dua byte tambahan, karakter tersebut dapat dihindari:

6Z9C8 7YDXE4BFA5U]q~m*f{=:*}4/{:-W*}/W*]`

Anda dapat mencoba versi ini secara online: Juru bahasa CJam

Uji kasus

Untuk menghitung (a + bi + cj + dk) * (e + fi + gj + hk), gunakan input berikut:

[ d c b a ] [ h g f e ]

Outputnya adalah

[ z y x w ]

yang sesuai dengan angka empat w + xi + yj + zk.

$ base64 -d > product.cjam <<< ImOchy0eS/pQIjI1NmJHYnF+bSpmez06Kn00L3s6LVcqfS9XKl1g
$ wc -c product.cjam
39 product.cjam
$ LANG=en_US cjam product.cjam <<< "[23 -2 54 12] [-2 6 4 1]"; echo
[331 270 -32 -146]
$ LANG=en_US cjam product.cjam <<< "[-2 6 4 1] [23 -2 54 12]"; echo
[-333 -130 236 -146]
$ LANG=en_US cjam product.cjam <<< "[0 -0.24 4.6 3.5] [-12 -4.3 -3 2.1]"; echo
[-62.5 39.646 2.04 20.118]

Bagaimana itu bekerja

6Z9C8 7YDXE4BFA5U]  " Push the array [ 6 3 9 12 8 7 2 13 1 14 4 11 15 10 5 0].         ";
q~                  " Read from STDIN and interpret the input.                         ";
m*                  " Compute the cartesian product of the input arrays.               ";
f                   " Execute the following for each element of the first array:       ";
{                   " Push the cartesian product (implicit).                           ";
    =               " Retrieve the corresponding pair of coefficients.                 ";
    :*              " Calculate their product.                                         ";
}                   "                                                                  ";
4/                  " Split into chunks of 4 elements.                                 ";
{:-W*}/             " For each, subtract the first element from the sum of the others. ";
W*                  " Multiply the last integers (coefficient of 1) by -1.             ";
]`                  " Collect the results into an array and stringify it.              ";

6

Python (83)

r=lambda A,B,R=range(4):[sum(A[m]*B[m^p]*(-1)**(14672>>p+4*m)for m in R)for p in R]

Mengambil dua daftar A,Bsecara [1,i,j,k]berurutan dan mengembalikan hasil dalam format yang sama.

Ide kuncinya adalah bahwa dengan [1,i,j,k]terkait dengan indeks [0,1,2,3], Anda mendapatkan indeks produk (hingga tanda tangan) dengan XOR'ing indeks. Jadi, istilah yang ditempatkan dalam indeks padalah mereka yang mengindeks XORp , dan dengan demikian produk A[m]*B[m^p].

Tinggal membuat tanda-tanda itu berhasil. Cara terpendek yang saya temukan adalah dengan hanya kode mereka menjadi string ajaib. 16 kemungkinan (m,p)berubah menjadi angka 0untuk 15sebagai p+4*m. Angka 14672dalam biner ada 1di tempat-tempat di mana -1tanda-tanda dibutuhkan. Dengan menggesernya jumlah tempat yang sesuai, a 1atau0 berakhir pada digit terakhir, membuat angka itu ganjil atau genap, dan demikian (-1)**juga salah satu 1atau -1sesuai kebutuhan.


Bagian XOR adalah jenius murni.
Dennis

3

Python - 90 75 72 69

Python Murni, tanpa perpustakaan - 90:

m=lambda a,b,c,d,e,f,g,h:[a*e-b*f-c*g-d*h,a*f+b*e+c*h-d*g,a*g-b*h+c*e+d*f,a*h+b*g-c*f+d*e]

Mungkin cukup sulit untuk mempersingkat solusi "default" ini dengan Python. Tapi saya sangat ingin tahu apa yang mungkin muncul dengan orang lain. :)


Menggunakan NumPy - 75 72 69:

Nah, karena input dan output agak fleksibel, kita dapat menggunakan beberapa fungsi NumPy dan mengeksploitasi representasi skalar-vektor :

import numpy
m=lambda s,p,t,q:[s*t-sum(p*q),s*q+t*p+numpy.cross(p,q)]

Masukan argumen sdan tmerupakan bagian skalar dari dua angka empat (bagian nyata) dan pdanq merupakan bagian vektor yang sesuai (unit imajiner). Output adalah daftar yang berisi bagian skalar dan bagian vektor dari angka empat yang dihasilkan, yang terakhir direpresentasikan sebagai array NumPy.

Skrip tes sederhana:

for i in range(5):
    a,b,c,d,e,f,g,h=np.random.randn(8)
    s,p,t,q=a, np.array([b, c, d]), e, np.array([f, g, h])
    print mult(a, b, c, d, e, f, g, h), "\n", m(s,p,t,q)

(mult(...) menjadi implementasi referensi OP.)

Keluaran:

[1.1564241702553644, 0.51859264077125156, 2.5839001110572792, 1.2010364098925583] 
[1.1564241702553644, array([ 0.51859264,  2.58390011,  1.20103641])]
[-1.8892934508324888, 1.5690229769129256, 3.5520713781125863, 1.455726589916204] 
[-1.889293450832489, array([ 1.56902298,  3.55207138,  1.45572659])]
[-0.72875976923685226, -0.69631848934167684, 0.77897519489219036, 1.4024428845608419] 
[-0.72875976923685226, array([-0.69631849,  0.77897519,  1.40244288])]
[-0.83690812141836401, -6.5476014589535243, 0.29693969165495304, 1.7810682337361325] 
[-0.8369081214183639, array([-6.54760146,  0.29693969,  1.78106823])]
[-1.1284033842268242, 1.4038096725834259, -0.12599103441714574, -0.5233468317643214] 
[-1.1284033842268244, array([ 1.40380967, -0.12599103, -0.52334683])]

2

Haskell, 85

m a b c d e f g h=[a*e-b*f-c*g-d*h,a*f+b*e+c*h-d*g,a*g-b*h+c*e+d*f,a*h+b*g-c*f+d*e]

Porting ke Haskell menyelamatkan kita beberapa karakter;)


2

Mathematica 83 50

Mungkin bisa bermain golf lagi ..

p = Permutations;
f = #1.(Join[{{1, 1, 1, 1}}, p[{-1, 1, -1, 1}][[1 ;; 3]]] p[#2][[{1, 8, 17, 24}]]) &

Spasi dan baris baru tidak dihitung & tidak diperlukan.

Pemakaian:

f[{a,b,c,d},{e,f,g,h}]        (* => {x,w,y,z}   *)


EDIT Cara kerjanya.

Fungsi Mathematica Permutationsmembuat semua kemungkinan permutasi #2(argumen kedua). Ada 24 permutasi, tapi kita hanya perlu {e,f,g,h}, {f,e,h,g}, {g,h,e,f}, dan {h,g,f,e}. Ini adalah permutasi pertama, 8, 17 dan 24. Jadi kodenya

p[#2][[{1,8,17,24}]]

tepatnya memilih ini dari permutasi argumen kedua dan mengembalikannya sebagai matriks. Tapi mereka belum memiliki tanda yang benar. Kode p[{-1,1,-1,1}][[1;;3]]mengembalikan matriks 3x4 dengan tanda yang benar. Kami menambahkannya dengan {1,1,1,1}menggunakanJoin , dan membuat perkalian normal (Times , atau seperti halnya di sini dengan hanya menulis satu sama lain) antara dua matriks membuat perkalian elemen demi elemen di Mathematica.

Akhirnya, hasil dari

(Join[{{1, 1, 1, 1}}, p[{-1, 1, -1, 1}][[1 ;; 3]]] p[#2][[{1, 8, 17, 24}]])

adalah matriks

 e  f  g  h
-f  e -h  g
-g  h  e -f
-h -g  f  e

Membuat perkalian matriks antara {a,b,c,d}(argumen pertama #1) dan matriks sebelumnya memberikan hasil yang diinginkan.



EDIT 2 Kode lebih pendek

Terinspirasi oleh kode Python dari Falko, saya membagi angka empat dalam skalar dan bagian vektor, dan menggunakan perintah built in Mathematica Crossuntuk menghitung produk silang dari bagian vektor:

f[a_, A_, b_, B_] := Join[{a*b - A.B}, a*B + b*A + Cross[A, B]]

Pemakaian:

f[a,{b,c,d},e,{f,g,h}]        (* => {x,w,y,z}   *)

Bisakah Anda menjelaskan cara kerjanya? Apa 1, 8, 17, 24?
xnor

1

Python, 94

Cara yang paling mudah tidak terlalu lama.

def m(a,b,c,d,e,f,g,h):return[a*e-b*f-c*g-d*h,a*f+b*e+c*h-d*g,a*g-b*h+c*e+d*f,a*h+b*g-c*f+d*e]

1

JavaScript ES6 - 86

f=(a,b,c,d,e,f,g,h)=>[a*e-b*f-c*g-d*h,a*f+b*e+c*h-d*g,a*g-b*h+c*e+d*f,a*h+b*g-c*f+d*e]

1

Lua - 99

Mungkin juga.

_,a,b,c,d,e,f,g,h=unpack(arg)print(a*e-b*f-c*g-d*h,a*f+b*e+c*h-d*g,a*g-b*h+c*e+d*f,a*h+b*g-c*f+d*e)

"Unpack ()" Lua membebaskan elemen tabel. Jadi tabel 'arg' adalah tempat semua input baris perintah disimpan (termasuk arg[0]yang merupakan nama file program, akan dibuang).


1

Python, 58 56 karakter

m=lambda x,y,z,w:(x*z-y*(2*w.real-w),x*w+y*(2*z.real-z))

Saya mengambil sangat menggunakan ruang gerak input / output format yang liberal. Input adalah 4 bilangan kompleks, yang dikodekan sebagai berikut:

x = a+b*i
y = c+d*i
z = e+f*i
w = g+h*i

Ini menghasilkan sepasang bilangan kompleks dalam format yang sama, yang pertama dari pasangan mengkode nyata dan ibagian, yang kedua mengkodej dan k.

Untuk melihat ini berfungsi, perhatikan bahwa angka empat pertama adalah x+y*jdan yang kedua adalah z+w*j. Cukup evaluasi (x+y*j)*(z+w*j)dan sadari bahwa j*t= conj(t)*juntuk nomor imajiner apa pun t.


Sangat pintar! Apakah Anda tahu mengapa angka empat tampaknya berlipat ganda seperti bilangan kompleks dengan koefisien kompleks, seperti yang terlihat dari ekspresi Anda?
xnor

Sudahlah, saya sekarang mengerti dari penjelasan Anda bagaimana idan jbertindak seperti koefisien kompleks dalam dan luar. Sangat menarik!
xnor

Sangat lucu bagaimana panggilan konjung mengambil lebih dari 2/5 dari karakter Anda. Saya pikir Anda dapat mencukur masing-masing menggunakan char (2*w.real-w). abs(w)**2/wakan bekerja tetapi untuk 0. Mungkin bahkan eksekutif dengan substitusi string akan sia-sia? `
xnor

1

Bisikan v2 , 396 byte

> 1
> 2
> 0
> 4
> Input
> Input
>> 6ᶠ2
>> 6ᵗ2
>> 7ⁿ3
>> 7ⁿ1
>> 10‖9
>> 8ⁿ3
>> 8ⁿ1
>> 13‖12
>> 7‖8
>> 11‖14
>> 8‖7
>> 14‖11
>> 15‖16
>> 19‖17
>> 20‖18
>> 4⋅5
>> L⋅R
>> Each 23 22 21
> [1,-1,-1,-1,1,1,1,-1,1,-1,1,1,1,1,-1,1]
>> Each 23 24 25
>> 26ᶠ4
>> 26ᵗ4
>> 28ᶠ4
> 8
>> 26ᵗ30
>> 31ᶠ4
>> 31ᵗ4
>> ∑27
>> ∑29
>> ∑32
>> ∑33
>> Output 34 35 36 37

Cobalah online!

Mengambil input dalam formulir

[a, b, c, d]
[e, f, g, h]

dan output sebagai

w
x
y
z

untuk mewakili q=w+xsaya+yj+zk

Struktur pohon dari jawaban ini adalah:

pohon

Sebagian besar jawaban ini berasal dari dua kesalahan utama di Whispers:

  • Tidak ada fungsi untuk membalikkan array
  • Penggunaan set dalam perhitungan produk Cartesian

Karena itu, kita dapat membagi kode menjadi 3 bagian.

Bagaimana itu bekerja

Kami akan menggunakan definisi berikut untuk kejelasan dan keringkasan:

q=Sebuah+bsaya+cj+dk
hal=e+fsaya+gj+hk
r=w+xsaya+yj+zk,(qhal=r)
SEBUAH=[Sebuah,b,c,d]
B=[e,f,g,h]
C=[w,x,y,z]

Bagian 1: Permuting SEBUAH dan B

Bagian pertama adalah yang terpanjang, membentang dari baris 1 ke baris 22 :

> 1
> 2
> 0
> 4
> Input
> Input
>> 6ᶠ2
>> 6ᵗ2
>> 7ⁿ3
>> 7ⁿ1
>> 10‖9
>> 8ⁿ3
>> 8ⁿ1
>> 13‖12
>> 7‖8
>> 11‖14
>> 8‖7
>> 14‖11
>> 15‖16
>> 19‖17
>> 20‖18
>> 4⋅5

Tujuan utama bagian ini adalah untuk mengubah urutan B sehingga perkalian elemen-bijaksana sederhana antara SEBUAH dan Badalah mungkin. Ada empat pengaturan berbedaB untuk melipatgandakan elemen SEBUAH dengan:

B1=[e,f,g,h]
B2=[f,e,h,g]
B3=[g,h,e,f]
B4=[h,g,f,e]

Input kedua, B, disimpan pada baris 6 . Kami kemudian berpisahB di tengah, karena setiap kemungkinan pengaturan Bdikelompokkan berpasangan. Untuk membalikkan pasangan ini (untuk mendapatkan pesanan yang benarB2 dan B4), kami mengambil elemen pertama dan terakhir, kemudian menggabungkannya dalam urutan terbalik:

>> 7ⁿ3
>> 7ⁿ1
>> 10‖9

(membentuk [f,e]) dan

>> 8ⁿ3
>> 8ⁿ1
>> 13‖12

(membentuk [h,g]). Kami sekarang memiliki semua bagian yang diperlukan untuk membentuk pengaturan, jadi kami menggabungkannya untuk membentukB1,B2,B3 dan B4. Akhirnya, kami menggabungkan empat pengaturan ini bersama untuk membentukBT. Kami kemudian dengan cepat membuatSEBUAHT, didefinisikan sebagai SEBUAH ulang 4 waktu:

SEBUAHT=[Sebuah,b,c,d,Sebuah,b,c,d,Sebuah,b,c,d,Sebuah,b,c,d]
BT=[e,f,g,h,f,e,h,g,g,h,e,f,h,g,f,e]

When each element of BT is multiplied by the corresponding element in AT, we get the (signless) values in qp

Section 2: Signs and products

As said in Section 1, the values in AT and BT correspond to the signless (i.e. positive) values of each of the coefficients in qp. No obvious pattern is found in the signs that would be shorter than simply hardcoding the array, so we hardcode the array:

> [1,-1,-1,-1,1,1,1,-1,1,-1,1,1,1,1,-1,1]

We'll call this array S (signs). Next, we zip together each element in AT,BT and S and take the product of each sub-array e.g. [[a,e,1],[b,f,1],,[e,f,1],[d,e,1]]D=[ae,bf,,ef,de].

Section 3: Partitions and final sums.

Once we have the array of coefficients of qp, with signs, we need to split it into 4 parts (i.e. the four factorised coefficients of qp), and then take the sums. This leads us to the only golfing opportunity found: moving the

> 4

to line 4 rather than 26, as it is used 6 times, each time saving a byte by moving it. Unfortunately, this costs a byte changing the 9 to a 10, so only 5 bytes are saved. The next section takes slices of size 4 from the front of D, saving each slice to the corresponding row and passing on the shortened list of D. Once 4 slices are taken, we the take the sum of each, before outputting them all.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.