Exemple #1
0
    def test_discard_with_dimod(self):
        sample0 = {0: -1, 1: -1, 2: +1}
        sample1 = {0: +1, 1: -1, 2: +1}
        samples = [sample0, sample1]

        # now set up an embedding that works for one sample and not the other
        embedding = {'a': {0, 1}, 'b': {2}}

        # load the samples into a dimod response
        response = dimod.SpinResponse()
        response.add_samples_from(samples, (0 for __ in samples))

        # specify that majority vote should be used
        source_samples = eutil.unembed_samples(
            response, embedding, chain_break_method=eutil.discard)

        # only the first sample should be returned
        self.assertEqual(len(source_samples), 1)
        self.assertEqual(source_samples, [{'a': -1, 'b': +1}])
Exemple #2
0
    def test_majority_vote_with_dimod(self):
        sample0 = {0: -1, 1: -1, 2: +1}
        sample1 = {0: +1, 1: -1, 2: +1}
        samples = [sample0, sample1]

        embedding = {'a': {0, 1, 2}}

        # load the samples into a dimod response
        response = dimod.SpinResponse()
        response.add_samples_from(samples, (0 for __ in samples))

        # specify that majority vote should be used
        source_samples = eutil.unembed_samples(
            response, embedding, chain_break_method=eutil.majority_vote)

        source0, source1 = source_samples

        self.assertEqual(source0['a'], -1)
        self.assertEqual(source1['a'], +1)
Exemple #3
0
    def test_typical_dimod_response(self):
        """unembed should be compatible with the dimod response object"""
        nodes = range(10)
        target_samples = [{v: random.choice((-1, 1))
                           for v in nodes} for __ in range(100)]

        # load the samples into a dimod response
        response = dimod.SpinResponse()
        response.add_samples_from(target_samples, (0 for __ in target_samples))

        # embedding is map half the target vars to one source, and the other half to
        # another
        embedding = {'a': range(5), 'b': range(5, 10)}

        # use the response as the target_samples
        source_samples = eutil.unembed_samples(response, embedding)

        # not checking correctness of samples, just that they have the correct form
        self.assertEqual(len(source_samples), 100)
        for sample in source_samples:
            self.assertIsInstance(sample, dict)
            self.assertEqual(set(sample), {'a', 'b'})  # maps to source vars
            self.assertTrue(all(bias in (-1, 1) for bias in sample.values()))
    def sample_ising(self, h, J, embedding_tag=None, **sapi_kwargs):
        """Embeds the given problem using sapi's find_embedding then invokes
        the given sampler to solve it.

        Args:
            h (dict/list): The linear terms in the Ising problem. If a
                dict, should be of the form {v: bias, ...} where v is
                a variable in the Ising problem, and bias is the linear
                bias associated with v. If a list, should be of the form
                [bias, ...] where the indices of the biases are the
                variables in the Ising problem.
            J (dict): A dictionary of the quadratic terms in the Ising
                problem. Should be of the form {(u, v): bias} where u,
                v are variables in the Ising problem and bias is the
                quadratic bias associated with u, v.
            embedding_tag: Allows the user to specify a tag for the generated
                embedding. Useful for when the user wishes to submit multiple
                problems with the same logical structure.
            Additional keyword parameters are the same as for
            SAPI's solve_ising function, see QUBIST documentation.

        Returns:
            :class:`dimod.SpinResponse`: The unembedded samples.

        Examples:
            >>> sampler = sapi.EmbeddingComposite(sapi.SAPILocalSampler('c4-sw_optimize'))
            >>> response = sampler.sample_ising({}, {(0, 1): 1, (0, 2): 1, (1, 2): 1})

            Using the embedding_tag, the embedding is generated only once.
            >>> h = {0: .1, 1: 1.3, 2: -1.}
            >>> J = {(0, 1): 1, (1, 2): 1, (0, 2): 1}
            >>> sampler = sapi.EmbeddingComposite(sapi.SAPILocalSampler('c4-sw_optimize'))
            >>> response0 = sampler.sample_ising(h, J, embedding_tag='K3')
            >>> response1 = sampler.sample_ising(h, J, embedding_tag='K3')

        """
        # get the sampler that is used by the composite
        sampler = self._child

        # the ising_index_labels decorator converted the keys of h to be indices 0, n-1
        # sapi wants h to be a list, so let's make that conversion, using the keys as
        # the indices.
        h_list = [h[v] for v in range(len(h))]

        # get the structure of the child sampler. The first value are the nodes which
        # we don't need, the second is the set of edges available.
        (__, edgeset) = sampler.structure

        if embedding_tag is None or embedding_tag not in self.cached_embeddings:
            # we have not previously cached an embedding so we need to determine it

            # get the adjacency structure of our problem
            S = set(J)
            S.update({(v, v) for v in h})

            # embed our adjacency structure, S, into the edgeset of the sampler.
            embeddings = find_embedding(S, edgeset)

            # sometimes it fails, often because the problem is too large
            if J and not embeddings:
                raise Exception('No embedding found')

            # now it is possible that h_list might include nodes not in embedding, so let's
            # handle that case here
            if len(h_list) > len(embeddings):
                emb_qubits = set().union(*embeddings)
                while len(h_list) > len(embeddings):
                    for v in sampler.solver.properties['qubits']:
                        if v not in emb_qubits:
                            embeddings.append([v])
                            emb_qubits.add(v)
                            break

            if embedding_tag is not None:
                # save the embedding for posterity
                self.cached_embeddings[embedding_tag] = embeddings
        else:
            # the user has asserted that we can reuse a previously created embedding
            embeddings = self.cached_embeddings[embedding_tag]

        # embed the problem
        h0, j0, jc, new_emb = embed_problem(h_list, J, embeddings, edgeset)

        # combine jc and j0
        emb_j = j0.copy()
        emb_j.update(jc)

        # pass the chains we made into the sampler if it wants them
        if 'chains' in sampler.solver.properties['parameters'] and 'chains' not in sapi_kwargs:
            sapi_kwargs['chains'] = new_emb

        # invoke the child sampler
        emb_response = sampler.sample_ising(h0, emb_j, **sapi_kwargs)

        # we need the samples back into lists for the unembed_answer function
        answers = [[sample[i] for i in range(len(sample))] for sample in emb_response]

        # unemnbed
        solutions = unembed_answer(answers, new_emb, 'minimize_energy', h_list, J)

        # and back once again into dicts for dimod...
        samples = ({v: sample[v] for v in h} for sample in solutions)
        sample_data = (data for __, data in emb_response.samples(data=True))
        response = dimod.SpinResponse()
        response.add_samples_from(samples, sample_data=sample_data, h=h, J=J)

        return response