Skip to content

Commit 4b0188f

Browse files
committed
renew eig kernel and rename
1 parent 5f14466 commit 4b0188f

File tree

8 files changed

+98
-150
lines changed

8 files changed

+98
-150
lines changed

dpnp/backend/backend_iface.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,19 @@ INP_DLLEXPORT void custom_prod_c(void* array, void* result, size_t size);
173173

174174
/**
175175
* @ingroup BACKEND_API
176-
* @brief Custom implementation of eig function
176+
* @brief Compute the eigenvalues and right eigenvectors of a square array.
177177
*
178-
* @param [in] array1 Input array.
178+
* @param [in] array_in Input array[size][size]
179179
*
180-
* @param [out] result1 Output array.
180+
* @param [out] result1 The eigenvalues, each repeated according to its multiplicity
181181
*
182-
* @param [in] size Number of elements in input arrays.
182+
* @param [out] result2 The normalized (unit “length”) eigenvectors
183+
*
184+
* @param [in] size One dimension of square [size][size] array
183185
*
184186
*/
185-
template <typename _DataType>
186-
INP_DLLEXPORT void custom_lapack_syevd_c(void* array1, void* result1, size_t size);
187+
template <typename _DataType, typename _ResultType>
188+
INP_DLLEXPORT void custom_lapack_eig_c(const void* array_in, void* result1, void* result2, size_t size);
187189

