diff --git a/qiskit_aer/backends/aer_compiler.py b/qiskit_aer/backends/aer_compiler.py index 69fba997f6..f1a8079d24 100644 --- a/qiskit_aer/backends/aer_compiler.py +++ b/qiskit_aer/backends/aer_compiler.py @@ -19,6 +19,7 @@ from typing import List from warnings import warn from concurrent.futures import Executor +import uuid import numpy as np from qiskit.circuit import QuantumCircuit, Clbit, ClassicalRegister, ParameterExpression @@ -27,6 +28,7 @@ from qiskit.circuit.library import Initialize from qiskit.providers.options import Options from qiskit.pulse import Schedule, ScheduleBlock +from qiskit.circuit import Store from qiskit.circuit.controlflow import ( WhileLoopOp, ForLoopOp, @@ -61,7 +63,7 @@ ) from .backend_utils import circuit_optypes -from ..library.control_flow_instructions import AerMark, AerJump +from ..library.control_flow_instructions import AerMark, AerJump, AerStore class AerCompiler: @@ -100,7 +102,9 @@ def compile(self, circuits, optypes=None): if self._is_dynamic(circuit, compiled_optypes[idx]): pm = PassManager([Decompose(["mark", "jump"])]) compiled_circ = pm.run(self._inline_circuit(circuit, None, None)) - + # compiled_circ._vars_local = inlined_circ._vars_local + # compiled_circ._vars_input = inlined_circ._vars_input + # compiled_circ._vars_capture = inlined_circ._vars_capture compiled_circuits.append(compiled_circ) # Recompute optype for compiled circuit compiled_optypes[idx] = circuit_optypes(compiled_circ) @@ -210,6 +214,12 @@ def _inline_circuit(self, circ, continue_label, break_label, bit_map=None): ret._append( AerJump(continue_label, ret.num_qubits, ret.num_clbits), ret.qubits, ret.clbits ) + elif isinstance(instruction.operation, Store): + ret._append( + AerStore(ret.num_qubits, ret.num_clbits, instruction.operation), + ret.qubits, + ret.clbits, + ) else: ret._append(instruction) return ret @@ -647,7 +657,7 @@ def assemble_circuit(circuit: QuantumCircuit, basis_gates=None): num_qubits = circuit.num_qubits num_memory = circuit.num_clbits - max_conditional_idx = 0 + extra_creg_idx = 0 qreg_sizes = [] creg_sizes = [] @@ -688,6 +698,12 @@ def assemble_circuit(circuit: QuantumCircuit, basis_gates=None): aer_circ.num_memory = num_memory aer_circ.global_phase_angle = global_phase + var_heap_map = {} + for var in _iter_var_recursive(circuit): + memory_pos = num_memory + extra_creg_idx + var_heap_map[var.name] = (memory_pos, var.type.width) + extra_creg_idx += var.type.width + num_of_aer_ops = 0 index_map = [] for inst in circuit.data: @@ -708,10 +724,10 @@ def assemble_circuit(circuit: QuantumCircuit, basis_gates=None): if clbit in ctrl_reg: mask |= 1 << idx val |= ((ctrl_val >> list(ctrl_reg).index(clbit)) & 1) << idx - conditional_reg = num_memory + max_conditional_idx + conditional_reg = num_memory + extra_creg_idx aer_circ.bfunc(f"0x{mask:X}", f"0x{val:X}", "==", conditional_reg) num_of_aer_ops += 1 - max_conditional_idx += 1 + extra_creg_idx += 1 elif hasattr(inst.operation, "condition_expr") and inst.operation.condition_expr: conditional_expr = inst.operation.condition_expr @@ -740,11 +756,30 @@ def _assemble_type(expr_type): raise AerError(f"unknown type: {expr_type.__class__}") +def _iter_var_recursive(circuit): + yield from circuit.iter_vars() + for data in circuit.data: + for param in data[0].params: + if isinstance(param, QuantumCircuit): + yield from _iter_var_recursive(param) + + +def _find_var_clbits(circuit, var_uuid): + clbit_index = circuit.num_clbits + for var in _iter_var_recursive(circuit): + if var.var == var_uuid: + return list(range(clbit_index, clbit_index + var.type.width)) + clbit_index += var.type.width + raise AerError(f"Var is not registed in this circuit: uuid={var_uuid}") + + def _assemble_clbit_indices(circ, c): if isinstance(c, (ClassicalRegister, list)): return [circ.find_bit(cbit).index for cbit in c] elif isinstance(c, Clbit): return [circ.find_bit(c).index] + elif isinstance(c, uuid.UUID): + return _find_var_clbits(circ, c) else: raise AerError(f"unknown clibt list: {c.__class__}") @@ -981,7 +1016,18 @@ def _assemble_op( raise AerError( "control-flow instructions must be converted " f"to jump and mark instructions: {name}" ) - + elif name == "aer_store": + if not isinstance(operation.store.lvalue, Var): + raise AerError(f"unsupported lvalue : {operation.store.lvalue.__class__}") + aer_circ.store(qubits, _assemble_clbit_indices(circ, operation.store.lvalue.var), + operation.store.rvalue.accept(_AssembleExprImpl(circ))) + num_of_aer_ops = 1 + elif name == "store": + if not isinstance(operation.lvalue, Var): + raise AerError(f"unsupported lvalue : {operation.lvalue.__class__}") + aer_circ.store(qubits, _assemble_clbit_indices(circ, operation.lvalue.var), + operation.rvalue.accept(_AssembleExprImpl(circ))) + num_of_aer_ops = 1 else: raise AerError(f"unknown instruction: {name}") diff --git a/qiskit_aer/backends/backend_utils.py b/qiskit_aer/backends/backend_utils.py index a030578b6c..af66c8c8bd 100644 --- a/qiskit_aer/backends/backend_utils.py +++ b/qiskit_aer/backends/backend_utils.py @@ -117,6 +117,7 @@ "pauli", "mcx_gray", "ecr", + "store", ] ), "density_matrix": sorted( @@ -198,6 +199,7 @@ "diagonal", "initialize", "ecr", + "store", ] ), "stabilizer": sorted( @@ -218,6 +220,7 @@ "pauli", "ecr", "rz", + "store", ] ), "extended_stabilizer": sorted( @@ -244,6 +247,7 @@ "pauli", "ecr", "rz", + "store", ] ), "unitary": sorted( @@ -308,6 +312,7 @@ "multiplexer", "pauli", "ecr", + "store", ] ), "superop": sorted( @@ -346,6 +351,7 @@ "unitary", "diagonal", "pauli", + "store", ] ), "tensor_network": sorted( @@ -412,6 +418,7 @@ "pauli", "mcx_gray", "ecr", + "store", ] ), } diff --git a/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp b/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp index 943f579693..7994b60e1d 100644 --- a/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp +++ b/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp @@ -193,6 +193,7 @@ void bind_aer_circuit(MODULE m) { aer_circuit.def("measure", &Circuit::measure); aer_circuit.def("reset", &Circuit::reset); aer_circuit.def("set_qerror_loc", &Circuit::set_qerror_loc); + aer_circuit.def("store", &Circuit::store); } #endif \ No newline at end of file diff --git a/qiskit_aer/library/control_flow_instructions/__init__.py b/qiskit_aer/library/control_flow_instructions/__init__.py index 4d373be5bd..ccc98ffa9a 100644 --- a/qiskit_aer/library/control_flow_instructions/__init__.py +++ b/qiskit_aer/library/control_flow_instructions/__init__.py @@ -13,3 +13,4 @@ from .jump import AerJump from .mark import AerMark +from .store import AerStore diff --git a/qiskit_aer/library/control_flow_instructions/store.py b/qiskit_aer/library/control_flow_instructions/store.py new file mode 100644 index 0000000000..b0af8a348b --- /dev/null +++ b/qiskit_aer/library/control_flow_instructions/store.py @@ -0,0 +1,29 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Simulator instruction to set a program counter +""" + +from qiskit.circuit import Instruction + + +class AerStore(Instruction): + """ + Store instruction for Aer to work wround transpilation issue + of qiskit.circuit.Store + """ + + _directive = True + + def __init__(self, num_qubits, num_clbits, store): + super().__init__("aer_store", num_qubits, num_clbits, [store.lvalue, store.rvalue]) + self.store = store diff --git a/releasenotes/notes/add_var_storage-99ec3509828754d4.yaml b/releasenotes/notes/add_var_storage-99ec3509828754d4.yaml new file mode 100644 index 0000000000..0a92ac3caf --- /dev/null +++ b/releasenotes/notes/add_var_storage-99ec3509828754d4.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Enable new control flow introduced in Qiskit 1.1. ``store`` instructions are + newly available since Qiskit 1.1 and Aer failed if this instruction is in a circuit. + This PR enables ``store`` and its simulation. diff --git a/src/framework/circuit.hpp b/src/framework/circuit.hpp index 35e79e7b2b..44540e6f18 100644 --- a/src/framework/circuit.hpp +++ b/src/framework/circuit.hpp @@ -275,6 +275,11 @@ class Circuit { ops.push_back(Operations::make_reset(qubits, cond_regidx)); } + void store(const reg_t &qubits, const reg_t &clbits, + const std::shared_ptr expr) { + ops.push_back(Operations::make_store(qubits, clbits, expr)); + } + private: Operations::OpSet opset_; // Set of operation types contained in circuit std::set qubitset_; // Set of qubits used in the circuit @@ -450,6 +455,12 @@ void Circuit::set_params(bool truncation) { const auto &op = ops[rpos]; if (op.type == OpType::mark && last_ancestor_pos == 0) last_ancestor_pos = rpos; + if (op.type == OpType::store) { + // Conservertively OpType::store does not allow sampling + can_sample = false; + if (last_ancestor_pos == 0) + last_ancestor_pos = rpos; + } if (!truncation || check_result_ancestor(op, ancestor_qubits)) { add_op_metadata(op); ancestor[rpos] = true; @@ -571,7 +582,7 @@ void Circuit::set_params(bool truncation) { } for (size_t pos = 0; pos < head_end; ++pos) { if (ops_to_remove && !ancestor[pos] && ops[pos].type != OpType::mark && - ops[pos].type != OpType::jump) { + ops[pos].type != OpType::jump && ops[pos].type != OpType::store) { // Skip if not ancestor continue; } @@ -675,7 +686,8 @@ bool Circuit::check_result_ancestor( case OpType::save_clifford: case OpType::save_unitary: case OpType::save_mps: - case OpType::save_superop: { + case OpType::save_superop: + case OpType::store: { ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); return true; } diff --git a/src/framework/creg.hpp b/src/framework/creg.hpp index b9c93d3a06..3a05960a71 100644 --- a/src/framework/creg.hpp +++ b/src/framework/creg.hpp @@ -76,6 +76,9 @@ class ClassicalRegister { // Apply readout error instruction to classical registers void apply_roerror(const Operations::Op &op, RngEngine &rng); + // Apply store instruction to classical registers + void apply_store(const Operations::Op &op); + // Store a measurement outcome in the specified memory and register bit // locations void store_measure(const reg_t &outcome, const reg_t &memory, @@ -258,6 +261,36 @@ void ClassicalRegister::apply_roerror(const Operations::Op &op, } } +// Apply store instruction to classical registers +void ClassicalRegister::apply_store(const Operations::Op &op) { + const auto ®isters = op.registers; + const auto &expr = op.expr; + + uint_t outcome = 0ULL; + if (expr->type->type == Operations::ValueType::Bool) { + outcome = op.expr->eval_bool(creg_memory_) ? 1ULL : 0ULL; + } else if (expr->type->type == Operations::ValueType::Uint) { + outcome = op.expr->eval_uint(creg_memory_); + } + + reg_t memory; + reg_t memory_output; + + for (size_t i = 0; i < registers.size(); i++) { + uint_t val = (outcome & 1ULL); // 0 or 1 + char val_char = val ? '1' : '0'; + outcome >>= 1; + if (registers[i] < creg_memory_.size()) { + memory.push_back(registers[i]); + memory_output.push_back(val); + } + const size_t pos = creg_register_.size() - registers[i] - 1; + creg_register_[pos] = val_char; // int->string->char + } + + store_measure(memory_output, memory, reg_t()); +} + //------------------------------------------------------------------------------ } // end namespace AER //------------------------------------------------------------------------------ diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 108b008e35..c8e0523a59 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -410,7 +410,8 @@ enum class OpType { jump, mark, unary_expr, - binary_expr + binary_expr, + store }; enum class DataSubType { @@ -555,6 +556,9 @@ inline std::ostream &operator<<(std::ostream &stream, const OpType &type) { case OpType::binary_expr: stream << "binary_expr"; break; + case OpType::store: + stream << "store"; + break; default: stream << "unknown"; } @@ -1033,6 +1037,17 @@ inline Op make_reset(const reg_t &qubits, const int_t conditional) { return op; } +inline Op make_store(const reg_t &qubits, const reg_t &clbits, + const std::shared_ptr expr) { + Op op; + op.type = OpType::store; + op.name = "store"; + op.qubits = qubits; + op.registers = clbits; + op.expr = expr; + return op; +} + inline Op make_multiplexer(const reg_t &qubits, const std::vector &mats, const int_t conditional = -1, diff --git a/src/simulators/circuit_executor.hpp b/src/simulators/circuit_executor.hpp index b30dba9751..39f9a62cff 100644 --- a/src/simulators/circuit_executor.hpp +++ b/src/simulators/circuit_executor.hpp @@ -1324,7 +1324,8 @@ bool Executor::check_measure_sampling_opt(const Circuit &circ) const { circ.opset().contains(Operations::OpType::kraus) || circ.opset().contains(Operations::OpType::superop) || circ.opset().contains(Operations::OpType::jump) || - circ.opset().contains(Operations::OpType::mark)) { + circ.opset().contains(Operations::OpType::mark) || + circ.opset().contains(Operations::OpType::store)) { return false; } // Otherwise true diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index e8b9d9c7cb..4300fed0db 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -45,7 +45,7 @@ const Operations::OpSet StateOpSet( OpType::set_densmat, OpType::save_expval, OpType::save_expval_var, OpType::save_densmat, OpType::save_probs, OpType::save_probs_ket, OpType::save_amps_sq, OpType::save_state, OpType::jump, - OpType::mark}, + OpType::mark, OpType::store}, // Gates {"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx", diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 1cfeb9b43d..d4b540d6a1 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -47,38 +47,25 @@ static uint_t instruction_number = 0; using OpType = Operations::OpType; +// clang-format off // OpSet of supported instructions const Operations::OpSet StateOpSet( - {OpType::gate, - OpType::measure, - OpType::reset, - OpType::initialize, - OpType::barrier, - OpType::bfunc, - OpType::roerror, - OpType::qerror_loc, - OpType::matrix, - OpType::diagonal_matrix, - OpType::kraus, - OpType::save_expval, - OpType::save_expval_var, - OpType::save_densmat, - OpType::save_statevec, - OpType::save_probs, - OpType::save_probs_ket, - OpType::save_amps, - OpType::save_amps_sq, - OpType::save_mps, - OpType::save_state, - OpType::set_mps, - OpType::set_statevec, - OpType::jump, - OpType::mark}, + // Op types + {OpType::gate, OpType::measure, OpType::reset, + OpType::initialize, OpType::barrier, OpType::bfunc, + OpType::roerror, OpType::qerror_loc, OpType::matrix, + OpType::diagonal_matrix, OpType::kraus, OpType::save_expval, + OpType::save_expval_var, OpType::save_densmat, OpType::save_statevec, + OpType::save_probs, OpType::save_probs_ket, OpType::save_amps, + OpType::save_amps_sq, OpType::save_mps, OpType::save_state, + OpType::set_mps, OpType::set_statevec, OpType::jump, + OpType::mark, OpType::store}, // Gates {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", "u1", "u2", "u3", "u", "U", "CX", "cx", "cy", "cz", "cp", "cu1", "swap", "ccx", "sx", "sxdg", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", "csx", "delay", "cswap", "pauli", "ecr"}); +// clang-format on //========================================================================= // Matrix Product State subclass diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index ab6805ec25..cf63648b1b 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -140,6 +140,9 @@ class Branch { } iter_++; return true; + } else if (iter_->type == Operations::OpType::store) { + creg.apply_store(*last); + return true; } return false; } diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index abb7cf386c..682ffee6ff 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -29,17 +29,21 @@ namespace Stabilizer { //============================================================================ using OpType = Operations::OpType; +// clang-format off // OpSet of supported instructions const Operations::OpSet StateOpSet( // Op types - {OpType::gate, OpType::measure, OpType::reset, OpType::barrier, - OpType::bfunc, OpType::qerror_loc, OpType::roerror, OpType::save_expval, - OpType::save_expval_var, OpType::save_probs, OpType::save_probs_ket, - OpType::save_amps_sq, OpType::save_stabilizer, OpType::save_clifford, - OpType::save_state, OpType::set_stabilizer, OpType::jump, OpType::mark}, + { OpType::gate, OpType::measure, OpType::reset, + OpType::barrier, OpType::bfunc, OpType::qerror_loc, + OpType::roerror, OpType::save_expval, OpType::save_expval_var, + OpType::save_probs, OpType::save_probs_ket, OpType::save_amps_sq, + OpType::save_stabilizer, OpType::save_clifford, OpType::save_state, + OpType::set_stabilizer, OpType::jump, OpType::mark, + OpType::store}, // Gates {"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", "delay", "pauli", "ecr", "rz"}); +// clang-format on enum class Gates { id, diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index e0aba472b2..98b717222a 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -328,6 +328,10 @@ void Base::apply_ops(const OpItr first, const OpItr last, } break; } + case Operations::OpType::store: { + creg().apply_store(*it); + break; + } default: { apply_op(*it, result, rng, final_ops && (it + 1 == last)); } diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 2da7726468..7ea03ebdd3 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -36,35 +36,19 @@ namespace Statevector { using OpType = Operations::OpType; +// clang-format off // OpSet of supported instructions const Operations::OpSet StateOpSet( // Op types - {OpType::gate, - OpType::measure, - OpType::reset, - OpType::initialize, - OpType::barrier, - OpType::bfunc, - OpType::roerror, - OpType::matrix, - OpType::diagonal_matrix, - OpType::multiplexer, - OpType::kraus, - OpType::qerror_loc, - OpType::sim_op, - OpType::set_statevec, - OpType::save_expval, - OpType::save_expval_var, - OpType::save_probs, - OpType::save_probs_ket, - OpType::save_amps, - OpType::save_amps_sq, - OpType::save_state, - OpType::save_statevec, - OpType::save_statevec_dict, - OpType::save_densmat, - OpType::jump, - OpType::mark}, + { OpType::gate, OpType::measure, OpType::reset, + OpType::initialize, OpType::barrier, OpType::bfunc, + OpType::roerror, OpType::matrix, OpType::diagonal_matrix, + OpType::multiplexer, OpType::kraus, OpType::qerror_loc, + OpType::sim_op, OpType::set_statevec, OpType::save_expval, + OpType::save_expval_var, OpType::save_probs, OpType::save_probs_ket, + OpType::save_amps, OpType::save_amps_sq, OpType::save_state, + OpType::save_statevec, OpType::save_statevec_dict, OpType::save_densmat, + OpType::jump, OpType::mark, OpType::store}, // Gates { "u1", "u2", "u3", "u", "U", "CX", "cx", @@ -77,6 +61,7 @@ const Operations::OpSet StateOpSet( "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu", "mcu", "mcp", "ecr", "mcphase", "crx", "cry", "crz", }); +// clang-format on // Allowed gates enum class enum class Gates { diff --git a/src/simulators/superoperator/superoperator_state.hpp b/src/simulators/superoperator/superoperator_state.hpp index 9d39de77d1..c70a149847 100644 --- a/src/simulators/superoperator/superoperator_state.hpp +++ b/src/simulators/superoperator/superoperator_state.hpp @@ -41,7 +41,8 @@ const Operations::OpSet StateOpSet( Operations::OpType::kraus, Operations::OpType::superop, Operations::OpType::save_state, Operations::OpType::save_superop, Operations::OpType::set_unitary, Operations::OpType::set_superop, - Operations::OpType::jump, Operations::OpType::mark}, + Operations::OpType::jump, Operations::OpType::mark, + Operations::OpType::store}, // Gates {"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx", diff --git a/src/simulators/tensor_network/tensor_net_state.hpp b/src/simulators/tensor_network/tensor_net_state.hpp index d8524dfe25..37138420c6 100644 --- a/src/simulators/tensor_network/tensor_net_state.hpp +++ b/src/simulators/tensor_network/tensor_net_state.hpp @@ -34,37 +34,20 @@ namespace TensorNetwork { using OpType = Operations::OpType; +// clang-format off // OpSet of supported instructions const Operations::OpSet StateOpSet( // Op types - {OpType::gate, - OpType::measure, - OpType::reset, - OpType::initialize, - OpType::barrier, - OpType::bfunc, - OpType::roerror, - OpType::matrix, - OpType::diagonal_matrix, - OpType::multiplexer, - OpType::kraus, - OpType::superop, - OpType::qerror_loc, - OpType::sim_op, - OpType::set_statevec, - OpType::set_densmat, - OpType::save_expval, - OpType::save_expval_var, - OpType::save_probs, - OpType::save_probs_ket, - OpType::save_amps, - OpType::save_amps_sq, - OpType::save_state, - OpType::save_statevec, - OpType::save_statevec_dict, - OpType::save_densmat, - OpType::jump, - OpType::mark}, + { OpType::gate, OpType::measure, OpType::reset, + OpType::initialize, OpType::barrier, OpType::bfunc, + OpType::roerror, OpType::matrix, OpType::diagonal_matrix, + OpType::multiplexer, OpType::kraus, OpType::superop, + OpType::qerror_loc, OpType::sim_op, OpType::set_statevec, + OpType::set_densmat, OpType::save_expval, OpType::save_expval_var, + OpType::save_probs, OpType::save_probs_ket, OpType::save_amps, + OpType::save_amps_sq, OpType::save_state, OpType::save_statevec, + OpType::save_statevec_dict, OpType::save_densmat, OpType::jump, + OpType::mark, OpType::store}, // Gates {"u1", "u2", "u3", "u", "U", "CX", "cx", "cz", "cy", "cp", "cu1", "cu2", "cu3", "swap", @@ -75,6 +58,7 @@ const Operations::OpSet StateOpSet( "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", "csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu", "mcu", "mcp", "ecr", "cswap", "crx", "cry", "crz"}); +// clang-format on // Allowed gates enum class enum class Gates { diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index 3c3ba3d2af..11b6700133 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -39,7 +39,8 @@ const Operations::OpSet StateOpSet( Operations::OpType::qerror_loc, Operations::OpType::matrix, Operations::OpType::diagonal_matrix, Operations::OpType::save_unitary, Operations::OpType::save_state, Operations::OpType::set_unitary, - Operations::OpType::jump, Operations::OpType::mark}, + Operations::OpType::jump, Operations::OpType::mark, + Operations::OpType::store}, // Gates { "u1", "u2", "u3", "u", "U", "CX", "cx", "cz", diff --git a/test/terra/backends/aer_simulator/test_control_flow.py b/test/terra/backends/aer_simulator/test_control_flow.py index 0b5e06301c..9bb9f989c8 100644 --- a/test/terra/backends/aer_simulator/test_control_flow.py +++ b/test/terra/backends/aer_simulator/test_control_flow.py @@ -1280,6 +1280,69 @@ def test_bit_not_operation(self, method): self.assertEqual(len(counts), 1) self.assertIn("0010101", counts) + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_store_simple(self, method): + """test store operation""" + backend = self.backend(method=method) + + # Check stored values can be sampled + qr = QuantumRegister(4) + cr = ClassicalRegister(4) + qc = QuantumCircuit(qr, cr) + qc.x(2) + qc.measure(range(4), range(4)) + qc.store(cr, 0b1000) # measured classical registers are modified + + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("1000", counts) + + # Check stored values to creg can be evaluated + qr = QuantumRegister(4) + cr = ClassicalRegister(4) + qc = QuantumCircuit(qr, cr) + qc.x(2) + qc.measure(range(4), range(4)) + qc.store(cr, 0b1000) # override + with qc.if_test((2, False)): + # must reach + qc.x(1) # 0b1010 + qc.measure(range(4), range(4)) + + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0110", counts) + + # Check stored values to clbit can be evaluated + qr = QuantumRegister(4) + cr = ClassicalRegister(4) + qc = QuantumCircuit(qr, cr) + qc.x(2) + qc.measure(range(4), range(4)) + qc.store(cr[2], False) # override + with qc.if_test((2, False)): + # must reach + qc.x(1) # 0b1010 + qc.measure(range(4), range(4)) + + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0110", counts) + + # Check stored values can be stored + qr = QuantumRegister(4) + cr0 = ClassicalRegister(4) + cr1 = ClassicalRegister(4) + qc = QuantumCircuit(qr, cr0, cr1) + qc.x(2) + qc.measure(range(4), range(4)) + qc.store(cr0, 0b1000) # measured classical registers are modified + qc.store(cr1, cr0) # measured classical registers are modified + + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("1000 1000", counts) + def test_bit_mapping_in_compiler(self): """Test different bit mappings are correctly inlined""" parent = QuantumCircuit(5, 2)