Skip to main content

ha_ndarray/host/
platform.rs

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}