qemcmc.circuits =============== .. py:module:: qemcmc.circuits Classes ------- .. autoapisummary:: qemcmc.circuits.CircuitMaker Module Contents --------------- .. 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.