1use anyhow::anyhow;
2use once_cell::sync::{Lazy, OnceCell};
3use serde::{Deserialize, Serialize};
4#[cfg(not(target_arch = "wasm32"))]
5use std::cell::Cell;
6use std::collections::{HashMap, HashSet};
7use std::future::Future;
8use std::pin::Pin;
9use std::sync::atomic::{AtomicU32, Ordering};
10#[cfg(feature = "wgpu")]
11use std::sync::Arc;
12#[cfg(target_arch = "wasm32")]
13use std::sync::Mutex;
14use std::sync::RwLock;
15
16type ResidencyMarkFn = fn(&GpuTensorHandle);
17type ResidencyClearFn = fn(&GpuTensorHandle);
18type SequenceThresholdFn = fn() -> Option<usize>;
19type WorkgroupSizeHintFn = fn() -> Option<u32>;
20
21static RESIDENCY_MARK: OnceCell<ResidencyMarkFn> = OnceCell::new();
22static RESIDENCY_CLEAR: OnceCell<ResidencyClearFn> = OnceCell::new();
23static SEQUENCE_THRESHOLD_PROVIDER: OnceCell<SequenceThresholdFn> = OnceCell::new();
24static WORKGROUP_SIZE_HINT_PROVIDER: OnceCell<WorkgroupSizeHintFn> = OnceCell::new();
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27struct HandleMetadataKey {
28 device_id: u32,
29 buffer_id: u64,
30}
31
32fn handle_metadata_key(handle: &GpuTensorHandle) -> HandleMetadataKey {
33 HandleMetadataKey {
34 device_id: handle.device_id,
35 buffer_id: handle.buffer_id,
36 }
37}
38
39static LOGICAL_HANDLES: Lazy<RwLock<HashSet<HandleMetadataKey>>> =
40 Lazy::new(|| RwLock::new(HashSet::new()));
41static LOGICAL_HANDLE_HITS: Lazy<RwLock<HashMap<HandleMetadataKey, u64>>> =
42 Lazy::new(|| RwLock::new(HashMap::new()));
43static TRANSPOSED_HANDLES: Lazy<RwLock<HashMap<HandleMetadataKey, TransposeInfo>>> =
44 Lazy::new(|| RwLock::new(HashMap::new()));
45
46static HANDLE_PRECISIONS: Lazy<RwLock<HashMap<HandleMetadataKey, ProviderPrecision>>> =
47 Lazy::new(|| RwLock::new(HashMap::new()));
48static HANDLE_CLASS_NAMES: Lazy<RwLock<HashMap<HandleMetadataKey, String>>> =
49 Lazy::new(|| RwLock::new(HashMap::new()));
50static HANDLE_STORAGES: Lazy<RwLock<HashMap<HandleMetadataKey, GpuTensorStorage>>> =
51 Lazy::new(|| RwLock::new(HashMap::new()));
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct TransposeInfo {
55 pub base_rows: usize,
56 pub base_cols: usize,
57}
58
59pub fn register_residency_mark(handler: ResidencyMarkFn) {
62 let _ = RESIDENCY_MARK.set(handler);
63}
64
65pub fn mark_residency(handle: &GpuTensorHandle) {
68 if let Some(handler) = RESIDENCY_MARK.get() {
69 handler(handle);
70 }
71}
72
73pub fn register_residency_clear(handler: ResidencyClearFn) {
77 let _ = RESIDENCY_CLEAR.set(handler);
78}
79
80pub fn clear_residency(handle: &GpuTensorHandle) {
83 if let Some(handler) = RESIDENCY_CLEAR.get() {
84 handler(handle);
85 }
86}
87
88pub fn register_sequence_threshold_provider(provider: SequenceThresholdFn) {
92 let _ = SEQUENCE_THRESHOLD_PROVIDER.set(provider);
93}
94
95pub fn sequence_threshold_hint() -> Option<usize> {
97 SEQUENCE_THRESHOLD_PROVIDER
98 .get()
99 .and_then(|provider| provider())
100}
101
102pub fn register_workgroup_size_hint_provider(provider: WorkgroupSizeHintFn) {
106 let _ = WORKGROUP_SIZE_HINT_PROVIDER.set(provider);
107}
108
109pub fn workgroup_size_hint() -> Option<u32> {
111 WORKGROUP_SIZE_HINT_PROVIDER
112 .get()
113 .and_then(|provider| provider())
114}
115
116pub fn export_context(kind: AccelContextKind) -> Option<AccelContextHandle> {
119 provider().and_then(|p| p.export_context(kind))
120}
121
122#[cfg(feature = "wgpu")]
126pub fn export_wgpu_buffer(handle: &GpuTensorHandle) -> Option<WgpuBufferRef> {
127 provider_for_handle(handle).and_then(|p| p.export_wgpu_buffer(handle))
128}
129
130pub fn set_handle_precision(handle: &GpuTensorHandle, precision: ProviderPrecision) {
133 if let Ok(mut guard) = HANDLE_PRECISIONS.write() {
134 guard.insert(handle_metadata_key(handle), precision);
135 }
136}
137
138pub fn handle_precision(handle: &GpuTensorHandle) -> Option<ProviderPrecision> {
140 HANDLE_PRECISIONS
141 .read()
142 .ok()
143 .and_then(|guard| guard.get(&handle_metadata_key(handle)).copied())
144}
145
146pub fn clear_handle_precision(handle: &GpuTensorHandle) {
148 if let Ok(mut guard) = HANDLE_PRECISIONS.write() {
149 guard.remove(&handle_metadata_key(handle));
150 }
151}
152
153pub fn set_handle_class_name(handle: &GpuTensorHandle, class_name: impl Into<String>) {
159 if let Ok(mut guard) = HANDLE_CLASS_NAMES.write() {
160 guard.insert(handle_metadata_key(handle), class_name.into());
161 }
162}
163
164pub fn handle_class_name(handle: &GpuTensorHandle) -> Option<String> {
166 HANDLE_CLASS_NAMES
167 .read()
168 .ok()
169 .and_then(|guard| guard.get(&handle_metadata_key(handle)).cloned())
170}
171
172pub fn clear_handle_class_name(handle: &GpuTensorHandle) {
174 if let Ok(mut guard) = HANDLE_CLASS_NAMES.write() {
175 guard.remove(&handle_metadata_key(handle));
176 }
177}
178
179pub fn set_handle_logical(handle: &GpuTensorHandle, logical: bool) {
182 let key = handle_metadata_key(handle);
183 if let Ok(mut guard) = LOGICAL_HANDLES.write() {
184 if logical {
185 guard.insert(key);
186 if let Ok(mut hits) = LOGICAL_HANDLE_HITS.write() {
187 *hits.entry(key).or_insert(0) += 1;
188 }
189 } else {
190 guard.remove(&key);
191 if let Ok(mut hits) = LOGICAL_HANDLE_HITS.write() {
192 hits.remove(&key);
193 }
194 }
195 }
196}
197
198pub fn clear_handle_logical(handle: &GpuTensorHandle) {
200 set_handle_logical(handle, false);
201}
202
203pub fn handle_is_logical(handle: &GpuTensorHandle) -> bool {
205 LOGICAL_HANDLES
206 .read()
207 .map(|guard| guard.contains(&handle_metadata_key(handle)))
208 .unwrap_or(false)
209}
210
211pub fn handle_logical_hits(handle: &GpuTensorHandle) -> Option<u64> {
212 LOGICAL_HANDLE_HITS
213 .read()
214 .ok()
215 .and_then(|guard| guard.get(&handle_metadata_key(handle)).copied())
216}
217
218pub fn record_handle_transpose(handle: &GpuTensorHandle, base_rows: usize, base_cols: usize) {
219 if let Ok(mut guard) = TRANSPOSED_HANDLES.write() {
220 guard.insert(
221 handle_metadata_key(handle),
222 TransposeInfo {
223 base_rows,
224 base_cols,
225 },
226 );
227 }
228}
229
230pub fn clear_handle_transpose(handle: &GpuTensorHandle) {
231 if let Ok(mut guard) = TRANSPOSED_HANDLES.write() {
232 guard.remove(&handle_metadata_key(handle));
233 }
234}
235
236pub fn handle_transpose_info(handle: &GpuTensorHandle) -> Option<TransposeInfo> {
237 TRANSPOSED_HANDLES
238 .read()
239 .ok()
240 .and_then(|guard| guard.get(&handle_metadata_key(handle)).copied())
241}
242
243pub fn handle_is_transposed(handle: &GpuTensorHandle) -> bool {
244 handle_transpose_info(handle).is_some()
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
248pub enum GpuTensorStorage {
249 Real,
250 ComplexInterleaved,
251}
252
253impl Default for GpuTensorStorage {
254 fn default() -> Self {
255 Self::Real
256 }
257}
258
259#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
260pub struct GpuTensorHandle {
261 pub shape: Vec<usize>,
262 pub device_id: u32,
263 pub buffer_id: u64,
264}
265
266#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
267pub enum ProviderSpectralRange {
268 Onesided,
269 Twosided,
270 Centered,
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
274pub enum ProviderSpectralFrameMode {
275 Sliding {
276 hop: usize,
277 },
278 ColumnSliding {
279 hop: usize,
280 input_rows: usize,
281 frames_per_column: usize,
282 },
283 FoldedColumns {
284 input_rows: usize,
285 },
286}
287
288#[derive(Clone, Debug)]
289pub struct ProviderSpectralRequest<'a> {
290 pub input: &'a GpuTensorHandle,
291 pub input_len: usize,
292 pub input_complex: bool,
293 pub window: &'a [f64],
294 pub nfft: usize,
295 pub frame_count: usize,
296 pub frame_mode: ProviderSpectralFrameMode,
297 pub range: ProviderSpectralRange,
298 pub denominator: f64,
299}
300
301#[derive(Clone, Debug)]
302pub struct ProviderSpectralResult {
303 pub s: GpuTensorHandle,
304 pub ps: GpuTensorHandle,
305 pub rows: usize,
306 pub cols: usize,
307}
308
309#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
310pub enum ProviderEnvelopeMethod {
311 Analytic,
312 AnalyticFir { filter_len: usize },
313 Rms { window_len: usize },
314}
315
316#[derive(Clone, Debug)]
317pub struct ProviderEnvelopeRequest<'a> {
318 pub input: &'a GpuTensorHandle,
319 pub channel_len: usize,
320 pub channel_count: usize,
321 pub output_shape: &'a [usize],
322 pub method: ProviderEnvelopeMethod,
323}
324
325#[derive(Clone, Debug)]
326pub struct ProviderEnvelopeResult {
327 pub upper: GpuTensorHandle,
328 pub lower: GpuTensorHandle,
329}
330
331#[derive(Clone, Debug)]
332pub struct ProviderHilbertRequest<'a> {
333 pub input: &'a GpuTensorHandle,
334 pub length: Option<usize>,
336 pub dim: usize,
338}
339
340#[derive(Clone, Debug)]
341pub struct ProviderModulationRequest<'a> {
342 pub input: &'a GpuTensorHandle,
343 pub constellation: &'a [f64],
345}
346
347#[derive(Clone, Debug)]
348pub struct ProviderBitModulationRequest<'a> {
349 pub input: &'a GpuTensorHandle,
350 pub input_rows: usize,
352 pub bits_per_symbol: usize,
354 pub constellation: &'a [f64],
356}
357
358pub async fn uniform_spectral_estimate(
359 request: ProviderSpectralRequest<'_>,
360) -> anyhow::Result<ProviderSpectralResult> {
361 validate_uniform_spectral_request(&request)?;
362
363 let provider = provider_for_handle(request.input)
364 .ok_or_else(|| anyhow!("uniform_spectral_estimate: GPU provider unavailable"))?;
365 provider.uniform_spectral_estimate(&request).await
366}
367
368fn validate_uniform_spectral_request(request: &ProviderSpectralRequest<'_>) -> anyhow::Result<()> {
369 let invalid_frame_mode = matches!(
370 request.frame_mode,
371 ProviderSpectralFrameMode::Sliding { hop: 0 }
372 | ProviderSpectralFrameMode::ColumnSliding { hop: 0, .. }
373 );
374 let invalid_input_coverage = match request.frame_mode {
375 ProviderSpectralFrameMode::Sliding { hop } => {
376 let required = request
377 .frame_count
378 .checked_sub(1)
379 .and_then(|frames| frames.checked_mul(hop))
380 .and_then(|offset| offset.checked_add(request.window.len()));
381 required.is_none_or(|required| required > request.input_len)
382 }
383 ProviderSpectralFrameMode::ColumnSliding {
384 hop,
385 input_rows,
386 frames_per_column,
387 } => {
388 if input_rows == 0 || frames_per_column == 0 {
389 true
390 } else {
391 let last_frame = request.frame_count - 1;
392 let source_col = last_frame / frames_per_column;
393 let segment = last_frame % frames_per_column;
394 source_col
395 .checked_mul(input_rows)
396 .and_then(|base| {
397 segment
398 .checked_mul(hop)
399 .and_then(|step| base.checked_add(step))
400 })
401 .and_then(|offset| offset.checked_add(request.window.len()))
402 .is_none_or(|required| required > request.input_len)
403 }
404 }
405 ProviderSpectralFrameMode::FoldedColumns { input_rows } => {
406 input_rows == 0
407 || input_rows
408 .checked_mul(request.frame_count)
409 .is_none_or(|required| required > request.input_len)
410 }
411 };
412 if request.window.is_empty()
413 || request.nfft == 0
414 || request.frame_count == 0
415 || invalid_frame_mode
416 || invalid_input_coverage
417 || !request.denominator.is_finite()
418 || request.denominator <= 0.0
419 {
420 return Err(anyhow!("uniform_spectral_estimate: invalid request"));
421 }
422
423 Ok(())
424}
425
426pub async fn signal_envelope(
427 request: ProviderEnvelopeRequest<'_>,
428) -> anyhow::Result<ProviderEnvelopeResult> {
429 let expected_len = request
430 .channel_len
431 .checked_mul(request.channel_count)
432 .ok_or_else(|| anyhow!("signal_envelope: invalid request"))?;
433 let output_len = request
434 .output_shape
435 .iter()
436 .try_fold(1usize, |acc, &dim| acc.checked_mul(dim))
437 .ok_or_else(|| anyhow!("signal_envelope: invalid request"))?;
438 let input_len = request
439 .input
440 .shape
441 .iter()
442 .try_fold(1usize, |acc, &dim| acc.checked_mul(dim))
443 .ok_or_else(|| anyhow!("signal_envelope: invalid request"))?;
444 if request.channel_len == 0
445 || request.channel_count == 0
446 || request.output_shape.is_empty()
447 || output_len != expected_len
448 || input_len != expected_len
449 || !provider_envelope_input_shape_matches(
450 &request.input.shape,
451 request.channel_len,
452 request.channel_count,
453 )
454 {
455 return Err(anyhow!("signal_envelope: invalid request"));
456 }
457
458 match request.method {
459 ProviderEnvelopeMethod::AnalyticFir { filter_len }
460 | ProviderEnvelopeMethod::Rms {
461 window_len: filter_len,
462 } if filter_len == 0 => return Err(anyhow!("signal_envelope: invalid request")),
463 _ => {}
464 }
465
466 let provider = provider_for_handle(request.input)
467 .ok_or_else(|| anyhow!("signal_envelope: GPU provider unavailable"))?;
468 provider.signal_envelope(&request).await
469}
470
471fn provider_envelope_input_shape_matches(
472 shape: &[usize],
473 channel_len: usize,
474 channel_count: usize,
475) -> bool {
476 if channel_count == 1 {
477 return match shape {
478 [len] => *len == channel_len,
479 [rows, cols] => {
480 (*rows == channel_len && *cols == 1) || (*rows == 1 && *cols == channel_len)
481 }
482 _ => false,
483 };
484 }
485
486 matches!(shape, [rows, cols] if *rows == channel_len && *cols == channel_count)
487}
488
489pub async fn signal_hilbert(
490 request: ProviderHilbertRequest<'_>,
491) -> anyhow::Result<GpuTensorHandle> {
492 if request.length == Some(0) {
493 return Err(anyhow!("signal_hilbert: invalid request"));
494 }
495 if request.dim >= request.input.shape.len() {
496 return Err(anyhow!("signal_hilbert: invalid request"));
497 }
498
499 let provider = provider_for_handle(request.input)
500 .ok_or_else(|| anyhow!("signal_hilbert: GPU provider unavailable"))?;
501 provider.signal_hilbert(&request).await
502}
503
504#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
505pub struct ApiDeviceInfo {
506 pub device_id: u32,
507 pub name: String,
508 pub vendor: String,
509 pub memory_bytes: Option<u64>,
510 pub backend: Option<String>,
511}
512
513#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
514pub struct ReduceDimResult {
515 pub values: GpuTensorHandle,
516 pub indices: GpuTensorHandle,
517}
518
519#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
520pub struct ProviderCumminResult {
521 pub values: GpuTensorHandle,
522 pub indices: GpuTensorHandle,
523}
524
525pub type ProviderCummaxResult = ProviderCumminResult;
530
531#[derive(Debug, Clone, Copy, PartialEq, Eq)]
533pub enum AccelContextKind {
534 Plotting,
535}
536
537#[derive(Clone)]
539pub enum AccelContextHandle {
540 #[cfg(feature = "wgpu")]
541 Wgpu(WgpuContextHandle),
542}
543
544impl AccelContextHandle {
545 #[cfg(feature = "wgpu")]
547 pub fn as_wgpu(&self) -> Option<&WgpuContextHandle> {
548 match self {
549 AccelContextHandle::Wgpu(ctx) => Some(ctx),
550 }
551 }
552}
553
554#[cfg(feature = "wgpu")]
556#[derive(Clone)]
557pub struct WgpuContextHandle {
558 pub instance: Arc<wgpu::Instance>,
559 pub device: Arc<wgpu::Device>,
560 pub queue: Arc<wgpu::Queue>,
561 pub adapter: Arc<wgpu::Adapter>,
562 pub adapter_info: wgpu::AdapterInfo,
563 pub limits: wgpu::Limits,
564 pub features: wgpu::Features,
565}
566
567#[cfg(feature = "wgpu")]
573#[derive(Clone)]
574pub struct WgpuBufferRef {
575 pub buffer: Arc<wgpu::Buffer>,
576 pub len: usize,
577 pub shape: Vec<usize>,
578 pub element_size: usize,
579 pub precision: ProviderPrecision,
580}
581
582pub fn set_handle_storage(handle: &GpuTensorHandle, storage: GpuTensorStorage) {
583 if let Ok(mut guard) = HANDLE_STORAGES.write() {
584 guard.insert(handle_metadata_key(handle), storage);
585 }
586}
587
588pub fn handle_storage(handle: &GpuTensorHandle) -> GpuTensorStorage {
589 HANDLE_STORAGES
590 .read()
591 .ok()
592 .and_then(|guard| guard.get(&handle_metadata_key(handle)).cloned())
593 .unwrap_or(GpuTensorStorage::Real)
594}
595
596pub fn clear_handle_storage(handle: &GpuTensorHandle) {
597 if let Ok(mut guard) = HANDLE_STORAGES.write() {
598 guard.remove(&handle_metadata_key(handle));
599 }
600}
601
602#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
603pub enum PagefunOp {
604 Mtimes,
605}
606
607#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
608pub struct PagefunRequest {
609 pub op: PagefunOp,
610 pub inputs: Vec<GpuTensorHandle>,
611 pub output_shape: Vec<usize>,
612 pub page_dims: Vec<usize>,
613 pub input_page_dims: Vec<Vec<usize>>,
614}
615
616#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
617pub enum FindDirection {
618 First,
619 Last,
620}
621
622#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
623pub struct ProviderFindResult {
624 pub linear: GpuTensorHandle,
625 pub rows: GpuTensorHandle,
626 pub cols: GpuTensorHandle,
627 pub values: Option<GpuTensorHandle>,
628}
629
630#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
631pub struct ProviderBandwidth {
632 pub lower: u32,
633 pub upper: u32,
634}
635
636#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
637pub enum ProviderSymmetryKind {
638 Symmetric,
639 Skew,
640}
641
642#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
643pub enum ProviderHermitianKind {
644 Hermitian,
645 Skew,
646}
647
648#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
649pub struct ProviderLuResult {
650 pub combined: GpuTensorHandle,
651 pub lower: GpuTensorHandle,
652 pub upper: GpuTensorHandle,
653 pub perm_matrix: GpuTensorHandle,
654 pub perm_vector: GpuTensorHandle,
655}
656
657#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
658pub struct ProviderCholResult {
659 pub factor: GpuTensorHandle,
660 pub info: u32,
662}
663
664#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
665pub struct ProviderQrResult {
666 pub q: GpuTensorHandle,
667 pub r: GpuTensorHandle,
668 pub perm_matrix: GpuTensorHandle,
669 pub perm_vector: GpuTensorHandle,
670}
671
672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
673pub struct ProviderQrPowerIterResult {
674 pub q: GpuTensorHandle,
675 pub r: GpuTensorHandle,
676 pub perm_matrix: GpuTensorHandle,
677 pub perm_vector: GpuTensorHandle,
678}
679
680#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
681pub struct ProviderLinsolveOptions {
682 pub lower: bool,
683 pub upper: bool,
684 pub rectangular: bool,
685 pub transposed: bool,
686 pub conjugate: bool,
687 pub symmetric: bool,
688 pub posdef: bool,
689 pub need_rcond: bool,
690 pub rcond: Option<f64>,
691}
692
693#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
694pub struct ProviderLinsolveResult {
695 pub solution: GpuTensorHandle,
696 pub reciprocal_condition: f64,
697}
698
699#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
700pub struct ProviderPinvOptions {
701 pub tolerance: Option<f64>,
702}
703
704#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
705pub struct ProviderPolyvalMu {
706 pub mean: f64,
707 pub scale: f64,
708}
709
710#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
711pub struct ProviderPolyvalOptions {
712 pub mu: Option<ProviderPolyvalMu>,
713}
714
715#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
716pub struct ProviderInvOptions {}
717
718#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
719pub struct ProviderPolyfitResult {
720 pub coefficients: Vec<f64>,
721 pub r_matrix: Vec<f64>,
722 pub normr: f64,
723 pub df: f64,
724 pub mu: [f64; 2],
725}
726
727#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
729pub struct ProviderPolyderQuotient {
730 pub numerator: GpuTensorHandle,
731 pub denominator: GpuTensorHandle,
732}
733
734#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
736pub enum ProviderCondNorm {
737 Two,
738 One,
739 Inf,
740 Fro,
741}
742
743#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
745pub enum ProviderNormOrder {
746 Two,
747 One,
748 Inf,
749 NegInf,
750 Zero,
751 Fro,
752 Nuc,
753 P(f64),
754}
755
756#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
757pub enum ProviderInterp1Method {
758 Linear,
759 Nearest,
760}
761
762#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
763pub enum ProviderInterp1Extrapolation {
764 Nan,
765 Extrapolate,
766 Value,
767}
768
769#[derive(Debug, Clone)]
770pub struct ProviderInterp1Request<'a> {
771 pub x: &'a GpuTensorHandle,
774 pub y: &'a GpuTensorHandle,
775 pub xq: &'a GpuTensorHandle,
776 pub sample_len: usize,
777 pub series_count: usize,
778 pub query_len: usize,
779 pub output_shape: &'a [usize],
780 pub method: ProviderInterp1Method,
781 pub extrapolation: ProviderInterp1Extrapolation,
782 pub extrapolation_value: f64,
783}
784
785#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
786pub struct ProviderEigResult {
787 pub eigenvalues: GpuTensorHandle,
788 pub diagonal: GpuTensorHandle,
789 pub right: GpuTensorHandle,
790 pub left: Option<GpuTensorHandle>,
791}
792
793#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
794pub enum ProviderQrPivot {
795 Matrix,
796 Vector,
797}
798
799#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
800pub struct ProviderQrOptions {
801 pub economy: bool,
802 pub pivot: ProviderQrPivot,
803}
804
805impl Default for ProviderQrOptions {
806 fn default() -> Self {
807 Self {
808 economy: false,
809 pivot: ProviderQrPivot::Matrix,
810 }
811 }
812}
813
814#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
815pub enum ProviderPrecision {
816 F32,
817 F64,
818}
819
820#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
825pub enum SpawnHandleConcurrency {
826 ImmutableShare,
828 CopyOnWrite,
830 SynchronizedMutation,
832 Reject,
834}
835
836impl SpawnHandleConcurrency {
837 pub fn as_str(self) -> &'static str {
838 match self {
839 SpawnHandleConcurrency::ImmutableShare => "immutable_share",
840 SpawnHandleConcurrency::CopyOnWrite => "copy_on_write",
841 SpawnHandleConcurrency::SynchronizedMutation => "synchronized_mutation",
842 SpawnHandleConcurrency::Reject => "reject",
843 }
844 }
845}
846
847#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
848pub enum ReductionTwoPassMode {
849 Auto,
850 ForceOn,
851 ForceOff,
852}
853
854impl ReductionTwoPassMode {
855 pub fn as_str(self) -> &'static str {
856 match self {
857 ReductionTwoPassMode::Auto => "auto",
858 ReductionTwoPassMode::ForceOn => "force_on",
859 ReductionTwoPassMode::ForceOff => "force_off",
860 }
861 }
862}
863
864#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
865pub enum ReductionFlavor {
866 Sum,
867 Mean,
868 CustomScale(f64),
869}
870
871impl ReductionFlavor {
872 pub fn is_mean(self) -> bool {
873 matches!(self, ReductionFlavor::Mean)
874 }
875
876 pub fn scale(self, reduce_len: usize) -> f64 {
877 match self {
878 ReductionFlavor::Sum => 1.0,
879 ReductionFlavor::Mean => {
880 if reduce_len == 0 {
881 1.0
882 } else {
883 1.0 / reduce_len as f64
884 }
885 }
886 ReductionFlavor::CustomScale(scale) => scale,
887 }
888 }
889}
890
891#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
893pub enum CorrcoefNormalization {
894 Unbiased,
895 Biased,
896}
897
898#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
900pub enum CorrcoefRows {
901 All,
902 Complete,
903 Pairwise,
904}
905
906#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
908pub struct CorrcoefOptions {
909 pub normalization: CorrcoefNormalization,
910 pub rows: CorrcoefRows,
911}
912
913impl Default for CorrcoefOptions {
914 fn default() -> Self {
915 Self {
916 normalization: CorrcoefNormalization::Unbiased,
917 rows: CorrcoefRows::All,
918 }
919 }
920}
921
922#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
924pub enum CovNormalization {
925 Unbiased,
926 Biased,
927}
928
929#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
931pub enum CovRows {
932 All,
933 OmitRows,
934 PartialRows,
935}
936
937#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
939pub struct CovarianceOptions {
940 pub normalization: CovNormalization,
941 pub rows: CovRows,
942 pub has_weight_vector: bool,
943}
944
945impl Default for CovarianceOptions {
946 fn default() -> Self {
947 Self {
948 normalization: CovNormalization::Unbiased,
949 rows: CovRows::All,
950 has_weight_vector: false,
951 }
952 }
953}
954
955#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
957pub enum ProviderStdNormalization {
958 Sample,
959 Population,
960}
961
962#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
964pub enum ProviderNanMode {
965 Include,
966 Omit,
967}
968
969#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
971pub enum ProviderMovingWindowOp {
972 Sum,
973 Mean,
974 Prod,
975 Min,
976 Max,
977 Median,
978 Std,
979 Var,
980}
981
982#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
984pub enum ProviderMovingWindowEndpoints {
985 Shrink,
986 Discard,
987 Fill(f64),
988}
989
990#[derive(Debug, Clone, Copy)]
992pub struct ProviderMovingWindowRequest<'a> {
993 pub input: &'a GpuTensorHandle,
994 pub output_shape: &'a [usize],
995 pub dim: usize,
997 pub before: usize,
998 pub after: usize,
999 pub op: ProviderMovingWindowOp,
1000 pub endpoints: ProviderMovingWindowEndpoints,
1001 pub nan_mode: ProviderNanMode,
1002 pub normalization: ProviderStdNormalization,
1003}
1004
1005#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1007pub enum ProviderModeAxes {
1008 Default,
1010 Dim(usize),
1012 All,
1014}
1015
1016#[derive(Debug, Clone, Copy)]
1018pub struct ProviderModeRequest<'a> {
1019 pub input: &'a GpuTensorHandle,
1020 pub axes: ProviderModeAxes,
1021 pub want_frequency: bool,
1022 pub want_ties: bool,
1023}
1024
1025#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1032pub struct ProviderModeTiedSets {
1033 pub values: HostTensorOwned,
1034 pub offsets: Vec<usize>,
1035 pub counts: Vec<usize>,
1036}
1037
1038#[derive(Debug, Clone, PartialEq)]
1045pub struct ProviderModeResult {
1046 pub values: GpuTensorHandle,
1047 pub frequencies: Option<GpuTensorHandle>,
1048 pub ties: Option<ProviderModeTiedSets>,
1049}
1050
1051#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1053pub enum ProviderScanDirection {
1054 Forward,
1055 Reverse,
1056}
1057
1058#[derive(Debug, Clone, Copy)]
1060pub enum ProviderTrapezoidSpacing<'a> {
1061 Unit,
1062 Scalar(f64),
1063 ScalarHandle(&'a GpuTensorHandle),
1064 Vector(&'a GpuTensorHandle),
1065 Tensor(&'a GpuTensorHandle),
1066}
1067
1068#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1070pub enum SortOrder {
1071 Ascend,
1072 Descend,
1073}
1074
1075#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1077pub enum SortComparison {
1078 Auto,
1079 Real,
1080 Abs,
1081}
1082
1083#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1085pub struct SortResult {
1086 pub values: HostTensorOwned,
1087 pub indices: HostTensorOwned,
1088}
1089
1090#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1091pub struct SortRowsColumnSpec {
1092 pub index: usize,
1093 pub order: SortOrder,
1094}
1095
1096#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1098pub enum UniqueOrder {
1099 Sorted,
1100 Stable,
1101}
1102
1103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1105pub enum UniqueOccurrence {
1106 First,
1107 Last,
1108}
1109
1110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1112pub struct UniqueOptions {
1113 pub rows: bool,
1114 pub order: UniqueOrder,
1115 pub occurrence: UniqueOccurrence,
1116}
1117
1118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1120pub struct UniqueResult {
1121 pub values: HostTensorOwned,
1122 pub ia: HostTensorOwned,
1123 pub ic: HostTensorOwned,
1124}
1125
1126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1128pub enum UnionOrder {
1129 Sorted,
1130 Stable,
1131}
1132
1133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1135pub struct UnionOptions {
1136 pub rows: bool,
1137 pub order: UnionOrder,
1138}
1139
1140#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1142pub struct UnionResult {
1143 pub values: HostTensorOwned,
1144 pub ia: HostTensorOwned,
1145 pub ib: HostTensorOwned,
1146}
1147
1148#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1150pub enum FspecialFilter {
1151 Average {
1152 rows: u32,
1153 cols: u32,
1154 },
1155 Disk {
1156 radius: f64,
1157 size: u32,
1158 },
1159 Gaussian {
1160 rows: u32,
1161 cols: u32,
1162 sigma: f64,
1163 },
1164 Laplacian {
1165 alpha: f64,
1166 },
1167 Log {
1168 rows: u32,
1169 cols: u32,
1170 sigma: f64,
1171 },
1172 Motion {
1173 length: u32,
1174 kernel_size: u32,
1175 angle_degrees: f64,
1176 oversample: u32,
1177 },
1178 Prewitt,
1179 Sobel,
1180 Unsharp {
1181 alpha: f64,
1182 },
1183}
1184
1185#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1187pub struct FspecialRequest {
1188 pub filter: FspecialFilter,
1189}
1190
1191#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1193pub enum ImfilterPadding {
1194 Constant,
1195 Replicate,
1196 Symmetric,
1197 Circular,
1198}
1199
1200#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1202pub enum ImfilterShape {
1203 Same,
1204 Full,
1205 Valid,
1206}
1207
1208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1210pub enum ImfilterMode {
1211 Correlation,
1212 Convolution,
1213}
1214
1215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1217pub struct ImfilterOptions {
1218 pub padding: ImfilterPadding,
1219 pub constant_value: f64,
1220 pub shape: ImfilterShape,
1221 pub mode: ImfilterMode,
1222}
1223
1224impl Default for ImfilterOptions {
1225 fn default() -> Self {
1226 Self {
1227 padding: ImfilterPadding::Constant,
1228 constant_value: 0.0,
1229 shape: ImfilterShape::Same,
1230 mode: ImfilterMode::Correlation,
1231 }
1232 }
1233}
1234
1235#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1237pub enum SetdiffOrder {
1238 Sorted,
1239 Stable,
1240}
1241
1242#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1244pub struct SetdiffOptions {
1245 pub rows: bool,
1246 pub order: SetdiffOrder,
1247}
1248
1249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1251pub struct SetdiffResult {
1252 pub values: HostTensorOwned,
1253 pub ia: HostTensorOwned,
1254}
1255
1256#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1258pub struct IsMemberOptions {
1259 pub rows: bool,
1260}
1261
1262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1264pub struct HostLogicalOwned {
1265 pub data: Vec<u8>,
1266 pub shape: Vec<usize>,
1267}
1268
1269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1271pub struct IsMemberResult {
1272 pub mask: HostLogicalOwned,
1273 pub loc: HostTensorOwned,
1274}
1275
1276#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1277pub enum ProviderConvMode {
1278 Full,
1279 Same,
1280 Valid,
1281}
1282
1283#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1284pub enum ProviderConvOrientation {
1285 Row,
1286 Column,
1287}
1288
1289#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1290pub struct ProviderConv1dOptions {
1291 pub mode: ProviderConvMode,
1292 pub orientation: ProviderConvOrientation,
1293}
1294
1295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1296pub struct ProviderIirFilterOptions {
1297 pub dim: usize,
1299 pub zi: Option<GpuTensorHandle>,
1301 pub unit_denominator: bool,
1306}
1307
1308#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1309pub struct ProviderIirFilterResult {
1310 pub output: GpuTensorHandle,
1312 pub final_state: Option<GpuTensorHandle>,
1314}
1315
1316#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1317pub struct ProviderMoments2 {
1318 pub mean: GpuTensorHandle,
1319 pub ex2: GpuTensorHandle,
1320}
1321
1322#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1323pub struct ProviderDispatchStats {
1324 pub count: u64,
1326 pub total_wall_time_ns: u64,
1328}
1329
1330#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
1331pub struct ProviderFallbackStat {
1332 pub reason: String,
1333 pub count: u64,
1334}
1335
1336#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
1337pub struct ProviderTelemetry {
1338 pub fused_elementwise: ProviderDispatchStats,
1339 pub fused_reduction: ProviderDispatchStats,
1340 pub matmul: ProviderDispatchStats,
1341 pub linsolve: ProviderDispatchStats,
1342 pub mldivide: ProviderDispatchStats,
1343 pub mrdivide: ProviderDispatchStats,
1344 pub upload_bytes: u64,
1345 pub download_bytes: u64,
1346 pub solve_fallbacks: Vec<ProviderFallbackStat>,
1347 pub fusion_cache_hits: u64,
1348 pub fusion_cache_misses: u64,
1349 pub bind_group_cache_hits: u64,
1350 pub bind_group_cache_misses: u64,
1351 pub bind_group_cache_by_layout: Option<Vec<BindGroupLayoutTelemetry>>,
1353 pub kernel_launches: Vec<KernelLaunchTelemetry>,
1355}
1356
1357#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1358pub struct BindGroupLayoutTelemetry {
1359 pub tag: String,
1360 pub hits: u64,
1361 pub misses: u64,
1362}
1363
1364#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1365pub struct KernelAttrTelemetry {
1366 pub key: String,
1367 pub value: u64,
1368}
1369
1370#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1371pub struct KernelLaunchTelemetry {
1372 pub kernel: String,
1373 pub precision: Option<String>,
1374 pub shape: Vec<KernelAttrTelemetry>,
1375 pub tuning: Vec<KernelAttrTelemetry>,
1376}
1377
1378pub type AccelProviderFuture<'a, T> = Pin<Box<dyn Future<Output = anyhow::Result<T>> + 'a>>;
1379pub type AccelDownloadFuture<'a> = AccelProviderFuture<'a, crate::HostTensorOwned>;
1380
1381fn unsupported_future<T>(message: &'static str) -> AccelProviderFuture<'static, T> {
1382 Box::pin(async move { Err(anyhow::anyhow!(message)) })
1383}
1384
1385pub trait AccelProvider: Send + Sync {
1387 fn upload(&self, host: &crate::HostTensorView) -> anyhow::Result<GpuTensorHandle>;
1388 fn download<'a>(&'a self, h: &'a GpuTensorHandle) -> AccelDownloadFuture<'a>;
1389 fn free(&self, h: &GpuTensorHandle) -> anyhow::Result<()>;
1390 fn device_info(&self) -> String;
1391 fn device_id(&self) -> u32 {
1392 0
1393 }
1394
1395 fn spawn_handle_concurrency(&self) -> SpawnHandleConcurrency {
1401 SpawnHandleConcurrency::Reject
1402 }
1403
1404 fn export_context(&self, _kind: AccelContextKind) -> Option<AccelContextHandle> {
1407 None
1408 }
1409
1410 #[cfg(feature = "wgpu")]
1412 fn export_wgpu_buffer(&self, _handle: &GpuTensorHandle) -> Option<WgpuBufferRef> {
1413 let _ = _handle;
1414 None
1415 }
1416
1417 fn gather_linear(
1424 &self,
1425 _source: &GpuTensorHandle,
1426 _indices: &[u32],
1427 _output_shape: &[usize],
1428 ) -> anyhow::Result<GpuTensorHandle> {
1429 Err(anyhow::anyhow!("gather_linear not supported by provider"))
1430 }
1431
1432 fn scatter_linear(
1439 &self,
1440 _target: &GpuTensorHandle,
1441 _indices: &[u32],
1442 _values: &GpuTensorHandle,
1443 ) -> anyhow::Result<()> {
1444 Err(anyhow::anyhow!("scatter_linear not supported by provider"))
1445 }
1446
1447 fn device_info_struct(&self) -> ApiDeviceInfo {
1449 ApiDeviceInfo {
1450 device_id: 0,
1451 name: self.device_info(),
1452 vendor: String::new(),
1453 memory_bytes: None,
1454 backend: None,
1455 }
1456 }
1457
1458 fn precision(&self) -> ProviderPrecision {
1459 ProviderPrecision::F64
1460 }
1461
1462 fn read_scalar(&self, _h: &GpuTensorHandle, _linear_index: usize) -> anyhow::Result<f64> {
1464 Err(anyhow::anyhow!("read_scalar not supported by provider"))
1465 }
1466
1467 fn zeros(&self, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1469 Err(anyhow::anyhow!("zeros not supported by provider"))
1470 }
1471
1472 fn zeros_with_storage(
1478 &self,
1479 shape: &[usize],
1480 storage: GpuTensorStorage,
1481 ) -> anyhow::Result<GpuTensorHandle> {
1482 if storage == GpuTensorStorage::Real {
1483 self.zeros(shape)
1484 } else {
1485 Err(anyhow::anyhow!(
1486 "zeros_with_storage not supported by provider for {storage:?}"
1487 ))
1488 }
1489 }
1490
1491 fn ones(&self, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1493 Err(anyhow::anyhow!("ones not supported by provider"))
1494 }
1495
1496 fn zeros_like(&self, prototype: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
1498 self.zeros(&prototype.shape)
1499 }
1500
1501 fn fill(&self, shape: &[usize], value: f64) -> anyhow::Result<GpuTensorHandle> {
1503 if value == 0.0 {
1504 return self.zeros(shape);
1505 }
1506 if let Ok(base) = self.zeros(shape) {
1507 match self.scalar_add(&base, value) {
1508 Ok(out) => {
1509 let _ = self.free(&base);
1510 return Ok(out);
1511 }
1512 Err(_) => {
1513 let _ = self.free(&base);
1514 }
1515 }
1516 }
1517 let len: usize = shape.iter().copied().product();
1518 let data = vec![value; len];
1519 let view = HostTensorView { data: &data, shape };
1520 self.upload(&view)
1521 }
1522
1523 fn fill_like(
1525 &self,
1526 prototype: &GpuTensorHandle,
1527 value: f64,
1528 ) -> anyhow::Result<GpuTensorHandle> {
1529 if value == 0.0 {
1530 return self.zeros_like(prototype);
1531 }
1532 if let Ok(base) = self.zeros_like(prototype) {
1533 match self.scalar_add(&base, value) {
1534 Ok(out) => {
1535 let _ = self.free(&base);
1536 return Ok(out);
1537 }
1538 Err(_) => {
1539 let _ = self.free(&base);
1540 }
1541 }
1542 }
1543 self.fill(&prototype.shape, value)
1544 }
1545
1546 fn ones_like(&self, prototype: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
1548 self.ones(&prototype.shape)
1549 }
1550
1551 fn eye(&self, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1553 Err(anyhow::anyhow!("eye not supported by provider"))
1554 }
1555
1556 fn eye_like(&self, prototype: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
1558 self.eye(&prototype.shape)
1559 }
1560
1561 fn meshgrid(&self, _axes: &[MeshgridAxisView<'_>]) -> anyhow::Result<ProviderMeshgridResult> {
1563 Err(anyhow::anyhow!("meshgrid not supported by provider"))
1564 }
1565
1566 fn ndgrid(&self, _request: &ProviderNdgridRequest<'_>) -> anyhow::Result<ProviderNdgridResult> {
1568 Err(anyhow::anyhow!("ndgrid not supported by provider"))
1569 }
1570
1571 fn black_scholes_price(
1573 &self,
1574 _request: &ProviderBlackScholesPriceRequest<'_>,
1575 ) -> anyhow::Result<ProviderBlackScholesPriceResult> {
1576 Err(anyhow::anyhow!(
1577 "black_scholes_price not supported by provider"
1578 ))
1579 }
1580
1581 fn adam_update(
1583 &self,
1584 _request: &ProviderAdamUpdateRequest<'_>,
1585 ) -> anyhow::Result<ProviderAdamUpdateResult> {
1586 Err(anyhow::anyhow!("adam_update not supported by provider"))
1587 }
1588
1589 fn crossentropy_terms(
1591 &self,
1592 _request: &ProviderCrossentropyRequest<'_>,
1593 ) -> anyhow::Result<ProviderCrossentropyResult> {
1594 Err(anyhow::anyhow!(
1595 "crossentropy_terms not supported by provider"
1596 ))
1597 }
1598
1599 fn diag_from_vector(
1601 &self,
1602 _vector: &GpuTensorHandle,
1603 _offset: isize,
1604 ) -> anyhow::Result<GpuTensorHandle> {
1605 Err(anyhow::anyhow!(
1606 "diag_from_vector not supported by provider"
1607 ))
1608 }
1609
1610 fn diag_from_vector_sized(
1614 &self,
1615 _vector: &GpuTensorHandle,
1616 _offset: isize,
1617 _rows: usize,
1618 _cols: usize,
1619 ) -> anyhow::Result<GpuTensorHandle> {
1620 Err(anyhow::anyhow!(
1621 "diag_from_vector_sized not supported by provider"
1622 ))
1623 }
1624
1625 fn diag_extract(
1627 &self,
1628 _matrix: &GpuTensorHandle,
1629 _offset: isize,
1630 ) -> anyhow::Result<GpuTensorHandle> {
1631 Err(anyhow::anyhow!("diag_extract not supported by provider"))
1632 }
1633
1634 fn tril<'a>(
1636 &'a self,
1637 _matrix: &'a GpuTensorHandle,
1638 _offset: isize,
1639 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1640 Box::pin(async move { Err(anyhow!("tril not supported by provider")) })
1641 }
1642
1643 fn triu<'a>(
1645 &'a self,
1646 _matrix: &'a GpuTensorHandle,
1647 _offset: isize,
1648 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1649 Box::pin(async move { Err(anyhow!("triu not supported by provider")) })
1650 }
1651
1652 fn polyval(
1654 &self,
1655 _coefficients: &GpuTensorHandle,
1656 _points: &GpuTensorHandle,
1657 _options: &ProviderPolyvalOptions,
1658 ) -> anyhow::Result<GpuTensorHandle> {
1659 Err(anyhow::anyhow!("polyval not supported by provider"))
1660 }
1661
1662 fn polyfit<'a>(
1664 &'a self,
1665 _x: &'a GpuTensorHandle,
1666 _y: &'a GpuTensorHandle,
1667 _degree: usize,
1668 _weights: Option<&'a GpuTensorHandle>,
1669 ) -> AccelProviderFuture<'a, ProviderPolyfitResult> {
1670 Box::pin(async move { Err(anyhow::anyhow!("polyfit not supported by provider")) })
1671 }
1672
1673 fn polyder_single<'a>(
1675 &'a self,
1676 _polynomial: &'a GpuTensorHandle,
1677 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1678 Box::pin(async move { Err(anyhow::anyhow!("polyder_single not supported by provider")) })
1679 }
1680
1681 fn polyder_product<'a>(
1683 &'a self,
1684 _p: &'a GpuTensorHandle,
1685 _q: &'a GpuTensorHandle,
1686 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1687 Box::pin(async move { Err(anyhow::anyhow!("polyder_product not supported by provider")) })
1688 }
1689
1690 fn polyder_quotient<'a>(
1692 &'a self,
1693 _u: &'a GpuTensorHandle,
1694 _v: &'a GpuTensorHandle,
1695 ) -> AccelProviderFuture<'a, ProviderPolyderQuotient> {
1696 Box::pin(async move {
1697 Err(anyhow::anyhow!(
1698 "polyder_quotient not supported by provider"
1699 ))
1700 })
1701 }
1702
1703 fn polyint(
1705 &self,
1706 _polynomial: &GpuTensorHandle,
1707 _constant: f64,
1708 ) -> anyhow::Result<GpuTensorHandle> {
1709 Err(anyhow::anyhow!("polyint not supported by provider"))
1710 }
1711
1712 fn random_uniform(&self, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1714 Err(anyhow::anyhow!("random_uniform not supported by provider"))
1715 }
1716
1717 fn random_uniform_like(&self, prototype: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
1719 self.random_uniform(&prototype.shape)
1720 }
1721
1722 fn random_normal(&self, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1724 Err(anyhow::anyhow!("random_normal not supported by provider"))
1725 }
1726
1727 fn random_normal_like(&self, prototype: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
1729 self.random_normal(&prototype.shape)
1730 }
1731
1732 fn random_exponential(&self, _mu: f64, _shape: &[usize]) -> anyhow::Result<GpuTensorHandle> {
1734 Err(anyhow::anyhow!(
1735 "random_exponential not supported by provider"
1736 ))
1737 }
1738
1739 fn random_normrnd(
1741 &self,
1742 _mu: f64,
1743 _sigma: f64,
1744 _shape: &[usize],
1745 ) -> anyhow::Result<GpuTensorHandle> {
1746 Err(anyhow::anyhow!("random_normrnd not supported by provider"))
1747 }
1748
1749 fn random_unifrnd(
1751 &self,
1752 _a: f64,
1753 _b: f64,
1754 _shape: &[usize],
1755 ) -> anyhow::Result<GpuTensorHandle> {
1756 Err(anyhow::anyhow!("random_unifrnd not supported by provider"))
1757 }
1758
1759 fn stochastic_evolution(
1760 &self,
1761 _state: &GpuTensorHandle,
1762 _drift: f64,
1763 _scale: f64,
1764 _steps: u32,
1765 ) -> anyhow::Result<GpuTensorHandle> {
1766 Err(anyhow::anyhow!(
1767 "stochastic_evolution not supported by provider"
1768 ))
1769 }
1770
1771 fn set_rng_state(&self, _state: u64) -> anyhow::Result<()> {
1773 Err(anyhow::anyhow!("set_rng_state not supported by provider"))
1774 }
1775
1776 fn fspecial(&self, _request: &FspecialRequest) -> anyhow::Result<GpuTensorHandle> {
1778 Err(anyhow::anyhow!("fspecial not supported by provider"))
1779 }
1780
1781 fn peaks(&self, _n: usize) -> anyhow::Result<GpuTensorHandle> {
1784 Err(anyhow::anyhow!("peaks not supported by provider"))
1785 }
1786
1787 fn peaks_xy(
1790 &self,
1791 _x: &GpuTensorHandle,
1792 _y: &GpuTensorHandle,
1793 ) -> anyhow::Result<GpuTensorHandle> {
1794 Err(anyhow::anyhow!("peaks_xy not supported by provider"))
1795 }
1796
1797 fn hann_window(&self, _len: usize, _periodic: bool) -> anyhow::Result<GpuTensorHandle> {
1798 Err(anyhow::anyhow!("hann_window not supported by provider"))
1799 }
1800
1801 fn hamming_window(&self, _len: usize, _periodic: bool) -> anyhow::Result<GpuTensorHandle> {
1802 Err(anyhow::anyhow!("hamming_window not supported by provider"))
1803 }
1804
1805 fn blackman_window(&self, _len: usize, _periodic: bool) -> anyhow::Result<GpuTensorHandle> {
1806 Err(anyhow::anyhow!("blackman_window not supported by provider"))
1807 }
1808
1809 fn imfilter<'a>(
1811 &'a self,
1812 _image: &'a GpuTensorHandle,
1813 _kernel: &'a GpuTensorHandle,
1814 _options: &'a ImfilterOptions,
1815 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1816 unsupported_future("imfilter not supported by provider")
1817 }
1818
1819 fn random_integer_range(
1821 &self,
1822 _lower: i64,
1823 _upper: i64,
1824 _shape: &[usize],
1825 ) -> anyhow::Result<GpuTensorHandle> {
1826 Err(anyhow::anyhow!(
1827 "random_integer_range not supported by provider"
1828 ))
1829 }
1830
1831 fn random_integer_like(
1833 &self,
1834 prototype: &GpuTensorHandle,
1835 lower: i64,
1836 upper: i64,
1837 ) -> anyhow::Result<GpuTensorHandle> {
1838 self.random_integer_range(lower, upper, &prototype.shape)
1839 }
1840
1841 fn random_permutation(&self, _n: usize, _k: usize) -> anyhow::Result<GpuTensorHandle> {
1843 Err(anyhow!("random_permutation not supported by provider"))
1844 }
1845
1846 fn random_permutation_like(
1848 &self,
1849 _prototype: &GpuTensorHandle,
1850 n: usize,
1851 k: usize,
1852 ) -> anyhow::Result<GpuTensorHandle> {
1853 self.random_permutation(n, k)
1854 }
1855
1856 fn covariance<'a>(
1858 &'a self,
1859 _matrix: &'a GpuTensorHandle,
1860 _second: Option<&'a GpuTensorHandle>,
1861 _weights: Option<&'a GpuTensorHandle>,
1862 _options: &'a CovarianceOptions,
1863 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1864 unsupported_future("covariance not supported by provider")
1865 }
1866
1867 fn corrcoef<'a>(
1869 &'a self,
1870 _matrix: &'a GpuTensorHandle,
1871 _options: &'a CorrcoefOptions,
1872 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1873 unsupported_future("corrcoef not supported by provider")
1874 }
1875
1876 fn covariance_to_correlation(
1878 &self,
1879 _matrix: &GpuTensorHandle,
1880 ) -> anyhow::Result<ProviderCovarianceToCorrelationResult> {
1881 Err(anyhow::anyhow!(
1882 "covariance_to_correlation not supported by provider"
1883 ))
1884 }
1885
1886 fn linspace(&self, _start: f64, _stop: f64, _count: usize) -> anyhow::Result<GpuTensorHandle> {
1888 Err(anyhow::anyhow!("linspace not supported by provider"))
1889 }
1890 fn elem_add<'a>(
1891 &'a self,
1892 _a: &'a GpuTensorHandle,
1893 _b: &'a GpuTensorHandle,
1894 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1895 unsupported_future("elem_add not supported by provider")
1896 }
1897 fn elem_mul<'a>(
1898 &'a self,
1899 _a: &'a GpuTensorHandle,
1900 _b: &'a GpuTensorHandle,
1901 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1902 unsupported_future("elem_mul not supported by provider")
1903 }
1904 fn elem_max<'a>(
1905 &'a self,
1906 _a: &'a GpuTensorHandle,
1907 _b: &'a GpuTensorHandle,
1908 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1909 unsupported_future("elem_max not supported by provider")
1910 }
1911 fn elem_min<'a>(
1912 &'a self,
1913 _a: &'a GpuTensorHandle,
1914 _b: &'a GpuTensorHandle,
1915 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1916 unsupported_future("elem_min not supported by provider")
1917 }
1918 fn elem_sub<'a>(
1919 &'a self,
1920 _a: &'a GpuTensorHandle,
1921 _b: &'a GpuTensorHandle,
1922 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1923 unsupported_future("elem_sub not supported by provider")
1924 }
1925 fn elem_div<'a>(
1926 &'a self,
1927 _a: &'a GpuTensorHandle,
1928 _b: &'a GpuTensorHandle,
1929 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1930 unsupported_future("elem_div not supported by provider")
1931 }
1932 fn elem_pow<'a>(
1933 &'a self,
1934 _a: &'a GpuTensorHandle,
1935 _b: &'a GpuTensorHandle,
1936 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1937 unsupported_future("elem_pow not supported by provider")
1938 }
1939
1940 fn complex_from_real<'a>(
1943 &'a self,
1944 _real: &'a GpuTensorHandle,
1945 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1946 unsupported_future("complex_from_real not supported by provider")
1947 }
1948
1949 fn complex_from_real_imag<'a>(
1954 &'a self,
1955 _real: &'a GpuTensorHandle,
1956 _imag: &'a GpuTensorHandle,
1957 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1958 unsupported_future("complex_from_real_imag not supported by provider")
1959 }
1960
1961 fn modulate_constellation<'a>(
1964 &'a self,
1965 _request: ProviderModulationRequest<'a>,
1966 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1967 unsupported_future("modulate_constellation not supported by provider")
1968 }
1969
1970 fn modulate_bits_constellation<'a>(
1973 &'a self,
1974 _request: ProviderBitModulationRequest<'a>,
1975 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1976 unsupported_future("modulate_bits_constellation not supported by provider")
1977 }
1978
1979 fn elem_hypot<'a>(
1980 &'a self,
1981 _a: &'a GpuTensorHandle,
1982 _b: &'a GpuTensorHandle,
1983 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1984 unsupported_future("elem_hypot not supported by provider")
1985 }
1986 fn elem_ge<'a>(
1987 &'a self,
1988 _a: &'a GpuTensorHandle,
1989 _b: &'a GpuTensorHandle,
1990 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1991 unsupported_future("elem_ge not supported by provider")
1992 }
1993 fn elem_le<'a>(
1994 &'a self,
1995 _a: &'a GpuTensorHandle,
1996 _b: &'a GpuTensorHandle,
1997 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
1998 unsupported_future("elem_le not supported by provider")
1999 }
2000 fn elem_lt<'a>(
2001 &'a self,
2002 _a: &'a GpuTensorHandle,
2003 _b: &'a GpuTensorHandle,
2004 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2005 unsupported_future("elem_lt not supported by provider")
2006 }
2007 fn elem_gt<'a>(
2008 &'a self,
2009 _a: &'a GpuTensorHandle,
2010 _b: &'a GpuTensorHandle,
2011 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2012 unsupported_future("elem_gt not supported by provider")
2013 }
2014 fn elem_eq<'a>(
2015 &'a self,
2016 _a: &'a GpuTensorHandle,
2017 _b: &'a GpuTensorHandle,
2018 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2019 unsupported_future("elem_eq not supported by provider")
2020 }
2021 fn elem_ne<'a>(
2022 &'a self,
2023 _a: &'a GpuTensorHandle,
2024 _b: &'a GpuTensorHandle,
2025 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2026 unsupported_future("elem_ne not supported by provider")
2027 }
2028 fn logical_and(
2029 &self,
2030 _a: &GpuTensorHandle,
2031 _b: &GpuTensorHandle,
2032 ) -> anyhow::Result<GpuTensorHandle> {
2033 Err(anyhow::anyhow!("logical_and not supported by provider"))
2034 }
2035 fn logical_or(
2036 &self,
2037 _a: &GpuTensorHandle,
2038 _b: &GpuTensorHandle,
2039 ) -> anyhow::Result<GpuTensorHandle> {
2040 Err(anyhow::anyhow!("logical_or not supported by provider"))
2041 }
2042 fn logical_xor(
2043 &self,
2044 _a: &GpuTensorHandle,
2045 _b: &GpuTensorHandle,
2046 ) -> anyhow::Result<GpuTensorHandle> {
2047 Err(anyhow::anyhow!("logical_xor not supported by provider"))
2048 }
2049 fn logical_not(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2050 Err(anyhow::anyhow!("logical_not not supported by provider"))
2051 }
2052 fn logical_islogical(&self, a: &GpuTensorHandle) -> anyhow::Result<bool> {
2053 Ok(handle_is_logical(a))
2054 }
2055 fn logical_isreal(&self, _a: &GpuTensorHandle) -> anyhow::Result<bool> {
2056 Err(anyhow::anyhow!("logical_isreal not supported by provider"))
2057 }
2058 fn logical_isfinite(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2059 Err(anyhow::anyhow!(
2060 "logical_isfinite not supported by provider"
2061 ))
2062 }
2063 fn logical_isnan(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2064 Err(anyhow::anyhow!("logical_isnan not supported by provider"))
2065 }
2066 fn logical_isinf(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2067 Err(anyhow::anyhow!("logical_isinf not supported by provider"))
2068 }
2069 fn elem_atan2<'a>(
2070 &'a self,
2071 _y: &'a GpuTensorHandle,
2072 _x: &'a GpuTensorHandle,
2073 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2074 unsupported_future("elem_atan2 not supported by provider")
2075 }
2076 fn unary_sin<'a>(
2078 &'a self,
2079 _a: &'a GpuTensorHandle,
2080 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2081 unsupported_future("unary_sin not supported by provider")
2082 }
2083 fn unary_sinc<'a>(
2084 &'a self,
2085 _a: &'a GpuTensorHandle,
2086 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2087 unsupported_future("unary_sinc not supported by provider")
2088 }
2089 fn unary_gamma<'a>(
2090 &'a self,
2091 _a: &'a GpuTensorHandle,
2092 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2093 unsupported_future("unary_gamma not supported by provider")
2094 }
2095 fn unary_gammaln<'a>(
2096 &'a self,
2097 _a: &'a GpuTensorHandle,
2098 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2099 unsupported_future("unary_gammaln not supported by provider")
2100 }
2101 fn unary_erf<'a>(
2102 &'a self,
2103 _a: &'a GpuTensorHandle,
2104 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2105 unsupported_future("unary_erf not supported by provider")
2106 }
2107 fn unary_erfcinv<'a>(
2108 &'a self,
2109 _a: &'a GpuTensorHandle,
2110 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2111 unsupported_future("unary_erfcinv not supported by provider")
2112 }
2113 fn unary_factorial<'a>(
2114 &'a self,
2115 _a: &'a GpuTensorHandle,
2116 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2117 unsupported_future("unary_factorial not supported by provider")
2118 }
2119 fn unary_asinh<'a>(
2120 &'a self,
2121 _a: &'a GpuTensorHandle,
2122 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2123 unsupported_future("unary_asinh not supported by provider")
2124 }
2125 fn unary_sinh<'a>(
2126 &'a self,
2127 _a: &'a GpuTensorHandle,
2128 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2129 unsupported_future("unary_sinh not supported by provider")
2130 }
2131 fn unary_cosh<'a>(
2132 &'a self,
2133 _a: &'a GpuTensorHandle,
2134 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2135 unsupported_future("unary_cosh not supported by provider")
2136 }
2137 fn unary_asin<'a>(
2138 &'a self,
2139 _a: &'a GpuTensorHandle,
2140 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2141 unsupported_future("unary_asin not supported by provider")
2142 }
2143 fn unary_acos<'a>(
2144 &'a self,
2145 _a: &'a GpuTensorHandle,
2146 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2147 unsupported_future("unary_acos not supported by provider")
2148 }
2149 fn unary_acosh<'a>(
2150 &'a self,
2151 _a: &'a GpuTensorHandle,
2152 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2153 unsupported_future("unary_acosh not supported by provider")
2154 }
2155 fn unary_tan<'a>(
2156 &'a self,
2157 _a: &'a GpuTensorHandle,
2158 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2159 unsupported_future("unary_tan not supported by provider")
2160 }
2161 fn unary_tanh<'a>(
2162 &'a self,
2163 _a: &'a GpuTensorHandle,
2164 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2165 unsupported_future("unary_tanh not supported by provider")
2166 }
2167 fn unary_atan<'a>(
2168 &'a self,
2169 _a: &'a GpuTensorHandle,
2170 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2171 unsupported_future("unary_atan not supported by provider")
2172 }
2173 fn unary_atanh<'a>(
2174 &'a self,
2175 _a: &'a GpuTensorHandle,
2176 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2177 unsupported_future("unary_atanh not supported by provider")
2178 }
2179 fn unary_ceil<'a>(
2180 &'a self,
2181 _a: &'a GpuTensorHandle,
2182 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2183 unsupported_future("unary_ceil not supported by provider")
2184 }
2185 fn unary_floor<'a>(
2186 &'a self,
2187 _a: &'a GpuTensorHandle,
2188 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2189 unsupported_future("unary_floor not supported by provider")
2190 }
2191 fn unary_round<'a>(
2192 &'a self,
2193 _a: &'a GpuTensorHandle,
2194 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2195 unsupported_future("unary_round not supported by provider")
2196 }
2197 fn round_digits<'a>(
2198 &'a self,
2199 _a: &'a GpuTensorHandle,
2200 _digits: i32,
2201 _significant: bool,
2202 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2203 unsupported_future("round_digits not supported by provider")
2204 }
2205 fn unary_fix<'a>(
2206 &'a self,
2207 _a: &'a GpuTensorHandle,
2208 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2209 unsupported_future("unary_fix not supported by provider")
2210 }
2211 fn unary_cos<'a>(
2212 &'a self,
2213 _a: &'a GpuTensorHandle,
2214 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2215 unsupported_future("unary_cos not supported by provider")
2216 }
2217 fn unary_angle<'a>(
2218 &'a self,
2219 _a: &'a GpuTensorHandle,
2220 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2221 unsupported_future("unary_angle not supported by provider")
2222 }
2223 fn unary_imag<'a>(
2224 &'a self,
2225 _a: &'a GpuTensorHandle,
2226 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2227 unsupported_future("unary_imag not supported by provider")
2228 }
2229 fn unary_real<'a>(
2230 &'a self,
2231 _a: &'a GpuTensorHandle,
2232 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2233 unsupported_future("unary_real not supported by provider")
2234 }
2235 fn unary_conj<'a>(
2236 &'a self,
2237 _a: &'a GpuTensorHandle,
2238 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2239 unsupported_future("unary_conj not supported by provider")
2240 }
2241 fn unary_abs<'a>(
2242 &'a self,
2243 _a: &'a GpuTensorHandle,
2244 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2245 unsupported_future("unary_abs not supported by provider")
2246 }
2247 fn unary_sign<'a>(
2248 &'a self,
2249 _a: &'a GpuTensorHandle,
2250 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2251 unsupported_future("unary_sign not supported by provider")
2252 }
2253 fn unary_heaviside<'a>(
2254 &'a self,
2255 _a: &'a GpuTensorHandle,
2256 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2257 unsupported_future("unary_heaviside not supported by provider")
2258 }
2259 fn unary_exp<'a>(
2260 &'a self,
2261 _a: &'a GpuTensorHandle,
2262 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2263 unsupported_future("unary_exp not supported by provider")
2264 }
2265 fn unary_expm1<'a>(
2266 &'a self,
2267 _a: &'a GpuTensorHandle,
2268 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2269 unsupported_future("unary_expm1 not supported by provider")
2270 }
2271 fn unary_log<'a>(
2272 &'a self,
2273 _a: &'a GpuTensorHandle,
2274 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2275 unsupported_future("unary_log not supported by provider")
2276 }
2277 fn unary_log2<'a>(
2278 &'a self,
2279 _a: &'a GpuTensorHandle,
2280 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2281 unsupported_future("unary_log2 not supported by provider")
2282 }
2283 fn unary_log10<'a>(
2284 &'a self,
2285 _a: &'a GpuTensorHandle,
2286 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2287 unsupported_future("unary_log10 not supported by provider")
2288 }
2289 fn unary_log1p<'a>(
2290 &'a self,
2291 _a: &'a GpuTensorHandle,
2292 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2293 unsupported_future("unary_log1p not supported by provider")
2294 }
2295 fn unary_sqrt<'a>(
2296 &'a self,
2297 _a: &'a GpuTensorHandle,
2298 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2299 unsupported_future("unary_sqrt not supported by provider")
2300 }
2301 fn unary_double<'a>(
2302 &'a self,
2303 _a: &'a GpuTensorHandle,
2304 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2305 unsupported_future("unary_double not supported by provider")
2306 }
2307 fn unary_single<'a>(
2308 &'a self,
2309 _a: &'a GpuTensorHandle,
2310 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2311 unsupported_future("unary_single not supported by provider")
2312 }
2313 fn unary_pow2<'a>(
2314 &'a self,
2315 _a: &'a GpuTensorHandle,
2316 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2317 unsupported_future("unary_pow2 not supported by provider")
2318 }
2319 fn unary_nextpow2<'a>(
2320 &'a self,
2321 _a: &'a GpuTensorHandle,
2322 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2323 unsupported_future("unary_nextpow2 not supported by provider")
2324 }
2325 fn pow2_scale(
2326 &self,
2327 _mantissa: &GpuTensorHandle,
2328 _exponent: &GpuTensorHandle,
2329 ) -> anyhow::Result<GpuTensorHandle> {
2330 Err(anyhow::anyhow!("pow2_scale not supported by provider"))
2331 }
2332 fn scalar_rsub(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2334 Err(anyhow::anyhow!("scalar_rsub not supported by provider"))
2335 }
2336 fn scalar_rdiv(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2337 Err(anyhow::anyhow!("scalar_rdiv not supported by provider"))
2338 }
2339 fn scalar_add(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2341 Err(anyhow::anyhow!("scalar_add not supported by provider"))
2342 }
2343 fn scalar_sub(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2344 Err(anyhow::anyhow!("scalar_sub not supported by provider"))
2345 }
2346 fn scalar_mul(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2347 Err(anyhow::anyhow!("scalar_mul not supported by provider"))
2348 }
2349 fn scalar_max(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2350 Err(anyhow::anyhow!("scalar_max not supported by provider"))
2351 }
2352 fn scalar_min(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2353 Err(anyhow::anyhow!("scalar_min not supported by provider"))
2354 }
2355 fn scalar_div(&self, _a: &GpuTensorHandle, _scalar: f64) -> anyhow::Result<GpuTensorHandle> {
2356 Err(anyhow::anyhow!("scalar_div not supported by provider"))
2357 }
2358 fn sort_dim<'a>(
2359 &'a self,
2360 _a: &'a GpuTensorHandle,
2361 _dim: usize,
2362 _order: SortOrder,
2363 _comparison: SortComparison,
2364 ) -> AccelProviderFuture<'a, SortResult> {
2365 unsupported_future("sort_dim not supported by provider")
2366 }
2367 fn sort_rows<'a>(
2368 &'a self,
2369 _a: &'a GpuTensorHandle,
2370 _columns: &'a [SortRowsColumnSpec],
2371 _comparison: SortComparison,
2372 ) -> AccelProviderFuture<'a, SortResult> {
2373 unsupported_future("sort_rows not supported by provider")
2374 }
2375 fn matmul<'a>(
2376 &'a self,
2377 _a: &'a GpuTensorHandle,
2378 _b: &'a GpuTensorHandle,
2379 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2380 unsupported_future("matmul not supported by provider")
2381 }
2382
2383 fn syrk(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2384 Err(anyhow::anyhow!("syrk not supported by provider"))
2385 }
2386 fn pagefun(&self, _request: &PagefunRequest) -> anyhow::Result<GpuTensorHandle> {
2387 Err(anyhow::anyhow!("pagefun not supported by provider"))
2388 }
2389
2390 fn matmul_epilogue<'a>(
2395 &'a self,
2396 a: &'a GpuTensorHandle,
2397 b: &'a GpuTensorHandle,
2398 epilogue: &'a MatmulEpilogue,
2399 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2400 Box::pin(async move {
2401 if epilogue.is_noop() {
2402 return self.matmul(a, b).await;
2403 }
2404 Err(anyhow::anyhow!("matmul_epilogue not supported by provider"))
2405 })
2406 }
2407 fn image_normalize<'a>(
2408 &'a self,
2409 _input: &'a GpuTensorHandle,
2410 _desc: &'a ImageNormalizeDescriptor,
2411 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2412 unsupported_future("image_normalize fusion not supported by provider")
2413 }
2414 fn matmul_power_step<'a>(
2415 &'a self,
2416 _lhs: &'a GpuTensorHandle,
2417 _rhs: &'a GpuTensorHandle,
2418 _epilogue: &'a PowerStepEpilogue,
2419 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2420 unsupported_future("matmul_power_step normalization not supported by provider")
2421 }
2422 fn linsolve<'a>(
2423 &'a self,
2424 _lhs: &'a GpuTensorHandle,
2425 _rhs: &'a GpuTensorHandle,
2426 _options: &'a ProviderLinsolveOptions,
2427 ) -> AccelProviderFuture<'a, ProviderLinsolveResult> {
2428 unsupported_future("linsolve not supported by provider")
2429 }
2430 fn inv<'a>(
2431 &'a self,
2432 _matrix: &'a GpuTensorHandle,
2433 _options: ProviderInvOptions,
2434 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2435 unsupported_future("inv not supported by provider")
2436 }
2437 fn pinv<'a>(
2438 &'a self,
2439 _matrix: &'a GpuTensorHandle,
2440 _options: ProviderPinvOptions,
2441 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2442 unsupported_future("pinv not supported by provider")
2443 }
2444 fn cond<'a>(
2445 &'a self,
2446 _matrix: &'a GpuTensorHandle,
2447 _norm: ProviderCondNorm,
2448 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2449 Box::pin(async move { Err(anyhow::anyhow!("cond not supported by provider")) })
2450 }
2451 fn norm<'a>(
2452 &'a self,
2453 _tensor: &'a GpuTensorHandle,
2454 _order: ProviderNormOrder,
2455 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2456 Box::pin(async move { Err(anyhow::anyhow!("norm not supported by provider")) })
2457 }
2458 fn interp1<'a>(
2459 &'a self,
2460 _request: &'a ProviderInterp1Request<'a>,
2461 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2462 unsupported_future("interp1 not supported by provider")
2463 }
2464 fn rank<'a>(
2465 &'a self,
2466 _matrix: &'a GpuTensorHandle,
2467 _tolerance: Option<f64>,
2468 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2469 Box::pin(async move { Err(anyhow::anyhow!("rank not supported by provider")) })
2470 }
2471 fn rcond<'a>(
2472 &'a self,
2473 _matrix: &'a GpuTensorHandle,
2474 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2475 Box::pin(async move { Err(anyhow::anyhow!("rcond not supported by provider")) })
2476 }
2477 fn mldivide<'a>(
2478 &'a self,
2479 _lhs: &'a GpuTensorHandle,
2480 _rhs: &'a GpuTensorHandle,
2481 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2482 Box::pin(async move { Err(anyhow::anyhow!("mldivide not supported by provider")) })
2483 }
2484 fn mrdivide<'a>(
2485 &'a self,
2486 _lhs: &'a GpuTensorHandle,
2487 _rhs: &'a GpuTensorHandle,
2488 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2489 Box::pin(async move { Err(anyhow::anyhow!("mrdivide not supported by provider")) })
2490 }
2491 fn eig<'a>(
2492 &'a self,
2493 _a: &'a GpuTensorHandle,
2494 _compute_left: bool,
2495 ) -> AccelProviderFuture<'a, ProviderEigResult> {
2496 Box::pin(async move { Err(anyhow::anyhow!("eig not supported by provider")) })
2497 }
2498 fn lu<'a>(&'a self, _a: &'a GpuTensorHandle) -> AccelProviderFuture<'a, ProviderLuResult> {
2499 Box::pin(async move { Err(anyhow::anyhow!("lu not supported by provider")) })
2500 }
2501
2502 fn chol<'a>(
2503 &'a self,
2504 _a: &'a GpuTensorHandle,
2505 _lower: bool,
2506 ) -> AccelProviderFuture<'a, ProviderCholResult> {
2507 Box::pin(async move { Err(anyhow::anyhow!("chol not supported by provider")) })
2508 }
2509 fn qr<'a>(
2510 &'a self,
2511 _a: &'a GpuTensorHandle,
2512 _options: ProviderQrOptions,
2513 ) -> AccelProviderFuture<'a, ProviderQrResult> {
2514 Box::pin(async move { Err(anyhow::anyhow!("qr not supported by provider")) })
2515 }
2516 fn take_matmul_sources(
2517 &self,
2518 _product: &GpuTensorHandle,
2519 ) -> Option<(GpuTensorHandle, GpuTensorHandle)> {
2520 None
2521 }
2522 fn qr_power_iter<'a>(
2523 &'a self,
2524 product: &'a GpuTensorHandle,
2525 _product_lhs: Option<&'a GpuTensorHandle>,
2526 q_handle: &'a GpuTensorHandle,
2527 options: &'a ProviderQrOptions,
2528 ) -> AccelProviderFuture<'a, Option<ProviderQrPowerIterResult>> {
2529 let _ = (product, q_handle, options);
2530 Box::pin(async move { Ok(None) })
2531 }
2532 fn transpose(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2533 Err(anyhow::anyhow!("transpose not supported by provider"))
2534 }
2535 fn conv1d(
2536 &self,
2537 _signal: &GpuTensorHandle,
2538 _kernel: &GpuTensorHandle,
2539 _options: ProviderConv1dOptions,
2540 ) -> anyhow::Result<GpuTensorHandle> {
2541 Err(anyhow::anyhow!("conv1d not supported by provider"))
2542 }
2543 fn conv2d(
2544 &self,
2545 _signal: &GpuTensorHandle,
2546 _kernel: &GpuTensorHandle,
2547 _mode: ProviderConvMode,
2548 ) -> anyhow::Result<GpuTensorHandle> {
2549 Err(anyhow::anyhow!("conv2d not supported by provider"))
2550 }
2551 fn iir_filter<'a>(
2552 &'a self,
2553 _b: &'a GpuTensorHandle,
2554 _a: &'a GpuTensorHandle,
2555 _x: &'a GpuTensorHandle,
2556 _options: ProviderIirFilterOptions,
2557 ) -> AccelProviderFuture<'a, ProviderIirFilterResult> {
2558 Box::pin(async move { Err(anyhow::anyhow!("iir_filter not supported by provider")) })
2559 }
2560 fn uniform_spectral_estimate<'a>(
2561 &'a self,
2562 _request: &'a ProviderSpectralRequest<'a>,
2563 ) -> AccelProviderFuture<'a, ProviderSpectralResult> {
2564 unsupported_future("uniform_spectral_estimate not supported by provider")
2565 }
2566 fn signal_envelope<'a>(
2567 &'a self,
2568 _request: &'a ProviderEnvelopeRequest<'a>,
2569 ) -> AccelProviderFuture<'a, ProviderEnvelopeResult> {
2570 unsupported_future("signal_envelope not supported by provider")
2571 }
2572 fn signal_hilbert<'a>(
2573 &'a self,
2574 _request: &'a ProviderHilbertRequest<'a>,
2575 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2576 unsupported_future("signal_hilbert not supported by provider")
2577 }
2578 fn permute(
2580 &self,
2581 _handle: &GpuTensorHandle,
2582 _order: &[usize],
2583 ) -> anyhow::Result<GpuTensorHandle> {
2584 Err(anyhow::anyhow!("permute not supported by provider"))
2585 }
2586 fn flip(&self, _handle: &GpuTensorHandle, _axes: &[usize]) -> anyhow::Result<GpuTensorHandle> {
2587 Err(anyhow::anyhow!("flip not supported by provider"))
2588 }
2589 fn circshift(
2590 &self,
2591 _handle: &GpuTensorHandle,
2592 _shifts: &[isize],
2593 ) -> anyhow::Result<GpuTensorHandle> {
2594 Err(anyhow::anyhow!("circshift not supported by provider"))
2595 }
2596 fn diff_dim(
2597 &self,
2598 _handle: &GpuTensorHandle,
2599 _order: usize,
2600 _dim: usize,
2601 ) -> anyhow::Result<GpuTensorHandle> {
2602 Err(anyhow::anyhow!("diff_dim not supported by provider"))
2603 }
2604 fn gradient_dim(
2605 &self,
2606 _handle: &GpuTensorHandle,
2607 _dim: usize,
2608 _spacing: f64,
2609 ) -> anyhow::Result<GpuTensorHandle> {
2610 Err(anyhow::anyhow!("gradient_dim not supported by provider"))
2611 }
2612 fn gradient_dim_with_coordinates(
2613 &self,
2614 _handle: &GpuTensorHandle,
2615 _dim: usize,
2616 _coordinates: &GpuTensorHandle,
2617 ) -> anyhow::Result<GpuTensorHandle> {
2618 Err(anyhow::anyhow!(
2619 "gradient_dim_with_coordinates not supported by provider"
2620 ))
2621 }
2622 fn fft_dim<'a>(
2624 &'a self,
2625 _handle: &'a GpuTensorHandle,
2626 _len: Option<usize>,
2627 _dim: usize,
2628 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2629 unsupported_future("fft_dim not supported by provider")
2630 }
2631 fn ifft_dim<'a>(
2632 &'a self,
2633 _handle: &'a GpuTensorHandle,
2634 _len: Option<usize>,
2635 _dim: usize,
2636 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2637 unsupported_future("ifft_dim not supported by provider")
2638 }
2639 fn fft_extract_real<'a>(
2640 &'a self,
2641 _handle: &'a GpuTensorHandle,
2642 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2643 unsupported_future("fft_extract_real not supported by provider")
2644 }
2645 fn unique<'a>(
2646 &'a self,
2647 _handle: &'a GpuTensorHandle,
2648 _options: &'a UniqueOptions,
2649 ) -> AccelProviderFuture<'a, UniqueResult> {
2650 Box::pin(async move { Err(anyhow::anyhow!("unique not supported by provider")) })
2651 }
2652 fn union<'a>(
2653 &'a self,
2654 _a: &'a GpuTensorHandle,
2655 _b: &'a GpuTensorHandle,
2656 _options: &'a UnionOptions,
2657 ) -> AccelProviderFuture<'a, UnionResult> {
2658 Box::pin(async move { Err(anyhow::anyhow!("union not supported by provider")) })
2659 }
2660 fn setdiff<'a>(
2661 &'a self,
2662 _a: &'a GpuTensorHandle,
2663 _b: &'a GpuTensorHandle,
2664 _options: &'a SetdiffOptions,
2665 ) -> AccelProviderFuture<'a, SetdiffResult> {
2666 Box::pin(async move { Err(anyhow::anyhow!("setdiff not supported by provider")) })
2667 }
2668 fn ismember<'a>(
2669 &'a self,
2670 _a: &'a GpuTensorHandle,
2671 _b: &'a GpuTensorHandle,
2672 _options: &'a IsMemberOptions,
2673 ) -> AccelProviderFuture<'a, IsMemberResult> {
2674 Box::pin(async move { Err(anyhow::anyhow!("ismember not supported by provider")) })
2675 }
2676 fn reshape(
2677 &self,
2678 handle: &GpuTensorHandle,
2679 new_shape: &[usize],
2680 ) -> anyhow::Result<GpuTensorHandle> {
2681 let mut updated = handle.clone();
2682 updated.shape = new_shape.to_vec();
2683 Ok(updated)
2684 }
2685 fn cat(&self, _dim: usize, _inputs: &[GpuTensorHandle]) -> anyhow::Result<GpuTensorHandle> {
2687 Err(anyhow::anyhow!("cat not supported by provider"))
2688 }
2689 fn repmat(
2690 &self,
2691 _handle: &GpuTensorHandle,
2692 _reps: &[usize],
2693 ) -> anyhow::Result<GpuTensorHandle> {
2694 Err(anyhow::anyhow!("repmat not supported by provider"))
2695 }
2696 fn kron(&self, _a: &GpuTensorHandle, _b: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2698 Err(anyhow::anyhow!("kron not supported by provider"))
2699 }
2700 fn cross(
2702 &self,
2703 _lhs: &GpuTensorHandle,
2704 _rhs: &GpuTensorHandle,
2705 _dim: Option<usize>,
2706 ) -> anyhow::Result<GpuTensorHandle> {
2707 Err(anyhow::anyhow!("cross not supported by provider"))
2708 }
2709 fn reduce_sum<'a>(
2710 &'a self,
2711 _a: &'a GpuTensorHandle,
2712 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2713 unsupported_future("reduce_sum not supported by provider")
2714 }
2715 fn reduce_sum_dim<'a>(
2716 &'a self,
2717 _a: &'a GpuTensorHandle,
2718 _dim: usize,
2719 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2720 unsupported_future("reduce_sum_dim not supported by provider")
2721 }
2722 fn dot<'a>(
2723 &'a self,
2724 _lhs: &'a GpuTensorHandle,
2725 _rhs: &'a GpuTensorHandle,
2726 _dim: Option<usize>,
2727 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2728 unsupported_future("dot not supported by provider")
2729 }
2730 fn reduce_nnz<'a>(
2731 &'a self,
2732 _a: &'a GpuTensorHandle,
2733 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2734 unsupported_future("reduce_nnz not supported by provider")
2735 }
2736 fn reduce_nnz_dim<'a>(
2737 &'a self,
2738 _a: &'a GpuTensorHandle,
2739 _dim: usize,
2740 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2741 unsupported_future("reduce_nnz_dim not supported by provider")
2742 }
2743 fn reduce_prod<'a>(
2744 &'a self,
2745 _a: &'a GpuTensorHandle,
2746 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2747 unsupported_future("reduce_prod not supported by provider")
2748 }
2749 fn reduce_prod_dim<'a>(
2750 &'a self,
2751 _a: &'a GpuTensorHandle,
2752 _dim: usize,
2753 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2754 unsupported_future("reduce_prod_dim not supported by provider")
2755 }
2756 fn reduce_mean<'a>(
2757 &'a self,
2758 _a: &'a GpuTensorHandle,
2759 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2760 unsupported_future("reduce_mean not supported by provider")
2761 }
2762 fn reduce_mean_nd<'a>(
2764 &'a self,
2765 _a: &'a GpuTensorHandle,
2766 _dims_zero_based: &'a [usize],
2767 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2768 unsupported_future("reduce_mean_nd not supported by provider")
2769 }
2770 fn reduce_moments_nd<'a>(
2773 &'a self,
2774 _a: &'a GpuTensorHandle,
2775 _dims_zero_based: &'a [usize],
2776 ) -> AccelProviderFuture<'a, ProviderMoments2> {
2777 unsupported_future("reduce_moments_nd not supported by provider")
2778 }
2779 fn reduce_mean_dim<'a>(
2780 &'a self,
2781 _a: &'a GpuTensorHandle,
2782 _dim: usize,
2783 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2784 unsupported_future("reduce_mean_dim not supported by provider")
2785 }
2786 fn reduce_std<'a>(
2787 &'a self,
2788 _a: &'a GpuTensorHandle,
2789 _normalization: ProviderStdNormalization,
2790 _nan_mode: ProviderNanMode,
2791 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2792 unsupported_future("reduce_std not supported by provider")
2793 }
2794 fn reduce_std_dim<'a>(
2795 &'a self,
2796 _a: &'a GpuTensorHandle,
2797 _dim: usize,
2798 _normalization: ProviderStdNormalization,
2799 _nan_mode: ProviderNanMode,
2800 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2801 unsupported_future("reduce_std_dim not supported by provider")
2802 }
2803 fn reduce_any<'a>(
2804 &'a self,
2805 _a: &'a GpuTensorHandle,
2806 _omit_nan: bool,
2807 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2808 unsupported_future("reduce_any not supported by provider")
2809 }
2810 fn reduce_any_dim<'a>(
2811 &'a self,
2812 _a: &'a GpuTensorHandle,
2813 _dim: usize,
2814 _omit_nan: bool,
2815 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2816 unsupported_future("reduce_any_dim not supported by provider")
2817 }
2818 fn reduce_all<'a>(
2819 &'a self,
2820 _a: &'a GpuTensorHandle,
2821 _omit_nan: bool,
2822 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2823 unsupported_future("reduce_all not supported by provider")
2824 }
2825 fn reduce_all_dim<'a>(
2826 &'a self,
2827 _a: &'a GpuTensorHandle,
2828 _dim: usize,
2829 _omit_nan: bool,
2830 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2831 unsupported_future("reduce_all_dim not supported by provider")
2832 }
2833 fn reduce_median<'a>(
2834 &'a self,
2835 _a: &'a GpuTensorHandle,
2836 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2837 unsupported_future("reduce_median not supported by provider")
2838 }
2839 fn reduce_median_dim<'a>(
2840 &'a self,
2841 _a: &'a GpuTensorHandle,
2842 _dim: usize,
2843 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2844 unsupported_future("reduce_median_dim not supported by provider")
2845 }
2846 fn mode_values<'a>(
2847 &'a self,
2848 _request: &'a ProviderModeRequest<'a>,
2849 ) -> AccelProviderFuture<'a, ProviderModeResult> {
2850 unsupported_future("mode_values not supported by provider")
2851 }
2852 fn moving_window<'a>(
2853 &'a self,
2854 _request: &'a ProviderMovingWindowRequest<'a>,
2855 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2856 unsupported_future("moving_window not supported by provider")
2857 }
2858 fn reduce_min<'a>(
2859 &'a self,
2860 _a: &'a GpuTensorHandle,
2861 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2862 unsupported_future("reduce_min not supported by provider")
2863 }
2864 fn reduce_min_dim<'a>(
2865 &'a self,
2866 _a: &'a GpuTensorHandle,
2867 _dim: usize,
2868 ) -> AccelProviderFuture<'a, ReduceDimResult> {
2869 unsupported_future("reduce_min_dim not supported by provider")
2870 }
2871 fn reduce_max<'a>(
2872 &'a self,
2873 _a: &'a GpuTensorHandle,
2874 ) -> AccelProviderFuture<'a, GpuTensorHandle> {
2875 unsupported_future("reduce_max not supported by provider")
2876 }
2877 fn reduce_max_dim<'a>(
2878 &'a self,
2879 _a: &'a GpuTensorHandle,
2880 _dim: usize,
2881 ) -> AccelProviderFuture<'a, ReduceDimResult> {
2882 unsupported_future("reduce_max_dim not supported by provider")
2883 }
2884 fn cumsum_scan(
2885 &self,
2886 _input: &GpuTensorHandle,
2887 _dim: usize,
2888 _direction: ProviderScanDirection,
2889 _nan_mode: ProviderNanMode,
2890 ) -> anyhow::Result<GpuTensorHandle> {
2891 Err(anyhow::anyhow!("cumsum_scan not supported by provider"))
2892 }
2893 fn trapz_dim(
2894 &self,
2895 _input: &GpuTensorHandle,
2896 _dim: usize,
2897 _spacing: ProviderTrapezoidSpacing<'_>,
2898 ) -> anyhow::Result<GpuTensorHandle> {
2899 Err(anyhow::anyhow!("trapz_dim not supported by provider"))
2900 }
2901 fn cumtrapz_dim(
2902 &self,
2903 _input: &GpuTensorHandle,
2904 _dim: usize,
2905 _spacing: ProviderTrapezoidSpacing<'_>,
2906 ) -> anyhow::Result<GpuTensorHandle> {
2907 Err(anyhow::anyhow!("cumtrapz_dim not supported by provider"))
2908 }
2909 fn cumprod_scan(
2910 &self,
2911 _input: &GpuTensorHandle,
2912 _dim: usize,
2913 _direction: ProviderScanDirection,
2914 _nan_mode: ProviderNanMode,
2915 ) -> anyhow::Result<GpuTensorHandle> {
2916 Err(anyhow::anyhow!("cumprod_scan not supported by provider"))
2917 }
2918 fn cummin_scan(
2919 &self,
2920 _input: &GpuTensorHandle,
2921 _dim: usize,
2922 _direction: ProviderScanDirection,
2923 _nan_mode: ProviderNanMode,
2924 ) -> anyhow::Result<ProviderCumminResult> {
2925 Err(anyhow::anyhow!("cummin_scan not supported by provider"))
2926 }
2927 fn cummax_scan(
2928 &self,
2929 _input: &GpuTensorHandle,
2930 _dim: usize,
2931 _direction: ProviderScanDirection,
2932 _nan_mode: ProviderNanMode,
2933 ) -> anyhow::Result<ProviderCummaxResult> {
2934 Err(anyhow::anyhow!("cummax_scan not supported by provider"))
2935 }
2936
2937 fn find(
2938 &self,
2939 _a: &GpuTensorHandle,
2940 _limit: Option<usize>,
2941 _direction: FindDirection,
2942 ) -> anyhow::Result<ProviderFindResult> {
2943 Err(anyhow::anyhow!("find not supported by provider"))
2944 }
2945
2946 fn fused_elementwise(
2947 &self,
2948 _shader: &str,
2949 _inputs: &[GpuTensorHandle],
2950 _output_shape: &[usize],
2951 _len: usize,
2952 ) -> anyhow::Result<GpuTensorHandle> {
2953 Err(anyhow::anyhow!(
2954 "fused_elementwise not supported by provider"
2955 ))
2956 }
2957
2958 fn fused_elementwise_multi(
2967 &self,
2968 _shader: &str,
2969 _inputs: &[GpuTensorHandle],
2970 _output_shape: &[usize],
2971 _len: usize,
2972 _num_outputs: usize,
2973 ) -> anyhow::Result<Vec<GpuTensorHandle>> {
2974 Err(anyhow::anyhow!(
2975 "fused_elementwise_multi not supported by provider"
2976 ))
2977 }
2978
2979 fn map_nan_to_zero(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2981 Err(anyhow::anyhow!("map_nan_to_zero not supported by provider"))
2982 }
2983
2984 fn not_nan_mask(&self, _a: &GpuTensorHandle) -> anyhow::Result<GpuTensorHandle> {
2986 Err(anyhow::anyhow!("not_nan_mask not supported by provider"))
2987 }
2988
2989 #[allow(clippy::too_many_arguments)]
2996 fn fused_reduction(
2997 &self,
2998 _shader: &str,
2999 _inputs: &[GpuTensorHandle],
3000 _output_shape: &[usize],
3001 _reduce_len: usize,
3002 _num_slices: usize,
3003 _workgroup_size: u32,
3004 _flavor: ReductionFlavor,
3005 ) -> anyhow::Result<GpuTensorHandle> {
3006 Err(anyhow::anyhow!("fused_reduction not supported by provider"))
3007 }
3008
3009 fn warmup(&self) {}
3011
3012 fn fused_cache_counters(&self) -> (u64, u64) {
3014 (0, 0)
3015 }
3016
3017 fn last_warmup_millis(&self) -> Option<u64> {
3019 None
3020 }
3021
3022 fn telemetry_snapshot(&self) -> ProviderTelemetry {
3024 let (hits, misses) = self.fused_cache_counters();
3025 ProviderTelemetry {
3026 fused_elementwise: ProviderDispatchStats::default(),
3027 fused_reduction: ProviderDispatchStats::default(),
3028 matmul: ProviderDispatchStats::default(),
3029 linsolve: ProviderDispatchStats::default(),
3030 mldivide: ProviderDispatchStats::default(),
3031 mrdivide: ProviderDispatchStats::default(),
3032 upload_bytes: 0,
3033 download_bytes: 0,
3034 solve_fallbacks: Vec::new(),
3035 fusion_cache_hits: hits,
3036 fusion_cache_misses: misses,
3037 bind_group_cache_hits: 0,
3038 bind_group_cache_misses: 0,
3039 bind_group_cache_by_layout: None,
3040 kernel_launches: Vec::new(),
3041 }
3042 }
3043
3044 fn reset_telemetry(&self) {}
3046
3047 fn default_reduction_workgroup_size(&self) -> u32 {
3049 256
3050 }
3051
3052 fn two_pass_threshold(&self) -> usize {
3054 1024
3055 }
3056
3057 fn reduction_two_pass_mode(&self) -> ReductionTwoPassMode {
3059 ReductionTwoPassMode::Auto
3060 }
3061
3062 fn scatter_column(
3065 &self,
3066 _matrix: &GpuTensorHandle,
3067 _col_index: usize,
3068 _values: &GpuTensorHandle,
3069 ) -> anyhow::Result<GpuTensorHandle> {
3070 Err(anyhow::anyhow!("scatter_column not supported by provider"))
3071 }
3072
3073 fn scatter_row(
3076 &self,
3077 _matrix: &GpuTensorHandle,
3078 _row_index: usize,
3079 _values: &GpuTensorHandle,
3080 ) -> anyhow::Result<GpuTensorHandle> {
3081 Err(anyhow::anyhow!("scatter_row not supported by provider"))
3082 }
3083
3084 fn sub2ind(
3085 &self,
3086 _dims: &[usize],
3087 _strides: &[usize],
3088 _inputs: &[&GpuTensorHandle],
3089 _scalar_mask: &[bool],
3090 _len: usize,
3091 _output_shape: &[usize],
3092 ) -> anyhow::Result<GpuTensorHandle> {
3093 Err(anyhow::anyhow!("sub2ind not supported by provider"))
3094 }
3095
3096 fn supports_ind2sub(&self) -> bool {
3098 false
3099 }
3100
3101 fn ind2sub(
3103 &self,
3104 _dims: &[usize],
3105 _strides: &[usize],
3106 _indices: &GpuTensorHandle,
3107 _total: usize,
3108 _len: usize,
3109 _output_shape: &[usize],
3110 ) -> anyhow::Result<Vec<GpuTensorHandle>> {
3111 Err(anyhow::anyhow!("ind2sub not supported by provider"))
3112 }
3113
3114 fn issymmetric(
3116 &self,
3117 _matrix: &GpuTensorHandle,
3118 _kind: ProviderSymmetryKind,
3119 _tolerance: f64,
3120 ) -> anyhow::Result<bool> {
3121 Err(anyhow::anyhow!(
3122 "issymmetric predicate not supported by provider"
3123 ))
3124 }
3125
3126 fn ishermitian<'a>(
3128 &'a self,
3129 _matrix: &'a GpuTensorHandle,
3130 _kind: ProviderHermitianKind,
3131 _tolerance: f64,
3132 ) -> AccelProviderFuture<'a, bool> {
3133 Box::pin(async move {
3134 Err(anyhow::anyhow!(
3135 "ishermitian predicate not supported by provider"
3136 ))
3137 })
3138 }
3139
3140 fn bandwidth(&self, _matrix: &GpuTensorHandle) -> anyhow::Result<ProviderBandwidth> {
3142 Err(anyhow::anyhow!("bandwidth not supported by provider"))
3143 }
3144
3145 fn sym_rcm<'a>(&'a self, _matrix: &'a GpuTensorHandle) -> AccelProviderFuture<'a, Vec<usize>> {
3150 Box::pin(async move { Err(anyhow::anyhow!("sym_rcm not supported by provider")) })
3151 }
3152}
3153
3154static GLOBAL_PROVIDER: Lazy<RwLock<Option<&'static dyn AccelProvider>>> =
3155 Lazy::new(|| RwLock::new(None));
3156static PROVIDER_REGISTRY: Lazy<RwLock<HashMap<u32, &'static dyn AccelProvider>>> =
3157 Lazy::new(|| RwLock::new(HashMap::new()));
3158static DEVICE_ID_COUNTER: AtomicU32 = AtomicU32::new(1);
3159
3160#[cfg(not(target_arch = "wasm32"))]
3161thread_local! {
3162 static THREAD_PROVIDER: Cell<Option<&'static dyn AccelProvider>> = Cell::new(None);
3163}
3164
3165#[cfg(target_arch = "wasm32")]
3166static WASM_THREAD_PROVIDER: Lazy<Mutex<Option<&'static dyn AccelProvider>>> =
3167 Lazy::new(|| Mutex::new(None));
3168
3169#[cfg(not(target_arch = "wasm32"))]
3170fn replace_thread_provider(
3171 provider: Option<&'static dyn AccelProvider>,
3172) -> Option<&'static dyn AccelProvider> {
3173 THREAD_PROVIDER.with(|cell| {
3174 let prev = cell.get();
3175 cell.set(provider);
3176 prev
3177 })
3178}
3179
3180#[cfg(target_arch = "wasm32")]
3181fn replace_thread_provider(
3182 provider: Option<&'static dyn AccelProvider>,
3183) -> Option<&'static dyn AccelProvider> {
3184 let mut slot = WASM_THREAD_PROVIDER
3185 .lock()
3186 .expect("wasm provider mutex poisoned");
3187 let prev = *slot;
3188 *slot = provider;
3189 prev
3190}
3191
3192#[cfg(not(target_arch = "wasm32"))]
3193fn current_thread_provider() -> Option<&'static dyn AccelProvider> {
3194 THREAD_PROVIDER.with(|cell| cell.get())
3195}
3196
3197#[cfg(target_arch = "wasm32")]
3198fn current_thread_provider() -> Option<&'static dyn AccelProvider> {
3199 WASM_THREAD_PROVIDER
3200 .lock()
3201 .expect("wasm provider mutex poisoned")
3202 .as_ref()
3203 .copied()
3204}
3205
3206pub unsafe fn register_provider(p: &'static dyn AccelProvider) {
3214 replace_thread_provider(Some(p));
3215 if let Ok(mut guard) = GLOBAL_PROVIDER.write() {
3216 *guard = Some(p);
3217 }
3218 register_provider_for_device(p.device_id(), p);
3219}
3220
3221unsafe fn register_provider_for_device(device_id: u32, provider: &'static dyn AccelProvider) {
3222 if let Ok(mut guard) = PROVIDER_REGISTRY.write() {
3223 guard.insert(device_id, provider);
3224 }
3225}
3226
3227pub fn provider() -> Option<&'static dyn AccelProvider> {
3228 if let Some(p) = current_thread_provider() {
3229 return Some(p);
3230 }
3231 GLOBAL_PROVIDER
3232 .read()
3233 .ok()
3234 .and_then(|guard| guard.as_ref().copied())
3235}
3236
3237pub fn clear_provider() {
3244 replace_thread_provider(None);
3245 if let Ok(mut guard) = GLOBAL_PROVIDER.write() {
3246 *guard = None;
3247 }
3248}
3249
3250pub fn provider_for_device(device_id: u32) -> Option<&'static dyn AccelProvider> {
3251 if let Some(registered) = PROVIDER_REGISTRY
3252 .read()
3253 .ok()
3254 .and_then(|guard| guard.get(&device_id).copied())
3255 {
3256 return Some(registered);
3257 }
3258 if let Some(thread_provider) = current_thread_provider() {
3259 if thread_provider.device_id() == device_id {
3260 return Some(thread_provider);
3261 }
3262 }
3263 GLOBAL_PROVIDER
3266 .read()
3267 .ok()
3268 .and_then(|guard| guard.as_ref().copied())
3269}
3270
3271pub fn provider_for_handle(handle: &GpuTensorHandle) -> Option<&'static dyn AccelProvider> {
3272 provider_for_device(handle.device_id)
3273}
3274
3275pub fn spawn_handle_concurrency_for(handle: &GpuTensorHandle) -> Option<SpawnHandleConcurrency> {
3276 provider_for_handle(handle).map(AccelProvider::spawn_handle_concurrency)
3277}
3278
3279pub fn next_device_id() -> u32 {
3280 DEVICE_ID_COUNTER.fetch_add(1, Ordering::Relaxed)
3281}
3282
3283pub struct ThreadProviderGuard {
3284 prev: Option<&'static dyn AccelProvider>,
3285}
3286
3287impl ThreadProviderGuard {
3288 pub fn set(provider: Option<&'static dyn AccelProvider>) -> Self {
3289 let prev = replace_thread_provider(provider);
3290 ThreadProviderGuard { prev }
3291 }
3292}
3293
3294impl Drop for ThreadProviderGuard {
3295 fn drop(&mut self) {
3296 let prev = self.prev.take();
3297 replace_thread_provider(prev);
3298 }
3299}
3300
3301pub fn set_thread_provider(provider: Option<&'static dyn AccelProvider>) {
3302 replace_thread_provider(provider);
3303}
3304
3305pub async fn try_elem_add(a: &GpuTensorHandle, b: &GpuTensorHandle) -> Option<GpuTensorHandle> {
3307 if a.device_id == b.device_id {
3308 let p = provider_for_handle(a)?;
3309 if let Ok(h) = p.elem_add(a, b).await {
3310 return Some(h);
3311 }
3312 }
3313 None
3314}
3315
3316pub async fn try_elem_hypot(a: &GpuTensorHandle, b: &GpuTensorHandle) -> Option<GpuTensorHandle> {
3318 if a.device_id == b.device_id {
3319 let p = provider_for_handle(a)?;
3320 if let Ok(h) = p.elem_hypot(a, b).await {
3321 return Some(h);
3322 }
3323 }
3324 None
3325}
3326
3327pub async fn try_elem_max(a: &GpuTensorHandle, b: &GpuTensorHandle) -> Option<GpuTensorHandle> {
3329 if a.device_id == b.device_id {
3330 let p = provider_for_handle(a)?;
3331 if let Ok(h) = p.elem_max(a, b).await {
3332 return Some(h);
3333 }
3334 }
3335 None
3336}
3337
3338pub async fn try_elem_min(a: &GpuTensorHandle, b: &GpuTensorHandle) -> Option<GpuTensorHandle> {
3340 if a.device_id == b.device_id {
3341 let p = provider_for_handle(a)?;
3342 if let Ok(h) = p.elem_min(a, b).await {
3343 return Some(h);
3344 }
3345 }
3346 None
3347}
3348
3349pub async fn try_elem_atan2(y: &GpuTensorHandle, x: &GpuTensorHandle) -> Option<GpuTensorHandle> {
3351 if y.device_id == x.device_id {
3352 let p = provider_for_handle(y)?;
3353 if let Ok(h) = p.elem_atan2(y, x).await {
3354 return Some(h);
3355 }
3356 }
3357 None
3358}
3359
3360#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3362pub struct HostTensorOwned {
3363 pub data: Vec<f64>,
3364 pub shape: Vec<usize>,
3365 pub storage: GpuTensorStorage,
3366}
3367
3368#[derive(Debug)]
3369pub struct HostTensorView<'a> {
3370 pub data: &'a [f64],
3371 pub shape: &'a [usize],
3372}
3373
3374#[derive(Debug)]
3376pub struct MeshgridAxisView<'a> {
3377 pub data: &'a [f64],
3378}
3379
3380#[derive(Debug, Clone)]
3382pub struct ProviderMeshgridResult {
3383 pub outputs: Vec<GpuTensorHandle>,
3384}
3385
3386#[derive(Debug, Clone, Copy)]
3388pub struct ProviderNdgridAxis<'a> {
3389 pub handle: &'a GpuTensorHandle,
3390}
3391
3392#[derive(Debug, Clone, Copy)]
3395pub struct ProviderNdgridRequest<'a> {
3396 pub axes: &'a [ProviderNdgridAxis<'a>],
3397 pub output_shape: &'a [usize],
3398 pub output_count: usize,
3399}
3400
3401#[derive(Debug, Clone)]
3403pub struct ProviderNdgridResult {
3404 pub outputs: Vec<GpuTensorHandle>,
3405}
3406
3407#[derive(Debug, Clone, Copy)]
3409pub struct ProviderBlackScholesPriceInput<'a> {
3410 pub handle: &'a GpuTensorHandle,
3411 pub shape: &'a [usize],
3413 pub strides: &'a [usize],
3415}
3416
3417#[derive(Debug, Clone, Copy)]
3420pub struct ProviderBlackScholesPriceRequest<'a> {
3421 pub inputs: &'a [ProviderBlackScholesPriceInput<'a>],
3422 pub output_shape: &'a [usize],
3423 pub len: usize,
3424}
3425
3426#[derive(Debug, Clone)]
3428pub struct ProviderBlackScholesPriceResult {
3429 pub call: GpuTensorHandle,
3430 pub put: GpuTensorHandle,
3431}
3432
3433#[derive(Debug, Clone)]
3436pub struct ProviderCovarianceToCorrelationResult {
3437 pub correlation: GpuTensorHandle,
3438 pub sigma: GpuTensorHandle,
3439}
3440
3441#[derive(Debug, Clone, Copy)]
3443pub struct ProviderAdamUpdateRequest<'a> {
3444 pub parameters: &'a GpuTensorHandle,
3445 pub gradient: &'a GpuTensorHandle,
3446 pub average_grad: Option<&'a GpuTensorHandle>,
3447 pub average_sq_grad: Option<&'a GpuTensorHandle>,
3448 pub iteration: usize,
3449 pub learn_rate: f64,
3450 pub gradient_decay_factor: f64,
3451 pub squared_gradient_decay_factor: f64,
3452 pub epsilon: f64,
3453}
3454
3455#[derive(Debug, Clone)]
3457pub struct ProviderAdamUpdateResult {
3458 pub parameters: GpuTensorHandle,
3459 pub average_grad: GpuTensorHandle,
3460 pub average_sq_grad: GpuTensorHandle,
3461}
3462
3463#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3465pub enum ProviderCrossentropyMode {
3466 SingleLabel,
3467 MultiLabel,
3468}
3469
3470#[derive(Debug, Clone, Copy)]
3472pub struct ProviderCrossentropyRequest<'a> {
3473 pub predictions: &'a GpuTensorHandle,
3474 pub targets: &'a GpuTensorHandle,
3475 pub weights: Option<&'a GpuTensorHandle>,
3476 pub mask: Option<&'a GpuTensorHandle>,
3477 pub mode: ProviderCrossentropyMode,
3478}
3479
3480#[derive(Debug, Clone)]
3482pub struct ProviderCrossentropyResult {
3483 pub losses: GpuTensorHandle,
3484}
3485
3486#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3492pub enum ScaleOp {
3493 Multiply,
3494 Divide,
3495}
3496
3497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3498pub struct MatmulEpilogue {
3499 pub alpha: f64,
3501 pub beta: f64,
3503 pub row_scale: Option<GpuTensorHandle>,
3505 pub col_scale: Option<GpuTensorHandle>,
3507 pub row_op: ScaleOp,
3509 pub col_op: ScaleOp,
3511 #[serde(default)]
3513 pub clamp_min: Option<f64>,
3514 #[serde(default)]
3516 pub clamp_max: Option<f64>,
3517 #[serde(default)]
3519 pub pow_exponent: Option<f64>,
3520 #[serde(default)]
3522 pub diag_output: Option<GpuTensorHandle>,
3523}
3524
3525impl MatmulEpilogue {
3526 pub fn noop() -> Self {
3527 Self {
3528 alpha: 1.0,
3529 beta: 0.0,
3530 row_scale: None,
3531 col_scale: None,
3532 row_op: ScaleOp::Multiply,
3533 col_op: ScaleOp::Multiply,
3534 clamp_min: None,
3535 clamp_max: None,
3536 pow_exponent: None,
3537 diag_output: None,
3538 }
3539 }
3540 pub fn is_noop(&self) -> bool {
3541 self.alpha == 1.0
3542 && self.beta == 0.0
3543 && self.row_scale.is_none()
3544 && self.col_scale.is_none()
3545 && self.clamp_min.is_none()
3546 && self.clamp_max.is_none()
3547 && self.pow_exponent.is_none()
3548 && self.diag_output.is_none()
3549 }
3550}
3551
3552#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
3553pub struct PowerStepEpilogue {
3554 pub epsilon: f64,
3555}
3556
3557impl Default for PowerStepEpilogue {
3558 fn default() -> Self {
3559 Self { epsilon: 0.0 }
3560 }
3561}
3562
3563#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3564pub struct ImageNormalizeDescriptor {
3565 pub batch: usize,
3566 pub height: usize,
3567 pub width: usize,
3568 pub epsilon: f64,
3569 #[serde(default)]
3570 pub gain: Option<f64>,
3571 #[serde(default)]
3572 pub bias: Option<f64>,
3573 #[serde(default)]
3574 pub gamma: Option<f64>,
3575 #[serde(default = "default_image_normalize_clamp_zero")]
3576 pub clamp_zero: bool,
3577}
3578
3579fn default_image_normalize_clamp_zero() -> bool {
3580 true
3581}
3582
3583#[cfg(test)]
3584mod tests {
3585 use super::*;
3586
3587 struct TestProvider {
3588 device_id: u32,
3589 name: &'static str,
3590 spawn_concurrency: SpawnHandleConcurrency,
3591 }
3592
3593 impl AccelProvider for TestProvider {
3594 fn upload(&self, _host: &HostTensorView) -> anyhow::Result<GpuTensorHandle> {
3595 Err(anyhow!("test provider upload should not be called"))
3596 }
3597
3598 fn download<'a>(&'a self, _h: &'a GpuTensorHandle) -> AccelDownloadFuture<'a> {
3599 unsupported_future("test provider download should not be called")
3600 }
3601
3602 fn free(&self, _h: &GpuTensorHandle) -> anyhow::Result<()> {
3603 Err(anyhow!("test provider free should not be called"))
3604 }
3605
3606 fn device_info(&self) -> String {
3607 self.name.to_string()
3608 }
3609
3610 fn device_id(&self) -> u32 {
3611 self.device_id
3612 }
3613
3614 fn spawn_handle_concurrency(&self) -> SpawnHandleConcurrency {
3615 self.spawn_concurrency
3616 }
3617 }
3618
3619 static PROVIDER_TEST_LOCK: Lazy<std::sync::Mutex<()>> = Lazy::new(|| std::sync::Mutex::new(()));
3620 static PROVIDER_A: TestProvider = TestProvider {
3621 device_id: 101,
3622 name: "provider-a",
3623 spawn_concurrency: SpawnHandleConcurrency::ImmutableShare,
3624 };
3625 static PROVIDER_B: TestProvider = TestProvider {
3626 device_id: 202,
3627 name: "provider-b",
3628 spawn_concurrency: SpawnHandleConcurrency::Reject,
3629 };
3630 static PROVIDER_C: TestProvider = TestProvider {
3631 device_id: 303,
3632 name: "provider-c",
3633 spawn_concurrency: SpawnHandleConcurrency::CopyOnWrite,
3634 };
3635
3636 fn register_test_providers() {
3637 clear_provider();
3638 unsafe {
3639 register_provider(&PROVIDER_A);
3640 register_provider(&PROVIDER_B);
3641 }
3642 }
3643
3644 fn test_handle(device_id: u32) -> GpuTensorHandle {
3645 GpuTensorHandle {
3646 shape: vec![1],
3647 device_id,
3648 buffer_id: 42,
3649 }
3650 }
3651
3652 #[test]
3653 fn handle_metadata_is_namespaced_by_device_and_buffer() {
3654 let first = test_handle(PROVIDER_A.device_id());
3655 let second = test_handle(PROVIDER_B.device_id());
3656 assert_eq!(first.buffer_id, second.buffer_id);
3657
3658 set_handle_precision(&first, ProviderPrecision::F32);
3659 set_handle_precision(&second, ProviderPrecision::F64);
3660 set_handle_class_name(&first, "single");
3661 set_handle_class_name(&second, "uint64");
3662 set_handle_storage(&first, GpuTensorStorage::Real);
3663 set_handle_storage(&second, GpuTensorStorage::ComplexInterleaved);
3664 set_handle_logical(&first, true);
3665 record_handle_transpose(&second, 2, 3);
3666
3667 assert_eq!(handle_precision(&first), Some(ProviderPrecision::F32));
3668 assert_eq!(handle_precision(&second), Some(ProviderPrecision::F64));
3669 assert_eq!(handle_class_name(&first).as_deref(), Some("single"));
3670 assert_eq!(handle_class_name(&second).as_deref(), Some("uint64"));
3671 assert_eq!(handle_storage(&first), GpuTensorStorage::Real);
3672 assert_eq!(
3673 handle_storage(&second),
3674 GpuTensorStorage::ComplexInterleaved
3675 );
3676 assert!(handle_is_logical(&first));
3677 assert!(!handle_is_logical(&second));
3678 assert!(handle_transpose_info(&first).is_none());
3679 assert_eq!(
3680 handle_transpose_info(&second),
3681 Some(TransposeInfo {
3682 base_rows: 2,
3683 base_cols: 3
3684 })
3685 );
3686
3687 clear_handle_precision(&first);
3688 clear_handle_precision(&second);
3689 clear_handle_class_name(&first);
3690 clear_handle_class_name(&second);
3691 clear_handle_storage(&first);
3692 clear_handle_storage(&second);
3693 clear_handle_logical(&first);
3694 clear_handle_transpose(&second);
3695 }
3696
3697 fn spectral_request<'a>(
3698 input: &'a GpuTensorHandle,
3699 frame_mode: ProviderSpectralFrameMode,
3700 ) -> ProviderSpectralRequest<'a> {
3701 static WINDOW: [f64; 4] = [1.0, 1.0, 1.0, 1.0];
3702 ProviderSpectralRequest {
3703 input,
3704 input_len: 16,
3705 input_complex: false,
3706 window: &WINDOW,
3707 nfft: 8,
3708 frame_count: 3,
3709 frame_mode,
3710 range: ProviderSpectralRange::Onesided,
3711 denominator: 1.0,
3712 }
3713 }
3714
3715 #[test]
3716 fn provider_envelope_shape_guard_rejects_equal_len_layout_spoofing() {
3717 assert!(provider_envelope_input_shape_matches(&[2, 3], 2, 3));
3718 assert!(provider_envelope_input_shape_matches(&[6, 1], 6, 1));
3719 assert!(provider_envelope_input_shape_matches(&[1, 6], 6, 1));
3720 assert!(provider_envelope_input_shape_matches(&[6], 6, 1));
3721
3722 assert!(!provider_envelope_input_shape_matches(&[3, 2], 2, 3));
3723 assert!(!provider_envelope_input_shape_matches(&[6], 2, 3));
3724 assert!(!provider_envelope_input_shape_matches(&[2, 1, 3], 2, 3));
3725 }
3726
3727 #[test]
3728 fn provider_for_device_prefers_registered_device_over_thread_provider() {
3729 let _lock = PROVIDER_TEST_LOCK
3730 .lock()
3731 .expect("provider test lock poisoned");
3732 register_test_providers();
3733 let _thread_provider = ThreadProviderGuard::set(Some(&PROVIDER_B));
3734
3735 let provider = provider_for_device(PROVIDER_A.device_id()).expect("provider for device");
3736
3737 assert_eq!(provider.device_info(), PROVIDER_A.name);
3738 clear_provider();
3739 }
3740
3741 #[test]
3742 fn provider_for_handle_uses_handle_device_owner() {
3743 let _lock = PROVIDER_TEST_LOCK
3744 .lock()
3745 .expect("provider test lock poisoned");
3746 register_test_providers();
3747 let _thread_provider = ThreadProviderGuard::set(Some(&PROVIDER_B));
3748
3749 let provider =
3750 provider_for_handle(&test_handle(PROVIDER_A.device_id())).expect("provider for handle");
3751
3752 assert_eq!(provider.device_info(), PROVIDER_A.name);
3753 clear_provider();
3754 }
3755
3756 #[test]
3757 fn clearing_active_provider_preserves_live_handle_owner() {
3758 let _lock = PROVIDER_TEST_LOCK
3759 .lock()
3760 .expect("provider test lock poisoned");
3761 register_test_providers();
3762 let handle = test_handle(PROVIDER_A.device_id());
3763
3764 clear_provider();
3765
3766 assert!(provider().is_none());
3767 let owner = provider_for_handle(&handle).expect("registered handle owner survives clear");
3768 assert_eq!(owner.device_info(), PROVIDER_A.name);
3769 }
3770
3771 #[test]
3772 fn concurrent_registration_keeps_each_threads_active_provider() {
3773 let _lock = PROVIDER_TEST_LOCK
3774 .lock()
3775 .expect("provider test lock poisoned");
3776 clear_provider();
3777
3778 let first = std::thread::spawn(|| {
3779 unsafe { register_provider(&PROVIDER_A) };
3780 std::thread::yield_now();
3781 provider().map(AccelProvider::device_info)
3782 });
3783 let second = std::thread::spawn(|| {
3784 unsafe { register_provider(&PROVIDER_B) };
3785 std::thread::yield_now();
3786 provider().map(AccelProvider::device_info)
3787 });
3788
3789 assert_eq!(
3790 first.join().expect("first registration thread"),
3791 Some(PROVIDER_A.name.to_string())
3792 );
3793 assert_eq!(
3794 second.join().expect("second registration thread"),
3795 Some(PROVIDER_B.name.to_string())
3796 );
3797 clear_provider();
3798 }
3799
3800 #[test]
3801 fn spawn_handle_concurrency_for_uses_registered_owner() {
3802 let _lock = PROVIDER_TEST_LOCK
3803 .lock()
3804 .expect("provider test lock poisoned");
3805 register_test_providers();
3806 let _thread_provider = ThreadProviderGuard::set(Some(&PROVIDER_B));
3807
3808 let concurrency = spawn_handle_concurrency_for(&test_handle(PROVIDER_A.device_id()))
3809 .expect("spawn concurrency");
3810
3811 assert_eq!(concurrency, PROVIDER_A.spawn_concurrency);
3812 clear_provider();
3813 }
3814
3815 #[test]
3816 fn provider_keeps_thread_local_active_provider_semantics() {
3817 let _lock = PROVIDER_TEST_LOCK
3818 .lock()
3819 .expect("provider test lock poisoned");
3820 register_test_providers();
3821 let _thread_provider = ThreadProviderGuard::set(Some(&PROVIDER_A));
3822
3823 let active = provider().expect("active provider");
3824
3825 assert_eq!(active.device_info(), PROVIDER_A.name);
3826 clear_provider();
3827 }
3828
3829 #[test]
3830 fn unregistered_thread_provider_only_matches_own_device_before_global_fallback() {
3831 let _lock = PROVIDER_TEST_LOCK
3832 .lock()
3833 .expect("provider test lock poisoned");
3834 clear_provider();
3835 unsafe {
3836 register_provider(&PROVIDER_A);
3837 }
3838 let _thread_provider = ThreadProviderGuard::set(Some(&PROVIDER_C));
3839
3840 let own_device = provider_for_device(PROVIDER_C.device_id()).expect("own provider");
3841 let fallback = provider_for_device(404).expect("global fallback provider");
3842
3843 assert_eq!(own_device.device_info(), PROVIDER_C.name);
3844 assert_eq!(fallback.device_info(), PROVIDER_A.name);
3845 clear_provider();
3846 }
3847
3848 #[test]
3849 fn uniform_spectral_request_validates_sliding_input_coverage() {
3850 let input = test_handle(PROVIDER_A.device_id());
3851 let mut request = spectral_request(&input, ProviderSpectralFrameMode::Sliding { hop: 6 });
3852 assert!(validate_uniform_spectral_request(&request).is_ok());
3853
3854 request.input_len = 15;
3855 assert!(validate_uniform_spectral_request(&request).is_err());
3856 }
3857
3858 #[test]
3859 fn uniform_spectral_request_rejects_sliding_coverage_overflow() {
3860 let input = test_handle(PROVIDER_A.device_id());
3861 let mut request = spectral_request(&input, ProviderSpectralFrameMode::Sliding { hop: 2 });
3862 request.frame_count = usize::MAX;
3863
3864 assert!(validate_uniform_spectral_request(&request).is_err());
3865 }
3866
3867 #[test]
3868 fn uniform_spectral_request_validates_folded_input_coverage() {
3869 let input = test_handle(PROVIDER_A.device_id());
3870 let mut request = spectral_request(
3871 &input,
3872 ProviderSpectralFrameMode::FoldedColumns { input_rows: 5 },
3873 );
3874 assert!(validate_uniform_spectral_request(&request).is_ok());
3875
3876 request.frame_mode = ProviderSpectralFrameMode::FoldedColumns { input_rows: 0 };
3877 assert!(validate_uniform_spectral_request(&request).is_err());
3878
3879 request.frame_mode = ProviderSpectralFrameMode::FoldedColumns { input_rows: 6 };
3880 assert!(validate_uniform_spectral_request(&request).is_err());
3881 }
3882
3883 #[test]
3884 fn uniform_spectral_request_rejects_folded_coverage_overflow() {
3885 let input = test_handle(PROVIDER_A.device_id());
3886 let request = spectral_request(
3887 &input,
3888 ProviderSpectralFrameMode::FoldedColumns {
3889 input_rows: usize::MAX,
3890 },
3891 );
3892
3893 assert!(validate_uniform_spectral_request(&request).is_err());
3894 }
3895
3896 #[test]
3897 fn image_normalize_descriptor_omitted_clamp_zero_defaults_true() {
3898 let payload = r#"{
3899 "batch": 2,
3900 "height": 4,
3901 "width": 5,
3902 "epsilon": 0.000001
3903 }"#;
3904
3905 let desc: ImageNormalizeDescriptor =
3906 serde_json::from_str(payload).expect("deserialize descriptor");
3907
3908 assert!(
3909 desc.clamp_zero,
3910 "legacy serialized descriptors should default to clamped image normalize"
3911 );
3912 }
3913
3914 #[test]
3915 fn image_normalize_descriptor_explicit_false_preserves_unclamped() {
3916 let payload = r#"{
3917 "batch": 2,
3918 "height": 4,
3919 "width": 5,
3920 "epsilon": 0.000001,
3921 "clamp_zero": false
3922 }"#;
3923
3924 let desc: ImageNormalizeDescriptor =
3925 serde_json::from_str(payload).expect("deserialize descriptor");
3926
3927 assert!(
3928 !desc.clamp_zero,
3929 "explicit clamp_zero=false should preserve unclamped semantics"
3930 );
3931 }
3932}