12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
14
15
- import itertools
16
- import cirq
17
- import numpy as np
18
- import sympy
15
+ from typing import Callable , cast , Dict , Union , List , Tuple , Optional
19
16
20
- from typing import Callable , cast , Dict , Union , List
17
+ import sympy
18
+ import numpy as np
21
19
from numpy .typing import NDArray
22
20
23
21
from pyquil .quil import Program
45
43
Parameter ,
46
44
substitute_array ,
47
45
)
48
- from pyquil .paulis import PauliSum as PyQuilPauliSum
49
- from pyquil .noise import pauli_kraus_map
50
46
from pyquil .simulation import matrices
51
47
52
48
from cirq .circuits .circuit import Circuit
65
61
from cirq .ops .measurement_gate import MeasurementGate
66
62
from cirq .ops .swap_gates import ISWAP , ISwapPowGate , SWAP
67
63
from cirq .ops .three_qubit_gates import CCNOT , CSWAP
68
- from cirq .ops .linear_combinations import PauliSum
69
- from cirq .ops .pauli_string import PauliString
70
64
from cirq .ops .raw_types import Gate
71
- from cirq .ops .common_channels import AsymmetricDepolarizingChannel
72
65
from cirq .ops .kraus_channel import KrausChannel
73
66
74
67
75
68
class UndefinedQuilGate (Exception ):
76
69
"""Error for a undefined Quil Gate."""
77
70
78
- pass
79
-
80
71
81
72
class UnsupportedQuilInstruction (Exception ):
82
73
"""Error for a unsupported instruction."""
83
74
84
- pass
85
-
86
75
87
76
#
88
77
# Cirq doesn't have direct analogues of these Quil gates
@@ -207,6 +196,7 @@ def _value_equality_approximate_values_(self):
207
196
RESET directives have special meaning on QCS, to enable active reset.
208
197
"""
209
198
199
+
210
200
# Parameterized gates map to functions that produce Gate constructors.
211
201
SUPPORTED_GATES : Dict [str , Union [Gate , Callable [..., Gate ]]] = {
212
202
"CCNOT" : CCNOT ,
@@ -315,7 +305,7 @@ def circuit_from_quil(quil: Union[str, Program]) -> Circuit:
315
305
elif gate_name in defined_gates :
316
306
u = quil_defined_gates [gate_name ]
317
307
else :
318
- raise ValueError (f"{ gate_name } is not known." )
308
+ raise UndefinedQuilGate (f"{ gate_name } is not known." )
319
309
320
310
entries = np .fromstring (
321
311
inst .freeform_string .strip ("()" ).replace ("i" , "j" ), dtype = np .complex_ , sep = " "
@@ -426,9 +416,20 @@ def circuit_from_quil(quil: Union[str, Program]) -> Circuit:
426
416
427
417
428
418
def kraus_noise_model_to_cirq (
429
- kraus_noise_model , defined_gates = SUPPORTED_GATES
419
+ kraus_noise_model : Dict [Tuple [str , ...], List [NDArray [np .complex_ ]]],
420
+ defined_gates : Optional [Dict [str , Gate ]] = None ,
430
421
) -> InsertionNoiseModel :
431
- """Construct a Cirq noise model from the provided Kraus operators."""
422
+ """Construct a Cirq noise model from the provided Kraus operators.
423
+
424
+ Args:
425
+ kraus_noise_model: A dictionary where the keys are tuples of Quil gate names and qubit
426
+ indices and the values are the Kraus representation of the noise channel.
427
+ defined_gates: A dictionary mapping Quil gates to Cirq gates.
428
+ Returns:
429
+ A Cirq InsertionNoiseModel which applies the Kraus operators to the specified gates.
430
+ """
431
+ if defined_gates is None :
432
+ defined_gates = SUPPORTED_GATES
432
433
ops_added = {}
433
434
for key , kraus_ops in kraus_noise_model .items ():
434
435
gate_name = key [0 ]
@@ -443,19 +444,36 @@ def kraus_noise_model_to_cirq(
443
444
return noise_model
444
445
445
446
446
- def remove_gate_from_kraus (kraus_ops , gate_matrix ):
447
- """
448
- Recover the kraus operators from a kraus composed with a gate. This function is the reverse of append_kraus_to_gate.
447
+ def remove_gate_from_kraus (
448
+ kraus_ops : List [NDArray [np .complex_ ]], gate_matrix : NDArray [np .complex_ ]
449
+ ) -> List [NDArray [np .complex_ ]]:
450
+ """Recover the kraus operators from a kraus composed with a gate.
451
+
452
+ This function is the reverse of append_kraus_to_gate.
453
+
454
+ Args:
455
+ kraus_ops: A list of Kraus operators.
456
+ gate_matrix: The target unitary of the gate.
449
457
450
- :param kraus_ops:
451
- :param gate_matrix:
452
- :return:
458
+ Returns:
459
+ The Kraus operators of the error channel.
453
460
"""
454
461
return [kju @ gate_matrix .conj ().T for kju in kraus_ops ]
455
462
456
463
457
464
def quil_expression_to_sympy (expression : ParameterDesignator ):
458
- """Convert a quil expression to a numpy function."""
465
+ """Convert a quil expression to a Sympy expression.
466
+
467
+ Args:
468
+ expression: A quil expression.
469
+
470
+ Returns:
471
+ The sympy form of the expression.
472
+
473
+ Raises:
474
+ ValueError: Connect convert unknown BinaryExp.
475
+ ValueError: Unrecognized expression.
476
+ """
459
477
if type (expression ) in {np .int_ , np .float_ , np .complex_ , int , float , complex }:
460
478
if isinstance (expression , (np .complex128 , complex )):
461
479
assert expression .imag < 1e-6 , "Parameters should be real."
@@ -505,12 +523,21 @@ def quil_expression_to_sympy(expression: ParameterDesignator):
505
523
506
524
else :
507
525
raise ValueError (
508
- f"quil_expression_to_sympy encountered unrecognized expression { expression } of type { type (expression )} "
526
+ f"Unrecognized expression { expression } of type { type (expression )} "
509
527
)
510
528
511
529
512
530
def defgate_to_cirq (defgate : DefGate ):
513
- """Convert a Quil DefGate to a Cirq Gate class."""
531
+ """Convert a Quil DefGate to a Cirq Gate class.
532
+
533
+ For non-parametric gates, it's recommended to create `MatrixGate` object. This function is
534
+ intended for the case of parametric gates.
535
+
536
+ Args:
537
+ defgate: A quil gate defintion.
538
+ Returns:
539
+ A subclass of `Gate` corresponding to the DefGate.
540
+ """
514
541
name = defgate .name
515
542
matrix = defgate .matrix
516
543
parameters = defgate .parameters
0 commit comments