def branchexeclp(self, allowaddcons): candidate_vars, *_ = self.model.getPseudoBranchCands() candidate_mask = [var.getCol().getIndex() for var in candidate_vars] state = utilities.extract_state(self.model, self.state_buffer) c, e, v = state v = v['values'][candidate_mask] state_khalil = utilities.extract_khalil_variable_features(self.model, candidate_vars, self.khalil_root_buffer) var_feats = np.concatenate([v, state_khalil, np.ones((v.shape[0],1))], axis=1) var_feats = utilities._preprocess(var_feats, mode="min-max-2") # TODO: Move to(device) inside as_tensor() var_feats = torch.as_tensor(var_feats, dtype=torch.float32).to(device) with torch.no_grad(): # TODO: drop .cpu().numpy() for faster running time? var_logits = self.policy(var_feats).cpu().numpy() best_var = candidate_vars[var_logits.argmax()] self.model.branchVar(best_var) result = scip.SCIP_RESULT.BRANCHED # fair node counting if result == scip.SCIP_RESULT.REDUCEDDOM: self.ndomchgs += 1 elif result == scip.SCIP_RESULT.CUTOFF: self.ncutoffs += 1 return {'result': result}
def branchexeclp(self, allowaddcons): candidate_vars, *_ = self.model.getPseudoBranchCands() candidate_mask = [var.getCol().getIndex() for var in candidate_vars] state = utilities.extract_state(self.model, self.state_buffer) c, e, v = state if self.model.getNNodes() == 1: state = ( torch.as_tensor(c['values'], dtype=torch.float32), torch.as_tensor(e['indices'], dtype=torch.long), torch.as_tensor(e['values'], dtype=torch.float32), torch.as_tensor(v['values'], dtype=torch.float32), torch.as_tensor(c['values'].shape[0], dtype=torch.int32), torch.as_tensor(v['values'].shape[0], dtype=torch.int32), ) state = map(lambda x: x.to(self.device), state) with torch.no_grad(): if self.teacher is not None: root_feats, _ = self.teacher(state) state = root_feats self.root_params = self.policy_get_root_params(state) v = v['values'][candidate_mask] state_khalil = utilities.extract_khalil_variable_features( self.model, candidate_vars, self.khalil_root_buffer) var_feats = np.concatenate( [v, state_khalil, np.ones((v.shape[0], 1))], axis=1) var_feats = utilities._preprocess(var_feats, mode="min-max-2") var_feats = torch.as_tensor(var_feats, dtype=torch.float32).to(device) with torch.no_grad(): var_logits = self.policy_predict( var_feats, self.root_params[candidate_mask]).cpu().numpy() best_var = candidate_vars[var_logits.argmax()] self.model.branchVar(best_var) result = scip.SCIP_RESULT.BRANCHED # fair node counting if result == scip.SCIP_RESULT.REDUCEDDOM: self.ndomchgs += 1 elif result == scip.SCIP_RESULT.CUTOFF: self.ncutoffs += 1 return {'result': result}
def branchexeclp(self, allowaddcons): # SCIP internal branching rule if self.policy_type == 'internal': result = self.model.executeBranchRule(self.policy, allowaddcons) # custom policy branching else: candidate_vars, *_ = self.model.getPseudoBranchCands() candidate_mask = [ var.getCol().getIndex() for var in candidate_vars ] state = utilities.extract_state(self.model, self.state_buffer) c, e, v = state state = ( torch.as_tensor(c['values'], dtype=torch.float32), torch.as_tensor(e['indices'], dtype=torch.long), torch.as_tensor(e['values'], dtype=torch.float32), torch.as_tensor(v['values'], dtype=torch.float32), torch.as_tensor(c['values'].shape[0], dtype=torch.int32), torch.as_tensor(v['values'].shape[0], dtype=torch.int32), ) state = map(lambda x: x.to(self.device), state) with torch.no_grad(): _, var_logits = self.policy(state) var_logits = torch.squeeze(var_logits, 0).cpu().numpy() candidate_scores = var_logits[candidate_mask] best_var = candidate_vars[candidate_scores.argmax()] self.model.branchVar(best_var) result = scip.SCIP_RESULT.BRANCHED # fair node counting if result == scip.SCIP_RESULT.REDUCEDDOM: self.ndomchgs += 1 elif result == scip.SCIP_RESULT.CUTOFF: self.ncutoffs += 1 return {'result': result}
def branchexeclp(self, allowaddcons): self.iteration_counter += 1 query_expert = self.rng.rand() < self.query_expert_prob if query_expert or self.model.getNNodes() == 1: candidate_vars, *_ = self.model.getPseudoBranchCands() candidate_mask = [ var.getCol().getLPPos() for var in candidate_vars ] state = utilities.extract_state(self.model) state_khalil = utilities.extract_khalil_variable_features( self.model, candidate_vars, self.khalil_root_buffer) result = self.model.executeBranchRule('vanillafullstrong', allowaddcons) cands_, scores, npriocands, bestcand = self.model.getVanillafullstrongData( ) best_var = cands_[bestcand] self.add_obs(best_var, (state, state_khalil), (cands_, scores)) if self.model.getNNodes() == 1: self.state = [state, state_khalil, self.obss[0]] self.model.branchVar(best_var) result = scip.SCIP_RESULT.BRANCHED else: result = self.model.executeBranchRule(self.exploration_policy, allowaddcons) # fair node counting if result == scip.SCIP_RESULT.REDUCEDDOM: self.ndomchgs += 1 elif result == scip.SCIP_RESULT.CUTOFF: self.ncutoffs += 1 return {'result': result}
def branchexeclp(self, allowaddcons): # SCIP internal branching rule if self.policy_type == 'internal': result = self.model.executeBranchRule(self.policy, allowaddcons) # custom policy branching else: candidate_vars, *_ = self.model.getPseudoBranchCands() candidate_mask = [ var.getCol().getLPPos() for var in candidate_vars ] # initialize root buffer for Khalil features extraction if self.model.getNNodes() == 1 \ and self.policy_type == 'ml-competitor' \ and self.feat_specs['type'] in ('khalil', 'all'): utilities.extract_khalil_variable_features( self.model, [], self.khalil_root_buffer) if len(candidate_vars) == 1: best_var = candidate_vars[0] elif self.policy_type == 'gcnn': state = utilities.extract_state(self.model, self.state_buffer) # convert state to tensors c, e, v = state state = ( tf.convert_to_tensor(c['values'], dtype=tf.float32), tf.convert_to_tensor(e['indices'], dtype=tf.int32), tf.convert_to_tensor(e['values'], dtype=tf.float32), tf.convert_to_tensor(v['values'], dtype=tf.float32), tf.convert_to_tensor([c['values'].shape[0]], dtype=tf.int32), tf.convert_to_tensor([v['values'].shape[0]], dtype=tf.int32), ) var_logits = self.policy( state, tf.convert_to_tensor(False)).numpy().squeeze(0) candidate_scores = var_logits[candidate_mask] best_var = candidate_vars[candidate_scores.argmax()] elif self.policy_type == 'ml-competitor': # build candidate features candidate_states = [] if self.feat_specs['type'] in ('all', 'gcnn_agg'): state = utilities.extract_state(self.model, self.state_buffer) candidate_states.append( utilities.compute_extended_variable_features( state, candidate_mask)) if self.feat_specs['type'] in ('all', 'khalil'): candidate_states.append( utilities.extract_khalil_variable_features( self.model, candidate_vars, self.khalil_root_buffer)) candidate_states = np.concatenate(candidate_states, axis=1) # feature preprocessing candidate_states = utilities.preprocess_variable_features( candidate_states, self.feat_specs['augment'], self.feat_specs['qbnorm']) # feature normalization candidate_states = (candidate_states - self.feat_shift) / self.feat_scale candidate_scores = self.policy.predict(candidate_states) best_var = candidate_vars[candidate_scores.argmax()] else: raise NotImplementedError self.model.branchVar(best_var) result = scip.SCIP_RESULT.BRANCHED # fair node counting if result == scip.SCIP_RESULT.REDUCEDDOM: self.ndomchgs += 1 elif result == scip.SCIP_RESULT.CUTOFF: self.ncutoffs += 1 return {'result': result}
def branchexeclp(self, allowaddcons): if self.model.getNNodes() == 1: # initialize root buffer for Khalil features extraction utilities.extract_khalil_variable_features(self.model, [], self.khalil_root_buffer) # once in a while, also run the expert policy and record the (state, action) pair query_expert = self.rng.rand() < self.query_expert_prob if query_expert: state = utilities.extract_state(self.model) cands, *_ = self.model.getPseudoBranchCands() state_khalil = utilities.extract_khalil_variable_features(self.model, cands, self.khalil_root_buffer) result = self.model.executeBranchRule('vanillafullstrong', allowaddcons) cands_, scores, npriocands, bestcand = self.model.getVanillafullstrongData() assert result == scip.SCIP_RESULT.DIDNOTRUN assert all([c1.getCol().getLPPos() == c2.getCol().getLPPos() for c1, c2 in zip(cands, cands_)]) action_set = [c.getCol().getLPPos() for c in cands] expert_action = action_set[bestcand] data = [state, state_khalil, expert_action, action_set, scores] # Do not record inconsistent scores. May happen if SCIP was early stopped (time limit). if not any([s < 0 for s in scores]): filename = f'{self.out_dir}/sample_{self.episode}_{self.sample_counter}.pkl' with gzip.open(filename, 'wb') as f: pickle.dump({ 'episode': self.episode, 'instance': self.instance, 'seed': self.seed, 'node_number': self.model.getCurrentNode().getNumber(), 'node_depth': self.model.getCurrentNode().getDepth(), 'data': data, }, f) self.out_queue.put({ 'type': 'sample', 'episode': self.episode, 'instance': self.instance, 'seed': self.seed, 'node_number': self.model.getCurrentNode().getNumber(), 'node_depth': self.model.getCurrentNode().getDepth(), 'filename': filename, }) self.sample_counter += 1 # if exploration and expert policies are the same, prevent running it twice if not query_expert or (not self.follow_expert and self.exploration_policy != 'vanillafullstrong'): result = self.model.executeBranchRule(self.exploration_policy, allowaddcons) # apply 'vanillafullstrong' branching decision if needed if query_expert and self.follow_expert or self.exploration_policy == 'vanillafullstrong': assert result == scip.SCIP_RESULT.DIDNOTRUN cands, scores, npriocands, bestcand = self.model.getVanillafullstrongData() self.model.branchVar(cands[bestcand]) result = scip.SCIP_RESULT.BRANCHED return {"result": result}
def branchexeclp(self, allowaddcons): if self.model.getNNodes() == 1: # initialize root buffer for Khalil features extraction utilities.extract_khalil_variable_features(self.model, [], self.khalil_root_buffer) depth = self.model.getDepth() if self.visited_maxDepth < depth: self.visited_maxDepth = depth # once in a while, also run the expert policy and record the (state, action) pair # if not self.sampleForTraining: # if generating valid set or test set # query_expert = (self.rng.random() < self.query_expert_prob) # else: with self.lock: if depth not in self.depthDict_accessTimes: self.depthDict_accessTimes[depth] = 1 else: self.depthDict_accessTimes[depth] += 1 if self.samplingStrategy == 'uniform5': # validation 和 test set 都用 uniform5 query_expert = (self.rng.random() < self.query_expert_prob) elif self.samplingStrategy == 'depthK': query_expert = (self.rng.random() < self.query_expert_prob) or ((depth < self.depthK) and (self.model.getNNodes() <= self.NNodeK)) elif self.samplingStrategy == 'depthK2': # 要通过读取depthTable来计算采样概率 with self.lock: if depth not in self.depthDict_sampleTimes.keys(): query_expert = True else: valSum = sum(self.depthDict_sampleTimes.values()) scores = {k:valSum/v for k,v in self.depthDict_sampleTimes.items()} query_expert_prob = scores[depth] / sum(scores.values()) query_expert = (self.rng.random() < query_expert_prob) elif self.samplingStrategy == 'depthK3': # 给采样概率增加上下界 with self.lock: if depth not in self.depthDict_sampleTimes: query_expert_prob = 0.5 else: valSum = sum(self.depthDict_sampleTimes.values()) scores = {k:valSum/v for k,v in self.depthDict_sampleTimes.items()} query_expert_prob = scores[depth] / sum(scores.values()) query_expert_prob = min(max(0.05, query_expert_prob), 0.5) query_expert = (self.rng.random() < query_expert_prob) elif self.samplingStrategy == 'depthK_adaptive': bin_size = 5 depth_binned = depth // bin_size query_expert_prob = self.query_expert_prob if (depth_binned in self.depthTable_SolSB_binned5.index) and (self.depthTable_SolSB_binned5.loc[depth_binned].item() > self.query_expert_prob): query_expert_prob = self.depthTable_SolSB_binned5.loc[depth_binned].item() query_expert = (self.rng.random() < query_expert_prob) elif self.samplingStrategy == 'depthK_adaptive2': query_expert_prob = self.query_expert_prob if depth >= 5 and depth < 20: query_expert_prob = 0.13 query_expert = (self.rng.random() < query_expert_prob) else: raise ValueError("Argument samplingStrategy can only be chosen from ['uniform5', 'depthK', 'depthK2', 'depthK3', 'depthK_adaptive]") if query_expert: # global lck, depthTable if self.sampleForTraining: with self.lock: if depth not in self.depthDict_sampleTimes: self.depthDict_sampleTimes[depth] = 1 else: self.depthDict_sampleTimes[depth] += 1 state = utilities.extract_state(self.model) cands, *_ = self.model.getPseudoBranchCands() state_khalil = utilities.extract_khalil_variable_features(self.model, cands, self.khalil_root_buffer) result = self.model.executeBranchRule('vanillafullstrong', allowaddcons) cands_, scores, npriocands, bestcand = self.model.getVanillafullstrongData() assert result == scip.SCIP_RESULT.DIDNOTRUN assert all([c1.getCol().getLPPos() == c2.getCol().getLPPos() for c1, c2 in zip(cands, cands_)]) action_set = [c.getCol().getLPPos() for c in cands] expert_action = action_set[bestcand] data = [state, state_khalil, expert_action, action_set, scores] # Do not record inconsistent scores. May happen if SCIP was early stopped (time limit). if not any([s < 0 for s in scores]): filename = f'{self.out_dir}/sample_{self.episode}_{self.sample_counter}.pkl' with gzip.open(filename, 'wb') as f: pickle.dump({ 'episode': self.episode, 'instance': self.instance, 'seed': self.seed, 'node_number': self.model.getCurrentNode().getNumber(), 'node_depth': self.model.getCurrentNode().getDepth(), 'data': data, }, f) self.out_queue.put({ 'type': 'sample', 'episode': self.episode, 'instance': self.instance, 'seed': self.seed, 'node_number': self.model.getCurrentNode().getNumber(), 'node_depth': self.model.getCurrentNode().getDepth(), 'filename': filename, }) self.sample_counter += 1 # if exploration and expert policies are the same, prevent running it twice if not query_expert or (not self.follow_expert and self.exploration_policy != 'vanillafullstrong'): result = self.model.executeBranchRule(self.exploration_policy, allowaddcons) # apply 'vanillafullstrong' branching decision if needed if query_expert and self.follow_expert or self.exploration_policy == 'vanillafullstrong': assert result == scip.SCIP_RESULT.DIDNOTRUN cands, scores, npriocands, bestcand = self.model.getVanillafullstrongData() self.model.branchVar(cands[bestcand]) result = scip.SCIP_RESULT.BRANCHED return {"result": result}