예제 #1
0
파일: mapping.py 프로젝트: MLeib/QAOA
    def __init__(self,
                 qpu: Type[QPU],
                 problem: dimod.BinaryQuadraticModel,
                 partial_initial_mapping: dict = None):
        if problem.vartype is dimod.BINARY:
            problem.change_vartype(dimod.SPIN)
            print('changed vartype of problem definition from BINARY to SPIN')

        self.log_qbs = set(problem.variables)
        self.hard_qbs = set(qpu.qubits())

        assert len(self.hard_qbs) == len(
            self.log_qbs
        ), 'number of hardware qubits does not match number of logical qubits'

        if partial_initial_mapping is None:
            self.hard2log = {
                hard_qb: log_qb
                for hard_qb, log_qb in zip(self.hard_qbs, self.log_qbs)
            }
            self.log2hard = {
                log_qb: hard_qb
                for log_qb, hard_qb in zip(self.log_qbs, self.hard_qbs)
            }
        else:
            assert len(set(partial_initial_mapping.values())) == len(
                partial_initial_mapping.values(
                )), 'partial_initial_mapping is not bijective'
            if len(partial_initial_mapping) < len(self.log_qbs):
                remaining_hard_qbs = self.hard_qbs - set(
                    partial_initial_mapping.keys())
                remaining_log_qbs = self.log_qbs - set(
                    partial_initial_mapping.values())
                initial_mapping = partial_initial_mapping
                for hard_qb, log_qb in zip(remaining_hard_qbs,
                                           remaining_log_qbs):
                    initial_mapping[hard_qb] = log_qb
            else:
                initial_mapping = partial_initial_mapping

            self.hard2log = initial_mapping
            self.log2hard = {
                log_qb: hard_qb
                for hard_qb, log_qb in self.hard2log.items()
            }
예제 #2
0
def convert_openfermion_ising_to_qubo(
        operator: IsingOperator) -> BinaryQuadraticModel:
    """
    Converts dimod Openfermion IsingOperator to BinaryQuadraticModel object.
    The resulting QUBO has the following property:
    For every bitstring, its energy is the same as the expected value of the original Ising Hamiltonian.
    For more context about conventions used please refer to note in `convert_measurements_to_sampleset` docstring.

    Note:
        The conversion might not be 100% accurate due to performing floating point operations during conversion between Ising and QUBO models.

    Args:
        operator: IsingOperator we want to convert
    Returns:
        qubo: BinaryQuadraticModel representation of the input operator

    """

    if not isinstance(operator, IsingOperator):
        raise TypeError(
            f"Input is of type: {type(operator)}. Only Ising Operators are supported."
        )
    offset = 0
    linear_terms = {}
    quadratic_terms = {}
    for term, coeff in operator.terms.items():
        if len(term) == 0:
            offset = coeff
        if len(term) == 1:
            linear_terms[term[0][0]] = -coeff
        if len(term) == 2:
            quadratic_terms[(term[0][0], term[1][0])] = coeff
        if len(term) > 2:
            raise ValueError(
                "Ising to QUBO conversion works only for quadratic Ising models."
            )

    dimod_ising = BinaryQuadraticModel(linear_terms,
                                       quadratic_terms,
                                       offset,
                                       vartype="SPIN")
    return dimod_ising.change_vartype("BINARY", inplace=False)
예제 #3
0
def convert_openfermion_ising_to_qubo(operator: IsingOperator):
    """
    Converts dimod BinaryQuadraticModel to OpenFermion IsingOperator object.
    NOTE: The conversion might not be 100% accurate due to performing floating point operations during conversion between Ising and QUBO models.

    Args:
        operator: IsingOperator we want to convert
    Returns:
        qubo: BinaryQuadraticModel representation of the input operator

    """

    if not isinstance(operator, IsingOperator):
        raise TypeError(
            f"Input is of type: {type(operator)}. Only Ising Operators are supported."
        )
    offset = 0
    linear_terms = {}
    quadratic_terms = {}
    for term, coeff in operator.terms.items():
        if len(term) == 0:
            offset = coeff
        if len(term) == 1:
            linear_terms[term[0][0]] = coeff
        if len(term) == 2:
            quadratic_terms[(term[0][0], term[1][0])] = coeff
        if len(term) > 2:
            raise ValueError(
                "Ising to QUBO conversion works only for quadratic Ising models."
            )

    dimod_ising = BinaryQuadraticModel(linear_terms,
                                       quadratic_terms,
                                       offset,
                                       vartype="SPIN")
    return dimod_ising.change_vartype("BINARY", inplace=False)
