Example #1
0
    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
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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
Example #5
0
    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")
Example #6
0
 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)
Example #7
0
    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
Example #8
0
    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}")
Example #9
0
 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]
Example #10
0
    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)
Example #11
0
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}")
Example #12
0
    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))
Example #13
0
    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))
Example #14
0
    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))
Example #15
0
 def _is_matching_stable(self, match):
     from algorithms.solution import Solution
     (stable, size) = Solution(self, match).is_stable()
     if stable:
         return match
     return None