[GS] (20190504) The idea behind the Cayley-Dickson construction [https://en.wikipedia.org/wiki/Cayley%E2%80%93Dickson_construction] is that a complex number `a + ib` can be written as a pair of real numbers `(a,b)`.

Multiplication is done like this : 

 (a,b)(c,d) = (ac - db,ad + cb)

And the conjugate of a complex number is defined like this :

 (a,b)* = (a,-b)

Now a quaternion can be considered as a pair of complex numbers where multiplication is :

 (a,b)(c,d) = (ac - db*,a*d + cb)

And the conjugate of a quaternion is defined like this :

 (a,b)* = (a*,-b)

We can continue considering octonion to be a pair of quaternions.

So, Cayley-Dickson construction can be used to multiply complex number, quaternion, octonion, 
sedenion and so forth. Length of lists must be a power of 2.


======
# cayleydickson.tcl
# Author:      Gerard Sookahet
# Date:        04 mai 2019
# Version:     0.1
# Description: Cayley-Dickson construction to multiply complex number quaternion octonion

namespace path ::tcl::mathop

proc Conjugate x {
 set res [lmap i $x {- $i}]
 lreplace $res 0 0 [- [lindex $res 0]]
}

# Vector operation (add or substract)
proc Vec {op a b} {
 if {[llength $a] == 1 && [llength $b] == 1} {
   $op $a $b
 } else {
   lmap i $a j $b {Vec $op $i $j}
 }
}

proc CayleyDickson {x y} {
 set n [llength $x]
 if {$n == 1} {return [* $x $y]}
 set m [/ $n 2]
 set m1 [- $m 1]
 set a [lrange $x 0 $m1]
 set b [lrange $x $m end]
 set c [lrange $y 0 $m1]
 set d [lrange $y $m end]
 return [list {*}[Vec - [CayleyDickson $a $c] [CayleyDickson [Conjugate $d] $b]] \
              {*}[Vec + [CayleyDickson $d $a] [CayleyDickson $b [Conjugate $c]]]]
}

# Tests

# Multiply two real 2 and 3
CayleyDickson 2 3

# Multiply two complex numbers 3 + i2  and 1 + i7  => -11 + i23
CayleyDickson [list 3 2] [list 1 7]

# Multiply two quaternions 0 + i3 + 0 - k and 2 + 0 + j + k => 1 + i7 - j3 + k
CayleyDickson [list 0 3 0 -1] [list 2 0 1 1]
======
[FM] : get a try wiyh [TIP 759]
======
# CayleyDickson 
proc CD {x y} {(
    (n = [llength $x]) == 1 ? [ return [($x * $y)] ]:;
    m = $n/2;
    a = [lrange $x 0 $m-1]; b = [lrange $x $m end];
    c = [lrange $y 0 $m-1]; d = [lrange $y $m end];
    
    [return [list  {*}[Vec [CD $a $c] - [CD [Conjugate $d]        $b      ]] \
                   {*}[Vec [CD $d $a] + [CD       $b        [Conjugate $c]]]]]
)}

proc Vec {a op b} {
    if {[llength $a] == 1 && [llength $b] == 1} {
        switch -- $op \
            "+" ($a+$b)\
            "-" ($a-$b) \
            "*" ($a*$b)\
            "/" ($a/double($b))\
            "%" ($a%double($b))\
            "**" ($a**$b) \
            "," ($a,$b)
    } else {
        lmap i $a j $b {Vec $i $op $j}
    }
}

proc Conjugate {x} {
    lmap i $x {( [incr j] == 1 ? $i : -$i )}
}

CD [list 3 2] [list 1 7]
# -11 23
(bin) 79 % CD [list 0 3 0 -1] [list 2 0 1 1]
# 1 7 -3 1
======
That said, this generality would be a lot more slow than a direct computation with coordinates. <<br>> Comparing with "mult" proc you can find in [Quaternion] gives :
======
timerate {CD [list 0 3 0 -1] [list 2 0 1 1]}
# 69.3958 µs/# 14410 # 14410.1 #/sec 999.994 net-ms
timerate {mult [list 0 3 0 -1] [list 2 0 1 1]}
# 1.480530 µs/# 675433 # 675433 #/sec 999.999 net-ms
======
<<categories>> Mathematics