ทวีคูณ Quaternions


13

เขียนฟังก์ชั่นที่มีชื่อหรือโปรแกรมที่คำนวณผลิตภัณฑ์ quaternion ของสอง quaternions ใช้น้อยที่สุดเท่าที่เป็นไปได้

quaternions

Quaternionsเป็นส่วนขยายของจำนวนจริงที่เพิ่มเติมขยายจำนวนเชิงซ้อน แทนที่จะเป็นหน่วยจินตภาพหน่วยเดียวiควอเทอร์เนียนใช้หน่วยจินตนาการสามหน่วยi,j,kที่สนองความสัมพันธ์

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

(นอกจากนี้ยังมีตารางเหล่านี้ในหน้า Wikipedia )

ในคำพูดหน่วยจินตภาพแต่ละหน่วยกำลังสอง-1และผลิตภัณฑ์ของหน่วยจินตภาพที่แตกต่างกันสองหน่วยคือหน่วยที่สามที่เหลือซึ่ง+/-ขึ้นอยู่กับว่ามีการปฏิบัติตามลำดับวงโคจรหรือ(i,j,k)ไม่ (เช่นกฎมือขวา ) ลำดับการคูณมีความสำคัญ

quaternion ทั่วไปเป็นการรวมกันเชิงเส้นของส่วนจริงและสามหน่วยจินตภาพ (a,b,c,d)ดังนั้นจึงมีการอธิบายโดยสี่ตัวเลขจริง

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

ดังนั้นเราสามารถคูณสองควอเทอร์เนียนโดยใช้สมบัติการกระจายระวังการคูณหน่วยในลำดับที่ถูกต้องและจัดกลุ่มเช่นคำศัพท์ในผลลัพธ์

(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

เห็นด้วยวิธีนี้การคูณแบบควอเทอเนียนสามารถดูเป็นแผนที่จากคู่ของ 4-tuples ไปเป็น 4-tuples เดียวซึ่งเป็นสิ่งที่คุณขอให้ติดตั้ง

รูปแบบ

คุณควรจะเขียนทั้งโปรแกรมหรือฟังก์ชั่นการตั้งชื่อ โปรแกรมควรรับอินพุตจาก STDIN และพิมพ์ผลลัพธ์ ฟังก์ชั่นควรใช้ในฟังก์ชั่นอินพุตและส่งคืน (ไม่พิมพ์) เอาต์พุต

รูปแบบอินพุตและเอาต์พุตมีความยืดหยุ่น อินพุตคือแปดจำนวนจริง (สัมประสิทธิ์สำหรับสองควอเทอร์เนียน) และเอาต์พุตประกอบด้วยตัวเลขจริงสี่ตัว อินพุตอาจเป็นตัวเลขแปดตัวรายการสองตัวในสี่ตัวเมทริกซ์ 2x4 เป็นต้นรูปแบบอินพุต / เอาต์พุตไม่จำเป็นต้องเหมือนกันการเรียงลำดับ(1,i,j,k)สัมประสิทธิ์ขึ้นอยู่กับคุณ

สัมประสิทธิ์สามารถเป็นลบหรือไม่ทั้งหมดก็ได้ ไม่ต้องกังวลกับความแม่นยำหรือล้นเกินจริง

ถูกแบน:ฟังก์ชั่นหรือประเภทเฉพาะสำหรับ quaternions หรือเทียบเท่า

กรณีทดสอบ

เหล่านี้อยู่ใน(1,i,j,k)รูปแบบค่าสัมประสิทธิ์

[[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]

การดำเนินการอ้างอิง

ใน Python เป็นฟังก์ชัน:

#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

คำตอบ:


4

CJam, 49 45 39 ไบต์

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

ด้านบนใช้เครื่องหมายรูปหมวกและ M เนื่องจากรหัสมีอักขระที่ไม่สามารถพิมพ์ได้

ด้วยค่าใช้จ่ายเพิ่มเติมสองไบต์อักขระเหล่านั้นสามารถหลีกเลี่ยงได้:

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

คุณสามารถลองรุ่นออนไลน์นี้ได้: ล่าม CJam

กรณีทดสอบ

ในการคำนวณ(a + bi + cj + dk) * (e + fi + gj + hk)ให้ใช้อินพุตต่อไปนี้:

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

ผลลัพธ์จะเป็น

[ z y x w ]

ซึ่งสอดคล้องกับ w + xi + yj + zkquaternion

$ 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]

มันทำงานอย่างไร

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]

ใช้เวลาสองรายการA,Bใน[1,i,j,k]การสั่งซื้อและผลตอบแทนในรูปแบบเดียวกัน

