動手寫點東西是學習新知識很重要的一個階段。之前用 Python 和 JavaScript 實現優化演算法,現在用 Golang 來實現。語法上略有不爽,某些C語言的思維又回來了。
- Golang 用 package 來組織程式碼,同一 package 下不同檔案之間的識別符號是共享的,不能包含兩個相同名稱的函式。而且只有 package main 能夠包含 main 函式。所以將公用的函式提取出來,放在package common。同時,每種例子程式移動到 examples 目錄下。
- 在 CleverAlgorithms 中都是隨機優化演算法,最常用的是隨機數或向量的生成函式。因為預設採用Fixed Seed,所以需要自行設定成執行時刻的納秒值作為種子。
- 在缺乏靈活的dict型別之後,需要定義struct組合型別來滿足陣列單元中儲存不同型別值的需求。
package common import ( "math/rand" "time" ) // InitSeed set random seed with current time value func InitSeed() { rand.Seed(time.Now().UnixNano()) } // RandomVector generates a random vector from min_max bound. // It returns the generated random vector. func RandomVector(min_max [][2]float64) []float64 { var v = make([]float64, len(min_max)) for i, mm := range min_max { v[i] = mm[0] + (mm[1]-mm[0])*rand.Float64() } return v } // RandomBound generates a random value from the bound. // It returns the random value. func RandomBound(bound [2]float64) float64 { return bound[0] + (bound[1]-bound[0])*rand.Float64() } // FRange simulates range in python for float64. // It yields values in the range. func FRange(start float64, stop float64, step float64) (c chan float64) { c = make(chan float64) go func() { for x := start; x<stop; x += step { c <- x } close(c) }() return } // Entity stores cost and vector. type Entity struct { Cost float64 Vector []float64 }
然後,隨機搜尋的程式碼變成:
// // Random Search // package stochastic import ( "clever_algorithms/common" "fmt" ) func objective_function(v []float64) float64 { return common.SphereFunction(v) } func RandomSearch(search_space [][2]float64, max_iteration int) common.Entity { var best common.Entity common.InitSeed() for i := 0; i < max_iteration; i++ { candidate := common.Entity{ 0.0, common.RandomVector(search_space), } candidate.Cost = objective_function(candidate.Vector) if best.Vector == nil || best.Cost > candidate.Cost { best = candidate } fmt.Println("Iteration ", i+1, ", best=", best.Cost) } return best }
新增簡單的單元測試:
package stochastic import ( "fmt" "testing" ) func TestObjectiveFunction(t *testing.T) { if 5 != objective_function([]float64{1, 2}) { t.Error("Objetive function failed") } } func TestSearch(t *testing.T) { // var problem_size = 2 var search_space = make([][2]float64, problem_size) for i, _ := range search_space { search_space[i] = [2]float64{-5, 5} } // const max_iteration = 100 // var best = RandomSearch(search_space, max_iteration) if best.Vector == nil { t.Error("Search result should not be nil.") } fmt.Println("Done. Best Solution: c=", best.Cost, ", v= [") for i, v := range best.Vector { fmt.Print(" ", v) if v < search_space[i][0] || v > search_space[i][1] { t.Error("vector values should be in the search space.") } } fmt.Println("]") }
[1]https://coding.net/u/huys03/p/clever_algorithms_go/git