18
\$\begingroup\$

The cross product is a peculiarly 3-dimensional phenomenon. There are multiple ways of generalizing it, but each of them have trade offs.

If you require that a cross product be a product of two vectors \$\mathbf{v}_1\times\mathbf{v}_2\$ such that it is:

  • linear, \$a\mathbf{v}_1\times\mathbf{v}_2 = a\left(\mathbf{v}_1\times\mathbf{v}_2\right)\$ and \$\left(\mathbf v_1+\mathbf v_2\right)\times\mathbf v_3 = \left(\mathbf v_1\times\mathbf v_3\right)+\left(\mathbf v_2\times\mathbf v_3\right)\$
  • anticommutative, \$\left(\mathbf{v}_1\times\mathbf{v}_2\right) + \left(\mathbf{v}_2\times\mathbf{v}_1\right) = \mathbf{0}\$
  • orthogonal, \$\left(\mathbf{v}_1\times\mathbf{v}_2\right)\cdot\mathbf v_1 = \mathbf 0\$
  • not everywhere zero

Then there are two dimensions that have cross products:

  • There is the ordinary cross product in 3D.
  • There is also a cross product in 7D.

Today our challenge is to implement this 7-dimensional cross product.

Definition

Although the above is a technically unambiguous challenge specification, I will give a complete definition of a 7D cross product here which you can readily implement as an algorithm.

In order to determine the cross product of two vectors you only need to know the behavior on the basis vectors. You can write each vector as a combination of basis vectors, e.g.

\$ \left[a,b,c,d,e,f,g\right]^\top = a\mathbf e_1 + b\mathbf e_2 + c\mathbf e_3 + d\mathbf e_4 + e\mathbf e_5 + f\mathbf e_6 + g\mathbf e_7 \$

Since the product is linear you can distribute until any cross product is written as the sum of products of basis vectors. For example here's a 3D case:

\begin{align} \left[a,b,c\right]^\top\times\left[x,y,z\right]^\top &= \left(a\mathbf e_1 + b\mathbf e_2 + c\mathbf e_3\right)\times\left(x\mathbf e_1 + y\mathbf e_2 + z\mathbf e_3\right) \\ &= \begin{matrix}& ax\left(e_1\times e_1\right) &+& bx\left(e_2\times e_1\right) &+& cx\left(e_3\times e_1\right) \\+& ay\left(e_1\times e_2\right) &+& by\left(e_2\times e_2\right) &+& cy\left(e_3\times e_2\right) \\+& az\left(e_1\times e_3\right) &+& bz\left(e_2\times e_3\right) &+& cy\left(e_3\times e_3\right)\end{matrix} \end{align}

Then for the product of basis vectors you can use the following product table:

×ばつ \$\mathbf e_1\$ \$\mathbf e_2\$ \$\mathbf e_3\$ \$\mathbf e_4\$ \$\mathbf e_5\$ \$\mathbf e_6\$ \$\mathbf e_7\$
\$\mathbf e_1\$ 0 \$\mathbf e_3\$ \$-\mathbf e_2\$ \$\mathbf e_5\$ \$-\mathbf e_4\$ \$-\mathbf e_7\$ \$\mathbf e_6\$
\$\mathbf e_2\$ \$-\mathbf e_3\$ 0 \$\mathbf e_1\$ \$\mathbf e_6\$ \$\mathbf e_7\$ \$-\mathbf e_4\$ \$-\mathbf e_5\$
\$\mathbf e_3\$ \$\mathbf e_2\$ \$-\mathbf e_1\$ 0 \$\mathbf e_7\$ \$-\mathbf e_6\$ \$\mathbf e_5\$ \$-\mathbf e_4\$
\$\mathbf e_4\$ \$-\mathbf e_5\$ \$-\mathbf e_6\$ \$-\mathbf e_7\$ 0 \$\mathbf e_1\$ \$\mathbf e_2\$ \$\mathbf e_3\$
\$\mathbf e_5\$ \$\mathbf e_4\$ \$-\mathbf e_7\$ \$\mathbf e_6\$ \$-\mathbf e_1\$ 0 \$-\mathbf e_3\$ \$\mathbf e_2\$
\$\mathbf e_6\$ \$\mathbf e_7\$ \$\mathbf e_4\$ \$-\mathbf e_5\$ \$-\mathbf e_2\$ \$\mathbf e_3\$ 0 \$-\mathbf e_1\$
\$\mathbf e_7\$ \$-\mathbf e_6\$ \$\mathbf e_5\$ \$\mathbf e_4\$ \$-\mathbf e_3\$ \$-\mathbf e_2\$ \$\mathbf e_1\$ 0

