# Quaternionic Kronecker Product

I want to define the Kronecker product of quaternionic matrices. I want to follow the idea of this answer of passing the NonCommutativeMultiply to the matrix product

times[q1_, q2_] := Inner[NonCommutativeMultiply, q1, q2, Plus]


As the standard KroneckerProduct does not allow to change the definition of its matrix multiplication I am attempting something like

Outer[NonCommutativeMultiply, q1, q2] // ArrayFlatten[#, 2] &


But this does not work as hoped.

• For future reference, please show the actual vs. desired output of your code, rather than saying "didn't work as hoped", so we know exactly what you want to achieve. Commented Sep 11, 2022 at 18:24

You could temporarily and locally change the "meaning" of Times to NonCommutativeMultiply just while you run KroneckerProduct:

Block[
{Times = NonCommutativeMultiply},
KroneckerProduct[Array[b, {2, 2}], Array[a, {2, 2}]]
]

(* Out:
{{b[1, 1] ** a[1, 1], b[1, 1] ** a[1, 2], b[1, 2] ** a[1, 1], b[1, 2] ** a[1, 2]},
{b[1, 1] ** a[2, 1], b[1, 1] ** a[2, 2], b[1, 2] ** a[2, 1], b[1, 2] ** a[2, 2]},
{b[2, 1] ** a[1, 1], b[2, 1] ** a[1, 2], b[2, 2] ** a[1, 1], b[2, 2] ** a[1, 2]},
{b[2, 1] ** a[2, 1], b[2, 1] ** a[2, 2], b[2, 2] ** a[2, 1], b[2, 2] ** a[2, 2]}}
*)

• Nice answer, indeed! Commented Sep 11, 2022 at 18:38
• Why are you inheriting the default definition of Times? After all, you are overriding most things anyway. Also, you are inheriting the Orderless attribute - that shouldn't matter here, since Times is immediately replaced my NonVommutativeMultiply, but I would be a bit worried about the evaluator canonicalizing the expression before replacing the head. Commented Sep 11, 2022 at 18:53
• Nevermind, it does matter: If you swap a and b, you still get a[...]**b[...] type products with the current answer Commented Sep 11, 2022 at 18:55
• @Lukas You have a good point. I went with InheritedBlock out of habit, but Block should actually do fine here, and it's simpler. That also returns b ** a products when swapping a and b. See update Commented Sep 11, 2022 at 19:31

Again, a possible solution is to define a new function.

qkronecker[q1_, q2_] := Outer[NonCommutativeMultiply, q1, q2] // ArrayFlatten


To see if this works, we first try not with quaternions, but with symbols:

am = Array[Subscript[a, #1, #2] &, {2, 2}];
bm = Array[Subscript[b, #1, #2] &, {2, 2}];

qkronecker[am, bm] // MatrixForm


Now with quaternions:

q = {{Quaternion[7, 0, 0, 0],
Quaternion[0, 1, 1, 0]}, {Quaternion[0, 0, 1, 7],
Quaternion[0, 5, 0, 1]}};

qkronecker[q, q] // MatrixForm


• I was about posting the same idea... ^^ Commented Sep 11, 2022 at 19:46