summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-12-28 23:27:58 +0700
committerShulhan <ms@kilabit.info>2024-12-29 00:06:17 +0700
commitec3fac32072a396a02b699065cb091ab292b9381 (patch)
tree88c14e9d35d18fe7ef9483c386aa346c6c8afa2d
parent7a57091317cd86b9c88f4c6b5127c76bee0f6ede (diff)
downloadpakakeh.go-ec3fac32072a396a02b699065cb091ab292b9381.tar.xz
all: merge package "lib/floats64" into "slices"
Now that Go has type parameter, we can use it to use the same function that accept different types for working with slice of float64.
-rw-r--r--lib/floats64/floats64.go354
-rw-r--r--lib/floats64/floats64_bench_test.go18
-rw-r--r--lib/floats64/floats64_test.go375
-rw-r--r--lib/mining/classifier/crf/crf.go8
-rw-r--r--lib/mining/classifier/rf/rf.go7
-rw-r--r--lib/mining/classifier/runtime.go3
-rw-r--r--lib/mining/gain/gini/gini.go4
-rw-r--r--lib/mining/gain/gini/ginifloat.go10
-rw-r--r--lib/slices/benchmark_test.go22
-rw-r--r--lib/slices/slices_float64_test.go464
10 files changed, 500 insertions, 765 deletions
diff --git a/lib/floats64/floats64.go b/lib/floats64/floats64.go
deleted file mode 100644
index 1781abb2..00000000
--- a/lib/floats64/floats64.go
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright 2018, Shulhan <ms@kilabit.info>. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package floats64 provide a library for working with slice of 64 bit float.
-package floats64
-
-import "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
-
-// Count number of class in data.
-func Count(d []float64, class float64) (count int) {
- if len(d) == 0 {
- return
- }
- for x := 0; x < len(d); x++ {
- if d[x] == class {
- count++
- }
- }
- return
-}
-
-// Counts count class in data and return each of the counter.
-//
-// For example, if data is "[1,1,2]" and class is "[1,2]", this function will
-// return "[2,1]".
-func Counts(d, classes []float64) (counts []int) {
- if len(classes) == 0 {
- return
- }
-
- counts = make([]int, len(classes))
-
- for x, c := range classes {
- counts[x] = Count(d, c)
- }
- return
-}
-
-// IndirectSort sort the data and return the sorted index.
-func IndirectSort(d []float64, asc bool) (sortedIdx []int) {
- dlen := len(d)
-
- sortedIdx = make([]int, dlen)
- for i := 0; i < dlen; i++ {
- sortedIdx[i] = i
- }
-
- InplaceMergesort(d, sortedIdx, 0, dlen, asc)
-
- return
-}
-
-// InplaceMergesort in-place merge-sort without memory allocation.
-func InplaceMergesort(d []float64, idx []int, l, r int, asc bool) {
- // (0) If data length == Threshold, then
- if l+7 >= r {
- // (0.1) use insertion sort.
- InplaceInsertionSort(d, idx, l, r, asc)
- return
- }
-
- // (1) Divide into left and right.
- res := (r + l) % 2
- c := (r + l) / 2
- if res == 1 {
- c++
- }
-
- // (2) Sort left.
- InplaceMergesort(d, idx, l, c, asc)
-
- // (3) Sort right.
- InplaceMergesort(d, idx, c, r, asc)
-
- // (4) Merge sorted left and right.
- if asc {
- if d[c-1] <= d[c] {
- // (4.1) If the last element of the left is lower then
- // the first element of the right, i.e. [1 2] [3 4];
- // no merging needed, return immediately.
- return
- }
- } else {
- if d[c-1] >= d[c] {
- return
- }
- }
-
- inplaceMerge(d, idx, l, c, r, asc)
-}
-
-// InplaceInsertionSort will sort the data using insertion-sort algorithm.
-//
-// Parameters:
-// `data` is slice that will be sorted,
-// `idx` is indices of data,
-// `l` is starting index of slice to be sorted, and
-// `r` is end index of slice to be sorted.
-func InplaceInsertionSort(d []float64, ids []int, l, r int, asc bool) {
- for x := l; x < r; x++ {
- for y := x + 1; y < r; y++ {
- if asc {
- if d[x] > d[y] {
- slices.Swap(ids, x, y)
- Swap(d, x, y)
- }
- } else {
- if d[x] < d[y] {
- slices.Swap(ids, x, y)
- Swap(d, x, y)
- }
- }
- }
- }
-}
-
-// IsExist will return true if value `v` exist in slice of `d`,
-// otherwise it will return false.
-func IsExist(d []float64, v float64) bool {
- for _, x := range d {
- if v == x {
- return true
- }
- }
- return false
-}
-
-// Max find the maximum value in slice and and return its value and index.
-//
-// If data is empty, it will return false in ok.
-//
-// Example, given data: [0.0 0.1 0.2 0.2 0.4], it will return 0.4 as max and 4
-// as index of maximum value.
-func Max(d []float64) (v float64, i int, ok bool) {
- if len(d) == 0 {
- return 0, 0, false
- }
- v = d[0]
- i = 0
- for x := 1; x < len(d); x++ {
- if d[x] > v {
- v = d[x]
- i = x
- }
- }
- return v, i, true
-}
-
-// MaxRange find the (last) maximum value in slice between index "l" and "r".
-//
-// WARNING: This function does not check index out of range.
-func MaxRange(d []float64, l, r int) (m int) {
- maxv := d[l]
- m = l
- for l++; l < r; l++ {
- if d[l] >= maxv {
- maxv = d[l]
- m = l
- }
- }
- return m
-}
-
-// MaxCountOf will count number of occurrence of each element of
-// classes in data and return the class with maximum count.
-//
-// If `classes` is empty, it will return -1 and false.
-// If `data` is empty, it will return -2 and false.
-// If classes has the same count value, then the first max in the class will be
-// returned.
-//
-// For example, given a data [5, 6, 5, 6, 5] and classes [5, 6, 7], the
-// function will count 5 as 3, 6 as 2, and 7 as 0.
-// Since frequency of 5 is greater than 6 and 7, then it will return `5` and
-// `true`.
-func MaxCountOf(d, classes []float64) (float64, bool) {
- if len(classes) == 0 {
- return -1, false
- }
- if len(d) == 0 {
- return -2, false
- }
-
- counts := Counts(d, classes)
-
- _, maxi := slices.Max2(counts)
-
- return classes[maxi], true
-}
-
-// Min find the minimum value in slice and and return it with their index.
-//
-// If data is empty, return 0 in value and index, and false in ok.
-//
-// Example, given data: [0.0 0.1 0.2 0.2 0.4], it will return 0 as min and 0
-// as index of minimum value.
-func Min(d []float64) (v float64, i int, ok bool) {
- if len(d) == 0 {
- return 0, 0, false
- }
- v = d[0]
- i = 0
- for x := 1; x < len(d); x++ {
- if d[x] < v {
- v = d[x]
- i = x
- }
- }
- return v, i, true
-}
-
-// MinRange find the (last) minimum value in slice between index "l" and "r".
-//
-// WARNING: This function does not check index out of range.
-func MinRange(d []float64, l, r int) (m int) {
- min := d[l]
- m = l
- for l++; l < r; l++ {
- if d[l] <= min {
- min = d[l]
- m = l
- }
- }
- return
-}
-
-// SortByIndex sort the slice of float using sorted index.
-func SortByIndex(d *[]float64, sortedListID []int) {
- newd := make([]float64, len(*d))
-
- for i := range sortedListID {
- newd[i] = (*d)[sortedListID[i]]
- }
-
- (*d) = newd
-}
-
-// Sum value of slice.
-func Sum(d []float64) (sum float64) {
- for x := 0; x < len(d); x++ {
- sum += d[x]
- }
- return
-}
-
-// Swap swap two indices value of 64bit float.
-func Swap(d []float64, x, y int) {
- if x == y || len(d) <= 1 || x > len(d) || y > len(d) {
- return
- }
- d[x], d[y] = d[y], d[x]
-}
-
-// Let `x` be the first index of left-side, `y` be the first index of
-// the right-side, and `r` as length of slice `d`
-func inplaceMerge(d []float64, idx []int, x, y, r int, asc bool) {
- var ylast int
-
- // (4.3) Loop until either x or y reached the maximum slice.
- for x < r && y < r {
- // (4.3.1) IF DATA[x] <= DATA[y]
- if asc {
- if d[x] <= d[y] {
- x++
-
- // (4.3.1.2) IF x >= y THEN GOTO 4.3.4
- if x >= y {
- goto next
- }
-
- // (4.3.1.3) GOTO 4.3
- continue
- }
- } else {
- if d[x] >= d[y] {
- x++
-
- if x >= y {
- goto next
- }
-
- continue
- }
- }
-
- // (4.3.2) LET YLAST := the next DATA[y] that is less DATA[x]
- ylast = moveY(d, x, y, r, asc)
-
- // (4.3.3) SWAP DATA, X, Y, YLAST
- multiswap(d, idx, x, y, ylast)
-
- next:
- // (4.3.4) LET Y := the minimum value between x and r on `d`
- minY(d, &x, &y, r, asc)
- }
-}
-
-// (4.3.4) LET Y := the minimum value between x and r on `d`.
-func minY(d []float64, x, y *int, r int, asc bool) {
- for *x < r {
- if asc {
- *y = MinRange(d, *x, r)
- } else {
- *y = MaxRange(d, *x, r)
- }
-
- if *y != *x {
- break
- }
- (*x)++
- }
-}
-
-func moveY(d []float64, x, y, r int, asc bool) int {
- yorg := y
- y++
- for y < r {
- if asc {
- if d[y] >= d[x] {
- break
- }
- if d[y] < d[yorg] {
- break
- }
- } else {
- if d[y] <= d[x] {
- break
- }
- if d[y] > d[yorg] {
- break
- }
- }
- y++
- }
- return y
-}
-
-func multiswap(d []float64, idx []int, x, y, ylast int) int {
- for y < ylast {
- slices.Swap(idx, x, y)
- Swap(d, x, y)
- x++
- y++
- if y >= ylast {
- return y
- }
- if d[x] <= d[y] {
- return y
- }
- }
-
- return y
-}
diff --git a/lib/floats64/floats64_bench_test.go b/lib/floats64/floats64_bench_test.go
deleted file mode 100644
index 2ca4547a..00000000
--- a/lib/floats64/floats64_bench_test.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018, Shulhan <ms@kilabit.info>. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package floats64
-
-import (
- "testing"
-)
-
-func BenchmarkInplaceMergesort(b *testing.B) {
- size := len(inSorts[6])
- ids := make([]int, size)
-
- for i := 0; i < b.N; i++ {
- InplaceMergesort(inSorts[6], ids, 0, size, true)
- }
-}
diff --git a/lib/floats64/floats64_test.go b/lib/floats64/floats64_test.go
deleted file mode 100644
index 15d5e2c2..00000000
--- a/lib/floats64/floats64_test.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2018, Shulhan <ms@kilabit.info>. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package floats64
-
-import (
- "fmt"
- "testing"
-
- "git.sr.ht/~shulhan/pakakeh.go/lib/numbers"
- "git.sr.ht/~shulhan/pakakeh.go/lib/test"
-)
-
-var (
- d = [][]float64{
- {},
- {0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
- {0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
- {1, 1, 2, 2, 3, 1, 2},
- }
- dSorted = [][]float64{
- {},
- {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9},
- {0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.1, 0.1, 0.1},
- {1, 1, 1, 2, 2, 2, 3},
- }
- dSortedDesc = [][]float64{
- {},
- {0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0},
- {0.1, 0.1, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
- {3, 2, 2, 2, 1, 1, 1},
- }
-)
-
-func TestMaxEmpty(t *testing.T) {
- gotv, goti, gotok := Max(d[0])
-
- test.Assert(t, "", float64(0), gotv)
- test.Assert(t, "", 0, goti)
- test.Assert(t, "", false, gotok)
-}
-
-func TestMax(t *testing.T) {
- gotv, goti, gotok := Max(d[1])
-
- test.Assert(t, "", float64(0.9), gotv)
- test.Assert(t, "", 4, goti)
- test.Assert(t, "", true, gotok)
-}
-
-func TestMinEmpty(t *testing.T) {
- gotv, goti, gotok := Min(d[0])
-
- test.Assert(t, "", gotv, float64(0))
- test.Assert(t, "", goti, 0)
- test.Assert(t, "", gotok, false)
-}
-
-func TestMin(t *testing.T) {
- gotv, goti, gotok := Min(d[1])
-
- test.Assert(t, "", gotv, float64(0.0))
- test.Assert(t, "", goti, 5)
- test.Assert(t, "", gotok, true)
-}
-
-func TestSum(t *testing.T) {
- got := Sum(d[1])
-
- test.Assert(t, "", float64(4.5), numbers.Float64Round(got, 1))
-}
-
-func TestCount(t *testing.T) {
- got := Count(d[0], 0)
-
- test.Assert(t, "", 0, got)
-
- got = Count(d[1], 0.1)
-
- test.Assert(t, "", 1, got)
-
- got = Count(d[2], 0.1)
-
- test.Assert(t, "", 4, got)
-
- got = Count(d[3], 0.1)
-
- test.Assert(t, "", 0, got)
-
- got = Count(d[3], 3)
-
- test.Assert(t, "", 1, got)
-}
-
-func TestCountsEmpty(t *testing.T) {
- classes := []float64{1, 2, 3}
- exp := []int{0, 0, 0}
-
- got := Counts(d[0], classes)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestCountsEmptyClasses(t *testing.T) {
- classes := []float64{}
- var exp []int
-
- got := Counts(d[1], classes)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestCounts(t *testing.T) {
- classes := []float64{1, 2, 3}
- exp := []int{3, 3, 1}
-
- got := Counts(d[3], classes)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestMaxCountOf(t *testing.T) {
- classes := []float64{0, 1}
- exp := float64(0)
- got, _ := MaxCountOf(d[2], classes)
-
- test.Assert(t, "", exp, got)
-
- // Swap the class values.
- classes = []float64{1, 0}
- got, _ = MaxCountOf(d[2], classes)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestSwapEmpty(t *testing.T) {
- exp := []float64{}
-
- Swap(d[0], 1, 6)
-
- test.Assert(t, "", exp, d[0])
-}
-
-func TestSwapEqual(t *testing.T) {
- in := make([]float64, len(d[1]))
- copy(in, d[1])
-
- exp := make([]float64, len(in))
- copy(exp, in)
-
- Swap(in, 1, 1)
-
- test.Assert(t, "", exp, in)
-}
-
-func TestSwapOutOfRange(t *testing.T) {
- in := make([]float64, len(d[1]))
- copy(in, d[1])
-
- exp := make([]float64, len(in))
- copy(exp, in)
-
- Swap(in, 1, 100)
-
- test.Assert(t, "", exp, in)
-}
-
-func TestSwap(t *testing.T) {
- in := make([]float64, len(d[1]))
- copy(in, d[1])
-
- exp := make([]float64, len(in))
- copy(exp, in)
-
- Swap(in, 0, len(in)-1)
-
- exp[0], exp[len(exp)-1] = exp[len(exp)-1], exp[0]
-
- test.Assert(t, "", exp, in)
-}
-
-func TestIsExist(t *testing.T) {
- got := IsExist(d[0], 0)
-
- test.Assert(t, "", false, got)
-
- got = IsExist(d[1], float64(0))
-
- test.Assert(t, "", true, got)
-
- got = IsExist(d[1], float64(0.01))
-
- test.Assert(t, "", false, got)
-}
-
-func TestInplaceInsertionSort(t *testing.T) {
- for x := range d {
- data := make([]float64, len(d[x]))
-
- copy(data, d[x])
-
- ids := make([]int, len(data))
- for x := range ids {
- ids[x] = x
- }
-
- InplaceInsertionSort(data, ids, 0, len(ids), true)
-
- test.Assert(t, "", dSorted[x], data)
- }
-}
-
-func TestInplaceInsertionSortDesc(t *testing.T) {
- for x := range d {
- data := make([]float64, len(d[x]))
-
- copy(data, d[x])
-
- ids := make([]int, len(data))
- for x := range ids {
- ids[x] = x
- }
-
- InplaceInsertionSort(data, ids, 0, len(ids), false)
-
- test.Assert(t, "", dSortedDesc[x], data)
- }
-}
-
-func TestSortByIndex(t *testing.T) {
- ids := [][]int{
- {},
- {5, 6, 7, 8, 9, 0, 1, 2, 3, 4},
- {0, 2, 4, 6, 8, 1, 3, 5, 7},
- {0, 1, 5, 6, 2, 3, 4},
- }
-
- for x := range d {
- data := make([]float64, len(d[x]))
-
- copy(data, d[x])
-
- SortByIndex(&data, ids[x])
-
- test.Assert(t, "", dSorted[x], data)
- }
-}
-
-var inSorts = [][]float64{
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
- {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {0.0, 6.0, 7.0, 8.0, 5.0, 1.0, 2.0, 3.0, 4.0, 9.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {5.1, 5, 5.6, 5.5, 5.5, 5.8, 5.5, 5.5, 5.8, 5.6,
- 5.7, 5, 5.6, 5.9, 6.2, 6, 4.9, 6.3, 6.1, 5.6,
- 5.8, 6.7, 6.1, 5.9, 6, 4.9, 5.6, 5.2, 6.1, 6.4,
- 7, 5.7, 6.5, 6.9, 5.7, 6.4, 6.2, 6.6, 6.3, 6.2,
- 5.4, 6.7, 6.1, 5.7, 5.5, 6, 3, 6.6, 5.7, 6,
- 6.8, 6, 6.1, 6.3, 5.8, 5.8, 5.6, 5.7, 6, 6.9,
- 6.9, 6.4, 6.3, 6.3, 6.7, 6.5, 5.8, 6.3, 6.4, 6.7,
- 5.9, 7.2, 6.3, 6.3, 6.5, 7.1, 6.7, 7.6, 7.3, 6.4,
- 6.7, 7.4, 6, 6.8, 6.5, 6.4, 6.7, 6.4, 6.5, 6.9,
- 7.7, 6.7, 7.2, 7.7, 7.2, 7.7, 6.1, 7.9, 7.7, 6.8,
- 6.2},
-}
-
-var expSorts = [][]float64{
- {3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {3, 4.9, 4.9, 5, 5, 5.1, 5.2, 5.4, 5.5, 5.5,
- 5.5, 5.5, 5.5, 5.6, 5.6, 5.6, 5.6, 5.6, 5.6, 5.7,
- 5.7, 5.7, 5.7, 5.7, 5.7, 5.8, 5.8, 5.8, 5.8, 5.8,
- 5.8, 5.9, 5.9, 5.9, 6, 6, 6, 6, 6, 6,
- 6, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.2, 6.2, 6.2,
- 6.2, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.4,
- 6.4, 6.4, 6.4, 6.4, 6.4, 6.4, 6.5, 6.5, 6.5, 6.5,
- 6.5, 6.6, 6.6, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7,
- 6.7, 6.8, 6.8, 6.8, 6.9, 6.9, 6.9, 6.9, 7, 7.1,
- 7.2, 7.2, 7.2, 7.3, 7.4, 7.6, 7.7, 7.7, 7.7, 7.7,
- 7.9},
-}
-
-var expSortsDesc = [][]float64{
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
- {9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {7.9, 7.7, 7.7, 7.7, 7.7, 7.6, 7.4, 7.3, 7.2, 7.2,
- 7.2, 7.1, 7, 6.9, 6.9, 6.9, 6.9, 6.8, 6.8, 6.8,
- 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.6, 6.6,
- 6.5, 6.5, 6.5, 6.5, 6.5, 6.4, 6.4, 6.4, 6.4, 6.4,
- 6.4, 6.4, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3,
- 6.2, 6.2, 6.2, 6.2, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1,
- 6, 6, 6, 6, 6, 6, 6, 5.9, 5.9, 5.9,
- 5.8, 5.8, 5.8, 5.8, 5.8, 5.8, 5.7, 5.7, 5.7, 5.7,
- 5.7, 5.7, 5.6, 5.6, 5.6, 5.6, 5.6, 5.6, 5.5, 5.5,
- 5.5, 5.5, 5.5, 5.4, 5.2, 5.1, 5, 5, 4.9, 4.9, 3},
-}
-
-func TestIndirectSort(t *testing.T) {
- var res, exp string
-
- for i := range inSorts {
- IndirectSort(inSorts[i], true)
-
- res = fmt.Sprint(inSorts[i])
- exp = fmt.Sprint(expSorts[i])
-
- test.Assert(t, "", exp, res)
- }
-}
-
-func TestIndirectSortDesc(t *testing.T) {
- var res, exp string
-
- for i := range inSorts {
- IndirectSort(inSorts[i], false)
-
- res = fmt.Sprint(inSorts[i])
- exp = fmt.Sprint(expSortsDesc[i])
-
- test.Assert(t, "", exp, res)
- }
-}
-
-func TestIndirectSort_Stability(t *testing.T) {
- exp := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
- got := IndirectSort(inSorts[5], true)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestIndirectSortDesc_Stability(t *testing.T) {
- exp := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
- got := IndirectSort(inSorts[5], false)
-
- test.Assert(t, "", exp, got)
-}
-
-func TestInplaceMergesort(t *testing.T) {
- size := len(inSorts[6])
- idx := make([]int, size)
-
- InplaceMergesort(inSorts[6], idx, 0, size, true)
-
- test.Assert(t, "", expSorts[6], inSorts[6])
-}
-
-func TestIndirectSort_SortByIndex(t *testing.T) {
- expListID := []int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
- in1 := []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0}
- in2 := []float64{0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}
-
- exp := fmt.Sprint(in1)
-
- sortedListID := IndirectSort(in1, true)
-
- test.Assert(t, "", expListID, sortedListID)
-
- // Reverse the sort.
- SortByIndex(&in2, sortedListID)
-
- got := fmt.Sprint(in2)
-
- test.Assert(t, "", exp, got)
-}
diff --git a/lib/mining/classifier/crf/crf.go b/lib/mining/classifier/crf/crf.go
index 1ea93e00..ceb9b605 100644
--- a/lib/mining/classifier/crf/crf.go
+++ b/lib/mining/classifier/crf/crf.go
@@ -15,10 +15,10 @@ import (
"math"
"sort"
- "git.sr.ht/~shulhan/pakakeh.go/lib/floats64"
"git.sr.ht/~shulhan/pakakeh.go/lib/mining/classifier"
"git.sr.ht/~shulhan/pakakeh.go/lib/mining/classifier/rf"
"git.sr.ht/~shulhan/pakakeh.go/lib/numbers"
+ "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
libstrings "git.sr.ht/~shulhan/pakakeh.go/lib/strings"
"git.sr.ht/~shulhan/pakakeh.go/lib/tabula"
)
@@ -368,7 +368,7 @@ func (crf *Runtime) ClassifySetByWeight(samples tabula.ClasetInterface,
vs := samples.GetClassValueSpace()
stageProbs := make([]float64, len(vs))
stageSumProbs := make([]float64, len(vs))
- sumWeights := floats64.Sum(crf.weights)
+ sumWeights := slices.Sum(crf.weights)
// (1)
rows := samples.GetDataAsRows()
@@ -400,8 +400,8 @@ func (crf *Runtime) ClassifySetByWeight(samples tabula.ClasetInterface,
}
// (1.3)
- _, maxi, ok := floats64.Max(stageProbs)
- if ok {
+ _, maxi := slices.Max2(stageProbs)
+ if maxi >= 0 {
predicts = append(predicts, vs[maxi])
}
diff --git a/lib/mining/classifier/rf/rf.go b/lib/mining/classifier/rf/rf.go
index 07da00ea..501080e4 100644
--- a/lib/mining/classifier/rf/rf.go
+++ b/lib/mining/classifier/rf/rf.go
@@ -16,9 +16,9 @@ import (
"math"
"slices"
- "git.sr.ht/~shulhan/pakakeh.go/lib/floats64"
"git.sr.ht/~shulhan/pakakeh.go/lib/mining/classifier"
"git.sr.ht/~shulhan/pakakeh.go/lib/mining/classifier/cart"
+ libslices "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
libstrings "git.sr.ht/~shulhan/pakakeh.go/lib/strings"
"git.sr.ht/~shulhan/pakakeh.go/lib/tabula"
)
@@ -275,9 +275,8 @@ func (forest *Runtime) ClassifySet(samples tabula.ClasetInterface,
// (1.2)
classProbs := libstrings.FrequencyOfTokens(votes, vs, false)
- _, idx, ok := floats64.Max(classProbs)
-
- if ok {
+ _, idx := libslices.Max2(classProbs)
+ if idx >= 0 {
predicts = append(predicts, vs[idx])
}
diff --git a/lib/mining/classifier/runtime.go b/lib/mining/classifier/runtime.go
index eeea1621..1d649788 100644
--- a/lib/mining/classifier/runtime.go
+++ b/lib/mining/classifier/runtime.go
@@ -9,7 +9,6 @@ import (
"math"
"git.sr.ht/~shulhan/pakakeh.go/lib/dsv"
- "git.sr.ht/~shulhan/pakakeh.go/lib/floats64"
"git.sr.ht/~shulhan/pakakeh.go/lib/numbers"
"git.sr.ht/~shulhan/pakakeh.go/lib/slices"
libstrings "git.sr.ht/~shulhan/pakakeh.go/lib/strings"
@@ -310,7 +309,7 @@ func (rt *Runtime) Performance(samples tabula.ClasetInterface,
// (1)
actuals := samples.GetClassAsStrings()
sortedListID := numbers.IntCreateSeq(0, len(probs)-1)
- floats64.InplaceMergesort(probs, sortedListID, 0, len(probs), false)
+ slices.InplaceMergesort(probs, sortedListID, 0, len(probs), false)
// (2)
libstrings.SortByIndex(&actuals, sortedListID)
diff --git a/lib/mining/gain/gini/gini.go b/lib/mining/gain/gini/gini.go
index 68995e28..58c7fd5a 100644
--- a/lib/mining/gain/gini/gini.go
+++ b/lib/mining/gain/gini/gini.go
@@ -11,7 +11,7 @@ package gini
import (
"fmt"
- "git.sr.ht/~shulhan/pakakeh.go/lib/floats64"
+ "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
libstrings "git.sr.ht/~shulhan/pakakeh.go/lib/strings"
)
@@ -167,7 +167,7 @@ func (gini *Gini) ComputeContinu(src *[]float64, target, classes *[]string) {
T2 := make([]string, len(*target))
copy(T2, *target)
- gini.SortedIndex = floats64.IndirectSort(A2, true)
+ gini.SortedIndex = slices.IndirectSort(A2, true)
// sort the target attribute using sorted index.
libstrings.SortByIndex(&T2, gini.SortedIndex)
diff --git a/lib/mining/gain/gini/ginifloat.go b/lib/mining/gain/gini/ginifloat.go
index 522ca396..e7cf0e07 100644
--- a/lib/mining/gain/gini/ginifloat.go
+++ b/lib/mining/gain/gini/ginifloat.go
@@ -4,9 +4,7 @@
package gini
-import (
- "git.sr.ht/~shulhan/pakakeh.go/lib/floats64"
-)
+import "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
// ComputeContinuFloat Given an attribute A and the target attribute T which contain
// N classes in C, compute the information gain of A.
@@ -23,10 +21,10 @@ import (
func (gini *Gini) ComputeContinuFloat(src, target, classes *[]float64) {
gini.IsContinu = true
- gini.SortedIndex = floats64.IndirectSort(*src, true)
+ gini.SortedIndex = slices.IndirectSort(*src, true)
// (1)
- floats64.SortByIndex(target, gini.SortedIndex)
+ slices.SortByIndex(target, gini.SortedIndex)
// (2)
gini.createContinuPartition(src)
@@ -53,7 +51,7 @@ func (gini *Gini) computeFloat(target, classes *[]float64) float64 {
return 0
}
- classCount := floats64.Counts(*target, *classes)
+ classCount := slices.Counts(*target, *classes)
var sump2 float64
diff --git a/lib/slices/benchmark_test.go b/lib/slices/benchmark_test.go
index 923f9429..5bbde4e4 100644
--- a/lib/slices/benchmark_test.go
+++ b/lib/slices/benchmark_test.go
@@ -48,3 +48,25 @@ func BenchmarkSort_int(b *testing.B) {
})
}
+
+func BenchmarkInplaceMergesort_float64(b *testing.B) {
+ var slice = []float64{
+ 5.1, 5, 5.6, 5.5, 5.5, 5.8, 5.5, 5.5, 5.8, 5.6,
+ 5.7, 5, 5.6, 5.9, 6.2, 6, 4.9, 6.3, 6.1, 5.6,
+ 5.8, 6.7, 6.1, 5.9, 6, 4.9, 5.6, 5.2, 6.1, 6.4,
+ 7, 5.7, 6.5, 6.9, 5.7, 6.4, 6.2, 6.6, 6.3, 6.2,
+ 5.4, 6.7, 6.1, 5.7, 5.5, 6, 3, 6.6, 5.7, 6,
+ 6.8, 6, 6.1, 6.3, 5.8, 5.8, 5.6, 5.7, 6, 6.9,
+ 6.9, 6.4, 6.3, 6.3, 6.7, 6.5, 5.8, 6.3, 6.4, 6.7,
+ 5.9, 7.2, 6.3, 6.3, 6.5, 7.1, 6.7, 7.6, 7.3, 6.4,
+ 6.7, 7.4, 6, 6.8, 6.5, 6.4, 6.7, 6.4, 6.5, 6.9,
+ 7.7, 6.7, 7.2, 7.7, 7.2, 7.7, 6.1, 7.9, 7.7, 6.8,
+ 6.2,
+ }
+ var size = len(slice)
+ var ids = make([]int, size)
+
+ for i := 0; i < b.N; i++ {
+ slices.InplaceMergesort(slice, ids, 0, size, true)
+ }
+}
diff --git a/lib/slices/slices_float64_test.go b/lib/slices/slices_float64_test.go
new file mode 100644
index 00000000..c15a9170
--- /dev/null
+++ b/lib/slices/slices_float64_test.go
@@ -0,0 +1,464 @@
+// SPDX-FileCopyrightText: 2024 M. Shulhan <ms@kilabit.info>
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+package slices_test
+
+import (
+ "fmt"
+ "testing"
+
+ "git.sr.ht/~shulhan/pakakeh.go/lib/numbers"
+ "git.sr.ht/~shulhan/pakakeh.go/lib/slices"
+ "git.sr.ht/~shulhan/pakakeh.go/lib/test"
+)
+
+func TestCount_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ val float64
+ exp int
+ }{{
+ desc: `empty`,
+ exp: 0,
+ }, {
+ desc: `case 1`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ val: 0.1,
+ exp: 1,
+ }, {
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ val: 0.1,
+ exp: 4,
+ }, {
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ val: 0.1,
+ exp: 0,
+ }, {
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ val: 3,
+ exp: 1,
+ }}
+
+ for _, tcase := range listCase {
+ var got = slices.Count(tcase.slice, tcase.val)
+ test.Assert(t, tcase.desc, tcase.exp, got)
+ }
+}
+
+func TestCounts_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ classes []float64
+ exp []int
+ }{{
+ desc: `empty slice`,
+ classes: []float64{1, 2, 3},
+ exp: []int{0, 0, 0},
+ }, {
+ desc: `empty classes`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ }, {
+ desc: `ok`,
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ classes: []float64{1, 2, 3},
+ exp: []int{3, 3, 1},
+ }}
+
+ for _, tcase := range listCase {
+ var got = slices.Counts(tcase.slice, tcase.classes)
+ test.Assert(t, tcase.desc, tcase.exp, got)
+ }
+}
+
+func TestIndirectSort_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ expSortedIdx []int
+ exp []float64
+ isAsc bool
+ }{{
+ desc: `case 1 asc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0},
+ exp: []float64{3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ expSortedIdx: []int{6, 5, 4, 3, 2, 1, 0},
+ isAsc: true,
+ }, {
+ desc: `case 1 desc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0},
+ exp: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6},
+ isAsc: false,
+ }, {
+ desc: `case 2 asc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
+ exp: []float64{0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ expSortedIdx: []int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+ isAsc: true,
+ }, {
+ desc: `case 2 desc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
+ exp: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ isAsc: false,
+ }, {
+ desc: `case 3 asc`,
+ slice: []float64{0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ exp: []float64{0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ isAsc: true,
+ }, {
+ desc: `case 3 desc`,
+ slice: []float64{0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ exp: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0},
+ expSortedIdx: []int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+ isAsc: false,
+ }, {
+ desc: `case 4 asc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0},
+ exp: []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0},
+ expSortedIdx: []int{8, 7, 6, 5, 4, 3, 2, 1, 0},
+ isAsc: true,
+ }, {
+ desc: `case 4 desc`,
+ slice: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0},
+ exp: []float64{9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6, 7, 8},
+ isAsc: false,
+ }, {
+ desc: `case 5 stable asc`,
+ slice: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ exp: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ isAsc: true,
+ }, {
+ desc: `case 5 stable desc`,
+ slice: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ exp: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ expSortedIdx: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ isAsc: false,
+ }, {
+ desc: `case 6 asc`,
+ slice: []float64{
+ 5.1, 5, 5.6, 5.5, 5.5, 5.8, 5.5, 5.5, 5.8, 5.6,
+ 5.7, 5, 5.6, 5.9, 6.2, 6, 4.9, 6.3, 6.1, 5.6,
+ 5.8, 6.7, 6.1, 5.9, 6, 4.9, 5.6, 5.2, 6.1, 6.4,
+ 7, 5.7, 6.5, 6.9, 5.7, 6.4, 6.2, 6.6, 6.3, 6.2,
+ 5.4, 6.7, 6.1, 5.7, 5.5, 6, 3, 6.6, 5.7, 6,
+ 6.8, 6, 6.1, 6.3, 5.8, 5.8, 5.6, 5.7, 6, 6.9,
+ 6.9, 6.4, 6.3, 6.3, 6.7, 6.5, 5.8, 6.3, 6.4, 6.7,
+ 5.9, 7.2, 6.3, 6.3, 6.5, 7.1, 6.7, 7.6, 7.3, 6.4,
+ 6.7, 7.4, 6, 6.8, 6.5, 6.4, 6.7, 6.4, 6.5, 6.9,
+ 7.7, 6.7, 7.2, 7.7, 7.2, 7.7, 6.1, 7.9, 7.7, 6.8,
+ 6.2,
+ },
+ exp: []float64{
+ 3, 4.9, 4.9, 5, 5, 5.1, 5.2, 5.4, 5.5, 5.5,
+ 5.5, 5.5, 5.5, 5.6, 5.6, 5.6, 5.6, 5.6, 5.6, 5.7,
+ 5.7, 5.7, 5.7, 5.7, 5.7, 5.8, 5.8, 5.8, 5.8, 5.8,
+ 5.8, 5.9, 5.9, 5.9, 6, 6, 6, 6, 6, 6,
+ 6, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.2, 6.2, 6.2,
+ 6.2, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.4,
+ 6.4, 6.4, 6.4, 6.4, 6.4, 6.4, 6.5, 6.5, 6.5, 6.5,
+ 6.5, 6.6, 6.6, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7,
+ 6.7, 6.8, 6.8, 6.8, 6.9, 6.9, 6.9, 6.9, 7, 7.1,
+ 7.2, 7.2, 7.2, 7.3, 7.4, 7.6, 7.7, 7.7, 7.7, 7.7,
+ 7.9,
+ },
+ isAsc: true,
+ }, {
+ desc: `case 6 desc`,
+ slice: []float64{
+ 5.1, 5, 5.6, 5.5, 5.5, 5.8, 5.5, 5.5, 5.8, 5.6,
+ 5.7, 5, 5.6, 5.9, 6.2, 6, 4.9, 6.3, 6.1, 5.6,
+ 5.8, 6.7, 6.1, 5.9, 6, 4.9, 5.6, 5.2, 6.1, 6.4,
+ 7, 5.7, 6.5, 6.9, 5.7, 6.4, 6.2, 6.6, 6.3, 6.2,
+ 5.4, 6.7, 6.1, 5.7, 5.5, 6, 3, 6.6, 5.7, 6,
+ 6.8, 6, 6.1, 6.3, 5.8, 5.8, 5.6, 5.7, 6, 6.9,
+ 6.9, 6.4, 6.3, 6.3, 6.7, 6.5, 5.8, 6.3, 6.4, 6.7,
+ 5.9, 7.2, 6.3, 6.3, 6.5, 7.1, 6.7, 7.6, 7.3, 6.4,
+ 6.7, 7.4, 6, 6.8, 6.5, 6.4, 6.7, 6.4, 6.5, 6.9,
+ 7.7, 6.7, 7.2, 7.7, 7.2, 7.7, 6.1, 7.9, 7.7, 6.8,
+ 6.2,
+ },
+ exp: []float64{
+ 7.9, 7.7, 7.7, 7.7, 7.7, 7.6, 7.4, 7.3, 7.2, 7.2,
+ 7.2, 7.1, 7, 6.9, 6.9, 6.9, 6.9, 6.8, 6.8, 6.8,
+ 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.6, 6.6,
+ 6.5, 6.5, 6.5, 6.5, 6.5, 6.4, 6.4, 6.4, 6.4, 6.4,
+ 6.4, 6.4, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3,
+ 6.2, 6.2, 6.2, 6.2, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1,
+ 6, 6, 6, 6, 6, 6, 6, 5.9, 5.9, 5.9,
+ 5.8, 5.8, 5.8, 5.8, 5.8, 5.8, 5.7, 5.7, 5.7, 5.7,
+ 5.7, 5.7, 5.6, 5.6, 5.6, 5.6, 5.6, 5.6, 5.5, 5.5,
+ 5.5, 5.5, 5.5, 5.4, 5.2, 5.1, 5, 5, 4.9, 4.9,
+ 3,
+ },
+ isAsc: false,
+ }}
+
+ for _, tcase := range listCase {
+ var gotSortedIdx = slices.IndirectSort(tcase.slice, tcase.isAsc)
+ test.Assert(t, tcase.desc, tcase.exp, tcase.slice)
+
+ if len(tcase.expSortedIdx) == 0 {
+ continue
+ }
+
+ var expSortedIdxStr = fmt.Sprint(tcase.expSortedIdx)
+ var gotSortedIdxStr = fmt.Sprint(gotSortedIdx)
+ test.Assert(t, tcase.desc+` sortedIdx`, expSortedIdxStr,
+ gotSortedIdxStr)
+ }
+}
+
+func TestInplaceInsertionSort_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp []float64
+ isAsc bool
+ }{{
+ desc: `case empty`,
+ }, {
+ desc: `case 1 asc`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ exp: []float64{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9},
+ isAsc: true,
+ }, {
+ desc: `case 1 desc`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ exp: []float64{0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0},
+ isAsc: false,
+ }, {
+ desc: `case 2 asc`,
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ exp: []float64{0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.1, 0.1, 0.1},
+ isAsc: true,
+ }, {
+ desc: `case 2 desc`,
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ exp: []float64{0.1, 0.1, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
+ isAsc: false,
+ }, {
+ desc: `case 3 asc`,
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ exp: []float64{1, 1, 1, 2, 2, 2, 3},
+ isAsc: true,
+ }, {
+ desc: `case 3 desc`,
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ exp: []float64{3, 2, 2, 2, 1, 1, 1},
+ isAsc: false,
+ }}
+ for _, tcase := range listCase {
+ var ids = make([]int, len(tcase.slice))
+ slices.InplaceInsertionSort(tcase.slice, ids, 0, len(ids),
+ tcase.isAsc)
+ test.Assert(t, tcase.desc, tcase.exp, tcase.slice)
+ }
+}
+
+func TestInplaceMergesort_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp []float64
+ }{{
+ desc: `case 1`,
+ slice: []float64{
+ 5.1, 5, 5.6, 5.5, 5.5, 5.8, 5.5, 5.5, 5.8, 5.6,
+ 5.7, 5, 5.6, 5.9, 6.2, 6, 4.9, 6.3, 6.1, 5.6,
+ 5.8, 6.7, 6.1, 5.9, 6, 4.9, 5.6, 5.2, 6.1, 6.4,
+ 7, 5.7, 6.5, 6.9, 5.7, 6.4, 6.2, 6.6, 6.3, 6.2,
+ 5.4, 6.7, 6.1, 5.7, 5.5, 6, 3, 6.6, 5.7, 6,
+ 6.8, 6, 6.1, 6.3, 5.8, 5.8, 5.6, 5.7, 6, 6.9,
+ 6.9, 6.4, 6.3, 6.3, 6.7, 6.5, 5.8, 6.3, 6.4, 6.7,
+ 5.9, 7.2, 6.3, 6.3, 6.5, 7.1, 6.7, 7.6, 7.3, 6.4,
+ 6.7, 7.4, 6, 6.8, 6.5, 6.4, 6.7, 6.4, 6.5, 6.9,
+ 7.7, 6.7, 7.2, 7.7, 7.2, 7.7, 6.1, 7.9, 7.7, 6.8,
+ 6.2,
+ },
+ exp: []float64{
+ 3, 4.9, 4.9, 5, 5, 5.1, 5.2, 5.4, 5.5, 5.5,
+ 5.5, 5.5, 5.5, 5.6, 5.6, 5.6, 5.6, 5.6, 5.6, 5.7,
+ 5.7, 5.7, 5.7, 5.7, 5.7, 5.8, 5.8, 5.8, 5.8, 5.8,
+ 5.8, 5.9, 5.9, 5.9, 6, 6, 6, 6, 6, 6,
+ 6, 6.1, 6.1, 6.1, 6.1, 6.1, 6.1, 6.2, 6.2, 6.2,
+ 6.2, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.4,
+ 6.4, 6.4, 6.4, 6.4, 6.4, 6.4, 6.5, 6.5, 6.5, 6.5,
+ 6.5, 6.6, 6.6, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7, 6.7,
+ 6.7, 6.8, 6.8, 6.8, 6.9, 6.9, 6.9, 6.9, 7, 7.1,
+ 7.2, 7.2, 7.2, 7.3, 7.4, 7.6, 7.7, 7.7, 7.7, 7.7,
+ 7.9,
+ },
+ }}
+
+ for _, tcase := range listCase {
+ var size = len(tcase.slice)
+ var idx = make([]int, size)
+
+ slices.InplaceMergesort(tcase.slice, idx, 0, size, true)
+ test.Assert(t, tcase.desc, tcase.exp, tcase.slice)
+ }
+}
+
+func TestMax_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp float64
+ expIdx int
+ }{{
+ expIdx: -1,
+ }, {
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ exp: 0.9,
+ expIdx: 4,
+ }}
+
+ for _, tcase := range listCase {
+ gotMax, gotIdx := slices.Max2(tcase.slice)
+
+ test.Assert(t, tcase.desc+` max`, tcase.exp, gotMax)
+ test.Assert(t, tcase.desc+` idx`, tcase.expIdx, gotIdx)
+ }
+}
+
+func TestMin_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp float64
+ expIdx int
+ }{{
+ expIdx: -1,
+ }, {
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ exp: 0.0,
+ expIdx: 5,
+ }}
+
+ for _, tcase := range listCase {
+ gotMin, gotIdx := slices.Min2(tcase.slice)
+
+ test.Assert(t, tcase.desc+` min`, tcase.exp, gotMin)
+ test.Assert(t, tcase.desc+` idx`, tcase.expIdx, gotIdx)
+ }
+}
+
+func TestMaxCountOf_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ classes []float64
+ exp float64
+ state int
+ }{{
+ desc: `case 1`,
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ classes: []float64{0, 1},
+ exp: 0,
+ state: 0,
+ }, {
+ desc: `case 2`,
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ classes: []float64{1, 0},
+ exp: 0,
+ }}
+
+ for _, tcase := range listCase {
+ got, gotState := slices.MaxCountOf(tcase.slice, tcase.classes)
+ test.Assert(t, tcase.desc+` got`, tcase.exp, got)
+ test.Assert(t, tcase.desc+` state`, tcase.state, gotState)
+ }
+}
+
+func TestSortByIndex_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ ids []int
+ exp []float64
+ }{{
+ desc: `case empty`,
+ }, {
+ desc: `case 1`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ ids: []int{5, 6, 7, 8, 9, 0, 1, 2, 3, 4},
+ exp: []float64{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9},
+ }, {
+ desc: `case 2`,
+ slice: []float64{0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0},
+ ids: []int{0, 2, 4, 6, 8, 1, 3, 5, 7},
+ exp: []float64{0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.1, 0.1, 0.1},
+ }, {
+ desc: `case 3`,
+ slice: []float64{1, 1, 2, 2, 3, 1, 2},
+ ids: []int{0, 1, 5, 6, 2, 3, 4},
+ exp: []float64{1, 1, 1, 2, 2, 2, 3},
+ }}
+
+ for _, tcase := range listCase {
+ slices.SortByIndex(&tcase.slice, tcase.ids)
+ test.Assert(t, tcase.desc, tcase.exp, tcase.slice)
+ }
+}
+
+func TestSum_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp float64
+ }{{
+ desc: `case 1`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ exp: 4.5,
+ }}
+
+ for _, tcase := range listCase {
+ var got = slices.Sum(tcase.slice)
+ got = numbers.Float64Round(got, 1)
+ test.Assert(t, tcase.desc, tcase.exp, got)
+ }
+}
+
+func TestSwap_float64(t *testing.T) {
+ var listCase = []struct {
+ desc string
+ slice []float64
+ exp []float64
+ idx1 int
+ idx2 int
+ }{{
+ desc: `empty`,
+ idx1: 1,
+ idx2: 6,
+ }, {
+ desc: `equal indices`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ idx1: 1,
+ idx2: 1,
+ exp: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ }, {
+ desc: `out of range indices`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ idx1: 1,
+ idx2: 100,
+ exp: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ }, {
+ desc: `case 1`,
+ slice: []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.4},
+ idx1: 0,
+ idx2: 9,
+ exp: []float64{0.4, 0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, 0.3, 0.5},
+ }}
+
+ for _, tcase := range listCase {
+ slices.Swap(tcase.slice, tcase.idx1, tcase.idx2)
+ test.Assert(t, tcase.desc, tcase.exp, tcase.slice)
+ }
+}