Rules

This is so the goal is to minimize the size of your source code as measured in bytes.

You should take input as two seven-dimensional vectors. You should output one seven-dimensional vector in the same format. You may approximate real numbers in any reasonable manner.

You may choose to take input in a way that permutes the basis vectors or multiply the result by -1, so long as it satisfies the definition of the cross product above.

Test cases

The table above provides 49 basic test cases. In addition I suggest you test the two linearity properties with random vectors. If your product is bilinear and satisfies the multiplication table above then it must be correct.

That is:

  • Take two random vectors and two random real numbers and test that \$a\mathbf{v}_1\times b\mathbf{v}_2 = ab\left(\mathbf{v}_1\times\mathbf{v}_2\right)\$
  • Take 3 random vectors and test that \$\left(\mathbf v_1+\mathbf v_2\right)\times\mathbf v_3 = \left(\mathbf v_1\times\mathbf v_3\right)+\left(\mathbf v_2\times\mathbf v_3\right)\$
asked Jul 28 at 15:30
\$\endgroup\$
6
  • \$\begingroup\$ "Although the above is technically unambiguous, I will give a complete definition of the 7D cross product here which you can readily implement as an algorithm." << This seems to be in contradiction with the wikipedia page, which if I understand it correctly, tells me that there can be many choices of seven-dimensional cross-product? \$\endgroup\$ Commented Jul 29 at 7:56
  • \$\begingroup\$ @Stef The constraints are an unambiguous challenge, not a definition of the cross product. The point of this sentence is "ok I've technically given the challenge, but here's a solution you can use". And likewise I'm not trying to say that permutations are exhaustive, just that they are one way to get more products. I've tried tweaking the wording a bit, let me know if there's something else you think could be changed, or feel free to edit the question directly. \$\endgroup\$ Commented Jul 29 at 12:04
  • \$\begingroup\$ can output be 15-dimensional vector (codegolf.stackexchange.com/a/282853)? \$\endgroup\$ Commented Jul 30 at 2:32
  • 2
    \$\begingroup\$ @Lucenaposition Mathematically speaking, the condition for orthogonality requires the output of the cross product operation to have the same dimensionality as the inputs. And it doesn't look like there's anything in the challenge statement that allowed a 15-component output to be interpreted as a 7-dimensional mathematical vector (say, by dropping components or some such thing), but I'm not the authority.... \$\endgroup\$ Commented Jul 30 at 22:11
  • \$\begingroup\$ @Stef In 3-d the properties above don't define the cross product uniquely, there is still a sign ambiguity. In 7-d you only need the cross product to be orthogonal to the 2 input vectors, which still gives you a 5-d space to choose from. But up to that choice, the cross products are all the same. So the multiplication table chooses a particular realization but all realizations are equivalent. \$\endgroup\$ Commented Jul 31 at 8:46

7 Answers 7

14
\$\begingroup\$

JavaScript (ES6), 83 bytes

Expects (u)(v).

u=>v=>[0,1,2,4].reduce((p,i)=>p.map(n=>i&&n+u[i%=7]*v[j%=7]-u[j++]*v[i++],j=i*3),u)

Try it online!

Commented

u => // u[] = first vector
v => // v[] = second vector
[0, 1, 2, 4] // lookup list
.reduce((p, i) => // for each value i with p[] as the accumulator:
 p.map(n => // for each value n in p[]:
 i && // force to zero if i = 0
 n + // otherwise, take the current value n
 u[i %= 7] * // and add u[i] * v[j] - u[j] * v[i]
 v[j %= 7] - // where both i and j are reduced modulo 7
 u[j++] * // and incremented afterwards
 v[i++], //
 j = i * 3 // start with j = i * 3, which gives (modulo 7):
 // (i,j) = (1,3), (2,6), (4,5)
 ), // end of map()
 u // start with p[] = u[] (but the content of p[]
 // is cleared on the first iteration)
) // end of reduce()
answered Jul 28 at 17:10
\$\endgroup\$
7
\$\begingroup\$

Wolfram Language (Mathematica), 62 bytes

