qemcmc ====== .. py:module:: qemcmc Submodules ---------- .. toctree:: :maxdepth: 1 /api/qemcmc/circuits/index /api/qemcmc/coarse_grain/index /api/qemcmc/main/index /api/qemcmc/model/index /api/qemcmc/sampler/index /api/qemcmc/spectralgap/index /api/qemcmc/utils/index Classes ------- .. autoapisummary:: qemcmc.Proposal qemcmc.ClassicalProposal qemcmc.QeProposal qemcmc.EnergyModel qemcmc.ConstraintModel qemcmc.ModelMaker qemcmc.CircuitMaker qemcmc.MCMCState qemcmc.MCMCChain qemcmc.SpectralGap qemcmc.CoarseGraining Functions --------- .. autoapisummary:: qemcmc.plot_chains qemcmc.get_random_state qemcmc.get_all_possible_states Package Contents ---------------- .. py:class:: Proposal(model: qemcmc.model.EnergyModel) Bases: :py:obj:`abc.ABC` Abstract base class for producing proposals for Markov Chain Monte Carlo algorithms. Subclasses implement the proposal mechanism by defining an ``update(state)`` method that generates a candidate state from the current one (e.g. single-spin flips, block updates, or quantum proposals). :param model: Energy model defining the target distribution over spin configurations. :type model: EnergyModel .. py:attribute:: model .. py:attribute:: n_spins .. py:method:: update(state: qemcmc.utils.MCMCState) -> qemcmc.utils.MCMCState :abstractmethod: Generate a candidate state from the current state using the proposal mechanism. This method should be implemented by subclasses to define the specific proposal strategy (e.g., single-spin flips, block updates, or quantum proposals). :param state: The current state of the Markov chain. :type state: MCMCState :returns: A new candidate state. :rtype: MCMCState .. py:class:: ClassicalProposal(model: qemcmc.model.EnergyModel, method: str = 'uniform') Bases: :py:obj:`qemcmc.sampler.Proposal` Classical Markov Chain Monte Carlo proposer. This class implements purely classical proposal mechanisms for MCMC. New candidate states are generated either by sampling a completely random (uniform) configuration, or by performing a local single-spin or two-spin flip. :param model: Energy model defining the target Boltzmann distribution. :type model: EnergyModel :param method: Proposal mechanism used to generate candidate states. - ``"uniform"`` : propose a completely random spin configuration. - ``"local"`` : flip a single randomly chosen spin. - ``"2-local"`` : flip two randomly chosen spins. Default is ``"uniform"``. :type method: str, optional .. py:attribute:: METHODS .. py:attribute:: method :value: 'uniform' .. py:method:: update(current_state_bitstring: str) -> str Generate a candidate state from the current state using the proposal mechanism. This method should be implemented by subclasses to define the specific proposal strategy (e.g., single-spin flips, block updates, or quantum proposals). :param state: The current state of the Markov chain. :type state: MCMCState :returns: A new candidate state. :rtype: MCMCState .. py:method:: update_uniform(current_state_bitstring: str) -> str Proposes a new state by generating a random bitstring. :param current_state_bitstring: The current state represented as a bitstring (not used, but required by the API). :type current_state_bitstring: str :returns: A new random state bitstring of the same length. :rtype: str .. py:method:: update_local(current_state_bitstring: str) -> str Proposes a new state by flipping a single randomly chosen spin. :param current_state_bitstring: The current state represented as a bitstring. :type current_state_bitstring: str :returns: The new state bitstring after flipping one spin. :rtype: str .. py:method:: update_2local(current_state_bitstring: str) -> str Proposes a new state by flipping two randomly chosen spins. :param current_state_bitstring: The current state represented as a bitstring. :type current_state_bitstring: str :returns: The new state bitstring after flipping two spins. :rtype: str .. py:class:: QeProposal(model: qemcmc.model.EnergyModel, gamma: float | tuple[float, float], time: float | tuple[float, float], r: Optional[int] = None, delta_t: Optional[float] = None, coarse_graining: Optional[qemcmc.coarse_grain.CoarseGraining] = None, coupling_weights: Optional[list[float | tuple[float, float]]] = None, m: int = 1) Bases: :py:obj:`qemcmc.sampler.Proposal` Quantum-enhanced Markov Chain Monte Carlo sampler. This class implements the proposal mechanism of the quantum-enhanced MCMC algorithm. Candidate states are generated by simulating the quantum time evolution of a transverse-field Hamiltonian. The quantum proposal circuit is constructed using :class:`CircuitMaker` and can optionally operate on coarse-grained subgroups of spins to improve scalability. :param model: Energy model defining the target Boltzmann distribution. :type model: EnergyModel :param gamma: Transverse field strength (Γ). If a tuple is provided, a value is sampled uniformly from the range [min, max] at each step. :type gamma: float | tuple[float, float] :param time: Total evolution time. If a tuple is provided, a value is sampled uniformly from the range [min, max] at each step. :type time: float | tuple[float, float] :param r: Number of Trotter steps. Mutually exclusive with ``delta_t``. If provided, the Trotter step size is derived as Δt = t / r and ``r`` stays fixed while Δt varies with ``t``. A warning is issued at init if the resulting Δt range falls outside [0.1, 2.0]. By default ``None``. :type r: int | None, optional :param delta_t: Trotter step size. Mutually exclusive with ``r``. If provided, the number of Trotter steps is derived as r = floor(t / Δt) per step, so ``r`` varies with ``t`` while Δt stays fixed. A warning is issued if Δt falls outside [0.1, 2.0]. By default ``None``. :type delta_t: float | None, optional :param coarse_graining: A coarse-graining scheme to define spin subgroups. If None, no coarse-graining is used. By default ``None``. :type coarse_graining: CoarseGraining | None, optional :param coupling_weights: Weights for the coupling tensors. If a tuple is provided, a weight is sampled uniformly from the range. This allows for dynamic adjustment of the influence of different terms in the Hamiltonian during the proposal step. By default ``None``. Note that this is further adjusted by (1 - gamma) to balance the influence of the problem Hamiltonian with the mixer term. Divide by (1 - gamma) if needed. Also, note that the coupling weights should include the mixing term. :type coupling_weights: list[float | tuple[float, float]] | None, optional :param m: Number of subgroups to partition the spins into for sequential updates. By default ``1``. :type m: int, optional .. rubric:: Notes The proposal step simulates the time evolution under a transverse-field Hamiltonian defined by the energy model and measures the resulting state to produce a candidate configuration. This proposal is then accepted or rejected using the Metropolis criterion to ensure convergence to the target Boltzmann distribution. Exactly one of ``r`` or ``delta_t`` should be passed in as an argument. If neither is given, a default Δt of 0.8 is used. .. py:attribute:: gamma .. py:attribute:: time .. py:attribute:: r :value: None .. py:attribute:: delta_t :value: None .. py:attribute:: m :value: 1 .. py:attribute:: method :value: 'quantum' .. py:attribute:: CM .. py:attribute:: cg .. py:method:: update(current_state: str) -> str Perform 'm' sequential quantum updates across non-overlapping subgroups. :param current_state: Current state of the system as a bitstring. :type current_state: str :returns: Updated state of the system as a bitstring. :rtype: str .. py:method:: sample_hyperparams() -> tuple[list[float], float, float, int] Sample hyperparameters (coupling weights, gamma, time, r) for the current proposal step. :returns: (final_coupling_weights, gamma, time, r) for this proposal step. :rtype: tuple[list[float], float, float, int] .. py:method:: _validate_gamma(gamma: float | tuple[float, float]) -> float | tuple[float, float] Validate the weight parameter gamma. .. py:method:: _validate_time(time: float | tuple[float, float]) -> float | tuple[float, float] Validate the total evolution time parameter. .. py:method:: _validate_r(r: Optional[int]) -> Optional[int] Validate the number of Trotter steps 'r'. .. py:method:: _validate_delta_t(delta_t: Optional[float]) -> Optional[float] Validate the Trotter step size 'delta_t'. .. py:method:: _validate_trotter_params() Check mutual exclusivity of r and delta_t, and warn if resulting Trotter step size falls outside [0.1, 2.0]. .. py:class:: EnergyModel(n: int, couplings: List[numpy.ndarray] = [], name: str = None, cost_function_signs: list = [-1, -1], model_type: str = 'ising') A base class for energy models for a classical energy function over n spins, defined by arbitrary-order coupling tensors. :param n: Number of spins :param couplings: List of numpy arrays representing interaction tensors. A 1D array encodes linear terms, a 2D array encodes pairwise terms (expected symmetric), and higher-rank tensors encode higher-order interactions. :param name: Optional label for the model (used in plotting / logging). :param cost_function_signs: Sign convention(s) used by downstream components (e.g. proposal/acceptance conventions). For example, `[-1, -1]` for linear and quadratic terms. :param model_type: Type of model, either 'ising' or 'binary'. This determines how the binary states are interpreted and how the energy is calculated. 'ising' models use spin values {-1, +1}, while 'binary' models use binary values {0, 1}. :type model_type: str .. rubric:: Notes - Energies are computed by mapping binary states ``{0,1}`` to spin values ``{-1,+1}`` internally. - Brute-force methods such as ``get_all_energies`` scale as O(2^n) and are intended only for small systems. .. py:attribute:: n .. py:attribute:: n_spins .. py:attribute:: couplings :value: [] .. py:attribute:: name :value: None .. py:attribute:: alphas .. py:attribute:: lowest_energy :value: None .. py:attribute:: normalised_couplings .. py:attribute:: cost_function_signs .. py:attribute:: initial_state :value: [] .. py:method:: get_initial_states(num_initial_states: int) Generates a list of random initial states. :param num_initial_states: The number of initial states to generate. :returns: A list of random initial states. :rtype: list .. py:method:: get_ground_state(num_reads=100, num_batches=10) Finds an approximate ground state using Simulated Annealing. .. py:method:: calculate_energy(state, couplings, cost_function_signs) Calculate the energy of a given state for an arbitrary-order Ising/binary model. :param state: State configuration. Can be: - Binary: "011", [0,1,1], (0,1,1), etc. - Spin: [-1,1,1], (-1,1,1), etc. :type state: array-like (str, list, tuple, np.array) :param couplings: List of coupling tensors where: - 1D arrays represent linear terms (h_i) - 2D arrays represent quadratic terms (J_ij) - 3D arrays represent cubic terms, etc. :type couplings: list of numpy arrays :returns: **float** :rtype: Total energy of the state .. py:method:: get_subgroup_couplings(subgroup: List[int], current_state: str, coupling_weights: List[float] = None) Calculates local couplings for a subgroup of spins. Spins outside the specified subgroup are treated as frozen constants, and their values are absorbed into the couplings of the subgroup. This is useful for calculating local effective Hamiltonians. :param subgroup: A list of indices of the spins in the subgroup. :type subgroup: List[int] :param current_state: The current state of the full system, as a binary string. :type current_state: str :param coupling_weights: Optional weights for the couplings. This can be used to effectively remove certain couplings from the proposal (e.g., constraints) by setting their weight to 0. It is important not to normalize the couplings after applying these weights. :type coupling_weights: List[float], optional :returns: A new list of coupling tensors for the subgroup. :rtype: List[np.ndarray] .. rubric:: Notes It might seem off to do the reweighting at this point, but here are reasons why I [SF] did it! Basically, when you get the subgroup couplings, the terms jumble up, so the returned local coupling list necessarily does not respect the order etc. of the different terms in the original. .. py:method:: calculate_alpha(n: int, couplings: list = None, eps: float = 1e-15) -> numpy.ndarray Compute alpha = sqrt(n) / sqrt(sum of squares of UNIQUE coupling coefficients), assuming coupling tensors are symmetric representations. Any non-symmetric 2-body input raises ValueError. :param n: Number of spins. :type n: int :param couplings: Couplings to use. Defaults to self.couplings if not provided. :type couplings: list[np.ndarray], optional :param eps: Small threshold to avoid division by zero. :type eps: float :returns: An array of normalising factors for each term in the couplings list. :rtype: np.ndarray .. py:method:: get_energy(state: str) -> float Returns the energy of a given state .. py:method:: get_all_energies() -> numpy.ndarray Calculate the energies for all possible spin states. This method generates all possible spin states for the system and calculates the energy for each state. :returns: An array containing the energies of all possible spin states. :rtype: np.ndarray .. py:method:: get_lowest_energies(num_states: int, return_configurations: bool = False) -> Tuple[numpy.ndarray, numpy.ndarray] Retrieve the lowest energy states and their degeneracies. This method computes all possible energies and then finds the specified number of lowest energy states along with their degeneracies. :param num_states (int): :type num_states (int): The number of lowest energy states to retrieve. :param return_configurations (bool): :type return_configurations (bool): Whether to also return the corresponding configurations of the lowest energy states. Defaults to False. :returns: - The first array contains the lowest energy values. - The second array contains the degeneracies of the corresponding energy values. :rtype: Tuple[np.ndarray, np.ndarray] .. rubric:: Notes This method is intended for small instances due to its brute-force nature, which is extremely memory intensive and slow. .. py:method:: find_lowest_values(arr: numpy.ndarray, num_values: int = 5) Find the lowest unique values in an array and their degeneracies. :param arr (np.ndarray): :type arr (np.ndarray): The input array from which to find the lowest values. :param num_values (int: :type num_values (int: The number of lowest unique values to find. Defaults to 5. :param optional): :type optional): The number of lowest unique values to find. Defaults to 5. :returns: - lowest_values (np.ndarray): The lowest unique values in the array. - degeneracy (np.ndarray): The counts of each of the lowest unique values. :rtype: Tuple[lowest_values (np.ndarray), degeneracy (np.ndarray)] .. py:method:: get_lowest_energy() Calculate and return the lowest energy from all possible energies. This method uses a brute force approach to find the lowest energy, making it extremely memory intensive and slow. It is recommended to use this method only for small instances. :returns: **float** :rtype: The lowest energy value. .. rubric:: Notes If the lowest energy has already been calculated and stored in `self.lowest_energy`, it will return that value directly to save computation time. .. py:method:: get_boltzmann_factor(state: str, beta: float = 1.0) -> float Get un-normalised boltzmann probability of a given state :param state: configuration of spins for which probability is to be calculated :type state: str :param beta: inverse temperature (1/T) at which the probability is to be calculated. :type beta: float :rtype: float corresponding to the un-normalised boltzmann probability of the given state. .. py:method:: get_boltzmann_factor_from_energy(E, beta: float = 1.0) -> float Get un-normalized Boltzmann probability for a given energy. :param E: Energy for which the Boltzmann factor is to be calculated. :type E: float :param beta: Inverse temperature (1/T) at which the probability is to be calculated. :type beta: float :returns: The un-normalized Boltzmann probability for the given energy. :rtype: float .. py:class:: ConstraintModel(n: int, constraint_couplings: list[numpy.ndarray], constraint_signs: list[float], couplings: list[numpy.ndarray], constraint_func: Callable[[str], bool], **kwargs) Bases: :py:obj:`qemcmc.model.energy_model.EnergyModel` A subclass of EnergyModel that incorporates a constraint function to define valid configurations. The constraint function takes a state as input and returns True if the state is valid (satisfies the constraint) and False otherwise. The energy of invalid states is set to infinity, effectively excluding them from the Boltzmann distribution. :param n: Number of spins in the model. :type n: int :param constraint_couplings: List of coupling tensors (numpy arrays) defining the constraint. :type constraint_couplings: list[np.ndarray] :param constraint_signs: Sign convention(s) for the constraint couplings. :type constraint_signs: list[float] :param couplings: List of coupling tensors (numpy arrays) defining the energy function. :type couplings: list[np.ndarray] :param constraint_func: A function that takes a state (string representation of spin configuration) and returns True if the state satisfies the constraint, and False otherwise. :type constraint_func: typing.Callable[[str], bool] :param name: Optional label for the model (used in plotting / logging). :type name: str, optional :param cost_function_signs: Sign convention(s) used by downstream components (e.g. proposal/acceptance conventions). :type cost_function_signs: list[float], optional :param model_type: Type of model, either 'ising' or 'binary'. This determines how the binary states are interpreted and how the energy is calculated. 'ising' models use spin values {-1, +1}, while 'binary' models use binary values {0, 1}. :type model_type: str, optional .. rubric:: Notes - The energy of any state that does not satisfy the constraint is set to infinity, which means such states will have zero probability in the Boltzmann distribution. - This class can be used to model systems with hard constraints on the configurations, such as certain combinatorial optimization problems or physical systems with forbidden states. .. py:attribute:: constraint_func .. py:attribute:: get_initial_states Generates a list of random initial states. :param num_initial_states: The number of initial states to generate. :returns: A list of random initial states. :rtype: list .. py:attribute:: constraint_couplings .. py:attribute:: constraint_signs .. py:attribute:: constraint_coupling_alphas .. py:attribute:: normalised_couplings .. py:attribute:: total_couplings .. py:method:: get_initial_states_constraint(num_initial_states: int) Generates a list of random initial states that satisfy the constraint function. :param num_initial_states: The number of initial states to generate. :returns: A list of random initial states that are valid according to the constraint. :rtype: list .. py:method:: get_constraint_energy(state: str) -> float Calculate the energy contribution from the constraint couplings for a given state. :param state: The state for which to calculate the constraint energy. :type state: str :returns: The energy contribution from the constraint couplings for the given state. :rtype: float .. py:method:: get_total_energy(state: str) -> float Calculate the total energy of a given state, including both the regular energy and the constraint energy. :param state: The state for which to calculate the total energy. :type state: str :returns: The total energy of the given state, including contributions from both the regular couplings and the constraint couplings. :rtype: float .. py:class:: ModelMaker(n_spins: int, model_type: str, name: str, cost_function_signs: list = [-1, -1]) Utility class for constructing standard Ising energy models used in simulations and experiments. This class constructs predefined random energy models used for testing and experimentation. Depending on the chosen ``model_type``, it generates coupling tensors and initialises an :class:`EnergyModel` instance. .. py:attribute:: name .. py:attribute:: n_spins .. py:attribute:: cost_function_signs .. py:method:: make_fully_connected_ising() .. py:method:: make_fully_connected_binary() Transforms the existing Ising couplings into an mathematically equivalent QUBO model via s = 2x - 1. .. py:class:: CircuitMaker(model: qemcmc.model.energy_model.EnergyModel) Constructs and simulates quantum circuits used to generate QeMCMC proposals. This class builds the Hamiltonian corresponding to a given energy model and simulates its time evolution using PennyLane. Starting from a classical bitstring configuration, the circuit performs Trotterised quantum evolution and samples a new configuration from the resulting quantum state. The generated sample serves as the proposal state in the quantum-enhanced MCMC algorithm. :param model: Energy model defining the problem Hamiltonian. :type model: EnergyModel .. rubric:: Notes The total Hamiltonian simulated by the circuit is ``H = γ H_mixer + (1 - γ) α H_problem`` where ``H_problem`` encodes the classical energy model and ``H_mixer`` corresponds to a transverse-field term. The evolution time ``t`` and number of Trotter steps ``r`` are passed per call, giving an effective Trotter step size of ``δt = t / r``. The evolution is approximated using Trotterisation via ``qml.ApproxTimeEvolution``. .. py:attribute:: model .. py:attribute:: n_qubits .. py:attribute:: dev .. py:attribute:: model_type .. py:attribute:: devices .. py:method:: _get_device(num_wires: int) Get or create a PennyLane device for the given number of wires. .. py:method:: get_problem_hamiltonian(couplings: List[numpy.ndarray], sign: int = 1) -> pennylane.Hamiltonian Construct the problem Hamiltonian from symmetric coupling tensors. This method supports both 'ising' (-1/+1) and 'binary' (0/1) models. :param couplings: A list of coupling tensors. :type couplings: List[np.ndarray] :param sign: A sign to apply to the Hamiltonian. Default is ``1``. :type sign: int, optional :returns: The problem Hamiltonian. :rtype: qml.Hamiltonian .. py:method:: get_mixer_hamiltonian(num_wires: int = None) -> pennylane.Hamiltonian Constructs the Mixer Hamiltonian: Σ X_i. This can be for the full system or a subgroup. :param num_wires: The number of wires (qubits) for the mixer. If None, uses the total number of qubits. :type num_wires: int, optional :returns: The mixer Hamiltonian. :rtype: qml.Hamiltonian .. py:method:: get_state_vector(s: str, weights: List[float], time: float, r: int, mix_weight: float) -> numpy.ndarray Evolve the initial state and return the final state vector. :param s: Input bitstring representing the initial state. :type s: str :param weights: Coefficients for the problem Hamiltonian terms. :type weights: list of float :param time: Total evolution time. :type time: float :param r: Number of Trotter steps for the approximate time evolution. :type r: int :param mix_weight: Coefficient for the mixer Hamiltonian (between 0 and 1). :type mix_weight: float :returns: The final state vector. :rtype: np.ndarray .. rubric:: Notes The total Hamiltonian simulated by the circuit is a weighted sum of the problem Hamiltonian terms and the mixer Hamiltonian: In Ferguson et al. (2025) [arXiv:2506.19538], we use gammas to weight the entire problem Hamiltonian vs the mixer vs the constraint Hamiltonian, such that the total Hamiltonian is: ``H = g_p * H_p + g_m * H_m + g_c * H_c`` but here we allow for separate weights for each coupling tensor term, as well as a separate gamma for the mixer. The total Hamiltonian is then: ``H = (w_b1*H_b1 + w_b2*H_b2 + ... + w_b2*H_bm) + g_m * H_m`` In other words, the constraint hamiltonian is absorbed in the coupling list, and weighted by the corresponding gamma in the gammas list. This allows for more flexible weighting of different terms, and also allows us to use the same code for both constrained and unconstrained problems (by simply including or excluding the constraint Hamiltonian in the coupling list and adjusting the gammas accordingly). Note that it is assumed that each term is already normalised appropriately, so the gammas can be interpreted as the relative weights of each term in the total Hamiltonian. .. py:method:: get_sample(s_cg: str, time: float, r: int, mix_weight: float, local_couplings: list, weights: List[float] = None) -> str Generate a single sample by evolving the system and measuring. :param s_cg: Input bitstring for the subgroup. :type s_cg: str :param time: Total evolution time. :type time: float :param r: Number of Trotter steps for the approximate time evolution. :type r: int :param mix_weight: Coefficient for the mixer Hamiltonian. :type mix_weight: float :param local_couplings: Coupling tensors for the subgroup. :type local_couplings: list :param weights: Coefficients for the problem Hamiltonian terms. Defaults to ones. :type weights: list of float, optional :returns: A single bitstring sample. :rtype: str .. py:method:: update(s: str, subgroup_choice: List[int], local_couplings: list, gamma: float, time: float, r: int) -> str Update a bitstring by evolving a subgroup. This performs a time evolution on a coarse-grained Hamiltonian to get s' from s. :param s: The initial bitstring. :type s: str :param subgroup_choice: Indices of the subgroup to evolve. :type subgroup_choice: list of int :param local_couplings: Coupling tensors for the subgroup. :type local_couplings: list :param gamma: Mixing parameter. :type gamma: float :param time: Evolution time. :type time: float :param r: Number of Trotter steps for the approximate time evolution. :type r: int :returns: The updated bitstring s'. :rtype: str .. py:method:: _validate_bitstring(s: str, *, length: int = None) Validate s is a bitstring. :param s: The string to validate. :type s: str :param length: The expected length of the string. :type length: int, optional :raises TypeError: If s is not a string. :raises ValueError: If s contains characters other than '0' or '1', or if its length is wrong. .. py:class:: MCMCState Represents a single step in an MCMC trajectory. Stores the proposed configuration, whether it was accepted by the Metropolis rule, its energy, and the position of the step in the chain. .. py:attribute:: bitstring :type: str .. py:attribute:: accepted :type: bool .. py:attribute:: energy :type: float :value: None .. py:attribute:: position :type: int :value: None .. py:class:: MCMCChain(states: Optional[List[MCMCState]] = None, name: Optional[str] = 'MCMC') Container for the sequence of states produced during an MCMC run. This class records all proposed states, tracks accepted configurations, and provides helper methods for extracting trajectories, energies, and empirical distributions from the Markov chain. .. py:attribute:: name :value: 'MCMC' .. py:method:: add_state(state: MCMCState) .. py:property:: states .. py:method:: get_accepted_energies() .. py:method:: get_current_energy_array() .. py:method:: get_pos_array() .. py:method:: get_current_state_array() .. py:method:: get_all_energies() .. py:property:: current_state .. py:property:: accepted_states :type: List[str] .. py:method:: get_list_markov_chain() -> List[str] .. py:method:: get_accepted_dict(normalize: bool = False, until_index: int = -1) .. py:function:: plot_chains(chains: list[MCMCChain], color: str, label: str, plot_individual_chains: bool = True) .. py:function:: get_random_state(num_spins: int) -> str Generate a random state for a given number of spins. :param num_spins: The number of spins in the system. :type num_spins: int :returns: A bitstring representing the random state. :rtype: str .. py:function:: get_all_possible_states(num_spins: int) -> list Returns all possible binary strings of length n=num_spins Paremeters: num_spins: n length of the bitstring :returns: A list of all possible binary strings of length num_spins. :rtype: list .. py:class:: SpectralGap(proposal: qemcmc.sampler.Proposal, model: qemcmc.model.energy_model.EnergyModel, temp: float = 1.0) Bases: :py:obj:`qemcmc.sampler.runners.Runner` Class that finds the spectral gap, and the acceptance and proposal matrices for a given mcmc. .. py:attribute:: proposal .. py:attribute:: model .. py:attribute:: temp :value: 1.0 .. py:method:: find_acceptance_matrix() Function to find the acceptance matrix for a given model instance. :returns: The acceptance matrix for the mcmc :rtype: A (np.ndarray) .. py:method:: find_proposal_matrix_local() Function to find the proposal matrix for a given local chain. :returns: The Q matrix for local proposal :rtype: Q (np.ndarray) .. py:method:: find_proposal_matrix_uniform() Function to find the proposal matrix for a given uniform chain. :returns: The Q matrix for uniform proposal :rtype: Q (np.ndarray) .. py:method:: find_proposal_matrix_quantum() Function to find the proposal matrix for a given QeMCMCChain object. :returns: The Q matrix for quantum proposal :rtype: Q (np.ndarray) .. py:method:: find_proposal_matrix_brute_force(multiple=100) .. py:method:: find_proposal_matrix() Function to find the proposal matrix for a given mcmc. This is not done by brute force .. py:method:: find_spectral_gap(A=None, Q=None) Function to find the spectral gap of a given mcmc. :param A (np.ndarray): The acceptance matrix for the mcmc (optional, if not given, will be calculated) :param Q (np.ndarray): The proposal matrix for the mcmc (optional, if not given, will be calculated) .. py:class:: CoarseGraining(n, subgroups=None, subgroup_probs=None, repeated=True) CoarseGraining class to generate partitions of spins for quantum proposals. :param n: Number of spins in the system. :type n: int :param subgroups: 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. :type subgroups: list[list[int]], optional :param subgroup_probs: 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. :type subgroup_probs: list[float], optional :param repeated: 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``. :type repeated: bool, optional .. py:attribute:: _user_specified .. py:attribute:: n .. py:attribute:: subgroups :value: None .. py:attribute:: subgroup_probs :value: None .. py:attribute:: repeated :value: True .. py:method:: sample() -> list[int] Randomly samples a subgroup according to the specified probability distribution. .. py:method:: get_partitions(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. :param m: The number of partitions to generate. Ignored if user-specified subgroups are provided. :type m: int