Skip to main content

faer/col/
colmut.rs

1use super::*;
2use crate::mat::matmut::SyncCell;
3use crate::utils::bound::{Array, Dim, Partition};
4use crate::{ContiguousFwd, Idx, IdxInc};
5use core::marker::PhantomData;
6use core::ptr::NonNull;
7use equator::assert;
8use generativity::Guard;
9/// see [`super::ColMut`]
10pub struct Mut<'a, T, Rows = usize, RStride = isize> {
11	pub(super) imp: ColView<T, Rows, RStride>,
12	pub(super) __marker: PhantomData<&'a mut T>,
13}
14impl<'short, T, Rows: Copy, RStride: Copy> Reborrow<'short>
15	for Mut<'_, T, Rows, RStride>
16{
17	type Target = Ref<'short, T, Rows, RStride>;
18
19	#[inline]
20	fn rb(&'short self) -> Self::Target {
21		Ref {
22			imp: self.imp,
23			__marker: PhantomData,
24		}
25	}
26}
27impl<'short, T, Rows: Copy, RStride: Copy> ReborrowMut<'short>
28	for Mut<'_, T, Rows, RStride>
29{
30	type Target = Mut<'short, T, Rows, RStride>;
31
32	#[inline]
33	fn rb_mut(&'short mut self) -> Self::Target {
34		Mut {
35			imp: self.imp,
36			__marker: PhantomData,
37		}
38	}
39}
40impl<'a, T, Rows: Copy, RStride: Copy> IntoConst for Mut<'a, T, Rows, RStride> {
41	type Target = Ref<'a, T, Rows, RStride>;
42
43	#[inline]
44	fn into_const(self) -> Self::Target {
45		Ref {
46			imp: self.imp,
47			__marker: PhantomData,
48		}
49	}
50}
51unsafe impl<T: Sync, Rows: Sync, RStride: Sync> Sync
52	for Mut<'_, T, Rows, RStride>
53{
54}
55unsafe impl<T: Send, Rows: Send, RStride: Send> Send
56	for Mut<'_, T, Rows, RStride>
57{
58}
59impl<'a, T> ColMut<'a, T> {
60	/// creates a column view over the given element
61	#[inline]
62	pub fn from_mut(value: &'a mut T) -> Self {
63		unsafe { ColMut::from_raw_parts_mut(value as *mut T, 1, 1) }
64	}
65
66	/// creates a `ColMut` from slice views over the column vector data, the
67	/// result has the same number of rows as the length of the input slice
68	#[inline]
69	pub fn from_slice_mut(slice: &'a mut [T]) -> Self {
70		let len = slice.len();
71		unsafe { Self::from_raw_parts_mut(slice.as_mut_ptr(), len, 1) }
72	}
73}
74impl<'a, T, Rows: Shape, RStride: Stride> ColMut<'a, T, Rows, RStride> {
75	/// creates a `ColMut` from pointers to the column vector data, number of
76	/// rows, and row stride
77	///
78	/// # safety
79	/// this function has the same safety requirements as
80	/// [`MatMut::from_raw_parts(ptr, nrows, 1, row_stride, 0)`]
81	#[inline(always)]
82	#[track_caller]
83	pub const unsafe fn from_raw_parts_mut(
84		ptr: *mut T,
85		nrows: Rows,
86		row_stride: RStride,
87	) -> Self {
88		Self {
89			0: Mut {
90				imp: ColView {
91					ptr: NonNull::new_unchecked(ptr),
92					nrows,
93					row_stride,
94				},
95				__marker: PhantomData,
96			},
97		}
98	}
99
100	/// returns a pointer to the column data
101	#[inline(always)]
102	pub fn as_ptr(&self) -> *const T {
103		self.rb().as_ptr()
104	}
105
106	/// returns the number of rows of the column
107	#[inline(always)]
108	pub fn nrows(&self) -> Rows {
109		self.imp.nrows
110	}
111
112	/// returns the number of columns of the column (always `1`)
113	#[inline(always)]
114	pub fn ncols(&self) -> usize {
115		1
116	}
117
118	/// returns the number of rows and columns of the column
119	#[inline(always)]
120	pub fn shape(&self) -> (Rows, usize) {
121		(self.nrows(), self.ncols())
122	}
123
124	/// returns the row stride of the column, specified in number of elements,
125	/// not in bytes
126	#[inline(always)]
127	pub fn row_stride(&self) -> RStride {
128		self.imp.row_stride
129	}
130
131	#[inline]
132	pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Col<U, Rows> {
133		self.rb().map(f)
134	}
135
136	#[inline]
137	pub fn for_each(&self, f: impl Fn(&T)) {
138		self.rb().for_each(f)
139	}
140
141	#[inline]
142	pub fn map_mut<U>(&mut self, f: impl FnMut(&mut T) -> U) -> Col<U, Rows> {
143		let mut f = f;
144		zip!(self).map(|unzip!(x)| f(x))
145	}
146
147	#[inline]
148	pub fn for_each_mut(&mut self, f: impl FnMut(&mut T)) {
149		let mut f = f;
150		zip!(self).for_each(|unzip!(x)| f(x))
151	}
152
153	/// returns a raw pointer to the element at the given index
154	#[inline(always)]
155	pub fn ptr_at(&self, row: IdxInc<Rows>) -> *const T {
156		self.rb().ptr_at(row)
157	}
158
159	/// returns a raw pointer to the element at the given index, assuming the
160	/// provided index is within the column bounds
161	///
162	/// # safety
163	/// the behavior is undefined if any of the following conditions are
164	/// violated:
165	/// * `row < self.nrows()`
166	#[inline(always)]
167	#[track_caller]
168	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>) -> *const T {
169		self.rb().ptr_inbounds_at(row)
170	}
171
172	#[inline]
173	#[track_caller]
174	/// see [`ColRef::split_at_row`]
175	pub fn split_at_row(
176		self,
177		row: IdxInc<Rows>,
178	) -> (ColRef<'a, T, usize, RStride>, ColRef<'a, T, usize, RStride>) {
179		self.into_const().split_at_row(row)
180	}
181
182	#[inline(always)]
183	/// see [`ColRef::transpose`]
184	pub fn transpose(self) -> RowRef<'a, T, Rows, RStride> {
185		self.into_const().transpose()
186	}
187
188	#[inline(always)]
189	/// see [`ColRef::conjugate`]
190	pub fn conjugate(self) -> ColRef<'a, T::Conj, Rows, RStride>
191	where
192		T: Conjugate,
193	{
194		self.into_const().conjugate()
195	}
196
197	#[inline(always)]
198	/// see [`ColRef::canonical`]
199	pub fn canonical(self) -> ColRef<'a, T::Canonical, Rows, RStride>
200	where
201		T: Conjugate,
202	{
203		self.into_const().canonical()
204	}
205
206	#[inline(always)]
207	/// see [`ColRef::adjoint`]
208	pub fn adjoint(self) -> RowRef<'a, T::Conj, Rows, RStride>
209	where
210		T: Conjugate,
211	{
212		self.into_const().adjoint()
213	}
214
215	#[track_caller]
216	#[inline(always)]
217	/// see [`ColRef::get`]
218	pub fn get<RowRange>(
219		self,
220		row: RowRange,
221	) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
222	where
223		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
224	{
225		<ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::get(
226			self.into_const(),
227			row,
228		)
229	}
230
231	#[track_caller]
232	#[inline(always)]
233	/// see [`ColRef::get_unchecked`]
234	pub unsafe fn get_unchecked<RowRange>(
235		self,
236		row: RowRange,
237	) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
238	where
239		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
240	{
241		unsafe {
242			<ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::get_unchecked(
243				self.into_const(),
244				row,
245			)
246		}
247	}
248
249	#[inline]
250	/// see [`ColRef::reverse_rows`]
251	pub fn reverse_rows(self) -> ColRef<'a, T, Rows, RStride::Rev> {
252		self.into_const().reverse_rows()
253	}
254
255	#[inline]
256	/// see [`ColRef::subrows`]
257	pub fn subrows<V: Shape>(
258		self,
259		row_start: IdxInc<Rows>,
260		nrows: V,
261	) -> ColRef<'a, T, V, RStride> {
262		self.into_const().subrows(row_start, nrows)
263	}
264
265	#[inline]
266	#[track_caller]
267	/// see [`ColRef::as_row_shape`]
268	pub fn as_row_shape<V: Shape>(self, nrows: V) -> ColRef<'a, T, V, RStride> {
269		self.into_const().as_row_shape(nrows)
270	}
271
272	#[inline]
273	/// see [`ColRef::as_dyn_rows`]
274	pub fn as_dyn_rows(self) -> ColRef<'a, T, usize, RStride> {
275		self.into_const().as_dyn_rows()
276	}
277
278	#[inline]
279	/// see [`ColRef::as_dyn_stride`]
280	pub fn as_dyn_stride(self) -> ColRef<'a, T, Rows, isize> {
281		self.into_const().as_dyn_stride()
282	}
283
284	#[inline]
285	/// see [`ColRef::iter`]
286	pub fn iter(
287		self,
288	) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a T>
289	where
290		Rows: 'a,
291	{
292		self.into_const().iter()
293	}
294
295	#[inline]
296	#[cfg(feature = "rayon")]
297	/// see [`ColRef::par_iter`]
298	pub fn par_iter(
299		self,
300	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a T>
301	where
302		T: Sync,
303		Rows: 'a,
304	{
305		self.into_const().par_iter()
306	}
307
308	#[inline]
309	#[track_caller]
310	#[cfg(feature = "rayon")]
311	/// see [`ColRef::par_partition`]
312	pub fn par_partition(
313		self,
314		count: usize,
315	) -> impl 'a
316	+ rayon::iter::IndexedParallelIterator<
317		Item = ColRef<'a, T, usize, RStride>,
318	>
319	where
320		T: Sync,
321		Rows: 'a,
322	{
323		self.into_const().par_partition(count)
324	}
325
326	#[inline]
327	/// see [`ColRef::try_as_col_major`]
328	pub fn try_as_col_major(
329		self,
330	) -> Option<ColRef<'a, T, Rows, ContiguousFwd>> {
331		self.into_const().try_as_col_major()
332	}
333
334	#[inline]
335	/// see [`ColRef::try_as_col_major`]
336	pub fn try_as_col_major_mut(
337		self,
338	) -> Option<ColMut<'a, T, Rows, ContiguousFwd>> {
339		self.into_const()
340			.try_as_col_major()
341			.map(|x| unsafe { x.const_cast() })
342	}
343
344	#[inline(always)]
345	#[doc(hidden)]
346	pub unsafe fn const_cast(self) -> ColMut<'a, T, Rows, RStride> {
347		self
348	}
349
350	#[inline]
351	#[doc(hidden)]
352	pub fn bind_r<'N>(self, row: Guard<'N>) -> ColMut<'a, T, Dim<'N>, RStride> {
353		unsafe {
354			ColMut::from_raw_parts_mut(
355				self.as_ptr_mut(),
356				self.nrows().bind(row),
357				self.row_stride(),
358			)
359		}
360	}
361
362	#[inline]
363	/// see [`ColRef::as_mat`]
364	pub fn as_mat(self) -> MatRef<'a, T, Rows, usize, RStride, isize> {
365		self.into_const().as_mat()
366	}
367
368	#[inline]
369	/// see [`ColRef::as_mat`]
370	pub fn as_mat_mut(self) -> MatMut<'a, T, Rows, usize, RStride, isize> {
371		unsafe { self.into_const().as_mat().const_cast() }
372	}
373
374	#[inline]
375	/// see [`ColRef::as_diagonal`]
376	pub fn as_diagonal(self) -> DiagRef<'a, T, Rows, RStride> {
377		DiagRef {
378			0: crate::diag::Ref {
379				inner: self.into_const(),
380			},
381		}
382	}
383}
384impl<
385	T,
386	Rows: Shape,
387	RStride: Stride,
388	Inner: for<'short> ReborrowMut<'short, Target = Mut<'short, T, Rows, RStride>>,
389> generic::Col<Inner>
390{
391	/// copies `other` into `self`
392	#[inline]
393	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(
394		&mut self,
395		other: impl AsColRef<T = RhsT, Rows = Rows>,
396	) where
397		T: ComplexField,
398	{
399		let other = other.as_col_ref();
400		let this = self.rb_mut();
401		assert!(all(
402			this.nrows() == other.nrows(),
403			this.ncols() == other.ncols(),
404		));
405		let m = this.nrows();
406		with_dim!(M, m.unbound());
407		imp(
408			self.rb_mut().as_row_shape_mut(M).as_dyn_stride_mut(),
409			other.as_row_shape(M).canonical(),
410			Conj::get::<RhsT>(),
411		);
412		pub fn imp<'M, 'N, T: ComplexField>(
413			this: ColMut<'_, T, Dim<'M>>,
414			other: ColRef<'_, T, Dim<'M>>,
415			conj_: Conj,
416		) {
417			match conj_ {
418				Conj::No => {
419					zip!(this, other)
420						.for_each(|unzip!(dst, src)| *dst = src.copy());
421				},
422				Conj::Yes => {
423					zip!(this, other)
424						.for_each(|unzip!(dst, src)| *dst = src.conj());
425				},
426			}
427		}
428	}
429
430	/// fills all the elements of `self` with `value`
431	#[inline]
432	pub fn fill(&mut self, value: T)
433	where
434		T: Clone,
435	{
436		fn cloner<T: Clone>(
437			value: T,
438		) -> impl for<'a> FnMut(crate::linalg::zip::Last<&'a mut T>) {
439			#[inline(always)]
440			move |x| *x.0 = value.clone()
441		}
442		z!(self.rb_mut().as_dyn_rows_mut()).for_each(cloner::<T>(value));
443	}
444
445	#[inline]
446	/// returns a view over `self`
447	pub fn as_mut(&mut self) -> ColMut<'_, T, Rows, RStride> {
448		self.rb_mut()
449	}
450}
451impl<'a, T, Rows: Shape, RStride: Stride> ColMut<'a, T, Rows, RStride> {
452	#[inline(always)]
453	/// see [`ColRef::as_ptr`]
454	pub fn as_ptr_mut(&self) -> *mut T {
455		self.rb().as_ptr() as *mut T
456	}
457
458	#[inline(always)]
459	/// see [`ColRef::ptr_at`]
460	pub fn ptr_at_mut(&self, row: IdxInc<Rows>) -> *mut T {
461		self.rb().ptr_at(row) as *mut T
462	}
463
464	#[inline(always)]
465	#[track_caller]
466	/// see [`ColRef::ptr_inbounds_at`]
467	pub unsafe fn ptr_inbounds_at_mut(&self, row: Idx<Rows>) -> *mut T {
468		self.rb().ptr_inbounds_at(row) as *mut T
469	}
470
471	#[inline]
472	#[track_caller]
473	/// see [`ColRef::split_at_row`]
474	pub fn split_at_row_mut(
475		self,
476		row: IdxInc<Rows>,
477	) -> (ColMut<'a, T, usize, RStride>, ColMut<'a, T, usize, RStride>) {
478		let (a, b) = self.into_const().split_at_row(row);
479		unsafe { (a.const_cast(), b.const_cast()) }
480	}
481
482	#[inline(always)]
483	/// see [`ColRef::transpose`]
484	pub fn transpose_mut(self) -> RowMut<'a, T, Rows, RStride> {
485		unsafe { self.into_const().transpose().const_cast() }
486	}
487
488	#[inline(always)]
489	/// see [`ColRef::conjugate`]
490	pub fn conjugate_mut(self) -> ColMut<'a, T::Conj, Rows, RStride>
491	where
492		T: Conjugate,
493	{
494		unsafe { self.into_const().conjugate().const_cast() }
495	}
496
497	#[inline(always)]
498	/// see [`ColRef::canonical`]
499	pub fn canonical_mut(self) -> ColMut<'a, T::Canonical, Rows, RStride>
500	where
501		T: Conjugate,
502	{
503		unsafe { self.into_const().canonical().const_cast() }
504	}
505
506	#[inline(always)]
507	/// see [`ColRef::adjoint`]
508	pub fn adjoint_mut(self) -> RowMut<'a, T::Conj, Rows, RStride>
509	where
510		T: Conjugate,
511	{
512		unsafe { self.into_const().adjoint().const_cast() }
513	}
514
515	#[inline(always)]
516	#[track_caller]
517	pub(crate) fn at_mut(self, row: Idx<Rows>) -> &'a mut T {
518		assert!(all(row < self.nrows()));
519		unsafe { self.at_mut_unchecked(row) }
520	}
521
522	#[inline(always)]
523	#[track_caller]
524	pub(crate) unsafe fn at_mut_unchecked(self, row: Idx<Rows>) -> &'a mut T {
525		&mut *self.ptr_inbounds_at_mut(row)
526	}
527
528	#[track_caller]
529	#[inline(always)]
530	/// see [`ColRef::get`]
531	pub fn get_mut<RowRange>(
532		self,
533		row: RowRange,
534	) -> <ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
535	where
536		ColMut<'a, T, Rows, RStride>: ColIndex<RowRange>,
537	{
538		<ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::get(self, row)
539	}
540
541	#[track_caller]
542	#[inline(always)]
543	/// see [`ColRef::get_unchecked`]
544	pub unsafe fn get_mut_unchecked<RowRange>(
545		self,
546		row: RowRange,
547	) -> <ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
548	where
549		ColMut<'a, T, Rows, RStride>: ColIndex<RowRange>,
550	{
551		unsafe {
552			<ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::get_unchecked(
553				self, row,
554			)
555		}
556	}
557
558	#[inline]
559	/// see [`ColRef::reverse_rows`]
560	pub fn reverse_rows_mut(self) -> ColMut<'a, T, Rows, RStride::Rev> {
561		unsafe { self.into_const().reverse_rows().const_cast() }
562	}
563
564	#[inline]
565	#[track_caller]
566	/// see [`ColRef::subrows`]
567	pub fn subrows_mut<V: Shape>(
568		self,
569		row_start: IdxInc<Rows>,
570		nrows: V,
571	) -> ColMut<'a, T, V, RStride> {
572		unsafe { self.into_const().subrows(row_start, nrows).const_cast() }
573	}
574
575	#[inline]
576	#[track_caller]
577	/// see [`ColRef::as_row_shape`]
578	pub fn as_row_shape_mut<V: Shape>(
579		self,
580		nrows: V,
581	) -> ColMut<'a, T, V, RStride> {
582		unsafe { self.into_const().as_row_shape(nrows).const_cast() }
583	}
584
585	#[inline]
586	/// see [`ColRef::as_dyn_rows`]
587	pub fn as_dyn_rows_mut(self) -> ColMut<'a, T, usize, RStride> {
588		unsafe { self.into_const().as_dyn_rows().const_cast() }
589	}
590
591	#[inline]
592	/// see [`ColRef::as_dyn_stride`]
593	pub fn as_dyn_stride_mut(self) -> ColMut<'a, T, Rows, isize> {
594		unsafe { self.into_const().as_dyn_stride().const_cast() }
595	}
596
597	#[inline]
598	/// see [`ColRef::iter`]
599	pub fn iter_mut(
600		self,
601	) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a mut T>
602	where
603		Rows: 'a,
604	{
605		let this = self.into_const();
606		Rows::indices(Rows::start(), this.nrows().end())
607			.map(move |j| unsafe { this.const_cast().at_mut_unchecked(j) })
608	}
609
610	#[inline]
611	#[cfg(feature = "rayon")]
612	/// see [`ColRef::par_iter`]
613	pub fn par_iter_mut(
614		self,
615	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a mut T>
616	where
617		T: Send,
618		Rows: 'a,
619	{
620		unsafe {
621			let this = self.as_type::<SyncCell<T>>().into_const();
622			use rayon::prelude::*;
623			(0..this.nrows().unbound()).into_par_iter().map(move |j| {
624				let ptr = this
625					.const_cast()
626					.at_mut_unchecked(Idx::<Rows>::new_unbound(j));
627				&mut *(ptr as *mut SyncCell<T> as *mut T)
628			})
629		}
630	}
631
632	#[inline]
633	#[track_caller]
634	#[cfg(feature = "rayon")]
635	/// see [`ColRef::par_partition`]
636	pub fn par_partition_mut(
637		self,
638		count: usize,
639	) -> impl 'a
640	+ rayon::iter::IndexedParallelIterator<
641		Item = ColMut<'a, T, usize, RStride>,
642	>
643	where
644		T: Send,
645		Rows: 'a,
646	{
647		use rayon::prelude::*;
648		unsafe {
649			self.as_type::<SyncCell<T>>()
650				.into_const()
651				.par_partition(count)
652				.map(|col| col.const_cast().as_type::<T>())
653		}
654	}
655
656	pub(crate) unsafe fn as_type<U>(self) -> ColMut<'a, U, Rows, RStride> {
657		ColMut::from_raw_parts_mut(
658			self.as_ptr_mut() as *mut U,
659			self.nrows(),
660			self.row_stride(),
661		)
662	}
663
664	#[inline]
665	/// see [`ColRef::as_diagonal`]
666	pub fn as_diagonal_mut(self) -> DiagMut<'a, T, Rows, RStride> {
667		DiagMut {
668			0: crate::diag::Mut { inner: self },
669		}
670	}
671
672	#[inline]
673	#[track_caller]
674	pub(crate) fn __at_mut(self, i: Idx<Rows>) -> &'a mut T {
675		self.at_mut(i)
676	}
677}
678impl<'a, T, Rows: Shape> ColMut<'a, T, Rows, ContiguousFwd> {
679	/// returns a reference over the elements as a slice
680	#[inline]
681	pub fn as_slice_mut(self) -> &'a mut [T] {
682		unsafe {
683			core::slice::from_raw_parts_mut(
684				self.as_ptr_mut(),
685				self.nrows().unbound(),
686			)
687		}
688	}
689}
690impl<'a, 'ROWS, T> ColMut<'a, T, Dim<'ROWS>, ContiguousFwd> {
691	/// returns a reference over the elements as a lifetime-bound slice
692	#[inline]
693	pub fn as_array_mut(self) -> &'a mut Array<'ROWS, T> {
694		unsafe {
695			&mut *(self.as_slice_mut() as *mut [_] as *mut Array<'ROWS, T>)
696		}
697	}
698}
699impl<'ROWS, 'a, T, RStride: Stride> ColMut<'a, T, Dim<'ROWS>, RStride> {
700	#[doc(hidden)]
701	#[inline]
702	pub fn split_rows_with<'TOP, 'BOT>(
703		self,
704		row: Partition<'TOP, 'BOT, 'ROWS>,
705	) -> (
706		ColRef<'a, T, Dim<'TOP>, RStride>,
707		ColRef<'a, T, Dim<'BOT>, RStride>,
708	) {
709		let (a, b) = self.split_at_row(row.midpoint());
710		(a.as_row_shape(row.head), b.as_row_shape(row.tail))
711	}
712}
713impl<'ROWS, 'a, T, RStride: Stride> ColMut<'a, T, Dim<'ROWS>, RStride> {
714	#[doc(hidden)]
715	#[inline]
716	pub fn split_rows_with_mut<'TOP, 'BOT>(
717		self,
718		row: Partition<'TOP, 'BOT, 'ROWS>,
719	) -> (
720		ColMut<'a, T, Dim<'TOP>, RStride>,
721		ColMut<'a, T, Dim<'BOT>, RStride>,
722	) {
723		let (a, b) = self.split_at_row_mut(row.midpoint());
724		(a.as_row_shape_mut(row.head), b.as_row_shape_mut(row.tail))
725	}
726}
727impl<T: core::fmt::Debug, Rows: Shape, RStride: Stride> core::fmt::Debug
728	for Mut<'_, T, Rows, RStride>
729{
730	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
731		self.rb().fmt(f)
732	}
733}
734impl<'a, T, Rows: Shape> ColMut<'a, T, Rows>
735where
736	T: RealField,
737{
738	/// Returns the maximum element in the column, or `None` if the column is
739	/// empty
740	pub fn max(&self) -> Option<T> {
741		self.rb().as_dyn_rows().as_dyn_stride().internal_max()
742	}
743
744	/// Returns the minimum element in the column, or `None` if the column is
745	/// empty
746	pub fn min(&self) -> Option<T> {
747		self.rb().as_dyn_rows().as_dyn_stride().internal_min()
748	}
749}
750#[cfg(test)]
751mod tests {
752	use crate::Col;
753	#[test]
754	fn test_col_min() {
755		let mut col: Col<f64> = Col::from_fn(5, |x| (x + 1) as f64);
756		let colmut = col.as_mut();
757		assert_eq!(colmut.min(), Some(1.0));
758		let mut empty: Col<f64> = Col::from_fn(0, |_| 0.0);
759		let emptymut = empty.as_mut();
760		assert_eq!(emptymut.min(), None);
761	}
762	#[test]
763	fn test_col_max() {
764		let mut col: Col<f64> = Col::from_fn(5, |x| (x + 1) as f64);
765		let colmut = col.as_mut();
766		assert_eq!(colmut.max(), Some(5.0));
767		let mut empty: Col<f64> = Col::from_fn(0, |_| 0.0);
768		let emptymut = empty.as_mut();
769		assert_eq!(emptymut.max(), None);
770	}
771}