func pointFromDirec(from *optim.Point, direc []int, m optim.Mesh) *optim.Point { pos := make([]float64, from.Len()) step := m.Step() for i, x0 := range from.Pos { pos[i] = x0 + float64(direc[i])*step } return &optim.Point{m.Nearest(pos), math.Inf(1)} }
func (m *Method) Iterate(obj optim.Objectiver, mesh optim.Mesh) (best *optim.Point, neval int, err error) { defer func() { m.iter++ }() // project positions onto mesh pmap := make(map[*optim.Point]*Particle, len(m.Pop)) points := make([]*optim.Point, len(m.Pop)) for i, particle := range m.Pop { p := particle.Point.Clone() p.Val = math.Inf(1) points[i] = p pmap[p] = particle } if mesh != nil { for _, p := range points { p.Pos = mesh.Nearest(p.Pos) } } // evaluate current positions results, n, err := m.Evaler.Eval(obj, points...) if err != nil { return &optim.Point{Val: math.Inf(1)}, n, err } for _, p := range results { pmap[p].Update(p) } m.updateDb(mesh) // TODO: write test to make sure this checks pbest.Best.Val instead of p.Val. pbest := m.Pop.Best() if pbest != nil && pbest.Best.Val < m.best.Val { m.best = pbest.Best } // move particles and update current best for _, p := range m.Pop { p.Move(m.best, m.Vmax, m.InertiaFn(m.iter), m.Social, m.Cognition) } // Kill slow particles near global optimum. // This MUST go after the updating of the iterator's best position. for i, p := range m.Pop { if p.Kill(m.best, m.Xtol, m.Vtol) { m.Pop = append(m.Pop[:i], m.Pop[i+1:]...) } } return m.best, n, nil }
// Poll polls on mesh m centered on point from. It is responsible for // selecting points and evaluating them with ev using obj. If a better // point was found, it returns success == true, the point, and number of // evaluations. If a better point was not found, it returns false, the // from point, and the number of evaluations. If err is non-nil, success // must be false and best must be from - neval may be non-zero. func (cp *Poller) Poll(obj optim.Objectiver, ev optim.Evaler, m optim.Mesh, from *optim.Point) (success bool, best *optim.Point, neval int, err error) { best = from if cp.Spanner == nil { cp.Spanner = Compass2N{} } pollpoints := []*optim.Point{} // Only poll compass directions if we haven't polled from this point // before. DONT DELETE - this can fire sometimes if the mesh isn't // allowed to contract below a certain step (i.e. integer meshes). h := from.Hash() if h != cp.prevhash || cp.prevstep != m.Step() { // TODO: write test that checks we poll compass dirs again if only mesh // step changed (and not from point) pollpoints = genPollPoints(from, cp.Spanner, m) cp.prevhash = h } else { // Use random directions instead. n := len(genPollPoints(from, cp.Spanner, m)) pollpoints = genPollPoints(from, &RandomN{N: n}, m) } cp.prevstep = m.Step() // Add successful directions from last poll. We want to add these points // in front of the other points so we can potentially stop earlier if // polling opportunistically. perms := optim.Rand.Perm(len(pollpoints)) // this is an extra safety check to make sure we don't index out of bounds // on the perms slice max := len(cp.keepdirecs) if max > len(perms) { max = len(perms) } for i, dir := range cp.keepdirecs[:max] { swapindex := perms[i] pollpoints[swapindex] = pointFromDirec(from, dir.dir, m) } // project points onto feasible region and mesh grid if m != nil { for _, p := range pollpoints { p.Pos = m.Nearest(p.Pos) } } cp.points = make([]*optim.Point, 0, len(pollpoints)) if cp.SkipEps == 0 { cp.points = pollpoints } else { for _, p := range pollpoints { // It is possible that due to the mesh gridding, the poll point is // outside of constraints or bounds and will be rounded back to the // current point. Check for this and skip the poll point if this is // the case. dist := optim.L2Dist(from, p) if dist > cp.SkipEps { cp.points = append(cp.points, p) } } } objstop := &objStopper{Objectiver: obj, Best: from.Val} results, n, err := ev.Eval(objstop, cp.points...) if err != nil && err != FoundBetterErr { return false, best, n, err } // this is separate from best to allow all points better than from to be // added to keepdirecs before we update the best point. nextbest := from // Sort results and keep the best Nkeep as poll directions. for _, p := range results { if p.Val < best.Val { cp.keepdirecs = append(cp.keepdirecs, direc{direcbetween(from, p, m), p.Val}) } if p.Val < nextbest.Val { nextbest = p } } best = nextbest nkeep := cp.Nkeep if max := len(pollpoints) / 4; max < nkeep { nkeep = max } sort.Sort(byval(cp.keepdirecs)) if len(cp.keepdirecs) > nkeep { cp.keepdirecs = cp.keepdirecs[:nkeep] } if best.Val < from.Val { return true, best, n, nil } else { return false, from, n, nil } }
func (m *Method) updateDb(mesh optim.Mesh) { if m.Db == nil { return } tx, err := m.Db.Begin() if err != nil { panic(err.Error()) } defer tx.Commit() s0, err := tx.Prepare("INSERT INTO " + TblParticles + " (particle,iter,val,posid,velid,vel) VALUES (?,?,?,?,?,?);") if checkdberr(err) { return } s0b, err := tx.Prepare("INSERT INTO " + TblParticlesMeshed + " (particle,iter,val,posid) VALUES (?,?,?,?);") if checkdberr(err) { return } s1, err := tx.Prepare("INSERT INTO " + TblParticlesBest + " (particle,iter,best,posid) VALUES (?,?,?,?);") if checkdberr(err) { return } pts := []*optim.Point{} for _, p := range m.Pop { vel := &optim.Point{Pos: p.Vel} pts = append(pts, p.Point) pts = append(pts, p.Best) // best might be a projected location and not present in normal eval points pts = append(pts, vel) _, err := s0.Exec(p.Id, m.iter, p.Val, p.HashSlice(), vel.HashSlice(), p.L2Vel()) if checkdberr(err) { return } _, err = s1.Exec(p.Id, m.iter, p.Best.Val, p.Best.HashSlice()) if checkdberr(err) { return } pp := &optim.Point{mesh.Nearest(p.Pos), p.Val} _, err = s0b.Exec(p.Id, m.iter, p.Val, pp.HashSlice()) if checkdberr(err) { return } } s2, err := tx.Prepare("INSERT INTO " + TblBest + " (iter,val,posid) VALUES (?,?,?);") glob := m.best _, err = s2.Exec(m.iter, glob.Val, glob.HashSlice()) if checkdberr(err) { return } pts = append(pts, glob) err = optim.RecordPointPos(tx, pts...) if checkdberr(err) { return } }