Source code for qemcmc.coarse_grain

from qemcmc.utils.helpers import validate_subgroups
import numpy as np


[docs] class CoarseGraining: """ CoarseGraining class to generate partitions of spins for quantum proposals. Parameters ---------- n : int Number of spins in the system. subgroups : list[list[int]], optional A list of subgroups, where each subgroup is a list of spin indices. If None, the entire set of spins is treated as one subgroup. subgroup_probs : list[float], optional A list of probabilities corresponding to each subgroup, used for weighted random selection. Must sum to 1. If None, subgroups are selected uniformly at random. repeated : bool, optional If True, then multiple subgroups are run on the quantum computer in serial, if not then only one subgroup is selected at random and run on the quantum computer. Default is ``True``. """ def __init__(self, n, subgroups=None, subgroup_probs=None, repeated=True):
[docs] self._user_specified = subgroups is not None
if subgroups is None: subgroups = [list(range(n))] subgroup_probs = [1.0] else: if subgroup_probs is None: subgroup_probs = [1.0 / len(subgroups)] * len(subgroups) validate_subgroups(subgroups=subgroups, subgroup_probs=subgroup_probs, n_spins=n)
[docs] self.n = n
[docs] self.subgroups = subgroups
[docs] self.subgroup_probs = subgroup_probs
[docs] self.repeated = repeated
[docs] def sample(self) -> list[int]: """ Randomly samples a subgroup according to the specified probability distribution. """ idx = np.random.choice(len(self.subgroups), p=self.subgroup_probs) return self.subgroups[idx]
[docs] def get_partitions(self, m: int) -> list[list[int]]: """ Returns partitions of spins for sequential quantum updates. If the user provided explicit subgroups at initialisation, those are returned directly (all if ``repeated=True``, otherwise just the first). If no subgroups were specified, random disjoint partitions of approximate size n/m are generated. Parameters ---------- m : int The number of partitions to generate. Ignored if user-specified subgroups are provided. """ if self._user_specified: if self.repeated: return self.subgroups else: return [self.subgroups[0]] spins = np.arange(self.n) np.random.shuffle(spins) # array_split handles uneven divisions gracefully chunks = [list(chunk) for chunk in np.array_split(spins, m)] if self.repeated: return chunks else: return [chunks[0]]