Помножте кватерніони


13

Напишіть названу функцію або програму, яка обчислює добу кватерніона двох кватерніонів. Використовуйте якомога менше байтів.

Кватерніони

Кватерніони - це розширення дійсних чисел, що ще більше розширює складні числа. Замість однієї уявної одиниці 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

(На сторінці у Вікіпедії також є таблиці .)

Словом, кожна уявна одиниця -1складається з квадратів , а добуток двох різних уявних одиниць є рештою третьою, +/-залежно від того, чи (i,j,k)дотримується циклічний порядок (тобто правий правий ). Отже, порядок множення має значення.

Загальний кватерніон - це лінійна комбінація реальної частини та трьох уявних одиниць. Отже, це описується чотирма реальними числами (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-кортежів до одного-4-кортезів, що саме вам пропонується реалізувати.

Формат

Ви повинні написати або програму, або назву функції . Програма повинна брати дані STDIN і роздрукувати результат. Функція повинна приймати функціональні входи та повертати (не друкувати) вихід.

Формати введення та виведення є гнучкими. Вхід - вісім реальних чисел (коефіцієнти для двох кватерніонів), а вихід складається з чотирьох дійсних чисел. На вході можуть бути вісім чисел, два списки з чотирьох чисел, матриця 2x4 тощо. Формат вводу / виводу не повинен бути однаковим. Упорядкування (1,i,j,k)коефіцієнтів залежить від вас.

Коефіцієнти можуть бути негативними або не цілими. Не турбуйтеся про справжню точність або переливи.

Заборонено: функція або типи, спеціально для кватерніонів або еквівалентів.

Тестові справи

Вони у (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 interpreter

Тестові справи

Для розрахунку (a + bi + cj + dk) * (e + fi + gj + hk)використовуйте наступний вхід:

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

Вихід буде

[ z y x w ]

що відповідає кватерніону 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]

Як це працює

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

Пітон (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це ті, хто індексує XOR до p, і, таким чином, є продуктами A[m]*B[m^p].

Залишилося лише зробити так, щоб знаки спрацювали. Найкоротший спосіб, який я знайшов, - це просто закодувати їх у чарівну струну. У 16 можливостей для (m,p)перетворені в номери , 0щоб , 15як p+4*m. Число 14672у двійковій є 1в місцях, де -1потрібні знаки. Перемістивши відповідну кількість місць, a 1або 0закінчившись останньою цифрою, зробивши число непарним або парним, і так (-1)**є 1або -1необхідним.


Частина XOR - це чистий геній.
Денніс

3

Пітон - 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є відповідні векторні частини (уявні одиниці). Вихід - це список, що містить скалярну частину та векторну частину результуючого кватерніона, останній представляється як масив 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(...)що є еталонною реалізацією ОП.)

Вихід:

[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

Хаскелл, 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

Математика 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}   *)


EDIT Як це працює.

Функція 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) та колишньою матрицею дає бажаний результат.



EDIT 2 Коротший код

Натхнений кодом Пітона Фалько, я розділив кватерніон на скалярну та векторну частину і використовую вбудовану команду 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

Пітона, 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' зберігається все введення командного рядка (у тому числі, arg[0]яке ім'я файлу програми, воно відкидається).


1

Пітона, 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частини.

Щоб побачити це, зауважте, що перший кватерніон є, x+y*jа другий є z+w*j. Просто оцініть (x+y*j)*(z+w*j)і зрозумійте, що j*t= conj(t)*jдля будь-якого уявного числа t.


Дуже розумний! Чи знаєте ви, чому кватерніони здаються множитися як складні числа зі складними коефіцієнтами, як це випливає з вашого виразу?
xnor

Незважаючи на те, я тепер з вашого пояснення розумію, як iі як jдіють як внутрішні та зовнішні складні коефіцієнти. Як захоплююче!
xnor

Смішно, як виклики conj займають більше 2/5 ваших символів. Я думаю, що ти можеш поголити чарочку, використовуючи кожен (2*w.real-w). abs(w)**2/wбуде працювати, але за 0. Можливо, навіть виконувати з підстановкою рядків варто? `
xnor

1

Шепіт 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

Дерево структури цієї відповіді:

дерево

Хороший фрагмент цієї відповіді випливає з двох основних помилок у Шепіт:

  • Немає функції для повернення масиву
  • Використання множин для обчислення декартового продукту

Тому ми можемо розділити код на 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.