def test_localsearch_friends(self): """When var flip decreases energy.""" allvar = select_localsearch_adversaries(self.notb, { 'a': 1, 'b': 1, 'c': 1 }, min_gain=None) self.assertEqual(allvar, ['c', 'a', 'b']) neutral = select_localsearch_adversaries(self.notb, { 'a': 1, 'b': 1, 'c': 1 }, min_gain=0.0) self.assertEqual(neutral, ['c', 'a']) nonevar = select_localsearch_adversaries(self.notb, { 'a': 1, 'b': 1, 'c': 1 }, min_gain=1.0) self.assertEqual(nonevar, []) friends = select_localsearch_adversaries(self.notb, { 'a': 1, 'b': 1, 'c': 1 }, min_gain=-10) self.assertEqual(friends, ['c', 'a', 'b'])
def next(self, state): bqm = state.problem if self.max_size > len(bqm): raise ValueError( "subproblem size cannot be greater than the problem size") # select a new subset of `max_size` variables, making sure they differ # from previous iteration by at least `min_diff` variables sample = state.samples.change_vartype(bqm.vartype).first.sample variables = select_localsearch_adversaries(bqm, sample, min_gain=self.min_gain) # TODO: soft fail strategy? skip one iteration or relax vars selection? if len(variables) < self.min_diff: raise ValueError("less than min_diff variables identified as" " contributors to min_gain energy increase") offset = 0 next_vars = set(variables[offset:offset + self.max_size]) while len(next_vars ^ self._prev_vars) < self.min_diff: offset += self.stride next_vars = set(variables[offset:offset + self.max_size]) logger.debug("Select variables: %r (diff from prev = %r)", next_vars, next_vars ^ self._prev_vars) self._prev_vars = next_vars # induce sub-bqm based on selected variables and global sample subbqm = bqm_induced_by(bqm, next_vars, sample) return state.updated(subproblem=subbqm)
def test_localsearch_adversaries(self): """When var flip increases energy.""" defvar = select_localsearch_adversaries(self.notall, {'a': 1, 'b': 1, 'c': -1}) self.assertEqual(defvar, ['c', 'b', 'a']) allvar = select_localsearch_adversaries(self.notall, {'a': 1, 'b': 1, 'c': -1}, max_n=3, min_gain=-1) self.assertEqual(allvar, ['c', 'b', 'a']) subvar = select_localsearch_adversaries(self.notall, {'a': 1, 'b': 1, 'c': -1}, max_n=2, min_gain=-1) self.assertEqual(subvar, ['c', 'b']) subvar = select_localsearch_adversaries(self.notall, {'a': 1, 'b': 1, 'c': -1}, min_gain=1) self.assertEqual(subvar, ['c']) nonevar = select_localsearch_adversaries(self.notall, {'a': 1, 'b': 1, 'c': -1}, min_gain=10) self.assertEqual(nonevar, [])
def next(self, state): bqm = state.problem sample = state.samples.change_vartype(bqm.vartype).first.sample size = self.size if self.size > len(bqm): logger.debug( "subproblem size greater than the problem size, adapting to problem size" ) size = len(bqm) bqm_changed = bqm != self._rolling_bqm sample_changed = sample != self._prev_sample if bqm_changed: self._rewind_rolling(state) if sample_changed: self._prev_sample = sample if bqm_changed or sample_changed or not self._variables: self._variables = select_localsearch_adversaries( bqm, sample, min_gain=self.min_gain) if self.rolling: if len(self._unrolled_vars) >= self.rolling_history * len(bqm): logger.debug("Rolling reset at unrolled history size = %d", len(self._unrolled_vars)) self._rewind_rolling(state) # reset before exception, to be ready on a subsequent call if not self.silent_rewind: raise EndOfStream novel_vars = [ v for v in self._variables if v not in self._unrolled_vars ] next_vars = novel_vars[:size] logger.debug("Selected %d subproblem variables: %r", len(next_vars), next_vars) if self.rolling: self._unrolled_vars.update(next_vars) # induce sub-bqm based on selected variables and global sample subbqm = bqm_induced_by(bqm, next_vars, sample) return state.updated(subproblem=subbqm)
def next(self, state): bqm = state.problem if bqm != self._rolling_bqm: self._reset_rolling(state) if self.max_size > len(bqm): raise ValueError( "subproblem size cannot be greater than the problem size") sample = state.samples.change_vartype(bqm.vartype).first.sample variables = select_localsearch_adversaries(bqm, sample, min_gain=self.min_gain) if self.rolling and len( self._unrolled_vars ) + self.max_size > self.rolling_history * len(bqm): logger.debug("rolling reset at unrolled history size = %d", len(self._unrolled_vars)) # reset before exception, to be ready on a subsequent call self._reset_rolling(state) if not self.silent_reset: raise EndOfStream novel_vars = [v for v in variables if v not in self._unrolled_vars] next_vars = novel_vars[:self.max_size] logger.debug("Selected %d subproblem variables: %r", len(next_vars), next_vars) if self.rolling: self._unrolled_vars.update(next_vars) # induce sub-bqm based on selected variables and global sample subbqm = bqm_induced_by(bqm, next_vars, sample) return state.updated(subproblem=subbqm)