diff --git a/scaluq/gate/gate_matrix.hpp b/scaluq/gate/gate_matrix.hpp index a995a14f..ae13b973 100644 --- a/scaluq/gate/gate_matrix.hpp +++ b/scaluq/gate/gate_matrix.hpp @@ -140,7 +140,11 @@ class DenseMatrixGateImpl : public GateBase { _target_mask, _control_mask, inv_eigen, _is_unitary); } - Matrix get_matrix_internal() const { return _matrix; } + Matrix get_matrix_internal() const { + Matrix ret("return matrix", _matrix.extent(0), _matrix.extent(1)); + Kokkos::deep_copy(ret, _matrix); + return ret; + } ComplexMatrix get_matrix() const override { return convert_internal_matrix_to_external_matrix(_matrix); @@ -184,13 +188,16 @@ class SparseMatrixGateImpl : public GateBase { ComplexMatrix get_matrix() const override { ComplexMatrix ret(_matrix._row, _matrix._col); - auto vec = _matrix._values; - for (std::size_t i = 0; i < vec.size(); i++) { - ret(vec[i].r, vec[i].c) = vec[i].val; + auto vec_d = _matrix._values; + auto vec_h = Kokkos::create_mirror_view(vec_d); + for (std::size_t i = 0; i < vec_h.size(); i++) { + ret(vec_h(i).r, vec_h(i).c) = vec_h(i).val; } return ret; } + SparseComplexMatrix get_sparse_matrix() const { return get_matrix().sparseView(); } + void update_quantum_state(StateVector& state_vector) const override { check_qubit_mask_within_bounds(state_vector); sparse_matrix_gate(_target_mask, _control_mask, _matrix, state_vector); @@ -219,7 +226,9 @@ void bind_gate_gate_matrix_hpp(nb::module_& m) { DEF_GATE(TwoTargetMatrixGate, "Specific class of two-qubit dense matrix gate.") .def("matrix", [](const TwoTargetMatrixGate& gate) { return gate->matrix(); }); DEF_GATE(SparseMatrixGate, "Specific class of sparse matrix gate.") - .def("matrix", [](const SparseMatrixGate& gate) { return gate->get_matrix(); }); + .def("matrix", [](const SparseMatrixGate& gate) { return gate->get_matrix(); }) + .def("sparse_matrix", + [](const SparseMatrixGate& gate) { return gate->get_sparse_matrix(); }); DEF_GATE(DenseMatrixGate, "Specific class of dense matrix gate.") .def("matrix", [](const DenseMatrixGate& gate) { return gate->get_matrix(); }); } diff --git a/scaluq/gate/update_ops_dense_matrix.cpp b/scaluq/gate/update_ops_dense_matrix.cpp index 5776465a..6c72f279 100644 --- a/scaluq/gate/update_ops_dense_matrix.cpp +++ b/scaluq/gate/update_ops_dense_matrix.cpp @@ -139,12 +139,13 @@ void multi_target_dense_matrix_gate(std::uint64_t target_mask, std::uint64_t basis = team.league_rank(); basis = insert_zero_at_mask_positions(basis, target_mask | control_mask) | control_mask; Kokkos::parallel_for(Kokkos::TeamThreadRange(team, matrix_dim), [&](std::uint64_t r) { - uint32_t dst_index = internal::insert_zero_at_mask_positions(r, outer_mask) | basis; + std::uint64_t dst_index = + internal::insert_zero_at_mask_positions(r, outer_mask) | basis; Complex sum = 0; Kokkos::parallel_reduce( Kokkos::ThreadVectorRange(team, matrix_dim), [&](std::uint64_t c, Complex& inner_sum) { - uint32_t src_index = + std::uint64_t src_index = internal::insert_zero_at_mask_positions(c, outer_mask) | basis; inner_sum += matrix(r, c) * state._raw(src_index); }, diff --git a/tests/gate/gate_test.cpp b/tests/gate/gate_test.cpp index 20fbc074..5914cd7d 100644 --- a/tests/gate/gate_test.cpp +++ b/tests/gate/gate_test.cpp @@ -15,7 +15,7 @@ using namespace scaluq; const auto eps = 1e-12; -using CComplex = std::complex; +using StdComplex = std::complex; template void run_random_gate_apply(std::uint64_t n_qubits) { @@ -36,7 +36,7 @@ void run_random_gate_apply(std::uint64_t n_qubits) { test_state = test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -62,7 +62,7 @@ void run_random_gate_apply(std::uint64_t n_qubits) { test_state = std::polar(1., angle) * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -90,7 +90,7 @@ void run_random_gate_apply(std::uint64_t n_qubits, test_state = get_expanded_eigen_matrix_with_identity(target, matrix, n_qubits) * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -119,7 +119,7 @@ void run_random_gate_apply(std::uint64_t n_qubits, test_state = get_expanded_eigen_matrix_with_identity(target, matrix, n_qubits) * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -165,7 +165,7 @@ void run_random_gate_apply_IBMQ( get_expanded_eigen_matrix_with_identity(target, matrix, n_qubits) * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -203,7 +203,7 @@ void run_random_gate_apply_two_target(std::uint64_t n_qubits) { test_state = test_mat * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -226,7 +226,7 @@ void run_random_gate_apply_two_target(std::uint64_t n_qubits) { test_state = test_mat * test_state; for (int i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } } } @@ -283,7 +283,7 @@ void run_random_gate_apply_pauli(std::uint64_t n_qubits) { // check if the state is updated correctly for (std::uint64_t i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } auto state_bef_cp = state_bef.get_amplitudes(); @@ -293,7 +293,7 @@ void run_random_gate_apply_pauli(std::uint64_t n_qubits) { // check if the state is restored correctly for (std::uint64_t i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)(state_cp[i] - state_bef_cp[i])), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)(state_cp[i] - state_bef_cp[i])), 0, eps); } } @@ -343,7 +343,7 @@ void run_random_gate_apply_pauli(std::uint64_t n_qubits) { assert((int)state_cp.size() == test_state.size()); // check if the state is updated correctly for (std::uint64_t i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)state_cp[i] - test_state[i]), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)state_cp[i] - test_state[i]), 0, eps); } Gate pauli_gate_inv = pauli_gate->get_inverse(); pauli_gate_inv->update_quantum_state(state); @@ -351,7 +351,7 @@ void run_random_gate_apply_pauli(std::uint64_t n_qubits) { auto state_bef_cp = state_bef.get_amplitudes(); // check if the state is restored correctly for (std::uint64_t i = 0; i < dim; i++) { - ASSERT_NEAR(std::abs((CComplex)(state_cp[i] - state_bef_cp[i])), 0, eps); + ASSERT_NEAR(std::abs((StdComplex)(state_cp[i] - state_bef_cp[i])), 0, eps); } } }