Beispiel #1
0
func (p *Particle) Update(newp *optim.Point) {
	// DO NOT update p's position with newp's position - it may have been
	// projected onto a mesh and be different.
	p.Val = newp.Val
	if p.Val < p.Best.Val {
		p.Best = newp.Clone()
	}
}
Beispiel #2
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 #3
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 #4
0
func genPollPoints(from *optim.Point, span Spanner, m optim.Mesh) []*optim.Point {
	ndim := from.Len()
	dirs := span.Span(ndim)
	polls := make([]*optim.Point, 0, len(dirs))
	for _, d := range dirs {
		polls = append(polls, pointFromDirec(from, d, m))
	}
	return polls
}
Beispiel #5
0
func New(start *optim.Point, opts ...Option) *Method {
	m := &Method{
		Curr:         start,
		ev:           optim.SerialEvaler{},
		Poller:       &Poller{Nkeep: start.Len() / 4, SkipEps: 1e-10},
		Searcher:     NullSearcher{},
		NsuccessGrow: -1,
		StepMult:     1.0 / 1.7,
	}

	for _, opt := range opts {
		opt(m)
	}
	m.initdb()
	return m
}
Beispiel #6
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 {
		ndim := len(from.Pos)
		if ndim > 10 {
			cp.Spanner = &RandomN{N: len(from.Pos)}
		} else {
			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 cp.FlipCompass > 0 && cp.nConsecFail >= cp.FlipCompass {
		// Use compass directions instead
		cp.Spanner = CompassNp1{}
	}
	pollpoints = genPollPoints(from, cp.Spanner, m)
	cp.prevhash = h
	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)
	}

	c2n := Compass2N{}
	if cp.Spanner != c2n {
		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 == FoundBetterErr {
		err = nil
	}

	// 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 {
		cp.nConsecFail = 0
	} else {
		cp.nConsecFail++
	}
	return best.Val < from.Val, best, n, err
}