Class: Quaternion
- Defined in:
- lib/quaternion_c2/base.rb,
lib/quaternion_c2/unary.rb,
lib/quaternion_c2/units.rb,
lib/quaternion_c2/units.rb,
lib/quaternion_c2/utils.rb,
lib/quaternion_c2/to_type.rb,
lib/quaternion_c2/equality.rb,
lib/quaternion_c2/arithmetic.rb,
lib/quaternion_c2/attributes.rb,
lib/quaternion_c2/conversion.rb,
lib/quaternion_c2/classification.rb
Overview
This class Quaternion is an analogue of Complex.
-
A subclass of
Numeric -
Immutable instances
-
Common / extended methods
Please require ‘quaternion_c2’ to load all functions.
Quaternion has many constructors to accept the various representations of a quaternion. It is recommended to use Kernel.#Quaternion and Quaternion.polar.
Constant Summary collapse
- I =
new(i, 0)
- J =
new(0, 1)
- K =
new(0, i)
Class Method Summary collapse
-
.hrect(w, x = 0, y = 0, z = 0) ⇒ Quaternion
Returns a quaternion object w+xi+yj+zk, where all of w, x, y, and z are real.
-
.hyperrectangular ⇒ Quaternion
Returns a quaternion object w+xi+yj+zk, where all of w, x, y, and z are real.
-
.polar(r, theta = 0, vector = ) ⇒ Quaternion
Returns a quaternion object which denotes the given polar form.
-
.rect(a, b = 0) ⇒ Quaternion
Returns a quaternion object a+bj, where both a and b are complex (or real).
-
.rectangular ⇒ Quaternion
Returns a quaternion object a+bj, where both a and b are complex (or real).
Instance Method Summary collapse
-
#*(other) ⇒ Quaternion
Performs multiplication.
-
#**(index) ⇒ Quaternion
Performs exponentiation.
-
#+(other) ⇒ Quaternion
Performs addition.
-
#-(other) ⇒ Quaternion
Performs subtraction.
-
#==(other) ⇒ Boolean
Returns true if it equals to the other numerically.
-
#abs ⇒ Real
(also: #magnitude)
Returns the absolute part of its polar form.
-
#abs2 ⇒ Real
Returns square of the absolute value.
-
#arg ⇒ Real
(also: #angle, #phase)
Returns the angle part of its polar form.
-
#axis ⇒ Vector
Returns the axis part of its polar form.
-
#coerce(other) ⇒ [Quaternion, self]
Performs type conversion.
-
#complex? ⇒ Boolean
Returns false.
-
#conj ⇒ Quaternion
(also: #conjugate)
Returns its conjugate.
-
#denominator ⇒ Integer
Returns the denominator (lcm of all components’ denominators).
-
#eql?(other) ⇒ Boolean
Returns true if two quaternions have same reals.
-
#fdiv(other) ⇒ Quaternion
Performs division as each part is a float, never returns a float.
-
#finite? ⇒ Boolean
Returns true if its magnitude is finite, oterwise returns false.
-
#hash ⇒ Integer
Returns a hash.
-
#hrect ⇒ [Real, Real, Real, Real]
(also: #hyperrectangular)
Returns an array of four real numbers.
-
#imag ⇒ Vector
(also: #imaginary, #vector)
Returns the imaginary part as a 3-D vector.
-
#infinite? ⇒ nil, +1
Returns values corresponding to the value of its magnitude.
-
#inspect ⇒ String
Returns the value as a string for inspection.
-
#numerator ⇒ Quaternion
Returns the numerator.
-
#polar ⇒ [Real, Real, Vector]
Returns an array; [q.abs, q.arg, q.axis].
-
#quo(other) ⇒ Quaternion
(also: #/)
Performs division.
-
#rationalize(eps = 0) ⇒ Rational
Returns the value as a rational if possible (the imaginary part should be exactly zero).
-
#real ⇒ Real
(also: #scalar)
Returns the real part.
-
#real? ⇒ Boolean
Returns false.
-
#rect ⇒ [Complex, Complex]
(also: #rectangular)
Returns an array of two complex numbers.
-
#to_c ⇒ Complex
Returns the value as a complex if possible (the discarded part should be exactly zero).
-
#to_f ⇒ Float
Returns the value as a float if possible (the imaginary part should be exactly zero).
-
#to_i ⇒ Integer
Returns the value as an integer if possible (the imaginary part should be exactly zero).
-
#to_q ⇒ self
Returns self.
-
#to_r ⇒ Rational
Returns the value as a rational if possible (the imaginary part should be exactly zero).
-
#to_s ⇒ String
Returns the value as a string.
Methods inherited from Numeric
Class Method Details
.hrect(w, x = 0, y = 0, z = 0) ⇒ Quaternion
Returns a quaternion object w+xi+yj+zk, where all of w, x, y, and z are real.
48 49 50 51 52 |
# File 'lib/quaternion_c2/conversion.rb', line 48 def hrect(w, x = 0, y = 0, z = 0) a = Complex.rect(w, x) b = Complex.rect(y, z) new(a, b) end |
.hyperrectangular ⇒ Quaternion
Returns a quaternion object w+xi+yj+zk, where all of w, x, y, and z are real.
53 54 55 56 57 |
# File 'lib/quaternion_c2/conversion.rb', line 53 def hrect(w, x = 0, y = 0, z = 0) a = Complex.rect(w, x) b = Complex.rect(y, z) new(a, b) end |
.polar(r, theta = 0, vector = ) ⇒ Quaternion
Returns a quaternion object which denotes the given polar form. The actual angle is recognized as theta * vector.norm.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/quaternion_c2/conversion.rb', line 75 def polar(r, theta = 0, vector = Vector[1, 0, 0]) unless vector.kind_of?(Enumerable) && vector.size == 3 raise TypeError, 'not a 3-D vector' end unless [r, theta, *vector].all? { |a| a.kind_of?(Numeric) && a.real? } raise TypeError, 'not a real' end vector = Vector[*vector] unless vector.kind_of?(Vector) norm = vector.norm theta *= norm r_cos = r * Math.cos(theta) r_sin = r * Math.sin(theta) r_sin /= norm if norm > 0 hrect(r_cos, *(r_sin * vector)) end |
.rect(a, b = 0) ⇒ Quaternion
Returns a quaternion object a+bj, where both a and b are complex (or real).
27 28 29 30 31 32 |
# File 'lib/quaternion_c2/conversion.rb', line 27 def rect(a, b = 0) unless [a, b].all? { |c| c.kind_of?(Numeric) && c.complex? } raise TypeError, 'not a complex' end new(a, b) end |
.rectangular ⇒ Quaternion
Returns a quaternion object a+bj, where both a and b are complex (or real).
33 34 35 36 37 38 |
# File 'lib/quaternion_c2/conversion.rb', line 33 def rect(a, b = 0) unless [a, b].all? { |c| c.kind_of?(Numeric) && c.complex? } raise TypeError, 'not a complex' end new(a, b) end |
Instance Method Details
#*(other) ⇒ Quaternion
Performs multiplication.
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/quaternion_c2/arithmetic.rb', line 51 def *(other) if other.kind_of?(Quaternion) _a = other.a _b = other.b __new__(@a * _a - _b.conj * @b, _b * @a + @b * _a.conj) elsif other.kind_of?(Numeric) && other.complex? __new__(@a * other, @b * other.conj) else n1, n2 = other.coerce(self) n1 * n2 end end |
#**(index) ⇒ Quaternion
Performs exponentiation.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/quaternion_c2/utils.rb', line 19 def **(index) unless index.kind_of?(Numeric) num1, num2 = index.coerce(self) return num1 ** num2 end if __exact_zero__(index) return __new__(1, 0) end # complex -> real # (only if the imaginary part is exactly zero) unless index.real? begin index.to_f rescue else index = index.real end end # rational -> integer if index.kind_of?(Rational) && index.denominator == 1 index = index.numerator end # calc and return if index.integer? # exponentiation by squaring x = (index >= 0) ? self : __reciprocal__ n = index.abs z = __new__(1, 0) while true z *= x if n.odd? n >>= 1 return z if n.zero? x *= x end elsif index.real? r, theta, vector = polar Quaternion.polar(r ** index, theta * index, vector) elsif index.complex? || index.kind_of?(Quaternion) # assume that log(self) commutes with index under multiplication r, theta, vector = polar q = Quaternion.hrect(Math.log(r), *(theta * vector)) q *= index Quaternion.polar(Math.exp(q.real), 1, q.imag) else num1, num2 = index.coerce(self) num1 ** num2 end end |
#+(other) ⇒ Quaternion
Performs addition.
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/quaternion_c2/arithmetic.rb', line 17 def +(other) if other.kind_of?(Quaternion) __new__(@a + other.a, @b + other.b) elsif other.kind_of?(Numeric) && other.complex? __new__(@a + other, @b) else n1, n2 = other.coerce(self) n1 + n2 end end |
#-(other) ⇒ Quaternion
Performs subtraction.
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/quaternion_c2/arithmetic.rb', line 34 def -(other) if other.kind_of?(Quaternion) __new__(@a - other.a, @b - other.b) elsif other.kind_of?(Numeric) && other.complex? __new__(@a - other, @b) else n1, n2 = other.coerce(self) n1 - n2 end end |
#==(other) ⇒ Boolean
Returns true if it equals to the other numerically.
14 15 16 17 18 19 20 21 22 |
# File 'lib/quaternion_c2/equality.rb', line 14 def ==(other) if other.kind_of?(Quaternion) @a == other.a && @b == other.b elsif other.kind_of?(Numeric) && other.complex? @a == other && @b == 0 else other == self end end |
#abs ⇒ Real Also known as: magnitude
Returns the absolute part of its polar form.
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/quaternion_c2/unary.rb', line 45 def abs a_abs = @a.abs b_abs = @b.abs if __exact_zero__(a_abs) b_abs elsif __exact_zero__(b_abs) a_abs else Math.hypot(a_abs, b_abs) end end |
#abs2 ⇒ Real
Returns square of the absolute value.
33 34 35 |
# File 'lib/quaternion_c2/unary.rb', line 33 def abs2 @a.abs2 + @b.abs2 end |
#arg ⇒ Real Also known as: angle, phase
Returns the angle part of its polar form.
163 164 165 166 167 |
# File 'lib/quaternion_c2/conversion.rb', line 163 def arg r_cos = real r_sin = imag.norm Math.atan2(r_sin, r_cos) end |
#axis ⇒ Vector
Returns the axis part of its polar form.
179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/quaternion_c2/conversion.rb', line 179 def axis v = imag norm = v.norm if norm.zero? # imag[0] == +0.0 -> q = r exp(+I PI) # imag[0] == 0/1 -> q = r exp(+I PI) # imag[0] == -0.0 -> q = r exp(-I PI) sign = (1.0 / imag[0] >= 0) ? 1 : -1 Vector[sign, 0, 0] else v / norm end end |
#coerce(other) ⇒ [Quaternion, self]
Performs type conversion.
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/quaternion_c2/arithmetic.rb', line 109 def coerce(other) if other.kind_of?(Quaternion) [other, self] elsif other.kind_of?(Numeric) && other.complex? [__new__(other, 0), self] else raise TypeError, "#{other.class} can't be coerced into #{self.class}" end end |
#complex? ⇒ Boolean
Returns false.
41 42 43 |
# File 'lib/quaternion_c2/classification.rb', line 41 def complex? false end |
#conj ⇒ Quaternion Also known as: conjugate
Returns its conjugate.
20 21 22 |
# File 'lib/quaternion_c2/unary.rb', line 20 def conj __new__(@a.conj, -@b) end |
#denominator ⇒ Integer
Returns the denominator (lcm of all components’ denominators).
79 80 81 82 83 |
# File 'lib/quaternion_c2/utils.rb', line 79 def denominator ad = @a.denominator bd = @b.denominator ad.lcm(bd) end |
#eql?(other) ⇒ Boolean
Returns true if two quaternions have same reals.
30 31 32 33 34 35 36 |
# File 'lib/quaternion_c2/equality.rb', line 30 def eql?(other) if other.kind_of?(Quaternion) @a.eql?(other.a) && @b.eql?(other.b) else false end end |
#fdiv(other) ⇒ Quaternion
Performs division as each part is a float, never returns a float.
83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/quaternion_c2/arithmetic.rb', line 83 [:quo, :fdiv].each do |sym| define_method(sym) do |other| if other.kind_of?(Quaternion) self * other.conj.send(sym, other.abs2) elsif other.kind_of?(Numeric) && other.complex? __new__(@a.send(sym, other), @b.send(sym, other.conj)) else n1, n2 = other.coerce(self) n1.send(sym, n2) end end end |
#finite? ⇒ Boolean
Returns true if its magnitude is finite, oterwise returns false.
17 18 19 |
# File 'lib/quaternion_c2/attributes.rb', line 17 def finite? abs.finite? end |
#hash ⇒ Integer
Returns a hash.
43 44 45 46 |
# File 'lib/quaternion_c2/equality.rb', line 43 def hash # q1.eql?(q2) -> q1.hash == q2.hash [@a, @b].hash end |
#hrect ⇒ [Real, Real, Real, Real] Also known as: hyperrectangular
Returns an array of four real numbers.
119 120 121 |
# File 'lib/quaternion_c2/conversion.rb', line 119 def hrect rect.flat_map(&:rect) end |
#imag ⇒ Vector Also known as: imaginary, vector
Returns the imaginary part as a 3-D vector.
145 146 147 |
# File 'lib/quaternion_c2/conversion.rb', line 145 def imag Vector[*hrect.drop(1)] end |
#infinite? ⇒ nil, +1
Returns values corresponding to the value of its magnitude.
29 30 31 |
# File 'lib/quaternion_c2/attributes.rb', line 29 def infinite? abs.infinite? end |
#inspect ⇒ String
Returns the value as a string for inspection.
99 100 101 |
# File 'lib/quaternion_c2/to_type.rb', line 99 def inspect "(#{__format__(:inspect)})" end |
#numerator ⇒ Quaternion
Returns the numerator.
1 1 1 3 4-6i-12j+9k <- numerator
- - -i - -j + -k -> -----------
3 2 1 4 12 <- denominator
100 101 102 103 104 105 106 107 |
# File 'lib/quaternion_c2/utils.rb', line 100 def numerator an = @a.numerator bn = @b.numerator ad = @a.denominator bd = @b.denominator abd = ad.lcm(bd) __new__(an * (abd / ad), bn * (abd / bd)) end |
#polar ⇒ [Real, Real, Vector]
Returns an array; [q.abs, q.arg, q.axis].
202 203 204 |
# File 'lib/quaternion_c2/conversion.rb', line 202 def polar [abs, arg, axis] end |
#quo(other) ⇒ Quaternion Also known as: /
Performs division.
|
|
# File 'lib/quaternion_c2/arithmetic.rb', line 64
|
#rationalize(eps = 0) ⇒ Rational
Returns the value as a rational if possible (the imaginary part should be exactly zero).
71 72 73 |
# File 'lib/quaternion_c2/to_type.rb', line 71 [:to_f, :to_r, :to_i, :rationalize].each do |sym| define_method(sym) { |*args| to_c.send(sym, *args) } end |
#real ⇒ Real Also known as: scalar
Returns the real part.
132 133 134 |
# File 'lib/quaternion_c2/conversion.rb', line 132 def real @a.real end |
#real? ⇒ Boolean
Returns false.
34 35 36 |
# File 'lib/quaternion_c2/classification.rb', line 34 def real? false end |
#rect ⇒ [Complex, Complex] Also known as: rectangular
Returns an array of two complex numbers.
106 107 108 |
# File 'lib/quaternion_c2/conversion.rb', line 106 def rect [@a, @b] end |
#to_c ⇒ Complex
Returns the value as a complex if possible (the discarded part should be exactly zero).
27 28 29 30 31 32 |
# File 'lib/quaternion_c2/to_type.rb', line 27 def to_c unless __exact_zero__(@b) raise RangeError, "can't convert #{self} into Complex" end @a end |
#to_f ⇒ Float
Returns the value as a float if possible (the imaginary part should be exactly zero).
|
|
# File 'lib/quaternion_c2/to_type.rb', line 34
|
#to_i ⇒ Integer
Returns the value as an integer if possible (the imaginary part should be exactly zero).
|
|
# File 'lib/quaternion_c2/to_type.rb', line 52
|
#to_q ⇒ self
Returns self.
17 18 19 |
# File 'lib/quaternion_c2/to_type.rb', line 17 def to_q self end |
#to_r ⇒ Rational
Returns the value as a rational if possible (the imaginary part should be exactly zero).
|
|
# File 'lib/quaternion_c2/to_type.rb', line 43
|
#to_s ⇒ String
Returns the value as a string.
85 86 87 |
# File 'lib/quaternion_c2/to_type.rb', line 85 def to_s __format__(:to_s) end |