qumat 0.0.1__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
qumat/qiskit_backend.py CHANGED
@@ -15,103 +15,204 @@
15
15
  # limitations under the License.
16
16
  #
17
17
  import qiskit
18
+ from qiskit_aer import AerSimulator
19
+
18
20
 
19
21
  def initialize_backend(backend_config):
20
- backend_options = backend_config['backend_options']
21
- simulator_type = backend_options['simulator_type']
22
- shots = backend_options['shots']
23
- backend = qiskit.Aer.get_backend(simulator_type)
22
+ backend_options = backend_config["backend_options"]
23
+ simulator_type = backend_options["simulator_type"]
24
+ shots = backend_options.get("shots", 1)
25
+
26
+ # Map legacy simulator types to AerSimulator methods
27
+ simulator_methods = {
28
+ "aer_simulator": "automatic",
29
+ "statevector_simulator": "statevector",
30
+ "qasm_simulator": "automatic",
31
+ "unitary_simulator": "unitary",
32
+ }
33
+
34
+ if simulator_type in simulator_methods:
35
+ backend = AerSimulator(method=simulator_methods[simulator_type])
36
+ else:
37
+ backend = AerSimulator(method=simulator_type)
38
+
24
39
  backend.shots = shots
25
40
  return backend
26
41
 
27
42
 
28
- def create_empty_circuit(num_qubits):
29
- return qiskit.QuantumCircuit(num_qubits)
43
+ def create_empty_circuit(num_qubits: int | None = None):
44
+ if num_qubits is not None:
45
+ return qiskit.QuantumCircuit(num_qubits)
46
+ else:
47
+ return qiskit.QuantumCircuit()
48
+
30
49
 
31
50
  def apply_not_gate(circuit, qubit_index):
32
51
  # Apply a NOT gate (X gate) on the specified qubit
33
52
  circuit.x(qubit_index)
34
53
 
54
+
35
55
  def apply_hadamard_gate(circuit, qubit_index):
36
56
  # Apply a Hadamard gate on the specified qubit
37
57
  circuit.h(qubit_index)
38
58
 
59
+
39
60
  def apply_cnot_gate(circuit, control_qubit_index, target_qubit_index):
40
61
  # Apply a CNOT gate (controlled-X gate) with the specified control and
41
62
  # target qubits
42
63
  circuit.cx(control_qubit_index, target_qubit_index)
43
64
 
44
- def apply_toffoli_gate(circuit, control_qubit_index1,
45
- control_qubit_index2,
46
- target_qubit_index):
65
+
66
+ def apply_toffoli_gate(
67
+ circuit, control_qubit_index1, control_qubit_index2, target_qubit_index
68
+ ):
47
69
  # Apply a Toffoli gate (controlled-controlled-X gate) with the
48
70
  # specified control and target qubits
49
- circuit.ccx(control_qubit_index1,
50
- control_qubit_index2,
51
- target_qubit_index)
71
+ circuit.ccx(control_qubit_index1, control_qubit_index2, target_qubit_index)
72
+
52
73
 
53
74
  def apply_swap_gate(circuit, qubit_index1, qubit_index2):
54
75
  # Apply a SWAP gate to exchange the states of two qubits
55
76
  circuit.swap(qubit_index1, qubit_index2)
56
77
 
78
+
79
+ def apply_cswap_gate(
80
+ circuit, control_qubit_index, target_qubit_index1, target_qubit_index2
81
+ ):
82
+ # Apply a controlled-SWAP (Fredkin) gate with the specified control and target qubits
83
+ circuit.cswap(control_qubit_index, target_qubit_index1, target_qubit_index2)
84
+
85
+
57
86
  def apply_pauli_x_gate(circuit, qubit_index):
58
87
  # Apply a Pauli X gate on the specified qubit
59
88
  circuit.x(qubit_index)
60
89
 
90
+
61
91
  def apply_pauli_y_gate(circuit, qubit_index):
62
92
  # Apply a Pauli Y gate on the specified qubit
63
93
  circuit.y(qubit_index)
64
94
 
95
+
65
96
  def apply_pauli_z_gate(circuit, qubit_index):
66
97
  # Apply a Pauli Z gate on the specified qubit
67
98
  circuit.z(qubit_index)
68
99
 
100
+
101
+ def apply_t_gate(circuit, qubit_index):
102
+ # Apply a T gate (π/8 gate) on the specified qubit
103
+ circuit.t(qubit_index)
104
+
105
+
69
106
  def execute_circuit(circuit, backend, backend_config):
107
+ working_circuit = circuit.copy()
108
+
70
109
  # Add measurements if they are not already present
71
- if not circuit.cregs:
72
- circuit.measure_all()
110
+ # Check if circuit already has measurement operations
111
+ has_measurements = any(
112
+ isinstance(inst.operation, qiskit.circuit.Measure)
113
+ for inst in working_circuit.data
114
+ )
115
+ if not has_measurements:
116
+ working_circuit.measure_all()
73
117
 
