def add_op_to_circuit(qsim_op: cirq.GateOperation, time: int, qubit_to_index_dict: Dict[cirq.Qid, int], circuit: Union[qsim.Circuit, qsim.NoisyCircuit]): """Adds an operation to a noisy or noiseless circuit.""" qsim_gate = qsim_op.gate gate_kind = _cirq_gate_kind(qsim_gate) qubits = [qubit_to_index_dict[q] for q in qsim_op.qubits] qsim_qubits = qubits is_controlled = isinstance(qsim_gate, cirq.ops.ControlledGate) if is_controlled: control_qubits, control_values = _control_details(qsim_gate, qubits) if control_qubits is None: # This gate has no valid control, and will be omitted. return if qsim_gate.num_qubits() > 4: raise NotImplementedError( f'Received control gate on {gate.num_qubits()} target qubits; ' + 'only up to 4-qubit gates are supported.') qsim_qubits = qubits[qsim_gate.num_controls():] qsim_gate = qsim_gate.sub_gate if (gate_kind == qsim.kTwoQubitDiagonalGate or gate_kind == qsim.kThreeQubitDiagonalGate): if isinstance(circuit, qsim.Circuit): qsim.add_diagonal_gate(time, qsim_qubits, qsim_gate._diag_angles_radians, circuit) else: qsim.add_diagonal_gate_channel(time, qsim_qubits, qsim_gate._diag_angles_radians, circuit) elif gate_kind == qsim.kMatrixGate: m = [ val for i in list(cirq.unitary(qsim_gate).flat) for val in [i.real, i.imag] ] if isinstance(circuit, qsim.Circuit): qsim.add_matrix_gate(time, qsim_qubits, m, circuit) else: qsim.add_matrix_gate_channel(time, qsim_qubits, m, circuit) else: params = { p.strip('_'): val for p, val in vars(qsim_gate).items() if isinstance(val, float) or isinstance(val, int) } if isinstance(circuit, qsim.Circuit): qsim.add_gate(gate_kind, time, qsim_qubits, params, circuit) else: qsim.add_gate_channel(gate_kind, time, qsim_qubits, params, circuit) if is_controlled: if isinstance(circuit, qsim.Circuit): qsim.control_last_gate(control_qubits, control_values, circuit) else: qsim.control_last_gate_channel(control_qubits, control_values, circuit)
def translate_cirq_to_qsim( self, qubit_order: cirq.ops.QubitOrderOrList = cirq.ops.QubitOrder.DEFAULT ) -> qsim.Circuit: """ Translates this Cirq circuit to the qsim representation. :qubit_order: Ordering of qubits :return: a C++ qsim Circuit object """ qsim_circuit = qsim.Circuit() qsim_circuit.num_qubits = len(self.all_qubits()) ordered_qubits = cirq.ops.QubitOrder.as_qubit_order( qubit_order).order_for(self.all_qubits()) # qsim numbers qubits in reverse order from cirq ordered_qubits = list(reversed(ordered_qubits)) qubit_to_index_dict = {q: i for i, q in enumerate(ordered_qubits)} time_offset = 0 for moment in self: ops_by_gate = [ cirq.decompose(op, keep=lambda x: _cirq_gate_kind(x.gate) != None) for op in moment ] moment_length = max(len(gate_ops) for gate_ops in ops_by_gate) # Gates must be added in time order. for gi in range(moment_length): for gate_ops in ops_by_gate: if gi >= len(gate_ops): continue qsim_op = gate_ops[gi] gate_kind = _cirq_gate_kind(qsim_op.gate) time = time_offset + gi qubits = [qubit_to_index_dict[q] for q in qsim_op.qubits] params = { p.strip('_'): val for p, val in vars(qsim_op.gate).items() if isinstance(val, float) or isinstance(val, int) } if gate_kind == qsim.kMatrixGate1: qsim.add_matrix1(time, qubits, cirq.unitary(qsim_op.gate).tolist(), qsim_circuit) elif gate_kind == qsim.kMatrixGate2: qsim.add_matrix2(time, qubits, cirq.unitary(qsim_op.gate).tolist(), qsim_circuit) else: qsim.add_gate(gate_kind, time, qubits, params, qsim_circuit) time_offset += moment_length return qsim_circuit
def translate_cirq_to_qsim( self, qubit_order: cirq.ops.QubitOrderOrList = cirq.ops.QubitOrder.DEFAULT ) -> qsim.Circuit: """ Translates this Cirq circuit to the qsim representation. :qubit_order: Ordering of qubits :return: a C++ qsim Circuit object """ qsim_circuit = qsim.Circuit() qsim_circuit.num_qubits = len(self.all_qubits()) ordered_qubits = cirq.ops.QubitOrder.as_qubit_order(qubit_order).order_for( self.all_qubits()) # qsim numbers qubits in reverse order from cirq ordered_qubits = list(reversed(ordered_qubits)) def has_qsim_kind(op: cirq.ops.GateOperation): return _cirq_gate_kind(op.gate) != None def to_matrix(op: cirq.ops.GateOperation): mat = cirq.protocols.unitary(op.gate, None) if mat is None: return NotImplemented return cirq.ops.MatrixGate(mat).on(*op.qubits) qubit_to_index_dict = {q: i for i, q in enumerate(ordered_qubits)} time_offset = 0 for moment in self: ops_by_gate = [ cirq.decompose(op, fallback_decomposer=to_matrix, keep=has_qsim_kind) for op in moment ] moment_length = max(len(gate_ops) for gate_ops in ops_by_gate) # Gates must be added in time order. for gi in range(moment_length): for gate_ops in ops_by_gate: if gi >= len(gate_ops): continue qsim_op = gate_ops[gi] gate_kind = _cirq_gate_kind(qsim_op.gate) time = time_offset + gi qubits = [qubit_to_index_dict[q] for q in qsim_op.qubits] qsim_gate = qsim_op.gate qsim_qubits = qubits is_controlled = isinstance(qsim_op.gate, cirq.ops.ControlledGate) if is_controlled: control_qubits, control_values = _control_details(qsim_op.gate, qubits) if control_qubits is None: # This gate has no valid control, and will be omitted. continue if qsim_gate.num_qubits() > 4: raise NotImplementedError( f'Received control gate on {gate.num_qubits()} target qubits; ' + 'only up to 4-qubit gates are supported.') qsim_gate = qsim_gate.sub_gate qsim_qubits = qubits[qsim_op.gate.num_controls():] if gate_kind == qsim.kTwoQubitDiagonalGate or gate_kind == qsim.kThreeQubitDiagonalGate: qsim.add_diagonal_gate(time, qsim_qubits, qsim_gate._diag_angles_radians, qsim_circuit) elif gate_kind == qsim.kMatrixGate: flatten = lambda l : [val for i in l for val in [i.real, i.imag]] qsim.add_matrix_gate(time, qsim_qubits, flatten(list(cirq.unitary(qsim_gate).flat)), qsim_circuit) else: params = { p.strip('_'): val for p, val in vars(qsim_gate).items() if isinstance(val, float) or isinstance(val, int) } qsim.add_gate(gate_kind, time, qsim_qubits, params, qsim_circuit) if is_controlled: qsim.control_last_gate(control_qubits, control_values, qsim_circuit) time_offset += moment_length return qsim_circuit