gonum.org/v1/gonum@v0.14.0/num/dualquat/dual_fike.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  // Derived from code by Jeffrey A. Fike at http://adl.stanford.edu/hyperdual/
     6  
     7  // The MIT License (MIT)
     8  //
     9  // Copyright (c) 2006 Jeffrey A. Fike
    10  //
    11  // Permission is hereby granted, free of charge, to any person obtaining a copy
    12  // of this software and associated documentation files (the "Software"), to deal
    13  // in the Software without restriction, including without limitation the rights
    14  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    15  // copies of the Software, and to permit persons to whom the Software is
    16  // furnished to do so, subject to the following conditions:
    17  //
    18  // The above copyright notice and this permission notice shall be included in
    19  // all copies or substantial portions of the Software.
    20  //
    21  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    22  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    23  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    24  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    25  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    26  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    27  // THE SOFTWARE.
    28  
    29  package dualquat
    30  
    31  import (
    32  	"math"
    33  
    34  	"gonum.org/v1/gonum/num/quat"
    35  )
    36  
    37  // PowReal returns d**p, the base-d exponential of p.
    38  //
    39  // Special cases are (in order):
    40  //
    41  //	PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x
    42  //	PowReal(x, ±0) = 1 for any x
    43  //	PowReal(1+xϵ, y) = 1+xyϵ for any y
    44  //	PowReal(x, 1) = x for any x
    45  //	PowReal(NaN+xϵ, y) = NaN+NaNϵ
    46  //	PowReal(x, NaN) = NaN+NaNϵ
    47  //	PowReal(±0, y) = ±Inf for y an odd integer < 0
    48  //	PowReal(±0, -Inf) = +Inf
    49  //	PowReal(±0, +Inf) = +0
    50  //	PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer
    51  //	PowReal(±0, y) = ±0 for y an odd integer > 0
    52  //	PowReal(±0, y) = +0 for finite y > 0 and not an odd integer
    53  //	PowReal(-1, ±Inf) = 1
    54  //	PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1
    55  //	PowReal(x+yϵ, +Inf) = +Inf for |x| > 1
    56  //	PowReal(x, -Inf) = +0+NaNϵ for |x| > 1
    57  //	PowReal(x, +Inf) = +0+NaNϵ for |x| < 1
    58  //	PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1
    59  //	PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1
    60  //	PowReal(+Inf, y) = +Inf for y > 0
    61  //	PowReal(+Inf, y) = +0 for y < 0
    62  //	PowReal(-Inf, y) = Pow(-0, -y)
    63  func PowReal(d Number, p float64) Number {
    64  	switch {
    65  	case p == 0:
    66  		switch {
    67  		case quat.IsNaN(d.Real):
    68  			return Number{Real: quat.Number{Real: 1}, Dual: quat.NaN()}
    69  		case d.Real == zeroQuat, quat.IsInf(d.Real):
    70  			return Number{Real: quat.Number{Real: 1}}
    71  		}
    72  	case p == 1:
    73  		return d
    74  	case math.IsInf(p, 1):
    75  		if Abs(d).Real > 1 {
    76  			if d.Dual == zeroQuat {
    77  				return Number{Real: quat.Inf(), Dual: quat.NaN()}
    78  			}
    79  			return Number{Real: quat.Inf(), Dual: quat.Inf()}
    80  		}
    81  		return Number{Real: zeroQuat, Dual: quat.NaN()}
    82  	case math.IsInf(p, -1):
    83  		if Abs(d).Real > 1 {
    84  			return Number{Real: zeroQuat, Dual: quat.NaN()}
    85  		}
    86  		if d.Dual == zeroQuat {
    87  			return Number{Real: quat.Inf(), Dual: quat.NaN()}
    88  		}
    89  		return Number{Real: quat.Inf(), Dual: quat.Inf()}
    90  	}
    91  	deriv := quat.Mul(quat.Number{Real: p}, quat.Pow(d.Real, quat.Number{Real: p - 1}))
    92  	return Number{
    93  		Real: quat.Pow(d.Real, quat.Number{Real: p}),
    94  		Dual: quat.Mul(d.Dual, deriv),
    95  	}
    96  }
    97  
    98  // Pow return d**p, the base-d exponential of p.
    99  func Pow(d, p Number) Number {
   100  	return Exp(Mul(p, Log(d)))
   101  }
   102  
   103  // Sqrt returns the square root of d
   104  //
   105  // Special cases are:
   106  //
   107  //	Sqrt(+Inf) = +Inf
   108  //	Sqrt(±0) = (±0+Infϵ)
   109  //	Sqrt(x < 0) = NaN
   110  //	Sqrt(NaN) = NaN
   111  func Sqrt(d Number) Number {
   112  	return PowReal(d, 0.5)
   113  }
   114  
   115  // Exp returns e**d, the base-e exponential of d.
   116  //
   117  // Special cases are:
   118  //
   119  //	Exp(+Inf) = +Inf
   120  //	Exp(NaN) = NaN
   121  //
   122  // Very large values overflow to 0 or +Inf.
   123  // Very small values underflow to 1.
   124  func Exp(d Number) Number {
   125  	fnDeriv := quat.Exp(d.Real)
   126  	return Number{
   127  		Real: fnDeriv,
   128  		Dual: quat.Mul(fnDeriv, d.Dual),
   129  	}
   130  }
   131  
   132  // Log returns the natural logarithm of d.
   133  //
   134  // Special cases are:
   135  //
   136  //	Log(+Inf) = (+Inf+0ϵ)
   137  //	Log(0) = (-Inf±Infϵ)
   138  //	Log(x < 0) = NaN
   139  //	Log(NaN) = NaN
   140  func Log(d Number) Number {
   141  	switch {
   142  	case d.Real == zeroQuat:
   143  		return Number{
   144  			Real: quat.Log(d.Real),
   145  			Dual: quat.Inf(),
   146  		}
   147  	case quat.IsInf(d.Real):
   148  		return Number{
   149  			Real: quat.Log(d.Real),
   150  			Dual: zeroQuat,
   151  		}
   152  	}
   153  	return Number{
   154  		Real: quat.Log(d.Real),
   155  		Dual: quat.Mul(d.Dual, quat.Inv(d.Real)),
   156  	}
   157  }