DPNP C++ backend kernel library 0.18.0dev0
Data Parallel Extension for NumPy*
Loading...
Searching...
No Matches
dpnp_utils.hpp
1//*****************************************************************************
2// Copyright (c) 2016-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//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23// THE POSSIBILITY OF SUCH DAMAGE.
24//*****************************************************************************
25
26#pragma once
27#ifndef BACKEND_UTILS_H // Cython compatibility
28#define BACKEND_UTILS_H
29
30#include <algorithm>
31#include <cassert>
32#include <complex>
33#include <iostream>
34#include <iterator>
35#include <stdexcept>
36
37#include <sycl/sycl.hpp>
38
39#include <dpnp_iface_fptr.hpp>
40
41#define LIBSYCL_VERSION_GREATER(major, minor, patch) \
42 (__LIBSYCL_MAJOR_VERSION > major) || \
43 (__LIBSYCL_MAJOR_VERSION == major and \
44 __LIBSYCL_MINOR_VERSION > minor) || \
45 (__LIBSYCL_MAJOR_VERSION == major and \
46 __LIBSYCL_MINOR_VERSION == minor and \
47 __LIBSYCL_PATCH_VERSION >= patch)
48
53#ifndef __SYCL_COMPILER_VECTOR_ABS_CHANGED
54#define __SYCL_COMPILER_VECTOR_ABS_CHANGED 20230503L
55#endif
56
60#ifndef __INTEL_MKL_2023_0_0_VERSION_REQUIRED
61#define __INTEL_MKL_2023_0_0_VERSION_REQUIRED 20230000
62#endif
63
70#ifndef __INTEL_MKL_2023_2_0_VERSION_REQUIRED
71#define __INTEL_MKL_2023_2_0_VERSION_REQUIRED 20230002L
72#endif
73
94template <typename _DataType>
95void get_shape_offsets_inkernel(const _DataType *shape,
96 size_t shape_size,
97 _DataType *offsets)
98{
99 size_t dim_prod_input = 1;
100 for (size_t i = 0; i < shape_size; ++i) {
101 long i_reverse = shape_size - 1 - i;
102 offsets[i_reverse] = dim_prod_input;
103 dim_prod_input *= shape[i_reverse];
104 }
105
106 return;
107}
108
125template <typename _DataType>
126_DataType get_xyz_id_by_id_inkernel(size_t global_id,
127 const _DataType *offsets,
128 size_t offsets_size,
129 size_t axis)
130{
131 /* avoid warning unused variable*/
132 (void)offsets_size;
133
134 assert(axis < offsets_size);
135
136 _DataType xyz_id = 0;
137 long reminder = global_id;
138 for (size_t i = 0; i < axis + 1; ++i) {
139 const _DataType axis_val = offsets[i];
140 xyz_id = reminder / axis_val;
141 reminder = reminder % axis_val;
142 }
143
144 return xyz_id;
145}
146
157static inline bool
158 broadcastable(const std::vector<shape_elem_type> &input_shape,
159 const std::vector<shape_elem_type> &output_shape)
160{
161 if (input_shape.size() > output_shape.size()) {
162 return false;
163 }
164
165 std::vector<shape_elem_type>::const_reverse_iterator irit =
166 input_shape.rbegin();
167 std::vector<shape_elem_type>::const_reverse_iterator orit =
168 output_shape.rbegin();
169 for (; irit != input_shape.rend(); ++irit, ++orit) {
170 if (*irit != 1 && *irit != *orit) {
171 return false;
172 }
173 }
174
175 return true;
176}
177
178static inline bool
179 broadcastable(const shape_elem_type *input_shape,
180 const size_t input_shape_size,
181 const std::vector<shape_elem_type> &output_shape)
182{
183 const std::vector<shape_elem_type> input_shape_vec(
184 input_shape, input_shape + input_shape_size);
185 return broadcastable(input_shape_vec, output_shape);
186}
187
199template <typename _DataType>
200static inline bool array_equal(const _DataType *input1,
201 const size_t input1_size,
202 const _DataType *input2,
203 const size_t input2_size)
204{
205 if (input1_size != input2_size)
206 return false;
207
208 const std::vector<_DataType> input1_vec(input1, input1 + input1_size);
209 const std::vector<_DataType> input2_vec(input2, input2 + input2_size);
210
211 return std::equal(std::begin(input1_vec), std::end(input1_vec),
212 std::begin(input2_vec));
213}
214
234static inline std::vector<shape_elem_type>
235 get_validated_axes(const std::vector<shape_elem_type> &__axes,
236 const size_t __shape_size,
237 const bool __allow_duplicate = false)
238{
239 std::vector<shape_elem_type> result;
240
241 if (__axes.empty()) {
242 goto out;
243 }
244
245 if (__axes.size() > __shape_size) {
246 goto err;
247 }
248
249 result.reserve(__axes.size());
250 for (std::vector<shape_elem_type>::const_iterator it = __axes.cbegin();
251 it != __axes.cend(); ++it)
252 {
253 const shape_elem_type _axis = *it;
254 const shape_elem_type input_shape_size_signed =
255 static_cast<shape_elem_type>(__shape_size);
256 if (_axis >= input_shape_size_signed) { // positive axis range check
257 goto err;
258 }
259
260 if (_axis < -input_shape_size_signed) { // negative axis range check
261 goto err;
262 }
263
264 const shape_elem_type positive_axis =
265 _axis < 0 ? (_axis + input_shape_size_signed) : _axis;
266
267 if (!__allow_duplicate) {
268 if (std::find(result.begin(), result.end(), positive_axis) !=
269 result.end()) { // find axis duplication
270 goto err;
271 }
272 }
273
274 result.push_back(positive_axis);
275 }
276
277out:
278 return result;
279
280err:
281 // TODO exception if wrong axis? need common function for throwing
282 // exceptions
283 throw std::range_error(
284 "DPNP Error: validate_axes() failed with axis check");
285}
286
297template <typename T>
298static inline void validate_type_for_device(const sycl::device &d)
299{
300 if constexpr (std::is_same_v<T, double>) {
301 if (!d.has(sycl::aspect::fp64)) {
302 throw std::runtime_error("Device " +
303 d.get_info<sycl::info::device::name>() +
304 " does not support type 'double'");
305 }
306 }
307 else if constexpr (std::is_same_v<T, std::complex<double>>) {
308 if (!d.has(sycl::aspect::fp64)) {
309 throw std::runtime_error(
310 "Device " + d.get_info<sycl::info::device::name>() +
311 " does not support type 'complex<double>'");
312 }
313 }
314 else if constexpr (std::is_same_v<T, sycl::half>) {
315 if (!d.has(sycl::aspect::fp16)) {
316 throw std::runtime_error("Device " +
317 d.get_info<sycl::info::device::name>() +
318 " does not support type 'half'");
319 }
320 }
321}
322
333template <typename T>
334static inline void validate_type_for_device(const sycl::queue &q)
335{
336 validate_type_for_device<T>(q.get_device());
337}
338
347template <typename T>
348std::ostream &operator<<(std::ostream &out, const std::vector<T> &vec)
349{
350 std::string delimiter;
351 out << "{";
352 // std::copy(vec.begin(), vec.end(), std::ostream_iterator<T>(out, ", "));
353 // out << "\b\b}"; // last two 'backspaces' needs to eliminate last
354 // delimiter. ex: {2, 3, 4, }
355 for (auto &elem : vec) {
356 out << delimiter << elem;
357 if (delimiter.empty()) {
358 delimiter.assign(", ");
359 }
360 }
361 out << "}";
362
363 return out;
364}
365
375template <typename T>
376std::ostream &operator<<(std::ostream &out, DPNPFuncType elem)
377{
378 out << static_cast<size_t>(elem);
379
380 return out;
381}
382
383#endif // BACKEND_UTILS_H
DPNPFuncType
Template types which are used in this interface.
std::ostream & operator<<(std::ostream &out, const std::vector< T > &vec)
print std::vector to std::ostream.
void get_shape_offsets_inkernel(const _DataType *shape, size_t shape_size, _DataType *offsets)
Shape offset calculation used in kernels.
_DataType get_xyz_id_by_id_inkernel(size_t global_id, const _DataType *offsets, size_t offsets_size, size_t axis)
Calculate xyz id for given axis from linear index.