diff --git a/qiskit_aer/noise/noise_model.py b/qiskit_aer/noise/noise_model.py index 24933ec1d3..af5328de3b 100644 --- a/qiskit_aer/noise/noise_model.py +++ b/qiskit_aer/noise/noise_model.py @@ -20,7 +20,8 @@ import numpy as np -from qiskit.circuit import Instruction, Delay +from qiskit.circuit import QuantumCircuit, Instruction, Delay, Reset +from qiskit.circuit.library.generalized_gates import PauliGate, UnitaryGate from qiskit.providers import QubitProperties from qiskit.providers.exceptions import BackendPropertyError from qiskit.providers.models.backendproperties import BackendProperties @@ -959,6 +960,105 @@ def to_dict(self, serializable=False): return ret + @staticmethod + def from_dict(noise_dict): + """ + Load NoiseModel from a dictionary. + Args: + noise_dict (dict): A serialized noise model. + Returns: + NoiseModel: the noise model. + Raises: + NoiseError: if dict cannot be converted to NoiseModel. + """ + warn( + "from_dict has been deprecated as of qiskit-aer 0.15.0" + " and will be removed no earlier than 3 months from that release date.", + DeprecationWarning, + stacklevel=2, + ) + + def inst_dic_list_to_circuit(dic_list): + num_qubits = max(max(dic["qubits"]) for dic in dic_list) + 1 + circ = QuantumCircuit(num_qubits) + for dic in dic_list: + if dic["name"] == "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"]) + elif dic["name"] == "pauli": + circ.append(PauliGate(dic["params"][0]), qargs=dic["qubits"]) + else: + with catch_warnings(): + filterwarnings( + "ignore", + category=DeprecationWarning, + module="qiskit_aer.noise.errors.errorutils", + ) + circ.append( + UnitaryGate( + label=dic["name"], data=_standard_gate_unitary(dic["name"]) + ), + qargs=dic["qubits"], + ) + return circ + + # Return noise model + noise_model = NoiseModel() + + # Get error terms + errors = noise_dict.get("errors", []) + + for error in errors: + error_type = error["type"] + + # Add QuantumError + if error_type == "qerror": + circuits = [inst_dic_list_to_circuit(dics) for dics in error["instructions"]] + noise_ops = tuple(zip(circuits, error["probabilities"])) + qerror = QuantumError(noise_ops) + qerror._id = error.get("id", None) or qerror.id + instruction_names = error["operations"] + all_gate_qubits = error.get("gate_qubits", None) + if all_gate_qubits is not None: + for gate_qubits in all_gate_qubits: + # Add local quantum error + noise_model.add_quantum_error( + qerror, instruction_names, gate_qubits, warnings=False + ) + else: + # Add all-qubit quantum error + noise_model.add_all_qubit_quantum_error( + qerror, instruction_names, warnings=False + ) + + # Add ReadoutError + elif error_type == "roerror": + probabilities = error["probabilities"] + all_gate_qubits = error.get("gate_qubits", None) + roerror = ReadoutError(probabilities) + # Add local readout error + if all_gate_qubits is not None: + for gate_qubits in all_gate_qubits: + noise_model.add_readout_error(roerror, gate_qubits, warnings=False) + # Add all-qubit readout error + else: + noise_model.add_all_qubit_readout_error(roerror, warnings=False) + # Invalid error type + else: + raise NoiseError("Invalid error type: {}".format(error_type)) + return noise_model + def _instruction_names_labels(self, instructions): """Return two lists of instruction name strings and label strings.""" if not isinstance(instructions, (list, tuple)): diff --git a/releasenotes/notes/revert_noise_from_dict-b3a85bf28582a9b1.yaml b/releasenotes/notes/revert_noise_from_dict-b3a85bf28582a9b1.yaml new file mode 100644 index 0000000000..0cd1bf54eb --- /dev/null +++ b/releasenotes/notes/revert_noise_from_dict-b3a85bf28582a9b1.yaml @@ -0,0 +1,5 @@ +--- +deprecations: + - | + Reverting NoiseModel.from_dict temporary to extend deprecation period + for qiskit-ibm-runtime, but we will remove again in the future release diff --git a/test/terra/noise/test_noise_model.py b/test/terra/noise/test_noise_model.py index 850e025192..892af7c9e7 100644 --- a/test/terra/noise/test_noise_model.py +++ b/test/terra/noise/test_noise_model.py @@ -21,7 +21,7 @@ from qiskit_aer.backends import AerSimulator from qiskit_aer.noise import NoiseModel from qiskit_aer.noise.device.models import _excited_population -from qiskit_aer.noise.errors import PauliError, PauliLindbladError +from qiskit_aer.noise.errors import QuantumError, PauliError, PauliLindbladError from qiskit_aer.noise.errors.standard_errors import amplitude_damping_error from qiskit_aer.noise.errors.standard_errors import kraus_error from qiskit_aer.noise.errors.standard_errors import pauli_error @@ -31,6 +31,8 @@ import qiskit from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.circuit.library.standard_gates import IGate, XGate +from qiskit.circuit.library.generalized_gates import PauliGate from qiskit.compiler import transpile from qiskit.transpiler import CouplingMap, Target from qiskit.providers import QubitProperties, BackendV2, Options @@ -416,6 +418,25 @@ def test_pauli_lindblad_error_sampling_equiv(self): probs2 = [counts2.get(i, 0) / shots for i in ["00", "01", "10", "11"]] np.testing.assert_allclose(probs1, probs2, atol=5e-2) + def test_from_dict(self): + noise_ops_1q = [((IGate(), [0]), 0.9), ((XGate(), [0]), 0.1)] + + noise_ops_2q = [ + ((PauliGate("II"), [0, 1]), 0.9), + ((PauliGate("IX"), [0, 1]), 0.045), + ((PauliGate("XI"), [0, 1]), 0.045), + ((PauliGate("XX"), [0, 1]), 0.01), + ] + + noise_model = NoiseModel() + with self.assertWarns(DeprecationWarning): + noise_model.add_quantum_error(QuantumError(noise_ops_1q), "h", [0]) + noise_model.add_quantum_error(QuantumError(noise_ops_1q), "h", [1]) + noise_model.add_quantum_error(QuantumError(noise_ops_2q), "cx", [0, 1]) + noise_model.add_quantum_error(QuantumError(noise_ops_2q), "cx", [1, 0]) + deserialized = NoiseModel.from_dict(noise_model.to_dict()) + self.assertEqual(noise_model, deserialized) + if __name__ == "__main__": unittest.main()