s&@Do[s[[t]]+=#[[t=Mod[i+{0,1,3},7,1]]]#2[[t]],{i,s=0#;7}]&

-1 bytes thanks to @att.

Try it online!

(\[Cross], unicode U+F4A0) is a special character in Mathematica that represents cross product.

First initialize the result \$\mathbf{s}\$ to a zero vector of length 7. And then:

  • \$(s_1, s_2, s_4) \leftarrow (s_1, s_2, s_4) + (a_1, a_2, a_4) \times (b_1, b_2, b_4)\$ (where \$\times\$ is the 3D cross product);
  • \$(s_2, s_3, s_5) \leftarrow (s_2, s_3, s_5) + (a_2, a_3, a_5) \times (b_2, b_3, b_5)\$;
  • \$\ldots\ldots\$
  • \$(s_7, s_1, s_3) \leftarrow (s_7, s_1, s_3) + (a_7, a_1, a_3) \times (b_7, b_1, b_3)\$.

Now \$\mathbf{s}\$ becomes the 7D cross product of \$\mathbf{a}\$ and \$\mathbf{b}\$.

answered Jul 29 at 3:55
\$\endgroup\$
3
  • 1
    \$\begingroup\$ -1 byte \$\endgroup\$ Commented Jul 29 at 11:33
  • \$\begingroup\$ Does Mathematica have a build in Octonian multiplication that one could use (even if it is not shorter)? \$\endgroup\$ Commented Jul 31 at 8:48
  • \$\begingroup\$ @quarague There are some 3rd-party packages for that, but there isn't a built-in. \$\endgroup\$ Commented Jul 31 at 9:52
5
\$\begingroup\$

Maple, (削除) 187 (削除ここまで) 176 bytes

(s,t)->eval(s^+.Matrix([[],[-e3],[e2,-e1],[-e5,-e6,-e7],[e4,-e7,e6,-e1],[e7,e4,-e5,-e2,e3],[-e6,e5,e4,-e3,-e2,e1,0]],shape=antisymmetric).t,{seq(e||i=Vector(7,{i=1}),i=1..7)});

If the two vectors are s and t, and Q is the multiplication table as a matrix, then the result in the form a*e1+b*e2+... is sT.Q.t. Then substitute e1, e2 etc with the unit vectors [1,0,0,0,0,0,0]T, [0,1,0,0,0,0,0]T etc. to get the final result.

answered Jul 28 at 22:46
\$\endgroup\$
5
\$\begingroup\$

PARI/GP, 74 bytes

f(a,b)=[sum(n=0,2,a[u=(i+2^n)%7+1]*b[v=(i+3<<n)%7+1]-b[u]*a[v])|i<-[0..6]]

Attempt This Online!

A port of Arnauld's JavaScript solution.


PARI/GP, 97 bytes

f(a,b)=Vecrev(sum(t=0,6,matdet([x^t,x^u=t++%7,x^v=(t+2)%7;a[t],a[u++],a[v++];b[t],b[u],b[v]])),7)

Attempt This Online!

Using the algorithm in my Mathematica answer.

answered Jul 29 at 3:38
\$\endgroup\$
5
\$\begingroup\$

Charcoal, (削除) 63 (削除ここまで) 35 bytes

×ばつ⎇&λ⊖λ§θ−ιλ±§θ+μλ§ημ

Try it online! Link is to verbose version of code. No test suite because that requires renaming the variables. Explanation: Uses the C(+) octonion multiplication table that I found here (warning: no SSL available).

 7 Literal integer `7`
 E Map over implicit range
 7 Literal integer `7`
 E Map over implicit range
 μ Inner index
 − Subtract
 ι Outer value
 % Modulo
 7 Literal integer `7`
 ⊗ Doubled
 E Map over values
 λ Inner value
 ∧ Logical And
 λ Inner value
 & Bitwise And
 λ Inner value
 ⊖ Decremented
 ⎇ If true then
 θ First input
 § Cyclically indexed by
 ι Outer value
 − Subtract
 λ Inner value
 θ Else first input
 § Cyclically indexed by
 μ Inner index
 + Plus
 λ Inner value
 ± Negated
 ×ばつ Multiplied by
 η Second input
 § Indexed by
 μ Inner index
 Σ Take the sum
I Cast to string
 Implicitly print
answered Jul 29 at 7:42
\$\endgroup\$
3
\$\begingroup\$

Python 2, (削除) 165 (削除ここまで) 146 bytes

def g(x,y):
 x*=2;y*=2;z=[0]*10;p,q,r=0,1,3
 for a in range(7)*3:p,q,r=q,r,p;z[a+p]+=x[a+q]*y[a+r]-x[a+r]*y[a+q]
 exec'print sum(z[p::7]);p+=1;'*7

Attempt This Online!

Changed my approach completely.

This is now a port of Seven-dimensional cross product.

Prints output to stdout.

answered Jul 30 at 0:28
\$\endgroup\$
1
\$\begingroup\$

Jelly, 28 bytes

ṙJ$(Ç¢œ?N5ẒƇ¤¦_W{JœṖ"$ZṚẎŒḌḋ

A dyadic Link that accepts \$\mathbf v_1\$ on the left and \$\mathbf v_2\$ on the right and yields \$\mathbf v_1\times\mathbf v_2\$

Try it online!

  • See the orthonormal multiplication table.
  • See two random vectors and two random scalars satisfying \$a\mathbf{v}_1\times b\mathbf{v}_2 = ab\left(\mathbf{v}_1\times\mathbf{v}_2\right)\$ here.
  • See three random vectors satisfying \$\left(\mathbf v_1+\mathbf v_2\right)\times\mathbf v_3 = \left(\mathbf v_1\times\mathbf v_3\right)+\left(\mathbf v_2\times\mathbf v_3\right)\$ here.

How?

Uses this multiplication table of orthonormal basis vectors:

×ばつ \$\mathbf e_1\$ \$\mathbf e_2\$ \$\mathbf e_3\$ \$\mathbf e_4\$ \$\mathbf e_5\$ \$\mathbf e_6\$ \$\mathbf e_7\$
\$\mathbf e_1\$ 0 \$-\mathbf e_4\$ \$-\mathbf e_7\$ \$\mathbf e_2\$ \$-\mathbf e_6\$ \$\mathbf e_5\$ \$\mathbf e_3\$
\$\mathbf e_2\$ \$\mathbf e_4\$ 0 \$-\mathbf e_5\$ \$-\mathbf e_1\$ \$\mathbf e_3\$ \$-\mathbf e_7\$ \$\mathbf e_6\$
\$\mathbf e_3\$ \$\mathbf e_7\$ \$\mathbf e_5\$ 0 \$-\mathbf e_6\$ \$-\mathbf e_2\$ \$\mathbf e_4\$ \$-\mathbf e_1\$
\$\mathbf e_4\$ \$-\mathbf e_2\$ \$\mathbf e_1\$ \$\mathbf e_6\$ 0 \$-\mathbf e_7\$ \$-\mathbf e_3\$ \$\mathbf e_5\$
\$\mathbf e_5\$ \$\mathbf e_6\$ \$-\mathbf e_3\$ \$\mathbf e_2\$ \$\mathbf e_7\$ 0 \$-\mathbf e_1\$ \$-\mathbf e_4\$
\$\mathbf e_6\$ \$-\mathbf e_5\$ \$\mathbf e_7\$ \$-\mathbf e_4\$ \$\mathbf e_3\$ \$\mathbf e_1\$ 0 \$-\mathbf e_2\$
\$\mathbf e_7\$ \$-\mathbf e_3\$ \$-\mathbf e_6\$ \$\mathbf e_1\$ \$-\mathbf e_5\$ \$\mathbf e_4\$ \$\mathbf e_2\$ 0
ṙJ$(Ç¢œ?N5ẒƇ¤¦_W{JœṖ"$ZṚẎŒḌḋ - Link: V1; V2 e.g. abcdefg; tuvwxyz
ṙJ$ - rotate {V1} left by its 1-indices
 -> bcdefga cdefgab defgabc efgabcd fgabcde gabcdef abcdefg
 (Ç¢œ? - 4502nd lexicographic permutation of {that}
 -> abcdefg cdefgab efgabcd fgabcde bcdefga gabcdef defgabc
 N5ẒƇ¤¦ - negate values in the 2nd, 3rd, and 5th lists (primes up to 5)
 _W{ - replace the 1st with zeros (subtract [V1])
 JœṖ"$ - partition each before its 1-index
 ZṚẎ - transpose, reverse and tighten
 ŒḌ - form a matrix from these diagonals
 -> 0 -d -g b -f e c
 d 0 -e -a c -g f
 g e 0 -f -b d -a
 -b a f 0 -g -c e
 f -c b g 0 -a -d
 -e g -d c a 0 -b
 -c -f a -e d b 0
 ḋ - dot-product {V2} (vectorsies)
 -> [ 0 - ud - vg + wb - xf + ye + zc,
 td + 0 - ve - wa + xc - yg + zf,
 tg + ue + 0 - wf - xb + yd - za,
 -tb + ua + vf + 0 - xg - yc + ze,
 tf - uc + vb + wg + 0 - ya - zd,
 -te + ug - vd + wc + xa + 0 - zb,
 -tc - uf + va - we + xd + yb + 0,
 ]
answered Aug 10 at 23:38
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.