def __init__(self, num_reads=None, num_trials=None): self.domain = ['4', '6', '8', '10', '12', '14', '16', '18', '20'] objective_functions = [] for size in self.domain: objective_functions.append( QAPObjectiveFunction(dat_file='had' + size + '.dat')) if num_reads: self.num_reads = num_reads else: self.num_reads = 100 sampler_kwargs = {'num_reads': self.num_reads} if num_trials: num_trials = num_trials else: num_trials = 100 dwave_solver = TabuSampler() self.data = { 'average': [], 'standard deviation': [], 'domain': self.domain, 'domain with QUBO size': [] } for objective_function in objective_functions: n_qap = objective_function.n s = SortingNetwork(n_qap) p = PermutationNetwork(n_qap) if s.depth <= p.depth: network = s else: network = p self.data['domain with QUBO size'].append('{} ({})'.format( n_qap, network.depth)) unique_bin_val = [] for trial in range(num_trials): binary_vals = [] q = np.random.randint(0, 2, size=network.depth) qubo = LQUBO(objective_function=objective_function, switch_network=network, num_activation_vectors=network.depth) formed_qubo = qubo.form_lqubo(q=q)[0] response = dwave_solver.sample_qubo(formed_qubo, **sampler_kwargs) reads = response.record for read in reads: for num_occurrence in range(read[2]): binary_vals.append(read[0]) num_unique_binary = 0 while len(binary_vals) != 0: num_unique_binary += 1 delta_q = binary_vals[0] binary_vals = remove_redundant_binaries( binary_list=binary_vals, delta_switch=delta_q) unique_bin_val.append(num_unique_binary) self.data['average'].append(stat.mean(unique_bin_val)) self.data['standard deviation'].append(stat.stdev(unique_bin_val))
class LocalQUBOIterativeSolver(Solver): """ The Local-QUBO Solver uses a switch/permutation network to encode the QAP permutation in a bitstring. """ def __init__(self, objective_function=None, dwave_sampler=None, dwave_sampler_kwargs=None, num_activation_vectors=None, activation_vec_hamming_dist=1, max_hd=None, parse_samples=True, experiment_type=None, num_reads=None, num_iters=None, network_type='minimum'): super().__init__(objective_function=objective_function) # Initialize switch network: # The default behavior here is to choose the smaller of either permutation or # sorting networks for the given input size. self.n_obj = self.objective_function.n if network_type == 'sorting': self.network = SortingNetwork(self.n_obj) elif network_type == 'permutation': self.network = PermutationNetwork(self.n_obj) elif network_type == 'minimum': s = SortingNetwork(self.n_obj) p = PermutationNetwork(self.n_obj) if s.depth <= p.depth: self.network = s else: self.network = p else: raise TypeError('Network type {} not recognized'.format(str(network_type))) self.n_qubo = self.network.depth self.dwave_solver = None self.sampler_kwargs = None self.qpu = False # Initialize dwave sampler: if dwave_sampler == 'QPU': self.dwave_solver = EmbeddingComposite(DWaveSampler()) self.qpu = True if dwave_sampler_kwargs: self.sampler_kwargs = dwave_sampler_kwargs else: self.sampler_kwargs = dict() elif dwave_sampler == 'SA': self.dwave_solver = SimulatedAnnealingSampler() if num_reads: self.sampler_kwargs = { 'num_reads': num_reads } else: self.sampler_kwargs = { 'num_reads': 25 } elif dwave_sampler == 'Tabu': self.dwave_solver = TabuSampler() if num_reads: self.sampler_kwargs = { 'num_reads': num_reads } else: self.sampler_kwargs = { 'num_reads': 250 } self.stopwatch = 0 # Initialize type of experiment # When running a timed experiment there is a high number of iterations and a 30 sec wall clock # When running a iteration experiment there is a iteration limit of 30 and no wall clock if experiment_type == 'time_lim': self.n_iters = 1000 self.time_limit = 30 if experiment_type == 'iter_lim' and num_iters: self.n_iters = num_iters self.time_limit = False else: self.n_iters = 50 self.time_limit = False if max_hd: self.max_hd = max_hd else: self.max_hd = 0 if num_activation_vectors: self.num_activation_vec = num_activation_vectors else: self.num_activation_vec = self.n_qubo self.form_qubo = LQUBO(objective_function=self.objective_function, switch_network=self.network, max_hamming_dist=self.max_hd, num_activation_vectors=self.num_activation_vec, activation_vec_hamming_dist=activation_vec_hamming_dist) self.solution = self.objective_function.min_v if parse_samples: self.selection = CheckAndSelect else: self.selection = Select def minimize_objective(self): start_code = time.time() q = np.random.randint(0, 2, size=self.n_qubo) p = self.network.permute(q) v = self.objective_function(p) delta_q = None data_dict = dict() data_dict['q_vec'] = [q] data_dict['p_vec'] = [p] data_dict['v_vec'] = [v] data_dict['delta_q_vec'] = [['random switch setting']] # Initialize bitstring begin_loop = time.time() self.stopwatch = begin_loop - start_code for iteration in range(self.n_iters): # If there is a timing limit and the stopwatch is greater than the timing limit then break if self.time_limit and self.time_limit <= self.stopwatch: break start_iteration = time.time() # Build the Local QUBO by creating all delta_q's that are hamming distance 2 # from the current q. For each of those, the new q gives a permutation (via # the network encoding) and hence a new objective function value. The deltas # in the objective function values are what populate the qubo. qubo = self.form_qubo.form_lqubo(q=q)[0] delta_q_basis = self.form_qubo.form_lqubo(q=q)[1] # Solve the QUBO for delta_q if self.qpu: self.sampler_kwargs.update({ 'chain_strength': 1.5*abs(max(qubo.values(), key=abs)), 'num_reads': 1000 }) retries = 10 while retries > 0: try: response = self.dwave_solver.sample_qubo(qubo, **self.sampler_kwargs) select_response = self.selection(objective_function=self.objective_function, switch_network=self.network, response_record=response.record, delta_q_basis=delta_q_basis, data_dict_qvecs=data_dict['q_vec'], current_q=q).select() q = select_response[0] p = select_response[1] v = select_response[2] delta_q = select_response[3] break except ValueError: print('retrying QUBO...') retries -= 1 if retries == 0: q = np.random.randint(0, 2, size=self.n_qubo) p = self.network.permute(q) v = self.objective_function(p) delta_q = None data_dict['q_vec'] = [q] data_dict['p_vec'] = [p] data_dict['v_vec'] = [v] data_dict['delta_q_vec'] = [['random switch setting']] data_dict['q_vec'].append(q) data_dict['p_vec'].append(p) data_dict['v_vec'].append(v) data_dict['delta_q_vec'].append(delta_q) end_iteration = time.time() self.stopwatch += end_iteration - start_iteration end_code = time.time() timing_code = end_code - start_code lqubo_ans = min(data_dict['v_vec']) num_iters = len(data_dict['v_vec']) - 1 if lqubo_ans == self.solution: obtain_optimal = 1 percent_error = 0 else: percent_error = abs(self.solution - lqubo_ans) / self.solution * 100 obtain_optimal = 0 return lqubo_ans, percent_error, obtain_optimal, timing_code, num_iters, data_dict, data_dict['v_vec']
class PopulationLQUBOSolver(Solver): """ The Local-QUBO Solver uses a switch/permutation network to encode the QAP permutation in a bitstring. """ def __init__(self, objective_function=None, dwave_sampler=None, dwave_sampler_kwargs=None, experiment_type=None, population_size=1, num_reads=1, num_iters=None): super().__init__(objective_function=objective_function) self.n_obj = self.objective_function.n self.n_qubo = self.n_obj - 1 self.dwave_solver = None self.sampler_kwargs = None self.qpu = False self.population_size = population_size self.num_reads = num_reads # Initialize dwave sampler: if dwave_sampler == 'QPU': self.dwave_solver = EmbeddingComposite(DWaveSampler()) self.qpu = True if dwave_sampler_kwargs: self.sampler_kwargs = dwave_sampler_kwargs else: self.sampler_kwargs = dict() elif dwave_sampler == 'SA': self.dwave_solver = SimulatedAnnealingSampler() if num_reads: self.sampler_kwargs = {'num_reads': num_reads} else: self.sampler_kwargs = {'num_reads': 25} elif dwave_sampler == 'Tabu': self.dwave_solver = TabuSampler() if num_reads: self.sampler_kwargs = {'num_reads': num_reads} else: self.sampler_kwargs = {'num_reads': 250} self.stopwatch = 0 if experiment_type == 'time_lim': self.n_iters = 1000 self.time_limit = 30 if experiment_type == 'iter_lim' and num_iters: self.n_iters = num_iters self.time_limit = False else: self.n_iters = 50 self.time_limit = False self.form_qubo = NewLQUBO(objective_function=self.objective_function) self.solution = self.objective_function.min_v def minimize_objective(self): start_code = time.time() population = initialize_population( population_size=self.population_size, n_obj=self.n_obj) evaluated_fitness = evaluate_fitness( population=population, objective_function=self.objective_function) max_fit = max_fitness(fitness_array=evaluated_fitness) min_fit = min_fitness(fitness_array=evaluated_fitness) avg_fit = avg_fitness(fitness_array=evaluated_fitness) data_dict = dict() data_dict['max_fitness'] = [max_fit] data_dict['min_fitness'] = [min_fit] data_dict['avg_fitness'] = [avg_fit] data_dict['population'] = [population] form_lqubo_timing = [] solve_lqubo_timing = [] # Initialize bitstring begin_loop = time.time() self.stopwatch = begin_loop - start_code for iteration in range(self.n_iters): # If there is a timing limit and the stopwatch is greater than the timing limit then break if self.time_limit and self.time_limit <= self.stopwatch: break start_iteration = time.time() total_lqubo_population = [] for perm in population: start_form_lqubo = time.time() lqubo = self.form_qubo.form_lqubo(p=perm) end_form_lqubo = time.time() form_lqubo_timing.append(end_form_lqubo - start_form_lqubo) # Solve the LQUBO for new permutations if self.qpu: self.sampler_kwargs.update({ 'chain_strength': 1.5 * abs(max(lqubo.values(), key=abs)), 'num_reads': 1000 }) start_solve_lqubo = time.time() response = self.dwave_solver.sample_qubo( lqubo, **self.sampler_kwargs) end_solve_lqubo = time.time() solve_lqubo_timing.append(end_solve_lqubo - start_solve_lqubo) lqubo_population = CollectLQUBOPopulation( objective_function=self.objective_function, response_record=response.record, current_perm=perm).collect_population() total_lqubo_population += lqubo_population tournament_selection = BestFitPopulation( final_population_size=self.population_size, lqubo_population=total_lqubo_population, previous_population=population, objective_function=self.objective_function) # Compile new population from tournament selection population = tournament_selection.return_population() evaluated_fitness = evaluate_fitness( population=population, objective_function=self.objective_function) max_fit = max_fitness(fitness_array=evaluated_fitness) min_fit = min_fitness(fitness_array=evaluated_fitness) avg_fit = avg_fitness(fitness_array=evaluated_fitness) data_dict['max_fitness'].append(max_fit) data_dict['min_fitness'].append(min_fit) data_dict['avg_fitness'].append(avg_fit) data_dict['population'].append(population) end_iteration = time.time() self.stopwatch += end_iteration - start_iteration end_code = time.time() timing_code = end_code - start_code average_form_lqubo = np.average(form_lqubo_timing) average_solve_lqubo = np.average(solve_lqubo_timing) lqubo_ans = min(data_dict['max_fitness']) num_iters = len(data_dict['max_fitness']) - 1 if lqubo_ans == self.solution: obtain_optimal = 1 percent_error = 0 else: percent_error = abs(self.solution - lqubo_ans) / self.solution * 100 obtain_optimal = 0 return lqubo_ans, percent_error, obtain_optimal, timing_code, num_iters, data_dict, data_dict['max_fitness'], \ average_form_lqubo, average_solve_lqubo, data_dict, data_dict['avg_fitness'], data_dict['min_fitness']