四元数相乘


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

(在Wikipedia页面上也有这些表格。)

换句话说,每个假想单位与平方-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

Answers:


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 + 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运算来获得产品的索引(最多为符号)。因此,放置在索引p中的术语是对XOR进行索引的那些,p因此也就是乘积A[m]*B[m^p]

剩下的只是使迹象变得可行。我发现的最短的方法是将它们简单地编码为魔术字符串。16种可能性(m,p)都变成了数字0,以15作为p+4*m14672二进制数在需要符号1的地方-1带有。通过将其移位适当的位数,a 10最后一位将结束,使该位数为奇数或偶数,因此根据需要(-1)**1-1


XOR部分是纯天才。
丹尼斯

3

蟒蛇-90 75 72 69

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

输入自变量st是两个四元数的标量部分(实部)和pq是对应的矢量部分(虚部)。输出是一个列表,其中包含所得四元数的标量部分和矢量部分,后者以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

哈斯克尔,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}通过使用JoinTimes在两个矩阵之间进行普通乘法(或在彼此之间逐个写法,在这里是这种情况)作为前缀,在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短代码

受Falko的Python代码启发,我将四元数分解为标量和矢量部分,并使用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 2014年

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

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

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

Lua的“ unpack()”释放表中的元素。因此,表“ arg”是所有命令行输入的存储位置(包括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部分,第二编码jk部件。

要查看此作品,请注意第一个四元数为x+y*j,第二个四元数为z+w*j。只要评估(x+y*j)*(z+w*j)并意识到j*t= conj(t)*j对于任何虚数t


非常聪明!您知道为什么四元数看起来像乘以复数的复数一样,从表达式中看吗?
xnor 2014年

没关系,我现在从你的解释如何理解ij像为内部和外部的复杂系数。多么迷人!
xnor 2014年

有趣的是,conj调用占用了超过2/5的字符。我认为您可以使用分别剃一个炭(2*w.real-w)abs(w)**2/w会工作,但为0。也许甚至用字符串替换的exec都值得吗?`
xnor 2014年

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

这个答案的结构树是:

树

这个答案的很大一部分来自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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.