def solve_multi(self, verbose=False, num_repeats=200): if self.qubo is None: self.pre_process() if verbose: print("Solving multiple solutions of MAX-SMTI with Qbsolv") if self.qubo_size == 0 or self.qubo_size == 1: return [Solution(self.matching, self.pre_evaluated_solution)] if self.mode == "np": # more memory intensive response = QBSolv().sample(BinaryQuadraticModel.from_numpy_matrix(self.qubo), num_repeats=num_repeats) elif self.mode == "bqm": response = QBSolv().sample(self.qubo, num_repeats=num_repeats) else: raise Exception(f"mode: {self.mode} cannot be solved yet") if verbose: print(response) for index, sample in enumerate(list(response.samples())): match, valid = self.encode(sample) print(index, ":", Solution(self.matching, match).is_stable(), match, valid) opt_en = self.get_optimal_energy(self.matching.size) solutions = [] for sample, energy, occ in response.record: if energy == opt_en: match, valid = self.encode_qa(sample.tolist()) if verbose and not valid: print("Invalid encoding and valid energy!") solutions.append(Solution(self.matching, match)) return solutions
def solve_multi_data(self, verbose=False, target=None, num_repeats=200): if self.qubo is None: self.pre_process() if verbose: print("Solving multiple solutions of MAX-SMTI with Qbsolv") if self.qubo_size == 0 or self.qubo_size == 1: return [Solution(self.matching, self.pre_evaluated_solution)] if self.mode == "np": # more memory intensive response = QBSolv().sample(BinaryQuadraticModel.from_numpy_matrix(self.qubo), num_repeats=num_repeats, target=target, algorithm=SOLUTION_DIVERSITY) elif self.mode == "bqm": response = QBSolv().sample(self.qubo, num_repeats=num_repeats, target=target) else: raise Exception(f"mode: {self.mode} cannot be solved yet") if verbose: print(response) for index, sample in enumerate(list(response.samples())): match, valid = self.encode(sample) print(index, ":", Solution(self.matching, match).is_stable(), match, valid) samples = pd.DataFrame() for sample, energy, occ in response.record: match, valid = self.encode_qa(sample.tolist()) stable, size = Solution(self.matching, match).is_stable() samples = samples.append({"match": match, "sample": sample.tolist(), "energy": energy, "occ": occ, "valid": valid, "stable": stable, "size": size}, ignore_index=True) return samples
def solve(self, verbose=False, num_repeats=50, target=None, debug=False): if self.qubo is None: self.pre_process() if verbose: print("Solving MAX-SMTI with Qbsolv") if self.qubo_size == 0 or self.qubo_size == 1: if debug: return None return Solution(self.matching, self.pre_evaluated_solution) if self.mode == "np": # more memory intensive response = QBSolv().sample(BinaryQuadraticModel.from_numpy_matrix(self.qubo), num_repeats=num_repeats, target=target) elif self.mode == "bqm": response = QBSolv().sample(self.qubo, num_repeats=num_repeats, target=target) else: raise Exception(f"mode: {self.mode} cannot be solved yet") if debug: return response if verbose: print(response) for index, sample in enumerate(list(response.samples())): match, valid = self.encode(sample) print(index, ":", Solution(self.matching, match).is_stable(), match, valid) energies = list(response.data_vectors['energy']) min_en = min(energies) ret_match, valid = self.encode(list(response.samples())[energies.index(min_en)]) return Solution(self.matching, ret_match, energy=min_en)
def solve_qa(self, verbose=True, num_reads=100): assert self.token is not None assert self.mode == "bqm" if self.qubo is None: self.pre_process() if verbose: print(f"Solving SMTI with: {SOLVER}") print(f"Optimal Solution: {-(len(self.encoding) * self.p2 + self.matching.size * self.p1)}") chain_strength = self.get_chain_stength() + 1 # max element in qubo matrix + epsilon solver_limit = len(self.encoding) # solver_limit => size of qubo matrix G = nx.complete_graph(solver_limit) dw_solver = DWaveSampler(solver=SOLVER, token=self.token, endpoint=ENDPOINT) embedding = minorminer.find_embedding(G.edges, dw_solver.edgelist) fixed_embedding = FixedEmbeddingComposite(dw_solver, embedding) result = fixed_embedding.sample(self.qubo, num_reads=num_reads, chain_strength=chain_strength) dw_solver.client.close() # clean up all the thread mess the client creates so it does not block my code if verbose: print(result) for index, (sample, energy, occ, chain) in enumerate(result.record): match_, _ = self.encode_qa(sample.tolist()) stable_, size_ = Solution(self.matching, match_).is_stable() print(f"{index}: ", match_, size_, stable_) samples = pd.DataFrame() for sample, energy, occ, chain in result.record: match, valid = self.encode_qa(sample.tolist()) stable, size = Solution(self.matching, match).is_stable() samples = samples.append({"match": match, "sample": sample.tolist(), "energy": energy, "occ": occ, "chain": chain, "valid": valid, "stable": stable, "size": size}, ignore_index=True) return samples
def compute_all_solutions(self, mode="SMTI"): from algorithms.solution import Solution if mode == "SMTI": all_matches = ut.get_all_matches(self.males, self.females, self.size, mode="SMTI") all_solutions = [] for match in all_matches: (stable, size) = Solution(self, match).is_stable() if stable: all_solutions.append(match) self.solutions = [ dict(s) for s in set( frozenset(d.items()) for d in all_solutions) ] elif mode == "SMP": all_solutions = BACKTRACK_SMP(self).solve() all_solutions = list(map(lambda x: x.solution_m, all_solutions)) self.solutions = all_solutions else: raise Exception(f"Mode: {mode} not implemented jet")
def get_solutions_match(self) -> Solution: match = {} for index_m, male in enumerate(self.matching.males): for index_w, female in enumerate(self.matching.females): if self.variables[index_m][index_w].solution_value() == 1: assert male not in match match[male] = female return Solution(self.matching, match)
def solve(self, time_limit=None): start = time.time() solutions = [] q = [-2 for _ in range(self.matching.size)] c = 0 from_backtrack = False while True: while c < self.matching.size: if not from_backtrack: q[c] = -1 from_backtrack = False while q[c] < self.matching.size: if time_limit is not None and time.time( ) - start >= time_limit: from algorithms.solution import Solution return list( map(lambda x: Solution(self.matching, x), solutions)) q[c] = q[c] + 1 if q[c] == self.matching.size: c = self.backtrack(c) if c is None: from algorithms.solution import Solution return list( map(lambda x: Solution(self.matching, x), solutions)) from_backtrack = True break if self.is_ok(c, q[c], q): from_backtrack = False c += 1 break solutions.append(self.convert_matching(q)) c = self.backtrack(c) from_backtrack = True if c is None: return solutions
def solve(self): matches_m = {} matches_w = {} proposal_m = {m: [] for m in self.matching.males} unmatched_males = deque(self.get_active()) m_pref = deepcopy(self.matching.males_pref) while not len(unmatched_males) == 0: m_alone = unmatched_males[0] most_desired = _get_most_desired(m_pref[m_alone], proposal_m[m_alone]) if most_desired is None: unmatched_males.remove(m_alone) continue proposal_m[m_alone].append(most_desired) if most_desired not in matches_w.keys(): if self.matching.is_acceptable(m_alone, most_desired): matches_w[most_desired] = m_alone matches_m[m_alone] = most_desired unmatched_males.remove(m_alone) else: if self.is_better_partner(most_desired, m_alone, matches_w[most_desired]): unmatched_males.remove(m_alone) unmatched_males.append(matches_w[most_desired]) proposal_m[matches_w[most_desired]].append(most_desired) del matches_m[matches_w[most_desired]] matches_w[most_desired] = m_alone matches_m[m_alone] = most_desired else: unmatched_males.rotate(1) if self.mode == "m_opt": return Solution(self.matching, matches_m) elif self.mode == "w_opt": matching = Matching(self.matching.females, self.matching.males, self.matching.females_pref, self.matching.males_pref) return Solution(matching, matches_w) else: raise Exception(f"unknown mode: {self.mode}")
def solve_multi(self, verbose=True, num_repeats=100, target=None): if self.qubo is None: self.create_qubo() if self.mode == "np": # more memory intensive response = QBSolv().sample(BinaryQuadraticModel.from_numpy_matrix(self.qubo), target=target) elif self.mode == "bqm": response = QBSolv().sample(self.qubo, num_repeats=num_repeats, target=target) else: raise Exception(f"mode: {self.mode} cannot be solved yet") if verbose: print(response) n = self.matching.size stable_energy = -3 / 2 * self.p1 * (n - 1) * n energies = list(response.data_vectors['energy']) samples = enumerate(list(response.samples())) allowed_samples = [sample for idx, sample in samples if energies[idx] == stable_energy] return [Solution(self.matching, self.encode(sample)) for sample in allowed_samples]
def solve(self, verbose=False, num_repeats=100, target=None): if self.qubo is None: self.create_qubo() if self.mode == "np": # more memory intensive response = QBSolv().sample(BinaryQuadraticModel.from_numpy_matrix(self.qubo), target=target) elif self.mode == "bqm": response = QBSolv().sample(self.qubo, num_repeats=num_repeats, target=target) else: raise Exception(f"mode: {self.mode} cannot be solved yet") if verbose: print(response) energies = list(response.data_vectors['energy']) min_en = min(energies) ret_match = self.encode(list(response.samples())[energies.index(min_en)]) return Solution(self.matching, ret_match)
def eval_algorithm(size, index_f, solver_type): matching = get_smti(index_f, size) if solver_type == "qbsolv": return QUBO_SMTI(matching).solve().is_stable() elif solver_type == "qa": solutions = QUBO_SMTI(matching).solve_qa(verbose=False) store_qa_solution(solutions, size, index_f, "smti") min_solution = solutions[solutions.energy == solutions.energy.min()] log.info(solutions) log.info(min_solution) return Solution(matching, min_solution["match"].to_numpy()[0]).is_stable() elif solver_type == "lp": return LP_smti(matching).solve().is_stable() elif solver_type == "shiftbrk": return ShiftBrk(matching).solve().is_stable() elif solver_type == "kiraly": return Kirialy2(matching).solve().is_stable() else: raise Exception(f"unknown solver_type: {solver_type}")
def test_generate_all_solutions_smp(self): for size in range(5): matching = create_smp_instance(size) all_possibilites = ut.get_all_matches(matching.males, matching.females, matching.size, mode="SMP") all_possibilites = list(all_possibilites) self.assertEqual(math.factorial(size), len(all_possibilites)) matching.compute_all_solutions(mode="SMP") for match in matching.solutions: (stable, s_size) = Solution(matching, match).is_stable() self.assertTrue(stable, "solution was not stable") self.assertTrue(s_size == size, "solution differed in size") self.assertTrue(size != -1, "solution had somebody matched twice") matching = mock_matching_smp() matching.compute_all_solutions() self.assertEqual(2, len(matching.solutions))
def test_generate_all_solutions_smti(self): def compute_solution_count(n): return sum([comb((n * n), i) for i in range(1, n + 1)]) for size in range(5): matching = create_smti_instance(size, 0.5, 0.5) all_possibilites = ut.get_all_matches(matching.males, matching.females, matching.size) self.assertEqual(compute_solution_count(size), len(list(all_possibilites))) matching.compute_all_solutions() for match in matching.solutions: (stable, s_size) = Solution(matching, match).is_stable() self.assertTrue(stable, "solution was not stable") self.assertTrue(s_size <= size, "solution size was bigger then expected") self.assertTrue(size != -1, "solution had somebody matched twice") matching = mock_matching_smti(2) matching.compute_all_solutions() self.assertEqual(2, len(matching.solutions))
def test_matching_and_solution(self): matching = mock_matching_smti() solution = Solution(matching, mock.smti_instance_solution) self.assertEqual(solution.get_partner("M0"), "W3") self.assertEqual(solution.get_partner("M1"), "W0") self.assertEqual(solution.get_partner("M2"), None) self.assertEqual(solution.is_free("M2"), True) self.assertEqual(solution.is_free("M1"), False) self.assertEqual(solution.is_acceptable("M1", "W0"), True) self.assertEqual(solution.is_acceptable("M1", "M2"), False) self.assertEqual(solution.is_blocking("M1", "M2", "smti"), False) self.assertEqual(solution.get_blocking_pairs("smti"), []) self.assertEqual(solution.is_stable("smti"), (True, 3)) self.assertTrue(solution.is_stable()[0]) matching = mock_matching_smp() matches = mock.smp_solution solution = Solution(matching, matches) gs_solution = StandardSMP(matching).solve() qubo_solution = QbsolvSMP(matching).solve() qubo_smti_solution = QUBO_SMTI(matching).solve() qubo_lp_solution = LP_smti(matching).solve() self.assertEqual(solution.is_stable("smp"), (True, 5)) self.assertEqual( solution.is_stable("smti"), (True, 5)) # for smp instances, both methods are supposed to work self.assertEqual(solution.get_solution(), gs_solution.get_solution()) self.assertEqual(qubo_solution.is_stable("smp"), (True, 5)) # self.assertEqual(qubo_smti_solution.is_stable("smp"), (True, 5)) self.assertEqual(qubo_smti_solution.is_stable("smti"), (True, 5)) # self.assertEqual(qubo_lp_solution.is_stable("smp"), (True, 5)) self.assertEqual(qubo_lp_solution.is_stable("smti"), (True, 5))
def _is_matching_stable(self, match): from algorithms.solution import Solution (stable, size) = Solution(self, match).is_stable() if stable: return match return None