def test_two_q_gates(self): """The method dag.twoQ_gates() returns all 2Q gate nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Barrier(2), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.twoQ_gates() self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() self.assertIsInstance(op_node.op, Gate) self.assertEqual(len(op_node.qargs), 2)
def test_get_gates_nodes(self): """The method dag.gate_nodes() returns all gate nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.gate_nodes() self.assertEqual(len(op_nodes), 2) op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() self.assertIsInstance(op_node_1.op, Gate) self.assertIsInstance(op_node_2.op, Gate)
def test_quantum_successors(self): """The method dag.quantum_successors() returns successors connected by quantum edges""" self.dag.apply_operation_back(Measure(self.qubit1, self.clbit1)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(Reset(self.qubit0)) successor_measure = self.dag.quantum_successors(self.dag.named_nodes('measure').pop()) self.assertEqual(len(successor_measure), 1) cnot_node = successor_measure[0] self.assertIsInstance(self.dag.multi_graph.nodes[cnot_node]["op"], CnotGate) successor_cnot = self.dag.quantum_successors(cnot_node) self.assertEqual(len(successor_cnot), 2) self.assertEqual(self.dag.multi_graph.nodes[successor_cnot[0]]["type"], 'out') self.assertIsInstance(self.dag.multi_graph.nodes[successor_cnot[1]]["op"], Reset)
def test_get_op_nodes_particular(self): """The method dag.get_gates_nodes(op=AGate) returns all the AGate nodes""" self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(HGate(self.qubit1)) self.dag.apply_operation_back(Reset(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) op_nodes = self.dag.get_op_nodes(op=HGate(self.qubit0)) self.assertEqual(len(op_nodes), 2) op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() self.assertIsInstance(self.dag.multi_graph.nodes[op_node_1]["op"], HGate) self.assertIsInstance(self.dag.multi_graph.nodes[op_node_2]["op"], HGate)
def test_get_op_nodes_particular(self): """The method dag.gates_nodes(op=AGate) returns all the AGate nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(HGate(), [self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) op_nodes = self.dag.op_nodes(op=HGate) self.assertEqual(len(op_nodes), 2) op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() self.assertIsInstance(op_node_1.op, HGate) self.assertIsInstance(op_node_2.op, HGate)
def test_quantum_successors(self): """The method dag.quantum_successors() returns successors connected by quantum edges""" self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) successor_measure = self.dag.quantum_successors( self.dag.named_nodes('measure').pop()) self.assertEqual(len(successor_measure), 1) cnot_node = successor_measure[0] self.assertIsInstance(cnot_node.op, CnotGate) successor_cnot = self.dag.quantum_successors(cnot_node) self.assertEqual(len(successor_cnot), 2) self.assertEqual(successor_cnot[0].type, 'out') self.assertIsInstance(successor_cnot[1].op, Reset)
def test_auto_method_clifford_circuits_and_reset_noise(self): """Test statevector method is used for Clifford circuit""" # Test noise model noise_circs = [Reset(), IGate()] noise_probs = [0.5, 0.5] error = QuantumError(zip(noise_circs, noise_probs)) noise_model = NoiseModel() noise_model.add_all_qubit_quantum_error( error, ['id', 'x', 'y', 'z', 'h', 's', 'sdg']) backend = self.backend(noise_model=noise_model) # Test circuits shots = 100 circuits = ref_2q_clifford.cz_gate_circuits_deterministic( final_measure=True) result = backend.run(circuits, shots=shots).result() success = getattr(result, 'success', False) self.assertTrue(success) self.compare_result_metadata(result, circuits, 'method', 'stabilizer')
def test_quantum_predecessors(self): """The method dag.quantum_predecessors() returns predecessors connected by quantum edges""" self.dag.apply_operation_back(Reset(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) predecessor_measure = self.dag.quantum_predecessors( self.dag.named_nodes('measure').pop()) cnot_node = next(predecessor_measure) with self.assertRaises(StopIteration): next(predecessor_measure) self.assertIsInstance(cnot_node.op, CnotGate) predecessor_cnot = self.dag.quantum_predecessors(cnot_node) self.assertIsInstance(next(predecessor_cnot).op, Reset) self.assertEqual(next(predecessor_cnot).type, 'in') with self.assertRaises(StopIteration): next(predecessor_cnot)
def test_quantum_predecessors(self): """The method dag.quantum_predecessors() returns predecessors connected by quantum edges""" # q_0: |0>─|0>───■───── # ┌─┴─┐┌─┐ # q_1: |0>─────┤ X ├┤M├ # └───┘└╥┘ # c_0: 0 ═══════════╬═ # ║ # c_1: 0 ═══════════╩═ self.dag.apply_operation_back(Reset(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) predecessor_measure = self.dag.quantum_predecessors( self.dag.named_nodes('measure').pop()) cnot_node = next(predecessor_measure) with self.assertRaises(StopIteration): next(predecessor_measure) self.assertIsInstance(cnot_node.op, CXGate) predecessor_cnot = self.dag.quantum_predecessors(cnot_node) # Ordering between Reset and in[q1] is indeterminant. predecessor1 = next(predecessor_cnot) predecessor2 = next(predecessor_cnot) with self.assertRaises(StopIteration): next(predecessor_cnot) self.assertTrue( (predecessor1.type == 'in' and isinstance(predecessor2.op, Reset)) or (predecessor2.type == 'in' and isinstance(predecessor1.op, Reset)))
def _to_circuit(cls, op): if isinstance(op, QuantumCircuit): return op if isinstance(op, tuple): inst, qubits = op circ = QuantumCircuit(max(qubits) + 1) circ.append(inst, qargs=qubits) return circ if isinstance(op, Instruction): if op.num_clbits > 0: raise NoiseError( f"Unable to convert instruction with clbits: {op.__class__.__name__}" ) circ = QuantumCircuit(op.num_qubits) circ.append(op, qargs=list(range(op.num_qubits))) return circ if isinstance(op, QuantumChannel): if not op.is_cptp(atol=cls.atol): raise NoiseError("Input quantum channel is not CPTP.") try: return cls._to_circuit(Kraus(op).to_instruction()) except QiskitError as err: raise NoiseError( f"Fail to convert {op.__class__.__name__} to Instruction." ) from err if isinstance(op, BaseOperator): if hasattr(op, 'to_instruction'): try: return cls._to_circuit(op.to_instruction()) except QiskitError as err: raise NoiseError( f"Fail to convert {op.__class__.__name__} to Instruction." ) from err else: raise NoiseError( f"Unacceptable Operator, not implementing to_instruction: " f"{op.__class__.__name__}") if isinstance(op, list): if all(isinstance(aop, tuple) for aop in op): num_qubits = max([max(qubits) for _, qubits in op]) + 1 circ = QuantumCircuit(num_qubits) for inst, qubits in op: try: circ.append(inst, qargs=qubits) except CircuitError as err: raise NoiseError( f"Invalid operation type: {inst.__class__.__name__}," f" not appendable to circuit.") from err return circ # Support for old-style json-like input TODO: to be removed elif all(isinstance(aop, dict) for aop in op): warnings.warn( 'Constructing QuantumError with list of dict representing a mixed channel' ' has been deprecated as of qiskit-aer 0.10.0 and will be removed' ' no earlier than 3 months from that release date.', DeprecationWarning, stacklevel=3) # Convert json-like to non-kraus Instruction num_qubits = max([max(dic['qubits']) for dic in op]) + 1 circ = QuantumCircuit(num_qubits) for dic in op: if dic['name'] == 'reset': # pylint: disable=import-outside-toplevel from qiskit.circuit import Reset circ.append(Reset(), qargs=dic['qubits']) elif dic['name'] == 'kraus': circ.append(Instruction(name='kraus', num_qubits=len(dic['qubits']), num_clbits=0, params=dic['params']), qargs=dic['qubits']) elif dic['name'] == 'unitary': circ.append(UnitaryGate(data=dic['params'][0]), qargs=dic['qubits']) else: with warnings.catch_warnings(): warnings.filterwarnings( "ignore", category=DeprecationWarning, module= "qiskit.providers.aer.noise.errors.errorutils") circ.append(UnitaryGate(label=dic['name'], data=standard_gate_unitary( dic['name'])), qargs=dic['qubits']) return circ else: raise NoiseError(f"Invalid type of op list: {op}") raise NoiseError( f"Invalid noise op type {op.__class__.__name__}: {op}")
return approximate_quantum_error(noise, operator_string=operator_string, operator_dict=operator_dict, operator_list=operator_list) return transform_noise_model(model, approximate) # pauli operators _PAULIS_Q0 = [[(IGate(), [0])], [(XGate(), [0])], [(YGate(), [0])], [(ZGate(), [0])]] _PAULIS_Q1 = [[(IGate(), [1])], [(XGate(), [1])], [(YGate(), [1])], [(ZGate(), [1])]] _PAULIS_Q0Q1 = [op_q0 + op_q1 for op_q0 in _PAULIS_Q0 for op_q1 in _PAULIS_Q1] # reset operators _RESET_Q0_TO_0 = [(Reset(), [0])] _RESET_Q0_TO_1 = [(Reset(), [0]), (XGate(), [0])] _RESET_Q0 = [[(IGate(), [0])], _RESET_Q0_TO_0, _RESET_Q0_TO_1] _RESET_Q1_TO_0 = [(Reset(), [1])] _RESET_Q1_TO_1 = [(Reset(), [1]), (XGate(), [1])] _RESET_Q1 = [[(IGate(), [1])], _RESET_Q1_TO_0, _RESET_Q1_TO_1] _RESET_Q0Q1 = [op_q0 + op_q1 for op_q0 in _RESET_Q0 for op_q1 in _RESET_Q1] # preset operator table _PRESET_OPERATOR_TABLE = { "pauli": { 1: _PAULIS_Q0[1:], 2: _PAULIS_Q0Q1[1:], }, "reset": { 1: _RESET_Q0[1:], 2: _RESET_Q0Q1[1:],
def _standard_gate_instruction(instruction, ignore_phase=True): """Temporary function to create Instruction objects from a json string, which is necessary for creating a new QuantumError object from deprecated json-based input. Note that the type of returned object is different from the deprecated standard_gate_instruction. TODO: to be removed after deprecation period. Args: instruction (dict): A qobj instruction. ignore_phase (bool): Ignore global phase on unitary matrix in comparison to canonical unitary. Returns: list: a list of (instructions, qubits) equivalent to in input instruction. """ gate = { "id": IGate(), "x": XGate(), "y": YGate(), "z": ZGate(), "h": HGate(), "s": SGate(), "sdg": SdgGate(), "t": TGate(), "tdg": TdgGate(), "cx": CXGate(), "cz": CZGate(), "swap": SwapGate() } name = instruction.get("name", None) qubits = instruction["qubits"] if name in gate: return [(gate[name], qubits)] if name not in ["mat", "unitary", "kraus"]: return [instruction] params = instruction["params"] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning, module="qiskit.providers.aer.noise.errors.errorutils") # Check for single-qubit reset Kraus if name == "kraus": if len(qubits) == 1: superop = SuperOp(Kraus(params)) # Check if reset to |0> reset0 = reset_superop(1) if superop == reset0: return [(Reset(), [0])] # Check if reset to |1> reset1 = reset0.compose(Operator(standard_gate_unitary('x'))) if superop == reset1: return [(Reset(), [0]), (XGate(), [0])] return [instruction] # Check single qubit gates mat = params[0] if len(qubits) == 1: # Check clifford gates for j in range(24): if matrix_equal( mat, single_qubit_clifford_matrix(j), ignore_phase=ignore_phase): return [(gate, [0]) for gate in _CLIFFORD_GATES[j]] # Check t gates for name in ["t", "tdg"]: if matrix_equal( mat, standard_gate_unitary(name), ignore_phase=ignore_phase): return [(gate[name], qubits)] # TODO: u1,u2,u3 decomposition # Check two qubit gates if len(qubits) == 2: for name in ["cx", "cz", "swap"]: if matrix_equal( mat, standard_gate_unitary(name), ignore_phase=ignore_phase): return [(gate[name], qubits)] # Check reversed CX if matrix_equal( mat, standard_gate_unitary("cx_10"), ignore_phase=ignore_phase): return [(CXGate(), [qubits[1], qubits[0]])] # Check 2-qubit Pauli's paulis = ["id", "x", "y", "z"] for pauli0 in paulis: for pauli1 in paulis: pmat = np.kron( standard_gate_unitary(pauli1), standard_gate_unitary(pauli0)) if matrix_equal(mat, pmat, ignore_phase=ignore_phase): if pauli0 == "id": return [(gate[pauli1], [qubits[1]])] elif pauli1 == "id": return [(gate[pauli0], [qubits[0]])] else: return [(gate[pauli0], [qubits[0]]), (gate[pauli1], [qubits[1]])] # Check three qubit toffoli if len(qubits) == 3: if matrix_equal( mat, standard_gate_unitary("ccx_012"), ignore_phase=ignore_phase): return [(CCXGate(), qubits)] if matrix_equal( mat, standard_gate_unitary("ccx_021"), ignore_phase=ignore_phase): return [(CCXGate(), [qubits[0], qubits[2], qubits[1]])] if matrix_equal( mat, standard_gate_unitary("ccx_120"), ignore_phase=ignore_phase): return [(CCXGate(), [qubits[1], qubits[2], qubits[0]])] # Else return input in return [instruction]
def thermal_relaxation_error(t1, t2, time, excited_state_population=0): r""" Return a single-qubit thermal relaxation quantum error channel. Args: t1 (double): the :math:`T_1` relaxation time constant. t2 (double): the :math:`T_2` relaxation time constant. time (double): the gate time for relaxation error. excited_state_population (double): the population of :math:`|1\rangle` state at equilibrium (default: 0). Returns: QuantumError: a quantum error object for a noise model. Raises: NoiseError: If noise parameters are invalid. Additional information: * For parameters to be valid :math:`T_1` and :math:`T_2` must satisfy :math:`T_2 \le 2 T_1`. * If :math:`T_2 \le T_1` the error can be expressed as a mixed reset and unitary error channel. * If :math:`T_1 < T_2 \le 2 T_1` the error must be expressed as a general non-unitary Kraus error channel. """ if excited_state_population < 0: raise NoiseError("Invalid excited state population " "({} < 0).".format(excited_state_population)) if excited_state_population > 1: raise NoiseError("Invalid excited state population " "({} > 1).".format(excited_state_population)) if time < 0: raise NoiseError("Invalid gate_time ({} < 0)".format(time)) if t1 <= 0: raise NoiseError("Invalid T_1 relaxation time parameter: T_1 <= 0.") if t2 <= 0: raise NoiseError("Invalid T_2 relaxation time parameter: T_2 <= 0.") if t2 - 2 * t1 > 0: raise NoiseError( "Invalid T_2 relaxation time parameter: T_2 greater than 2 * T_1.") # T1 relaxation rate if t1 == np.inf: rate1 = 0 p_reset = 0 else: rate1 = 1 / t1 p_reset = 1 - np.exp(-time * rate1) # T2 dephasing rate if t2 == np.inf: rate2 = 0 exp_t2 = 1 else: rate2 = 1 / t2 exp_t2 = np.exp(-time * rate2) # Qubit state equilibrium probabilities p0 = 1 - excited_state_population p1 = excited_state_population if t2 > t1: # If T_2 > T_1 we must express this as a Kraus channel # We start with the Choi-matrix representation: chan = Choi( np.array([[1 - p1 * p_reset, 0, 0, exp_t2], [0, p1 * p_reset, 0, 0], [0, 0, p0 * p_reset, 0], [exp_t2, 0, 0, 1 - p0 * p_reset]])) return QuantumError(Kraus(chan)) else: # If T_2 < T_1 we can express this channel as a probabilistic # mixture of reset operations and unitary errors: circuits = [[(IGate(), [0])], [(ZGate(), [0])], [(Reset(), [0])], [(Reset(), [0]), (XGate(), [0])]] # Probability p_reset0 = p_reset * p0 p_reset1 = p_reset * p1 p_z = (1 - p_reset) * (1 - np.exp(-time * (rate2 - rate1))) / 2 p_identity = 1 - p_z - p_reset0 - p_reset1 probabilities = [p_identity, p_z, p_reset0, p_reset1] return QuantumError(zip(circuits, probabilities))