Skip to content

Commit

Permalink
Merge branch 'main' into add_test_for_result_serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
doichanj authored Oct 10, 2023
2 parents bb3ea81 + 94377f8 commit 248adb2
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 13 deletions.
24 changes: 21 additions & 3 deletions qiskit_aer/backends/aer_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,12 @@ def assemble_circuit(circuit: QuantumCircuit):
return aer_circ, index_map


def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg):
def _check_no_conditional(inst_name, conditional_reg):
if conditional_reg >= 0:
raise AerError(f"instruction {inst_name} does not support conditional")


def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg=-1):
operation = inst.operation
qubits = [qubit_indices[qubit] for qubit in inst.qubits]
clbits = [clbit_indices[clbit] for clbit in inst.clbits]
Expand Down Expand Up @@ -663,16 +668,18 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c
else:
aer_circ.measure(qubits, clbits, [])
elif name == "reset":
aer_circ.reset(qubits)
aer_circ.reset(qubits, conditional_reg)
elif name == "diagonal":
aer_circ.diagonal(qubits, params, label if label else "diagonal")
aer_circ.diagonal(qubits, params, conditional_reg, label if label else "diagonal")
elif name == "unitary":
aer_circ.unitary(qubits, params[0], conditional_reg, label if label else "unitary")
elif name == "pauli":
aer_circ.gate(name, qubits, [], params, conditional_reg, label if label else name)
elif name == "initialize":
_check_no_conditional(name, conditional_reg)
aer_circ.initialize(qubits, params)
elif name == "roerror":
_check_no_conditional(name, conditional_reg)
aer_circ.roerror(qubits, params)
elif name == "multiplexer":
aer_circ.multiplexer(qubits, params, conditional_reg, label if label else name)
Expand All @@ -691,10 +698,13 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c
"save_state",
"save_stabilizer",
}:
_check_no_conditional(name, conditional_reg)
aer_circ.save_state(qubits, name, operation._subtype, label if label else name)
elif name in {"save_amplitudes", "save_amplitudes_sq"}:
_check_no_conditional(name, conditional_reg)
aer_circ.save_amplitudes(qubits, name, params, operation._subtype, label if label else name)
elif name in ("save_expval", "save_expval_var"):
_check_no_conditional(name, conditional_reg)
paulis = []
coeff_reals = []
coeff_imags = []
Expand All @@ -712,24 +722,32 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c
label if label else name,
)
elif name == "set_statevector":
_check_no_conditional(name, conditional_reg)
aer_circ.set_statevector(qubits, params)
elif name == "set_unitary":
_check_no_conditional(name, conditional_reg)
aer_circ.set_unitary(qubits, params)
elif name == "set_density_matrix":
_check_no_conditional(name, conditional_reg)
aer_circ.set_density_matrix(qubits, params)
elif name == "set_stabilizer":
_check_no_conditional(name, conditional_reg)
aer_circ.set_clifford(qubits, params)
elif name == "set_superop":
_check_no_conditional(name, conditional_reg)
aer_circ.set_superop(qubits, params)
elif name == "set_matrix_product_state":
_check_no_conditional(name, conditional_reg)
aer_circ.set_matrix_product_state(qubits, params)
elif name == "superop":
aer_circ.superop(qubits, params[0], conditional_reg)
elif name == "barrier":
_check_no_conditional(name, conditional_reg)
num_of_aer_ops = 0
elif name == "jump":
aer_circ.jump(qubits, params, conditional_reg)
elif name == "mark":
_check_no_conditional(name, conditional_reg)
aer_circ.mark(qubits, params)
elif name == "qerror_loc":
aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg)
Expand Down
62 changes: 60 additions & 2 deletions qiskit_aer/noise/errors/quantum_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@

import numpy as np

from qiskit.circuit import QuantumCircuit, Instruction, QuantumRegister
from qiskit.circuit import QuantumCircuit, Instruction, QuantumRegister, Reset
from qiskit.circuit.exceptions import CircuitError
from qiskit.circuit.library.generalized_gates import PauliGate
from qiskit.circuit.library.standard_gates import IGate
from qiskit.circuit.library.standard_gates import IGate, XGate, YGate, ZGate
from qiskit.exceptions import QiskitError
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.quantum_info.operators.channel import Kraus, SuperOp
from qiskit.quantum_info.operators.channel.quantum_channel import QuantumChannel
from qiskit.quantum_info.operators.mixins import TolerancesMixin
from qiskit.quantum_info.operators.predicates import is_identity_matrix
from qiskit.quantum_info.operators.symplectic import Clifford
from qiskit.extensions import UnitaryGate
from ..noiseerror import NoiseError


