def _extrapolate_xs(self, current): '''generate a new individual based on individuals in the frontier''' sample = self._sample_frontier_exclude(current, n=3) rv_list = [x for x in current.xs] # randomly pick at least one x-position to change change_indices = [i for i in xrange(len(rv_list)) if random.random() < self.spec.p_crossover] if not change_indices: change_indices = [base.random_index(rv_list)] # extrapolate a new value for each of the chosen indices for i in change_indices: rv_list[i] = self._extrapolate_x(x, (s.xs[i] for s in sample), self.model.xs[i]) return tuple(rv_list)
def _extrapolate_xs(self, current): '''generate a new individual based on individuals in the frontier''' a, b, c = self._sample_frontier_exclude(current, n=3) rv_list = [x for x in current.xs] # randomly pick at least one x-position to change change_indices = [ i for i in xrange(len(rv_list)) if random.random() < self.spec.p_crossover ] if not change_indices: change_indices = [base.random_index(rv_list)] # extrapolate a new value for each of the chosen indices for i in change_indices: extrapolated = a.xs[i] + self.spec.f * (b.xs[i] - c.xs[i]) rv_list[i] = self.model.xs[i].clip(extrapolated) return tuple(rv_list)
def run(self, text_report=True): '''run MaxWalkSat on self.model''' # current ModelIO to evaluate and mutate self._current = self.model.random_model_io() self._best = self._current # initialize and update log variables to track values by era self._current_era = NumberLog() self._current_era += self._current.energy self._best_era = None # bookkeeping variables self._evals = 0 self._lives = 4 self._report = StringBuilder() if text_report else NullObject() self._terminate = False while self._evals < self.spec.iterations and not self._terminate: # get the generator for a random independent variable if self.spec.p_mutation > random.random(): # if not searching a dimension, mutate randomly self._update('+') else: # if doing a local search, choose a dimension dimension = base.random_index(self._current.xs) search_iv = self.model.xs[dimension] # then try points all along the dimension lo, hi = search_iv.lo, search_iv.hi for j in self._local_search_xs(lo, hi, 10): self._update('|', dimension=dimension, value=j) return SearchReport(best=self._best.energy, best_era=self._best_era, evaluations=self._evals, searcher=self.__class__, spec=self.spec, report=self._report)
def _update(self, improvement_char, dimension=None, value=None): '''calculate the next value from the model and update state as necessary''' # check for invalid input if value is not None and dimension is None: err = 'cannot call _update with specified value but no dimension' raise ValueError(err) if dimension is None: dimension = base.random_index(self._current.xs) if value is None: # get random value if no value input value = self.model.xs[dimension]() updated = False while not updated: new_xs = tuple_replace(self._current.xs, dimension, value) try: self._current = self.model(new_xs, io=True) updated = True except ModelInputException: value = self.model.xs[dimension]() self._evals += 1 self._current_era += self._current.energy # compare to previous best and update as necessary if self._current.energy < self._best.energy: self._best = self._current self._report += improvement_char else: self._report += '.' # end-of-era bookkeeping if self._evals % self.spec.era_length == 0: self._end_era()
def _mutate(self, child): i = base.random_index(child) return base.tuple_replace(child, i, self.model.xs[i]())
def random_index(self): return base.random_index(self._cache)