Quaternions   are an extension of the idea of   complex numbers.

A complex number has a real and complex part,   sometimes written as     a + bi,  

where     a     and     b     stand for real numbers, and     i     stands for the square root of minus 1.

An example of a complex number might be     -3 + 2i,    

where the real part,     a     is     -3.0     and the complex part,     b     is     +2.0.  

A quaternion has one real part and three imaginary parts,     i,       j,     and     k.  

A quaternion might be written as     a + bi + cj + dk.  

In the quaternion numbering system:

     i∙i = j∙j = k∙k = i∙j∙k = -1,         or more simply,
     ii  = jj  = kk  = ijk   = -1.  
The order of multiplication is important, as, in general, for two quaternions:

     q1     and     q2:         q1q2 ≠ q2q1.  
An example of a quaternion might be     1 +2i +3j +4k  

There is a list form of notation where just the numbers are shown and the imaginary multipliers    i,       j,     and     k     are assumed by position.

So the example above would be written as     (1, 2, 3, 4)  



Task

Given the three quaternions and their components: 

   q  = (1, 2, 3, 4) = (a,  b,  c,  d)
   q1 = (2, 3, 4, 5) = (a1, b1, c1, d1)
   q2 = (3, 4, 5, 6) = (a2, b2, c2, d2) 

And a wholly real number     r = 7.  



Create functions   (or classes)   to perform simple maths with quaternions including computing:

 The norm of a quaternion: 




=



a

2


+

b

2


+

c

2


+

d

2






{\displaystyle ={\sqrt {a^{2}+b^{2}+c^{2}+d^{2}}}}

 
 The negative of a quaternion: 
   = (-a, -b, -c, -d)  
 The conjugate of a quaternion: 
   = ( a, -b, -c, -d)  
 Addition of a real number     r     and a quaternion     q:  
  r + q = q + r = (a+r, b, c, d)  
 Addition of two quaternions: 
   q1 + q2 = (a1+a2, b1+b2, c1+c2, d1+d2)  
 Multiplication of a real number and a quaternion: 
   qr = rq = (ar, br, cr, dr)  
 Multiplication of two quaternions     q1     and   q2     is given by: 
   ( a1a2 − b1b2 − c1c2 − d1d2, 
   a1b2 + b1a2 + c1d2 − d1c2, 
   a1c2 − b1d2 + c1a2 + d1b2, 
   a1d2 + b1c2 − c1b2 + d1a2 )  
 Show that, for the two quaternions     q1     and     q2: 
 q1q2 ≠ q2q1  


If a language has built-in support for quaternions, then use it.



C.f.

   Vector products
   On Quaternions;   or on a new System of Imaginaries in Algebra.   By Sir William Rowan Hamilton LL.D, P.R.I.A., F.R.A.S., Hon. M. R. Soc. Ed. and Dub., Hon. or Corr. M. of the Royal or Imperial Academies of St. Petersburgh, Berlin, Turin and Paris, Member of the American Academy of Arts and Sciences, and of other Scientific Societies at Home and Abroad, Andrews' Prof. of Astronomy in the University of Dublin, and Royal Astronomer of Ireland.


$ include "seed7_05.s7i";
  include "float.s7i";
  include "math.s7i";
 
 
# Define the quaternion number data type.
const type: quaternion is new object struct
    var float: a is 0.0;
    var float: b is 0.0;
    var float: c is 0.0;
    var float: d is 0.0;
  end struct;
 
 
# Create a quaternion number from its real and imaginary parts.
const func quaternion: quaternion
    (in float: a, in float: b, in float: c, in float: d) is func
  result
    var quaternion: aQuaternion is quaternion.value;
  begin
    aQuaternion.a := a;
    aQuaternion.b := b;
    aQuaternion.c := c;
    aQuaternion.d := d;
  end func;
 
 
# Helper function for str().
const func string: signed (in float: number, in string: part) is func
  result
    var string: stri is str(number) & part;
  begin
    if number > 0.0 then
      stri := "+" & stri;
    elsif number = 0.0 then
      stri := "";
    end if;
  end func;
 
 
