• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IntelPython / dpnp / 24171220084

09 Apr 2026 03:44AM UTC coverage: 81.051% (-1.0%) from 82.034%
24171220084

Pull #2841

github

web-flow
Merge c330a04a3 into 2a78c0628
Pull Request #2841: Feature sparse linalg solvers

1328 of 2472 branches covered (53.72%)

Branch coverage included in aggregate %.

605 of 1006 new or added lines in 7 files covered. (60.14%)

23 existing lines in 1 file now uncovered.

20388 of 24321 relevant lines covered (83.83%)

6715.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.9
/dpnp/backend/extensions/sparse/sparse_py.cpp
1
//*****************************************************************************
2
// Copyright (c) 2025, Intel Corporation
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are met:
7
// - Redistributions of source code must retain the above copyright notice,
8
//   this list of conditions and the following disclaimer.
9
// - Redistributions in binary form must reproduce the above copyright notice,
10
//   this list of conditions and the following disclaimer in the documentation
11
//   and/or other materials provided with the distribution.
12
// - Neither the name of the copyright holder nor the names of its contributors
13
//   may be used to endorse or promote products derived from this software
14
//   without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
// POSSIBILITY OF SUCH DAMAGE.
27
//*****************************************************************************
28

29
#include <cstdint>
30
#include <tuple>
31
#include <vector>
32

33
#include <pybind11/pybind11.h>
34
#include <pybind11/stl.h>
35

36
#include <sycl/sycl.hpp>
37

38
#include <dpctl4pybind11.hpp>
39

40
#include "gemv.hpp"
41

42
namespace py = pybind11;
43

44
using dpnp::extensions::sparse::init_sparse_gemv_dispatch_tables;
45
using dpnp::extensions::sparse::sparse_gemv_compute;
46
using dpnp::extensions::sparse::sparse_gemv_init;
47
using dpnp::extensions::sparse::sparse_gemv_release;
48

