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 main(argv): if len(argv) > 1: raise app.UsageError('Too many command-line arguments.') rule = rules.ExchangeCommutingOperations() circ = circuit.Circuit(7, [ circuit.Operation(circuit.ControlledZGate(), [0, 1]), circuit.Operation(circuit.RotZGate(0.42), [0]), circuit.Operation(circuit.ControlledZGate(), [1, 2]), circuit.Operation(circuit.PhasedXGate(0.815, 0.4711), [1]), circuit.Operation(circuit.ControlledZGate(), [0, 1]), circuit.Operation(circuit.ControlledZGate(), [1, 2]) ]) transformations = tuple(rule.scan(circ)) # Show 4 transformations. print(transformations)
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 parse_gates(gates, *gate_types): """Parses gates into expected gate types.""" if len(gates) != len(gate_types): raise ValueError( 'inconsistent length of gates and gate_types (%d vs %d)' % (len(gates), len(gate_types))) parsed_gates = [] for gate_in, gate_type in zip(gates, gate_types): if not isinstance(gate_in, circuit.Gate): raise TypeError('%s is not a Gate' % type(gate_in).__name__) if not isinstance(gate_type, type): raise TypeError('%s instance is not a type' % type(gate_type).__name__) if not issubclass(gate_type, circuit.Gate): raise TypeError('%s is not a Gate type' % gate_type.__name__) if gate_type == circuit.PhasedXGate: if gate_in.get_num_qubits() != 1: return None elif isinstance(gate_in, circuit.PhasedXGate): gate_out = gate_in elif isinstance(gate_in, circuit.RotZGate): if gate_in.is_identity(phase_invariant=True): gate_out = circuit.PhasedXGate(0.0, 0.0) else: return None else: pauli_transform = gate_in.get_pauli_transform() if np.isclose(pauli_transform[2, 2], -1.0): gate_out = circuit.PhasedXGate( np.pi, 0.5 * np.arctan2(pauli_transform[0, 1], pauli_transform[0, 0])) else: rotation = scipy.spatial.transform.Rotation.from_dcm( pauli_transform) alpha, beta, gamma = rotation.as_euler('zxz') if np.isclose(alpha, -gamma): gate_out = circuit.PhasedXGate(beta, -alpha) else: return None elif gate_type == circuit.RotZGate: if gate_in.get_num_qubits() != 1: return None elif isinstance(gate_in, circuit.RotZGate): gate_out = gate_in elif isinstance(gate_in, circuit.PhasedXGate): if gate_in.is_identity(phase_invariant=True): gate_out = circuit.RotZGate(0.0) else: return None else: pauli_transform = gate_in.get_pauli_transform() if np.isclose(pauli_transform[2, 2], 1.0): gate_out = circuit.RotZGate( np.arctan2(pauli_transform[1, 0], pauli_transform[0, 0])) else: return None elif gate_type == circuit.ControlledZGate: if gate_in.get_num_qubits() != 2: return None elif isinstance(gate_in, circuit.ControlledZGate): gate_out = gate_in elif gate_in == circuit.ControlledZGate(): gate_out = circuit.ControlledZGate() else: return None else: raise ValueError('unknown Gate type: %s' % gate_type.__name__) assert isinstance(gate_out, gate_type) parsed_gates.append(gate_out) assert len(parsed_gates) == len(gates) return parsed_gates