1use number_general as ng;
2use rayon::prelude::*;
3use safecast::CastInto;
4
5use crate::access::{Access, AccessOp};
6use crate::buffer::BufferConverter;
7use crate::host::StackVec;
8use crate::ops::{
9 Concat, ConstructConcat, ConstructRange, ElementwiseAbs, ElementwiseBoolean,
10 ElementwiseBooleanScalar, ElementwiseCast, ElementwiseCompare, ElementwiseCompareScalar,
11 ElementwiseDual, ElementwiseNumeric, ElementwiseScalar, ElementwiseTrig, ElementwiseUnary,
12 ElementwiseUnaryBoolean, GatherCond, LinAlgDual, LinAlgUnary, Random, ReduceAll, ReduceAxes,
13 Transform,
14};
15use crate::platform::{Convert, PlatformInstance};
16use crate::{stackvec, Axes, Constant, Error, Float, Number, Range, Real, Shape};
17
18use super::buffer::Buffer;
19use super::ops::*;
20
21pub const VEC_MIN_SIZE: usize = 64;
22
23#[derive(Debug, Copy, Clone, Eq, PartialEq)]
24pub struct Stack;
25
26impl PlatformInstance for Stack {
27 fn select(_size_hint: usize) -> Self {
28 Self
29 }
30}
31
32impl<T: Number> Constant<T> for Stack {
33 type Buffer = StackVec<T>;
34
35 fn constant(&self, value: T, size: usize) -> Result<Self::Buffer, Error> {
36 Ok(stackvec![value; size])
37 }
38}
39
40impl<T: Number> Convert<T> for Stack {
41 type Buffer = StackVec<T>;
42
43 fn convert(&self, buffer: BufferConverter<T>) -> Result<Self::Buffer, Error> {
44 buffer.to_slice().map(|buf| buf.into_stackvec())
45 }
46}
47
48impl<A, T> ReduceAll<A, T> for Stack
49where
50 A: Access<T>,
51 T: Number,
52{
53 fn all(self, access: A) -> Result<bool, Error> {
54 access
55 .read()
56 .and_then(|buf| buf.to_slice())
57 .map(|slice| slice.iter().copied().all(|n| n != T::ZERO))
58 }
59
60 fn any(self, access: A) -> Result<bool, Error> {
61 access
62 .read()
63 .and_then(|buf| buf.to_slice())
64 .map(|slice| slice.iter().copied().any(|n| n != T::ZERO))
65 }
66
67 fn max(self, access: A) -> Result<T, Error>
68 where
69 T: Real,
70 {
71 access
72 .read()
73 .and_then(|buf| buf.to_slice())
74 .map(|slice| slice.iter().copied().reduce(T::max).expect("max"))
75 }
76
77 fn min(self, access: A) -> Result<T, Error>
78 where
79 T: Real,
80 {
81 access
82 .read()
83 .and_then(|buf| buf.to_slice())
84 .map(|slice| slice.iter().copied().reduce(T::min).expect("min"))
85 }
86
87 fn product(self, access: A) -> Result<T, Error> {
88 access
89 .read()
90 .and_then(|buf| buf.to_slice())
91 .map(|slice| slice.iter().copied().reduce(T::mul).expect("product"))
92 }
93
94 fn sum(self, access: A) -> Result<T, Error> {
95 access
96 .read()
97 .and_then(|buf| buf.to_slice())
98 .map(|slice| slice.iter().copied().reduce(T::add).expect("sum"))
99 }
100}
101
102#[derive(Debug, Copy, Clone, Eq, PartialEq)]
103pub struct Heap;
104
105impl PlatformInstance for Heap {
106 fn select(_size_hint: usize) -> Self {
107 Self
108 }
109}
110
111impl<T: Number> Constant<T> for Heap {
112 type Buffer = Vec<T>;
113
114 fn constant(&self, value: T, size: usize) -> Result<Self::Buffer, Error> {
115 Ok(vec![value; size])
116 }
117}
118
119impl<T: Number> Convert<T> for Heap {
120 type Buffer = Vec<T>;
121
122 fn convert(&self, buffer: BufferConverter<T>) -> Result<Self::Buffer, Error> {
123 buffer.to_slice().map(|buf| buf.into_vec())
124 }
125}
126
127impl<A, T> ReduceAll<A, T> for Heap
128where
129 A: Access<T>,
130 T: Number,
131{
132 fn all(self, access: A) -> Result<bool, Error> {
133 access
134 .read()
135 .and_then(|buf| buf.to_slice())
136 .map(|slice| slice.into_par_iter().copied().all(|n| n != T::ZERO))
137 }
138
139 fn any(self, access: A) -> Result<bool, Error> {
140 access
141 .read()
142 .and_then(|buf| buf.to_slice())
143 .map(|slice| slice.into_par_iter().copied().any(|n| n != T::ZERO))
144 }
145
146 fn max(self, access: A) -> Result<T, Error>
147 where
148 T: Real,
149 {
150 access
151 .read()
152 .and_then(|buf| buf.to_slice())
153 .map(|slice| slice.into_par_iter().copied().reduce(|| T::MIN, T::max))
154 }
155
156 fn min(self, access: A) -> Result<T, Error>
157 where
158 T: Real,
159 {
160 access
161 .read()
162 .and_then(|buf| buf.to_slice())
163 .map(|slice| slice.into_par_iter().copied().reduce(|| T::MAX, T::min))
164 }
165
166 fn product(self, access: A) -> Result<T, Error> {
167 access
168 .read()
169 .and_then(|buf| buf.to_slice())
170 .map(|slice| slice.into_par_iter().copied().reduce(|| T::ONE, T::mul))
171 }
172
173 fn sum(self, access: A) -> Result<T, Error> {
174 access
175 .read()
176 .and_then(|buf| buf.to_slice())
177 .map(|slice| slice.into_par_iter().copied().reduce(|| T::ZERO, T::add))
178 }
179}
180
181#[derive(Debug, Copy, Clone, Eq, PartialEq)]
182pub enum Host {
183 Stack(Stack),
184 Heap(Heap),
185}
186
187impl PlatformInstance for Host {
188 fn select(size_hint: usize) -> Self {
189 if size_hint < VEC_MIN_SIZE {
190 Self::Stack(Stack)
191 } else {
192 Self::Heap(Heap)
193 }
194 }
195}
196
197impl<T: Number> Constant<T> for Host {
198 type Buffer = Buffer<T>;
199
200 fn constant(&self, value: T, size: usize) -> Result<Self::Buffer, Error> {
201 match self {
202 Self::Heap(heap) => heap.constant(value, size).map(Buffer::Heap),
203 Self::Stack(stack) => stack.constant(value, size).map(Buffer::Stack),
204 }
205 }
206}
207
208impl<T: Number> Convert<T> for Host {
209 type Buffer = Buffer<T>;
210
211 fn convert(&self, buffer: BufferConverter<T>) -> Result<Self::Buffer, Error> {
212 match self {
213 Self::Heap(heap) => heap.convert(buffer).map(Buffer::Heap),
214 Self::Stack(stack) => stack.convert(buffer).map(Buffer::Stack),
215 }
216 }
217}
218
219impl From<Heap> for Host {
220 fn from(heap: Heap) -> Self {
221 Self::Heap(heap)
222 }
223}
224
225impl From<Stack> for Host {
226 fn from(stack: Stack) -> Self {
227 Self::Stack(stack)
228 }
229}
230
231impl<A, T> ConstructConcat<A, T> for Host
232where
233 A: Access<T>,
234 T: Number,
235{
236 type Op = Concat<A, T>;
237
238 fn concat(self, data: Vec<A>) -> Result<AccessOp<Self::Op, Self>, Error> {
239 Ok(Concat::new(data).into())
240 }
241}
242
243impl<T: Number + PartialOrd> ConstructRange<T> for Host {
244 type Range = Linear<T>;
245
246 fn range(self, start: T, stop: T, size: usize) -> Result<AccessOp<Self::Range, Self>, Error> {
247 if start <= stop {
248 let size_t = ng::Number::from(size as u64).cast_into();
249 let step = T::div(T::sub(stop, start), size_t);
250 Ok(Linear::new(start, step, size).into())
251 } else {
252 Err(Error::bounds(format!("invalid range: [{start}, {stop})")))
253 }
254 }
255}
256
257impl<A: Access<IT>, IT: Number, OT: Number> ElementwiseCast<A, IT, OT> for Host {
258 type Op = Cast<A, IT, OT>;
259
260 fn cast(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
261 Ok(Cast::new(access).into())
262 }
263}
264
265impl<A, L, R, T> GatherCond<A, L, R, T> for Host
266where
267 A: Access<u8>,
268 L: Access<T>,
269 R: Access<T>,
270 T: Number,
271{
272 type Op = Cond<A, L, R, T>;
273
274 fn cond(self, cond: A, then: L, or_else: R) -> Result<AccessOp<Self::Op, Self>, Error> {
275 Ok(Cond::new(cond, then, or_else).into())
276 }
277}
278
279impl<A: Access<T>, T: Number> ElementwiseAbs<A, T> for Host {
280 type Op = Unary<A, T, T::Abs>;
281
282 fn abs(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
283 Ok(Unary::abs(access).into())
284 }
285}
286
287impl<L, R, T> ElementwiseBoolean<L, R, T> for Host
288where
289 L: Access<T>,
290 R: Access<T>,
291 T: Number,
292{
293 type Op = Dual<L, R, T, u8>;
294
295 fn and(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
296 Ok(Dual::and(left, right).into())
297 }
298
299 fn or(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
300 Ok(Dual::or(left, right).into())
301 }
302
303 fn xor(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
304 Ok(Dual::xor(left, right).into())
305 }
306}
307
308impl<A: Access<T>, T: Number> ElementwiseBooleanScalar<A, T> for Host {
309 type Op = Scalar<A, T, u8>;
310
311 fn and_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
312 Ok(Scalar::and(left, right).into())
313 }
314
315 fn or_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
316 Ok(Scalar::or(left, right).into())
317 }
318
319 fn xor_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
320 Ok(Scalar::xor(left, right).into())
321 }
322}
323
324impl<L, R, T> ElementwiseCompare<L, R, T> for Host
325where
326 L: Access<T>,
327 R: Access<T>,
328 T: Number,
329{
330 type Op = Dual<L, R, T, u8>;
331
332 fn eq(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
333 where
334 T: PartialEq,
335 {
336 Ok(Dual::eq(left, right).into())
337 }
338
339 fn ge(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
340 where
341 T: PartialOrd,
342 {
343 Ok(Dual::ge(left, right).into())
344 }
345
346 fn gt(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
347 where
348 T: PartialOrd,
349 {
350 Ok(Dual::gt(left, right).into())
351 }
352
353 fn le(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
354 where
355 T: PartialOrd,
356 {
357 Ok(Dual::le(left, right).into())
358 }
359
360 fn lt(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
361 where
362 T: PartialOrd,
363 {
364 Ok(Dual::lt(left, right).into())
365 }
366
367 fn ne(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
368 where
369 T: PartialEq,
370 {
371 Ok(Dual::ne(left, right).into())
372 }
373}
374
375impl<A, T> ElementwiseCompareScalar<A, T> for Host
376where
377 A: Access<T>,
378 T: Number,
379{
380 type Op = Scalar<A, T, u8>;
381
382 fn eq_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
383 Ok(Scalar::eq(left, right).into())
384 }
385
386 fn ge_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error>
387 where
388 T: Real,
389 {
390 Ok(Scalar::ge(left, right).into())
391 }
392
393 fn gt_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error>
394 where
395 T: Real,
396 {
397 Ok(Scalar::gt(left, right).into())
398 }
399
400 fn le_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error>
401 where
402 T: Real,
403 {
404 Ok(Scalar::le(left, right).into())
405 }
406
407 fn lt_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error>
408 where
409 T: Real,
410 {
411 Ok(Scalar::lt(left, right).into())
412 }
413
414 fn ne_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
415 Ok(Scalar::ne(left, right).into())
416 }
417}
418
419#[cfg(feature = "complex")]
420impl<A, T> crate::ops::complex::ElementwiseUnaryComplex<A, T> for Host
421where
422 A: Access<T>,
423 T: crate::Complex,
424{
425 type Real = Unary<A, T, T::Real>;
426 type Complex = Unary<A, T, T>;
427
428 fn angle(self, access: A) -> Result<AccessOp<Self::Real, Self>, Error> {
429 Ok(Unary::angle(access).into())
430 }
431
432 fn conj(self, access: A) -> Result<AccessOp<Self::Complex, Self>, Error> {
433 Ok(Unary::conj(access).into())
434 }
435
436 fn re(self, access: A) -> Result<AccessOp<Self::Real, Self>, Error> {
437 Ok(Unary::re(access).into())
438 }
439
440 fn im(self, access: A) -> Result<AccessOp<Self::Real, Self>, Error> {
441 Ok(Unary::im(access).into())
442 }
443}
444
445impl<L, R, T> ElementwiseDual<L, R, T> for Host
446where
447 L: Access<T>,
448 R: Access<T>,
449 T: Number,
450{
451 type Op = Dual<L, R, T, T>;
452
453 fn add(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
454 Ok(Dual::add(left, right).into())
455 }
456
457 fn div(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
458 Ok(Dual::div(left, right).into())
459 }
460
461 fn log(self, arg: L, base: R) -> Result<AccessOp<Self::Op, Self>, Error>
462 where
463 T: Float,
464 {
465 Ok(Dual::log(arg, base).into())
466 }
467
468 fn mul(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
469 Ok(Dual::mul(left, right).into())
470 }
471
472 fn pow(self, arg: L, exp: R) -> Result<AccessOp<Self::Op, Self>, Error> {
473 Ok(Dual::pow(arg, exp).into())
474 }
475
476 fn rem(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error>
477 where
478 T: Real,
479 {
480 Ok(Dual::rem(left, right).into())
481 }
482
483 fn sub(self, left: L, right: R) -> Result<AccessOp<Self::Op, Self>, Error> {
484 Ok(Dual::sub(left, right).into())
485 }
486}
487
488impl<A: Access<T>, T: Number> ElementwiseScalar<A, T> for Host {
489 type Op = Scalar<A, T, T>;
490
491 fn add_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
492 Ok(Scalar::add(left, right).into())
493 }
494
495 fn div_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
496 Ok(Scalar::div(left, right).into())
497 }
498
499 fn log_scalar(self, arg: A, base: T) -> Result<AccessOp<Self::Op, Self>, Error>
500 where
501 T: Float,
502 {
503 Ok(Scalar::log(arg, base).into())
504 }
505
506 fn mul_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
507 Ok(Scalar::mul(left, right).into())
508 }
509
510 fn pow_scalar(self, arg: A, exp: T) -> Result<AccessOp<Self::Op, Self>, Error> {
511 Ok(Scalar::pow(arg, exp).into())
512 }
513
514 fn rem_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error>
515 where
516 T: Real,
517 {
518 Ok(Scalar::rem(left, right).into())
519 }
520
521 fn sub_scalar(self, left: A, right: T) -> Result<AccessOp<Self::Op, Self>, Error> {
522 Ok(Scalar::sub(left, right).into())
523 }
524}
525
526impl<A: Access<T>, T: Float> ElementwiseNumeric<A, T> for Host {
527 type Op = Unary<A, T, u8>;
528
529 fn is_inf(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
530 Ok(Unary::inf(access).into())
531 }
532
533 fn is_nan(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
534 Ok(Unary::nan(access).into())
535 }
536}
537
538impl<A: Access<T>, T: Float> ElementwiseTrig<A, T> for Host {
539 type Op = Unary<A, T, T>;
540
541 fn sin(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
542 Ok(Unary::sin(access).into())
543 }
544
545 fn asin(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
546 Ok(Unary::asin(access).into())
547 }
548
549 fn sinh(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
550 Ok(Unary::sinh(access).into())
551 }
552
553 fn cos(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
554 Ok(Unary::cos(access).into())
555 }
556
557 fn acos(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
558 Ok(Unary::acos(access).into())
559 }
560
561 fn cosh(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
562 Ok(Unary::cosh(access).into())
563 }
564
565 fn tan(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
566 Ok(Unary::tan(access).into())
567 }
568
569 fn atan(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
570 Ok(Unary::atan(access).into())
571 }
572
573 fn tanh(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
574 Ok(Unary::tanh(access).into())
575 }
576}
577
578impl<A: Access<T>, T: Float> ElementwiseUnary<A, T> for Host {
579 type Op = Unary<A, T, T>;
580
581 fn exp(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
582 Ok(Unary::exp(access).into())
583 }
584
585 fn ln(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
586 Ok(Unary::ln(access).into())
587 }
588
589 fn round(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error>
590 where
591 T: Real,
592 {
593 Ok(Unary::round(access).into())
594 }
595}
596
597impl<A: Access<T>, T: Number> ElementwiseUnaryBoolean<A, T> for Host {
598 type Op = Unary<A, T, u8>;
599
600 fn not(self, access: A) -> Result<AccessOp<Self::Op, Self>, Error> {
601 Ok(Unary::not(access).into())
602 }
603}
604
605#[cfg(feature = "complex")]
606impl<A, T> crate::ops::complex::Fourier<A, num_complex::Complex<T>> for Host
607where
608 A: Access<num_complex::Complex<T>>,
609 T: rustfft::FftNum,
610 num_complex::Complex<T>: crate::Complex,
611{
612 type Op = complex::FFT<A, num_complex::Complex<T>>;
613
614 fn fft(self, access: A, dim: usize) -> Result<AccessOp<Self::Op, Self>, Error> {
615 complex::FFT::fft(access, dim).map(AccessOp::from)
616 }
617
618 fn ifft(self, access: A, dim: usize) -> Result<AccessOp<Self::Op, Self>, Error> {
619 complex::FFT::ifft(access, dim).map(AccessOp::from)
620 }
621}
622
623impl<L, R, T> LinAlgDual<L, R, T> for Host
624where
625 L: Access<T>,
626 R: Access<T>,
627 T: Number,
628{
629 type Op = MatMul<L, R, T>;
630
631 fn matmul(
632 self,
633 left: L,
634 right: R,
635 dims: [usize; 4],
636 ) -> Result<AccessOp<Self::Op, Self>, Error> {
637 Ok(MatMul::new(left, right, dims).into())
638 }
639}
640
641impl<A: Access<T>, T: Number> LinAlgUnary<A, T> for Host {
642 type Op = MatDiag<A, T>;
643
644 fn diag(
645 self,
646 access: A,
647 batch_size: usize,
648 dim: usize,
649 ) -> Result<AccessOp<Self::Op, Self>, Error> {
650 Ok(MatDiag::new(access, batch_size, dim).into())
651 }
652}
653
654impl Random for Host {
655 type Normal = RandomNormal;
656 type Uniform = RandomUniform;
657
658 fn random_normal(self, size: usize) -> Result<AccessOp<Self::Normal, Self>, Error> {
659 Ok(RandomNormal::new(size).into())
660 }
661
662 fn random_uniform(self, size: usize) -> Result<AccessOp<Self::Uniform, Self>, Error> {
663 Ok(RandomUniform::new(size).into())
664 }
665}
666
667impl<A: Access<T>, T: Number> ReduceAll<A, T> for Host {
668 fn all(self, access: A) -> Result<bool, Error> {
669 match self {
670 Self::Heap(heap) => heap.all(access),
671 Self::Stack(stack) => stack.all(access),
672 }
673 }
674
675 fn any(self, access: A) -> Result<bool, Error> {
676 match self {
677 Self::Heap(heap) => heap.any(access),
678 Self::Stack(stack) => stack.any(access),
679 }
680 }
681
682 fn max(self, access: A) -> Result<T, Error>
683 where
684 T: Real,
685 {
686 match self {
687 Self::Heap(heap) => heap.max(access),
688 Self::Stack(stack) => stack.max(access),
689 }
690 }
691
692 fn min(self, access: A) -> Result<T, Error>
693 where
694 T: Real,
695 {
696 match self {
697 Self::Heap(heap) => heap.min(access),
698 Self::Stack(stack) => stack.min(access),
699 }
700 }
701
702 fn product(self, access: A) -> Result<T, Error> {
703 match self {
704 Self::Heap(heap) => heap.product(access),
705 Self::Stack(stack) => stack.product(access),
706 }
707 }
708
709 fn sum(self, access: A) -> Result<T, Error> {
710 match self {
711 Self::Heap(heap) => heap.sum(access),
712 Self::Stack(stack) => stack.sum(access),
713 }
714 }
715}
716
717impl<A: Access<T>, T: Number> ReduceAxes<A, T> for Host {
718 type Op = Reduce<A, T>;
719
720 fn max(self, access: A, stride: usize) -> Result<AccessOp<Self::Op, Self>, Error>
721 where
722 T: Real,
723 {
724 Ok(Reduce::max(access, stride).into())
725 }
726
727 fn min(self, access: A, stride: usize) -> Result<AccessOp<Self::Op, Self>, Error>
728 where
729 T: Real,
730 {
731 Ok(Reduce::min(access, stride).into())
732 }
733
734 fn product(self, access: A, stride: usize) -> Result<AccessOp<Self::Op, Self>, Error> {
735 Ok(Reduce::product(access, stride).into())
736 }
737
738 fn sum(self, access: A, stride: usize) -> Result<AccessOp<Self::Op, Self>, Error> {
739 Ok(Reduce::sum(access, stride).into())
740 }
741}
742
743impl<A, T> Transform<A, T> for Host
744where
745 A: Access<T>,
746 T: Number,
747{
748 type Broadcast = View<A, T>;
749 type Flip = Flip<A, T>;
750 type Slice = Slice<A, T>;
751 type Transpose = View<A, T>;
752
753 fn broadcast(
754 self,
755 access: A,
756 shape: Shape,
757 broadcast: Shape,
758 ) -> Result<AccessOp<Self::Broadcast, Self>, Error> {
759 Ok(View::broadcast(access, shape, broadcast).into())
760 }
761
762 fn flip(
763 self,
764 access: A,
765 shape: Shape,
766 axis: usize,
767 ) -> Result<AccessOp<Self::Flip, Self>, Error> {
768 Flip::new(access, shape, axis).map(AccessOp::from)
769 }
770
771 fn slice(
772 self,
773 access: A,
774 shape: &[usize],
775 range: Range,
776 ) -> Result<AccessOp<Self::Slice, Self>, Error> {
777 Ok(Slice::new(access, shape, range).into())
778 }
779
780 fn transpose(
781 self,
782 access: A,
783 shape: Shape,
784 permutation: Axes,
785 ) -> Result<AccessOp<Self::Transpose, Self>, Error> {
786 Ok(View::transpose(access, shape, permutation).into())
787 }
788}