# Convert a quaternion number to a string.
const func string: str (in quaternion: number) is func
  result
    var string: stri is "";
  begin
    if number.a <> 0.0 then
      stri &:= str(number.a);
    end if;
    stri &:= signed(number.b, "i");
    stri &:= signed(number.c, "j");
    stri &:= signed(number.d, "k");
  end func;
 
 
# Compute the norm of a quaternion number.
const func float: norm (in quaternion: number) is func
  result
    var float: qnorm is 0.0;
  begin
    qnorm := sqrt(
      number.a ** 2.0 + number.b ** 2.0 +
      number.c ** 2.0 + number.d ** 2.0
    );
  end func;
 
 
# Compute the negative of a quaternion number.
const func quaternion: - (in quaternion: number) is func
  result
    var quaternion: negatedNumber is quaternion.value;
  begin
    negatedNumber.a := -number.a;
    negatedNumber.b := -number.b;
    negatedNumber.c := -number.c;
    negatedNumber.d := -number.d;
  end func;
 
 
# Compute the conjugate of a quaternion number.
const func quaternion: conjugate (in quaternion: number) is func
  result
    var quaternion: conjugateNumber is quaternion.value;
  begin
    conjugateNumber.a :=  number.a;
    conjugateNumber.b := -number.b;
    conjugateNumber.c := -number.c;
    conjugateNumber.d := -number.d;
  end func;
 
 
# Add a float to a quaternion number.
const func quaternion: (in quaternion: number) + (in float: real) is func
  result
    var quaternion: sum is quaternion.value;
  begin
    sum.a := number.a + real;
    sum.b := number.b;
    sum.c := number.c;
    sum.d := number.d;
  end func;
 
 
# Add a quaternion number to a float.
const func quaternion: (in float: real) + (in quaternion: number) is
  return number + real;
 
 
# Add two quaternion numbers.
const func quaternion: (in quaternion: number1) + (in quaternion: number2) is func
  result
    var quaternion: sum is quaternion.value;
  begin
    sum.a := number1.a + number2.a;
    sum.b := number1.b + number2.b;
    sum.c := number1.c + number2.c;
    sum.d := number1.d + number2.d;
  end func;
 
 
# Multiply a float and a quaternion number.
const func quaternion: (in float: real) * (in quaternion: number) is func
  result
    var quaternion: product is quaternion.value;
  begin
    product.a := number.a * real;
    product.b := number.b * real;
    product.c := number.c * real;
    product.d := number.d * real;
  end func;
 
 
# Multiply a quaternion number and a float.
const func quaternion: (in quaternion: number) * (in float: real) is
  return real * number;
 
 
# Multiply two quaternion numbers.
const func quaternion: (in quaternion: x) * (in quaternion: y) is func
  result
    var quaternion: product is quaternion.value;
  begin
    product.a := x.a * y.a - x.b * y.b - x.c * y.c - x.d * y.d;
    product.b := x.a * y.b + x.b * y.a + x.c * y.d - x.d * y.c;
    product.c := x.a * y.c - x.b * y.d + x.c * y.a + x.d * y.b;
    product.d := x.a * y.d + x.b * y.c - x.c * y.b + x.d * y.a;
  end func;
 
 
# Allow quaternions to be written using write(), writeln() etc.
enable_output(quaternion);
 
 
# Demonstrate quaternion numbers.
const proc: main is func
  local
    const quaternion: q is quaternion(1.0, 2.0, 3.0, 4.0);
    const quaternion: q1 is quaternion(2.0, 3.0, 4.0, 5.0);
    const quaternion: q2 is quaternion(3.0, 4.0, 5.0, 6.0);
    const float: r is 7.0;
  begin
    writeln(" q = " <& q);
    writeln("q1 = " <& q1);
    writeln("q2 = " <& q2);
    writeln(" r = " <& r <& "\n");
 
    writeln("norm(q) = " <& norm(q));
    writeln("-q = " <& -q);
    writeln("conjugate(q) = " <& conjugate(q));
    writeln("q + r = " <& q + r);
    writeln("r + q = " <& r + q);
    writeln("q1 + q2 = " <& q1 + q2);
    writeln("q2 + q1 = " <& q2 + q1);
    writeln("q * r = " <& q * r);
    writeln("r * q = " <& r * q);
    writeln("q1 * q2 = " <& q1 * q2);
    writeln("q2 * q1 = " <& q2 * q1);
  end func;