def update_potential_rectangle(self, x, depth, i): ''' Check potentially Potential Hyper-rectangles. :param x: :param depth: :param i: :return: updated or not ''' # print("x::::::::::", x) f = self.fun(self.denormalize(x)) if depth[i] <= self.max_depth and f <= self.f: # build new cube with x_new, depth_new x_new = x.copy() depth_new = depth.copy() depth_new[i] += 1 cube = Cube(x_new, f, depth_new) heapq.heappush(self.pq_cache, (f - self.K * 0.5**depth_new[i], self.niter, cube)) if f < self.f: self.f = f self.x = x.copy() if self.debug: DbgMsgOut( "DIRECT", "Better centers found in iteration i=" + str(self.niter) + " fbest=" + str(self.f)) return 1 elif f == self.f: return 0 else: return -1
def reset(self, x0): """ Puts the optimizer in its initial state and sets the initial point to be the 1-dimensional array or list *x0*. """ # Debug message if self.debug: DbgMsgOut("OPT", "Resetting.") # Determine dimension of the problem from initial point x0 = array(x0) self.ndim = x0.shape[0] if x0.ndim != 1: raise Exception(DbgMsg("OPT", "Initial point must be a vector.")) # Store initial point self.x = x0.copy() self.f = None # Reset iteration counter self.niter = 0 # Reset plugins for plugin in self.plugins: if plugin is not None: plugin.reset()
def reset(self, x0): x0 = array(x0) Optimizer.reset(self, x0) if self.debug: DbgMsgOut("BCOPT", "Resetting.") # Set default bounds to Inf, -Inf if self.xlo is None: self.xlo = zeros(self.ndim) self.xlo.fill(-Inf) else: self.xlo = array(self.xlo) if self.xhi is None: self.xhi = zeros(self.ndim) self.xhi.fill(Inf) else: self.xhi = array(self.xhi) self.hasBounds = False if np.isfinite(self.xlo).any() or np.isfinite(self.xhi).any(): self.hasBounds = True self.allBounds = False if np.isfinite(self.xlo).all() or np.isfinite(self.xhi).all(): self.allBounds = True # Check initial point against bounds if (x0 < self.xlo).any(): raise Exception( DbgMsg("BCOPT", "Initial point violates lower bound.")) if (x0 > self.xhi).any(): raise Exception( DbgMsg("BCOPT", "Initial point violates upper bound.")) # Normalization (defaults to low-high range) self.normScale = self.xhi - self.xlo self.normOrigin = self.xlo.copy() ndx = where(isinf(self.xlo) & ~isinf(self.xhi)) if len(ndx[0]) > 0: self.normScale[ndx] = 2 * (self.xhi[ndx] - x0[ndx]) self.normOrigin[ndx] = x0[ndx] - self.normScale[ndx] / 2.0 ndx = where(~isinf(self.xlo) & isinf(self.xhi)) if len(ndx[0]) > 0: self.normScale[ndx] = 2 * (x0[ndx] - self.xlo[ndx]) self.normOrigin[ndx] = self.xlo[ndx] ndx = where(isinf(self.xlo) & isinf(self.xhi)) if len(ndx[0]) > 0: self.normScale[ndx] = 2.0 self.normOrigin[ndx] = x0[ndx] - 1.0
def reset(self, x0): """ Puts the optimizer in its initial state and sets the initial point to be the 1-dimensional array *x0*. The length of the array becomes the dimension of the optimization problem (:attr:`ndim` member). The shape of *x* must match that of *xlo* and *xhi*. """ BoxConstrainedOptimizer.reset(self, x0) # Debug message if self.debug: DbgMsgOut("DIRECT", "Resetting DIRECT")
def newResult(self, x, f, annotations=None): """ Registers the cost function value *f* obtained at point *x* with annotations list given by *annotations*. """ self.niter += 1 if self.cache and self.cache.lookup(x) is None: self.cache.insert(x, (f, annotations, self.niter)) updated = self.updateBest(x, f) if annotations is not None: self.annotations = annotations self.annGrp.consume(annotations) if updated: self.bestAnnotations = self.annotations nplugins = len(self.plugins) for index in range(nplugins): plugin = self.plugins[index] if plugin is not None: stopBefore = self.stop plugin(x, f, self) if self.debug and self.stop and not stopBefore: DbgMsgOut("OPT", "Run stopped by plugin object.") # Force stop condition on f<=fstop if self.fstop is not None and self.f <= self.fstop: self.stop = True if self.debug: DbgMsgOut("OPT", "Function fell below desired value. Stopping.") # Force stop condition on niter > maxiter if self.maxiter is not None and self.niter >= self.maxiter: self.stop = True if self.debug: DbgMsgOut("OPT", "Maximal number of iterations exceeded. Stopping.")
def reset(self, x0): """ Puts the optimizer in its initial state and sets the initial point to be the 1-dimensional array *x0*. The length of the array becomes the dimension of the optimization problem (:attr:`ndim` member). The shape of *x* must match that of *xlo* and *xhi*. """ BoxConstrainedOptimizer.reset(self, x0) # Debug message if self.debug: DbgMsgOut("CSOPT", "Resetting coordinate search.") if self.step0 is None: self.step0 = self.normScale / 10.0 if self.minstep is None: self.minstep = self.normScale / 1000.0 self.step = self.step0
def run(self): """ Run the DIRECT algorithm. """ # Debug message if self.debug: DbgMsgOut( "CSOPT", "Starting a coordinate search run at i=" + str(self.niter)) # Reset stop flag self.stop = False # Check self.check() self.x = 0.5 * np.ones(shape=(self.ndim, )) self.f = self.fun(self.denormalize(self.x)) # pq: potentiality, f(center), depth self.pq_cache = [(self.f - 1.0 / 3.0 * self.K, 1, Cube(self.x, self.f, np.ones(shape=(self.ndim, ))))] while not self.stop and self.pq_cache: val, it, cube = heapq.heappop(self.pq_cache) self.update_cube(cube) x, depth = cube.x, cube.depth minimum_depth = min(depth) # print("depth: ", depth) if self.debug: DbgMsgOut("DIRECT", "Cube.f =" + str(cube.f)) inc_index, better_index, same_index, worse_index = [], [], [], [] for i in range(self.ndim): # try points with length of the maximum side of hyper-rectangle if depth[i] == minimum_depth: x[i] -= (1 / 3)**depth[i] improved = self.update_potential_rectangle(x, depth, i) if improved == 0: same_index.append(i) elif improved > 0: better_index.append(i) else: worse_index.append(i) x[i] += 2 * (1 / 3)**depth[i] improved = self.update_potential_rectangle(x, depth, i) if improved == 0: same_index.append(i) elif improved > 0: better_index.append(i) else: worse_index.append(i) x[i] -= (1 / 3)**depth[i] inc_index.append(i) if better_index != [] and worse_index != []: # Decrease the size of the cube and save it in the cache for idx in inc_index: cube.increase_depth(idx) self.niter += 1 # Push the smaller cube into the cache centering at self.x heapq.heappush( self.pq_cache, (cube.f - 0.5**depth[0] * self.K, self.niter, cube)) if self.debug: DbgMsgOut( "DIRECT", "Iteration i=" + str(self.niter) + " fbest=" + str(self.f))
def run(self): """ Runs the optimization algorithm. """ # Debug message if self.debug: DbgMsgOut("CSOPT", "Starting a coordinate search run at i=" + str(self.niter)) # Reset stop flag self.stop = False # Check self.check() # Evaluate initial point (if needed) if self.f is None: self.f = self.fun(self.x) # Retrieve best-yet point x = self.x.copy() f = self.f.copy() # Retrieve step step = self.step # Main loop while not self.stop: if self.minstep is not None and (step < self.minstep).all(): if self.debug: DbgMsgOut("CSOPT", "Iteration i=" + str(self.niter) + ": step small enough, stopping") break # Trial steps i = 0 while i < self.ndim: if step.size == 1: delta = step else: delta = step[i] xnew = x.copy() xnew[i] = x[i] + delta self.bound(xnew) fnew = self.fun(xnew) # Debug message if self.debug: DbgMsgOut("CSOPT", "Iteration i=" + str(self.niter) + ": di=" + str(i + 1) + " f=" + str(f) + " step=" + str(max(abs(step)))) if fnew < f: break xnew[i] = x[i] - delta self.bound(xnew) fnew = self.fun(xnew) # Debug message if self.debug: DbgMsgOut("CSOPT", "Iteration i=" + str(self.niter) + ": di=" + str(-i - 1) + " f=" + str(f) + " step=" + str(max(abs(step)))) if fnew < f: break i += 1 if fnew < f: x = xnew f = fnew if step.size == 1: step = step * self.stepup else: step[i] = step[i] * self.stepup else: step = step * self.stepdn if self.debug: DbgMsgOut("CSOPT", "Coordinate search finished.") self.step = step