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  }