แนวคิดหลักคือด้วย[1,i,j,k]ดัชนีที่สอดคล้องกัน[0,1,2,3]คุณจะได้รับดัชนีของผลิตภัณฑ์ (ลงนาม) โดย XOR'ing ดัชนี ดังนั้นข้อตกลงที่ได้รับการวางไว้ในดัชนีpผู้ที่ดัชนีจะแฮคเกอร์และจึงผลิตภัณฑ์pA[m]*B[m^p]

มันยังคงอยู่เพียงเพื่อให้สัญญาณทำงาน วิธีที่สั้นที่สุดที่ฉันพบคือการเขียนโค้ดลงในสตริงมายากล 16 เป็นไปได้สำหรับ(m,p)จะกลายเป็นตัวเลข0ที่จะเป็น15 p+4*mตัวเลข14672ในเลขฐานสองมี1อยู่ในสถานที่ที่-1จำเป็นต้องใช้สัญญาณ ด้วยการเลื่อนจำนวนสถานที่ที่เหมาะสมให้มากขึ้น1หรือ0หมุนไปตามหลักสุดท้ายทำให้เป็นเลขคี่หรือคู่และ(-1)**เป็นเช่นนั้น1หรือ-1ตามความจำเป็น


ส่วน XOR เป็นอัจฉริยะบริสุทธิ์
เดนนิส

3

Python - 90 75 72 69

Pure Python ไม่มีไลบรารี่ - 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]

อาจเป็นเรื่องยากที่จะตัดทอน "ค่าเริ่มต้น" ใน Python ให้สั้นลง แต่ฉันอยากรู้ว่าสิ่งที่คนอื่นอาจเกิดขึ้น :)


ใช้ NumPy - 75 72 69:

เนื่องจากอินพุตและเอาต์พุตค่อนข้างยืดหยุ่นเราจึงสามารถใช้ฟังก์ชัน NumPy และใช้ประโยชน์จากการนำเสนอแบบสเกลาร์ - เวกเตอร์ :

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

อาร์กิวเมนต์ที่ป้อนเข้าsและtเป็นส่วนเซนต์คิตส์และเนวิสของทั้งสอง (ส่วนจริง) และpและqเป็นเวกเตอร์ที่สอดคล้องกัน (หน่วยจินตภาพ) เอาท์พุทเป็นรายการที่มีส่วนสเกลาร์และส่วนเวกเตอร์ของผล quaternion หลังถูกแสดงเป็นอาร์เรย์ NumPy

สคริปต์ทดสอบอย่างง่าย:

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(...)เป็นการนำมาใช้อ้างอิงของ OP)

เอาท์พุท:

[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]

การย้ายไปที่ Haskell ช่วยเราประหยัดไม่กี่ตัวอักษร;)


2

Mathematica 83 50

อาจจะสามารถเล่นกอล์ฟได้มากกว่านี้ ..

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

ช่องว่างและบรรทัดใหม่ไม่นับ & ไม่จำเป็น

การใช้งาน:

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


แก้ไข มันทำงานอย่างไร

ฟังก์ชัน Mathematica Permutationsสร้างการเรียงสับเปลี่ยนที่เป็นไปได้ทั้งหมด#2(อาร์กิวเมนต์ที่สอง) มี 24 พีชคณิตมี แต่เราต้องการเพียง{e,f,g,h}, {f,e,h,g}, และ{g,h,e,f} {h,g,f,e}นี่คือการเปลี่ยนลำดับครั้งแรก, 8, 17 และ 24 ดังนั้นรหัส

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

เลือกสิ่งเหล่านี้อย่างแน่นอนจากการเรียงสับเปลี่ยนของอาร์กิวเมนต์ที่สองและส่งกลับเป็นเมทริกซ์ แต่พวกเขายังไม่มีสัญญาณที่ถูกต้อง รหัสp[{-1,1,-1,1}][[1;;3]]ส่งกลับเมทริกซ์ 3x4 พร้อมเครื่องหมายถูก เราเติมมัน{1,1,1,1}โดยใช้Joinและทำการคูณปกติ ( Timesหรือเป็นกรณีที่นี่โดยเพียงแค่เขียนพวกมันหลังจากกัน) ระหว่างสองเมทริกซ์ทำให้การคูณองค์ประกอบโดยองค์ประกอบใน Mathematica

ดังนั้นในที่สุดผลลัพธ์ของ

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

คือเมทริกซ์

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

