Documentation ¶
Overview ¶
Package dualcmplx provides the anti-commutative dual complex numeric type and functions.
See https://arxiv.org/abs/1601.01754v1 for details.
Example ¶
package main import ( "fmt" "math" "gonum.org/v1/gonum/floats/scalar" "gonum.org/v1/gonum/num/dualcmplx" ) // point is a 2-dimensional point/vector. type point struct { x, y float64 } // raise raises the dimensionality of a point to a complex. func raise(p point) complex128 { return complex(p.x, p.y) } // raiseDual raises the dimensionality of a point to a dual complex number. func raiseDual(p point) dualcmplx.Number { return dualcmplx.Number{ Real: 1, Dual: complex(p.x, p.y), } } // transform performs the transformation of p by the given dual complex numbers. // The transformations are normalized to unit vectors. func transform(p point, by ...dualcmplx.Number) point { if len(by) == 0 { return p } // Ensure the modulus of by is correctly scaled. for i := range by { if len := dualcmplx.Abs(by[i]); len != 1 { by[i].Real *= complex(1/len, 0) } } // Perform the transformations. z := by[0] for _, o := range by[1:] { z = dualcmplx.Mul(o, z) } pp := dualcmplx.Mul(dualcmplx.Mul(z, raiseDual(p)), dualcmplx.Conj(z)) // Extract the point. return point{x: real(pp.Dual), y: imag(pp.Dual)} } func main() { // Translate a 1×1 square by [3, 4] and rotate it 90° around the // origin. fmt.Println("square:") // Construct a displacement. displace := dualcmplx.Number{ Real: 1, Dual: 0.5 * raise(point{3, 4}), } // Construct a rotation. alpha := math.Pi / 2 rotate := dualcmplx.Number{Real: complex(math.Cos(alpha/2), math.Sin(alpha/2))} for i, p := range []point{ {x: 0, y: 0}, {x: 0, y: 1}, {x: 1, y: 0}, {x: 1, y: 1}, } { pp := transform(p, displace, rotate, ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } // Rotate a line segment 90° around its lower end [2, 2]. fmt.Println("\nline segment:") // Construct a displacement to the origin from the lower end... origin := dualcmplx.Number{ Real: 1, Dual: 0.5 * raise(point{-2, -2}), } // ... and back from the origin to the lower end. replace := dualcmplx.Number{ Real: 1, Dual: -origin.Dual, } for i, p := range []point{ {x: 2, y: 2}, {x: 2, y: 3}, } { pp := transform(p, origin, // Displace to origin. rotate, // Rotate around axis. replace, // Displace back to original location. ) // Clean up floating point error for clarity. pp.x = scalar.Round(pp.x, 2) pp.y = scalar.Round(pp.y, 2) fmt.Printf(" %d %+v -> %+v\n", i, p, pp) } }
Output: square: 0 {x:0 y:0} -> {x:-4 y:3} 1 {x:0 y:1} -> {x:-5 y:3} 2 {x:1 y:0} -> {x:-4 y:4} 3 {x:1 y:1} -> {x:-5 y:4} line segment: 0 {x:2 y:2} -> {x:2 y:2} 1 {x:2 y:3} -> {x:1 y:2}
Example (Displace) ¶
package main import ( "fmt" "gonum.org/v1/gonum/num/dualcmplx" ) func main() { // Displace a point [3, 4] by [4, 3]. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(d, p), dualcmplx.Conj(d)).Dual) }
Output: (7+7i)
Example (DisplaceAndRotate) ¶
package main import ( "fmt" "math" "gonum.org/v1/gonum/num/dualcmplx" ) func main() { // Displace a point [3, 4] by [4, 3] and then rotate // by 90° around the origin. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} // Rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} // Combine the rotation and displacement so // the displacement is performed first. q := dualcmplx.Mul(r, d) fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(q, p), dualcmplx.Conj(q)).Dual) }
Output: (-7+7i)
Example (Rotate) ¶
package main import ( "fmt" "math" "gonum.org/v1/gonum/num/dualcmplx" ) func main() { // Rotate a point [3, 4] by 90° around the origin. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Half the rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(r, p), dualcmplx.Conj(r)).Dual) }
Output: (-4+3i)
Example (RotateAndDisplace) ¶
package main import ( "fmt" "math" "gonum.org/v1/gonum/num/dualcmplx" ) func main() { // Rotate a point [3, 4] by 90° around the origin and then // displace by [4, 3]. // Point to be transformed in the dual imaginary vector. p := dualcmplx.Number{Real: 1, Dual: 3 + 4i} // Displacement vector, half [4, 3], in the dual imaginary vector. d := dualcmplx.Number{Real: 1, Dual: 2 + 1.5i} // Rotation in the real complex number. r := dualcmplx.Number{Real: complex(math.Cos(math.Pi/4), math.Sin(math.Pi/4))} // Combine the rotation and displacement so // the displacement is performed first. q := dualcmplx.Mul(d, r) fmt.Printf("%.0f\n", dualcmplx.Mul(dualcmplx.Mul(q, p), dualcmplx.Conj(q)).Dual) }
Output: (0+6i)
Index ¶
- func Abs(d Number) float64
- type Number
- func Add(x, y Number) Number
- func Conj(d Number) Number
- func Exp(d Number) Number
- func Inv(d Number) Number
- func Log(d Number) Number
- func Mul(x, y Number) Number
- func Pow(d, p Number) Number
- func PowReal(d Number, p float64) Number
- func Scale(f float64, d Number) Number
- func Sqrt(d Number) Number
- func Sub(x, y Number) Number
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Number ¶
type Number struct {
Real, Dual complex128
}
Number is a float64 precision anti-commutative dual complex number.
func Exp ¶
Exp returns e**q, the base-e exponential of d.
Special cases are:
Exp(+Inf) = +Inf Exp(NaN) = NaN
Very large values overflow to 0 or +Inf. Very small values underflow to 1.
func Log ¶
Log returns the natural logarithm of d.
Special cases are:
Log(+Inf) = (+Inf+0ϵ) Log(0) = (-Inf±Infϵ) Log(x < 0) = NaN Log(NaN) = NaN
func PowReal ¶
PowReal returns d**p, the base-d exponential of p.
Special cases are (in order):
PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x Pow(0+xϵ, y) = 0+Infϵ for all y < 1. Pow(0+xϵ, y) = 0 for all y > 1. PowReal(x, ±0) = 1 for any x PowReal(1+xϵ, y) = 1+xyϵ for any y Pow(Inf, y) = +Inf+NaNϵ for y > 0 Pow(Inf, y) = +0+NaNϵ for y < 0 PowReal(x, 1) = x for any x PowReal(NaN+xϵ, y) = NaN+NaNϵ PowReal(x, NaN) = NaN+NaNϵ PowReal(-1, ±Inf) = 1 PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 PowReal(x, +Inf) = +0+NaNϵ for |x| < 1 PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 PowReal(+Inf, y) = +Inf for y > 0 PowReal(+Inf, y) = +0 for y < 0 PowReal(-Inf, y) = Pow(-0, -y)
Click to show internal directories.
Click to hide internal directories.