Binary Quadratic Model, Qubo & Ising
Any qlassf function can be transformed to a binary quadratic model using the to_bqm
function. In this example we create a generic function that factorize num
, and we bind num
with 15.
from qlasskit import qlassf, Qint, Parameter
@qlassf
def test_factor_generic(num: Parameter[Qint[4]], a: Qint[3], b: Qint[3]) -> Qint[4]:
return num - (a * b)
test_factor = test_factor_generic.bind(num=15)
bqm = test_factor.to_bqm()
print("Vars:", bqm.num_variables, "\nInteractions:", bqm.num_interactions)
Vars: 14
Interactions: 41
A qlassf function can also be exported as a QUBO model using to_bqm('qubo')
or as an Ising model using to_bqm('ising')
.
Running on simulated sampler annealer
Now we can run a simulated sampler annealer to minimize this function; qlasskit offer a decode_samples
helper function that translates sample result to the high level types of qlasskit.
import neal
from qlasskit.bqm import decode_samples
sa = neal.SimulatedAnnealingSampler()
sampleset = sa.sample(bqm, num_reads=10)
decoded_samples = decode_samples(test_factor, sampleset)
best_sample = min(decoded_samples, key=lambda x: x.energy)
print(best_sample.sample)
{'a': 3, 'b': 5}
The result is 5 and 3 as expected (since 5 times 3 is equal to 15).
Running on DWave annealer
If we have a valid DWave account, we can run our problem on a real quantum annealer as follow:
from dwave.system import DWaveSampler, EmbeddingComposite
sampler = EmbeddingComposite(DWaveSampler())
sampleset = sampler.sample(bqm, num_reads=10)
decoded_samples = decode_samples(test_factor, sampleset)
best_sample = min(decoded_samples, key=lambda x: x.energy)
print(best_sample.sample)
---------------------------------------------------------------------------
SolverFailureError Traceback (most recent call last)
Cell In[3], line 5
3 sampler = EmbeddingComposite(DWaveSampler())
4 sampleset = sampler.sample(bqm, num_reads=10)
----> 5 decoded_samples = decode_samples(test_factor, sampleset)
6 best_sample = min(decoded_samples, key=lambda x: x.energy)
7 print(best_sample.sample)
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/qlasskit-0.1.18-py3.10.egg/qlasskit/bqm.py:142, in decode_samples(qf, sampleset)
140 """Get dimod sampleset and return an high level decoded solution"""
141 model = qf.to_bqm("pq_model")
--> 142 decoded = model.decode_sampleset(sampleset)
144 new_dec = []
145 for el in decoded:
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dimod/sampleset.py:1121, in SampleSet.record(self)
1105 @property
1106 def record(self):
1107 """:obj:`numpy.recarray` containing the samples, energies, number of occurences, and other sample data.
1108
1109 Examples:
(...)
1119
1120 """
-> 1121 self.resolve()
1122 return self._record
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dimod/sampleset.py:1485, in SampleSet.resolve(self)
1483 # if it doesn't have the attribute then it is already resolved
1484 if hasattr(self, '_future'):
-> 1485 samples = self._result_hook(self._future)
1486 self.__init__(samples.record, samples.variables, samples.info, samples.vartype)
1487 del self._future
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/system/composites/embedding.py:284, in EmbeddingComposite.sample.<locals>.async_unembed(response)
279 def async_unembed(response):
280 # unembed the sampleset aysnchronously.
282 warninghandler.chain_break(response, embedding)
--> 284 sampleset = unembed_sampleset(response, embedding, source_bqm=bqm,
285 chain_break_method=chain_break_method,
286 chain_break_fraction=chain_break_fraction,
287 return_embedding=return_embedding)
289 if return_embedding:
290 sampleset.info['embedding_context'].update(
291 embedding_parameters=embedding_parameters,
292 chain_strength=embedding.chain_strength)
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/embedding/transforms.py:606, in unembed_sampleset(target_sampleset, embedding, source_bqm, chain_break_method, chain_break_fraction, return_embedding)
603 except KeyError:
604 raise ValueError("given bqm does not match the embedding")
--> 606 record = target_sampleset.record
608 unembedded, idxs = chain_break_method(target_sampleset, chains)
610 reserved = {'sample', 'energy'}
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dimod/sampleset.py:1121, in SampleSet.record(self)
1105 @property
1106 def record(self):
1107 """:obj:`numpy.recarray` containing the samples, energies, number of occurences, and other sample data.
1108
1109 Examples:
(...)
1119
1120 """
-> 1121 self.resolve()
1122 return self._record
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dimod/sampleset.py:1485, in SampleSet.resolve(self)
1483 # if it doesn't have the attribute then it is already resolved
1484 if hasattr(self, '_future'):
-> 1485 samples = self._result_hook(self._future)
1486 self.__init__(samples.record, samples.variables, samples.info, samples.vartype)
1487 del self._future
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/system/samplers/dwave_sampler.py:452, in DWaveSampler.sample.<locals>._hook(computation)
450 except (SolverError, InvalidAPIResponseError) as exc:
451 if not self.failover:
--> 452 raise exc
453 if isinstance(exc, SolverAuthenticationError):
454 raise exc
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/system/samplers/dwave_sampler.py:439, in DWaveSampler.sample.<locals>._hook(computation)
436 return sampleset
438 try:
--> 439 return resolve(computation)
441 except (ProblemUploadError, RequestTimeout, PollingTimeout) as exc:
442 if not self.failover:
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/system/samplers/dwave_sampler.py:429, in DWaveSampler.sample.<locals>._hook.<locals>.resolve(computation)
427 def resolve(computation):
428 sampleset = computation.sampleset
--> 429 sampleset.resolve()
431 if warninghandler is not None:
432 warninghandler.too_few_samples(sampleset)
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dimod/sampleset.py:1485, in SampleSet.resolve(self)
1483 # if it doesn't have the attribute then it is already resolved
1484 if hasattr(self, '_future'):
-> 1485 samples = self._result_hook(self._future)
1486 self.__init__(samples.record, samples.variables, samples.info, samples.vartype)
1487 del self._future
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/cloud/computation.py:823, in Future.sampleset.<locals>.<lambda>(f)
818 except ImportError:
819 raise RuntimeError("Can't construct SampleSet without dimod. "
820 "Re-install the library with 'bqm' support.")
822 self._sampleset = sampleset = dimod.SampleSet.from_future(
--> 823 self, lambda f: f.wait_sampleset())
825 # propagate id to sampleset as well
826 # note: this requires dimod>=0.8.21 (before that version SampleSet
827 # had slots set which prevented dynamic addition of attributes).
828 sampleset.wait_id = self.wait_id
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/cloud/computation.py:755, in Future.wait_sampleset(self)
752 """Blocking sampleset getter."""
754 # blocking result get
--> 755 result = self._load_result()
757 # common problem info: id/label
758 problem_info = dict(problem_id=self.id)
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/cloud/computation.py:893, in Future._load_result(self)
891 # Check for other error conditions
892 if self._exception is not None:
--> 893 raise self._exception
895 # If someone else took care of this while we were waiting
896 if self._result is not None:
File ~/.pyenv/versions/3.10.13/envs/qlasskit_310-env/lib/python3.10/site-packages/dwave/cloud/client/base.py:1309, in Client._handle_problem_status(self, message, future)
1307 if 'error_code' in message and 'error_msg' in message:
1308 logger.debug("Error response received: %r", message)
-> 1309 raise SolverFailureError(message['error_msg'])
1311 if 'status' not in message:
1312 raise InvalidAPIResponseError("'status' missing in problem description response")
SolverFailureError: Problem not accepted because user has insufficient remaining solver access time in project DEV.