def HybridizedPopulationAnnealing(num_reads=20, num_iter=20, num_sweeps=1000): """Workflow generator for population annealing initialized with QPU samples. Args: num_reads (int): Size of the population of samples. num_iter (int): Number of temperatures over which we iterate fixed-temperature sampling / resampling. num_sweeps (int): Number of sweeps in the fixed temperature sampling step. Returns: Workflow (:class:`~hybrid.core.Runnable` instance). """ # QPU initial sampling: limits the PA workflow to QPU-sized problems qpu_init = (hybrid.IdentityDecomposer() | hybrid.QPUSubproblemAutoEmbeddingSampler(num_reads=num_reads) | hybrid.IdentityComposer()) | hybrid.AggregatedSamples(False) # PA workflow: after initial QPU sampling and initial beta schedule estimation, # we do `num_iter` steps (one per beta/temperature) of fixed-temperature # sampling / weighted resampling workflow = qpu_init | CalculateAnnealingBetaSchedule( length=num_iter) | hybrid.Loop( ProgressBetaAlongSchedule() | hybrid.FixedTemperatureSampler(num_sweeps=num_sweeps) | EnergyWeightedResampler(), max_iter=num_iter) return workflow
def SimplifiedQbsolv(max_iter=10, max_time=None, convergence=3, energy_threshold=None, max_subproblem_size=30): """Races a Tabu solver and a QPU-based sampler of flip-energy-impact induced subproblems. For arguments description see: :class:`~hybrid.reference.kerberos.Kerberos`. """ energy_reached = None if energy_threshold is not None: energy_reached = lambda en: en <= energy_threshold workflow = hybrid.Loop(hybrid.Race( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer( size=max_subproblem_size, rolling=True, rolling_history=0.15) | hybrid.QPUSubproblemAutoEmbeddingSampler() | hybrid.SplatComposer()) | hybrid.ArgMin() | hybrid.TrackMin(output=True), max_iter=max_iter, max_time=max_time, convergence=convergence, terminate=energy_reached) return workflow
def hybrid_solver(): workflow = hybrid.LoopUntilNoImprovement(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=20) | hybrid.QPUSubproblemAutoEmbeddingSampler() | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) return hybrid.HybridSampler(workflow)
def hybrid_solver(): workflow = hybrid.Loop(hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer( size=30, rolling=True, rolling_history=0.75) | hybrid.QPUSubproblemAutoEmbeddingSampler() | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=1) return hybrid.HybridSampler(workflow)
def HybridizedPopulationAnnealing(num_reads=100, num_iter=100, num_sweeps=100, beta_range=None): """Workflow generator for population annealing initialized with QPU samples. Args: num_reads (int): Size of the population of samples. num_iter (int): Number of temperatures over which we iterate fixed-temperature sampling / resampling. num_sweeps (int): Number of sweeps in the fixed temperature sampling step. beta_range (tuple[float], optional): A 2-tuple defining the beginning and end of the beta schedule, where beta is the inverse temperature. Passed to :class:`.CalculateAnnealingBetaSchedule` for linear schedule generation. Returns: Workflow (:class:`~hybrid.core.Runnable` instance). """ # QPU initial sampling: limits the PA workflow to QPU-sized problems qpu_init = (hybrid.IdentityDecomposer() | hybrid.QPUSubproblemAutoEmbeddingSampler(num_reads=num_reads) | hybrid.IdentityComposer()) | hybrid.AggregatedSamples(False) # PA workflow: after initial QPU sampling and initial beta schedule estimation, # we do `num_iter` steps (one per beta/temperature) of fixed-temperature # sampling / weighted resampling schedule_init = CalculateAnnealingBetaSchedule(length=num_iter, beta_range=beta_range, interpolation='linear') workflow = qpu_init | schedule_init | hybrid.Loop( ProgressBetaAlongSchedule() | hybrid.FixedTemperatureSampler(num_sweeps=num_sweeps) | EnergyWeightedResampler(), max_iter=num_iter) return workflow
# distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import sys import dimod import hybrid # load a problem problem = sys.argv[1] with open(problem) as fp: bqm = dimod.BinaryQuadraticModel.from_coo(fp) # define the workflow workflow = hybrid.Loop(hybrid.RacingBranches( hybrid.Identity(), hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=50, rolling=True, traversal='bfs') | hybrid.QPUSubproblemAutoEmbeddingSampler() | hybrid.SplatComposer()) | hybrid.ArgMin(), convergence=3) # create a dimod sampler that runs the workflow and sample result = hybrid.HybridSampler(workflow).sample(bqm) # show results print("Solution: sample={.first}".format(result))
print("BQM: {} nodes, {} edges, {:.2f} density".format( len(bqm), len(bqm.quadratic), hybrid.bqm_density(bqm))) # sweeps per fixed-temperature sampling step num_sweeps = 1000 # number of generations, or temperatures to progress through num_iter = 20 # population size num_samples = 20 # QPU initial sampling: limits the PA workflow to QPU-sized problems qpu_init = (hybrid.IdentityDecomposer() | hybrid.QPUSubproblemAutoEmbeddingSampler(num_reads=num_samples) | hybrid.IdentityComposer()) | hybrid.AggregatedSamples(False) # PA workflow: after initial beta schedule estimation, we do `num_iter` steps # (one per beta/temperature) of fixed-temperature sampling / weighted resampling workflow = qpu_init | CalculateAnnealingBetaSchedule( length=num_iter) | hybrid.Loop( ProgressBetaAlongSchedule() | FixedTemperatureSampler( num_sweeps=num_sweeps) | EnergyWeightedResampler(), max_iter=num_iter) # run the workflow state = hybrid.State.from_problem(bqm) solution = workflow.run(state).result() # show execution profile
for sample in sample_set.samples(): list1, list2 = split_numbers_list(numbers, sample) print "list1: {}, sum: {}, list2: {}, sum: {}".format( list1, sum(list1), list2, sum(list2)) dwave_sampler = EmbeddingComposite(DWaveSampler()) print "#" * 80 numbers = generate_numbers( 100) # generate a list of numbers to be split into equal sums bqm = to_bqm(numbers) # Redefine the workflow: a rolling decomposition window decomposer = hybrid.EnergyImpactDecomposer(size=50, rolling_history=0.15) sampler = hybrid.QPUSubproblemAutoEmbeddingSampler() composer = hybrid.SplatComposer() iteration = hybrid.RacingBranches(decomposer | sampler | composer) | hybrid.ArgMin() workflow = hybrid.LoopUntilNoImprovement(iteration, convergence=3) init_state = hybrid.State.from_problem(bqm) start = time.time() final_state = workflow.run(init_state).result() end = time.time() print "Using dwave-hybrid (elapsed time: {}s)".format(end - start) print(final_state.samples) print_result(final_state.samples)
n_sweeps = 10000 n_replicas = 10 n_iterations = 10 # replicas are initialized with random samples state = hybrid.State.from_problem(bqm) replicas = hybrid.States(*[state.updated() for _ in range(n_replicas)]) # get a reasonable beta range beta_hot, beta_cold = neal.default_beta_range(bqm) # generate betas for all branches/replicas betas = np.geomspace(beta_hot, beta_cold, n_replicas) # QPU branch: limits the PT workflow to QPU-sized problems qpu = hybrid.IdentityDecomposer() | hybrid.QPUSubproblemAutoEmbeddingSampler( ) | hybrid.IdentityComposer() # use QPU as the hottest temperature sampler and `n_replicas-1` fixed-temperature-samplers update = hybrid.Branches( qpu, *[ FixedTemperatureSampler(beta=beta, num_sweeps=n_sweeps) for beta in betas[1:] ]) # swap step is `n_replicas-1` pairwise potential swaps swap = SwapReplicasDownsweep(betas=betas) # we'll run update/swap sequence for `n_iterations` workflow = hybrid.Loop(update | swap, max_iter=n_iterations) \ | hybrid.MergeSamples(aggregate=True)
import time start_time = time.time() # Define the workflow iteration = hybrid.RacingBranches( # Runs (races) multiple workflows of type Runnable in parallel, stopping all once the first # finishes. Returns the results of all, in the specified order. hybrid.InterruptableTabuSampler( ), # Tabu algorithm seek of best solutions hybrid.EnergyImpactDecomposer( size=5 ) # Selects a subproblem of variables maximally contributing to the # problem energy. | hybrid.QPUSubproblemAutoEmbeddingSampler( ) # A quantum sampler for a subproblem with automated heuristic # minor-embedding. | hybrid.SplatComposer( ) # A composer that overwrites current samples with subproblem samples. ) | hybrid.ArgMin() # Selects the best state from a sequence of States workflow = hybrid.LoopUntilNoImprovement( iteration, convergence) # Iterates Runnable for up to max_iter times, # or until a state quality metric, defined by the key function, shows no improvement for at least convergence # number of iterations. # Solve the problem init_state = hybrid.State.from_problem(_QUBOdictionary) computation = workflow.run(init_state).result() # print execution time print('Execution time for {0} nodes: {1} milliseconds'.format(
problem = sys.argv[1] with open(problem) as fp: bqm = dimod.BinaryQuadraticModel.from_coo(fp) # define a qbsolv-like workflow def merge_substates(_, substates): a, b = substates return a.updated( subsamples=hybrid.hstack_samplesets(a.subsamples, b.subsamples)) subproblems = hybrid.Unwind( hybrid.EnergyImpactDecomposer(size=50, rolling_history=0.15)) qpu = hybrid.Map(hybrid.QPUSubproblemAutoEmbeddingSampler()) | hybrid.Reduce( hybrid.Lambda(merge_substates)) | hybrid.SplatComposer() random = hybrid.Map(hybrid.RandomSubproblemSampler()) | hybrid.Reduce( hybrid.Lambda(merge_substates)) | hybrid.SplatComposer() subsampler = hybrid.Parallel(qpu, random, endomorphic=False) | hybrid.ArgMin() iteration = hybrid.Race(hybrid.InterruptableTabuSampler(), subproblems | subsampler) | hybrid.ArgMin() main = hybrid.Loop(iteration, max_iter=10, convergence=3) # run the workflow init_state = hybrid.State.from_sample(hybrid.min_sample(bqm), bqm) solution = main.run(init_state).result()
def Kerberos(max_iter=100, max_time=None, convergence=3, energy_threshold=None, sa_reads=1, sa_sweeps=10000, tabu_timeout=500, qpu_reads=100, qpu_sampler=None, qpu_params=None, max_subproblem_size=50): """An opinionated hybrid asynchronous decomposition sampler for problems of arbitrary structure and size. Runs Tabu search, Simulated annealing and QPU subproblem sampling (for high energy impact problem variables) in parallel and returns the best samples. Kerberos workflow is used by :class:`KerberosSampler`. Termination Criteria Args: max_iter (int): Number of iterations in the hybrid algorithm. max_time (float/None, optional, default=None): Wall clock runtime termination criterion. Unlimited by default. convergence (int): Number of iterations with no improvement that terminates sampling. energy_threshold (float, optional): Terminate when this energy threshold is surpassed. Check is performed at the end of each iteration. Simulated Annealing Parameters: sa_reads (int): Number of reads in the simulated annealing branch. sa_sweeps (int): Number of sweeps in the simulated annealing branch. Tabu Search Parameters: tabu_timeout (int): Timeout for non-interruptable operation of tabu search (time in milliseconds). QPU Sampling Parameters: qpu_reads (int): Number of reads in the QPU branch. qpu_sampler (:class:`dimod.Sampler`, optional, default=DWaveSampler()): Quantum sampler such as a D-Wave system. qpu_params (dict): Dictionary of keyword arguments with values that will be used on every call of the QPU sampler. max_subproblem_size (int): Maximum size of the subproblem selected in the QPU branch. Returns: Workflow (:class:`~hybrid.core.Runnable` instance). """ energy_reached = None if energy_threshold is not None: energy_reached = lambda en: en <= energy_threshold iteration = hybrid.Race( hybrid.Identity(), hybrid.InterruptableTabuSampler(timeout=tabu_timeout), hybrid.InterruptableSimulatedAnnealingProblemSampler( num_reads=sa_reads, num_sweeps=sa_sweeps), hybrid.EnergyImpactDecomposer(size=max_subproblem_size, rolling=True, rolling_history=0.3, traversal='bfs') | hybrid.QPUSubproblemAutoEmbeddingSampler(num_reads=qpu_reads, qpu_sampler=qpu_sampler, qpu_params=qpu_params) | hybrid.SplatComposer()) | hybrid.ArgMin() workflow = hybrid.Loop(iteration, max_iter=max_iter, max_time=max_time, convergence=convergence, terminate=energy_reached) return workflow
def HybridizedParallelTempering(num_sweeps=10000, num_replicas=10, max_iter=None, max_time=None, convergence=3): """Parallel tempering workflow generator. Args: num_sweeps (int, optional): Number of sweeps in the fixed temperature sampling. num_replicas (int, optional): Number of replicas (parallel states / workflow branches). max_iter (int/None, optional): Maximum number of iterations of the update/swaps loop. max_time (int/None, optional): Maximum wall clock runtime (in seconds) allowed in the update/swaps loop. convergence (int/None, optional): Number of times best energy of the coldest replica has to repeat before we terminate. Returns: Workflow (:class:`~hybrid.core.Runnable` instance). """ # expand single input state into `num_replicas` replica states preprocess = SpawnParallelTemperingReplicas(num_replicas=num_replicas) # QPU branch: limits the PT workflow to QPU-sized problems qpu = (hybrid.IdentityDecomposer() | hybrid.QPUSubproblemAutoEmbeddingSampler() | hybrid.IdentityComposer()) # use QPU as the hottest temperature sampler and `num_replicas-1` fixed-temperature-samplers update = hybrid.Branches( qpu, *[ FixedTemperatureSampler(num_sweeps=num_sweeps) for _ in range(num_replicas - 1) ]) # replica exchange step: do the top-down sweep over adjacent pairs # (good hot samples sink to bottom) swap = SwapReplicasDownsweep() # loop termination key function def key(states): if states is not None: return states[-1].samples.first.energy # replicas update/swap until Loop termination criteria reached loop = hybrid.Loop(update | swap, max_iter=max_iter, max_time=max_time, convergence=convergence, key=key) # collapse all replicas (although the bottom one should be the best) postprocess = hybrid.MergeSamples(aggregate=True) workflow = preprocess | loop | postprocess return workflow
sorted(glob('../problems/random-chimera/8192*'))[:problems_per_group], sorted(glob('../problems/ac3/*'))[:problems_per_group], )) workflows = [ ("10s-tabu", lambda **kw: hybrid.TabuProblemSampler(timeout=10000)), ("10k-sa", lambda **kw: (hybrid.IdentityDecomposer() | hybrid.SimulatedAnnealingSubproblemSampler(sweeps=10000) | hybrid.SplatComposer())), ("qbsolv-like", lambda qpu, energy_threshold, **kw: hybrid.Loop(hybrid.Race( hybrid.InterruptableTabuSampler(timeout=200), hybrid.EnergyImpactDecomposer( size=50, rolling=True, rolling_history=0.15) | hybrid.QPUSubproblemAutoEmbeddingSampler(qpu_sampler=qpu) | hybrid.SplatComposer()) | hybrid.ArgMin(), max_iter=100, convergence=10, terminate=None if energy_threshold is None else lambda en: en <= energy_threshold)), ("tiling-chimera", lambda qpu, energy_threshold, **kw: hybrid.Loop( hybrid.Race( hybrid.InterruptableTabuSampler(timeout=200), hybrid.TilingChimeraDecomposer(size=(16, 16, 4)) | hybrid.QPUSubproblemExternalEmbeddingSampler(qpu_sampler=qpu) | hybrid.SplatComposer(), ) | hybrid.ArgMin(),
def sample(self, bqm, init_sample=None, max_iter=100, convergence=3, num_reads=1, sa_reads=1, sa_sweeps=10000, tabu_timeout=500, qpu_reads=100, qpu_sampler=None, qpu_params=None, max_subproblem_size=50, energy_threshold=None): """Run Tabu search, Simulated annealing and QPU subproblem sampling (for high energy impact problem variables) in parallel and return the best samples. Args: bqm (:obj:`~dimod.BinaryQuadraticModel`): Binary quadratic model to be sampled from. init_sample (:class:`~dimod.SampleSet`, callable, ``None``): Initial sample set (or sample generator) used for each "read". Use a random sample for each read by default. max_iter (int): Number of iterations in the hybrid algorithm. convergence (int): Number of iterations with no improvement that terminates sampling. num_reads (int): Number of reads. Each sample is the result of a single run of the hybrid algorithm. sa_reads (int): Number of reads in the simulated annealing branch. sa_sweeps (int): Number of sweeps in the simulated annealing branch. tabu_timeout (int): Timeout for non-interruptable operation of tabu search (time in milliseconds). qpu_reads (int): Number of reads in the QPU branch. qpu_sampler (:class:`dimod.Sampler`, optional, default=DWaveSampler()): Quantum sampler such as a D-Wave system. qpu_params (dict): Dictionary of keyword arguments with values that will be used on every call of the QPU sampler. max_subproblem_size (int): Maximum size of the subproblem selected in the QPU branch. energy_threshold (float, optional): Terminate when this energy threshold is surpassed. Check is performed at the end of each iteration. Returns: :obj:`~dimod.SampleSet`: A `dimod` :obj:`.~dimod.SampleSet` object. """ if callable(init_sample): init_state_gen = lambda: hybrid.State.from_sample( init_sample(), bqm) elif init_sample is None: init_state_gen = lambda: hybrid.State.from_sample( hybrid.random_sample(bqm), bqm) elif isinstance(init_sample, dimod.SampleSet): init_state_gen = lambda: hybrid.State.from_sample(init_sample, bqm) else: raise TypeError( "'init_sample' should be a SampleSet or a SampleSet generator") subproblem_size = min(len(bqm), max_subproblem_size) energy_reached = None if energy_threshold is not None: energy_reached = lambda en: en <= energy_threshold iteration = hybrid.Race( hybrid.Identity(), hybrid.InterruptableTabuSampler(timeout=tabu_timeout), hybrid.InterruptableSimulatedAnnealingProblemSampler( num_reads=sa_reads, num_sweeps=sa_sweeps), hybrid.EnergyImpactDecomposer(size=subproblem_size, rolling=True, rolling_history=0.3, traversal='bfs') | hybrid.QPUSubproblemAutoEmbeddingSampler(num_reads=qpu_reads, qpu_sampler=qpu_sampler, qpu_params=qpu_params) | hybrid.SplatComposer(), ) | hybrid.ArgMin() self.runnable = hybrid.Loop(iteration, max_iter=max_iter, convergence=convergence, terminate=energy_reached) samples = [] energies = [] for _ in range(num_reads): init_state = init_state_gen() final_state = self.runnable.run(init_state) # the best sample from each run is one "read" ss = final_state.result().samples ss.change_vartype(bqm.vartype, inplace=True) samples.append(ss.first.sample) energies.append(ss.first.energy) return dimod.SampleSet.from_samples(samples, vartype=bqm.vartype, energy=energies)
def solve(self): self.n_bins_truth = self._data.x.shape[0] self.n_bins_reco = self._data.d.shape[0] if not self._data.R.shape[1] == self.n_bins_truth: raise Exception( "Number of bins at truth level do not match between 1D spectrum (%i) and response matrix (%i)" % (self.n_bins_truth, self._data.R.shape[1])) if not self._data.R.shape[0] == self.n_bins_reco: raise Exception( "Number of bins at reco level do not match between 1D spectrum (%i) and response matrix (%i)" % (self.n_bins_reco, self._data.R.shape[0])) self.convert_to_binary() print("INFO: N bins:", self._data.x.shape[0]) print("INFO: n-bits encoding:", self.rho) print("INFO: Signal truth-level x:") print(self._data.x) print("INFO: pseudo-data b:") print(self._data.d) print("INFO: Response matrix:") print(self._data.R) self.Q = self.make_qubo_matrix() self._bqm = dimod.BinaryQuadraticModel.from_numpy_matrix(self.Q) print("INFO: solving the QUBO model (size=%i)..." % len(self._bqm)) if self.backend in [Backends.cpu]: print("INFO: running on CPU...") self._results = dimod.ExactSolver().sample(self._bqm) self._status = StatusCode.success elif self.backend in [Backends.sim]: num_reads = self.solver_parameters['num_reads'] print("INFO: running on simulated annealer (neal), num_reads=", num_reads) sampler = neal.SimulatedAnnealingSampler() self._results = sampler.sample(self._bqm, num_reads=num_reads).aggregate() self._status = StatusCode.success elif self.backend in [ Backends.qpu, Backends.qpu_hinoise, Backends.qpu_lonoise, Backends.hyb, Backends.qsolv ]: print("INFO: running on QPU") config_file = self.get_config_file() self._hardware_sampler = DWaveSampler(config_file=config_file) print("INFO: QPU configuration file:", config_file) print("INFO: finding optimal minor embedding...") n_bits_avg = np.mean(self._encoder.rho) thr = 4. / float(self.n_bins_truth) n_tries = 5 if n_bits_avg < thr else 10 J = qubo_quadratic_terms_from_np_array(self.Q) embedding = self.find_embedding(J, n_tries) print("INFO: creating DWave sampler...") sampler = FixedEmbeddingComposite(self._hardware_sampler, embedding) if self.backend in [ Backends.qpu, Backends.qpu_hinoise, Backends.qpu_lonoise ]: print("INFO: Running on QPU") params = self.solver_parameters self._results = sampler.sample(self._bqm, **params).aggregate() self._status = StatusCode.success elif self.backend in [Backends.hyb]: print("INFO: hybrid execution") import hybrid num_reads = self.solver_parameters['num_reads'] # Define the workflow # hybrid.EnergyImpactDecomposer(size=len(bqm), rolling_history=0.15) iteration = hybrid.RacingBranches( hybrid.InterruptableTabuSampler(), hybrid.EnergyImpactDecomposer(size=len(self._bqm) // 2, rolling=True) | hybrid.QPUSubproblemAutoEmbeddingSampler( num_reads=num_reads) | hybrid.SplatComposer()) | hybrid.ArgMin() #workflow = hybrid.LoopUntilNoImprovement(iteration, convergence=3) workflow = hybrid.Loop(iteration, max_iter=20, convergence=3) init_state = hybrid.State.from_problem(self._bqm) self._results = workflow.run(init_state).result().samples self._status = StatusCode.success # show execution profile print("INFO: timing:") workflow.timers hybrid.print_structure(workflow) hybrid.profiling.print_counters(workflow) elif self.backend in [Backends.qsolv]: print("INFO: using QBsolve with FixedEmbeddingComposite") self._results = QBSolv().sample_qubo(S, solver=sampler, solver_limit=5) self._status = StatusCode.success else: raise Exception("ERROR: unknown backend", self.backend) print("DEBUG: status =", self._status) return self._status