Skip to content
This repository has been archived by the owner on Jan 26, 2023. It is now read-only.

QBSolv doesn't use QPU #134

Closed
mstechly opened this issue Oct 11, 2018 · 11 comments
Closed

QBSolv doesn't use QPU #134

mstechly opened this issue Oct 11, 2018 · 11 comments

Comments

@mstechly
Copy link

Description
When I pass sampler to QBSolv, it still uses classical solver instead of running code on QPU.

To Reproduce

from dwave.system.samplers import DWaveSampler
from dwave_qbsolv import QBSolv
from dwave.system.composites import EmbeddingComposite

Q = {(0, 0): 1, (1, 1): 1, (0, 1): 1}

sapi_token = 'my_token'

endpoint = 'https://cloud.dwavesys.com/sapi'
sampler = DWaveSampler(token=sapi_token, endpoint= endpoint)

# Not sure which version is correct, both solve clasically
response = QBSolv().sample_qubo(Q, solver=sampler)
response = QBSolv().sample_qubo(Q, solver=EmbeddingComposite(sampler))

# This works on QPU, but I wanted to use QBSolv
response = EmbeddingComposite(sampler).sample_qubo(Q)

Expected behavior
I expect that my code will be executed on QPU when I pass a sampler, especially that I tested that this sampler executes code on QPU without QBSolv.
It should at least print a warning since this behavior is not what I expected.

Environment:

  • OS: 10.13.6
  • Python version: 3.6.4
  • dwave-qbsolv==0.2.9
  • dwave-system==0.5.3
@JoelPasvolsky
Copy link
Contributor

Hi @mstechly,

If you look at solver.cc, you see this bit of code:

