github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/gnum/gnum.go (about)

     1  // Package gnum provides generic numerical functions.
     2  package gnum
     3  
     4  import (
     5  	"fmt"
     6  	"math"
     7  
     8  	"golang.org/x/exp/constraints"
     9  )
    10  
    11  // Number is a constraint that contains comparable numbers.
    12  type Number interface {
    13  	constraints.Float | constraints.Integer
    14  }
    15  
    16  // Max returns the maximal value in the slice or zero if the slice is empty.
    17  func Max[S ~[]N, N constraints.Ordered](s S) N {
    18  	var e N
    19  	for i, v := range s {
    20  		if i == 0 || v > e {
    21  			e = v
    22  		}
    23  	}
    24  	return e
    25  }
    26  
    27  // Min returns the maximal value in the slice or zero if the slice is empty.
    28  func Min[S ~[]N, N constraints.Ordered](s S) N {
    29  	var e N
    30  	for i, v := range s {
    31  		if i == 0 || v < e {
    32  			e = v
    33  		}
    34  	}
    35  	return e
    36  }
    37  
    38  // Abs returns the absolute value of n.
    39  func Abs[N Number](n N) N {
    40  	if n < 0 {
    41  		return -n
    42  	}
    43  	return n
    44  }
    45  
    46  // Diff returns the non-negative difference between a and b.
    47  func Diff[N Number](a, b N) N {
    48  	if a > b {
    49  		return a - b
    50  	}
    51  	return b - a
    52  }
    53  
    54  // Sum returns the sum of the slice.
    55  func Sum[S ~[]N, N Number](a S) N {
    56  	var sum N
    57  	for _, v := range a {
    58  		sum += v
    59  	}
    60  	return sum
    61  }
    62  
    63  // Mean returns the average of the slice.
    64  func Mean[S ~[]N, N Number](a S) float64 {
    65  	return float64(Sum(a)) / float64(len(a))
    66  }
    67  
    68  // Cov returns the covariance of a and b.
    69  func Cov[S ~[]N, N Number](a, b S) float64 {
    70  	assertMatchingLengths(a, b)
    71  	ma := Mean(a)
    72  	mb := Mean(b)
    73  	cov := 0.0
    74  	for i := range a {
    75  		cov += (float64(a[i]) - ma) * (float64(b[i]) - mb)
    76  	}
    77  	cov /= float64(len(a))
    78  	return cov
    79  }
    80  
    81  // Var returns the variance of a.
    82  func Var[S ~[]N, N Number](a S) float64 {
    83  	return Cov(a, a)
    84  }
    85  
    86  // Std returns the standard deviation of a.
    87  func Std[S ~[]N, N Number](a S) float64 {
    88  	return math.Sqrt(Var(a))
    89  }
    90  
    91  // Corr returns the Pearson correlation between the a and b.
    92  func Corr[S ~[]N, N Number](a, b S) float64 {
    93  	return Cov(a, b) / Std(a) / Std(b)
    94  }
    95  
    96  // Entropy returns the Shannon-entropy of a.
    97  // The elements in a don't have to sum up to 1.
    98  func Entropy[S ~[]N, N Number](a S) float64 {
    99  	sum := float64(Sum(a))
   100  	result := 0.0
   101  	for i, v := range a {
   102  		if v < 0.0 {
   103  			panic(fmt.Sprintf("negative value at position %d: %v",
   104  				i, v))
   105  		}
   106  		if v == 0 {
   107  			continue
   108  		}
   109  		p := float64(v) / sum
   110  		result -= p * math.Log2(p)
   111  	}
   112  	return result
   113  }