การคูณเมทริกซ์ระหว่าง{a,b,c,d}(อาร์กิวเมนต์แรก#1) กับเมทริกซ์เดิมให้ผลลัพธ์ที่ต้องการ



แก้ไข 2รหัสสั้นกว่า

แรงบันดาลใจจากรหัส Python ของ Falko ฉันแบ่ง quaternion ในสเกลาร์และส่วนเวกเตอร์และใช้คำสั่งของ Mathematica ในCrossการคำนวณผลคูณไขว้ของส่วนเวกเตอร์:

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

การใช้งาน:

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

คุณอธิบายได้ไหมว่ามันทำงานอย่างไร อะไรนะ1, 8, 17, 24?
xnor

1

Python, 94

วิธีที่ตรงไปตรงมาที่สุดไม่นานเกินไป

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

ลัวะ - 99

อาจจะเช่นกัน

_,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 ทำให้องค์ประกอบของตารางเป็นอิสระ ดังนั้นตาราง 'หาเรื่อง' จึงเป็นที่เก็บอินพุตบรรทัดคำสั่งทั้งหมด (รวมถึงarg[0]ชื่อไฟล์ของโปรแกรมซึ่งจะถูกทิ้ง)


1

Python 58 56 ตัวอักษร

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

ฉันใช้รูปแบบอินพุต / เอาท์พุตแบบเสรีมาก อินพุตมีจำนวนเชิงซ้อน 4 ตัวจึงเข้ารหัส:

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

มันส่งออกตัวเลขที่ซับซ้อนในรูปแบบที่คล้ายกันคู่แรกเข้ารหัสส่วนที่แท้จริงและiส่วนที่สองเข้ารหัสjและkชิ้นส่วน

หากต้องการดูผลงานนี้ทราบว่า quaternion แรกคือและที่สองคือx+y*j z+w*jเพียงแค่การประเมิน(x+y*j)*(z+w*j)และตระหนักดีว่าj*t= จำนวนจินตนาการใดconj(t)*jt


ฉลาดมาก! คุณรู้หรือไม่ว่าเหตุใดควอเทอร์ชันจึงดูเหมือนเป็นจำนวนเชิงซ้อนที่มีค่าสัมประสิทธิ์ซับซ้อนเท่าที่ดูจากการแสดงออกของคุณ?
xnor

ไม่เป็นไรตอนนี้ฉันเข้าใจจากคำอธิบายของคุณว่าiและjทำตัวเป็นสัมประสิทธิ์ความซับซ้อนภายในและภายนอกอย่างไร น่าทึ่งมาก!
xnor

มันตลกที่การโทร conj ใช้เวลามากกว่า 2/5 ของตัวอักษรของคุณ (2*w.real-w)ฉันคิดว่าคุณสามารถโกนถ่านแต่ละใช้ abs(w)**2/wจะทำงาน แต่สำหรับ 0 บางทีแม้กระทั่ง exec ด้วยการแทนที่สตริงจะคุ้มค่าหรือไม่ `
xnor

1

Whispers v2 , 396 ไบต์

> 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

ลองออนไลน์!

รับอินพุตในแบบฟอร์ม

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

และเอาท์พุทเป็น

w
x
y
z

q=w+xi+yj+zk

แผนผังโครงสร้างของคำตอบนี้คือ:

ต้นไม้

อันดีของคำตอบนี้มาจากความผิดพลาดหลักสองประการใน Whispers:

  • ไม่มีฟังก์ชั่นในการย้อนกลับอาร์เรย์
  • การใช้ชุดในการคำนวณของผลิตภัณฑ์คาร์ทีเซียน

ดังนั้นเราสามารถแบ่งรหัสออกเป็น 3 ส่วน

มันทำงานอย่างไร

เราจะใช้คำจำกัดความต่อไปนี้เพื่อความชัดเจนและรัดกุม:

q=a+bi+cj+dk
p=e+fi+gj+hk
r=w+xi+yj+zk,(qp=r)
A=[a,b,c,d]
B=[e,f,g,h]
C=[w,x,y,z]

AB

ส่วนแรกยาวที่สุดโดยขยายจากบรรทัด1ถึงบรรทัด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

BABBA

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

BBBB2B4

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

[f,e]

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

[h,g]B1,B2,B3B4BTATA4

AT=[a,b,c,d,a,b,c,d,a,b,c,d,a,b,c,d]
BT=[e,f,g,h,f,e,h,g,g,h,e,f,h,g,f,e]

BTATqp

ส่วนที่ 2: สัญญาณและผลิตภัณฑ์

ATBTqp

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

SAT,BTS[[a,e,1],[b,f,1],,[e,f,1],[d,e,1]]D=[ae,bf,,ef,de]

ส่วนที่ 3: พาร์ทิชันและเงินก้อนสุดท้าย

qpqp

> 4

54DD

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.