github.com/kaydxh/golang@v0.0.131/pkg/gocv/cvtable/cvtable.go (about) 1 /* 2 *Copyright (c) 2023, kaydxh 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining a copy 5 *of this software and associated documentation files (the "Software"), to deal 6 *in the Software without restriction, including without limitation the rights 7 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 *copies of the Software, and to permit persons to whom the Software is 9 *furnished to do so, subject to the following conditions: 10 * 11 *The above copyright notice and this permission notice shall be included in all 12 *copies or substantial portions of the Software. 13 * 14 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 *SOFTWARE. 21 */ 22 package cvtable 23 24 import ( 25 "fmt" 26 "sort" 27 "strconv" 28 29 io_ "github.com/kaydxh/golang/go/io" 30 exp_ "github.com/kaydxh/golang/go/math/exp" 31 ) 32 33 const ( 34 validateRows = 101 35 maxScore = 100 36 minScore = 0 37 ) 38 39 type CVTable struct { 40 table []float64 41 } 42 43 func NewCVTable(filepath string) (*CVTable, error) { 44 table, err := io_.ReadFileLines(filepath) 45 if err != nil { 46 return nil, err 47 } 48 49 c := &CVTable{} 50 if table[0] != "0" { 51 c.table = append(c.table, 0) 52 } 53 54 for _, v := range table { 55 sim, err := strconv.ParseFloat(v, 64) 56 if err != nil { 57 return nil, err 58 } 59 c.table = append(c.table, sim) 60 } 61 err = c.Validate() 62 if err != nil { 63 return nil, err 64 } 65 return c, nil 66 } 67 68 func (c CVTable) Validate() error { 69 if len(c.table) != validateRows { 70 return fmt.Errorf("invalid cv table rows %v, must be %v", len(c.table), validateRows) 71 } 72 73 return nil 74 } 75 76 // score 0-100, mapping to sim 77 func (c CVTable) Sim(score float64) float64 { 78 if score <= minScore { 79 return 0 80 } 81 82 // integerPart integer part of a decimal 83 // decimalPart decimal part of a decimal 84 integerPart := int(score) 85 decimalPart := score - float64(integerPart) 86 87 // len(c.table) - 1 == 100 88 if integerPart >= len(c.table)-1 { 89 return 1 90 } 91 92 return c.table[integerPart] + (c.table[integerPart+1]-c.table[integerPart])*decimalPart 93 } 94 95 func (c CVTable) Score(sim float64) float64 { 96 if sim <= 0 { 97 return minScore 98 } 99 if sim >= 1 { 100 return maxScore 101 } 102 103 pos := sort.Search(len(c.table), func(i int) bool { return c.table[i] >= sim }) 104 score := float64(pos) 105 if pos > 0 && pos < len(c.table) { 106 score += -1.0 + (sim-c.table[pos-1])/(c.table[pos]-c.table[pos-1]) 107 } 108 109 return exp_.Value(score, minScore, maxScore) 110 }