dwavesystems / dwave-qiskit-plugin

D-Wave Ocean plugin for IBM Qiskit.
Apache License 2.0
33 stars 21 forks source link

Problem Label Feature with dwave-qiskit-plugin #1

Closed tomtuamnuq closed 3 years ago

tomtuamnuq commented 3 years ago

With 2021-01-27 Leap Release problem label assignment was announced.

How should one set up the problem label when using dwave-ocean plugin for IBM Qiskit?

The MinimumEigenOptimizer uses the DWaveMinimumEigensolver.

We use the solve method of Qiskits MinimumEigenOptimizer, which does not support problem label feature.

I have not found the problem label in the source code of DWaveMinimumEigensolver so far. It could probably be added in line 191 of dwave_minimum_eigen_solver.py

arcondello commented 3 years ago

Hi @tomtuamnuq , there is not a way currently.

One solution would be to add a label, or perhaps a more general sample_kwargs dict, keyword argument to https://github.com/dwavesystems/dwave-qiskit-plugin/blob/7c604da4600e46224de647190a300f067cc99f21/dwave/plugins/qiskit/minimum_eigen_solvers/dwave_minimum_eigen_solver.py#L177 then https://github.com/dwavesystems/dwave-qiskit-plugin/blob/7c604da4600e46224de647190a300f067cc99f21/dwave/plugins/qiskit/minimum_eigen_solvers/dwave_minimum_eigen_solver.py#L205 and then https://github.com/dwavesystems/dwave-qiskit-plugin/blob/7c604da4600e46224de647190a300f067cc99f21/dwave/plugins/qiskit/minimum_eigen_solvers/dwave_minimum_eigen_solver.py#L187

tomtuamnuq commented 3 years ago

Hello @arcondello , thanks for your advice. I have added the keyword argument sample_kwargs to the above mentioned methods. Now I can set a label by calling compute_minimum_eigenvalue: result = dwave_mes.compute_minimum_eigenvalue(operator, label="test_of_label_problem_compute_min_eig") result.sampleset.info['problem_label'] The sampler will understand all parameters as described in D-Wave System Documentation's `solver guide.

I can submit num_reads as well. This leads to the question, how to handle this case because the num_reads parameter is set extra in https://github.com/dwavesystems/dwave-qiskit-plugin/blob/7c604da4600e46224de647190a300f067cc99f21/dwave/plugins/qiskit/minimum_eigen_solvers/dwave_minimum_eigen_solver.py#L189-L191

I think using the num_reads from the compute_minimum_eigenvalue method would be better because it can be set specific to the submitted problem. Therefore I would only use the num_reads from sampler in case it is not set in sample_kwargs.

UPDATE: By only adding sample_kwargs to compute_minimum_eigenvalue I cannot pass params when using qiskit mes. Adding a sample_kwargs property to dwave_mes would solves my problem. I have added this to my fork and extended the unit test for checking param propagation as well.

randomir commented 3 years ago

Thanks for opening this issue, @tomtuamnuq. We'll consider adding **kwargs support as described above.

Until then, a non-invasive way for this would be to create a new dimod.ComposedSampler that will supply custom sampling kwargs, like label:

from dimod import ComposedSampler

class CustomArgsSampler(ComposedSampler):
    def __init__(self, child_sampler, sample_kwargs=None):
        self._children = [child_sampler]
        if sample_kwargs is None:
            sample_kwargs = {}
        self._sample_kwargs = sample_kwargs

    @property
    def children(self):
        return self._children

    @property
    def parameters(self):
        return self.child.parameters.copy()

    @property
    def properties(self):
        return {'child_properties': self.child.properties.copy()}

    def sample(self, bqm, **kwargs):
        kwargs.update(self._sample_kwargs)
        return self.child.sample(bqm, **kwargs)

You could use it then like this:

from dwave.system import AutoEmbeddingComposite, DWaveSampler

qpu = AutoEmbeddingComposite(DWaveSampler())
sampler = CustomArgsSampler(qpu, sample_kwargs=dict(label='...'))
dwave_mes = DWaveMinimumEigensolver(sampler=sampler)
tomtuamnuq commented 3 years ago

Thanks four your support @randomir . The class CustomArgsSampler solves my issue. Anyway, I would add:

def set_label(self, label: str) -> None:
    """Sets the label for future problem submissions.

    Args:
        label (str): Problem label to be used in :meth:`.sample`.
    """
    self._sample_kwargs['label'] = label

With this method I don`t have to instantiate the instance again for every submission with a different label.