# Multiply Quaternions

### 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]
```

Takes two lists `A,B`

in `[1,i,j,k]`

order and returns a result in the same format.

The key idea is that with `[1,i,j,k]`

corresponding to indices `[0,1,2,3]`

, you get the product's index (up to sign) by XOR'ing the indices. So, the terms that get placed in index `p`

are those who indices XOR to `p`

, and are thus the products `A[m]*B[m^p]`

.

It only remains to make the signs work out. The shortest way I found was to simply code them into a magic string. The 16 possibilities for `(m,p)`

are turned into numbers `0`

to `15`

as `p+4*m`

. The number `14672`

in binary has `1`

's at the places where `-1`

signs are needed. By shifting it the appropriate number of places , a `1`

or `0`

winds up at the last digit, making the number odd or even, and so `(-1)**`

is either `1`

or `-1`

as needed.

## CJam, ~~49~~ ~~45~~ 39 bytes

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

The above uses caret and M notation, since the code contains unprintable characters.

At the cost of two additional bytes, those characters can be avoided:

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

You can try this version online: CJam interpreter

### Test cases

To calculate `(a + bi + cj + dk) * (e + fi + gj + hk)`

, use the following input:

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

The output will be

```
[ z y x w ]
```

which corresponds to the quaternion `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]
```

### How it works

```
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. ";
```

## Python - ~~90 75 72~~ 69

**Pure Python, no libraries - 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]
```

It's probably pretty hard to shorten this "default" solution in Python. But I'm very curious as to what other might come up with. :)

**Using NumPy - 75 72 69:**

Well, since the input and output are rather flexible, we can use some NumPy functions and exploit the scalar-vector representation:

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

Input arguments `s`

and `t`

are the scalar parts of the two quaternions (the real parts) and `p`

and `q`

are the corresponding vector parts (the imaginary units). Output is a list containing scalar part and vector part of the resulting quaternion, the latter being represented as NumPy array.

**Simple test script:**

```
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(...)`

being the OP's reference implementation.)

Output:

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