Beispiel #1
0
func direcbetween(from, to *optim.Point, m optim.Mesh) []int {
	d := make([]int, from.Len())
	step := m.Step()
	for i, x0 := range from.Pos {
		d[i] = int((to.Pos[i] - x0) / step)
	}
	return d
}
Beispiel #2
0
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)}
}
Beispiel #3
0
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
}
Beispiel #4
0
// 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
	}
}
Beispiel #5
0
// Iterate mutates m and so for each iteration, the same, mutated m should be
// passed in.
func (m *Method) Iterate(o optim.Objectiver, mesh optim.Mesh) (best *optim.Point, n int, err error) {
	if m.count == 0 {
		m.origstep = mesh.Step()
	} else if mesh.Step() < m.ResetStep {
		mesh.SetStep(m.origstep)
	}

	var nevalsearch, nevalpoll int
	var success bool
	defer m.updateDb(&nevalsearch, &nevalpoll, mesh.Step())
	m.count++

	prevstep := mesh.Step()
	if !m.DiscreteSearch {
		mesh.SetStep(0)
	}

	success, best, nevalsearch, err = m.Searcher.Search(o, mesh, m.Curr)
	mesh.SetStep(prevstep)

	n += nevalsearch
	if err != nil {
		return best, n, err
	} else if success {
		m.Curr = best
		return best, n, nil
	}

	// It is important to recenter mesh on new best point before polling.
	// This is necessary because the search may not be operating on the
	// current mesh grid.  This doesn't need to happen if search succeeds
	// because search either always operates on the same grid, or always
	// operates in continuous space.
	mesh.SetOrigin(m.Curr.Pos) // TODO: test that this doesn't get set to Zero pos [0 0 0...] on first iteration.

	success, best, nevalpoll, err = m.Poller.Poll(o, m.ev, mesh, m.Curr)
	m.Poller.Spanner.Update(mesh.Step(), success)

	n += nevalpoll
	if err != nil {
		return m.Curr, n, err
	} else if success {
		m.Curr = best
		m.nsuccess++
		if m.nsuccess == m.NsuccessGrow { // == allows -1 to mean never grow
			mesh.SetStep(mesh.Step() * 2.0)
			m.nsuccess = 0 // reset after resize
		}

		// Important to recenter mesh on new best point.  More particularly,
		// the mesh may have been resized and the new best may not lie on the
		// previous mesh grid.
		mesh.SetOrigin(best.Pos)

		return best, n, nil
	} else {
		m.nsuccess = 0
		var err error
		mesh.SetStep(mesh.Step() * 0.5)
		if mesh.Step() == 0 {
			err = ZeroStepErr
		}
		return m.Curr, n, err
	}
}
Beispiel #6
0
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
	}
}