September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -32,14 +32,11 @@ Given the three quaternions and their components: <big>
|
|||
And a wholly real number <big> <code> r = 7. </code> </big>
|
||||
|
||||
|
||||
'''Note:''' ''The first formula below is invisible to the majority of browsers, including Chrome, IE/Edge, Safari, Opera etc. It may, subject to the installation of requisite fonts, prove visible in Firefox.''
|
||||
|
||||
|
||||
Create functions (or classes) to perform simple maths with quaternions including computing:
|
||||
# The norm of a quaternion: <br> <big> <code> <math> = \sqrt{ a^2 + b^2 + c^2 + d^2 } </math> </code> </big>
|
||||
# The norm of a quaternion: <br><big><code><math>= \sqrt{a^2 + b^2 + c^2 + d^2}</math></code></big>
|
||||
# The negative of a quaternion: <br> <big> <code> = (-a, -b, -c, -d)</code> </big>
|
||||
# The conjugate of a quaternion: <br> <big> <code> = ( a, -b, -c, -d)</code> </big>
|
||||
# Addition of a real number <big> <code> r </code> </big> and <big> <code> a </code> </big> quaternion <big> <code> q: </code> </big> <br> <big> <code> r + q = q + r = (a+r, b, c, d) </code> </big>
|
||||
# Addition of a real number <big> <code> r </code> </big> and a quaternion <big> <code> q: </code> </big> <br> <big> <code> r + q = q + r = (a+r, b, c, d) </code> </big>
|
||||
# Addition of two quaternions: <br> <big> <code> q<sub>1</sub> + q<sub>2</sub> = (a<sub>1</sub>+a<sub>2</sub>, b<sub>1</sub>+b<sub>2</sub>, c<sub>1</sub>+c<sub>2</sub>, d<sub>1</sub>+d<sub>2</sub>) </code> </big>
|
||||
# Multiplication of a real number and a quaternion: <br> <big> <code> qr = rq = (ar, br, cr, dr) </code> </big>
|
||||
# Multiplication of two quaternions <big> <code> q<sub>1</sub> </code> </big> and <big><code>q<sub>2</sub> </code> </big> is given by: <br> <big> <code> ( a<sub>1</sub>a<sub>2</sub> − b<sub>1</sub>b<sub>2</sub> − c<sub>1</sub>c<sub>2</sub> − d<sub>1</sub>d<sub>2</sub>, </code> <br> <code> a<sub>1</sub>b<sub>2</sub> + b<sub>1</sub>a<sub>2</sub> + c<sub>1</sub>d<sub>2</sub> − d<sub>1</sub>c<sub>2</sub>, </code> <br> <code> a<sub>1</sub>c<sub>2</sub> − b<sub>1</sub>d<sub>2</sub> + c<sub>1</sub>a<sub>2</sub> + d<sub>1</sub>b<sub>2</sub>, </code> <br> <code> a<sub>1</sub>d<sub>2</sub> + b<sub>1</sub>c<sub>2</sub> − c<sub>1</sub>b<sub>2</sub> + d<sub>1</sub>a<sub>2</sub> ) </code> </big>
|
||||
|
|
|
|||
57
Task/Quaternion-type/Kotlin/quaternion-type.kotlin
Normal file
57
Task/Quaternion-type/Kotlin/quaternion-type.kotlin
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// version 1.1.2
|
||||
|
||||
data class Quaternion(val a: Double, val b: Double, val c: Double, val d: Double) {
|
||||
operator fun plus(other: Quaternion): Quaternion {
|
||||
return Quaternion (this.a + other.a, this.b + other.b,
|
||||
this.c + other.c, this.d + other.d)
|
||||
}
|
||||
|
||||
operator fun plus(r: Double) = Quaternion(a + r, b, c, d)
|
||||
|
||||
operator fun times(other: Quaternion): Quaternion {
|
||||
return Quaternion(
|
||||
this.a * other.a - this.b * other.b - this.c * other.c - this.d * other.d,
|
||||
this.a * other.b + this.b * other.a + this.c * other.d - this.d * other.c,
|
||||
this.a * other.c - this.b * other.d + this.c * other.a + this.d * other.b,
|
||||
this.a * other.d + this.b * other.c - this.c * other.b + this.d * other.a
|
||||
)
|
||||
}
|
||||
|
||||
operator fun times(r: Double) = Quaternion(a * r, b * r, c * r, d * r)
|
||||
|
||||
operator fun unaryMinus() = Quaternion(-a, -b, -c, -d)
|
||||
|
||||
fun conj() = Quaternion(a, -b, -c, -d)
|
||||
|
||||
fun norm() = Math.sqrt(a * a + b * b + c * c + d * d)
|
||||
|
||||
override fun toString() = "($a, $b, $c, $d)"
|
||||
}
|
||||
|
||||
// extension functions for Double type
|
||||
operator fun Double.plus(q: Quaternion) = q + this
|
||||
operator fun Double.times(q: Quaternion) = q * this
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val q = Quaternion(1.0, 2.0, 3.0, 4.0)
|
||||
val q1 = Quaternion(2.0, 3.0, 4.0, 5.0)
|
||||
val q2 = Quaternion(3.0, 4.0, 5.0, 6.0)
|
||||
val r = 7.0
|
||||
println("q = $q")
|
||||
println("q1 = $q1")
|
||||
println("q2 = $q2")
|
||||
println("r = $r\n")
|
||||
println("norm(q) = ${"%f".format(q.norm())}")
|
||||
println("-q = ${-q}")
|
||||
println("conj(q) = ${q.conj()}\n")
|
||||
println("r + q = ${r + q}")
|
||||
println("q + r = ${q + r}")
|
||||
println("q1 + q2 = ${q1 + q2}\n")
|
||||
println("r * q = ${r * q}")
|
||||
println("q * r = ${q * r}")
|
||||
val q3 = q1 * q2
|
||||
val q4 = q2 * q1
|
||||
println("q1 * q2 = $q3")
|
||||
println("q2 * q1 = $q4\n")
|
||||
println("q1 * q2 != q2 * q1 = ${q3 != q4}")
|
||||
}
|
||||
150
Task/Quaternion-type/OoRexx/quaternion-type.rexx
Normal file
150
Task/Quaternion-type/OoRexx/quaternion-type.rexx
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
q = .quaternion~new(1, 2, 3, 4)
|
||||
q1 = .quaternion~new(2, 3, 4, 5)
|
||||
q2 = .quaternion~new(3, 4, 5, 6)
|
||||
r = 7
|
||||
|
||||
say "q =" q
|
||||
say "q1 =" q1
|
||||
say "q2 =" q2
|
||||
say "r =" r
|
||||
say "norm(q) =" q~norm
|
||||
say "-q =" (-q)
|
||||
say "q* =" q~conjugate
|
||||
say "q + r =" q + r
|
||||
say "q1 + q2 =" q1 + q2
|
||||
say "q * r =" q * r
|
||||
q1q2 = q1 * q2
|
||||
q2q1 = q2 * q1
|
||||
say "q1 * q2 =" q1q2
|
||||
say "q2 * q1 =" q2q1
|
||||
say "q1 == q1 =" (q1 == q1)
|
||||
say "q1q2 == q2q1 =" (q1q2 == q2q1)
|
||||
|
||||
|
||||
::class quaternion
|
||||
::method init
|
||||
expose r i j k
|
||||
use strict arg r, i = 0, j = 0, k = 0
|
||||
|
||||
-- quaternion instances are immutable, so these are
|
||||
-- read only attributes
|
||||
::attribute r GET
|
||||
::attribute i GET
|
||||
::attribute j GET
|
||||
::attribute k GET
|
||||
|
||||
::method norm
|
||||
expose r i j k
|
||||
return rxcalcsqrt(r * r + i * i + j * j + k * k)
|
||||
|
||||
::method invert
|
||||
expose r i j k
|
||||
norm = self~norm
|
||||
return self~class~new(r / norm, i / norm, j / norm, k / norm)
|
||||
|
||||
::method negative
|
||||
expose r i j k
|
||||
return self~class~new(-r, -i, -j, -k)
|
||||
|
||||
::method conjugate
|
||||
expose r i j k
|
||||
return self~class~new(r, -i, -j, -k)
|
||||
|
||||
::method add
|
||||
expose r i j k
|
||||
use strict arg other
|
||||
if other~isa(.quaternion) then
|
||||
return self~class~new(r + other~r, i + other~i, j + other~j, k + other~k)
|
||||
else return self~class~new(r + other, i, j, k)
|
||||
|
||||
::method subtract
|
||||
expose r i j k
|
||||
use strict arg other
|
||||
if other~isa(.quaternion) then
|
||||
return self~class~new(r - other~r, i - other~i, j - other~j, k - other~k)
|
||||
else return self~class~new(r - other, i, j, k)
|
||||
|
||||
::method times
|
||||
expose r i j k
|
||||
use strict arg other
|
||||
if other~isa(.quaternion) then
|
||||
return self~class~new(r * other~r - i * other~i - j * other~j - k * other~k, -
|
||||
r * other~i + i * other~r + j * other~k - k * other~j, -
|
||||
r * other~j - i * other~k + j * other~r + k * other~i, -
|
||||
r * other~k + i * other~j - j * other~i + k * other~r)
|
||||
else return self~class~new(r * other, i * other, j * other, k * other)
|
||||
|
||||
::method divide
|
||||
use strict arg other
|
||||
-- this is easier if everything is a quaternion
|
||||
if \other~isA(.quaternion) then other = .quaternion~new(other)
|
||||
-- division is multiplication with the inversion
|
||||
return self * other~invert
|
||||
|
||||
::method "=="
|
||||
expose r i j k
|
||||
use strict arg other
|
||||
|
||||
if \other~isa(.quaternion) then return .false
|
||||
-- Note: these are numeric comparisons, so we're using the "="
|
||||
-- method so those are handled correctly
|
||||
return r = other~r & i = other~i & j = other~j & k = other~k
|
||||
|
||||
::method "\=="
|
||||
use strict arg other
|
||||
return \self~"\=="(other)
|
||||
|
||||
::method "="
|
||||
-- this is equivalent of "=="
|
||||
forward message("==")
|
||||
|
||||
::method "\="
|
||||
-- this is equivalent of "\=="
|
||||
forward message("\==")
|
||||
|
||||
::method "<>"
|
||||
-- this is equivalent of "\=="
|
||||
forward message("\==")
|
||||
|
||||
::method "><"
|
||||
-- this is equivalent of "\=="
|
||||
forward message("\==")
|
||||
|
||||
-- some operator overrides -- these only work if the left-hand-side of the
|
||||
-- subexpression is a quaternion
|
||||
::method "*"
|
||||
forward message("TIMES")
|
||||
|
||||
::method "/"
|
||||
forward message("DIVIDE")
|
||||
|
||||
::method "-"
|
||||
-- need to check if this is a prefix minus or a subtract
|
||||
if arg() == 0 then
|
||||
forward message("NEGATIVE")
|
||||
else
|
||||
forward message("SUBTRACT")
|
||||
|
||||
::method "+"
|
||||
-- need to check if this is a prefix plus or an addition
|
||||
if arg() == 0 then
|
||||
return self -- we can return this copy since it is immutable
|
||||
else
|
||||
forward message("ADD")
|
||||
|
||||
::method string
|
||||
expose r i j k
|
||||
return r self~formatnumber(i)"i" self~formatnumber(j)"j" self~formatnumber(k)"k"
|
||||
|
||||
::method formatnumber private
|
||||
use arg value
|
||||
if value > 0 then return "+" value
|
||||
else return "-" value~abs
|
||||
|
||||
-- override hashcode for collection class hash uses
|
||||
::method hashCode
|
||||
expose r i j k
|
||||
return r~hashcode~bitxor(i~hashcode)~bitxor(j~hashcode)~bitxor(k~hashcode)
|
||||
|
||||
|
||||
::requires rxmath LIBRARY
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
require 'matrix' # For Vector#norm
|
||||
|
||||
class Quaternion
|
||||
def initialize(*parts)
|
||||
raise "Invalid number of quaternion parts" unless parts.length == 4
|
||||
@parts, @vector = parts, Vector[*parts]
|
||||
end
|
||||
|
||||
def to_a; @parts; end
|
||||
def to_s; "Quaternion#{to_a.to_s}" end
|
||||
def complex_parts; [Complex(*to_a[0..1]), Complex(*to_a[2..3])]; end
|
||||
def zip(other); to_a.zip(other.to_a); end
|
||||
|
||||
def real; @parts.first; end
|
||||
def imag; @parts[1..3]; end
|
||||
def conj; Quaternion.new(real, *imag.map(&:-@)); end
|
||||
def norm; @vector.norm; end # Or: Math.sqrt(to_a.reduce { |sum, e| sum + e**2 }) # In Rails: Math.sqrt(to_a.sum { e**2 })
|
||||
|
||||
def ==(other); to_a == other.to_a end
|
||||
def -@; Quaternion.new(*to_a.map(&:-@)); end
|
||||
def -(other); self + -other; end
|
||||
|
||||
def +(other)
|
||||
case other
|
||||
when Numeric
|
||||
Quaternion.new(real + other, *imag)
|
||||
when Quaternion
|
||||
Quaternion.new(*zip(other).map { |x,y| x + y }) # In Rails: zip(other).map(&:sum) # Or: (vector + other.vector).to_a
|
||||
end
|
||||
end
|
||||
|
||||
def *(other)
|
||||
case other
|
||||
when Numeric
|
||||
Quaternion.new(*to_a.map { |x| x * other }) # Or: (vector * other).to_a
|
||||
when Quaternion
|
||||
# Multiplication of quaternions in C x C space. See "Cayley-Dickson construction".
|
||||
a, b, c, d = *complex_parts, *other.complex_parts
|
||||
x, y = a*c - d.conj*b, a*d + b*c.conj
|
||||
Quaternion.new(x.real, x.imag, y.real, y.imag)
|
||||
end
|
||||
end
|
||||
|
||||
# Coerce is called by Ruby to return a compatible type/receiver when the called method/operation does not accept a Quaternion
|
||||
def coerce(other)
|
||||
case other
|
||||
when Numeric then [Scalar.new(other), self]
|
||||
else raise TypeError, "#{other.class} can't be coerced into #{self.class}"
|
||||
end
|
||||
end
|
||||
|
||||
class Scalar
|
||||
def initialize(val); @val = val; end
|
||||
def +(other); other + @val; end
|
||||
def *(other); other * @val; end
|
||||
def -(other); Quaternion.new(@val, 0, 0, 0) - other; end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
irb(main):001:0> require 'quaternion'
|
||||
=> true
|
||||
irb(main):002:0> q = Quaternion.new(1,2,3,4)
|
||||
=> Quaternion[1, 2, 3, 4]
|
||||
irb(main):003:0> q1 = Quaternion.new(2,3,4,5)
|
||||
=> Quaternion[2, 3, 4, 5]
|
||||
irb(main):004:0> q2 = Quaternion.new(3,4,5,6)
|
||||
=> Quaternion[3, 4, 5, 6]
|
||||
irb(main):005:0> r = 7
|
||||
=> 7
|
||||
irb(main):006:0> q.norm
|
||||
=> 5.477225575051661
|
||||
irb(main):007:0> q1.norm
|
||||
=> 7.3484692283495345
|
||||
irb(main):008:0> q2.norm
|
||||
=> 9.273618495495704
|
||||
irb(main):009:0> -q
|
||||
=> Quaternion[-1, -2, -3, -4]
|
||||
irb(main):010:0> q.conj
|
||||
=> Quaternion[1, -2, -3, -4]
|
||||
irb(main):011:0> q1 + q2
|
||||
=> Quaternion[5, 7, 9, 11]
|
||||
irb(main):012:0> q2 + q1
|
||||
=> Quaternion[5, 7, 9, 11]
|
||||
irb(main):013:0> q + r
|
||||
=> Quaternion[8, 2, 3, 4]
|
||||
irb(main):014:0> r + q
|
||||
=> Quaternion[8, 2, 3, 4]
|
||||
irb(main):015:0> q * r
|
||||
=> Quaternion[7, 14, 21, 28]
|
||||
irb(main):016:0> r * q
|
||||
=> Quaternion[7, 14, 21, 28]
|
||||
irb(main):017:0> q1 * q2
|
||||
=> Quaternion[-56, 16, 24, 26]
|
||||
irb(main):018:0> q2 * q1
|
||||
=> Quaternion[-56, 18, 20, 28]
|
||||
irb(main):019:0> q1 * q2 != q2 * q1
|
||||
=> true
|
||||
53
Task/Quaternion-type/Zkl/quaternion-type-1.zkl
Normal file
53
Task/Quaternion-type/Zkl/quaternion-type-1.zkl
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
class Quat{
|
||||
fcn init(real=0,i1=0,i2=0,i3=0){
|
||||
var [const] vector= // Quat(r,i,j,k) or Quat( (r,i,j,k) )
|
||||
(if(List.isType(real)) real else vm.arglist).apply("toFloat");
|
||||
var r,i,j,k; r,i,j,k=vector; // duplicate data for ease of coding
|
||||
var [const] // properties: This is one way to do it
|
||||
norm2=vector.apply("pow",2).sum(0.0), // Norm squared
|
||||
abs=norm2.sqrt(), // Norm
|
||||
arg=(r/abs()).acos(), // Theta !!!this may be incorrect...
|
||||
;
|
||||
}
|
||||
fcn toString { String("[",vector.concat(","),"]") }
|
||||
var [const proxy] // properties that need calculation (or are recursive)
|
||||
conj =fcn{ Quat(r,-i,-j,-k) }, // Conjugate
|
||||
recip =fcn{ n2:=norm2; Quat(r/n2,-i/n2,-j/n2,-k/n2) },// Reciprocal
|
||||
pureim =fcn{ Quat(0, i, j, k) }, // Pure imagery
|
||||
versor =fcn{ self / abs; }, // Unit versor
|
||||
iversor=fcn{ pureim / pureim.abs; }, // Unit versor of imagery part
|
||||
;
|
||||
|
||||
fcn __opEQ(z) { r == z.r and i == z.i and j == z.j and k == z.k }
|
||||
fcn __opNEQ(z){ (not (self==z)) }
|
||||
|
||||
fcn __opNegate{ Quat(-r, -i, -j, -k) }
|
||||
fcn __opAdd(z){
|
||||
if (Quat.isInstanceOf(z)) Quat(vector.zipWith('+,z.vector));
|
||||
else Quat(r+z,i,j,k);
|
||||
}
|
||||
fcn __opSub(z){
|
||||
if (Quat.isInstanceOf(z)) Quat(vector.zipWith('-,z.vector));
|
||||
else Quat(r-z,vector.xplode(1)); // same as above
|
||||
}
|
||||
fcn __opMul(z){
|
||||
if (Quat.isInstanceOf(z)){
|
||||
Quat(r*z.r - i*z.i - j*z.j - k*z.k,
|
||||
r*z.i + i*z.r + j*z.k - k*z.j,
|
||||
r*z.j - i*z.k + j*z.r + k*z.i,
|
||||
r*z.k + i*z.j - j*z.i + k*z.r);
|
||||
}
|
||||
else Quat(vector.apply('*(z)));
|
||||
}
|
||||
fcn __opDiv(z){
|
||||
if (Quat.isInstanceOf(z)) self*z.recip;
|
||||
else Quat(r/z,i/z,j/z,k/z);
|
||||
}
|
||||
|
||||
fcn pow(r){ exp(r*iversor*arg)*abs.pow(r) } // Power function
|
||||
fcn log{ iversor*(r / abs).acos() + abs.log() }
|
||||
fcn exp{ // e^q
|
||||
inorm:=pureim.abs;
|
||||
(iversor*inorm.sin() + inorm.cos()) * r.exp();
|
||||
}
|
||||
}
|
||||
39
Task/Quaternion-type/Zkl/quaternion-type-2.zkl
Normal file
39
Task/Quaternion-type/Zkl/quaternion-type-2.zkl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Demo code
|
||||
r:=7;
|
||||
q:=Quat(2,3,4,5); q1:=Quat(2,3,4,5); q2:=Quat(3,4,5,6);
|
||||
|
||||
println("1. norm: q.abs: ", q.abs);
|
||||
println("2. -q: ", -q);
|
||||
println("3. conjugate: q.conj: ", q.conj);
|
||||
println("4. Quat(r) + q: ", Quat(r) + q);
|
||||
println(" q + r: ", q + r);
|
||||
println("5. q1 + q2: ", q1 + q2);
|
||||
println("6. Quat(r) * q: ", Quat(r) * q);
|
||||
println(" q * r: ", q * r);
|
||||
println("7. q1 * q2: ", q1 * q2);
|
||||
println(" q2 * q1: ", q2 * q1);
|
||||
println("8. q1 * q2 == q2 * q1 ? ", q1 * q2 == q2 * q1);
|
||||
|
||||
i:=Quat(0,1); j:=Quat(0,0,1); k:=Quat(0,0,0,1);
|
||||
println("9.1 i * i: ", i * i);
|
||||
println(" J * j: ", j * j);
|
||||
println(" k * k: ", k * k);
|
||||
println(" i * j * k: ", i * j * k);
|
||||
|
||||
println("9.2 q1 / q2: ", q1 / q2);
|
||||
println("9.3 q1 / q2 * q2: ", q1 / q2 * q2);
|
||||
println(" q2 * q1 / q2: ", q2 * q1 / q2);
|
||||
println("9.4 (i * pi).exp(): ", (i * (0.0).pi).exp());
|
||||
println(" exp(j * pi): ", (j * (0.0).pi).exp());
|
||||
println(" exp(k * pi): ", (k * (0.0).pi).exp());
|
||||
println(" q.exp(): ", q.exp());
|
||||
println(" q.log(): ", q.log());
|
||||
println(" q.log().exp(): ", q.log().exp());
|
||||
println(" q.exp().log(): ", q.exp().log());
|
||||
|
||||
s:=q.exp().log();
|
||||
println("9.5 let s=q.exp().log(): ", s);
|
||||
println(" s.exp(): ", s.exp());
|
||||
println(" s.log(): ", s.log());
|
||||
println(" s.log().exp(): ", s.log().exp());
|
||||
println(" s.exp().log(): ", s.exp().log());
|
||||
Loading…
Add table
Add a link
Reference in a new issue