188190
/**
189191
* @ingroup BACKEND_API

dpnp/backend/backend_iface_fptr.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,10 @@ static func_map_t func_map_init()
315315
fmap[DPNPFuncName::DPNP_FN_DOT][eft_FLT][eft_FLT] = {eft_FLT, (void*)custom_blas_dot_c<float>};
316316
fmap[DPNPFuncName::DPNP_FN_DOT][eft_DBL][eft_DBL] = {eft_DBL, (void*)custom_blas_dot_c<double>};
317317

318-
fmap[DPNPFuncName::DPNP_FN_EIG][eft_INT][eft_INT] = {eft_DBL, (void*)custom_lapack_syevd_c<double>};
319-
fmap[DPNPFuncName::DPNP_FN_EIG][eft_LNG][eft_LNG] = {eft_DBL, (void*)custom_lapack_syevd_c<double>};
320-
fmap[DPNPFuncName::DPNP_FN_EIG][eft_FLT][eft_FLT] = {eft_FLT, (void*)custom_lapack_syevd_c<float>};
321-
fmap[DPNPFuncName::DPNP_FN_EIG][eft_DBL][eft_DBL] = {eft_DBL, (void*)custom_lapack_syevd_c<double>};
318+
fmap[DPNPFuncName::DPNP_FN_EIG][eft_INT][eft_INT] = {eft_DBL, (void*)custom_lapack_eig_c<int, double>};
319+
fmap[DPNPFuncName::DPNP_FN_EIG][eft_LNG][eft_LNG] = {eft_DBL, (void*)custom_lapack_eig_c<long, double>};
320+
fmap[DPNPFuncName::DPNP_FN_EIG][eft_FLT][eft_FLT] = {eft_FLT, (void*)custom_lapack_eig_c<float, float>};
321+
fmap[DPNPFuncName::DPNP_FN_EIG][eft_DBL][eft_DBL] = {eft_DBL, (void*)custom_lapack_eig_c<double, double>};
322322

323323
fmap[DPNPFuncName::DPNP_FN_EXP][eft_INT][eft_INT] = {eft_DBL, (void*)custom_elemwise_exp_c<int, double>};
324324
fmap[DPNPFuncName::DPNP_FN_EXP][eft_LNG][eft_LNG] = {eft_DBL, (void*)custom_elemwise_exp_c<long, double>};

dpnp/backend/custom_kernels.cpp

Lines changed: 46 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -186,114 +186,69 @@ template void custom_blas_dot_c<long>(void* array1_in, void* array2_in, void* re
186186
template void custom_blas_dot_c<float>(void* array1_in, void* array2_in, void* result1, size_t size);
187187
template void custom_blas_dot_c<double>(void* array1_in, void* array2_in, void* result1, size_t size);
188188

189-
template <typename _DataType>
190-
void custom_lapack_syevd_c(void* array_in, void* result1, size_t size)
189+
template <typename _DataType, typename _ResultType>
190+
void custom_lapack_eig_c(const void* array_in, void* result1, void* result2, size_t size)
191191
{
192+
// TODO this kernel works with square 2-D array only
193+
194+
// Kernel Type for calculation is double type
195+
// because interface requires float type but calculations are expected in double type
196+
192197
if (!size)
193198
{
194199
return;
195200
}
196201

197-
_DataType* array = reinterpret_cast<_DataType*>(array_in);
198-
_DataType* result = reinterpret_cast<_DataType*>(result1);
202+
cl::sycl::event event;
199203

200-
if constexpr (std::is_same<_DataType, double>::value || std::is_same<_DataType, float>::value)
201-
{
202-
cl::sycl::event event;
204+
const _DataType* array = reinterpret_cast<const _DataType*>(array_in);
205+
_ResultType* result_val = reinterpret_cast<_ResultType*>(result1);
206+
_ResultType* result_vec = reinterpret_cast<_ResultType*>(result2);
203207

204-
_DataType* syevd_array = reinterpret_cast<_DataType*>(dpnp_memory_alloc_c(size * size * sizeof(_DataType)));
205-
dpnp_memory_memcpy_c(syevd_array, array, size * size * sizeof(_DataType));
208+
double* result_val_kern = reinterpret_cast<double*>(dpnp_memory_alloc_c(size * sizeof(double)));
209+
double* result_vec_kern = reinterpret_cast<double*>(dpnp_memory_alloc_c(size * size * sizeof(double)));
206210

207-
const std::int64_t lda = std::max<size_t>(1UL, size);
211+
// type conversion. Also, math library requires copy memory because override
212+
for (size_t it = 0; it < (size * size); ++it)
213+
{
214+
result_vec_kern[it] = array[it];
215+
}
208216

209-
const std::int64_t scratchpad_size = mkl_lapack::syevd_scratchpad_size<_DataType>(
210-
DPNP_QUEUE, oneapi::mkl::job::vec, oneapi::mkl::uplo::upper, size, lda);
217+
const std::int64_t lda = std::max<size_t>(1UL, size);
211218

212-
_DataType* scratchpad = reinterpret_cast<_DataType*>(dpnp_memory_alloc_c(scratchpad_size * sizeof(_DataType)));
219+
const std::int64_t scratchpad_size = mkl_lapack::syevd_scratchpad_size<double>(
220+
DPNP_QUEUE, oneapi::mkl::job::vec, oneapi::mkl::uplo::upper, size, lda);
213221

214-
event = mkl_lapack::syevd(DPNP_QUEUE, // queue
215-
oneapi::mkl::job::vec, // jobz
216-
oneapi::mkl::uplo::upper, // uplo
217-
size, // The order of the matrix A (0≤n)
218-
syevd_array, // will be overwritten with eigenvectors
219-
lda,
220-
result,
221-
scratchpad,
222-
scratchpad_size);
223-
event.wait();
222+
double* scratchpad = reinterpret_cast<double*>(dpnp_memory_alloc_c(scratchpad_size * sizeof(double)));
224223

225-
dpnp_memory_free_c(scratchpad);
224+
event = mkl_lapack::syevd(DPNP_QUEUE, // queue
225+
oneapi::mkl::job::vec, // jobz
226+
oneapi::mkl::uplo::upper, // uplo
227+
size, // The order of the matrix A (0 <= n)
228+
result_vec_kern, // will be overwritten with eigenvectors
229+
lda,
230+
result_val_kern,
231+
scratchpad,
232+
scratchpad_size);
233+
event.wait();
226234

227-
custom_elemwise_transpose_c<_DataType>(
228-
syevd_array, {(long)size, (long)size}, {(long)size, (long)size}, {1, 0}, array, size * size);
235+
dpnp_memory_free_c(scratchpad);
229236

230-
dpnp_memory_free_c(syevd_array);
231-
}
232-
else
237+
for (size_t it1 = 0; it1 < size; ++it1)
233238
{
234-
// TODO: implement SYCL kernel for int/long input
239+
result_val[it1] = result_val_kern[it1];
240+
for (size_t it2 = 0; it2 < size; ++it2)
241+
{
242+
// copy + transpose
243+
result_vec[it2 * size + it1] = result_vec_kern[it1 * size + it2];
244+
}
235245
}
236-
}
237246

238-
template void custom_lapack_syevd_c<int>(void* array1_in, void* result1, size_t size);
239-
template void custom_lapack_syevd_c<long>(void* array1_in, void* result1, size_t size);
240-
template void custom_lapack_syevd_c<float>(void* array1_in, void* result1, size_t size);
241-
template void custom_lapack_syevd_c<double>(void* array1_in, void* result1, size_t size);
242-
243-
#if 0 // Example for OpenCL kernel
244-
#include <map>
245-
#include <typeindex>
246-
247-
static std::map<std::type_index, std::string> types_map = {{typeid(long), "long"}, {typeid(int), "int"}};
248-
249-
static const char* blas_gemm_naive =
250-
"//#define __KERNEL_TYPE__ long \n"
251-
"#define __KERNEL_TYPE_ZERO__ 0 \n"
252-
"__kernel void blas_gemm_naive(__global __KERNEL_TYPE__* array_1, \n"
253-
" __global __KERNEL_TYPE__* array_2, \n"
254-
" __global __KERNEL_TYPE__* result, \n"
255-
" unsigned long size) \n"
256-
"{ \n"
257-
" size_t i = get_global_id(0); //for (size_t i = 0; i < size; ++i) \n"
258-
" { \n"
259-
" size_t j = get_global_id(1); //for (size_t j = 0; j < size; ++j) \n"
260-
" { \n"
261-
" __KERNEL_TYPE__ temp = __KERNEL_TYPE_ZERO__; \n"
262-
" for (size_t k = 0; k < size; ++k) \n"
263-
" { \n"
264-
" const size_t index_1 = i * size + k; \n"
265-
" const size_t index_2 = k * size + j; \n"
266-
" temp += array_1[index_1] * array_2[index_2]; \n"
267-
" } \n"
268-
" \n"
269-
" const size_t index_result = i * size + j; \n"
270-
" result[index_result] = temp; \n"
271-
" } \n"
272-
" } \n"
273-
"} \n";
274-
275-
template <typename _DataType>
276-
void custom_dgemm_c_opencl(void* array_1_in, void* array_2_in, void* result_1, size_t size)
277-
{
278-
_DataType* array_1 = reinterpret_cast<_DataType*>(array_1_in);
279-
_DataType* array_2 = reinterpret_cast<_DataType*>(array_2_in);
280-
_DataType* result = reinterpret_cast<_DataType*>(result_1);
281-
282-
std::string compile_time_options("-cl-std=CL1.2");
283-
compile_time_options += " -D__KERNEL_TYPE__=" + types_map.at(typeid(_DataType));
284-
285-
cl::sycl::program program_src(DPNP_QUEUE.get_context());
286-
program_src.build_with_source(blas_gemm_naive, compile_time_options);
287-
288-
cl::sycl::range<2> kernel_work_ids(size, size); // dimensions are: "i" and "j"
289-
DPNP_QUEUE.submit([&](cl::sycl::handler& cgh) {
290-
cgh.set_args(array_1, array_2, result, size);
291-
cgh.parallel_for(kernel_work_ids, program_src.get_kernel("blas_gemm_naive"));
292-
});
293-
294-
DPNP_QUEUE.wait();
247+
dpnp_memory_free_c(result_val_kern);
248+
dpnp_memory_free_c(result_vec_kern);
295249
}
296250

297-
template void custom_dgemm_c_opencl<long>(void* array_1_in, void* array_2_in, void* result_1, size_t size);
298-
299-
#endif
251+
template void custom_lapack_eig_c<int, double>(const void* array_in, void* result1, void* result2, size_t size);
252+
template void custom_lapack_eig_c<long, double>(const void* array_in, void* result1, void* result2, size_t size);
253+
template void custom_lapack_eig_c<float, float>(const void* array_in, void* result1, void* result2, size_t size);
254+
template void custom_lapack_eig_c<double, double>(const void* array_in, void* result1, void* result2, size_t size);

dpnp/linalg/linalg.pyx

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,21 @@ __all__ = [
4444
]
4545

4646

47-
cpdef tuple dpnp_eig(dparray in_array1):
48-
cdef dparray_shape_type shape1 = in_array1.shape
47+
cpdef tuple dpnp_eig(dparray x1):
48+
cdef dparray_shape_type x1_shape = x1.shape
4949

50-
cdef size_t size1 = 0
51-
if not shape1.empty():
52-
size1 = shape1.front()
50+
cdef size_t size = 0 if x1_shape.empty() else x1_shape.front()
5351

54-
# convert string type names (dparray.dtype) to C enum DPNPFuncType
55-
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(in_array1.dtype)
56-
57-
# get the FPTR data structure
52+
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(x1.dtype)
5853
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_EIG, param1_type, param1_type)
5954

6055
result_type = dpnp_DPNPFuncType_to_dtype( < size_t > kernel_data.return_type)
61-
# this array is used as input for MKL and will be overwritten with eigen vectors
62-
res_vec = in_array1.astype(result_type)
63-
# ceate result array with type given by FPTR data
64-
cdef dparray res_val = dparray((size1,), dtype=result_type)
6556

66-
cdef fptr_1in_1out_t func = <fptr_1in_1out_t > kernel_data.ptr
57+
cdef dparray res_val = dparray((size,), dtype=result_type)
58+
cdef dparray res_vec = dparray(x1_shape, dtype=result_type)
59+
60+
cdef fptr_2in_1out_t func = <fptr_2in_1out_t > kernel_data.ptr
6761
# call FPTR function
68-
func(res_vec.get_data(), res_val.get_data(), size1)
62+
func(x1.get_data(), res_val.get_data(), res_vec.get_data(), size)
6963

70-
return res_val, res_vec
64+
return (res_val, res_vec)

dpnp/linalg/linalg_iface.py

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,33 +55,21 @@
5555
]
5656

5757

58-
def eig(in_array1):
58+
def eig(x1):
5959
"""
6060
Compute the eigenvalues and right eigenvectors of a square array.
61-
Parameters
62-
----------
63-
a : (..., M, M) array
64-
Matrices for which the eigenvalues and right eigenvectors will
65-
be computed
66-
Returns
67-
-------
68-
w : (..., M) array
69-
The eigenvalues, each repeated according to its multiplicity.
70-
The eigenvalues are not necessarily ordered. The resulting
71-
array will be of complex type, unless the imaginary part is
72-
zero in which case it will be cast to a real type. When `a`
73-
is real the resulting eigenvalues will be real (0 imaginary
74-
part) or occur in conjugate pairs
75-
v : (..., M, M) array
76-
The normalized (unit "length") eigenvectors, such that the
77-
column ``v[:,i]`` is the eigenvector corresponding to the
78-
eigenvalue ``w[i]``.
61+
62+
.. seealso:: :func:`numpy.linalg.eig`
63+
7964
"""
8065

81-
if (use_origin_backend()):
82-
return numpy.linalg.eig(in_array1)
66+
is_x1_dparray = isinstance(x1, dparray)
67+
68+
if (not use_origin_backend(x1) and is_x1_dparray):
69+
if (x1.size > 0):
70+
return dpnp_eig(x1)
8371

84-
return dpnp_eig(in_array1)
72+
return call_origin(numpy.linalg.eig, x1)
8573

8674

8775
def matrix_power(input, count):

examples/example7.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ int main(int, char**)
4545

4646
dpnp_queue_initialize_c(QueueOptions::CPU_SELECTOR);
4747

48-
int* array = (int*)dpnp_memory_alloc_c(len * sizeof(int));
49-
double* result = (double*)dpnp_memory_alloc_c(size * sizeof(double));
48+
float* array = (float*)dpnp_memory_alloc_c(len * sizeof(float));
49+
float* result1 = (float*)dpnp_memory_alloc_c(size * sizeof(float));
50+
float* result2 = (float*)dpnp_memory_alloc_c(len * sizeof(float));
5051

5152
/* init input diagonal array like:
5253
1, 0, 0,
@@ -62,16 +63,17 @@ int main(int, char**)
6263
array[size * i + i] = i + 1;
6364
}
6465

65-
custom_lapack_syevd_c<double>(array, result, size);
66+
custom_lapack_eig_c<float, float>(array, result1, result2, size);
6667

6768
std::cout << "eigen values" << std::endl;
6869
for (size_t i = 0; i < size; ++i)
6970
{
70-
std::cout << result[i] << ", ";
71+
std::cout << result1[i] << ", ";
7172
}
7273
std::cout << std::endl;
7374

74-
dpnp_memory_free_c(result);
75+
dpnp_memory_free_c(result2);
76+
dpnp_memory_free_c(result1);
7577
dpnp_memory_free_c(array);
7678

7779
return 0;

tests/skipped_tests.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
tests/test_linalg.py::test_eig_arange[16-float32]
2-
tests/test_linalg.py::test_eig_arange[300-float32]
3-
tests/test_linalg.py::test_eig_arange[8-float32]
41
tests/third_party/cupy/binary_tests/test_elementwise.py::TestElementwise::test_bitwise_and
52
tests/third_party/cupy/binary_tests/test_elementwise.py::TestElementwise::test_bitwise_or
63
tests/third_party/cupy/binary_tests/test_elementwise.py::TestElementwise::test_bitwise_xor

tests/test_linalg.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ def vvsort(val, vec, size):
2929
[2, 4, 8, 16, 300])
3030
def test_eig_arange(type, size):
3131
a = numpy.arange(size * size, dtype=type).reshape((size, size))
32-
symm = numpy.tril(a) + numpy.tril(a, -1).T + numpy.diag(numpy.full((size,), size * size, dtype=type))
33-
isymm = inp.array(symm)
32+
symm_orig = numpy.tril(a) + numpy.tril(a, -1).T + numpy.diag(numpy.full((size,), size * size, dtype=type))
33+
symm = symm_orig
34+
dpnp_symm_orig = inp.array(symm)
35+
dpnp_symm = dpnp_symm_orig
3436

35-
dpnp_val, dpnp_vec = inp.linalg.eig(isymm)
37+
dpnp_val, dpnp_vec = inp.linalg.eig(dpnp_symm)
3638
np_val, np_vec = numpy.linalg.eig(symm)
3739

3840
# DPNP sort val/vec by abs value
@@ -46,5 +48,13 @@ def test_eig_arange(type, size):
4648
if np_vec[0, i] * dpnp_vec[0, i] < 0:
4749
np_vec[:, i] = -np_vec[:, i]
4850

51+
numpy.testing.assert_array_equal(symm_orig, symm)
52+
numpy.testing.assert_array_equal(dpnp_symm_orig, dpnp_symm)
53+
54+
assert (dpnp_val.dtype == np_val.dtype)
55+
assert (dpnp_vec.dtype == np_vec.dtype)
56+
assert (dpnp_val.shape == np_val.shape)
57+
assert (dpnp_vec.shape == np_vec.shape)
58+
4959
numpy.testing.assert_allclose(dpnp_val, np_val, rtol=1e-05, atol=1e-05)
5060
numpy.testing.assert_allclose(dpnp_vec, np_vec, rtol=1e-05, atol=1e-05)

0 commit comments

Comments
 (0)