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 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
bqm = dimod.BinaryQuadraticModel.from_coo(fp) 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()
""" 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) # construct a Dialectic Search workflow generate_antithesis = (hybrid.IdentityDecomposer() | hybrid.RandomSubproblemSampler() | hybrid.SplatComposer() | hybrid.TabuProblemSampler()) generate_synthesis = (hybrid.GreedyPathMerge() | hybrid.TabuProblemSampler()) tracker = hybrid.TrackMin() local_update = hybrid.LoopWhileNoImprovement( hybrid.Parallel(hybrid.Identity(), generate_antithesis) | generate_synthesis | tracker, max_tries=10) global_update = hybrid.Loop(generate_antithesis | local_update, max_iter=10)
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)
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
chain( sorted(glob('../problems/qbsolv/bqp50_*'))[:problems_per_group], sorted(glob('../problems/qbsolv/bqp100_*'))[:problems_per_group], sorted(glob('../problems/qbsolv/bqp250_*'))[:problems_per_group], sorted(glob('../problems/qbsolv/bqp500_*'))[:problems_per_group], sorted(glob('../problems/qbsolv/bqp1000_*'))[:problems_per_group], sorted(glob('../problems/qbsolv/bqp2500_*'))[:problems_per_group], sorted(glob('../problems/random-chimera/2048*'))[:problems_per_group], 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)),