// outer loop begin
    while (ContinueWhile) {
        if (qubo_size > 20 &&
            subMatrix < qubo_size) {  // these are of the size that will use updates from submatrix processing

The outer loop of qbsolv runs a tabu search and only delegates subproblems to the subproblem solver when qubo_size is greater than 20 variables. Your current problem has 3 variables, so it's too small for the QPU to be called. Go big: try something like qubo_size = 200 and subqubo_size = 30 and then the QPU will be called.

@mstechly
Copy link
Author

@JoelPasvolsky I did as you suggested:

from dwave.system.samplers import DWaveSampler
from dwave_qbsolv import QBSolv
from dwave.system.composites import EmbeddingComposite
import numpy as np

sapi_token = 'my_token'
endpoint = 'https://cloud.dwavesys.com/sapi'
sampler = DWaveSampler(token=sapi_token, endpoint=endpoint)

problem_size = 200
matrix = np.random.random((problem_size,problem_size))
matrix = (matrix + matrix.T)/2
Q = {}
for i in range(problem_size):
    for j in range(i, problem_size):
        if i==j:
            Q[(i,j)] = -problem_size/2
        else:
            Q[(i, j)] = matrix[i][j]

response = QBSolv().sample_qubo(Q, solver=sampler, sub_size=30)

And got the following message, many, many times:

Exception ignored in: 'dwave_qbsolv.qbsolv_binding.solver_callback'
Traceback (most recent call last):
  File "python/dwave_qbsolv/qbsolv_binding.pyx", line 65, in dwave_qbsolv.qbsolv_binding.run_qbsolv.dimod_callback
  File "/my_venv/lib/python3.6/site-packages/dwave/system/samplers/dwave_sampler.py", line 332, in sample_qubo
    future = self.solver.sample_qubo(Q, **kwargs)
  File "/my_venv/lib/python3.6/site-packages/dwave/cloud/solver.py", line 257, in sample_qubo
    return self._sample('qubo', linear, quadratic, params)
  File "/my_venv/lib/python3.6/site-packages/dwave/cloud/solver.py", line 272, in _sample
    raise ValueError("Problem graph incompatible with solver.")
ValueError: Problem graph incompatible with solver.

It gives me some results but doesn't seem to call QPU.

Also, how can I check if QPU was actually called? Now I'm comparing calculation times with tabu parameters and look if any packets to/from D-Wave go in/out my computer, but there's probably some more elegant way?

@JoelPasvolsky
Copy link
Contributor

Hi @mstechly,

The problem graph needs to be embedded onto the QPU. For example, a quick way to do that is by replacing the line sampler = DWaveSampler(token=sapi_token, endpoint=endpoint) with the line sampler = EmbeddingComposite(DWaveSampler(token=sapi_token, endpoint=endpoint)).
See more here: https://docs.ocean.dwavesys.com/projects/system/en/latest/reference/composites/embedding.html
A better way is to use a repeated embedding for all calls, such as https://docs.ocean.dwavesys.com/projects/system/en/latest/reference/composites/fixed_embedding.html, for example, and soon dwavesystems/dwave-system#112.

You also need to specify 'solver_limit' parameter instead of sub_size=30 in the call: response = QBSolv().sample_qubo(Q, solver=sampler, solver_limit=30)

If you want to see what's happening during the execution, you can set the verbosity parameter to 4.

@mstechly
Copy link
Author

Thank you @JoelPasvolsky !
Things start making sense to me :)

I will refactor my code to use fixed embedding, but for now I'm still not sure if QBsolv is using QPU.

This is output after one iteration and it seems to me to work on classical tabu:

Bits set before solver 111111110110111011111111111111
Bits set after solver  111111111110111111111110111111

4.581024 seconds  ***Full Tabu  -- after partition pass
4.582666 seconds Latest answer  -10124.55638 iterations =1640195
 DUPLICATE_HIGHEST_ENERGY     10124.556376 2 0
4.582695 seconds V Best outer loop =-10124.556376 iterations 1640195
Reduced submatrix solution l = 0; 42, subMatrix size = 30
Submatrix starting at backbone 0

@randomir
Copy link
Member

Additionally, @mstechly, if you're generating problems (like with random in your example), you might find useful the list of available nodes (qubits) and edges (couplings):

>>> from dwave.system.samplers import DWaveSampler
>>> sampler = DWaveSampler()
>>> sampler.nodelist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12... # snipped
>>> sampler.edgelist
[(0, 4), (0, 5), (0, 6), (0, 7), (0, 128), (1, 4), (1, 5), (1, 6), (1, 7), (1, 129)... # snipped

@JoelPasvolsky
Copy link
Contributor

@mstechly, if you check on your Leap Dashboard, you'll see how much QPU time your execution consumed. If the value of the "REMAINING QPU TIME" did not change then it did not run on the QPU.

@mstechly
Copy link
Author

@JoelPasvolsky Thanks, now I see it works.
I would like to incorporate some of the conclusions to documentation - what do you think would be the best place for it?

If I wanted to analyze how much time I spent on qpu etc. (as I get when I use simply EmbeddingComposite(sampler).sample_qubo(Q) instead of QBSolv) is there a simple way to do that?

@JoelPasvolsky
Copy link
Contributor

@mstechly, We have someone planning to do a significant documentation update soon. Would it be easier to write up your conclusions in a new issue (feature request for added documentation) until that's done?

qbsolv does not provide the kind of low-level control of communications with a QPU as you can get with working directly with dwave-cloud-client. So I think just checking the Leap dashboard before and after a run to see the time difference.

@mstechly
Copy link
Author

@JoelPasvolsky Sure!
We found other way to overcome this limitation of qbsolv, I hope we will post the code next week.

@JoelPasvolsky
Copy link
Contributor

JoelPasvolsky commented Oct 19, 2018

@arcondello, closed by Issue #135

@dexter2206
Copy link

If anybody is interested, this gist shows the code that we use with @mstechly for recording timing information for QBsolv.

https://gist.github.com/dexter2206/916e407e4ce88475ea93e20d2516f78f

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants