dualcmplx

package
v0.8.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2023 License: BSD-3-Clause Imports: 4 Imported by: 0

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"

	"github.com/ArkaGPL/gonum/floats/scalar"
	"github.com/ArkaGPL/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"

	"github.com/ArkaGPL/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"

	"github.com/ArkaGPL/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"

	"github.com/ArkaGPL/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"

	"github.com/ArkaGPL/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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Abs

func Abs(d Number) float64

Abs returns the absolute value of d.

Types

type Number

type Number struct {
	Real, Dual complex128
}

Number is a float64 precision anti-commutative dual complex number.

func Add

func Add(x, y Number) Number

Add returns the sum of x and y.

func Conj

func Conj(d Number) Number

Conj returns the conjugate of d₁+d₂ϵ, d̅₁+d₂ϵ.

func Exp

func Exp(d Number) Number

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 Inv

func Inv(d Number) Number

Inv returns the dual inverse of d.

func Log

func Log(d Number) Number

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 Mul

func Mul(x, y Number) Number

Mul returns the dual product of x and y, x×y.

func Pow

func Pow(d, p Number) Number

Pow returns d**p, the base-d exponential of p.

func PowReal

func PowReal(d Number, p float64) Number

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)

func Scale

func Scale(f float64, d Number) Number

Scale returns d scaled by f.

func Sqrt

func Sqrt(d Number) Number

Sqrt returns the square root of d.

Special cases are:

Sqrt(+Inf) = +Inf
Sqrt(±0) = (±0+Infϵ)
Sqrt(x < 0) = NaN
Sqrt(NaN) = NaN

func Sub

func Sub(x, y Number) Number

Sub returns the difference of x and y, x-y.

func (Number) Format

func (d Number) Format(fs fmt.State, c rune)

Format implements fmt.Formatter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL