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_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 perform(self, operation_first, operation_second): # implements abstract method from parent class PairTransformationRule if not self.accept(operation_first, operation_second): raise RuleNotApplicableError parsed = parsing.parse_operations([operation_first, operation_second], circuit.PhasedXGate, circuit.ControlledZGate) if parsed is not None: phased_x, cz = parsed else: parsed = parsing.parse_operations( [operation_first, operation_second], circuit.ControlledZGate, circuit.PhasedXGate) if parsed is not None: cz, phased_x = parsed else: raise RuleNotApplicableError if not np.isclose(np.cos(phased_x.get_gate().get_rotation_angle()), -1.0): raise RuleNotApplicableError other_qubit, = set(cz.get_qubits()).difference(phased_x.get_qubits()) z_flip = np.diag([-1.0, -1.0, 1.0]) # the pauli_transform for a Z flip z_flip = [ circuit.Operation(gate, [other_qubit]) for gate in self.architecture.decompose_single_qubit_gate(z_flip) ] return [operation_second], z_flip + [operation_first]
def parse_operations(operations, *gate_types): """Parse operations into expected gate types.""" if len(operations) != len(gate_types): raise ValueError('inconsistent length of operations and gate_types' ' (%d vs %d)' % (len(operations), len(gate_types))) for operation in operations: if not isinstance(operation, circuit.Operation): raise TypeError('%s is not an Operation' % type(operation).__name__) parsed_gates = parse_gates( [operation.get_gate() for operation in operations], *gate_types) if parsed_gates is None: return None else: parsed_operations = [] for operation, parsed_gate in zip(operations, parsed_gates): if operation.get_gate() is not parsed_gate: operation = circuit.Operation(parsed_gate, operation.get_qubits()) parsed_operations.append(operation) return parsed_operations
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__)
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 perform(self, operations): # implements abstract method from parent class LocalGroupTransformationRule if not self.accept(operations): raise RuleNotApplicableError qubits = [operation.get_qubits() for operation in operations] if not all(len(qu) == 1 for qu in qubits): raise RuntimeError() # cmp. TODO at the beginning of this file qubits = set().union(*qubits) if len(qubits) != 1: raise RuntimeError() # cmp. TODO at the beginning of this file qubit, = qubits pauli_transform = np.eye(3) for operation in operations: pauli_transform = np.dot( operation.get_gate().get_pauli_transform(), pauli_transform) gates = self.architecture.decompose_single_qubit_gate(pauli_transform) return [circuit.Operation(gate, [qubit]) for gate in gates]
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 _random_operation(*qubits): return circuit.Operation( circuit.MatrixGate(stats.unitary_group.rvs(2 ** len(qubits))), qubits )