gonum.org/v1/gonum@v0.14.0/num/dualquat/dual.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package dualquat 6 7 import ( 8 "fmt" 9 "strings" 10 11 "gonum.org/v1/gonum/num/dual" 12 "gonum.org/v1/gonum/num/quat" 13 ) 14 15 // Number is a float64 precision dual quaternion. A dual quaternion 16 // is a hypercomplex number composed of two quaternions, q₀+q₂ϵ, 17 // where ϵ²=0, but ϵ≠0. Here, q₀ is termed the real and q₂ the dual. 18 type Number struct { 19 Real, Dual quat.Number 20 } 21 22 var zeroQuat quat.Number 23 24 // Format implements fmt.Formatter. 25 func (d Number) Format(fs fmt.State, c rune) { 26 prec, pOk := fs.Precision() 27 if !pOk { 28 prec = -1 29 } 30 width, wOk := fs.Width() 31 if !wOk { 32 width = -1 33 } 34 switch c { 35 case 'v': 36 if fs.Flag('#') { 37 fmt.Fprintf(fs, "%T{Real:%#v, Dual:%#v}", d, d.Real, d.Dual) 38 return 39 } 40 if fs.Flag('+') { 41 fmt.Fprintf(fs, "{Real:%+v, Dual:%+v}", d.Real, d.Dual) 42 return 43 } 44 c = 'g' 45 prec = -1 46 fallthrough 47 case 'e', 'E', 'f', 'F', 'g', 'G': 48 fre := fmtString(fs, c, prec, width, false) 49 fim := fmtString(fs, c, prec, width, true) 50 fmt.Fprintf(fs, fmt.Sprintf("(%s+%[2]sϵ)", fre, fim), d.Real, d.Dual) 51 default: 52 fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, d) 53 return 54 } 55 } 56 57 // This is horrible, but it's what we have. 58 func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { 59 var b strings.Builder 60 b.WriteByte('%') 61 for _, f := range "0+- " { 62 if fs.Flag(int(f)) || (f == '+' && wantPlus) { 63 b.WriteByte(byte(f)) 64 } 65 } 66 if width >= 0 { 67 fmt.Fprint(&b, width) 68 } 69 if prec >= 0 { 70 b.WriteByte('.') 71 if prec > 0 { 72 fmt.Fprint(&b, prec) 73 } 74 } 75 b.WriteRune(c) 76 return b.String() 77 } 78 79 // Add returns the sum of x and y. 80 func Add(x, y Number) Number { 81 return Number{ 82 Real: quat.Add(x.Real, y.Real), 83 Dual: quat.Add(x.Dual, y.Dual), 84 } 85 } 86 87 // Sub returns the difference of x and y, x-y. 88 func Sub(x, y Number) Number { 89 return Number{ 90 Real: quat.Sub(x.Real, y.Real), 91 Dual: quat.Sub(x.Dual, y.Dual), 92 } 93 } 94 95 // Mul returns the dual product of x and y. 96 func Mul(x, y Number) Number { 97 return Number{ 98 Real: quat.Mul(x.Real, y.Real), 99 Dual: quat.Add(quat.Mul(x.Real, y.Dual), quat.Mul(x.Dual, y.Real)), 100 } 101 } 102 103 // Inv returns the dual inverse of d. 104 func Inv(d Number) Number { 105 return Number{ 106 Real: quat.Inv(d.Real), 107 Dual: quat.Scale(-1, quat.Mul(d.Dual, quat.Inv(quat.Mul(d.Real, d.Real)))), 108 } 109 } 110 111 // Conj returns the dual quaternion conjugate of d₁+d₂ϵ, d̅₁-d̅₂ϵ. 112 func Conj(d Number) Number { 113 return Number{ 114 Real: quat.Conj(d.Real), 115 Dual: quat.Scale(-1, quat.Conj(d.Dual)), 116 } 117 } 118 119 // ConjDual returns the dual conjugate of d₁+d₂ϵ, d₁-d₂ϵ. 120 func ConjDual(d Number) Number { 121 return Number{ 122 Real: d.Real, 123 Dual: quat.Scale(-1, d.Dual), 124 } 125 } 126 127 // ConjQuat returns the quaternion conjugate of d₁+d₂ϵ, d̅₁+d̅₂ϵ. 128 func ConjQuat(d Number) Number { 129 return Number{ 130 Real: quat.Conj(d.Real), 131 Dual: quat.Conj(d.Dual), 132 } 133 } 134 135 // Scale returns d scaled by f. 136 func Scale(f float64, d Number) Number { 137 return Number{Real: quat.Scale(f, d.Real), Dual: quat.Scale(f, d.Dual)} 138 } 139 140 // Abs returns the absolute value of d. 141 func Abs(d Number) dual.Number { 142 return dual.Number{ 143 Real: quat.Abs(d.Real), 144 Emag: quat.Abs(d.Dual), 145 } 146 }