예제 #1
0
def encode_bqm_as_qp(solver, linear, quadratic):
    """Encode the binary quadratic problem for submission to a given solver,
    using the `qp` format for data.

    Args:
        solver (:class:`dwave.cloud.solver.Solver`):
            The solver used.

        linear (dict[variable, bias]/list[variable, bias]):
            Linear terms of the model.

        quadratic (dict[(variable, variable), bias]):
            Quadratic terms of the model.

    Returns:
        encoded submission dictionary
    """
    active = active_qubits(linear, quadratic)

    # Encode linear terms. The coefficients of the linear terms of the objective
    # are encoded as an array of little endian 64 bit doubles.
    # This array is then base64 encoded into a string safe for json.
    # The order of the terms is determined by the _encoding_qubits property
    # specified by the server.
    # Note: only active qubits are coded with double, inactive with NaN
    nan = float('nan')
    lin = [
        uniform_get(linear, qubit, 0 if qubit in active else nan)
        for qubit in solver._encoding_qubits
    ]
    lin = base64.b64encode(struct.pack('<' + ('d' * len(lin)), *lin))

    # Encode the coefficients of the quadratic terms of the objective
    # in the same manner as the linear terms, in the order given by the
    # _encoding_couplers property, discarding tailing zero couplings
    quad = [
        quadratic.get((q1, q2), 0) + quadratic.get((q2, q1), 0)
        for (q1, q2) in solver._encoding_couplers
        if q1 in active and q2 in active
    ]
    quad = base64.b64encode(struct.pack('<' + ('d' * len(quad)), *quad))

    # The name for this encoding is 'qp' and is explicitly included in the
    # message for easier extension in the future.
    return {
        'format': 'qp',
        'lin': lin.decode('utf-8'),
        'quad': quad.decode('utf-8')
    }
예제 #2
0
 def test_active_qubits_list(self):
     self.assertEqual(active_qubits([], {}), set())
     self.assertEqual(active_qubits([2], {}), {0})
     self.assertEqual(active_qubits([2, 2, 0], {}), {0, 1, 2})
     self.assertEqual(active_qubits([], {(0, 1): 0}), {0, 1})
     self.assertEqual(active_qubits([0, 0], {(0, 2): 0}), {0, 1, 2})
예제 #3
0
def from_qmi_response(problem,
                      response,
                      embedding_context=None,
                      warnings=None,
                      params=None,
                      sampleset=None):
    """Construct problem data for visualization based on the low-level sampling
    problem definition and the low-level response.

    Args:
        problem ((list/dict, dict[(int, int), float]) or dict[(int, int), float]):
            Problem in Ising or QUBO form, conforming to solver graph.
            Note: if problem is given as tuple, it is assumed to be in Ising
            variable space, and if given as a dict, Binary variable space is
            assumed. Zero energy offset is always implied.

        response (:class:`dwave.cloud.computation.Future`):
            Sampling response, as returned by the low-level sampling interface
            in the Cloud Client (e.g. :meth:`dwave.cloud.Solver.sample_ising`
            for Ising problems).

        embedding_context (dict, optional):
            A map containing an embedding of logical problem onto the
            solver's graph (the ``embedding`` key) and embedding parameters
            used (e.g. ``chain_strength``).

        warnings (list[dict], optional):
            Optional list of warnings.

        params (dict, optional):
            Sampling parameters used.

        sampleset (:class:`dimod.SampleSet`, optional):
            Optional unembedded sampleset.

    """
    logger.debug("from_qmi_response({!r})".format(
        dict(problem=problem,
             response=response,
             response_energies=response['energies'],
             embedding_context=embedding_context,
             warnings=warnings,
             params=params,
             sampleset=sampleset)))

    try:
        linear, quadratic = problem
    except:
        linear, quadratic = reformat_qubo_as_ising(problem)

    # make sure lin/quad are not dimod views (that handle directed edges)
    if isinstance(linear, BQMView):
        linear = dict(linear)
    if isinstance(quadratic, BQMView):
        quadratic = dict(quadratic)

    solver = response.solver
    if not isinstance(response.solver, StructuredSolver):
        raise TypeError("only structured solvers are supported")

    topology = _get_solver_topology(solver)
    if topology['type'] not in SUPPORTED_SOLVER_TOPOLOGY_TYPES:
        raise TypeError("unsupported solver topology type")

    solver_id = solver.id
    problem_type = response.problem_type

    variables = list(response.variables)
    active = active_qubits(linear, quadratic)

    # filter out invalid values (user's error in problem definition), since
    # SAPI ignores them too
    active = {q for q in active if q in solver.variables}

    # sanity check
    active_variables = response['active_variables']
    assert set(active) == set(active_variables)

    solutions = list(map(itemsgetter(*active_variables),
                         response['solutions']))
    energies = response['energies']
    num_occurrences = response.num_occurrences
    num_variables = solver.num_qubits
    timing = response.timing

    # note: we can't use encode_problem_as_qp(solver, linear, quadratic) because
    # visualizer accepts decoded lists (and nulls instead of NaNs)
    problem_data = {
        "format":
        "qp",  # SAPI non-conforming (nulls vs nans)
        "lin": [
            uniform_get(linear, v, 0 if v in active else None)
            for v in solver._encoding_qubits
        ],
        "quad": [
            quadratic.get((q1, q2), 0) + quadratic.get((q2, q1), 0)
            for (q1, q2) in solver._encoding_couplers
            if q1 in active and q2 in active
        ]
    }

    # include optional embedding
    if embedding_context is not None and 'embedding' in embedding_context:
        problem_data['embedding'] = embedding_context['embedding']

    # try to reconstruct sampling params
    if params is None:
        params = {'num_reads': int(sum(num_occurrences))}

    # expand with defaults
    params = _expand_params(solver, params, timing)

    # construct problem stats
    problem_stats = _problem_stats(response=response,
                                   sampleset=sampleset,
                                   embedding_context=embedding_context)

    data = {
        "ready":
        True,
        "details":
        _details_dict(response),
        "data":
        _problem_dict(solver_id, problem_type, problem_data, params,
                      problem_stats),
        "answer":
        _answer_dict(solutions, active_variables, energies, num_occurrences,
                     timing, num_variables),
        "warnings":
        _warnings(warnings),
        "rel":
        dict(solver=solver),
    }

    if sampleset is not None:
        data["unembedded_answer"] = _unembedded_answer_dict(sampleset)

    logger.trace("from_qmi_response returned %r", data)

    return data
예제 #4
0
 def test_active_qubits_dict(self):
     self.assertEqual(active_qubits({}, {}), set())
     self.assertEqual(active_qubits({0: 0}, {}), {0})
     self.assertEqual(active_qubits({}, {(0, 1): 0}), {0, 1})
     self.assertEqual(active_qubits({2: 0}, {(0, 1): 0}), {0, 1, 2})