7
7
from typing import TYPE_CHECKING , Any
8
8
9
9
import numpy as np
10
- from qiskit import QuantumCircuit , transpile
11
- from qiskit import __version__ as qiskit_version
10
+
11
+ from . _compat . optional import HAS_QISKIT
12
12
13
13
if TYPE_CHECKING :
14
14
from numpy .typing import NDArray
15
+ from qiskit .circuit import QuantumCircuit
15
16
16
17
17
18
@unique
@@ -154,8 +155,10 @@ def __str__(self) -> str:
154
155
multi_controlled_gates_v_chain = [mcx_v_chain ]
155
156
156
157
157
- def create_general_gate (qubits : int , params : int , controls : int , identifier : str ) -> QuantumCircuit :
158
+ def __create_general_gate (qubits : int , params : int , controls : int , identifier : str ) -> QuantumCircuit :
158
159
"""Create a ``QuantumCircuit`` containing a single gate ``identifier`` with the given number of ``qubits``, ``params``, and ``controls``."""
160
+ from qiskit .circuit import QuantumCircuit
161
+
159
162
required_qubits = qubits + controls
160
163
qc = QuantumCircuit (required_qubits )
161
164
gate_identifier = "c" * controls + identifier
@@ -167,7 +170,7 @@ def create_general_gate(qubits: int, params: int, controls: int, identifier: str
167
170
return qc
168
171
169
172
170
- def create_multi_controlled_gate (
173
+ def __create_multi_controlled_gate (
171
174
qubits : int ,
172
175
params : int ,
173
176
controls : int ,
@@ -176,6 +179,8 @@ def create_multi_controlled_gate(
176
179
identifier : str ,
177
180
) -> QuantumCircuit :
178
181
"""Create a ``QuantumCircuit`` containing a single multi-controlled gate ``identifier`` with the given number of ``qubits``, ``params``, and ``controls`` using ``ancilla_qubits`` ancilla qubits and the given ancilla ``mode``."""
182
+ from qiskit .circuit import QuantumCircuit
183
+
179
184
required_qubits = qubits + controls
180
185
181
186
# special handling for v-chain mode which is indicated by the ancilla_qubits being None
@@ -208,12 +213,14 @@ def create_multi_controlled_gate(
208
213
return qc
209
214
210
215
211
- def compute_cost (
216
+ def __compute_cost (
212
217
qc : QuantumCircuit ,
213
218
basis_gates : list [str ],
214
219
optimization_level : int = 1 ,
215
220
) -> int :
216
221
"""Compute the cost of a circuit by transpiling the circuit to a given ``basis_gates`` gate set and a certain ``optimization_level``."""
222
+ from qiskit import transpile
223
+
217
224
transpiled_circuit = transpile (
218
225
qc , basis_gates = basis_gates , optimization_level = optimization_level , seed_transpiler = 12345
219
226
)
@@ -228,7 +235,7 @@ class GateType(Enum):
228
235
MULTI_CONTROLLED = 2
229
236
230
237
231
- def create_gate_profile_data (
238
+ def __create_gate_profile_data (
232
239
gate_collection : list [dict [str , Any ]],
233
240
gate_type : GateType ,
234
241
basis_gates : list [str ] | None = None ,
@@ -254,9 +261,9 @@ def create_gate_profile_data(
254
261
qc = None
255
262
# create the gate
256
263
if gate_type == GateType .GENERAL :
257
- qc = create_general_gate (qubits , params , control , gate )
264
+ qc = __create_general_gate (qubits , params , control , gate )
258
265
elif gate_type == GateType .MULTI_CONTROLLED :
259
- qc = create_multi_controlled_gate (
266
+ qc = __create_multi_controlled_gate (
260
267
qubits ,
261
268
params ,
262
269
control ,
@@ -265,14 +272,14 @@ def create_gate_profile_data(
265
272
gate ,
266
273
)
267
274
# compute the cost
268
- cost = compute_cost (qc , basis_gates , optimization_level )
275
+ cost = __compute_cost (qc , basis_gates , optimization_level )
269
276
270
277
# add the cost to the profile data
271
278
profile_data [gate , control ] = cost
272
279
return profile_data
273
280
274
281
275
- def add_special_case_data (
282
+ def __add_special_case_data (
276
283
profile_data : dict [tuple [str , int ], int ],
277
284
special_cases : dict [str , Any ] | None = None ,
278
285
) -> None :
@@ -292,19 +299,17 @@ def add_special_case_data(
292
299
profile_data .setdefault ((gate , nc ), cost )
293
300
294
301
295
- def generate_profile_name (optimization_level : int = 1 , mode : AncillaMode = AncillaMode .NO_ANCILLA ) -> str :
296
- """Generate a profile name based on the given optimization level and ancilla mode."""
297
- return "qiskit_O" + str (optimization_level ) + "_" + str (mode ) + ".profile"
298
-
299
-
300
- def write_profile_data_to_file (profile_data : dict [tuple [str , int ], int ], filename : Path ) -> None :
302
+ def __write_profile_data_to_file (profile_data : dict [tuple [str , int ], int ], filename : Path ) -> None :
301
303
"""Write the profile data to a file."""
304
+ HAS_QISKIT .require_now ("generate compilation flow profiles" )
305
+ from qiskit import __version__ as qiskit_version
306
+
302
307
with Path (filename ).open ("w+" , encoding = "utf-8" ) as f :
303
308
f .write (f"# { filename } , Qiskit version: { qiskit_version } \n " )
304
309
f .writelines (f"{ gate } { controls } { cost } \n " for (gate , controls ), cost in profile_data .items ())
305
310
306
311
307
- def check_recurrence (seq : list [int ], order : int = 2 ) -> list [int ] | None :
312
+ def __check_recurrence (seq : list [int ], order : int = 2 ) -> list [int ] | None :
308
313
"""Determine a recurrence relation with a given ``order`` in ``sequence`` and return the corresponding coefficients or ``None`` if no relation was determined."""
309
314
if len (seq ) < (2 * order + 1 ):
310
315
return None
@@ -325,7 +330,7 @@ def check_recurrence(seq: list[int], order: int = 2) -> list[int] | None:
325
330
return list (coefficients )
326
331
327
332
328
- def find_continuation (
333
+ def __find_continuation (
329
334
profile_data : dict [tuple [str , int ], int ],
330
335
gate : str ,
331
336
cutoff : int = 5 ,
@@ -345,7 +350,7 @@ def find_continuation(
345
350
346
351
coeffs = None
347
352
for order in range (1 , max_order + 1 ):
348
- coeffs = check_recurrence (sequence , order )
353
+ coeffs = __check_recurrence (sequence , order )
349
354
if coeffs is not None :
350
355
break
351
356
@@ -371,6 +376,11 @@ def find_continuation(
371
376
default_profile_path = Path (__file__ ).resolve ().parent .joinpath ("profiles" )
372
377
373
378
379
+ def generate_profile_name (optimization_level : int = 1 , mode : AncillaMode = AncillaMode .NO_ANCILLA ) -> str :
380
+ """Generate a profile name based on the given optimization level and ancilla mode."""
381
+ return "qiskit_O" + str (optimization_level ) + "_" + str (mode ) + ".profile"
382
+
383
+
374
384
def generate_profile (
375
385
optimization_level : int = 1 ,
376
386
mode : AncillaMode = AncillaMode .NO_ANCILLA ,
@@ -392,34 +402,34 @@ def generate_profile(
392
402
filepath = default_profile_path
393
403
394
404
# generate general profile data
395
- profile = create_gate_profile_data (general_gates , GateType .GENERAL , optimization_level = optimization_level )
405
+ profile = __create_gate_profile_data (general_gates , GateType .GENERAL , optimization_level = optimization_level )
396
406
397
407
# add multi-controlled gates
398
408
profile .update (
399
- create_gate_profile_data (
409
+ __create_gate_profile_data (
400
410
multi_controlled_gates ,
401
411
GateType .MULTI_CONTROLLED ,
402
412
optimization_level = optimization_level ,
403
413
)
404
414
)
405
- find_continuation (profile , gate = "p" , max_control = max_controls )
415
+ __find_continuation (profile , gate = "p" , max_control = max_controls )
406
416
407
417
gate_collection = gate_collection_for_mode [mode ]
408
418
409
419
# add multi-controlled gates with specific mode
410
420
profile .update (
411
- create_gate_profile_data (
421
+ __create_gate_profile_data (
412
422
gate_collection ,
413
423
GateType .MULTI_CONTROLLED ,
414
424
optimization_level = optimization_level ,
415
425
)
416
426
)
417
- find_continuation (profile , gate = "x" , max_control = max_controls )
427
+ __find_continuation (profile , gate = "x" , max_control = max_controls )
418
428
419
429
# add special case data
420
- add_special_case_data (profile )
430
+ __add_special_case_data (profile )
421
431
422
432
# write profile data to file
423
433
filename = generate_profile_name (optimization_level = optimization_level , mode = mode )
424
434
filepath = filepath .joinpath (filename )
425
- write_profile_data_to_file (profile , filepath )
435
+ __write_profile_data_to_file (profile , filepath )
0 commit comments