49
PYBIND11_MODULE(_sparse_impl, m)
50
{
2✔
51
    init_sparse_gemv_dispatch_tables();
2✔
52

53
    // ------------------------------------------------------------------
54
    // _using_onemath()
55
    //
56
    // Reports whether the module was compiled against the portable
57
    // OneMath interface (USE_ONEMATH) rather than direct oneMKL.
58
    // ------------------------------------------------------------------
59
    m.def("_using_onemath", []() -> bool {
2✔
60
#ifdef USE_ONEMATH
61
        return true;
62
#else
NEW
63
        return false;
×
NEW
64
#endif
×
NEW
65
    });
×
66

67
    // ------------------------------------------------------------------
68
    // _sparse_gemv_init(exec_q, trans, row_ptr, col_ind, values,
69
    //                   num_rows, num_cols, nnz, depends)
70
    //     -> (handle: int, val_type_id: int, event)
71
    //
72
    // Calls init_matrix_handle + set_csr_data + optimize_gemv ONCE.
73
    //
74
    // The returned handle is an opaque uintptr_t; val_type_id is the
75
    // dpctl typenum lookup id of the matrix value dtype and MUST be
76
    // passed back to _sparse_gemv_compute so the C++ layer can verify
77
    // that x and y dtype match the handle.
78
    //
79
    // LIFETIME CONTRACT: the caller must keep row_ptr / col_ind / values
80
    // USM allocations alive until _sparse_gemv_release has been called
81
    // AND its returned event has completed. The handle does not copy
82
    // the CSR arrays.
83
    // ------------------------------------------------------------------
84
    m.def(
2✔
85
        "_sparse_gemv_init",
2✔
86
        [](sycl::queue &exec_q,
2✔
87
           const int trans,
2✔
88
           const dpctl::tensor::usm_ndarray &row_ptr,
2✔
89
           const dpctl::tensor::usm_ndarray &col_ind,
2✔
90
           const dpctl::tensor::usm_ndarray &values,
2✔
91
           const std::int64_t num_rows,
2✔
92
           const std::int64_t num_cols,
2✔
93
           const std::int64_t nnz,
2✔
94
           const std::vector<sycl::event> &depends)
2✔
95
            -> std::tuple<std::uintptr_t, int, sycl::event>
2✔
96
        {
2✔
NEW
97
            return sparse_gemv_init(
×
NEW
98
                exec_q, trans,
×
NEW
99
                row_ptr, col_ind, values,
×
NEW
100
                num_rows, num_cols, nnz,
×
NEW
101
                depends);
×
NEW
102
        },
×
103
        py::arg("exec_q"),
2✔
104
        py::arg("trans"),
2✔
105
        py::arg("row_ptr"),
2✔
106
        py::arg("col_ind"),
2✔
107
        py::arg("values"),
2✔
108
        py::arg("num_rows"),
2✔
109
        py::arg("num_cols"),
2✔
110
        py::arg("nnz"),
2✔
111
        py::arg("depends"),
2✔
112
        "Initialise oneMKL sparse matrix handle "
2✔
113
        "(set_csr_data + optimize_gemv). "
2✔
114
        "Returns (handle_ptr: int, val_type_id: int, event). "
2✔
115
        "Call once per operator."
2✔
116
    );
2✔
117

118
    // ------------------------------------------------------------------
119
    // _sparse_gemv_compute(exec_q, handle, val_type_id, trans, alpha,
120
    //                     x, beta, y, num_rows, num_cols, depends)
121
    //     -> gemv_event
122
    //
123
    // Fires sparse::gemv using a pre-built handle. Verifies x and y
124
    // dtype match val_type_id from init, and that shapes agree with
125
    // op(A) dimensions (swapped for trans != N).
126
    //
127
    // Only the cheap MKL kernel is dispatched; no analysis overhead.
128
    // No host_task keep-alive is submitted -- pybind11 refcounts the
129
    // usm_ndarrays across the call, and sequencing of subsequent work
130
    // on the same queue happens automatically.
131
    // ------------------------------------------------------------------
132
    m.def(
2✔
133
        "_sparse_gemv_compute",
2✔
134
        [](sycl::queue &exec_q,
2✔
135
           const std::uintptr_t handle_ptr,
2✔
136
           const int val_type_id,
2✔
137
           const int trans,
2✔
138
           const double alpha,
2✔
139
           const dpctl::tensor::usm_ndarray &x,
2✔
140
           const double beta,
2✔
141
           const dpctl::tensor::usm_ndarray &y,
2✔
142
           const std::int64_t num_rows,
2✔
143
           const std::int64_t num_cols,
2✔
144
           const std::vector<sycl::event> &depends)
2✔
145
            -> sycl::event
2✔
146
        {
2✔
NEW
147
            return sparse_gemv_compute(
×
NEW
148
                exec_q, handle_ptr, val_type_id, trans, alpha,
×
NEW
149
                x, beta, y,
×
NEW
150
                num_rows, num_cols,
×
NEW
151
                depends);
×
NEW
152
        },
×
153
        py::arg("exec_q"),
2✔
154
        py::arg("handle"),
2✔
155
        py::arg("val_type_id"),
2✔
156
        py::arg("trans"),
2✔
157
        py::arg("alpha"),
2✔
158
        py::arg("x"),
2✔
159
        py::arg("beta"),
2✔
160
        py::arg("y"),
2✔
161
        py::arg("num_rows"),
2✔
162
        py::arg("num_cols"),
2✔
163
        py::arg("depends"),
2✔
164
        "Execute sparse::gemv using a pre-built handle. "
2✔
165
        "Returns the gemv event."
2✔
166
    );
2✔
167

168
    // ------------------------------------------------------------------
169
    // _sparse_gemv_release(exec_q, handle, depends) -> event
170
    //
171
    // Releases the matrix_handle allocated by _sparse_gemv_init.
172
    // Must be called exactly once per handle after all compute calls
173
    // referencing it have completed. The returned event depends on the
174
    // release, so callers can chain CSR buffer deallocation on it.
175
    // ------------------------------------------------------------------
176
    m.def(
2✔
177
        "_sparse_gemv_release",
2✔
178
        [](sycl::queue &exec_q,
2✔
179
           const std::uintptr_t handle_ptr,
2✔
180
           const std::vector<sycl::event> &depends)
2✔
181
            -> sycl::event
2✔
182
        {
2✔
NEW
183
            return sparse_gemv_release(exec_q, handle_ptr, depends);
×
NEW
184
        },
×
185
        py::arg("exec_q"),
2✔
186
        py::arg("handle"),
2✔
187
        py::arg("depends"),
2✔
188
        "Release the oneMKL matrix_handle created by _sparse_gemv_init."
2✔
189
    );
2✔
190
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc