Skip to main content

faer/col/
colref.rs

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