Source code for qlauncher.hampy.debug

  1"""Module with functionalities for debugging Hamiltonians and checking their boolean properties"""
  2
  3from itertools import product
  4
  5import matplotlib.pyplot as plt
  6import numpy as np
  7from qiskit.quantum_info import SparsePauliOp
  8
  9from qlauncher.hampy.object import Equation
 10
 11
[docs] 12class TruthTable: 13 """ 14 Generates and analyzes a full truth table for a Hamiltonian represented as 15 either an :class:`Equation` or a :class:`qiskit.quantum_info.SparsePauliOp`. 16 17 The class evaluates the Hamiltonian on all possible bitstrings of length 18 ``size`` and exposes utilities for debugging, visualizing value 19 distributions, and checking boolean properties (e.g., whether the 20 Hamiltonian is binary-valued). 21 22 Parameters 23 ---------- 24 equation : Equation or SparsePauliOp 25 Hamiltonian to evaluate. If an :class:`Equation` is provided, its 26 simplified SparsePauliOp is used. If a SparsePauliOp is provided, 27 the number of qubits is inferred. 28 return_int : bool, optional 29 Whether to cast diagonal values to integers. Defaults to ``True``. 30 31 Examples 32 -------- 33 From an Equation: 34 >>> eq = Equation(2) 35 >>> x0, x1 = eq[0], eq[1] 36 >>> tt = TruthTable(x0 ^ x1) 37 >>> tt.truth_table 38 {'00': 0, '01': 1, '10': 1, '11': 0} 39 40 From a SparsePauliOp: 41 >>> from qiskit.quantum_info import SparsePauliOp 42 >>> H = SparsePauliOp.from_sparse_list([('Z', [0], 1.0)], 1) 43 >>> tt = TruthTable(H) 44 >>> tt['0'], tt['1'] 45 (1, -1) 46 47 Get solutions for a given value: 48 >>> tt.get_solutions(tt.lowest_value) 49 ['1'] 50 51 Check if the Hamiltonian is binary-valued: 52 >>> tt.check_if_binary() # Hamiltonian is binary if all energy values ar either 0 or 1 53 False 54 55 Plot the distribution of output energies: 56 >>> tt.plot_distribution() 57 58 Access row by integer or bitstring: 59 >>> tt[0] 60 1 61 >>> tt['1'] 62 -1 63 """ 64 65 def __init__(self, equation: Equation | SparsePauliOp, return_int: bool = True): 66 if isinstance(equation, SparsePauliOp): 67 hamiltonian = equation 68 size = hamiltonian.num_qubits 69 if not isinstance(size, int): 70 raise TypeError('Cannot read number of qubits from provided SparsePauliOp') 71 elif isinstance(equation, Equation): 72 hamiltonian = equation.hamiltonian 73 size = equation.size 74 self.size = size 75 self.return_int = return_int 76 self.truth_table = self._ham_to_truth(hamiltonian) 77 self.lowest_value = min(self.truth_table.values()) 78
[docs] 79 def count(self, value: int) -> int: 80 return list(self.truth_table.values()).count(value)
81
[docs] 82 def get_solutions(self, value: int) -> list[str]: 83 return list(filter(lambda x: self.truth_table[x] == value, self.truth_table.keys()))
84
[docs] 85 def count_min_value_solutions(self) -> int: 86 return self.count(self.lowest_value)
87
[docs] 88 def get_min_value_solutions(self) -> list[str]: 89 return self.get_solutions(self.lowest_value)
90
[docs] 91 def check_if_binary(self) -> bool: 92 return all((value == 0 or value == 1) for value in self.truth_table.values())
93
[docs] 94 def plot_distribution(self) -> None: 95 values = list(self.truth_table.values()) 96 counts, bins = np.histogram(values, max(values) + 1) 97 plt.stairs(counts, bins) 98 plt.show()
99 100 def _ham_to_truth(self, hamiltonian: SparsePauliOp) -> dict[str, int]: 101 return { 102 ''.join(reversed(bitstring)): value 103 for bitstring, value in zip( 104 product(('0', '1'), repeat=self.size), 105 (int(x.real) for x in hamiltonian.to_matrix().diagonal()) if self.return_int else hamiltonian.to_matrix().diagonal(), 106 strict=True, 107 ) 108 } 109 110 def __getitem__(self, index: str | int): 111 if isinstance(index, int): 112 index = bin(index)[2:].zfill(self.size) 113 return self.truth_table[index]