1+ /* numpy-quaddtype shim around QBLAS.
2+ *
3+ * The legacy code called the QuadBLAS:: C++ template namespace from the
4+ * pre-overhaul, header-only QBLAS. The current QBLAS (branch
5+ * `overhaul-rewrite`) exposes a stable C ABI in `qblas/qblas.h` with
6+ * CBLAS-style entry points (`cblas_qdot`, `cblas_qgemm`, …) and runtime
7+ * SIMD dispatch (sse2/avx2/avx512/neon). This file translates the
8+ * `qblas_dot` / `qblas_gemv` / `qblas_gemm` symbols that the rest of
9+ * numpy-quaddtype calls into the new CBLAS-style API. Function
10+ * signatures exposed to the rest of the package are unchanged.
11+ */
12+
113#include " quadblas_interface.h"
214#include < cstring>
315#include < algorithm>
416
517#ifndef DISABLE_QUADBLAS
6- #include " quadblas/quadblas.hpp "
7- #endif // DISABLE_QUADBLAS
18+ #include < qblas/qblas.h >
19+ #endif
820
921extern " C" {
1022
23+ #ifndef DISABLE_QUADBLAS
1124
12- #ifndef DISABLE_QUADBLAS
25+ static inline QBLAS_LAYOUT to_layout (char c) {
26+ return (c == ' C' || c == ' c' ) ? QblasColMajor : QblasRowMajor;
27+ }
28+ static inline QBLAS_TRANSPOSE to_trans (char c) {
29+ if (c == ' T' || c == ' t' ) return QblasTrans;
30+ if (c == ' C' || c == ' c' ) return QblasConjTrans;
31+ return QblasNoTrans;
32+ }
1333
1434int
15- qblas_dot (size_t n, Sleef_quad *x, size_t incx, Sleef_quad *y, size_t incy, Sleef_quad *result)
35+ qblas_dot (size_t n, Sleef_quad *x, size_t incx,
36+ Sleef_quad *y, size_t incy, Sleef_quad *result)
1637{
1738 if (!x || !y || !result || n == 0 ) {
1839 return -1 ;
1940 }
20-
21- try {
22- *result = QuadBLAS::dot (n, x, incx, y, incy);
23- return 0 ;
24- }
25- catch (...) {
26- return -1 ;
27- }
41+ *result = cblas_qdot ((int )n, x, (int )incx, y, (int )incy);
42+ return 0 ;
2843}
2944
3045int
31- qblas_gemv (char layout, char trans, size_t m, size_t n, Sleef_quad *alpha, Sleef_quad *A,
32- size_t lda, Sleef_quad *x, size_t incx, Sleef_quad *beta, Sleef_quad *y, size_t incy)
46+ qblas_gemv (char layout, char trans, size_t m, size_t n,
47+ Sleef_quad *alpha, Sleef_quad *A, size_t lda,
48+ Sleef_quad *x, size_t incx,
49+ Sleef_quad *beta, Sleef_quad *y, size_t incy)
3350{
3451 if (!alpha || !A || !x || !beta || !y || m == 0 || n == 0 ) {
3552 return -1 ;
3653 }
37-
38- try {
39- // Convert layout
40- QuadBLAS::Layout qblas_layout;
41- if (layout == ' R' || layout == ' r' ) {
42- qblas_layout = QuadBLAS::Layout::RowMajor;
43- }
44- else if (layout == ' C' || layout == ' c' ) {
45- qblas_layout = QuadBLAS::Layout::ColMajor;
46- }
47- else {
48- return -1 ; // Invalid layout
49- }
50-
51- // Handle transpose (swap dimensions for transpose)
52- size_t actual_m = m, actual_n = n;
53- if (trans == ' T' || trans == ' t' || trans == ' C' || trans == ' c' ) {
54- std::swap (actual_m, actual_n);
55- // For transpose, we need to adjust the layout
56- if (qblas_layout == QuadBLAS::Layout::RowMajor) {
57- qblas_layout = QuadBLAS::Layout::ColMajor;
58- }
59- else {
60- qblas_layout = QuadBLAS::Layout::RowMajor;
61- }
62- }
63-
64- // Call QBLAS GEMV
65- QuadBLAS::gemv (qblas_layout, actual_m, actual_n, *alpha, A, lda, x, incx, *beta, y, incy);
66-
67- return 0 ;
68- }
69- catch (...) {
70- return -1 ;
71- }
54+ cblas_qgemv (to_layout (layout), to_trans (trans),
55+ (int )m, (int )n,
56+ *alpha, A, (int )lda,
57+ x, (int )incx,
58+ *beta, y, (int )incy);
59+ return 0 ;
7260}
7361
7462int
75- qblas_gemm (char layout, char transa, char transb, size_t m, size_t n, size_t k, Sleef_quad *alpha,
76- Sleef_quad *A, size_t lda, Sleef_quad *B, size_t ldb, Sleef_quad *beta, Sleef_quad *C,
77- size_t ldc)
63+ qblas_gemm (char layout, char transa, char transb,
64+ size_t m, size_t n, size_t k,
65+ Sleef_quad *alpha, Sleef_quad *A, size_t lda,
66+ Sleef_quad *B, size_t ldb,
67+ Sleef_quad *beta, Sleef_quad *C, size_t ldc)
7868{
7969 if (!alpha || !A || !B || !beta || !C || m == 0 || n == 0 || k == 0 ) {
8070 return -1 ;
8171 }
82-
83- try {
84- QuadBLAS::Layout qblas_layout;
85- if (layout == ' R' || layout == ' r' ) {
86- qblas_layout = QuadBLAS::Layout::RowMajor;
87- }
88- else if (layout == ' C' || layout == ' c' ) {
89- qblas_layout = QuadBLAS::Layout::ColMajor;
90- }
91- else {
92- return -1 ; // Invalid layout
93- }
94-
95- // For now, we only support no transpose
96- // TODO: Implement transpose support if needed
97- if ((transa != ' N' && transa != ' n' ) || (transb != ' N' && transb != ' n' )) {
98- return -1 ; // Transpose not implemented yet
99- }
100-
101- QuadBLAS::gemm (qblas_layout, m, n, k, *alpha, A, lda, B, ldb, *beta, C, ldc);
102-
103- return 0 ;
104- }
105- catch (...) {
106- return -1 ;
107- }
72+ cblas_qgemm (to_layout (layout), to_trans (transa), to_trans (transb),
73+ (int )m, (int )n, (int )k,
74+ *alpha, A, (int )lda, B, (int )ldb,
75+ *beta, C, (int )ldc);
76+ return 0 ;
10877}
10978
11079int
11180qblas_supports_backend (QuadBackendType backend)
11281{
113- // QBLAS only supports SLEEF backend
82+ /* QBLAS only supports the SLEEF backend (it is built on top of SLEEF). */
11483 return (backend == BACKEND_SLEEF ) ? 1 : 0 ;
11584}
11685
@@ -121,113 +90,94 @@ py_quadblas_set_num_threads(PyObject *self, PyObject *args)
12190 if (!PyArg_ParseTuple (args, " i" , &num_threads)) {
12291 return NULL ;
12392 }
124-
12593 if (num_threads <= 0 ) {
12694 PyErr_SetString (PyExc_ValueError, " Number of threads must be positive" );
12795 return NULL ;
12896 }
129-
130- QuadBLAS::set_num_threads (num_threads);
97+ qblas_set_num_threads (num_threads);
13198 Py_RETURN_NONE;
13299}
133100
134101PyObject *
135102py_quadblas_get_num_threads (PyObject *self, PyObject *args)
136103{
137- int num_threads = QuadBLAS::get_num_threads ();
138- return PyLong_FromLong (num_threads);
104+ return PyLong_FromLong (qblas_get_num_threads ());
139105}
140106
141107PyObject *
142108py_quadblas_get_version (PyObject *self, PyObject *args)
143109{
144- return PyUnicode_FromString (" QuadBLAS 1.0.0 - High Performance Quad Precision BLAS" );
110+ /* qblas_get_version() returns "QBLAS X.Y.Z"; pair it with the
111+ * runtime-detected SIMD tier so callers can confirm what's active. */
112+ const char *ver = qblas_get_version ();
113+ const char *tier = qblas_get_dispatch_tier ();
114+ char buf[256 ];
115+ PyOS_snprintf (buf, sizeof buf, " %s (dispatch: %s)" , ver, tier);
116+ return PyUnicode_FromString (buf);
145117}
146118
147119int
148120_quadblas_set_num_threads (int num_threads)
149121{
150- QuadBLAS::set_num_threads (num_threads);
122+ qblas_set_num_threads (num_threads);
151123 return 0 ;
152124}
153125
154126int
155127_quadblas_get_num_threads (void )
156128{
157- int num_threads = QuadBLAS::get_num_threads ();
158- return num_threads;
129+ return qblas_get_num_threads ();
159130}
160131
161- #else // DISABLE_QUADBLAS
162-
132+ #else /* DISABLE_QUADBLAS */
163133
164134int
165135qblas_dot (size_t n, Sleef_quad *x, size_t incx, Sleef_quad *y, size_t incy, Sleef_quad *result)
166- {
167- return -1 ; // QBLAS is disabled, dot product not available
168- }
136+ { return -1 ; }
169137
170138int
171139qblas_gemv (char layout, char trans, size_t m, size_t n, Sleef_quad *alpha, Sleef_quad *A,
172140 size_t lda, Sleef_quad *x, size_t incx, Sleef_quad *beta, Sleef_quad *y, size_t incy)
173- {
174- return -1 ; // QBLAS is disabled, GEMV not available
175- }
141+ { return -1 ; }
176142
177143int
178144qblas_gemm (char layout, char transa, char transb, size_t m, size_t n, size_t k, Sleef_quad *alpha,
179145 Sleef_quad *A, size_t lda, Sleef_quad *B, size_t ldb, Sleef_quad *beta, Sleef_quad *C,
180146 size_t ldc)
181- {
182- return -1 ; // QBLAS is disabled, GEMM not available
183- }
147+ { return -1 ; }
184148
185- int
186- qblas_supports_backend (QuadBackendType backend)
187- {
188- return -1 ; // QBLAS is disabled, backend support not available
189- }
149+ int qblas_supports_backend (QuadBackendType backend) { return -1 ; }
190150
191151PyObject *
192152py_quadblas_set_num_threads (PyObject *self, PyObject *args)
193153{
194- // raise error
195154 PyErr_SetString (PyExc_NotImplementedError, " QuadBLAS is disabled" );
196155 return NULL ;
197156}
198-
199157PyObject *
200158py_quadblas_get_num_threads (PyObject *self, PyObject *args)
201159{
202- // raise error
203160 PyErr_SetString (PyExc_NotImplementedError, " QuadBLAS is disabled" );
204161 return NULL ;
205162}
206-
207163PyObject *
208164py_quadblas_get_version (PyObject *self, PyObject *args)
209165{
210- // raise error
211166 PyErr_SetString (PyExc_NotImplementedError, " QuadBLAS is disabled" );
212167 return NULL ;
213168}
214169
215- int
216- _quadblas_set_num_threads (int num_threads)
170+ int _quadblas_set_num_threads (int num_threads)
217171{
218- // raise error
219172 PyErr_SetString (PyExc_NotImplementedError, " QuadBLAS is disabled" );
220173 return -1 ;
221174}
222-
223- int
224- _quadblas_get_num_threads (void )
175+ int _quadblas_get_num_threads (void )
225176{
226- // raise error
227177 PyErr_SetString (PyExc_NotImplementedError, " QuadBLAS is disabled" );
228178 return -1 ;
229179}
230180
231- #endif // DISABLE_QUADBLAS
181+ #endif /* DISABLE_QUADBLAS */
232182
233- } // extern "C"
183+ } /* extern "C" */
0 commit comments