1 | package pge
|
---|
2 |
|
---|
3 | import (
|
---|
4 | "bufio"
|
---|
5 | "fmt"
|
---|
6 | "io/ioutil"
|
---|
7 | "log"
|
---|
8 | "math"
|
---|
9 | "os"
|
---|
10 | "strconv"
|
---|
11 | "strings"
|
---|
12 |
|
---|
13 | levmar "github.com/verdverm/go-levmar"
|
---|
14 | config "github.com/verdverm/go-pge/config"
|
---|
15 | probs "github.com/verdverm/go-pge/problems"
|
---|
16 | expr "github.com/verdverm/go-symexpr"
|
---|
17 | )
|
---|
18 |
|
---|
19 | type PgeConfig struct {
|
---|
20 | // search params
|
---|
21 | maxGen int
|
---|
22 | pgeRptEpoch int
|
---|
23 | pgeRptCount int
|
---|
24 | pgeArchiveCap int
|
---|
25 |
|
---|
26 | simprules expr.SimpRules
|
---|
27 | treecfg *probs.TreeParams
|
---|
28 |
|
---|
29 | // PGE specific options
|
---|
30 | peelCnt int
|
---|
31 | sortType probs.SortType
|
---|
32 | zeroEpsilon float64
|
---|
33 |
|
---|
34 | initMethod string
|
---|
35 | growMethod string
|
---|
36 |
|
---|
37 | evalrCount int
|
---|
38 | }
|
---|
39 |
|
---|
40 | func pgeConfigParser(field, value string, config interface{}) (err error) {
|
---|
41 |
|
---|
42 | PC := config.(*PgeConfig)
|
---|
43 |
|
---|
44 | switch strings.ToUpper(field) {
|
---|
45 | case "MAXGEN":
|
---|
46 | PC.maxGen, err = strconv.Atoi(value)
|
---|
47 | case "PGERPTEPOCH":
|
---|
48 | PC.pgeRptEpoch, err = strconv.Atoi(value)
|
---|
49 | case "PGERPTCOUNT":
|
---|
50 | PC.pgeRptCount, err = strconv.Atoi(value)
|
---|
51 | case "PGEARCHIVECAP":
|
---|
52 | PC.pgeArchiveCap, err = strconv.Atoi(value)
|
---|
53 |
|
---|
54 | case "PEELCOUNT":
|
---|
55 | PC.peelCnt, err = strconv.Atoi(value)
|
---|
56 |
|
---|
57 | case "EVALRCOUNT":
|
---|
58 | PC.evalrCount, err = strconv.Atoi(value)
|
---|
59 |
|
---|
60 | case "SORTTYPE":
|
---|
61 | switch strings.ToLower(value) {
|
---|
62 | case "paretotrainerror":
|
---|
63 | PC.sortType = probs.PESORT_PARETO_TRN_ERR
|
---|
64 | case "paretotesterror":
|
---|
65 | PC.sortType = probs.PESORT_PARETO_TST_ERR
|
---|
66 |
|
---|
67 | default:
|
---|
68 | log.Printf("PGE Config Not Implemented: %s, %s\n\n", field, value)
|
---|
69 | }
|
---|
70 |
|
---|
71 | case "ZEROEPSILON":
|
---|
72 | PC.zeroEpsilon, err = strconv.ParseFloat(value, 64)
|
---|
73 |
|
---|
74 | default:
|
---|
75 | // check augillary parsable structures [only TreeParams for now]
|
---|
76 | if PC.treecfg == nil {
|
---|
77 | PC.treecfg = new(probs.TreeParams)
|
---|
78 | }
|
---|
79 | found, ferr := probs.ParseTreeParams(field, value, PC.treecfg)
|
---|
80 | if ferr != nil {
|
---|
81 | log.Fatalf("error parsing PGE - treecfg Config\n")
|
---|
82 | return ferr
|
---|
83 | }
|
---|
84 | if !found {
|
---|
85 | log.Printf("PGE Config Not Implemented: %s, %s\n\n", field, value)
|
---|
86 | }
|
---|
87 |
|
---|
88 | }
|
---|
89 | return
|
---|
90 | }
|
---|
91 |
|
---|
92 | type PgeSearch struct {
|
---|
93 | id int
|
---|
94 | cnfg PgeConfig
|
---|
95 | prob *probs.ExprProblem
|
---|
96 | iter int
|
---|
97 | stop bool
|
---|
98 |
|
---|
99 | // comm up
|
---|
100 | commup *probs.ExprProblemComm
|
---|
101 |
|
---|
102 | // comm down
|
---|
103 |
|
---|
104 | // best exprs
|
---|
105 | Best *probs.ReportQueue
|
---|
106 |
|
---|
107 | // training data in C format
|
---|
108 | c_input []levmar.C_double
|
---|
109 | c_ygiven []levmar.C_double
|
---|
110 |
|
---|
111 | // logs
|
---|
112 | logDir string
|
---|
113 | mainLog *log.Logger
|
---|
114 | mainLogBuf *bufio.Writer
|
---|
115 | eqnsLog *log.Logger
|
---|
116 | eqnsLogBuf *bufio.Writer
|
---|
117 | errLog *log.Logger
|
---|
118 | errLogBuf *bufio.Writer
|
---|
119 |
|
---|
120 | fitnessLog *log.Logger
|
---|
121 | fitnessLogBuf *bufio.Writer
|
---|
122 | ipreLog *log.Logger
|
---|
123 | ipreLogBuf *bufio.Writer
|
---|
124 |
|
---|
125 | // equations visited
|
---|
126 | Trie *IpreNode
|
---|
127 | Queue *probs.ReportQueue
|
---|
128 |
|
---|
129 | // eval channels
|
---|
130 | eval_in chan expr.Expr
|
---|
131 | eval_out chan *probs.ExprReport
|
---|
132 |
|
---|
133 | // genStuff
|
---|
134 | GenRoots []expr.Expr
|
---|
135 | GenLeafs []expr.Expr
|
---|
136 | GenNodes []expr.Expr
|
---|
137 | GenNonTrig []expr.Expr
|
---|
138 |
|
---|
139 | // FFXish stuff
|
---|
140 | ffxBases []expr.Expr
|
---|
141 |
|
---|
142 | // statistics
|
---|
143 | neqns int
|
---|
144 | ipreCnt int
|
---|
145 | maxSize int
|
---|
146 | maxScore int
|
---|
147 | minError float64
|
---|
148 | }
|
---|
149 |
|
---|
150 | func (PS *PgeSearch) GetMaxIter() int {
|
---|
151 | return PS.cnfg.maxGen
|
---|
152 | }
|
---|
153 | func (PS *PgeSearch) GetPeelCount() int {
|
---|
154 | return PS.cnfg.peelCnt
|
---|
155 | }
|
---|
156 | func (PS *PgeSearch) SetMaxIter(iter int) {
|
---|
157 | PS.cnfg.maxGen = iter
|
---|
158 | }
|
---|
159 | func (PS *PgeSearch) SetPeelCount(cnt int) {
|
---|
160 | PS.cnfg.peelCnt = cnt
|
---|
161 | }
|
---|
162 | func (PS *PgeSearch) SetInitMethod(init string) {
|
---|
163 | PS.cnfg.initMethod = init
|
---|
164 | }
|
---|
165 | func (PS *PgeSearch) SetGrowMethod(grow string) {
|
---|
166 | PS.cnfg.growMethod = grow
|
---|
167 | }
|
---|
168 | func (PS *PgeSearch) SetEvalrCount(cnt int) {
|
---|
169 | PS.cnfg.evalrCount = cnt
|
---|
170 | }
|
---|
171 |
|
---|
172 | func (PS *PgeSearch) ParseConfig(filename string) {
|
---|
173 | fmt.Printf("Parsing PGE Config: %s\n", filename)
|
---|
174 | data, err := ioutil.ReadFile(filename)
|
---|
175 | if err != nil {
|
---|
176 | log.Fatal(err)
|
---|
177 | }
|
---|
178 | err = config.ParseConfig(data, pgeConfigParser, &PS.cnfg)
|
---|
179 | if err != nil {
|
---|
180 | log.Fatal(err)
|
---|
181 | }
|
---|
182 | }
|
---|
183 |
|
---|
184 | func (PS *PgeSearch) Init(done chan int, prob *probs.ExprProblem, logdir string, input interface{}) {
|
---|
185 |
|
---|
186 | //fmt.Printf("Init'n PGE\n")
|
---|
187 | // setup data
|
---|
188 |
|
---|
189 | // open logs
|
---|
190 | PS.initLogs(logdir)
|
---|
191 |
|
---|
192 | PS.stop = false
|
---|
193 |
|
---|
194 | // copy in common config options
|
---|
195 | PS.prob = prob
|
---|
196 | if PS.cnfg.treecfg == nil {
|
---|
197 | PS.cnfg.treecfg = PS.prob.TreeCfg.Clone()
|
---|
198 | }
|
---|
199 | srules := expr.DefaultRules()
|
---|
200 | srules.ConvertConsts = true
|
---|
201 | PS.cnfg.simprules = srules
|
---|
202 |
|
---|
203 | //fmt.Println("Roots: ", PS.cnfg.treecfg.RootsS)
|
---|
204 | //fmt.Println("Nodes: ", PS.cnfg.treecfg.NodesS)
|
---|
205 | //fmt.Println("Leafs: ", PS.cnfg.treecfg.LeafsS)
|
---|
206 | //fmt.Println("NonTrig: ", PS.cnfg.treecfg.NonTrigS)
|
---|
207 |
|
---|
208 | PS.GenRoots = make([]expr.Expr, len(PS.cnfg.treecfg.Roots))
|
---|
209 | for i := 0; i < len(PS.GenRoots); i++ {
|
---|
210 | PS.GenRoots[i] = PS.cnfg.treecfg.Roots[i].Clone()
|
---|
211 | }
|
---|
212 | PS.GenNodes = make([]expr.Expr, len(PS.cnfg.treecfg.Nodes))
|
---|
213 | for i := 0; i < len(PS.GenNodes); i++ {
|
---|
214 | PS.GenNodes[i] = PS.cnfg.treecfg.Nodes[i].Clone()
|
---|
215 | }
|
---|
216 | PS.GenNonTrig = make([]expr.Expr, len(PS.cnfg.treecfg.NonTrig))
|
---|
217 | for i := 0; i < len(PS.GenNonTrig); i++ {
|
---|
218 | PS.GenNonTrig[i] = PS.cnfg.treecfg.NonTrig[i].Clone()
|
---|
219 | }
|
---|
220 |
|
---|
221 | PS.GenLeafs = make([]expr.Expr, 0)
|
---|
222 | for _, t := range PS.cnfg.treecfg.LeafsT {
|
---|
223 | switch t {
|
---|
224 | case expr.TIME:
|
---|
225 | PS.GenLeafs = append(PS.GenLeafs, expr.NewTime())
|
---|
226 |
|
---|
227 | case expr.VAR:
|
---|
228 | //fmt.Println("Use Vars: ", PS.cnfg.treecfg.UsableVars)
|
---|
229 | for _, i := range PS.cnfg.treecfg.UsableVars {
|
---|
230 | PS.GenLeafs = append(PS.GenLeafs, expr.NewVar(i))
|
---|
231 | }
|
---|
232 |
|
---|
233 | case expr.SYSTEM:
|
---|
234 | for i := 0; i < PS.prob.Train[0].NumSys(); i++ {
|
---|
235 | PS.GenLeafs = append(PS.GenLeafs, expr.NewSystem(i))
|
---|
236 | }
|
---|
237 |
|
---|
238 | }
|
---|
239 | }
|
---|
240 | /*** FIX ME
|
---|
241 | PS.GenLeafs = make([]expr.Expr, len(PS.cnfg.treecfg.Leafs))
|
---|
242 | for i := 0; i < len(PS.GenLeafs); i++ {
|
---|
243 | PS.GenLeafs[i] = PS.cnfg.treecfg.Leafs[i].Clone()
|
---|
244 | }
|
---|
245 | ***/
|
---|
246 |
|
---|
247 | //fmt.Println("Roots: ", PS.GenRoots)
|
---|
248 | //fmt.Println("Nodes: ", PS.GenNodes)
|
---|
249 | //fmt.Println("Leafs: ", PS.GenLeafs)
|
---|
250 | //fmt.Println("NonTrig: ", PS.GenNonTrig)
|
---|
251 |
|
---|
252 | // setup communication struct
|
---|
253 | PS.commup = input.(*probs.ExprProblemComm)
|
---|
254 |
|
---|
255 | // initialize bbq
|
---|
256 | PS.Trie = new(IpreNode)
|
---|
257 | PS.Trie.val = -1
|
---|
258 | PS.Trie.next = make(map[int]*IpreNode)
|
---|
259 |
|
---|
260 | PS.Best = probs.NewReportQueue()
|
---|
261 | PS.Best.SetSort(probs.GPSORT_PARETO_TST_ERR)
|
---|
262 |
|
---|
263 | PS.Queue = PS.GenInitExpr()
|
---|
264 | PS.Queue.SetSort(probs.PESORT_PARETO_TST_ERR)
|
---|
265 |
|
---|
266 | PS.neqns = PS.Queue.Len()
|
---|
267 |
|
---|
268 | PS.minError = math.Inf(1)
|
---|
269 |
|
---|
270 | PS.eval_in = make(chan expr.Expr, 4048)
|
---|
271 | PS.eval_out = make(chan *probs.ExprReport, 4048)
|
---|
272 |
|
---|
273 | for i := 0; i < PS.cnfg.evalrCount; i++ {
|
---|
274 | go PS.Evaluate()
|
---|
275 | }
|
---|
276 | }
|
---|
277 |
|
---|
278 | func (PS *PgeSearch) Evaluate() {
|
---|
279 |
|
---|
280 | for !PS.stop {
|
---|
281 | e := <-PS.eval_in
|
---|
282 | if e == nil {
|
---|
283 | continue
|
---|
284 | }
|
---|
285 | re := RegressExpr(e, PS.prob)
|
---|
286 | //fmt.Printf("reg: %v\n", re)
|
---|
287 | PS.eval_out <- re
|
---|
288 | }
|
---|
289 |
|
---|
290 | }
|
---|
291 |
|
---|
292 | func (PS *PgeSearch) Run() {
|
---|
293 | fmt.Printf("Running PGE\n")
|
---|
294 |
|
---|
295 | PS.Loop()
|
---|
296 |
|
---|
297 | fmt.Println("PGE exitting")
|
---|
298 |
|
---|
299 | PS.Clean()
|
---|
300 | PS.commup.Cmds <- -1
|
---|
301 | }
|
---|
302 |
|
---|
303 | func (PS *PgeSearch) Loop() {
|
---|
304 |
|
---|
305 | PS.checkMessages()
|
---|
306 | for !PS.stop {
|
---|
307 |
|
---|
308 | fmt.Println("in: PS.step() ", PS.iter)
|
---|
309 | PS.Step()
|
---|
310 |
|
---|
311 | // if PS.iter%PS.cnfg.pgeRptEpoch == 0 {
|
---|
312 | PS.reportExpr()
|
---|
313 | // }
|
---|
314 |
|
---|
315 | // report current iteration
|
---|
316 | PS.commup.Gen <- [2]int{PS.id, PS.iter}
|
---|
317 | PS.iter++
|
---|
318 |
|
---|
319 | PS.Clean()
|
---|
320 |
|
---|
321 | PS.checkMessages()
|
---|
322 |
|
---|
323 | }
|
---|
324 |
|
---|
325 | // done expanding, pull the rest of the regressed solutions from the queue
|
---|
326 | p := 0
|
---|
327 | for PS.Queue.Len() > 0 {
|
---|
328 | e := PS.Queue.Pop().(*probs.ExprReport)
|
---|
329 |
|
---|
330 | bPush := true
|
---|
331 | if len(e.Coeff()) == 1 && math.Abs(e.Coeff()[0]) < PS.cnfg.zeroEpsilon {
|
---|
332 | // fmt.Println("No Best Push")
|
---|
333 | bPush = false
|
---|
334 | }
|
---|
335 |
|
---|
336 | if bPush {
|
---|
337 | // fmt.Printf("pop/push(%d,%d): %v\n", p, PS.Best.Len(), e.Expr())
|
---|
338 | PS.Best.Push(e)
|
---|
339 | p++
|
---|
340 | }
|
---|
341 |
|
---|
342 | if e.TestScore() > PS.maxScore {
|
---|
343 | PS.maxScore = e.TestScore()
|
---|
344 | }
|
---|
345 | if e.TestError() < PS.minError {
|
---|
346 | PS.minError = e.TestError()
|
---|
347 | fmt.Printf("EXITING New Min Error: %v\n", e)
|
---|
348 | }
|
---|
349 | if e.Size() > PS.maxSize {
|
---|
350 | PS.maxSize = e.Size()
|
---|
351 | }
|
---|
352 | }
|
---|
353 |
|
---|
354 | fmt.Println("PGE sending last report")
|
---|
355 | PS.reportExpr()
|
---|
356 |
|
---|
357 | }
|
---|
358 |
|
---|
359 | func (PS *PgeSearch) Step() {
|
---|
360 | loop := 0
|
---|
361 | eval_cnt := 0 // for channeled eval
|
---|
362 |
|
---|
363 | es := PS.peel()
|
---|
364 |
|
---|
365 | ex := PS.expandPeeled(es)
|
---|
366 |
|
---|
367 | for cnt := range ex {
|
---|
368 | E := ex[cnt]
|
---|
369 |
|
---|
370 | if E == nil {
|
---|
371 | continue
|
---|
372 | }
|
---|
373 |
|
---|
374 | for _, e := range E {
|
---|
375 | if e == nil {
|
---|
376 | continue
|
---|
377 | }
|
---|
378 | if !PS.cnfg.treecfg.CheckExpr(e) {
|
---|
379 | continue
|
---|
380 | }
|
---|
381 |
|
---|
382 | // check ipre_trie
|
---|
383 | serial := make([]int, 0, 64)
|
---|
384 | serial = e.Serial(serial)
|
---|
385 | ins := PS.Trie.InsertSerial(serial)
|
---|
386 | if !ins {
|
---|
387 | continue
|
---|
388 | }
|
---|
389 |
|
---|
390 | // for serial eval
|
---|
391 | // re := RegressExpr(e, PS.prob)
|
---|
392 |
|
---|
393 | // start channeled eval
|
---|
394 | PS.eval_in <- e
|
---|
395 | eval_cnt++
|
---|
396 | }
|
---|
397 | }
|
---|
398 | for i := 0; i < eval_cnt; i++ {
|
---|
399 | re := <-PS.eval_out
|
---|
400 | // end channeled eval
|
---|
401 |
|
---|
402 | // check for NaN/Inf in re.error and if so, skip
|
---|
403 | if math.IsNaN(re.TestError()) || math.IsInf(re.TestError(), 0) {
|
---|
404 | // fmt.Printf("Bad Error\n%v\n", re)
|
---|
405 | continue
|
---|
406 | }
|
---|
407 |
|
---|
408 | if re.TestError() < PS.minError {
|
---|
409 | PS.minError = re.TestError()
|
---|
410 | }
|
---|
411 |
|
---|
412 | // check for coeff == 0
|
---|
413 | doIns := true
|
---|
414 | for _, c := range re.Coeff() {
|
---|
415 | // i > 0 for free coeff
|
---|
416 | if math.Abs(c) < PS.cnfg.zeroEpsilon {
|
---|
417 | doIns = false
|
---|
418 | break
|
---|
419 | }
|
---|
420 | }
|
---|
421 |
|
---|
422 | if doIns {
|
---|
423 | re.SetProcID(PS.id)
|
---|
424 | re.SetIterID(PS.iter)
|
---|
425 | re.SetUnitID(loop)
|
---|
426 | re.SetUniqID(PS.neqns)
|
---|
427 | loop++
|
---|
428 | PS.neqns++
|
---|
429 | // fmt.Printf("Queue.Push(): %v\n%v\n\n", re.Expr(), serial)
|
---|
430 | // fmt.Printf("Queue.Push(): %v\n", re)
|
---|
431 | // fmt.Printf("Queue.Push(): %v\n", re.Expr())
|
---|
432 |
|
---|
433 | PS.Queue.Push(re)
|
---|
434 |
|
---|
435 | }
|
---|
436 | }
|
---|
437 | // } // for sequential eval
|
---|
438 | PS.Queue.Sort()
|
---|
439 | }
|
---|
440 |
|
---|
441 | func (PS *PgeSearch) peel() []*probs.ExprReport {
|
---|
442 | es := make([]*probs.ExprReport, PS.cnfg.peelCnt)
|
---|
443 | for p := 0; p < PS.cnfg.peelCnt && PS.Queue.Len() > 0; p++ {
|
---|
444 | e := PS.Queue.Pop().(*probs.ExprReport)
|
---|
445 | bPush := true
|
---|
446 | if len(e.Coeff()) == 1 && math.Abs(e.Coeff()[0]) < PS.cnfg.zeroEpsilon {
|
---|
447 | fmt.Println("No Best Push")
|
---|
448 | p--
|
---|
449 | continue
|
---|
450 | }
|
---|
451 |
|
---|
452 | if bPush {
|
---|
453 | fmt.Printf("pop/push DO(%d,%d): %v\n", p, PS.Best.Len(), e.Expr())
|
---|
454 | PS.Best.Push(e)
|
---|
455 | }
|
---|
456 |
|
---|
457 | es[p] = e
|
---|
458 |
|
---|
459 | if e.TestScore() > PS.maxScore {
|
---|
460 | PS.maxScore = e.TestScore()
|
---|
461 | }
|
---|
462 | if e.TestError() < PS.minError {
|
---|
463 | PS.minError = e.TestError()
|
---|
464 | fmt.Printf("Best New Min Error: %v\n", e)
|
---|
465 | }
|
---|
466 | if e.Size() > PS.maxSize {
|
---|
467 | PS.maxSize = e.Size()
|
---|
468 | }
|
---|
469 |
|
---|
470 | }
|
---|
471 | return es
|
---|
472 | }
|
---|
473 |
|
---|
474 |
|
---|
475 | type PeelResult struct {
|
---|
476 | Es *probs.ExprReport
|
---|
477 |
|
---|
478 | Nobestpush bool
|
---|
479 | BestNewMinErr bool
|
---|
480 |
|
---|
481 | Bestlen1 int
|
---|
482 | Bestlen2 int
|
---|
483 |
|
---|
484 | Coeff []float64
|
---|
485 | TestScore int
|
---|
486 |
|
---|
487 | Expre expr.Expr
|
---|
488 | ExpreRe *probs.ExprReport
|
---|
489 | }
|
---|
490 |
|
---|
491 |
|
---|
492 | func (PS *PgeSearch) SingleStep() []*PeelResult {
|
---|
493 | loop := 0
|
---|
494 | eval_cnt := 0
|
---|
495 | PR := PS.peelRes()
|
---|
496 |
|
---|
497 | es := make([]*probs.ExprReport, len(PR))
|
---|
498 |
|
---|
499 | for i, elem := range PR {
|
---|
500 | es[i] = elem.ExpreRe
|
---|
501 | }
|
---|
502 |
|
---|
503 | ex := PS.expandPeeled(es)
|
---|
504 |
|
---|
505 | for cnt := range ex {
|
---|
506 | E := ex[cnt]
|
---|
507 | if E == nil {
|
---|
508 | continue
|
---|
509 | }
|
---|
510 | for _, e := range E {
|
---|
511 | if e == nil {
|
---|
512 | continue
|
---|
513 | }
|
---|
514 | if !PS.cnfg.treecfg.CheckExpr(e) {
|
---|
515 | continue
|
---|
516 | }
|
---|
517 | serial := make([]int, 0, 64)
|
---|
518 | serial = e.Serial(serial)
|
---|
519 | ins := PS.Trie.InsertSerial(serial)
|
---|
520 |
|
---|
521 | if !ins {
|
---|
522 | continue
|
---|
523 | }
|
---|
524 | PS.eval_in <- e
|
---|
525 | eval_cnt++
|
---|
526 | }
|
---|
527 | }
|
---|
528 | for i := 0; i < eval_cnt; i++ {
|
---|
529 | re := <-PS.eval_out
|
---|
530 | if math.IsNaN(re.TestError()) || math.IsInf(re.TestError(), 0) {
|
---|
531 | continue
|
---|
532 | }
|
---|
533 | if re.TestError() < PS.minError {
|
---|
534 | PS.minError = re.TestError()
|
---|
535 | }
|
---|
536 | doIns := true
|
---|
537 | for _, c := range re.Coeff() {
|
---|
538 | if math.Abs(c) < PS.cnfg.zeroEpsilon {
|
---|
539 | doIns = false
|
---|
540 | break
|
---|
541 | }
|
---|
542 | }
|
---|
543 | if doIns {
|
---|
544 | re.SetProcID(PS.id)
|
---|
545 | re.SetIterID(PS.iter)
|
---|
546 | re.SetUnitID(loop)
|
---|
547 | re.SetUniqID(PS.neqns)
|
---|
548 | loop++
|
---|
549 | PS.neqns++
|
---|
550 | PS.Queue.Push(re)
|
---|
551 | }
|
---|
552 | }
|
---|
553 | PS.Queue.Sort()
|
---|
554 |
|
---|
555 | PS.reportExpr()
|
---|
556 | PS.iter++
|
---|
557 |
|
---|
558 | return PR
|
---|
559 | }
|
---|
560 |
|
---|
561 | func (PS *PgeSearch) peelRes() []*PeelResult {
|
---|
562 | //es := make([]*probs.ExprReport, PS.cnfg.peelCnt)
|
---|
563 | PRes := make([]*PeelResult, PS.cnfg.peelCnt)
|
---|
564 |
|
---|
565 | for p := 0; p < PS.cnfg.peelCnt && PS.Queue.Len() > 0; p++ {
|
---|
566 | PR := new(PeelResult)
|
---|
567 |
|
---|
568 | PR.BestNewMinErr = false
|
---|
569 | PR.Nobestpush = false
|
---|
570 |
|
---|
571 | e := PS.Queue.Pop().(*probs.ExprReport)
|
---|
572 |
|
---|
573 | bPush := true
|
---|
574 | if len(e.Coeff()) == 1 && math.Abs(e.Coeff()[0]) < PS.cnfg.zeroEpsilon {
|
---|
575 | //fmt.Println("No Best Push")
|
---|
576 | PR.Nobestpush = true
|
---|
577 | p--
|
---|
578 | continue
|
---|
579 | }
|
---|
580 |
|
---|
581 | if bPush {
|
---|
582 | //fmt.Printf("pop/push (%d,%d): %v\n", p, PS.Best.Len(), e.Expr())
|
---|
583 | PR.Bestlen1 = p
|
---|
584 | PR.Bestlen2 = PS.Best.Len()
|
---|
585 | PR.Expre = e.Expr()
|
---|
586 | PR.ExpreRe = e
|
---|
587 | PS.Best.Push(e)
|
---|
588 | }
|
---|
589 |
|
---|
590 | //es[p] = e
|
---|
591 | PR.Es = e
|
---|
592 | PR.Coeff = e.Coeff()
|
---|
593 | PR.TestScore = e.TestScore()
|
---|
594 |
|
---|
595 |
|
---|
596 | if e.TestScore() > PS.maxScore {
|
---|
597 | PS.maxScore = e.TestScore()
|
---|
598 | }
|
---|
599 | if e.TestError() < PS.minError {
|
---|
600 | PS.minError = e.TestError()
|
---|
601 | PR.BestNewMinErr = true
|
---|
602 | //fmt.Printf("Best New Min Error: %v\n", e)
|
---|
603 | }
|
---|
604 | if e.Size() > PS.maxSize {
|
---|
605 | PS.maxSize = e.Size()
|
---|
606 | }
|
---|
607 |
|
---|
608 | PRes[p] = PR
|
---|
609 | }
|
---|
610 |
|
---|
611 | return PRes
|
---|
612 | }
|
---|
613 |
|
---|
614 |
|
---|
615 | func (PS *PgeSearch) expandPeeled(es []*probs.ExprReport) [][]expr.Expr {
|
---|
616 | eqns := make([][]expr.Expr, PS.cnfg.peelCnt)
|
---|
617 | for p := 0; p < PS.cnfg.peelCnt; p++ {
|
---|
618 | if es[p] == nil {
|
---|
619 | continue
|
---|
620 | }
|
---|
621 | // fmt.Printf("expand(%d): %v\n", p, es[p].Expr())
|
---|
622 | if es[p].Expr().ExprType() != expr.ADD {
|
---|
623 | add := expr.NewAdd()
|
---|
624 | add.Insert(es[p].Expr())
|
---|
625 | add.CalcExprStats()
|
---|
626 | es[p].SetExpr(add)
|
---|
627 | }
|
---|
628 | eqns[p] = PS.Expand(es[p].Expr())
|
---|
629 | // fmt.Printf("Results:\n")
|
---|
630 | // for i, e := range eqns[p] {
|
---|
631 | // fmt.Printf("%d,%d: %v\n", p, i, e)
|
---|
632 | // }
|
---|
633 | // fmt.Println()
|
---|
634 | }
|
---|
635 | return eqns
|
---|
636 | }
|
---|
637 |
|
---|
638 | func (PS *PgeSearch) reportExpr() {
|
---|
639 |
|
---|
640 | cnt := PS.cnfg.pgeRptCount
|
---|
641 | PS.Best.Sort()
|
---|
642 |
|
---|
643 | // repot best equations
|
---|
644 | rpt := make(probs.ExprReportArray, cnt)
|
---|
645 | if PS.Best.Len() < cnt {
|
---|
646 | cnt = PS.Best.Len()
|
---|
647 | }
|
---|
648 | copy(rpt, PS.Best.GetQueue()[:cnt])
|
---|
649 |
|
---|
650 | errSum, errCnt := 0.0, 0
|
---|
651 | PS.eqnsLog.Println("\n\nReport", PS.iter)
|
---|
652 | for i, r := range rpt {
|
---|
653 | PS.eqnsLog.Printf("\n%d: %v\n", i, r)
|
---|
654 | if r != nil && r.Expr() != nil {
|
---|
655 | errSum += r.TestError()
|
---|
656 | errCnt++
|
---|
657 | }
|
---|
658 | }
|
---|
659 |
|
---|
660 | PS.mainLog.Printf("Iter: %d %f %f\n", PS.iter, errSum/float64(errCnt), PS.minError)
|
---|
661 |
|
---|
662 | PS.ipreLog.Println(PS.iter, PS.neqns, PS.Trie.cnt, PS.Trie.vst)
|
---|
663 | PS.fitnessLog.Println(PS.iter, PS.neqns, PS.Trie.cnt, PS.Trie.vst, errSum/float64(errCnt), PS.minError)
|
---|
664 |
|
---|
665 | PS.commup.Rpts <- &rpt
|
---|
666 |
|
---|
667 | }
|
---|
668 |
|
---|
669 | func (PS *PgeSearch) Clean() {
|
---|
670 | PS.errLogBuf.Flush()
|
---|
671 | PS.mainLogBuf.Flush()
|
---|
672 | PS.eqnsLogBuf.Flush()
|
---|
673 | PS.fitnessLogBuf.Flush()
|
---|
674 | PS.ipreLogBuf.Flush()
|
---|
675 | }
|
---|
676 |
|
---|
677 | func (PS *PgeSearch) initLogs(logdir string) {
|
---|
678 | // open logs
|
---|
679 | PS.logDir = logdir + "pge/"
|
---|
680 | os.Mkdir(PS.logDir, os.ModePerm)
|
---|
681 | tmpF0, err5 := os.Create(PS.logDir + "pge:err.log")
|
---|
682 | if err5 != nil {
|
---|
683 | log.Fatal("couldn't create errs log")
|
---|
684 | }
|
---|
685 | PS.errLogBuf = bufio.NewWriter(tmpF0)
|
---|
686 | PS.errLogBuf.Flush()
|
---|
687 | PS.errLog = log.New(PS.errLogBuf, "", log.LstdFlags)
|
---|
688 |
|
---|
689 | tmpF1, err1 := os.Create(PS.logDir + "pge:main.log")
|
---|
690 | if err1 != nil {
|
---|
691 | log.Fatal("couldn't create main log")
|
---|
692 | }
|
---|
693 | PS.mainLogBuf = bufio.NewWriter(tmpF1)
|
---|
694 | PS.mainLogBuf.Flush()
|
---|
695 | PS.mainLog = log.New(PS.mainLogBuf, "", log.LstdFlags)
|
---|
696 |
|
---|
697 | tmpF2, err2 := os.Create(PS.logDir + "pge:eqns.log")
|
---|
698 | if err2 != nil {
|
---|
699 | log.Fatal("couldn't create eqns log")
|
---|
700 | }
|
---|
701 | PS.eqnsLogBuf = bufio.NewWriter(tmpF2)
|
---|
702 | PS.eqnsLogBuf.Flush()
|
---|
703 | PS.eqnsLog = log.New(PS.eqnsLogBuf, "", 0)
|
---|
704 |
|
---|
705 | tmpF3, err3 := os.Create(PS.logDir + "pge:fitness.log")
|
---|
706 | if err3 != nil {
|
---|
707 | log.Fatal("couldn't create eqns log")
|
---|
708 | }
|
---|
709 | PS.fitnessLogBuf = bufio.NewWriter(tmpF3)
|
---|
710 | PS.fitnessLogBuf.Flush()
|
---|
711 | PS.fitnessLog = log.New(PS.fitnessLogBuf, "", log.Ltime|log.Lmicroseconds)
|
---|
712 |
|
---|
713 | tmpF4, err4 := os.Create(PS.logDir + "pge:ipre.log")
|
---|
714 | if err4 != nil {
|
---|
715 | log.Fatal("couldn't create eqns log")
|
---|
716 | }
|
---|
717 | PS.ipreLogBuf = bufio.NewWriter(tmpF4)
|
---|
718 | PS.ipreLogBuf.Flush()
|
---|
719 | PS.ipreLog = log.New(PS.ipreLogBuf, "", log.Ltime|log.Lmicroseconds)
|
---|
720 | }
|
---|
721 |
|
---|
722 | func (PS *PgeSearch) checkMessages() {
|
---|
723 |
|
---|
724 | // check messages from superior
|
---|
725 | select {
|
---|
726 | case cmd, ok := <-PS.commup.Cmds:
|
---|
727 | if ok {
|
---|
728 | if cmd == -1 {
|
---|
729 | fmt.Println("PGE: stop sig recv'd")
|
---|
730 | PS.stop = true
|
---|
731 | return
|
---|
732 | }
|
---|
733 | }
|
---|
734 | default:
|
---|
735 | return
|
---|
736 | }
|
---|
737 | }
|
---|
738 |
|
---|
739 | var c_input, c_ygiven []levmar.C_double
|
---|
740 |
|
---|
741 | func RegressExpr(E expr.Expr, P *probs.ExprProblem) (R *probs.ExprReport) {
|
---|
742 |
|
---|
743 | guess := make([]float64, 0)
|
---|
744 | guess, eqn := E.ConvertToConstants(guess)
|
---|
745 |
|
---|
746 | var coeff []float64
|
---|
747 | if len(guess) > 0 {
|
---|
748 |
|
---|
749 | //fmt.Printf("IMREGEXP %v %v\n", P.SearchType, P.SearchVar)
|
---|
750 | //fmt.Printf("REGPTrain %T | %#v | %v\n", P.Train, P.Train, P.Train)
|
---|
751 | //fmt.Printf("eqn %T | %#v | %v\n", eqn, eqn, eqn)
|
---|
752 | //fmt.Printf("guess %T | %#v | %v\n", guess, guess, guess)
|
---|
753 |
|
---|
754 | // Callback version
|
---|
755 |
|
---|
756 |
|
---|
757 | coeff = levmar.LevmarExpr(eqn, P.SearchVar, P.SearchType, guess, P.Train, P.Test)
|
---|
758 |
|
---|
759 |
|
---|
760 | // Stack version
|
---|
761 | // x_dim := P.Train[0].NumDim()
|
---|
762 | // if c_input == nil {
|
---|
763 | // ps := P.Train[0].NumPoints()
|
---|
764 | // PS := len(P.Train) * ps
|
---|
765 | // x_tot := PS * x_dim
|
---|
766 |
|
---|
767 | // c_input = make([]levmar.C_double, x_tot)
|
---|
768 | // c_ygiven = make([]levmar.C_double, PS)
|
---|
769 |
|
---|
770 | // for i1, T := range P.Train {
|
---|
771 | // for i2, p := range T.Points() {
|
---|
772 | // i := i1*ps + i2
|
---|
773 | // c_ygiven[i] = levmar.MakeCDouble(p.Depnd(P.SearchVar))
|
---|
774 | // for i3, x_p := range p.Indeps() {
|
---|
775 | // j := i1*ps*x_dim + i2*x_dim + i3
|
---|
776 | // c_input[j] = levmar.MakeCDouble(x_p)
|
---|
777 | // }
|
---|
778 | // }
|
---|
779 | // }
|
---|
780 | // }
|
---|
781 | // coeff = levmar.StackLevmarExpr(eqn, x_dim, guess, c_ygiven, c_input)
|
---|
782 |
|
---|
783 | // serial := make([]int, 0)
|
---|
784 | // serial = eqn.StackSerial(serial)
|
---|
785 | // fmt.Printf("StackSerial: %v\n", serial)
|
---|
786 | // fmt.Printf("%v\n%v\n%v\n\n", eqn, coeff, steff)
|
---|
787 | }
|
---|
788 |
|
---|
789 | R = new(probs.ExprReport)
|
---|
790 | R.SetExpr(eqn) /*.ConvertToConstantFs(coeff)*/
|
---|
791 |
|
---|
792 | R.SetCoeff(coeff)
|
---|
793 | R.Expr().CalcExprStats()
|
---|
794 |
|
---|
795 | // hitsL1, hitsL2, evalCnt, nanCnt, infCnt, l1_err, l2_err := scoreExpr(E, P, coeff)
|
---|
796 | _, _, _, trnNanCnt, _, trn_l1_err, _ := scoreExpr(E, P, P.Train, coeff)
|
---|
797 | _, _, tstEvalCnt, tstNanCnt, _, tst_l1_err, tst_l2_err := scoreExpr(E, P, P.Test, coeff)
|
---|
798 |
|
---|
799 | R.SetTrainScore(trnNanCnt)
|
---|
800 | R.SetTrainError(trn_l1_err)
|
---|
801 |
|
---|
802 | R.SetPredScore(tstNanCnt)
|
---|
803 | R.SetTestScore(tstEvalCnt)
|
---|
804 | R.SetTestError(tst_l1_err)
|
---|
805 | R.SetPredError(tst_l2_err)
|
---|
806 |
|
---|
807 | return R
|
---|
808 | }
|
---|
809 |
|
---|
810 | func scoreExpr(e expr.Expr, P *probs.ExprProblem, dataSets []*probs.PointSet, coeff []float64) (hitsL1, hitsL2, evalCnt, nanCnt, infCnt int, l1_err, l2_err float64) {
|
---|
811 | var l1_sum, l2_sum float64
|
---|
812 | for _, PS := range dataSets {
|
---|
813 | for _, p := range PS.Points() {
|
---|
814 | y := p.Depnd(P.SearchVar)
|
---|
815 | var out float64
|
---|
816 | if P.SearchType == probs.ExprBenchmark {
|
---|
817 | out = e.Eval(0, p.Indeps(), coeff, PS.SysVals())
|
---|
818 | } else if P.SearchType == probs.ExprDiffeq {
|
---|
819 | out = e.Eval(p.Indep(0), p.Indeps()[1:], coeff, PS.SysVals())
|
---|
820 | }
|
---|
821 |
|
---|
822 | if math.IsNaN(out) {
|
---|
823 | nanCnt++
|
---|
824 | continue
|
---|
825 | } else if math.IsInf(out, 0) {
|
---|
826 | infCnt++
|
---|
827 | continue
|
---|
828 | } else {
|
---|
829 | evalCnt++
|
---|
830 | }
|
---|
831 |
|
---|
832 | diff := out - y
|
---|
833 | l1_val := math.Abs(diff)
|
---|
834 | l2_val := diff * diff
|
---|
835 | l1_sum += l1_val
|
---|
836 | l2_sum += l2_val
|
---|
837 |
|
---|
838 | if l1_val < P.HitRatio {
|
---|
839 | hitsL1++
|
---|
840 | }
|
---|
841 | if l2_val < P.HitRatio {
|
---|
842 | hitsL2++
|
---|
843 | }
|
---|
844 | }
|
---|
845 | }
|
---|
846 |
|
---|
847 | if evalCnt == 0 {
|
---|
848 | l1_err = math.NaN()
|
---|
849 | l2_err = math.NaN()
|
---|
850 | } else {
|
---|
851 | fEvalCnt := float64(evalCnt + 1)
|
---|
852 | l1_err = l1_sum / fEvalCnt
|
---|
853 | l2_err = math.Sqrt(l2_sum / fEvalCnt)
|
---|
854 | }
|
---|
855 |
|
---|
856 | return
|
---|
857 | }
|
---|
858 |
|
---|
859 | func (PS *PgeSearch) CreateDS(maxGen int, pgeRptEpoch int, pgeRptCount int, pgeArchiveCap int, peelCnt int, evalrCount int, zeroEpsilon float64, initMethod string, growMethod string, sortType int) {
|
---|
860 | PS.id = 0 //maxGen
|
---|
861 |
|
---|
862 | var PC PgeConfig
|
---|
863 |
|
---|
864 | PC.pgeRptEpoch = pgeRptEpoch
|
---|
865 | PC.pgeRptCount = pgeRptCount
|
---|
866 | PC.pgeArchiveCap = pgeArchiveCap
|
---|
867 | PC.peelCnt = peelCnt
|
---|
868 | PC.evalrCount = evalrCount
|
---|
869 | PC.zeroEpsilon = zeroEpsilon
|
---|
870 | PC.initMethod = initMethod
|
---|
871 | PC.growMethod = growMethod
|
---|
872 |
|
---|
873 | if sortType == 1 {
|
---|
874 | PC.sortType = probs.PESORT_PARETO_TRN_ERR
|
---|
875 | } else {
|
---|
876 | PC.sortType = probs.PESORT_PARETO_TST_ERR
|
---|
877 | }
|
---|
878 |
|
---|
879 | PC.maxGen = maxGen
|
---|
880 | PS.cnfg = PC
|
---|
881 |
|
---|
882 | PS.iter = 0
|
---|
883 | }
|
---|
884 |
|
---|
885 | func (PS *PgeSearch) SetProb(ep *probs.ExprProblem) {
|
---|
886 | PS.prob = ep
|
---|
887 | }
|
---|
888 | func (PS *PgeSearch) GetIter() int {
|
---|
889 | return PS.iter
|
---|
890 | } |
---|