github.com/schollz/clusters@v0.0.0-20221201012527-c6c68863636f/common.go (about) 1 package clusters 2 3 import ( 4 "container/heap" 5 "math/rand" 6 "sync" 7 ) 8 9 // struct denoting start and end indices of database portion to be scanned for nearest neighbours by workers in DBSCAN and OPTICS 10 type rangeJob struct { 11 a, b int 12 } 13 14 // priority queue 15 type pItem struct { 16 v int 17 p float64 18 i int 19 } 20 21 type priorityQueue []*pItem 22 23 func newPriorityQueue(size int) priorityQueue { 24 q := make(priorityQueue, 0, size) 25 heap.Init(&q) 26 27 return q 28 } 29 30 func (pq priorityQueue) Len() int { return len(pq) } 31 32 func (pq priorityQueue) Less(i, j int) bool { 33 return pq[i].p > pq[j].p 34 } 35 36 func (pq priorityQueue) Swap(i, j int) { 37 pq[i], pq[j] = pq[j], pq[i] 38 pq[i].i = i 39 pq[j].i = j 40 } 41 42 func (pq *priorityQueue) Push(x interface{}) { 43 n := len(*pq) 44 item := x.(*pItem) 45 item.i = n 46 *pq = append(*pq, item) 47 heap.Fix(pq, item.i) 48 } 49 50 func (pq *priorityQueue) Pop() interface{} { 51 old := *pq 52 n := len(old) 53 item := old[n-1] 54 item.i = -1 55 *pq = old[0 : n-1] 56 return item 57 } 58 59 func (pq *priorityQueue) NotEmpty() bool { 60 return len(*pq) > 0 61 } 62 63 func (pq *priorityQueue) Update(item *pItem, value int, priority float64) { 64 item.v = value 65 item.p = priority 66 heap.Fix(pq, item.i) 67 } 68 69 func bounds(data [][]float64) []*[2]float64 { 70 var ( 71 wg sync.WaitGroup 72 73 l = len(data[0]) 74 r = make([]*[2]float64, l) 75 ) 76 77 for i := 0; i < l; i++ { 78 r[i] = &[2]float64{ 79 data[0][i], 80 data[0][i], 81 } 82 } 83 84 wg.Add(l) 85 86 for i := 0; i < l; i++ { 87 go func(n int) { 88 defer wg.Done() 89 90 for j := 0; j < len(data); j++ { 91 if data[j][n] < r[n][0] { 92 r[n][0] = data[j][n] 93 } else if data[j][n] > r[n][1] { 94 r[n][1] = data[j][n] 95 } 96 } 97 }(i) 98 } 99 100 wg.Wait() 101 102 return r 103 } 104 105 func uniform(data *[2]float64) float64 { 106 return rand.Float64()*(data[1]-data[0]) + data[0] 107 }