use alloc::vec::Vec;
use core::array;
use p3_field::PackedValue;
use p3_matrix::{Matrix, dense::RowMajorMatrix};
use p3_util::log2_strict_usize;
use serde::{Deserialize, Serialize};
#[inline]
pub fn log2_strict_u8(n: usize) -> u8 {
log2_strict_usize(n) as u8
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
pub struct RowList<T> {
elems: Vec<T>,
widths: Vec<usize>,
}
impl<T> RowList<T> {
pub fn new(elems: Vec<T>, widths: &[usize]) -> Self {
let expected: usize = widths.iter().sum();
assert_eq!(
elems.len(),
expected,
"RowList invariant violated: {} elems but widths sum to {}",
elems.len(),
expected,
);
Self {
elems,
widths: widths.to_vec(),
}
}
pub fn from_rows<R: AsRef<[T]>>(rows: impl IntoIterator<Item = R>) -> Self
where
T: Clone,
{
let mut elems = Vec::new();
let mut widths = Vec::new();
for row in rows {
let row = row.as_ref();
widths.push(row.len());
elems.extend_from_slice(row);
}
Self { elems, widths }
}
#[inline]
pub fn as_slice(&self) -> &[T] {
&self.elems
}
#[inline]
pub fn iter_values(&self) -> impl Iterator<Item = T> + '_
where
T: Copy,
{
self.elems.iter().copied()
}
#[inline]
pub fn num_rows(&self) -> usize {
self.widths.len()
}
pub fn iter_rows(&self) -> impl Iterator<Item = &[T]> {
let mut offset = 0;
self.widths.iter().map(move |&w| {
let row = &self.elems[offset..offset + w];
offset += w;
row
})
}
pub fn row(&self, idx: usize) -> &[T] {
let offset: usize = self.widths[..idx].iter().sum();
&self.elems[offset..offset + self.widths[idx]]
}
}
impl<T: Copy + Default> RowList<T> {
pub fn iter_aligned(&self, alignment: usize) -> impl Iterator<Item = T> + '_ {
self.iter_rows().flat_map(move |row| {
let padding = aligned_len(row.len(), alignment) - row.len();
row.iter()
.copied()
.chain(core::iter::repeat_n(T::default(), padding))
})
}
}
impl<T: Default + Clone> RowList<T> {
pub fn from_rows_aligned<R: AsRef<[T]>>(
rows: impl IntoIterator<Item = R>,
alignment: usize,
) -> Self {
let mut elems = Vec::new();
let mut widths = Vec::new();
for row in rows {
let row = row.as_ref();
let padded_len = aligned_len(row.len(), alignment);
widths.push(padded_len);
elems.extend_from_slice(row);
elems.resize(elems.len() + (padded_len - row.len()), T::default());
}
Self { elems, widths }
}
}
pub trait PackedValueExt: PackedValue {
#[inline]
#[must_use]
fn pack_columns<const N: usize>(rows: &[[Self::Value; N]]) -> [Self; N] {
assert_eq!(rows.len(), Self::WIDTH);
array::from_fn(|col| Self::from_fn(|lane| rows[lane][col]))
}
}
impl<T: PackedValue> PackedValueExt for T {}
#[inline]
pub const fn aligned_len(len: usize, alignment: usize) -> usize {
if alignment <= 1 {
len
} else {
len.next_multiple_of(alignment)
}
}
pub fn aligned_widths(mut widths: Vec<usize>, alignment: usize) -> Vec<usize> {
for w in &mut widths {
*w = aligned_len(*w, alignment);
}
widths
}
pub fn pad_row_to_alignment<F: Default>(mut row: Vec<F>, alignment: usize) -> Vec<F> {
debug_assert!(alignment > 0, "alignment must be non-zero");
let padded_len = aligned_len(row.len(), alignment);
row.resize_with(padded_len, || F::default());
row
}
pub fn upsample_matrix<F: Clone + Send + Sync>(
matrix: &impl Matrix<F>,
target_height: usize,
) -> RowMajorMatrix<F> {
let height = matrix.height();
assert!(target_height >= height);
assert!(height.is_power_of_two() && target_height.is_power_of_two());
let repeat_factor = target_height / height;
let width = matrix.width();
let mut values = Vec::with_capacity(target_height * width);
for row in matrix.rows() {
let row_vec: Vec<F> = row.collect();
for _ in 0..repeat_factor {
values.extend(row_vec.iter().cloned());
}
}
RowMajorMatrix::new(values, width)
}