From da692e1fc5547d10d961d8fa279ac327b8f5d1c8 Mon Sep 17 00:00:00 2001 From: Christopher Wood Date: Mon, 31 Aug 2020 13:47:24 -0400 Subject: [PATCH] Add rotation gates to unitary simulator --- .../aer/backends/unitary_simulator.py | 264 +++------------ src/simulators/unitary/unitary_state.hpp | 320 ++++++++++-------- 2 files changed, 228 insertions(+), 356 deletions(-) diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index 137135aa3a..b3dddc36d1 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -11,7 +11,6 @@ # that they have been altered from the originals. # pylint: disable=invalid-name - """ Qiskit Aer Unitary Simulator Backend. """ @@ -75,225 +74,52 @@ class UnitarySimulator(AerBackend): performance (Default: 14). """ - MAX_QUBIT_MEMORY = int(log2(sqrt(local_hardware_info()['memory'] * (1024 ** 3) / 16))) + MAX_QUBIT_MEMORY = int( + log2(sqrt(local_hardware_info()['memory'] * (1024**3) / 16))) DEFAULT_CONFIGURATION = { - 'backend_name': 'unitary_simulator', - 'backend_version': __version__, - 'n_qubits': MAX_QUBIT_MEMORY, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'local': True, - 'conditional': False, - 'open_pulse': False, - 'memory': False, - 'max_shots': int(1e6), # Note that this backend will only ever - # perform a single shot. This value is just - # so that the default shot value for execute - # will not raise an error when trying to run - # a simulation - 'description': 'A C++ unitary simulator for QASM Qobj files', - 'coupling_map': None, + 'backend_name': + 'unitary_simulator', + 'backend_version': + __version__, + 'n_qubits': + MAX_QUBIT_MEMORY, + 'url': + 'https://github.com/Qiskit/qiskit-aer', + 'simulator': + True, + 'local': + True, + 'conditional': + False, + 'open_pulse': + False, + 'memory': + False, + 'max_shots': + int(1e6), # Note that this backend will only ever + # perform a single shot. This value is just + # so that the default shot value for execute + # will not raise an error when trying to run + # a simulation + 'description': + 'A C++ unitary simulator for QASM Qobj files', + 'coupling_map': + None, 'basis_gates': [ 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', - 't', 'tdg', 'swap', 'ccx', 'unitary', 'diagonal', 'cu1', 'cu2', - 'cu3', 'cswap', 'mcx', 'mcy', 'mcz', 'mcu1', 'mcu2', 'mcu3', - 'mcswap', 'multiplexer', + 't', 'tdg', 'swap', 'ccx', 'r', 'rx', 'ry', 'rz', 'rxx', 'ryy', + 'rzz', 'rzx', 'unitary', 'diagonal', 'cu1', 'cu2', + 'cu3', 'cswap', 'mcx', 'mcy', 'mcz', 'mcrx', 'mcry', 'mcrz', 'mcr', + 'mcu1', 'mcu2', 'mcu3', 'mcswap', 'multiplexer', 'kraus', 'roerror' ], - 'gates': [{ - 'name': 'u1', - 'parameters': ['lam'], - 'conditional': True, - 'description': 'Single-qubit gate [[1, 0], [0, exp(1j*lam)]]', - 'qasm_def': 'gate u1(lam) q { U(0,0,lam) q; }' - }, { - 'name': 'u2', - 'parameters': ['phi', 'lam'], - 'conditional': True, - 'description': - 'Single-qubit gate [[1, -exp(1j*lam)], [exp(1j*phi), exp(1j*(phi+lam))]]/sqrt(2)', - 'qasm_def': 'gate u2(phi,lam) q { U(pi/2,phi,lam) q; }' - }, { - 'name': - 'u3', - 'parameters': ['theta', 'phi', 'lam'], - 'conditional': - True, - 'description': - 'Single-qubit gate with three rotation angles', - 'qasm_def': - 'gate u3(theta,phi,lam) q { U(theta,phi,lam) q; }' - }, { - 'name': 'cx', - 'parameters': [], - 'conditional': True, - 'description': 'Two-qubit Controlled-NOT gate', - 'qasm_def': 'gate cx c,t { CX c,t; }' - }, { - 'name': 'cz', - 'parameters': [], - 'conditional': True, - 'description': 'Two-qubit Controlled-Z gate', - 'qasm_def': 'gate cz a,b { h b; cx a,b; h b; }' - }, { - 'name': 'id', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit identity gate', - 'qasm_def': 'gate id a { U(0,0,0) a; }' - }, { - 'name': 'x', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit Pauli-X gate', - 'qasm_def': 'gate x a { U(pi,0,pi) a; }' - }, { - 'name': 'y', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit Pauli-Y gate', - 'qasm_def': 'TODO' - }, { - 'name': 'z', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit Pauli-Z gate', - 'qasm_def': 'TODO' - }, { - 'name': 'h', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit Hadamard gate', - 'qasm_def': 'TODO' - }, { - 'name': 's', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit phase gate', - 'qasm_def': 'TODO' - }, { - 'name': 'sdg', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit adjoint phase gate', - 'qasm_def': 'TODO' - }, { - 'name': 't', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit T gate', - 'qasm_def': 'TODO' - }, { - 'name': 'tdg', - 'parameters': [], - 'conditional': True, - 'description': 'Single-qubit adjoint T gate', - 'qasm_def': 'TODO' - }, { - 'name': 'swap', - 'parameters': [], - 'conditional': True, - 'description': 'Two-qubit SWAP gate', - 'qasm_def': 'TODO' - }, { - 'name': 'ccx', - 'parameters': [], - 'conditional': True, - 'description': 'Three-qubit Toffoli gate', - 'qasm_def': 'TODO' - }, { - 'name': 'cswap', - 'parameters': [], - 'conditional': True, - 'description': 'Three-qubit Fredkin (controlled-SWAP) gate', - 'qasm_def': 'TODO' - }, { - 'name': 'unitary', - 'parameters': ['matrix'], - 'conditional': True, - 'description': 'N-qubit arbitrary unitary gate. ' - 'The parameter is the N-qubit matrix to apply.', - 'qasm_def': 'unitary(matrix) q1, q2,...' - }, { - 'name': 'diagonal', - 'parameters': ['diag_elements'], - 'conditional': True, - 'description': 'N-qubit diagonal unitary gate. The parameters are the' - ' diagonal entries of the N-qubit matrix to apply.', - 'qasm_def': 'TODO' - }, { - 'name': 'cu1', - 'parameters': ['lam'], - 'conditional': True, - 'description': 'Two-qubit Controlled-u1 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'cu2', - 'parameters': ['phi', 'lam'], - 'conditional': True, - 'description': 'Two-qubit Controlled-u2 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'cu3', - 'parameters': ['theta', 'phi', 'lam'], - 'conditional': True, - 'description': 'Two-qubit Controlled-u3 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcx', - 'parameters': [], - 'conditional': True, - 'description': 'N-qubit multi-controlled-X gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcy', - 'parameters': [], - 'conditional': True, - 'description': 'N-qubit multi-controlled-Y gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcz', - 'parameters': [], - 'conditional': True, - 'description': 'N-qubit multi-controlled-Z gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcu1', - 'parameters': ['lam'], - 'conditional': True, - 'description': 'N-qubit multi-controlled-u1 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcu2', - 'parameters': ['phi', 'lam'], - 'conditional': True, - 'description': 'N-qubit multi-controlled-u2 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcu3', - 'parameters': ['theta', 'phi', 'lam'], - 'conditional': True, - 'description': 'N-qubit multi-controlled-u3 gate', - 'qasm_def': 'TODO' - }, { - 'name': 'mcswap', - 'parameters': [], - 'conditional': True, - 'description': 'N-qubit multi-controlled-SWAP gate', - 'qasm_def': 'TODO' - }, { - 'name': 'multiplexer', - 'parameters': ['mat1', 'mat2', '...'], - 'conditional': True, - 'description': 'N-qubit multi-plexer gate. ' - 'The input parameters are the gates for each value.', - 'qasm_def': 'TODO' - }] + 'gates': [] } def __init__(self, configuration=None, provider=None): super().__init__(unitary_controller_execute, - QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), + QasmBackendConfiguration.from_dict( + self.DEFAULT_CONFIGURATION), provider=provider) def _validate(self, qobj, backend_options, noise_model): @@ -312,20 +138,20 @@ def _validate(self, qobj, backend_options, noise_model): if n_qubits > max_qubits: raise AerError( 'Number of qubits ({}) is greater than max ({}) for "{}" with {} GB system memory.' - .format(n_qubits, max_qubits, name, int(local_hardware_info()['memory']))) + .format(n_qubits, max_qubits, name, + int(local_hardware_info()['memory']))) if qobj.config.shots != 1: - logger.info('"%s" only supports 1 shot. Setting shots=1.', - name) + logger.info('"%s" only supports 1 shot. Setting shots=1.', name) qobj.config.shots = 1 for experiment in qobj.experiments: exp_name = experiment.header.name if getattr(experiment.config, 'shots', 1) != 1: - logger.info('"%s" only supports 1 shot. ' - 'Setting shots=1 for circuit "%s".', - name, exp_name) + logger.info( + '"%s" only supports 1 shot. ' + 'Setting shots=1 for circuit "%s".', name, exp_name) experiment.config.shots = 1 for operation in experiment.instructions: if operation.name in ['measure', 'reset']: raise AerError( - 'Unsupported {} instruction {} in circuit {}' - .format(name, operation.name, exp_name)) + 'Unsupported {} instruction {} in circuit {}'.format( + name, operation.name, exp_name)) diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index cedefd349d..72c52edf89 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -19,9 +19,9 @@ #define _USE_MATH_DEFINES #include -#include "simulators/state.hpp" #include "framework/json.hpp" #include "framework/utils.hpp" +#include "simulators/state.hpp" #include "unitarymatrix.hpp" #ifdef AER_THRUST_SUPPORTED #include "unitarymatrix_thrust.hpp" @@ -32,31 +32,41 @@ namespace QubitUnitary { // OpSet of supported instructions const Operations::OpSet StateOpSet( - // Op types - {Operations::OpType::gate, Operations::OpType::barrier, - Operations::OpType::matrix, Operations::OpType::diagonal_matrix, - Operations::OpType::snapshot}, - // Gates - {"u1", "u2", "u3", "cx", "cz", "cy", "cu1", - "cu2", "cu3", "swap", "id", "x", "y", "z", - "h", "s", "sdg", "t", "tdg", "ccx", "cswap", - "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap"}, - // Snapshots - {"unitary"} -); + // Op types + {Operations::OpType::gate, Operations::OpType::barrier, + Operations::OpType::matrix, Operations::OpType::diagonal_matrix, + Operations::OpType::snapshot}, + // Gates + {"u1", "u2", "u3", "cx", "cz", "cy", "cu1", "cu2", + "cu3", "swap", "id", "x", "y", "z", "h", "s", + "sdg", "t", "tdg", "ccx", "cswap", "mcx", "mcy", "mcz", + "mcu1", "mcu2", "mcu3", "mcswap", "r", "rx", "ry", "rz", + "rxx", "ryy", "rzz", "rzx", "mcr", "mcrx", "mcry", "mcrz"}, + // Snapshots + {"unitary"}); // Allowed gates enum class enum class Gates { + // 1-qubit id, h, s, sdg, t, - tdg, // single qubit + tdg, + // 2-qubit + rxx, + ryy, + rzz, + rzx, // multi-qubit controlled (including single-qubit non-controlled) mcx, mcy, mcz, + mcr, + mcrx, + mcry, + mcrz, mcu1, mcu2, mcu3, @@ -69,7 +79,7 @@ enum class Gates { template > class State : public Base::State { - public: +public: using BaseState = Base::State; State() : BaseState(StateOpSet) {} @@ -97,8 +107,9 @@ class State : public Base::State { // Returns the required memory for storing an n-qubit state in megabytes. // For this state the memory is indepdentent of the number of ops // and is approximately 16 * 1 << 2 * num_qubits bytes - virtual size_t required_memory_mb( - uint_t num_qubits, const std::vector &ops) const override; + virtual size_t + required_memory_mb(uint_t num_qubits, + const std::vector &ops) const override; // Load the threshold for applying OpenMP parallelization // if the controller/engine allows threads for it @@ -115,7 +126,7 @@ class State : public Base::State { // Initialize OpenMP settings for the underlying QubitVector class void initialize_omp(); - protected: +protected: //----------------------------------------------------------------------- // Apply Instructions //----------------------------------------------------------------------- @@ -173,38 +184,51 @@ class State : public Base::State { template const stringmap_t State::gateset_({ // Single qubit gates - {"id", Gates::id}, // Pauli-Identity gate - {"x", Gates::mcx}, // Pauli-X gate - {"y", Gates::mcy}, // Pauli-Y gate - {"z", Gates::mcz}, // Pauli-Z gate - {"s", Gates::s}, // Phase gate (aka sqrt(Z) gate) - {"sdg", Gates::sdg}, // Conjugate-transpose of Phase gate - {"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2)) - {"t", Gates::t}, // T-gate (sqrt(S)) - {"tdg", Gates::tdg}, // Conjguate-transpose of T gate + {"id", Gates::id}, // Pauli-Identity gate + {"x", Gates::mcx}, // Pauli-X gate + {"y", Gates::mcy}, // Pauli-Y gate + {"z", Gates::mcz}, // Pauli-Z gate + {"s", Gates::s}, // Phase gate (aka sqrt(Z) gate) + {"sdg", Gates::sdg}, // Conjugate-transpose of Phase gate + {"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2)) + {"t", Gates::t}, // T-gate (sqrt(S)) + {"tdg", Gates::tdg}, // Conjguate-transpose of T gate + // 1-qubit rotation Gates + {"r", Gates::mcr}, // R rotation gate + {"rx", Gates::mcrx}, // Pauli-X rotation gate + {"ry", Gates::mcry}, // Pauli-Y rotation gate + {"rz", Gates::mcrz}, // Pauli-Z rotation gate // Waltz Gates - {"u1", Gates::mcu1}, // zero-X90 pulse waltz gate - {"u2", Gates::mcu2}, // single-X90 pulse waltz gate - {"u3", Gates::mcu3}, // two X90 pulse waltz gate + {"u1", Gates::mcu1}, // zero-X90 pulse waltz gate + {"u2", Gates::mcu2}, // single-X90 pulse waltz gate + {"u3", Gates::mcu3}, // two X90 pulse waltz gate // Two-qubit gates - {"cx", Gates::mcx}, // Controlled-X gate (CNOT) - {"cy", Gates::mcy}, // Controlled-Z gate - {"cz", Gates::mcz}, // Controlled-Z gate - {"cu1", Gates::mcu1}, // Controlled-u1 gate - {"cu2", Gates::mcu2}, // Controlled-u2 - {"cu3", Gates::mcu3}, // Controlled-u3 gate - {"swap", Gates::mcswap}, // SWAP gate + {"cx", Gates::mcx}, // Controlled-X gate (CNOT) + {"cy", Gates::mcy}, // Controlled-Z gate + {"cz", Gates::mcz}, // Controlled-Z gate + {"cu1", Gates::mcu1}, // Controlled-u1 gate + {"cu2", Gates::mcu2}, // Controlled-u2 + {"cu3", Gates::mcu3}, // Controlled-u3 gate + {"swap", Gates::mcswap}, // SWAP gate + {"rxx", Gates::rxx}, // Pauli-XX rotation gate + {"ryy", Gates::ryy}, // Pauli-YY rotation gate + {"rzz", Gates::rzz}, // Pauli-ZZ rotation gate + {"rzx", Gates::rzx}, // Pauli-ZX rotation gate // Three-qubit gates - {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) - {"cswap", Gates::mcswap}, // Controlled-SWAP gate (Fredkin) + {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) + {"cswap", Gates::mcswap}, // Controlled-SWAP gate (Fredkin) // Multi-qubit controlled gates - {"mcx", Gates::mcx}, // Multi-controlled-X gate - {"mcy", Gates::mcy}, // Multi-controlled-Y gate - {"mcz", Gates::mcz}, // Multi-controlled-Z gate - {"mcu1", Gates::mcu1}, // Multi-controlled-u1 - {"mcu2", Gates::mcu2}, // Multi-controlled-u2 - {"mcu3", Gates::mcu3}, // Multi-controlled-u3 - {"mcswap", Gates::mcswap} // Multi-controlled-SWAP gate + {"mcx", Gates::mcx}, // Multi-controlled-X gate + {"mcy", Gates::mcy}, // Multi-controlled-Y gate + {"mcz", Gates::mcz}, // Multi-controlled-Z gate + {"mcr", Gates::mcr}, // Multi-controlled R-rotation gate + {"mcrx", Gates::mcrx}, // Multi-controlled X-rotation gate + {"mcry", Gates::mcry}, // Multi-controlled Y-rotation gate + {"mcrz", Gates::mcrz}, // Multi-controlled Z-rotation gate + {"mcu1", Gates::mcu1}, // Multi-controlled-u1 + {"mcu2", Gates::mcu2}, // Multi-controlled-u2 + {"mcu3", Gates::mcu3}, // Multi-controlled-u3 + {"mcswap", Gates::mcswap} // Multi-controlled-SWAP gate }); //============================================================================ @@ -212,30 +236,30 @@ const stringmap_t State::gateset_({ //============================================================================ template -void State::apply_ops( - const std::vector &ops, ExperimentData &data, - RngEngine &rng) { +void State::apply_ops(const std::vector &ops, + ExperimentData &data, RngEngine &rng) { // Simple loop over vector of input operations for (const auto &op : ops) { switch (op.type) { - case Operations::OpType::barrier: - break; - case Operations::OpType::gate: - // Note conditionals will always fail since no classical registers - if (BaseState::creg_.check_conditional(op)) apply_gate(op); - break; - case Operations::OpType::snapshot: - apply_snapshot(op, data); - break; - case Operations::OpType::matrix: - apply_matrix(op.qubits, op.mats[0]); - break; - case Operations::OpType::diagonal_matrix: - BaseState::qreg_.apply_diagonal_matrix(op.qubits, op.params); - break; - default: - throw std::invalid_argument( - "QubitUnitary::State::invalid instruction \'" + op.name + "\'."); + case Operations::OpType::barrier: + break; + case Operations::OpType::gate: + // Note conditionals will always fail since no classical registers + if (BaseState::creg_.check_conditional(op)) + apply_gate(op); + break; + case Operations::OpType::snapshot: + apply_snapshot(op, data); + break; + case Operations::OpType::matrix: + apply_matrix(op.qubits, op.mats[0]); + break; + case Operations::OpType::diagonal_matrix: + BaseState::qreg_.apply_diagonal_matrix(op.qubits, op.params); + break; + default: + throw std::invalid_argument( + "QubitUnitary::State::invalid instruction \'" + op.name + "\'."); } } } @@ -245,7 +269,7 @@ size_t State::required_memory_mb( uint_t num_qubits, const std::vector &ops) const { // An n-qubit unitary as 2^2n complex doubles // where each complex double is 16 bytes - (void)ops; // avoid unused variable compiler warning + (void)ops; // avoid unused variable compiler warning size_t shift_mb = std::max(0, num_qubits + 4 - 20); size_t mem_mb = 1ULL << (2 * shift_mb); return mem_mb; @@ -269,8 +293,8 @@ void State::initialize_qreg(uint_t num_qubits) { } template -void State::initialize_qreg( - uint_t num_qubits, const unitary_matrix_t &unitary) { +void State::initialize_qreg(uint_t num_qubits, + const unitary_matrix_t &unitary) { // Check dimension of state if (unitary.num_qubits() != num_qubits) { throw std::invalid_argument( @@ -284,8 +308,8 @@ void State::initialize_qreg( } template -void State::initialize_qreg( - uint_t num_qubits, const cmatrix_t &unitary) { +void State::initialize_qreg(uint_t num_qubits, + const cmatrix_t &unitary) { // Check dimension of unitary if (unitary.size() != 1ULL << (2 * num_qubits)) { throw std::invalid_argument( @@ -302,7 +326,7 @@ void State::initialize_omp() { BaseState::qreg_.set_omp_threshold(omp_qubit_threshold_); if (BaseState::threads_ > 0) BaseState::qreg_.set_omp_threads( - BaseState::threads_); // set allowed OMP threads in qubitvector + BaseState::threads_); // set allowed OMP threads in qubitvector } //========================================================================= @@ -318,66 +342,90 @@ void State::apply_gate(const Operations::Op &op) { op.name + "\'."); Gates g = it->second; switch (g) { - case Gates::mcx: - // Includes X, CX, CCX, etc - BaseState::qreg_.apply_mcx(op.qubits); - break; - case Gates::mcy: - // Includes Y, CY, CCY, etc - BaseState::qreg_.apply_mcy(op.qubits); - break; - case Gates::mcz: - // Includes Z, CZ, CCZ, etc - BaseState::qreg_.apply_mcphase(op.qubits, -1); - break; - case Gates::id: - break; - case Gates::h: - apply_gate_mcu3(op.qubits, M_PI / 2., 0., M_PI); - break; - case Gates::s: - apply_gate_phase(op.qubits[0], complex_t(0., 1.)); - break; - case Gates::sdg: - apply_gate_phase(op.qubits[0], complex_t(0., -1.)); - break; - case Gates::t: { - const double isqrt2{1. / std::sqrt(2)}; - apply_gate_phase(op.qubits[0], complex_t(isqrt2, isqrt2)); - } break; - case Gates::tdg: { - const double isqrt2{1. / std::sqrt(2)}; - apply_gate_phase(op.qubits[0], complex_t(isqrt2, -isqrt2)); - } break; - case Gates::mcswap: - // Includes SWAP, CSWAP, etc - BaseState::qreg_.apply_mcswap(op.qubits); - break; - case Gates::mcu3: - // Includes u3, cu3, etc - apply_gate_mcu3(op.qubits, std::real(op.params[0]), - std::real(op.params[1]), std::real(op.params[2])); - break; - case Gates::mcu2: - // Includes u2, cu2, etc - apply_gate_mcu3(op.qubits, M_PI / 2., std::real(op.params[0]), - std::real(op.params[1])); - break; - case Gates::mcu1: - // Includes u1, cu1, etc - BaseState::qreg_.apply_mcphase(op.qubits, - std::exp(complex_t(0, 1) * op.params[0])); - break; - default: - // We shouldn't reach here unless there is a bug in gateset - throw std::invalid_argument( - "Unitary::State::invalid gate instruction \'" + op.name + "\'."); + case Gates::mcx: + // Includes X, CX, CCX, etc + BaseState::qreg_.apply_mcx(op.qubits); + break; + case Gates::mcy: + // Includes Y, CY, CCY, etc + BaseState::qreg_.apply_mcy(op.qubits); + break; + case Gates::mcz: + // Includes Z, CZ, CCZ, etc + BaseState::qreg_.apply_mcphase(op.qubits, -1); + break; + case Gates::mcr: + BaseState::qreg_.apply_mcu(op.qubits, Linalg::VMatrix::r(op.params[0], op.params[1])); + break; + case Gates::mcrx: + BaseState::qreg_.apply_mcu(op.qubits, Linalg::VMatrix::rx(op.params[0])); + break; + case Gates::mcry: + BaseState::qreg_.apply_mcu(op.qubits, Linalg::VMatrix::ry(op.params[0])); + break; + case Gates::mcrz: + BaseState::qreg_.apply_mcu(op.qubits, Linalg::VMatrix::rz(op.params[0])); + break; + case Gates::rxx: + BaseState::qreg_.apply_matrix(op.qubits, Linalg::VMatrix::rxx(op.params[0])); + break; + case Gates::ryy: + BaseState::qreg_.apply_matrix(op.qubits, Linalg::VMatrix::ryy(op.params[0])); + break; + case Gates::rzz: + BaseState::qreg_.apply_diagonal_matrix(op.qubits, Linalg::VMatrix::rzz_diag(op.params[0])); + break; + case Gates::rzx: + BaseState::qreg_.apply_matrix(op.qubits, Linalg::VMatrix::rzx(op.params[0])); + break; + case Gates::id: + break; + case Gates::h: + apply_gate_mcu3(op.qubits, M_PI / 2., 0., M_PI); + break; + case Gates::s: + apply_gate_phase(op.qubits[0], complex_t(0., 1.)); + break; + case Gates::sdg: + apply_gate_phase(op.qubits[0], complex_t(0., -1.)); + break; + case Gates::t: { + const double isqrt2{1. / std::sqrt(2)}; + apply_gate_phase(op.qubits[0], complex_t(isqrt2, isqrt2)); + } break; + case Gates::tdg: { + const double isqrt2{1. / std::sqrt(2)}; + apply_gate_phase(op.qubits[0], complex_t(isqrt2, -isqrt2)); + } break; + case Gates::mcswap: + // Includes SWAP, CSWAP, etc + BaseState::qreg_.apply_mcswap(op.qubits); + break; + case Gates::mcu3: + // Includes u3, cu3, etc + apply_gate_mcu3(op.qubits, std::real(op.params[0]), std::real(op.params[1]), + std::real(op.params[2])); + break; + case Gates::mcu2: + // Includes u2, cu2, etc + apply_gate_mcu3(op.qubits, M_PI / 2., std::real(op.params[0]), + std::real(op.params[1])); + break; + case Gates::mcu1: + // Includes u1, cu1, etc + BaseState::qreg_.apply_mcphase(op.qubits, + std::exp(complex_t(0, 1) * op.params[0])); + break; + default: + // We shouldn't reach here unless there is a bug in gateset + throw std::invalid_argument("Unitary::State::invalid gate instruction \'" + + op.name + "\'."); } } template void State::apply_matrix(const reg_t &qubits, - const cmatrix_t &mat) { + const cmatrix_t &mat) { if (qubits.empty() == false && mat.size() > 0) { apply_matrix(qubits, Utils::vectorize_matrix(mat)); } @@ -385,7 +433,7 @@ void State::apply_matrix(const reg_t &qubits, template void State::apply_matrix(const reg_t &qubits, - const cvector_t &vmat) { + const cvector_t &vmat) { // Check if diagonal matrix if (vmat.size() == 1ULL << qubits.size()) { BaseState::qreg_.apply_diagonal_matrix(qubits, vmat); @@ -395,8 +443,7 @@ void State::apply_matrix(const reg_t &qubits, } template -void State::apply_gate_phase(uint_t qubit, - complex_t phase) { +void State::apply_gate_phase(uint_t qubit, complex_t phase) { cmatrix_t diag(1, 2); diag(0, 0) = 1.0; diag(0, 1) = phase; @@ -404,16 +451,15 @@ void State::apply_gate_phase(uint_t qubit, } template -void State::apply_gate_mcu3(const reg_t &qubits, - double theta, double phi, - double lambda) { +void State::apply_gate_mcu3(const reg_t &qubits, double theta, + double phi, double lambda) { const auto u3 = Linalg::Matrix::u3(theta, phi, lambda); BaseState::qreg_.apply_mcu(qubits, Utils::vectorize_matrix(u3)); } template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentData &data) { // Look for snapshot type in snapshotset if (op.name == "unitary" || op.name == "state") { data.add_pershot_snapshot("unitary", op.string_params[0], @@ -426,7 +472,7 @@ void State::apply_snapshot(const Operations::Op &op, } //------------------------------------------------------------------------------ -} // namespace QubitUnitary -} // end namespace AER +} // namespace QubitUnitary +} // end namespace AER //------------------------------------------------------------------------------ #endif