예제 #4
0
    def sample(self,
               bqm: dimod.BinaryQuadraticModel,
               method="miqp",
               num_reads=1,
               gurobi_params_kw=None):
        assert (method in ["mip", "miqp"])
        bqm_bin = bqm.change_vartype(vartype=dimod.BINARY, inplace=False)
        variable_ids = frozenset(bqm_bin.variables)
        variable_product_ids = frozenset(bqm_bin.quadratic)

        m = Model()

        gurobi_params = {
            "OutputFlag": 0,
            "TimeLimit": 60,
            "Threads": 12,
            "Cuts": 1,
            "MIPFocus": 2,
            "PoolSearchMode": 2,
            "PoolSolutions": num_reads
        }

        if gurobi_params_kw is None:
            gurobi_params_kw = {}

        gurobi_params.update(gurobi_params_kw)

        for param, value in gurobi_params.items():
            m.setParam(param, value)

        variable_lookup = {}
        for vid in variable_ids:
            variable_lookup[vid] = m.addVar(lb=0,
                                            ub=1,
                                            vtype=GRB.BINARY,
                                            name="var_{}".format(vid))
        if method == "mip":
            for pair in variable_product_ids:
                variable_lookup[pair] = m.addVar(lb=0,
                                                 ub=1,
                                                 vtype=GRB.BINARY,
                                                 name="link_{}_{}".format(
                                                     str(pair[0]),
                                                     str(pair[1])))
        m.update()
        if method == "mip":
            for i, j in variable_product_ids:
                m.addConstr(variable_lookup[(i, j)] >= variable_lookup[i] +
                            variable_lookup[j] - 1)
                m.addConstr(variable_lookup[(i, j)] <= variable_lookup[i])
                m.addConstr(variable_lookup[(i, j)] <= variable_lookup[j])

        bqm_ising = bqm.change_vartype(vartype=dimod.SPIN, inplace=False)
        if len(bqm_ising.linear) <= 0 or all(bqm_ising.linear[lt] == 0.0
                                             for lt in bqm_ising.linear):
            warnings.warn(
                'detected spin symmetry, adding symmetry breaking constraint')
            v1 = variable_ids[0]
            m.addConstr(variable_lookup[v1] == 0)

        obj = 0.0
        for lt in bqm_bin.linear:
            obj += bqm_bin.linear[lt] * variable_lookup[lt]

        if method == "mip":
            for qt in bqm_bin.quadratic:
                obj += bqm_bin.quadratic[qt] * variable_lookup[qt]
        elif method == "miqp":
            for qt in bqm_bin.quadratic:
                i = qt[0]
                j = qt[1]
                obj += bqm_bin.quadratic[qt] * variable_lookup[
                    i] * variable_lookup[j]

        m.setObjective(obj, GRB.MINIMIZE)
        m.update()

        m.optimize()

        energies = []
        samples = []
        for i in range(m.SolCount):
            m.Params.SolutionNumber = i  # set solution numbers
            energy = m.ObjVal + bqm_bin.offset
            sample = {k: int(variable_lookup[k].X) for k in variable_ids}
            energies.append(energy)
            samples.append(sample)

        ss = dimod.SampleSet.from_samples(samples,
                                          vartype=bqm.BINARY,
                                          energy=energies,
                                          aggregate_samples=True)
        return ss.change_vartype(bqm.vartype)