1#[allow(unused_imports)]
2use crate::error::Status;
3
4use std::ptr;
5
6use singe_cuda::data_type::{DataType, DataTypeLike};
7
8use crate::{
9 context::Context,
10 error::{Error, Result},
11 sys, try_ffi,
12 utility::to_i64_vec,
13};
14
15#[derive(Debug)]
16pub struct TensorDescriptor {
17 handle: sys::cutensorTensorDescriptor_t,
18 shape: Vec<u64>,
19 strides: Option<Vec<u64>>,
20 data_type: DataType,
21 alignment_requirement: u32,
22}
23
24impl TensorDescriptor {
25 pub fn create_for<T: DataTypeLike>(
26 ctx: &Context,
27 shape: &[u64],
28 alignment_requirement: u32,
29 ) -> Result<Self> {
30 Self::create(ctx, shape, T::data_type(), alignment_requirement)
31 }
32
33 pub fn create(
34 ctx: &Context,
35 shape: &[u64],
36 data_type: DataType,
37 alignment_requirement: u32,
38 ) -> Result<Self> {
39 Self::create_with_strides(ctx, shape, None, data_type, alignment_requirement)
40 }
41
42 pub fn create_with_strides(
57 ctx: &Context,
58 shape: &[u64],
59 strides: Option<&[u64]>,
60 data_type: DataType,
61 alignment_requirement: u32,
62 ) -> Result<Self> {
63 ctx.bind()?;
64
65 let rank = shape.len() as u32;
66 if let Some(strides) = strides
67 && shape.len() != strides.len()
68 {
69 return Err(Error::TensorStrideMismatch {
70 rank,
71 stride_length: strides.len(),
72 });
73 }
74
75 let extent = to_i64_vec(shape, "shape")?;
76 let strides_vec = strides.map(<[u64]>::to_vec);
77 let stride_i64 = strides_vec
78 .as_ref()
79 .map(|values| to_i64_vec(values, "strides"))
80 .transpose()?;
81
82 let mut handle = ptr::null_mut();
83 unsafe {
84 try_ffi!(sys::cutensorCreateTensorDescriptor(
85 ctx.as_raw(),
86 &raw mut handle,
87 rank,
88 extent.as_ptr(),
89 stride_i64.as_ref().map_or(ptr::null(), Vec::as_ptr),
90 data_type.into(),
91 alignment_requirement,
92 ))?;
93 }
94
95 if handle.is_null() {
96 return Err(Error::NullHandle);
97 }
98
99 Ok(Self {
100 handle,
101 shape: shape.to_vec(),
102 strides: strides_vec,
103 data_type,
104 alignment_requirement,
105 })
106 }
107
108 pub fn create_with_strides_for<T: DataTypeLike>(
109 ctx: &Context,
110 shape: &[u64],
111 strides: Option<&[u64]>,
112 alignment_requirement: u32,
113 ) -> Result<Self> {
114 Self::create_with_strides(ctx, shape, strides, T::data_type(), alignment_requirement)
115 }
116
117 pub fn shape(&self) -> &[u64] {
118 &self.shape
119 }
120
121 pub fn strides(&self) -> Option<&[u64]> {
122 self.strides.as_deref()
123 }
124
125 pub fn rank(&self) -> u32 {
126 self.shape.len() as u32
127 }
128
129 pub fn data_type(&self) -> DataType {
130 self.data_type
131 }
132
133 pub fn alignment_requirement(&self) -> u32 {
134 self.alignment_requirement
135 }
136
137 pub const fn as_raw(&self) -> sys::cutensorTensorDescriptor_t {
138 self.handle
139 }
140}
141
142impl Drop for TensorDescriptor {
143 fn drop(&mut self) {
144 unsafe {
145 if let Err(err) = try_ffi!(sys::cutensorDestroyTensorDescriptor(self.handle)) {
146 #[cfg(debug_assertions)]
147 eprintln!("failed to destroy cutensor tensor descriptor: {err}");
148 }
149 }
150 }
151}
152
153#[derive(Debug)]
154pub struct BlockSparseTensorDescriptor {
155 handle: sys::cutensorBlockSparseTensorDescriptor_t,
156 mode_count: u32,
157 non_zero_block_count: u64,
158 data_type: DataType,
159}
160
161impl BlockSparseTensorDescriptor {
162 pub fn create(
207 ctx: &Context,
208 section_count_per_mode: &[u32],
209 section_extents: &[u64],
210 non_zero_block_count: u64,
211 non_zero_coordinates: &[i32],
212 block_strides: Option<&[u64]>,
213 data_type: DataType,
214 ) -> Result<Self> {
215 ctx.bind()?;
216
217 let mode_count = section_count_per_mode.len() as u32;
218 let expected_section_extents = section_count_per_mode
219 .iter()
220 .try_fold(0usize, |sum, &value| sum.checked_add(value as usize))
221 .ok_or(Error::OutOfRange {
222 name: "section_extents".into(),
223 })?;
224 if section_extents.len() != expected_section_extents {
225 return Err(Error::LengthMismatch {
226 name: "section_extents".into(),
227 expected: expected_section_extents,
228 actual: section_extents.len(),
229 });
230 }
231
232 let expected_coordinates =
233 mode_count
234 .checked_mul(non_zero_block_count as u32)
235 .ok_or(Error::OutOfRange {
236 name: "non_zero_coordinates".into(),
237 })?;
238 if non_zero_coordinates.len() != expected_coordinates as usize {
239 return Err(Error::LengthMismatch {
240 name: "non_zero_coordinates".into(),
241 expected: expected_coordinates as usize,
242 actual: non_zero_coordinates.len(),
243 });
244 }
245
246 if let Some(block_strides) = block_strides
247 && block_strides.len() != expected_coordinates as usize
248 {
249 return Err(Error::TensorStrideMismatch {
250 rank: expected_coordinates,
251 stride_length: block_strides.len(),
252 });
253 }
254
255 let num_sections_per_mode = section_count_per_mode.to_vec();
256 let section_extents = to_i64_vec(section_extents, "section_extents")?;
257 let block_strides = block_strides
258 .map(|block_strides| to_i64_vec(block_strides, "block_strides"))
259 .transpose()?;
260
261 let mut handle = ptr::null_mut();
262 unsafe {
263 try_ffi!(sys::cutensorCreateBlockSparseTensorDescriptor(
264 ctx.as_raw(),
265 &raw mut handle,
266 mode_count,
267 non_zero_block_count,
268 num_sections_per_mode.as_ptr(),
269 section_extents.as_ptr(),
270 non_zero_coordinates.as_ptr(),
271 block_strides.as_ref().map_or(ptr::null(), Vec::as_ptr),
272 data_type.into(),
273 ))?;
274 }
275
276 if handle.is_null() {
277 return Err(Error::NullHandle);
278 }
279
280 Ok(Self {
281 handle,
282 mode_count,
283 non_zero_block_count,
284 data_type,
285 })
286 }
287
288 pub fn mode_count(&self) -> u32 {
289 self.mode_count
290 }
291
292 pub fn non_zero_block_count(&self) -> u64 {
293 self.non_zero_block_count
294 }
295
296 pub fn data_type(&self) -> DataType {
297 self.data_type
298 }
299
300 pub const fn as_raw(&self) -> sys::cutensorBlockSparseTensorDescriptor_t {
301 self.handle
302 }
303}
304
305impl Drop for BlockSparseTensorDescriptor {
306 fn drop(&mut self) {
307 unsafe {
308 if let Err(err) = try_ffi!(sys::cutensorDestroyBlockSparseTensorDescriptor(self.handle))
309 {
310 #[cfg(debug_assertions)]
311 eprintln!("failed to destroy cutensor block sparse tensor descriptor: {err}");
312 }
313 }
314 }
315}