// DotInt64 performs a dot product on two arrays of float64 func DotInt64(a, b []int64) int64 { result := int64(0) if a != nil && b != nil { length := gomath.MinInt(len(a), len(b)) a = a[:length] b = b[:length] thunk := func() DotThunk { localResult := int64(0) return DotThunk{ Save: func() { result += localResult }, Dot: func(start, end int) { for start < end { localResult += a[start] * b[start] start++ } }, Print: func(i int) { log.Println(i, ": ", localResult) }, } } generateAndRun(thunk, length) } return result }
// DotFloat32 performs a dot product on two arrays of float32 func DotFloat32(a, b []float32) float32 { f, err := os.Create("profile.prof") if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() result := float32(0.0) if a != nil && b != nil { length := gomath.MinInt(len(a), len(b)) a = a[:length] b = b[:length] thunk := func() DotThunk { localResult := float32(0) return DotThunk{ Save: func() { result += localResult }, Dot: func(start, end int) { for start < end { localResult += a[start] * b[start] start++ } }, Print: func(i int) { log.Println(i, ": ", localResult) }, } } generateAndRun(thunk, length) } else { panic(fmt.Sprint("Invalid parameters:", a, b)) } return result }
func init() { features := 8 jump := 1000 var wg sync.WaitGroup LargeData = make([]classify.Data, LargeK) for i := 0; i < LargeK; i += jump { wg.Add(1) go func(i int) { start := i end := gomath.MinInt(LargeK, i+jump) for start < end { vArray := make([]gotypes.Value, features) LargeData[start] = &mydata{value: vArray, class: 0} for k := range vArray { vArray[k] = gotypes.WrapReal(rand.Float64()) } start++ } wg.Done() }(i) } wg.Wait() }
// Foreach mimics a parallel foreach construct // // This code should be equivalent to the serial code: // // for i := 0 ; i < iterations; i++ { // f(i); // } // // @f - Function to call in each iteration of the for loop // @iterations - How many iterations we should perform // // // func Foreach(f func(i int) bool, iterations int) { rt := GetRuntime() rt.Start() jobs := []Job(nil) for iter := 0; iter < iterations; iter += _BatchSize { function := func(start, end int) func(int) bool { return func(i int) bool { if i >= end { return false } return f(i) } }(iter, gomath.MinInt(iter+_BatchSize, iterations)) theJob := CreateIterableJob("Foreach", function, iter) jobs = append(jobs, theJob) } Run(jobs) }
func generateAndRun(thunkFunc func() DotThunk, length int) { _maxThreads := 16 _minWork := parallels.MinWorkPerThread threads := (length + _minWork - 1) / _minWork if threads > _maxThreads { threads = _maxThreads _minWork = (length + threads - 1) / threads } var lock sync.Mutex theJobs := []parallels.Job(nil) for threadID := 0; threadID < threads; threadID++ { myFunc := func(threadID, start, end int, mutex *sync.Mutex) parallels.Job { f := generateFunction(thunkFunc(), start, end, mutex) return parallels.CreateIterableJob(fmt.Sprint("Dot Product ", threadID, end), f, 0) } start := threadID * _minWork end := gomath.MinInt(start+_minWork, length) theJobs = append(theJobs, myFunc(threadID, start, end, &lock)) } parallels.Run(theJobs) }
// KMeans clustering // TODO: Change to not only be numeric func KMeans(data []classify.Data, K int, metric Metric, means [][]float64) [][]float64 { features := len(data[0].Value()) if means == nil { /* Todo: randomly initialize k means */ means = make([][]float64, K) for i := range means { means[i] = make([]float64, features) val := data[rand.Intn(len(data))] for j, v := range val.Value() { means[i][j] = v.Real() } } } counts := make([]int, K) newMeans := make([][]float64, K) for i := range newMeans { newMeans[i] = make([]float64, features) } maxElemPerThread := 10000 // 1K iterations := gomath.MaxInt(1, (len(data)+maxElemPerThread-1)/maxElemPerThread) elemPerThread := (len(data) + iterations - 1) / iterations change := true for change { change = false var lock sync.Mutex parallels.Foreach(func(i int) bool { // List of stuff nMs := make([][]float64, K) cs := make([]int, K) for i := range nMs { nMs[i] = make([]float64, features) } start := i * elemPerThread end := gomath.MinInt(start+elemPerThread, len(data)) for start < end { d := data[start] closest := 0 wrap, err := gotypes.WrapArray(means[0], gotypes.Array) if err != nil { panic(err) } dist := metric(d.Value(), wrap.Array()) for k := 1; k < K; k++ { wrap, err = gotypes.WrapArray(means[k], gotypes.Array) if err != nil { panic(err) } nDist := metric(d.Value(), wrap.Array()) if nDist < dist { dist = nDist closest = k } } // Save cs[closest]++ for i := 0; i < features; i++ { t := d.Value()[i].Real() nMs[closest][i] += t } start++ } lock.Lock() defer lock.Unlock() for i := 0; i < K; i++ { for j := 0; j < features; j++ { newMeans[i][j] += nMs[i][j] } counts[i] += cs[i] } return false }, iterations) // Update means for i := range newMeans { for j := range newMeans[i] { newMeans[i][j] /= float64(counts[i]) } if !same(newMeans[i], means[i]) { change = true } for j := range newMeans[i] { means[i][j] = newMeans[i][j] newMeans[i][j] = 0 } counts[i] = 0 } } return means }