74
118
  # Ensure the circuit is parameterized properly
75
- if circuit.parameters:
119
+ if working_circuit.parameters:
76
120
  # Parse the global parameter configuration
77
- parameter_bindings = {param: backend_config['parameter_values'][str(param)] for param in circuit.parameters}
78
- transpiled_circuit = qiskit.transpile(circuit, backend)
79
- qobj = qiskit.assemble(transpiled_circuit, parameter_binds=[parameter_bindings], shots=backend_config['backend_options']['shots'])
80
- job = backend.run(qobj)
121
+ parameter_bindings = {
122
+ param: backend_config["parameter_values"][str(param)]
123
+ for param in working_circuit.parameters
124
+ }
125
+ transpiled_circuit = qiskit.transpile(working_circuit, backend)
126
+ bound_circuit = transpiled_circuit.assign_parameters(parameter_bindings)
127
+ job = backend.run(
128
+ bound_circuit, shots=backend_config["backend_options"].get("shots", 1)
129
+ )
81
130
  result = job.result()
82
131
  return result.get_counts()
83
132
  else:
84
- transpiled_circuit = qiskit.transpile(circuit, backend)
85
- job = qiskit.execute(transpiled_circuit, backend, shots=backend_config['backend_options']['shots'])
133
+ transpiled_circuit = qiskit.transpile(working_circuit, backend)
134
+ job = backend.run(
135
+ transpiled_circuit, shots=backend_config["backend_options"].get("shots", 1)
136
+ )
86
137
  result = job.result()
87
138
  return result.get_counts()
88
139
 
140
+
89
141
  # placeholder method for use in the testing suite
90
142
  def get_final_state_vector(circuit, backend, backend_config):
91
- simulator = qiskit.Aer.get_backend('statevector_simulator')
143
+ working_circuit = circuit.copy()
144
+
145
+ simulator = AerSimulator(method="statevector")
146
+
147
+ # Add save_statevector instruction
148
+ working_circuit.save_statevector()
149
+
150
+ # Bind parameters if present
151
+ if working_circuit.parameters:
152
+ parameter_values = backend_config.get("parameter_values", {})
153
+ parameter_bindings = {
154
+ param: parameter_values[str(param)] for param in working_circuit.parameters
155
+ }
156
+ working_circuit = working_circuit.assign_parameters(parameter_bindings)
92
157
 
93
158
  # Simulate the circuit
94
- job = qiskit.execute(circuit, simulator)
159
+ transpiled_circuit = qiskit.transpile(working_circuit, simulator)
160
+ job = simulator.run(transpiled_circuit)
95
161
  result = job.result()
96
162
 
97
163
  return result.get_statevector()
98
164
 
165
+
99
166
  def draw_circuit(circuit):
100
167
  # Use Qiskit's built-in drawing function
101
- print(circuit.draw())
168
+ return circuit.draw()
169
+
102
170
 
103
171
  def apply_rx_gate(circuit, qubit_index, angle):
104
172
  param = qiskit.circuit.Parameter(angle) if isinstance(angle, str) else angle
105
173
  circuit.rx(param, qubit_index)
106
174
 
175
+
107
176
  def apply_ry_gate(circuit, qubit_index, angle):
108
177
  param = qiskit.circuit.Parameter(angle) if isinstance(angle, str) else angle
109
178
  circuit.ry(param, qubit_index)
110
179
 
180
+
111
181
  def apply_rz_gate(circuit, qubit_index, angle):
112
182
  param = qiskit.circuit.Parameter(angle) if isinstance(angle, str) else angle
113
183
  circuit.rz(param, qubit_index)
114
184
 
185
+
115
186
  def apply_u_gate(circuit, qubit_index, theta, phi, lambd):
116
187
  # Apply the U gate directly with specified parameters
117
188
  circuit.u(theta, phi, lambd, qubit_index)
189
+
190
+
191
+ def calculate_prob_zero(results, ancilla_qubit, num_qubits):
192
+ """
193
+ Calculate the probability of measuring the ancilla qubit in |0> state.
194
+
195
+ Qiskit uses little-endian qubit ordering with string format results,
196
+ where the rightmost bit corresponds to qubit 0.
197
+
198
+ Args:
199
+ results: Measurement results from execute_circuit() (dict with string keys)
200
+ ancilla_qubit: Index of the ancilla qubit
201
+ num_qubits: Total number of qubits in the circuit
202
+
203
+ Returns:
204
+ float: Probability of measuring ancilla in |0> state
205
+ """
206
+ # Handle different result formats from different backends
207
+ if isinstance(results, list):
208
+ results = results[0]
209
+
210
+ total_shots = sum(results.values())
211
+ count_zero = 0
212
+
213
+ for state, count in results.items():
214
+ # Qiskit: little-endian, rightmost bit is qubit 0
215
+ if len(state) > ancilla_qubit and state[-(ancilla_qubit + 1)] == "0":
216
+ count_zero += count
217
+
218
+ return count_zero / total_shots if total_shots > 0 else 0.0