Sampling Models - dynexcoin/DynexSDK GitHub Wiki
Sampling Models
In the previous section we learned how to define a model for the Dynex sampler. To sample models, we need to
Defining the Dynex Sampler Object
A Dynex sampler object is created with the following command:
sampler = dynex.DynexSampler(model)
>>> [DYNEX] SAMPLER INITIALISED
The output confirms that the the sampler object has been successfully initialised. The following (optional) parameters can be set:
logging (Default: True)
Defines if the sampler class should show logging information during initialisation and the sampling process.
sampler = dynex.DynexSampler(model, logging=False);
Silences logging information.
mainnet (Default: True)
Defines if you want to use the Dynex Platform for sampling or the local sampler. Especially during implementation and testing it is advisable to work with a local sampler before having large scale samples run on the Dynex Platform. Usage of the local sampler requires minimum one GPU on your local machine.
sampler = dynex.DynexSampler(model, mainnet=False)
Defines that the sampler will use the local GPU for sampling.
description (Default: 'Dynex SDK Job')
You can define an individual descriptor label which is also being shown on the Dynex job boards.
sampler = dynex.DynexSampler(model, description='Dynex SDK test')
Will show sampled jobs on the Dynex job boards as "Dynex SDK test".
Sampling with the Sampler
With the sampler object being defined, we can start the sampling process. Depending on the configuration of your sampler, the sampling can be performed locally on the local GPU or on the Dynex Platform.
Local Sampling (mainnet=False)
The following example creates a simple problem and samples it locally using the local GPU. Note that to use local sampling (for testing, mainnet=False), you also need to install the Dynex SDK Local Testnet Sampler.
import dynex
import dimod
from pyqubo import Array
# Define the QUBO problem:
N = 15
K = 3
numbers = [4.8097315016016315, 4.325157567810298, 2.9877429101815127,
3.199880179616316, 0.5787939511978596, 1.2520928214246918,
2.262867466401502, 1.2300003067401255, 2.1601079352817925,
3.63753899583021, 4.598232793833491, 2.6215815162575646,
3.4227134835783364, 0.28254151584552023, 4.2548151473817075]
q = Array.create('q', N, 'BINARY')
H = sum(numbers[i] * q[i] for i in range(N)) + 5.0 * (sum(q) - K)**2
model = H.compile()
Q, offset = model.to_qubo(index_label=True)
# BQM from QUBO:
bqm = dimod.BinaryQuadraticModel.from_qubo(Q, offset)
# sample on Dynex:
model = dynex.BQM(bqm);
sampler = dynex.DynexSampler(model, mainnet=False, description='Dynex SDK test');
sampleset = sampler.sample(num_reads=10000, annealing_time = 1000, debugging=False);
print('Result:',sampleset)
Which generates the following output:
[DYNEX] MODEL CONVERTED TO QUBO
[DYNEX] PRECISION SET TO 0.001
[DYNEX] QUBO: Constant offset of the binary quadratic model: 45.0
[DYNEX] SAMPLER INITIALISED
[DYNEX|TESTNET] *** WAITING FOR READS ***
โญโโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโฎ
โ DYNEXJOB โ ELAPSED โ WORKERS โ CHIPS โ โ โ STEPS โ LOC โ โ โ ENERGY โ โ โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโค
โ -1 โ 0.00 โ 1 โ 0 โ 10000 โ 1000 โ 0 โ 14 โ 0 โ 290466.00 โ
โฐโโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโฏ
โญโโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโฎ
โ DYNEXJOB โ ELAPSED โ WORKERS โ CHIPS โ โ โ STEPS โ LOC โ โ โ ENERGY โ โ โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโค
โ -1 โ 0.00 โ 1 โ 0 โ 10000 โ 1000 โ 0 โ 14 โ 0 โ 290466.00 โ
โฐโโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโฏ
[DYNEX] FINISHED READ AFTER 0.00 SECONDS
[DYNEX] SAMPLESET READY
Result:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 energy num_oc.
0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 2.091336 1
['BINARY', 1 rows, 1 samples, 15 variables]
Sampling on the Dynex Platform (mainnet)
The following example creates a simple problem and samples it locally using the Dynex Platform:
import dynex
import dimod
from pyqubo import Array
# Define the QUBO problem:
N = 15
K = 3
numbers = [4.8097315016016315, 4.325157567810298, 2.9877429101815127,
3.199880179616316, 0.5787939511978596, 1.2520928214246918,
2.262867466401502, 1.2300003067401255, 2.1601079352817925,
3.63753899583021, 4.598232793833491, 2.6215815162575646,
3.4227134835783364, 0.28254151584552023, 4.2548151473817075]
q = Array.create('q', N, 'BINARY')
H = sum(numbers[i] * q[i] for i in range(N)) + 5.0 * (sum(q) - K)**2
model = H.compile()
Q, offset = model.to_qubo(index_label=True)
# BQM from QUBO:
bqm = dimod.BinaryQuadraticModel.from_qubo(Q, offset)
# sample on Dynex:
model = dynex.BQM(bqm);
sampler = dynex.DynexSampler(model, mainnet=True, description='Dynex SDK test');
sampleset = sampler.sample(num_reads=10000, annealing_time = 1000, debugging=False);
print('Result:',sampleset)
Which generates the following output:
โญโโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฎ
โ DYNEXJOB โ ELAPSED โ WORKERS โ CHIPS โ โ โ STEPS โ LOC โ โ โ ENERGY โ โ โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโค
โ 3628 โ 0.10 โ 2 โ 39952 โ 19984 โ 1000 โ 14 โ 14 โ 290466.00 โ 290466.00 โ
โฐโโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโฏ
โญโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโฎ
โ WORKER โ VERSION โ CHIPS โ LOC โ ENERGY โ RUNTIME โ LAST UPDATE โ STATUS โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 97931927 โ 2.3.0.OZM.122 โ 9984 โ 14 โ 290466.00 โ 0.07 min โ 5.00s ago โ STOPPED โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 97931931 โ 2.3.0.OZM.121 โ 9984 โ 14 โ 290466.00 โ 0.02 min โ 8.00s ago โ STOPPED โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 97932007 โ 2.3.0.OZM.120 โ 10000 โ 14 โ 290466.00 โ 0.02 min โ 6.00s ago โ STOPPED โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ 97931969 โ 2.3.0.OZM.122 โ 9984 โ 14 โ 290466.00 โ 0.05 min โ 4.00s ago โ STOPPED โ
โฐโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโฏ
[DYNEX] FINISHED READ AFTER 0.10 SECONDS
[DYNEX] COMPUTING FILE 2c9d94f3233be134799e45ff8be57e5c.bin REMOVED
[DYNEX] SAMPLESET READY
[DYNEX] MALLOB: JOB UPDATED: 3628 STATUS: 2
Result:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 energy num_oc.
0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 2.091336 1
['BINARY', 1 rows, 1 samples, 15 variables]
Sampling Result
The returned value is a class:dimod.SampleSet compatible object:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 energy num_oc.
0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 2.091336 1
['BINARY', 1 rows, 1 samples, 15 variables]
The SampleSet class contains the following parameters:
-
record (numpy.recarray) โ A NumPy record array. Must have โsampleโ, โenergyโ and โnum_occurrencesโ as fields. The โsampleโ field should be a 2D NumPy array where each row is a sample and each column represents the value of a variable.
-
variables (iterable) โ An iterable of variable labels, corresponding to columns in record.samples.
-
info (dict) โ Information about the SampleSet as a whole, formatted as a dict.
-
vartype (Vartype/str/set) โ Variable type for the SampleSet. Accepted input values:
- Vartype.SPIN, 'SPIN', {-1, 1}
- Vartype.BINARY, 'BINARY', {0, 1}
- ExtendedVartype.DISCRETE, 'DISCRETE'
The SampleSet class supports the following properties:
- SampleSet.first | Sample with the lowest-energy.
- SampleSet.info | Dict of information about the SampleSet as a whole.
- SampleSet.record | numpy.recarray containing the samples, energies, number of occurrences, and other sample data.
- SampleSet.variables | Variables of variable labels.
- SampleSet.vartype | Vartype of the samples.
The SampleSet class supports the following methods:
- SampleSet.aggregate() | Create a new SampleSet with repeated samples aggregated.
- SampleSet.append_variables(samples_like[, ...]) | Deprecated in favor of dimod.append_variables.
- SampleSet.change_vartype(vartype[, ...]) | Return the SampleSet with the given vartype.
- SampleSet.copy() | Create a shallow copy.
- SampleSet.data([fields, sorted_by, name, ...]) | Iterate over the data in the SampleSet.
- SampleSet.done() | Return True if a pending computation is done.
- SampleSet.filter(pred) | Return a new sampleset with rows filtered by the given predicate.
- SampleSet.from_future(future[, result_hook]) | Construct a SampleSet referencing the result of a future computation.
- SampleSet.from_samples(samples_like, ...[, ...]) | Build a SampleSet from raw samples.
- SampleSet.from_samples_bqm(samples_like, ...) | Build a sample set from raw samples and a binary quadratic model.
- SampleSet.from_samples_cqm(samples_like, cqm) | Build a sample set from raw samples and a constrained quadratic model.
- SampleSet.from_serializable(obj) | Deserialize a SampleSet.
- SampleSet.lowest([rtol, atol]) | Return a sample set containing the lowest-energy samples.
- SampleSet.resolve() | Ensure that the sampleset is resolved if constructed from a future.
- SampleSet.relabel_variables(mapping[, inplace]) | Relabel the variables of a SampleSet according to the specified mapping.
- SampleSet.samples([n, sorted_by]) | Return an iterable over the samples.
- SampleSet.slice(*slice_args, **kwargs) | Create a new sample set with rows sliced according to standard Python slicing syntax.
- SampleSet.to_pandas_dataframe([sample_column]) | Convert a sample set to a Pandas DataFrame.
- SampleSet.to_serializable([use_bytes, ...]) | Convert a SampleSet to a serializable object.
- SampleSet.truncate(n[, sorted_by]) | Create a new sample set with up to n rows.
The SampleSet class includes the following utility functions:
- append_data_vectors(sampleset, **vectors) | Create a new SampleSet with additional fields in SampleSet.record.
- append_variables(sampleset, samples_like[, ...]) | Create a new SampleSet with the given variables and values.
- concatenate(samplesets[, defaults]) | Combine sample sets.
- drop_variables(sampleset, variables) | Return a new sample set with the given variables removed.
- keep_variables(sampleset, variables) | Return a new sample set with only the given variables.
Visualisation of the SampleSet:
The following code visualised a histogram of the returned SampleSet:
import matplotlib.pyplot as plt
import numpy as np
# generate data:
data = np.zeros(len(sampleset.variables))
for s in sampleset.record: #s[0] samples [1] energy [2] num_oc
for i in range(0,len(s[0])):
data[i] += ( s[0][i] * s[2] ); # weighted by num_oc
plt.bar(sampleset.variables, data)
plt.bar(sampleset.variables, sampleset.first.sample.values())
plt.xlabel("Variables")
plt.ylabel("Occurences (positive)")
plt.title("Sampleset (orange: lowest ground state)")
plt.show()
Sampling Parameters
num_reads (Default: 32)
To be consistent with parameters used on Quantum computers, the value num_reads defines the number states (output solutions) to read. Neuromorphic computations are being performed on the Dynex Platform by converting the Ising/QUBO problem into an individual circuit ("Dynex Chip") which is then being run on the contributing GPUs by ODE integration. The parameter num_reads defines how many Dynex Chips will be utilised to find the lowest energy state of the problem.
- positive integer value > 0
annealing_time (Default: 10)
The parameter 'annealing_time' defines the duration of the computing process in number of integration steps. Longer annealing_time values lead to longer computation times, but to lower energy states of the solutions. Samples are being read only after the number of integration steps has been reached. During the sampling process you can follow the progress (number of Dynex chips, energy levels and number of soft falsified clauses) in the Python console.
- Positive integer value > 0
clones (Default: 1)
Defines the number of clones being used for sampling. Default value is 1 which means that no clones are being sampled. Especially when all requested num_reads will fit on one worker, it is desired to also retrieve the optimum ground states found from more than just one worker. The number of clones runs the sampler for n clones in parallel and aggregates the samples. This ensures a broader spectrum of retrieved samples. Please note, it the number of clones is set higher than the number of available threads on your local machine, then the number of clones processed in parallel is being processed in batches. Clone sampling is only available when sampling on the mainnet.
- Integer value in the range of [1,128]
Alpha, Beta, Gamma, Delta, Epsilon, Zeta (Default: 0)
The Ising/QUBO samplers of the Dynex platform are automatically finding the best values for the ODE integration's fixed parameters. The search space for these parameters can be limited to an upper bound which can be defined with these variables. For more details on the equations of motions of the Ising/QUBO sampling process, we refer to the latest DynexSolve white paper.
- Values are double precision (fp64) in range [0..1]
minimum_stepsize (Default: 0.00000006)
The Ising/QUBO samplers of the Dynex platform are performing ODE integration with an adaptive stepsize model, determining the optimal step of each forward Euler integration step. The minimum_stepsize parameter defines the lowest step being taken in consideration. Depending on the problem to be computed, sometimes it is not necessary to perform adaptive steps with such precision. In this case, the minumum_stepsize can be defined individually.
- Value is double precision (fp64)
debugging (Default: False)
This parameter is only applied when in local mode. It allows detailed logging from the local sampler.
block_fee (Default: 0)
Computing jobs on the Dynex platform are being prioritised by the block fee which is being offered for computation. If this parameter is not specified, the current average block fee on the platform is being charged. To set an individual block fee for the sampling, specify this parameter, which is the amount of DNX in nanoDNX (1 DNX = 1,000,000,000 nanoDNX)