1use crate::{BinaryOp, AutogradMetaT, CmpOp, Error, FloatDType, NumDType, Shape, Storage, StorageIndices, TensorOrScalar, UnaryOp, WithDType};
2use crate::Tensor;
3use paste::paste;
4
5impl<T: WithDType> Tensor<T> {
10 pub(crate) fn same_shape_binary_op(&self, rhs: &Self, op: &'static str) -> crate::Result<&Shape> {
11 let lhs = self.shape();
12 let rhs = rhs.shape();
13 if lhs != rhs {
14 Err(Error::ShapeMismatchBinaryOp {
15 lhs: lhs.clone(),
16 rhs: rhs.clone(),
17 op,
18 })?
19 } else {
20 Ok(lhs)
21 }
22 }
23}
24
25impl<T: WithDType> Tensor<T> {
26 fn compute_binary_scalar_rhs_op<U, F>(lhs: &Tensor<T>, rhs: T, f: F, _op_name: &'static str) -> crate::Result<(Storage<U>, Shape)>
27 where
28 U: WithDType,
29 F: Fn(T, T) -> U
30 {
31 let shape = lhs.shape();
32 let lhs_storage = lhs.storage_read()?;
33 let lhs_layout = lhs.layout();
34 let lhs = lhs_storage.data();
35
36 let output: Vec<_> = match lhs_layout.storage_indices() {
37 StorageIndices::Contiguous(index) => {
38 let lhs = &lhs[index.begin_index..index.end_index];
39 lhs.iter()
40 .map(|&v| f(v, rhs))
41 .collect()
42 }
43 StorageIndices::Uncontiguous(index) => {
44 index
45 .map(|lhs_index| f(lhs[lhs_index], rhs))
46 .collect()
47 }
48 };
49
50 let storage = Storage::<U>::new(output);
51 Ok((storage, shape.clone()))
52 }
53
54 fn compute_binary_scalar_lhs_op<U, F>(lhs: T, rhs: &Tensor<T>, f: F, _op_name: &'static str) -> crate::Result<(Storage<U>, Shape)>
55 where
56 U: WithDType,
57 F: Fn(T, T) -> U
58 {
59 let shape = rhs.shape();
60 let rhs_storage = rhs.storage_read()?;
61 let rhs_layout = rhs.layout();
62 let rhs = rhs_storage.data();
63
64 let output: Vec<_> = match rhs_layout.storage_indices() {
65 StorageIndices::Contiguous(index) => {
66 let rhs = &rhs[index.begin_index..index.end_index];
67 rhs.iter()
68 .map(|&v| f(lhs, v))
69 .collect()
70 }
71 StorageIndices::Uncontiguous(index) => {
72 index
73 .map(|index| f(lhs, rhs[index]))
74 .collect()
75 }
76 };
77
78 let storage = Storage::<U>::new(output);
79 Ok((storage, shape.clone()))
80 }
81
82 fn compute_binary_op<U, F>(lhs: &Tensor<T>, rhs: &Tensor<T>, f: F, op_name: &'static str) -> crate::Result<(Storage<U>, Shape)>
83 where
84 U: WithDType,
85 F: Fn(T, T) -> U + Send + Sync
86 {
87 let shape = Tensor::<T>::same_shape_binary_op(lhs, rhs, op_name)?;
88 let lhs_storage = lhs.storage_read()?;
89 let rhs_storage = rhs.storage_read()?;
90 let lhs_layout = lhs.layout();
91 let rhs_layout = rhs.layout();
92
93 assert_eq!(lhs_layout.dims(), rhs_layout.dims(), "lhs dims != rhs dim2");
94
95 let lhs = lhs_storage.data();
96 let rhs = rhs_storage.data();
97
98 let output: Vec<_> = match (lhs_layout.storage_indices(), rhs_layout.storage_indices()) {
99 (StorageIndices::Contiguous(lhs_index), StorageIndices::Contiguous(rhs_index)) => {
100 let lhs = &lhs[lhs_index.begin_index..lhs_index.end_index];
101 let rhs = &rhs[rhs_index.begin_index..rhs_index.end_index];
102 lhs.iter().zip(rhs.iter())
103 .map(|(&l, &r)| f(l, r))
104 .collect()
105 }
106 (StorageIndices::Contiguous(lhs_index), StorageIndices::Uncontiguous(rhs_index)) => {
107 let lhs = &lhs[lhs_index.begin_index..lhs_index.end_index];
108 lhs.iter().zip(rhs_index)
109 .map(|(&l, r_index)| f(l, rhs[r_index]))
110 .collect()
111 }
112 (StorageIndices::Uncontiguous(lhs_index), StorageIndices::Contiguous(rhs_index)) => {
113 let rhs = &rhs[rhs_index.begin_index..rhs_index.end_index];
114 lhs_index.zip(rhs.iter())
115 .map(|(l_index, &r)| f(lhs[l_index], r))
116 .collect()
117 }
118 (StorageIndices::Uncontiguous(lhs_index), StorageIndices::Uncontiguous(rhs_index)) => {
119 lhs_index.zip(rhs_index)
120 .map(|(lhs_index, rhs_index)| f(lhs[lhs_index], rhs[rhs_index]))
121 .collect()
122 }
123 };
124
125 let storage = Storage::<U>::new(output);
126 Ok((storage, shape.clone()))
127 }
128
129 fn binary_op<U, F>(lhs: &Tensor<T>, rhs: &Tensor<T>, f: F, meta: U::AutogradMeta, op_name: &'static str) -> crate::Result<Tensor<U>>
130 where
131 U: WithDType,
132 F: Fn(T, T) -> U + Sync + Send
133 {
134 let (storage, shape) = Self::compute_binary_op(lhs, rhs, f, op_name)?;
135 Ok(Tensor::<U>::from_storage(storage, shape, meta))
136 }
137
138 fn binary_scalar_rhs_op<U, F>(lhs: &Tensor<T>, rhs: T, f: F, meta: U::AutogradMeta, op_name: &'static str) -> crate::Result<Tensor<U>>
139 where
140 U: WithDType,
141 F: Fn(T, T) -> U
142 {
143 let (storage, shape) = Self::compute_binary_scalar_rhs_op(lhs, rhs, f, op_name)?;
144 Ok(Tensor::<U>::from_storage(storage, shape, meta))
145 }
146
147 fn binary_scalar_lhs_op<U, F>(lhs: T, rhs: &Tensor<T>, f: F, meta: U::AutogradMeta, op_name: &'static str) -> crate::Result<Tensor<U>>
148 where
149 U: WithDType,
150 F: Fn(T, T) -> U
151 {
152 let (storage, shape) = Self::compute_binary_scalar_lhs_op(lhs, rhs, f, op_name)?;
153 Ok(Tensor::<U>::from_storage(storage, shape, meta))
154 }
155}
156
157macro_rules! binary_op_impl {
158 ($fn_name:ident) => {
159 paste! {
160 pub fn [< $fn_name _tensor >](&self, rhs: &Self) -> crate::Result<Self> {
161 let meta = T::AutogradMeta::on_binary_op(self, rhs, BinaryOp:: [< $fn_name:camel >]);
162 Self::binary_op(self, rhs, T::$fn_name, meta, stringify!([< $fn_name _tensor >]))
163 }
164
165 pub fn [< $fn_name _scalar >](&self, rhs: T) -> crate::Result<Self> {
166 let meta = T::AutogradMeta::on_binary_scalar_rhs_op(self, rhs, BinaryOp:: [< $fn_name:camel >]);
167 Self::binary_scalar_rhs_op(self, rhs, T::$fn_name, meta, stringify!([< $fn_name _scalar >]))
168 }
169
170 pub fn [< scalar_ $fn_name >](lhs: T, rhs: &Tensor<T>) -> crate::Result<Tensor<T>> {
171 let meta = T::AutogradMeta::on_binary_scalar_lhs_op(lhs, rhs, BinaryOp:: [< $fn_name:camel >]);
172 Self::binary_scalar_lhs_op(lhs, rhs, T::$fn_name, meta, stringify!([< scalar_ $fn_name >]))
173 }
174
175 pub fn $fn_name(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Self> {
176 match rhs.into() {
177 TensorOrScalar::Tensor(t) => self.[< $fn_name _tensor >](&t),
178 TensorOrScalar::Scalar(s) => self.[< $fn_name _scalar >](s)
179 }
180 }
181 }
182 };
183}
184
185impl<T: NumDType> Tensor<T> {
186 binary_op_impl!(add);
187 binary_op_impl!(mul);
188 binary_op_impl!(sub);
189 binary_op_impl!(div);
190 binary_op_impl!(minimum);
191 binary_op_impl!(maximum);
192
193 pub fn clamp(&self, min: T, max: T) -> crate::Result<Self> {
194 self.maximum(min)?.minimum(max)
195 }
196}
197
198impl<T: NumDType> Tensor<T> {
199 fn binary_inplace_op<F>(lhs: &Tensor<T>, rhs: &Tensor<T>, f: F, op_name: &'static str) -> crate::Result<()>
200 where
201 F: Fn(T, T) -> T
202 {
203 let _ = Tensor::<T>::same_shape_binary_op(lhs, rhs, op_name)?;
204
205 let mut lhs_storage = lhs.storage_write()?;
206 let rhs_storage = rhs.storage_read()?;
207 let lhs_layout = lhs.layout();
208 let rhs_layout = rhs.layout();
209
210 assert_eq!(lhs_layout.dims(), rhs_layout.dims(), "lhs dims != rhs dim2");
211
212 let lhs = lhs_storage.data_mut();
213 let rhs = rhs_storage.data();
214
215 match (lhs_layout.storage_indices(), rhs_layout.storage_indices()) {
216 (StorageIndices::Contiguous(lhs_index), StorageIndices::Contiguous(rhs_index)) => {
217 let lhs = &mut lhs[lhs_index.begin_index..lhs_index.end_index];
218 let rhs = &rhs[rhs_index.begin_index..rhs_index.end_index];
219 lhs.iter_mut().zip(rhs.iter())
220 .for_each(|(l, &r)| *l = f(*l, r));
221 }
222 (StorageIndices::Contiguous(lhs_index), StorageIndices::Uncontiguous(rhs_index)) => {
223 let lhs = &mut lhs[lhs_index.begin_index..lhs_index.end_index];
224 lhs.iter_mut().zip(rhs_index)
225 .for_each(|(l, rhs_index)| *l = f(*l, rhs[rhs_index]));
226 }
227 (StorageIndices::Uncontiguous(lhs_index), StorageIndices::Contiguous(rhs_index)) => {
228 let rhs = &rhs[rhs_index.begin_index..rhs_index.end_index];
229 lhs_index.zip(rhs.iter())
230 .for_each(|(lhs_index, &r)| lhs[lhs_index] = f(lhs[lhs_index], r));
231 }
232 (StorageIndices::Uncontiguous(lhs_index), StorageIndices::Uncontiguous(rhs_index)) => {
233 lhs_index.zip(rhs_index)
234 .for_each(|(lhs_index, rhs_index)| lhs[lhs_index] = f(lhs[lhs_index], rhs[rhs_index]));
235 }
236 }
237
238 Ok(())
239 }
240
241 fn binary_op_scalar_inplace<F>(lhs: &Tensor<T>, rhs: T, f: F, _op_name: &'static str) -> crate::Result<()>
242 where
243 F: Fn(T, T) -> T
244 {
245 let mut lhs_storage = lhs.storage_write()?;
246 let lhs_layout = lhs.layout();
247 let lhs = lhs_storage.data_mut();
248
249 match lhs_layout.storage_indices() {
250 StorageIndices::Contiguous(index) => {
251 let lhs = &mut lhs[index.begin_index..index.end_index];
252 lhs.iter_mut().for_each(|l| *l = f(*l, rhs));
253 }
254 StorageIndices::Uncontiguous(index) => {
255 index.for_each(|lhs_index| lhs[lhs_index] = f(lhs[lhs_index], rhs));
256 }
257 }
258
259 Ok(())
260 }
261}
262
263macro_rules! binary_inplace_op_impl {
264 ($fn_name:ident) => {
265 paste! {
266 pub fn [< $fn_name _ >](&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Self> {
271 self.check_implace_op()?;
272 self.[<impl_ $fn_name _ >](rhs)
273 }
274
275 pub(crate) fn [<impl_ $fn_name _ >](&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Self> {
276 let rhs = rhs.into();
277 match rhs {
278 TensorOrScalar::Scalar(rhs) => Self::binary_op_scalar_inplace(self, rhs, T::$fn_name, stringify!([< $fn_name _scalar_ >]))?,
279 TensorOrScalar::Tensor(rhs) => Self::binary_inplace_op(self, &rhs, T::$fn_name, stringify!([< $fn_name _scalar >]))?,
280 }
281 Ok(self.clone())
282 }
283 }
284 };
285}
286
287#[allow(unused)]
288impl<T: NumDType> Tensor<T> {
289 binary_inplace_op_impl!(add);
290 binary_inplace_op_impl!(sub);
291 binary_inplace_op_impl!(mul);
292 binary_inplace_op_impl!(div);
293 binary_inplace_op_impl!(minimum);
294 binary_inplace_op_impl!(maximum);
295
296 pub fn clamp_(&self, min: T, max: T) -> crate::Result<()> {
301 self.maximum_(min)?;
302 self.minimum_(max)?;
303 Ok(())
304 }
305}
306
307impl<T: NumDType> Tensor<T> {
308 pub fn eq(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
309 self.cmp(rhs, CmpOp::Eq)
310 }
311
312 pub fn ne(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
313 self.cmp(rhs, CmpOp::Ne)
314 }
315
316 pub fn le(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
317 self.cmp(rhs, CmpOp::Le)
318 }
319
320 pub fn ge(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
321 self.cmp(rhs, CmpOp::Ge)
322 }
323
324 pub fn lt(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
325 self.cmp(rhs, CmpOp::Lt)
326 }
327
328 pub fn gt(&self, rhs: impl Into<TensorOrScalar<T>>) -> crate::Result<Tensor<bool>> {
329 self.cmp(rhs, CmpOp::Gt)
330 }
331
332 pub fn cmp(&self, rhs: impl Into<TensorOrScalar<T>>, op: CmpOp) -> crate::Result<Tensor<bool>> {
333 match rhs.into() {
334 TensorOrScalar::Tensor(rhs) => {
335 match op {
336 CmpOp::Eq => Self::binary_op(self, &rhs, |a, b| a == b, Default::default(), "eq"),
337 CmpOp::Ne => Self::binary_op(self, &rhs, |a, b| a != b, Default::default(), "nq"),
338 CmpOp::Le => Self::binary_op(self, &rhs, |a, b| a <= b, Default::default(), "le"),
339 CmpOp::Ge => Self::binary_op(self, &rhs, |a, b| a >= b, Default::default(), "ge"),
340 CmpOp::Lt => Self::binary_op(self, &rhs, |a, b| a < b, Default::default(), "lt"),
341 CmpOp::Gt => Self::binary_op(self, &rhs, |a, b| a > b, Default::default(), "gt"),
342 }
343 }
344 TensorOrScalar::Scalar(rhs) => {
345 match op {
346 CmpOp::Eq => Self::binary_scalar_rhs_op(self, rhs, |a, b| a == b, Default::default(), "eq"),
347 CmpOp::Ne => Self::binary_scalar_rhs_op(self, rhs, |a, b| a != b, Default::default(), "nq"),
348 CmpOp::Le => Self::binary_scalar_rhs_op(self, rhs, |a, b| a <= b, Default::default(), "le"),
349 CmpOp::Ge => Self::binary_scalar_rhs_op(self, rhs, |a, b| a >= b, Default::default(), "ge"),
350 CmpOp::Lt => Self::binary_scalar_rhs_op(self, rhs, |a, b| a < b, Default::default(), "lt"),
351 CmpOp::Gt => Self::binary_scalar_rhs_op(self, rhs, |a, b| a > b, Default::default(), "gt"),
352 }
353 }
354 }
355 }
356}
357
358impl Tensor<bool> {
359 pub fn and(&self, rhs: impl Into<TensorOrScalar<bool>>) -> crate::Result<Tensor<bool>> {
360 match rhs.into() {
361 TensorOrScalar::Tensor(rhs) => Self::binary_op(self, &rhs, |a, b| a & b, Default::default(), "and"),
362 TensorOrScalar::Scalar(rhs) => Self::binary_scalar_rhs_op(self, rhs, |a, b| a & b, Default::default(), "and"),
363 }
364 }
365
366 pub fn or(&self, rhs: impl Into<TensorOrScalar<bool>>) -> crate::Result<Tensor<bool>> {
367 match rhs.into() {
368 TensorOrScalar::Tensor(rhs) => Self::binary_op(self, &rhs, |a, b| a | b, Default::default(), "or"),
369 TensorOrScalar::Scalar(rhs) => Self::binary_scalar_rhs_op(self, rhs, |a, b| a | b, Default::default(), "or"),
370 }
371 }
372
373 pub fn xor(&self, rhs: impl Into<TensorOrScalar<bool>>) -> crate::Result<Tensor<bool>> {
374 match rhs.into() {
375 TensorOrScalar::Tensor(rhs) => Self::binary_op(self, &rhs, |a, b| a ^ b, Default::default(), "xor"),
376 TensorOrScalar::Scalar(rhs) => Self::binary_scalar_rhs_op(self, rhs, |a, b| a ^ b, Default::default(), "xor"),
377 }
378 }
379
380 pub fn not(&self) -> crate::Result<Tensor<bool>> {
381 if self.element_count() == 0 {
382 return Ok(self.clone());
383 }
384 let storage = self.compute_unary_op(|v| !v)?;
385 Ok(Self::from_storage(storage, self.shape(), Default::default()))
386 }
387}
388
389impl<T: WithDType> Tensor<T> {
394 fn compute_unary_op<U, F>(&self, f: F) -> crate::Result<Storage<U>>
395 where
396 U: WithDType,
397 F: Fn(T) -> U
398 {
399 let storage = self.storage_read()?;
400 let vec = storage.data();
401
402 let output: Vec<_> = match self.storage_indices() {
403 StorageIndices::Contiguous(index) => {
404 let data = &vec[index.begin_index..index.end_index];
405 data.iter().map(|&v| f(v)).collect()
406 }
407 StorageIndices::Uncontiguous(index) => {
408 index.map(|i| f(vec[i])).collect()
409 }
410 };
411
412 Ok(Storage::new(output))
413 }
414
415 fn unary_op<U, F>(&self, f: F, meta: U::AutogradMeta) -> crate::Result<Tensor<U>>
416 where
417 U: WithDType,
418 F: Fn(T) -> U
419 {
420 let storage = self.compute_unary_op(f)?;
421 Ok(Tensor::from_storage(storage, self.shape(), meta))
422 }
423
424 fn unary_assign_op<F>(&self, f: F) -> crate::Result<()>
425 where
426 F: Fn(T) -> T
427 {
428 self.check_implace_op()?;
429
430 let mut storage = self.storage_write()?;
431 let vec = storage.data_mut();
432 match self.layout().storage_indices() {
433 StorageIndices::Contiguous(index) => {
434 let vec = &mut vec[index.begin_index..index.end_index];
435 vec.iter_mut().for_each(|v| *v = f(*v));
436 }
437 StorageIndices::Uncontiguous(index) => {
438 for index in index {
439 vec[index] = f(vec[index]);
440 }
441 }
442 }
443
444 Ok(())
445 }
446}
447
448macro_rules! float_unary_op_impl {
449 ($fn_name:ident) => {
450 paste! {
451 pub fn $fn_name(&self) -> crate::Result<Self> {
452 let meta = F::AutogradMeta::on_unray_op(self, UnaryOp:: [< $fn_name:camel >]);
453 self.unary_op(F::$fn_name, meta)
454 }
455
456 #[inline]
461 pub fn [<$fn_name _>](&self) -> crate::Result<()> {
462 self.unary_assign_op(F::$fn_name)
463 }
464 }
465 };
466}
467
468impl<F: NumDType> Tensor<F> {
469 pub fn sign(&self) -> crate::Result<Self> {
470 let meta = F::AutogradMeta::on_unray_op(self, UnaryOp::Sign);
471 self.unary_op(F::sign, meta)
472 }
473
474 #[inline]
479 pub fn sign_(&self) -> crate::Result<()> {
480 self.unary_assign_op(F::sign)
481 }
482}
483
484impl<F: FloatDType> Tensor<F> {
485 float_unary_op_impl!(floor);
486 float_unary_op_impl!(ceil);
487 float_unary_op_impl!(round);
488 float_unary_op_impl!(exp);
489 float_unary_op_impl!(ln);
490 float_unary_op_impl!(sin);
491 float_unary_op_impl!(cos);
492 float_unary_op_impl!(tanh);
493 float_unary_op_impl!(sqrt);
494 float_unary_op_impl!(sqr);
495 float_unary_op_impl!(abs);
496 float_unary_op_impl!(recip);
497 float_unary_op_impl!(gelu);
498 float_unary_op_impl!(gelu_erf);
499 float_unary_op_impl!(erf);
500 float_unary_op_impl!(relu);
501 float_unary_op_impl!(silu);
502 float_unary_op_impl!(sigmoid);
503
504 pub fn leaky_relu(&self, negative_slope: F) -> crate::Result<Self> {
505 let meta = F::AutogradMeta::on_unray_op(self, UnaryOp::LeakyRelu(negative_slope));
506 self.unary_op(|v: F| F::leaky_relu(v, negative_slope), meta)
507 }
508
509 #[inline]
510 pub fn leaky_relu_(&self, negative_slope: F) -> crate::Result<()> {
511 self.unary_assign_op(|v: F| F::leaky_relu(v, negative_slope))
512 }
513}
514
515impl<F: FloatDType> Tensor<F> {
516 pub fn pow(&self, e: F) -> crate::Result<Self> {
517 let meta = F::AutogradMeta::on_unray_op(self, UnaryOp::Pow(e));
518 self.unary_op(|v: F| v.powf(e), meta)
519 }
520
521 #[inline]
522 pub fn pow_(&self, e: F) -> crate::Result<()> {
523 self.unary_assign_op(|v: F| v.powf(e))
524 }
525}
526
527impl<T: WithDType> Tensor<T> {
528 #[inline]
529 pub fn map<F, O>(&self, f: F) -> crate::Result<Tensor<O>>
530 where
531 O: WithDType,
532 F: Fn(T) -> O,
533 {
534 self.unary_op(f, Default::default())
535 }
536
537 #[inline]
538 pub fn map_<F>(&self, f: F) -> crate::Result<()>
539 where
540 F: Fn(T) -> T,
541 {
542 self.unary_assign_op(f)
543 }
544}
545
546impl<T: NumDType + Neg<Output = T>> Tensor<T> {
547 pub fn neg(&self) -> crate::Result<Self> {
548 let meta = T::AutogradMeta::on_unray_op(self, UnaryOp::Neg);
549 self.unary_op(T::neg, meta)
550 }
551
552 #[inline]
553 pub fn neg_(&self) -> crate::Result<()> {
554 self.unary_assign_op(T::neg)
555 }
556}
557
558impl<T: NumDType> Tensor<T> {
559 pub fn affine(&self, mul: T, add: T) -> crate::Result<Self> {
561 let meta = T::AutogradMeta::on_unray_op(self, UnaryOp::Affine{ mul, add });
562 self.unary_op(|v| v * mul + add, meta)
563 }
564
565 #[inline]
566 pub fn affine_(&self, mul: T, add: T) -> crate::Result<()> {
567 self.unary_assign_op(|v| v * mul + add)
568 }
569}
570
571use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Sub};
572
573impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Add<R> for &Tensor<T> {
578 type Output = Tensor<T>;
579 fn add(self, rhs: R) -> Self::Output {
580 Tensor::add(self, rhs).expect("Tensor::add failed")
581 }
582}
583
584impl<'a, T: NumDType, R> Add<R> for Tensor<T>
585where R: Into<TensorOrScalar<T>>
586{
587 type Output = Tensor<T>;
588 fn add(self, rhs: R) -> Self::Output {
589 Tensor::add(&self, rhs).expect("Tensor::add failed")
590 }
591}
592
593impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Sub<R> for &Tensor<T> {
598 type Output = Tensor<T>;
599 fn sub(self, rhs: R) -> Self::Output {
600 Tensor::sub(self, rhs).expect("Tensor::sub failed")
601 }
602}
603
604impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Sub<R> for Tensor<T> {
605 type Output = Tensor<T>;
606 fn sub(self, rhs: R) -> Self::Output {
607 Tensor::sub(&self, rhs).expect("Tensor::sub failed")
608 }
609}
610
611impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Mul<R> for &Tensor<T> {
616 type Output = Tensor<T>;
617 fn mul(self, rhs: R) -> Self::Output {
618 Tensor::mul(self, rhs).expect("Tensor::mul failed")
619 }
620}
621
622impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Mul<R> for Tensor<T> {
623 type Output = Tensor<T>;
624 fn mul(self, rhs: R) -> Self::Output {
625 Tensor::mul(&self, rhs).expect("Tensor::mul failed")
626 }
627}
628
629impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Div<R> for &Tensor<T> {
634 type Output = Tensor<T>;
635 fn div(self, rhs: R) -> Self::Output {
636 Tensor::div(self, rhs).expect("Tensor::div failed")
637 }
638}
639
640impl<'a, T: NumDType, R: Into<TensorOrScalar<T>>> Div<R> for Tensor<T> {
641 type Output = Tensor<T>;
642 fn div(self, rhs: R) -> Self::Output {
643 Tensor::div(&self, rhs).expect("Tensor::div failed")
644 }
645}
646
647impl<'a, R: Into<TensorOrScalar<bool>>> BitAnd<R> for &Tensor<bool> {
652 type Output = Tensor<bool>;
653 fn bitand(self, rhs: R) -> Self::Output {
654 self.and(rhs).expect("Tensor::and failed")
655 }
656}
657
658impl<'a, R: Into<TensorOrScalar<bool>>> BitAnd<R> for Tensor<bool> {
659 type Output = Tensor<bool>;
660 fn bitand(self, rhs: R) -> Self::Output {
661 self.and(rhs).expect("Tensor::and failed")
662 }
663}
664
665impl<'a, R: Into<TensorOrScalar<bool>>> BitOr<R> for &Tensor<bool> {
666 type Output = Tensor<bool>;
667 fn bitor(self, rhs: R) -> Self::Output {
668 self.or(rhs).expect("Tensor::or failed")
669 }
670}
671
672impl<'a, R: Into<TensorOrScalar<bool>>> BitOr<R> for Tensor<bool> {
673 type Output = Tensor<bool>;
674 fn bitor(self, rhs: R) -> Self::Output {
675 self.or(rhs).expect("Tensor::or failed")
676 }
677}
678
679impl<'a, R: Into<TensorOrScalar<bool>>> BitXor<R> for &Tensor<bool> {
680 type Output = Tensor<bool>;
681 fn bitxor(self, rhs: R) -> Self::Output {
682 self.xor(rhs).expect("Tensor::xor failed")
683 }
684}
685
686impl<'a, R: Into<TensorOrScalar<bool>>> BitXor<R> for Tensor<bool> {
687 type Output = Tensor<bool>;
688 fn bitxor(self, rhs: R) -> Self::Output {
689 self.xor(rhs).expect("Tensor::xor failed")
690 }
691}
692
693macro_rules! impl_scalar_tensor_binary {
698 ($($t:ty),*) => {
699 $(
700 impl Add<Tensor<$t>> for $t {
701 type Output = Tensor<$t>;
702
703 fn add(self, rhs: Tensor<$t>) -> Self::Output {
704 Tensor::add(&rhs, self).expect("Tensor::add failed")
705 }
706 }
707
708 impl Add<&Tensor<$t>> for $t {
709 type Output = Tensor<$t>;
710
711 fn add(self, rhs: &Tensor<$t>) -> Self::Output {
712 Tensor::add(rhs, self).expect("Tensor::add failed")
713 }
714 }
715
716 impl Mul<Tensor<$t>> for $t {
717 type Output = Tensor<$t>;
718
719 fn mul(self, rhs: Tensor<$t>) -> Self::Output {
720 Tensor::mul(&rhs, self).expect("Tensor::mul failed")
721 }
722 }
723
724 impl Mul<&Tensor<$t>> for $t {
725 type Output = Tensor<$t>;
726
727 fn mul(self, rhs: &Tensor<$t>) -> Self::Output {
728 Tensor::mul(rhs, self).expect("Tensor::mul failed")
729 }
730 }
731
732 impl Sub<&Tensor<$t>> for $t {
733 type Output = Tensor<$t>;
734
735 fn sub(self, rhs: &Tensor<$t>) -> Self::Output {
736 Tensor::scalar_sub(self, rhs).expect("Tensor::scalar_sub failed")
737 }
738 }
739
740 impl Sub<Tensor<$t>> for $t {
741 type Output = Tensor<$t>;
742
743 fn sub(self, rhs: Tensor<$t>) -> Self::Output {
744 Tensor::scalar_sub(self, &rhs).expect("Tensor::scalar_sub failed")
745 }
746 }
747
748 impl Div<&Tensor<$t>> for $t {
749 type Output = Tensor<$t>;
750
751 fn div(self, rhs: &Tensor<$t>) -> Self::Output {
752 Tensor::scalar_div(self, rhs).expect("Tensor::scalar_div failed")
753 }
754 }
755
756 impl Div<Tensor<$t>> for $t {
757 type Output = Tensor<$t>;
758
759 fn div(self, rhs: Tensor<$t>) -> Self::Output {
760 Tensor::scalar_div(self, &rhs).expect("Tensor::scalar_div failed")
761 }
762 }
763 )*
764 };
765}
766
767impl_scalar_tensor_binary!(half::bf16, f32, f64, u8, i32, u32);
768
769#[cfg(test)]
770mod tests {
771 use super::*;
772
773 #[test]
774 fn test_inplace_safe_ops() -> crate::Result<()> {
775 let data = vec![-1.5f32, -0.5, 0.0, 0.5, 1.5];
776
777 macro_rules! test_op {
778 ($op:ident, $op_inplace:ident) => {{
779 let a = Tensor::new(data.clone())?;
780 let b = Tensor::new(data.clone())?;
781
782 let out = a.$op()?;
783 b.$op_inplace()?;
784
785 assert!(b.allclose(&out, 1e-5, 1e-6)?);
786 }};
787 }
788
789 test_op!(floor, floor_);
790 test_op!(ceil, ceil_);
791 test_op!(round, round_);
792 test_op!(sin, sin_);
793 test_op!(cos, cos_);
794 test_op!(tanh, tanh_);
795 test_op!(abs, abs_);
796 test_op!(relu, relu_);
797 test_op!(silu, silu_);
798 test_op!(sigmoid, sigmoid_);
799
800 Ok(())
801 }
802
803 #[test]
804 fn test_inplace_positive_domain_ops() -> crate::Result<()> {
805 let data = vec![0.1f32, 0.5, 1.0, 2.0];
806
807 macro_rules! test_op {
808 ($op:ident, $op_inplace:ident) => {{
809 let a = Tensor::new(data.clone())?;
810 let b = Tensor::new(data.clone())?;
811
812 let out = a.$op()?;
813 b.$op_inplace()?;
814
815 assert!(b.allclose(&out, 1e-5, 1e-6)?);
816 }};
817 }
818
819 test_op!(ln, ln_);
820 test_op!(sqrt, sqrt_);
821 test_op!(recip, recip_);
822 test_op!(exp, exp_);
823 test_op!(gelu, gelu_);
824 test_op!(gelu_erf, gelu_erf_);
825 test_op!(erf, erf_);
826
827 Ok(())
828 }
829
830 #[test]
831 fn test_exp_log() -> crate::Result<()> {
832 let a = Tensor::new(&[0.0f32, 1.0, 2.0])?;
833 let exp_a = a.exp()?;
834 let log_a = exp_a.ln()?;
835 assert!(a.allclose(&log_a, 1e-5, 1e-8)?);
836 Ok(())
837 }
838
839 #[test]
840 fn test_trig() -> crate::Result<()> {
841 let a = Tensor::new(&[0.0f32, std::f32::consts::FRAC_PI_2])?;
842 let sin_a = a.sin()?;
843 let cos_a = a.cos()?;
844
845 let expected_sin = Tensor::new(&[0.0f32, 1.0])?;
846 let expected_cos = Tensor::new(&[1.0f32, 0.0])?;
847
848 println!("{:?}", cos_a.iter()?.collect::<Vec<_>>());
849
850 assert!(sin_a.allclose(&expected_sin, 1e-5, 1e-8)?);
851 assert!(cos_a.allclose(&expected_cos, 1e-5, 8e-8)?);
852
853 Ok(())
854 }
855
856 #[test]
857 fn test_abs_neg() -> crate::Result<()> {
858 let a = Tensor::new(&[-1.0f32, 0.0, 2.0])?;
859 let abs_a = a.abs()?;
860 let neg_a = a.neg()?;
861
862 let expected_abs = Tensor::new(&[1.0f32, 0.0, 2.0])?;
863 let expected_neg = Tensor::new(&[1.0f32, 0.0, -2.0])?;
864
865 assert!(abs_a.allclose(&expected_abs, 1e-6, 1e-6)?);
866 assert!(neg_a.allclose(&expected_neg, 1e-6, 1e-6)?);
867
868 Ok(())
869 }
870
871 #[test]
872 fn test_floor_ceil_round() -> crate::Result<()> {
873 let a = Tensor::new(&[1.2f32, 2.7, -1.3])?;
874 let floor_a = a.floor()?;
875 let ceil_a = a.ceil()?;
876 let round_a = a.round()?;
877
878 let expected_floor = Tensor::new(&[1.0f32, 2.0, -2.0])?;
879 let expected_ceil = Tensor::new(&[2.0f32, 3.0, -1.0])?;
880 let expected_round = Tensor::new(&[1.0f32, 3.0, -1.0])?;
881
882 assert!(floor_a.allclose(&expected_floor, 1e-6, 1e-6)?);
883 assert!(ceil_a.allclose(&expected_ceil, 1e-6, 1e-6)?);
884 assert!(round_a.allclose(&expected_round, 1e-6, 1e-6)?);
885
886 Ok(())
887 }
888
889 #[test]
890 fn test_floor_recip() -> crate::Result<()> {
891 let a = Tensor::new(&[1.2f32, 2.7, -1.3])?;
892 let recip_a = a.recip()?;
893 let expected = Tensor::new(&[1.2f32.recip(), 2.7f32.recip(), -1.3f32.recip(),])?;
894
895 assert!(recip_a.allclose(&expected, 1e-6, 1e-6)?);
896
897 Ok(())
898 }
899
900 #[test]
901 fn test_add_basic() -> crate::Result<()> {
902 let a = Tensor::new(&[1.0f32, 2.0, 3.0])?;
903 let b = Tensor::new(&[4.0f32, 5.0, 6.0])?;
904 let c = Tensor::add(&a, &b)?;
905 let expected = Tensor::new(&[5.0f32, 7.0, 9.0])?;
906 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
907
908 Ok(())
909 }
910
911 #[test]
912 fn test_add_basic_variable() -> crate::Result<()> {
913 let a = Tensor::new_var(&[1.0f32, 2.0, 3.0])?;
914 let b = Tensor::new_var(&[4.0f32, 5.0, 6.0])?;
915 let c = Tensor::add(&a, &b)?;
916 let expected = Tensor::new(&[5.0f32, 7.0, 9.0])?;
917 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
918
919 Ok(())
920 }
921
922 #[test]
923 fn test_sub_basic() -> crate::Result<()> {
924 let a = Tensor::new(&[10.0f32, 20.0, 30.0])?;
925 let b = Tensor::new(&[1.0f32, 2.0, 3.0])?;
926 let c = Tensor::sub(&a, &b)?;
927 let expected = Tensor::new(&[9.0f32, 18.0, 27.0])?;
928 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
929
930 Ok(())
931 }
932
933 #[test]
934 fn test_mul_basic() -> crate::Result<()> {
935 let a = Tensor::new(&[1.0f32, 2.0, 3.0])?;
936 let b = Tensor::new(&[2.0f32, 3.0, 4.0])?;
937 let c = Tensor::mul(&a, &b)?;
938 let expected = Tensor::new(&[2.0f32, 6.0, 12.0])?;
939 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
940
941 Ok(())
942 }
943
944 #[test]
945 fn test_div_basic() -> crate::Result<()> {
946 let a = Tensor::new(&[4.0f32, 9.0, 16.0])?;
947 let b = Tensor::new(&[2.0f32, 3.0, 4.0])?;
948 let c = Tensor::div(&a, &b)?;
949 let expected = Tensor::new(&[2.0f32, 3.0, 4.0])?;
950 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
951
952 Ok(())
953 }
954
955 #[test]
956 fn test_min_max_basic() -> crate::Result<()> {
957 let a = Tensor::new(&[1.0f32, 5.0, 3.0])?;
958 let b = Tensor::new(&[2.0f32, 4.0, 6.0])?;
959 let min_res = Tensor::minimum(&a, &b)?;
960 let max_res = Tensor::maximum(&a, &b)?;
961 let expected_min = Tensor::new(&[1.0f32, 4.0, 3.0])?;
962 let expected_max = Tensor::new(&[2.0f32, 5.0, 6.0])?;
963 assert!(min_res.allclose(&expected_min, 1e-6, 1e-6)?);
964 assert!(max_res.allclose(&expected_max, 1e-6, 1e-6)?);
965
966 Ok(())
967 }
968
969 #[test]
970 fn test_comparisons() -> crate::Result<()> {
971 let a = Tensor::new(&[1, 2, 3])?;
972 let b = Tensor::new(&[1, 0, 3])?;
973
974 assert_eq!(a.eq(&b).unwrap().to_vec()?, [true, false, true]);
975 assert_eq!(a.ne(&b).unwrap().to_vec()?, [false, true, false]);
976 assert_eq!(a.lt(&b).unwrap().to_vec()?, [false, false, false]);
977 assert_eq!(a.le(&b).unwrap().to_vec()?, [true, false, true]);
978 assert_eq!(a.gt(&b).unwrap().to_vec()?, [false, true, false]);
979 assert_eq!(a.ge(&b).unwrap().to_vec()?, [true, true, true]);
980
981 Ok(())
982 }
983
984 #[test]
985 fn test_add_mul_2d_3d() -> crate::Result<()> {
986 let a = Tensor::new(&[[1.0f32, 2.0], [3.0, 4.0]])?;
987 let b = Tensor::new(&[[5.0f32, 6.0], [7.0, 8.0]])?;
988 let c = Tensor::add(&a, &b)?;
989 let expected = Tensor::new(&[[6., 8.], [10., 12.]])?;
990 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
991
992 let a3 = Tensor::new(&[
993 [[1., 2.], [3., 4.]],
994 [[5., 6.], [7., 8.]],
995 ])?;
996 let b3 = Tensor::new(&[
997 [[2., 0.5], [1., 2.]],
998 [[0.5, 2.], [1.5, 1.]],
999 ])?;
1000 let c3 = Tensor::mul(&a3, &b3)?;
1001 let expected3 = Tensor::new(&[
1002 [[2., 1.], [3., 8.]],
1003 [[2.5, 12.], [10.5, 8.]],
1004 ])?;
1005 assert!(c3.allclose(&expected3, 1e-6, 1e-6)?);
1006
1007 Ok(())
1008 }
1009
1010 #[test]
1011 fn test_div_high_dim() -> crate::Result<()> {
1012 let a = Tensor::full((2, 2, 2, 2), 8.0f32)?;
1013 let b = Tensor::full((2, 2, 2, 2), 2.0f32)?;
1014 let c = Tensor::div(&a, &b)?;
1015 let expected = Tensor::full((2, 2, 2, 2), 4.0f32)?;
1016 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1017
1018 Ok(())
1019 }
1020
1021 #[test]
1022 fn test_affine_and_affine_() -> crate::Result<()> {
1023 let a = Tensor::<f64>::ones((3, 3))?;
1024 let b = a.affine(3., 2.)?;
1025 let expected = Tensor::new(&[[5., 5., 5.],[5.,5.,5.],[5.,5.,5.]])?;
1026 assert!(b.allclose(&expected, 1e-6, 1e-6)?);
1027
1028 let a2 = Tensor::<f64>::ones((3, 3))?;
1029 a2.affine_(3., 2.)?;
1030 assert!(a2.allclose(&expected, 1e-6, 1e-6)?);
1031 Ok(())
1032 }
1033
1034 #[test]
1035 fn test_add_scalar() -> crate::Result<()> {
1036 let a = Tensor::new(&[1.0f32, 2.0, 3.0])?;
1037 let b = 10.0f32;
1038 let c = Tensor::add(&a, b)?;
1039 let expected = Tensor::new(&[11.0f32, 12.0, 13.0])?;
1040 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1041 Ok(())
1042 }
1043
1044 #[test]
1045 fn test_sub_scalar() -> crate::Result<()> {
1046 let a = Tensor::new(&[10.0f32, 20.0, 30.0])?;
1047 let b = 5.0f32;
1048 let c = Tensor::sub(&a, b)?;
1049 let expected = Tensor::new(&[5.0f32, 15.0, 25.0])?;
1050 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1051 Ok(())
1052 }
1053
1054 #[test]
1055 fn test_mul_scalar() -> crate::Result<()> {
1056 let a = Tensor::new(&[1.0f32, 2.0, 3.0])?;
1057 let b = 2.0f32;
1058 let c = Tensor::mul(&a, b)?;
1059 let expected = Tensor::new(&[2.0f32, 4.0, 6.0])?;
1060 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1061 Ok(())
1062 }
1063
1064 #[test]
1065 fn test_div_scalar() -> crate::Result<()> {
1066 let a = Tensor::new(&[4.0f32, 9.0, 16.0])?;
1067 let b = 2.0f32;
1068 let c = Tensor::div(&a, b)?;
1069 let expected = Tensor::new(&[2.0f32, 4.5, 8.0])?;
1070 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1071 Ok(())
1072 }
1073
1074 #[test]
1075 fn test_minimum_scalar() -> crate::Result<()> {
1076 let a = Tensor::new(&[1.0f32, 5.0, 3.0])?;
1077 let b = 4.0f32;
1078 let c = Tensor::minimum(&a, b)?;
1079 let expected = Tensor::new(&[1.0f32, 4.0, 3.0])?;
1080 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1081 Ok(())
1082 }
1083
1084 #[test]
1085 fn test_maximum_scalar() -> crate::Result<()> {
1086 let a = Tensor::new(&[1.0f32, 5.0, 3.0])?;
1087 let b = 4.0f32;
1088 let c = Tensor::maximum(&a, b)?;
1089 let expected = Tensor::new(&[4.0f32, 5.0, 4.0])?;
1090 assert!(c.allclose(&expected, 1e-6, 1e-6)?);
1091 Ok(())
1092 }
1093
1094 #[test]
1095 fn test_eq_ne_scalar() -> crate::Result<()> {
1096 let a = Tensor::new(&[1, 2, 3])?;
1097 let b = 2;
1098
1099 let eq_res = a.eq(b)?;
1101 let expected_eq = Tensor::new(&[false, true, false])?;
1102 assert_eq!(eq_res.to_vec()?, expected_eq.to_vec()?);
1103
1104 let ne_res = a.ne(b)?;
1105 let expected_ne = Tensor::new(&[true, false, true])?;
1106 assert_eq!(ne_res.to_vec()?, expected_ne.to_vec()?);
1107 Ok(())
1108 }
1109
1110 #[test]
1111 fn test_lt_le_gt_ge_scalar() -> crate::Result<()> {
1112 let a = Tensor::new(&[1, 2, 3])?;
1113 let b = 2;
1114
1115 let lt_res = a.lt(b)?;
1116 assert_eq!(lt_res.to_vec()?, [true, false, false]);
1117
1118 let le_res = a.le(b)?;
1119 assert_eq!(le_res.to_vec()?, [true, true, false]);
1120
1121 let gt_res = a.gt(b)?;
1122 assert_eq!(gt_res.to_vec()?, [false, false, true]);
1123
1124 let ge_res = a.ge(b)?;
1125 assert_eq!(ge_res.to_vec()?, [false, true, true]);
1126
1127 Ok(())
1128 }
1129
1130 #[test]
1131 fn test_eq_ne_tensor() -> crate::Result<()> {
1132 let a = Tensor::new(&[1, 2, 3])?;
1133 let b = Tensor::new(&[1, 0, 3])?;
1134
1135 let eq_res = a.eq(&b)?;
1136 assert_eq!(eq_res.to_vec()?, [true, false, true]);
1137
1138 let ne_res = a.ne(&b)?;
1139 assert_eq!(ne_res.to_vec()?, [false, true, false]);
1140
1141 Ok(())
1142 }
1143
1144 #[test]
1145 fn test_lt_le_gt_ge_tensor() -> crate::Result<()> {
1146 let a = Tensor::new(&[1, 2, 3])?;
1147 let b = Tensor::new(&[2, 2, 1])?;
1148
1149 let lt_res = a.lt(&b)?;
1150 assert_eq!(lt_res.to_vec()?, [true, false, false]);
1151
1152 let le_res = a.le(&b)?;
1153 assert_eq!(le_res.to_vec()?, [true, true, false]);
1154
1155 let gt_res = a.gt(&b)?;
1156 assert_eq!(gt_res.to_vec()?, [false, false, true]);
1157
1158 let ge_res = a.ge(&b)?;
1159 assert_eq!(ge_res.to_vec()?, [false, true, true]);
1160
1161 Ok(())
1162 }
1163
1164 #[test]
1165 fn test_comparison_2d() -> crate::Result<()> {
1166 let a = Tensor::new(&[[1, 2], [3, 4]])?;
1167 let b = Tensor::new(&[[2, 2], [1, 5]])?;
1168
1169 let eq_res = a.eq(&b)?;
1170 let expected_eq = Tensor::new(&[[false, true], [false, false]])?;
1171 assert_eq!(eq_res.to_vec()?, expected_eq.to_vec()?);
1172
1173 let gt_res = a.gt(&b)?;
1174 let expected_gt = Tensor::new(&[[false, false], [true, false]])?;
1175 assert_eq!(gt_res.to_vec()?, expected_gt.to_vec()?);
1176
1177 let le_res = a.le(3)?;
1179 let expected_le = Tensor::new(&[[true, true], [true, false]])?;
1180 assert_eq!(le_res.to_vec()?, expected_le.to_vec()?);
1181
1182 Ok(())
1183 }
1184
1185 #[test]
1186 fn test_std_ops() -> crate::Result<()> {
1187 let a = Tensor::new(&[[1., 2.], [3., 4.]])?;
1188 let b = Tensor::new(&[[2., 2.], [1., 5.]])?;
1189 let _ = a + b;
1190
1191 let a = Tensor::new(&[[1., 2.], [3., 4.]])?;
1192 let b = Tensor::new(&[[2., 2.], [1., 5.]])?;
1193 let _ = &a + &b;
1194
1195 let a = Tensor::new(&[[1., 2.], [3., 4.]])?;
1196 let b = Tensor::new(&[[2., 2.], [1., 5.]])?;
1197 let _ = a + b;
1198
1199 let a = Tensor::new(&[[1., 2.], [3., 4.]])?;
1200 let b = Tensor::new(&[[2., 2.], [1., 5.]])?;
1201 let _ = a + b;
1202
1203 Ok(())
1204 }
1205
1206 #[test]
1207 fn test_large_ops() -> crate::Result<()> {
1208 let a = Tensor::randn(0.0, 1.0, (5000, 1000))?;
1209 let b = Tensor::randn(0.0, 1.0, (5000, 1000))?;
1210 let now = std::time::Instant::now();
1211 let _ = a + b;
1212 println!("{:?}", std::time::Instant::now() - now);
1213 Ok(())
1214 }
1215}