def test_operations(self, num_qubits): # construct the original operation op_orig = circuit.Operation( circuit.MatrixGate(stats.unitary_group.rvs(2 ** num_qubits)), np.random.permutation(10)[:num_qubits] ) # export the operation to Cirq op_exported = cirq_converter.export_to_cirq(op_orig) # check that the operations are equivalent self.assertIsInstance(op_exported, cirq.GateOperation) np.testing.assert_allclose( op_orig.get_gate().get_operator(), cirq.unitary(op_exported.gate), rtol=1e-5, atol=1e-8 ) self.assertTupleEqual( op_orig.get_qubits(), tuple(qubit.x for qubit in op_exported.qubits) ) # reimport the operation from Cirq op_reimported = cirq_converter.import_from_cirq(op_exported) # check that the original and the reimported operation are equivalent self.assertIs(type(op_reimported), circuit.Operation) self.assertEqual(op_reimported.get_num_qubits(), op_orig.get_num_qubits()) np.testing.assert_allclose( op_orig.get_gate().get_operator(), op_reimported.get_gate().get_operator() ) self.assertTupleEqual(op_orig.get_qubits(), op_reimported.get_qubits())
def test_export_large_matrix_gate_error(self): matrix_gate = circuit.MatrixGate(stats.unitary_group.rvs(8)) with self.assertRaisesRegex( ValueError, r'MatrixGate for 3 qubits not supported \(Cirq has matrix gates only up' r' to 2 qubits\)'): cirq_converter.export_to_cirq(matrix_gate)
class InvertCnot(PointTransformationRule): """Invert the direction of a CNOT, creating additional Hadamard gates.""" hadamard = circuit.MatrixGate(np.sqrt(0.5) * np.array([ [1.0, 1.0], [1.0, -1.0] ])) cnot = circuit.MatrixGate(np.array([ [1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0] ])) inverted_cnot = cnot.permute_qubits([1, 0]) def __init__(self, architecture): self.architecture = architecture def accept(self, operation): # implements abstract method from parent class PointTransformationRule gate = operation.get_gate() return gate == self.cnot or gate == self.inverted_cnot def perform(self, operation): # implements abstract method from parent class PointTransformationRule if not self.accept(operation): raise RuleNotApplicableError hadamard_pauli_transform = self.hadamard.get_pauli_transform() hadamard_on_both = itertools.product( operation.get_qubits(), self.architecture.decompose_single_qubit_gate(hadamard_pauli_transform) ) hadamard_on_both = [ circuit.Operation(gate, [qubit]) for qubit, gate in hadamard_on_both ] inverted = operation.permute_qubits([1, 0]) return hadamard_on_both + [inverted] + hadamard_on_both
def import_from_cirq(obj): """Imports a gate, operation or circuit from Cirq. Args: obj: the Cirq object to be imported. Returns: the imported object (an instance of circuit.Circuit, circuit.Operation, or a subclass of circuit.Gate). Raises: TypeError: if import is not supported for the given type. ValueError: if the object cannot be imported successfully. """ if isinstance(obj, cirq.PhasedXPowGate): return circuit.PhasedXGate(obj.exponent * np.pi, obj.phase_exponent * np.pi) elif isinstance(obj, cirq.ZPowGate): return circuit.RotZGate(obj.exponent * np.pi) elif isinstance(obj, cirq.CZPowGate): if not np.isclose(np.mod(obj.exponent, 2.0), 1.0): raise ValueError('partial ControlledZ gates are not supported') return circuit.ControlledZGate() elif isinstance(obj, (cirq.SingleQubitMatrixGate, cirq.TwoQubitMatrixGate)): return circuit.MatrixGate(cirq.unitary(obj)) elif isinstance(obj, cirq.GateOperation): return circuit.Operation(import_from_cirq(obj.gate), [qubit.x for qubit in obj.qubits]) elif isinstance(obj, cirq.Circuit): qubits = obj.all_qubits() if not all(isinstance(qubit, cirq.LineQubit) for qubit in qubits): qubit_types = set(type(qubit) for qubit in qubits) qubit_types = sorted(qubit_type.__name__ for qubit_type in qubit_types) raise ValueError( 'import is supported for circuits on LineQubits only' ' [found qubit type(s): %s]' % ', '.join(qubit_types)) return circuit.Circuit( max(qubit.x for qubit in qubits) + 1, [ import_from_cirq(operation) for operation in itertools.chain.from_iterable(obj) ]) else: raise TypeError('unknown type: %s' % type(obj).__name__)
class TestExportAndImport(parameterized.TestCase): @parameterized.parameters([ circuit.PhasedXGate(0.47, 0.11), circuit.RotZGate(0.42), circuit.ControlledZGate(), circuit.MatrixGate(stats.unitary_group.rvs(2)), # random 1-qubit unitary circuit.MatrixGate(stats.unitary_group.rvs(4)), # random 2-qubit unitary circuit.MatrixGate(stats.unitary_group.rvs(8)), # random 3-qubit unitary circuit.MatrixGate(stats.unitary_group.rvs(16)) # random 4-qubit unitary ]) def test_gates(self, gate_orig): # export the gate to Cirq gate_exported = cirq_converter.export_to_cirq(gate_orig) # check that the gates are equivalent self.assertIsInstance(gate_exported, cirq.Gate) np.testing.assert_allclose( gate_orig.get_pauli_transform(), circuit.compute_pauli_transform(cirq.unitary(gate_exported)), rtol=1e-5, atol=1e-8 ) # reimport the gate from Cirq gate_reimported = cirq_converter.import_from_cirq(gate_exported) # check that the original and the reimported gate are equivalent self.assertIs(type(gate_reimported), type(gate_orig)) self.assertEqual( gate_reimported.get_num_qubits(), gate_orig.get_num_qubits() ) np.testing.assert_allclose( gate_orig.get_operator(), gate_reimported.get_operator(), rtol=1e-5, atol=1e-8 ) @parameterized.parameters([1, 2]) def test_operations(self, num_qubits): # construct the original operation op_orig = circuit.Operation( circuit.MatrixGate(stats.unitary_group.rvs(2 ** num_qubits)), np.random.permutation(10)[:num_qubits] ) # export the operation to Cirq op_exported = cirq_converter.export_to_cirq(op_orig) # check that the operations are equivalent self.assertIsInstance(op_exported, cirq.GateOperation) np.testing.assert_allclose( op_orig.get_gate().get_operator(), cirq.unitary(op_exported.gate), rtol=1e-5, atol=1e-8 ) self.assertTupleEqual( op_orig.get_qubits(), tuple(qubit.x for qubit in op_exported.qubits) ) # reimport the operation from Cirq op_reimported = cirq_converter.import_from_cirq(op_exported) # check that the original and the reimported operation are equivalent self.assertIs(type(op_reimported), circuit.Operation) self.assertEqual(op_reimported.get_num_qubits(), op_orig.get_num_qubits()) np.testing.assert_allclose( op_orig.get_gate().get_operator(), op_reimported.get_gate().get_operator() ) self.assertTupleEqual(op_orig.get_qubits(), op_reimported.get_qubits()) def test_circuit(self): # construct the original circuit circ_orig = circuit.Circuit(2, [ circuit.Operation(circuit.PhasedXGate(0.47, 0.11), [0]), circuit.Operation(circuit.ControlledZGate(), [0, 1]), circuit.Operation(circuit.RotZGate(0.42), [1]), ]) # export the circuit to Cirq circ_exported = cirq_converter.export_to_cirq(circ_orig) # check the type of circ_exported self.assertIsInstance(circ_exported, cirq.Circuit) # TODO(tfoesel): # a direct comparison between circ_orig and circ_exported would be better # reimport the circuit from Cirq circ_reimported = cirq_converter.import_from_cirq(circ_exported) # check that the number of operations and the gate types are conserved self.assertEqual(len(circ_orig), len(circ_reimported)) self.assertEqual( [type(operation.get_gate()) for operation in circ_orig], [type(operation.get_gate()) for operation in circ_orig] ) def test_export_unknown_type_error(self): with self.assertRaisesRegex(TypeError, r'unknown type: range'): cirq_converter.export_to_cirq(range(42)) def test_import_unknown_type_error(self): with self.assertRaisesRegex(TypeError, r'unknown type: range'): cirq_converter.import_from_cirq(range(42)) def test_import_partial_cz_error(self): partial_cz = cirq.CZPowGate(exponent=0.37) with self.assertRaisesRegex( ValueError, r'partial ControlledZ gates are not supported'): cirq_converter.import_from_cirq(partial_cz) def test_import_non_line_qubits_error(self): qubit_a = cirq.GridQubit(0, 1) qubit_b = cirq.GridQubit(0, 2) circ = cirq.Circuit( cirq.PhasedXPowGate(exponent=0.47, phase_exponent=0.11).on(qubit_a), cirq.CZPowGate(exponent=1.0).on(qubit_a, qubit_b), cirq.ZPowGate(exponent=0.42).on(qubit_b) ) with self.assertRaisesRegex( ValueError, r'import is supported for circuits on LineQubits only \[found qubit' r' type\(s\): GridQubit\]'): cirq_converter.import_from_cirq(circ)
def _random_operation(*qubits): return circuit.Operation( circuit.MatrixGate(stats.unitary_group.rvs(2 ** len(qubits))), qubits )