Expand Down Expand Up @@ -345,6 +346,63 @@ def to_dict(self):
}
return error

@staticmethod
def from_dict(error):
"""Implement current error from a dictionary."""
# check if dictionary
if not isinstance(error, dict):
raise NoiseError("error is not a dictionary")
# check expected keys "type, id, operations, instructions, probabilities"
if (
("type" not in error)
or ("id" not in error)
or ("operations" not in error)
or ("instructions" not in error)
or ("probabilities" not in error)
):
raise NoiseError("erorr dictionary not containing expected keys")
error_instructions = error["instructions"]
error_probabilities = error["probabilities"]

if len(error_instructions) != len(error_probabilities):
raise NoiseError("probabilities not matching with instructions")
# parse instructions and turn to noise_ops
noise_ops = []
for idx, inst in enumerate(error_instructions):
noise_elem = []
for elem in inst:
inst_name = elem["name"]
inst_qubits = elem["qubits"]

if inst_name == "x":
noise_elem.append((XGate(), inst_qubits))
elif inst_name == "id":
noise_elem.append((IGate(), inst_qubits))
elif inst_name == "y":
noise_elem.append((YGate(), inst_qubits))
elif inst_name == "z":
noise_elem.append((ZGate(), inst_qubits))
elif inst_name == "kraus":
if "params" not in inst[0]:
raise NoiseError("kraus does not have a parameter value")
noise_elem.append((Kraus(inst[0]["params"]), inst_qubits))
elif inst_name == "reset":
noise_elem.append((Reset(), inst_qubits))
elif inst_name == "measure":
raise NoiseError("instruction 'measure' not supported")
elif inst_name == "unitary":
if "params" not in inst[0]:
raise NoiseError("unitary does not have a parameter value")
noise_elem.append((UnitaryGate(inst[0]["params"][0]), inst_qubits))
else:
raise NoiseError("error gate for instruction not recognized")

noise_ops.append((noise_elem, error_probabilities[idx]))

error_obj = QuantumError(noise_ops)

return error_obj

def compose(self, other, qargs=None, front=False):
if not isinstance(other, QuantumError):
other = QuantumError(other)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
Implements from_dict() method for QuantumError. This takes a dictionary
and checks if style is the one from to_dict() method. If any mismatches
are determined then NoiseError is raised. Else dict is parsed and a new
QuantumError with noise_ops created.
6 changes: 6 additions & 0 deletions releasenotes/notes/support_c_if_reset-1f0b8e84948fb3fc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
features:
- |
``c_if`` is supportted of ``reset`` instruction and an exception
is thrown if `c_if` is called for an instruction that does not
support ``c_if``.
8 changes: 4 additions & 4 deletions src/framework/circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ class Circuit {
}

void diagonal(const reg_t &qubits, const cvector_t &vec,
const std::string &label) {
ops.push_back(Operations::make_diagonal(qubits, vec, label));
const int_t cond_regidx = -1, const std::string label = "") {
ops.push_back(Operations::make_diagonal(qubits, vec, cond_regidx, label));
}

void unitary(const reg_t &qubits, const cmatrix_t &mat,
Expand Down Expand Up @@ -259,8 +259,8 @@ class Circuit {
ops.push_back(Operations::make_measure(qubits, memory, registers));
}

void reset(const reg_t &qubits) {
ops.push_back(Operations::make_reset(qubits));
void reset(const reg_t &qubits, const int_t cond_regidx = -1) {
ops.push_back(Operations::make_reset(qubits, cond_regidx));
}

private:
Expand Down
20 changes: 19 additions & 1 deletion src/framework/operations.hpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -468,27 +468,39 @@ inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat,
}

inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec,
const int_t conditional = -1,
const std::string label = "") {
Op op;
op.type = OpType::diagonal_matrix;
op.name = "diagonal";
op.qubits = qubits;
op.params = vec;

if (conditional >= 0) {
op.conditional = true;
op.conditional_reg = conditional;
}

if (label != "")
op.string_params = {label};

return op;
}

inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec,
const int_t conditional = -1,
const std::string label = "") {
Op op;
op.type = OpType::diagonal_matrix;
op.name = "diagonal";
op.qubits = qubits;
op.params = std::move(vec);

if (conditional >= 0) {
op.conditional = true;
op.conditional_reg = conditional;
}

if (label != "")
op.string_params = {label};

Expand Down Expand Up @@ -658,11 +670,17 @@ inline Op make_u3(uint_t qubit, T theta, T phi, T lam) {
return op;
}

inline Op make_reset(const reg_t &qubits, uint_t state = 0) {
inline Op make_reset(const reg_t &qubits, const int_t conditional) {
Op op;
op.type = OpType::reset;
op.name = "reset";
op.qubits = qubits;

if (conditional >= 0) {
op.conditional = true;
op.conditional_reg = conditional;
}

return op;
}

Expand Down
4 changes: 2 additions & 2 deletions src/transpile/fusion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class FusionMethod {
for (size_t i = 0; i < vec.size(); ++i)
vec[i] = fusioned_op.mats[0](i, i);
fusioned_op = Operations::make_diagonal(
fusioned_op.qubits, std::move(vec), std::string("fusion"));
fusioned_op.qubits, std::move(vec), -1, std::string("fusion"));
}
} else {
// loop for runtime parameter binding
Expand All @@ -83,7 +83,7 @@ class FusionMethod {
vec.assign((1UL << new_op.qubits.size()), 0);
for (size_t i = 0; i < vec.size(); ++i)
vec[i] = new_op.mats[0](i, i);
new_op = Operations::make_diagonal(new_op.qubits, std::move(vec),
new_op = Operations::make_diagonal(new_op.qubits, std::move(vec), -1,
std::string("fusion"));
}

Expand Down
70 changes: 70 additions & 0 deletions test/terra/backends/aer_simulator/test_conditional.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from test.terra.reference import ref_conditionals
from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods

from qiskit import QuantumCircuit


@ddt
class TestConditionalGates(SimulatorTestCase):
Expand Down Expand Up @@ -310,3 +312,71 @@ def test_conditional_superop_132bit(self, method, device):
result = backend.run(circuits, shots=shots).result()
self.assertSuccess(result)
self.compare_counts(result, circuits, targets, hex_counts=False, delta=0)


@ddt
class TestConditionalReset(SimulatorTestCase):
"""AerSimulator conditional reset tests."""

SUPPORTED_METHODS = [
"automatic",
"statevector",
"density_matrix",
"matrix_product_state",
"tensor_network",
]

# ---------------------------------------------------------------------
# Test conditional
# ---------------------------------------------------------------------
@supported_methods(SUPPORTED_METHODS)
def test_conditional_reset_1bit(self, method, device):
"""Test conditional reset on 1-bit conditional register."""
shots = 100
backend = self.backend(method=method, device=device)
backend.set_options(max_parallel_experiments=0)

circuits = ref_conditionals.conditional_circuits_1bit(
final_measure=True, conditional_type="reset"
)
targets = ref_conditionals.conditional_counts_1bit_with_reset(shots)
result = backend.run(circuits, shots=shots).result()
self.assertSuccess(result)
self.compare_counts(result, circuits, targets, delta=0)


@ddt
class TestConditionalDiagonal(SimulatorTestCase):
"""AerSimulator conditional diagonal tests."""

# ---------------------------------------------------------------------
# Test conditional
# ---------------------------------------------------------------------
def test_conditional_diagonal(self):
"""Test conditional diagonal with statevector."""
shots = 100
backend = self.backend(method="statevector", device="CPU")
backend.set_options(max_parallel_experiments=0)

circuit = QuantumCircuit(4, 4)
for i in range(1, 4):
circuit.h(i)
circuit.save_statevector(label="base")

circuit0 = QuantumCircuit(4, 4)
for i in range(1, 4):
circuit0.h(i)
circuit0.diagonal([-1, -1], [1]).c_if(circuit0.clbits[0], 0)
circuit0.save_statevector(label="diff")

circuit1 = QuantumCircuit(4, 4)
for i in range(1, 4):
circuit1.h(i)
circuit1.diagonal([-1, -1], [1]).c_if(circuit1.clbits[0], 1)
circuit1.save_statevector(label="equal")

result = backend.run([circuit, circuit0, circuit1], shots=1).result()
self.assertSuccess(result)

self.assertNotEqual(result.data(circuit)["base"], result.data(circuit0)["diff"])
self.assertEqual(result.data(circuit)["base"], result.data(circuit1)["equal"])
Loading

0 comments on commit 248adb2

Please sign in to comment.