Implementing a Sampler
This walkthrough builds a minimal sampler that works through the same public interfaces used by package wrappers. It uses exhaustive search so the example is self-contained; a production wrapper can replace that inner loop with a call to an external library, service, or device.
Minimal module
A QUBODrivers sampler needs an optimizer type and a QUBODrivers.sample method. The QUBODrivers.@setup macro creates the optimizer type, standard MOI methods, and attribute storage.
module DemoSampler
import QUBODrivers
import QUBODrivers: MOI, QUBOTools, Sample, SampleSet
QUBODrivers.@setup Optimizer begin
name = "Demo Sampler"
version = v"0.1.0"
attributes = begin
NumberOfReads["num_reads"]::Integer = 1
end
end
function QUBODrivers.sample(sampler::Optimizer{T}) where {T}
n, linear, quadratic, scale, offset = QUBOTools.qubo(
sampler,
:dict;
sense = :min,
)
num_reads = MOI.get(sampler, NumberOfReads())
if num_reads < 1
error("'num_reads' must be a positive integer")
end
best_state = Vector{Int}()
best_value = nothing
for state in Iterators.product(ntuple(_ -> (0, 1), n)...)
candidate_state = collect(state)
candidate_value = QUBOTools.value(
candidate_state,
linear,
quadratic,
scale,
offset,
)
if isnothing(best_value) || candidate_value < best_value
best_state = candidate_state
best_value = candidate_value
end
end
samples = [
Sample{T,Int}(copy(best_state), best_value)
for _ in 1:num_reads
]
metadata = Dict{String,Any}(
"origin" => "Demo Sampler",
"time" => Dict{String,Any}("effective" => 0.0),
"status" => "optimal",
)
return SampleSet{T}(samples, metadata; sense = :min, domain = :bool)
end
end
nothingUse it from JuMP
The generated Optimizer type is an MOI.AbstractOptimizer, so it can be passed directly to JuMP.Model.
using JuMP
model = Model(DemoSampler.Optimizer)
set_optimizer_attribute(model, "num_reads", 2)
@variable(model, x[1:2], Bin)
@objective(model, Min, -x[1] - 2x[2] + 3x[1] * x[2])
optimize!(model)
(objective_value(model), round.(Int, value.(x)), result_count(model))(-2.0, [0, 1], 1)Implementation checklist
When adapting the example for a real sampler:
- choose the QUBOTools representation that matches the backend, such as
QUBOTools.qubo(sampler, :dict; sense = :min)orQUBOTools.ising(sampler, :dense; sense = :max); - read user-facing options through MOI attributes generated by
@setup; - convert backend outputs into
Sample{T,Int}entries; - return a
SampleSet{T}with the correctsenseanddomain; - include useful metadata such as timing, backend status, and backend version;
- run
QUBODrivers.test(YourSampler.Optimizer)in the package test suite.
The built-in RandomSampler and ExactSampler implementations are compact references for these same steps.