/
main.go
160 lines (137 loc) · 3.59 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"encoding/json"
"flag"
"math/rand"
"os"
"runtime/pprof"
"time"
. "github.com/j4rv/gostuff/approximations"
"github.com/j4rv/gostuff/log"
"github.com/j4rv/gostuff/stopwatch"
)
const defaultPoints = `[
{"x":0, "y":0 },
{"x":0.2,"y":30 },
{"x":1, "y":100},
{"x":1.5,"y":118},
{"x":2, "y":160},
{"x":2.3,"y":182},
{"x":2.5,"y":180},
{"x":2.6,"y":189},
{"x":3, "y":200},
{"x":3.1,"y":199},
{"x":3.3,"y":190},
{"x":3.4,"y":146},
{"x":4, "y":220},
{"x":4.8,"y":230},
{"x":5, "y":150},
{"x":5.2,"y":160},
{"x":5.3,"y":184},
{"x":5.6,"y":151},
{"x":6, "y":310},
{"x":6.9,"y":410},
{"x":7, "y":428}
]`
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write mem profile to file")
func init() {
rand.Seed(time.Now().Unix())
}
func main() {
params := parseFlagParams()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
cfg := configFromFlags(params)
points := params.points
log.Info("Approximating best function...")
stop := stopwatch.Start()
bestCell, bestFit := CalcBestCell(cfg, params.cellType, points)
elapsed := stop()
log.Info("Done in seconds:", elapsed.Seconds())
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal(err)
}
_ = pprof.WriteHeapProfile(f)
_ = f.Close()
return
}
log.Info("Best approximation: ", bestCell)
log.Info("Best fit: ", bestFit)
log.Info(bestCell.String())
PlotResult(points, params.resPath, bestCell)
}
type flagParams struct {
generations int
population int
mutationPercentage int
initialTemp float64
cellType CellType
points *[]Point
resPath string
verbose bool
}
func parseFlagParams() flagParams {
var res flagParams
typeFlag := flag.String("type", "sines3", "The type of function to approximate")
pointsFlag := flag.String("points", defaultPoints, "The cloud of points to approximate")
flag.StringVar(&res.resPath, "resPath", "./result.png", "Where the result image will be saved")
flag.IntVar(&res.generations, "generations", 500, "Must be higher than 1")
flag.IntVar(&res.population, "population", 20000, "Must be higher than 1")
flag.IntVar(&res.mutationPercentage, "mutationPercentage", 20, "Must be in range [0, 100]")
flag.Float64Var(&res.initialTemp, "initialTemp", 0,
`Represents the initial 'temperature'.
Higher values means the <?> numbers will start with higher absolute values, but can also cause overfitting.
Must be higher than Zero. If not setted, it will be automatically calculated based on the points.`)
flag.BoolVar(&res.verbose, "v", false, "Verbose")
flag.Parse()
t, err := TypeFromString(*typeFlag)
if err != nil {
log.Error(err.Error())
}
res.cellType = t
points := pointsFromJSON(*pointsFlag)
res.points = points
return res
}
func randPoints(amount int) *[]Point {
res := make([]Point, amount)
f := func(x float64) float64 {
return x
}
for i := 0; i < amount; i++ {
x := rand.Float64() + float64(i)
y := f(x) + (rand.Float64()-0.5)*0.1
res[i] = Point{X: x, Y: y}
}
return &res
}
func configFromFlags(fp flagParams) Config {
if fp.verbose {
SetLogLevel(log.ALL)
}
cfg, err := NewConfig(fp.population, fp.mutationPercentage, fp.generations)
if err != nil {
log.Error(err)
os.Exit(1)
}
SetInitialTemp(&cfg, fp.initialTemp)
return cfg
}
func pointsFromJSON(s string) *[]Point {
points := make([]Point, 0)
err := json.Unmarshal([]byte(s), &points)
if err != nil {
log.Error(err)
os.Exit(1)
}
return &points
}