diff --git a/lightmotif-bench/dna.rs b/lightmotif-bench/dna.rs index 66383e46791a78da59d4e7125e2b88dfadedab77..b09f0676c5eef1f21209f52ed600f931a024c166 100644 --- a/lightmotif-bench/dna.rs +++ b/lightmotif-bench/dna.rs @@ -6,6 +6,7 @@ extern crate test; use lightmotif::abc::Background; use lightmotif::abc::Dna; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U1; use lightmotif::num::U16; @@ -77,7 +78,10 @@ mod f32 { /// Bench how long `Pipeline::score` and `Pipeline::argmax` take for /// an arbitrary pipeline. - fn bench_lightmotif<C: StrictlyPositive, P: Score<f32, Dna, C> + Maximum<f32, C>>( + fn bench_lightmotif< + C: StrictlyPositive + ArrayLength, + P: Score<f32, Dna, C> + Maximum<f32, C>, + >( bencher: &mut test::Bencher, pli: &P, ) { @@ -148,7 +152,10 @@ mod u8 { /// Bench how long `Pipeline::score` and `Pipeline::argmax` take for /// an arbitrary pipeline using discrete scores. - fn bench_lightmotif_discrete<C: StrictlyPositive, P: Score<u8, Dna, C> + Maximum<u8, C>>( + fn bench_lightmotif_discrete< + C: StrictlyPositive + ArrayLength, + P: Score<u8, Dna, C> + Maximum<u8, C>, + >( bencher: &mut test::Bencher, pli: &P, ) { diff --git a/lightmotif-io/src/jaspar/parse.rs b/lightmotif-io/src/jaspar/parse.rs index 73cc1ddc42dd1565e2419cdf2c68b7e8014e20ac..00b1181916867bc6649817511c781f8179733aca 100644 --- a/lightmotif-io/src/jaspar/parse.rs +++ b/lightmotif-io/src/jaspar/parse.rs @@ -23,7 +23,6 @@ use lightmotif::abc::Alphabet; use lightmotif::abc::Dna; use lightmotif::abc::Nucleotide; use lightmotif::abc::Symbol; -use lightmotif::dense::DefaultAlignment; use lightmotif::dense::DenseMatrix; use lightmotif::err::InvalidData; use lightmotif::num::PowerOfTwo; @@ -64,10 +63,10 @@ pub fn matrix_column(input: &str) -> IResult<&str, Vec<u32>> { terminated(counts, line_ending)(input) } -pub fn build_matrix<B: Unsigned + PowerOfTwo>( +pub fn build_matrix( input: GenericArray<Vec<u32>, U4>, symbols: &[<Dna as Alphabet>::Symbol], -) -> Result<DenseMatrix<u32, <Dna as Alphabet>::K, B>, InvalidData> { +) -> Result<DenseMatrix<u32, <Dna as Alphabet>::K>, InvalidData> { let mut matrix = DenseMatrix::new(input[0].len()); for (counts, s) in input.as_slice().into_iter().zip(symbols) { // check that array length is consistent @@ -82,9 +81,7 @@ pub fn build_matrix<B: Unsigned + PowerOfTwo>( Ok(matrix) } -pub fn matrix<B: Unsigned + PowerOfTwo>( - input: &str, -) -> IResult<&str, DenseMatrix<u32, <Dna as Alphabet>::K, B>> { +pub fn matrix(input: &str) -> IResult<&str, DenseMatrix<u32, <Dna as Alphabet>::K>> { let (input, a) = matrix_column(input)?; let (input, c) = matrix_column(input)?; let (input, g) = matrix_column(input)?; @@ -119,7 +116,7 @@ pub fn header(input: &str) -> IResult<&str, (&str, Option<&str>)> { pub fn record(input: &str) -> IResult<&str, Record> { let (input, (id, description)) = header(input)?; - let (input, matrix) = map_res(matrix::<DefaultAlignment>, CountMatrix::new)(input)?; + let (input, matrix) = map_res(matrix, CountMatrix::new)(input)?; Ok(( input, @@ -147,7 +144,7 @@ mod tests { #[test] fn test_matrix() { - let (_rest, matrix) = super::matrix::<DefaultAlignment>(concat!( + let (_rest, matrix) = super::matrix(concat!( "10 12 4 1 2 2 0 0 0 8 13\n", " 2 2 7 1 0 8 0 0 1 2 2\n", " 3 1 1 0 23 0 26 26 0 0 4\n", diff --git a/lightmotif-io/src/jaspar16/parse.rs b/lightmotif-io/src/jaspar16/parse.rs index f9db9db3caa8a03d36e3c71881e74a2813fb6c0f..ffa5b2305e8390a0525ed5944bd6321932047c3e 100644 --- a/lightmotif-io/src/jaspar16/parse.rs +++ b/lightmotif-io/src/jaspar16/parse.rs @@ -4,9 +4,9 @@ use std::str::FromStr; use lightmotif::abc::Alphabet; use lightmotif::abc::Symbol; -use lightmotif::dense::DefaultAlignment; use lightmotif::dense::DenseMatrix; use lightmotif::err::InvalidData; +use lightmotif::num::ArrayLength; use lightmotif::num::PowerOfTwo; use lightmotif::num::Unsigned; use lightmotif::pwm::CountMatrix; @@ -48,9 +48,9 @@ pub fn matrix_column<A: Alphabet>(input: &str) -> IResult<&str, (A::Symbol, Vec< terminated(separated_pair(symbol::<A>, space1, counts), line_ending)(input) } -pub fn build_matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( +pub fn build_matrix<A: Alphabet>( input: Vec<(A::Symbol, Vec<u32>)>, -) -> Result<DenseMatrix<u32, A::K, B>, InvalidData> { +) -> Result<DenseMatrix<u32, A::K>, InvalidData> { let mut done = vec![false; A::K::USIZE]; let mut matrix = DenseMatrix::new(input[0].1.len()); @@ -73,10 +73,8 @@ pub fn build_matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( Ok(matrix) } -pub fn matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( - input: &str, -) -> IResult<&str, DenseMatrix<u32, A::K, B>> { - map_res(nom::multi::many1(matrix_column::<A>), build_matrix::<A, B>)(input) +pub fn matrix<A: Alphabet>(input: &str) -> IResult<&str, DenseMatrix<u32, A::K>> { + map_res(nom::multi::many1(matrix_column::<A>), build_matrix::<A>)(input) } pub fn header(input: &str) -> IResult<&str, (&str, Option<&str>)> { @@ -102,7 +100,7 @@ pub fn header(input: &str) -> IResult<&str, (&str, Option<&str>)> { pub fn record<A: Alphabet>(input: &str) -> IResult<&str, Record<A>> { let (input, (id, description)) = header(input)?; - let (input, matrix) = map_res(matrix::<A, DefaultAlignment>, CountMatrix::<A>::new)(input)?; + let (input, matrix) = map_res(matrix::<A>, CountMatrix::<A>::new)(input)?; Ok(( input, @@ -141,7 +139,7 @@ mod tests { #[test] fn test_matrix() { - let (_rest, matrix) = super::matrix::<Dna, DefaultAlignment>(concat!( + let (_rest, matrix) = super::matrix::<Dna>(concat!( "A [10 12 4 1 2 2 0 0 0 8 13 ]\n", "C [ 2 2 7 1 0 8 0 0 1 2 2 ]\n", "G [ 3 1 1 0 23 0 26 26 0 0 4 ]\n", diff --git a/lightmotif-io/src/transfac/parse.rs b/lightmotif-io/src/transfac/parse.rs index afb07dda4aff9dec72863487219d57b97df229ae..00e43bf021217702b59007a57f2c5ae0de6e9c05 100644 --- a/lightmotif-io/src/transfac/parse.rs +++ b/lightmotif-io/src/transfac/parse.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use nom::branch::alt; use nom::bytes::complete::tag; use nom::bytes::complete::take_till; diff --git a/lightmotif-io/src/uniprobe/mod.rs b/lightmotif-io/src/uniprobe/mod.rs index 7a0797c8180b132dbabc65f8c599b679b952a9e1..a823bc3f1577a68e36cee27645841a2a6b2cf5c0 100644 --- a/lightmotif-io/src/uniprobe/mod.rs +++ b/lightmotif-io/src/uniprobe/mod.rs @@ -16,7 +16,6 @@ use std::io::BufRead; use lightmotif::abc::Alphabet; -use lightmotif::dense::DefaultAlignment; use lightmotif::pwm::FrequencyMatrix; use crate::error::Error; @@ -123,7 +122,7 @@ impl<B: BufRead, A: Alphabet> Iterator for Reader<B, A> { } } - let matrix = match self::parse::build_matrix::<A, DefaultAlignment>(columns) { + let matrix = match self::parse::build_matrix::<A>(columns) { Err(e) => return Some(Err(Error::from(e))), Ok(matrix) => matrix, }; diff --git a/lightmotif-io/src/uniprobe/parse.rs b/lightmotif-io/src/uniprobe/parse.rs index 1a3257d201dfb62676a6b48d71831b134f109898..32d8d4446e5bad53587ef9c08b7a378e920d09e7 100644 --- a/lightmotif-io/src/uniprobe/parse.rs +++ b/lightmotif-io/src/uniprobe/parse.rs @@ -4,22 +4,21 @@ use std::str::FromStr; use lightmotif::abc::Alphabet; use lightmotif::abc::Symbol; -use lightmotif::dense::DefaultAlignment; use lightmotif::dense::DenseMatrix; use lightmotif::err::InvalidData; +use lightmotif::num::ArrayLength; use lightmotif::num::PowerOfTwo; use lightmotif::num::Unsigned; use lightmotif::pwm::FrequencyMatrix; use nom::bytes::complete::take_while; use nom::character::complete::anychar; use nom::character::complete::line_ending; -use nom::number::complete::float; - use nom::character::complete::not_line_ending; use nom::character::complete::tab; use nom::combinator::map; use nom::combinator::map_res; use nom::multi::many1; +use nom::number::complete::float; use nom::sequence::pair; use nom::sequence::preceded; use nom::sequence::separated_pair; @@ -45,9 +44,9 @@ pub fn matrix_column<A: Alphabet>(input: &str) -> IResult<&str, (A::Symbol, Vec< )(input) } -pub fn build_matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( +pub fn build_matrix<A: Alphabet>( input: Vec<(A::Symbol, Vec<f32>)>, -) -> Result<DenseMatrix<f32, A::K, B>, InvalidData> { +) -> Result<DenseMatrix<f32, A::K>, InvalidData> { let mut done = vec![false; A::K::USIZE]; let mut matrix = DenseMatrix::new(input[0].1.len()); @@ -70,10 +69,8 @@ pub fn build_matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( Ok(matrix) } -pub fn matrix<A: Alphabet, B: Unsigned + PowerOfTwo>( - input: &str, -) -> IResult<&str, DenseMatrix<f32, A::K, B>> { - map_res(nom::multi::many1(matrix_column::<A>), build_matrix::<A, B>)(input) +pub fn matrix<A: Alphabet>(input: &str) -> IResult<&str, DenseMatrix<f32, A::K>> { + map_res(nom::multi::many1(matrix_column::<A>), build_matrix::<A>)(input) } pub fn id(input: &str) -> IResult<&str, &str> { @@ -82,10 +79,7 @@ pub fn id(input: &str) -> IResult<&str, &str> { pub fn record<A: Alphabet>(input: &str) -> IResult<&str, (&str, FrequencyMatrix<A>)> { terminated( - pair( - id, - map_res(matrix::<A, DefaultAlignment>, FrequencyMatrix::<A>::new), - ), + pair(id, map_res(matrix::<A>, FrequencyMatrix::<A>::new)), line_ending, )(input) } @@ -107,7 +101,7 @@ mod tests { #[test] fn test_matrix() { - let (_rest, matrix) = super::matrix::<Dna, DefaultAlignment>(concat!( + let (_rest, matrix) = super::matrix::<Dna>(concat!( "A: 0.179 0.210 0.182\n", "C: 0.268 0.218 0.213\n", "G: 0.383 0.352 0.340\n", diff --git a/lightmotif-py/lightmotif/io.rs b/lightmotif-py/lightmotif/io.rs index af7b0d2532d265b0a2f677662db847b5ba3b39f3..fd32a8cb4fd12f1c4f7030007369b97e0af15203 100644 --- a/lightmotif-py/lightmotif/io.rs +++ b/lightmotif-py/lightmotif/io.rs @@ -10,7 +10,6 @@ use pyo3::exceptions::PyOSError; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::types::PyBytes; -use pyo3::types::PyString; use super::pyfile::PyFileRead; use super::CountMatrixData; diff --git a/lightmotif-py/lightmotif/lib.rs b/lightmotif-py/lightmotif/lib.rs index 36918f86e7cf6a406cad557fd43e9704cc4a4401..6eedc89a1f6305ae2bf55c999cdfd870e3bb4eae 100644 --- a/lightmotif-py/lightmotif/lib.rs +++ b/lightmotif-py/lightmotif/lib.rs @@ -6,11 +6,8 @@ extern crate lightmotif; extern crate lightmotif_tfmpvalue; extern crate pyo3; -use std::borrow::Borrow; use std::fmt::Display; use std::fmt::Formatter; -use std::pin::Pin; -use std::sync::Arc; use lightmotif::abc::Alphabet; use lightmotif::abc::Dna; diff --git a/lightmotif/benches/max.rs b/lightmotif/benches/max.rs index e419225094ae664a834c852cf33617bb43152ba3..d4bf19b39188d547fb119983dee332ce1acd8490 100644 --- a/lightmotif/benches/max.rs +++ b/lightmotif/benches/max.rs @@ -4,6 +4,7 @@ extern crate lightmotif; extern crate test; use lightmotif::abc::Dna; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U16; use lightmotif::num::U32; @@ -21,7 +22,7 @@ mod f32 { use super::*; - fn bench<C: StrictlyPositive, P: Score<f32, Dna, C> + Maximum<f32, C>>( + fn bench<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C> + Maximum<f32, C>>( bencher: &mut test::Bencher, pli: &P, ) { @@ -91,7 +92,7 @@ mod u8 { use super::*; - fn bench<C: StrictlyPositive, P: Score<u8, Dna, C> + Maximum<u8, C>>( + fn bench<C: StrictlyPositive + ArrayLength, P: Score<u8, Dna, C> + Maximum<u8, C>>( bencher: &mut test::Bencher, pli: &P, ) { diff --git a/lightmotif/benches/score.rs b/lightmotif/benches/score.rs index 4f0044005e2a3aa9d170ca364680482f237213ff..a0a03d540748610c196899a16e1cb20b275c212a 100644 --- a/lightmotif/benches/score.rs +++ b/lightmotif/benches/score.rs @@ -3,6 +3,7 @@ extern crate lightmotif; extern crate test; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U16; use lightmotif::num::U32; @@ -24,7 +25,10 @@ mod dna { mod f32 { use super::*; - fn bench<C: StrictlyPositive, P: Score<f32, Dna, C>>(bencher: &mut test::Bencher, pli: &P) { + fn bench<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C>>( + bencher: &mut test::Bencher, + pli: &P, + ) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -89,7 +93,10 @@ mod dna { mod u8 { use super::*; - fn bench<C: StrictlyPositive, P: Score<u8, Dna, C>>(bencher: &mut test::Bencher, pli: &P) { + fn bench<C: StrictlyPositive + ArrayLength, P: Score<u8, Dna, C>>( + bencher: &mut test::Bencher, + pli: &P, + ) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -163,7 +170,7 @@ mod protein { mod f32 { use super::*; - fn bench<C: StrictlyPositive, P: Score<f32, Protein, C>>( + fn bench<C: StrictlyPositive + ArrayLength, P: Score<f32, Protein, C>>( bencher: &mut test::Bencher, pli: &P, ) { diff --git a/lightmotif/benches/threshold.rs b/lightmotif/benches/threshold.rs index a4783011c08fe5598b6816e7172a03cca4466b4b..7dcd6011f9624c516238c0a2f397bcfaefdcfb5d 100644 --- a/lightmotif/benches/threshold.rs +++ b/lightmotif/benches/threshold.rs @@ -4,6 +4,7 @@ extern crate lightmotif; extern crate test; use lightmotif::abc::Dna; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U16; use lightmotif::num::U32; @@ -21,7 +22,7 @@ mod f32 { use super::*; - fn bench<C: StrictlyPositive, P: Score<f32, Dna, C> + Threshold<f32, C>>( + fn bench<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C> + Threshold<f32, C>>( bencher: &mut test::Bencher, pli: &P, ) { @@ -91,7 +92,7 @@ mod u8 { use super::*; - fn bench<C: StrictlyPositive, P: Score<u8, Dna, C> + Threshold<u8, C>>( + fn bench<C: StrictlyPositive + ArrayLength, P: Score<u8, Dna, C> + Threshold<u8, C>>( bencher: &mut test::Bencher, pli: &P, ) { diff --git a/lightmotif/src/dense.rs b/lightmotif/src/dense.rs index 351a371d1f230903ae6ed397aa1f1581c108a59e..481f67c61a61d78b8bf2935600a1a38c818df2bf 100644 --- a/lightmotif/src/dense.rs +++ b/lightmotif/src/dense.rs @@ -7,27 +7,8 @@ use std::iter::FusedIterator; use std::ops::Index; use std::ops::IndexMut; use std::ops::Range; -use std::ptr::NonNull; -use crate::num::PowerOfTwo; -use crate::num::Unsigned; - -// --- DefaultAlignment -------------------------------------------------------- - -#[cfg(target_arch = "x86_64")] -type _DefaultAlignment = typenum::consts::U32; -#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "aarch64"))] -type _DefaultAlignment = typenum::consts::U16; -#[cfg(not(any( - target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm", - target_arch = "aarch64" -)))] -type _DefaultAlignment = typenum::consts::U1; - -/// The default alignment used in dense matrices. -pub type DefaultAlignment = _DefaultAlignment; +use crate::num::ArrayLength; // --- MatrixElement ----------------------------------------------------------- @@ -53,50 +34,34 @@ impl MatrixCoordinates { // --- DenseMatrix ------------------------------------------------------------- +#[cfg_attr(target_arch = "x86_64", repr(align(32)))] +#[cfg_attr(not(target_arch = "x86_64"), repr(align(16)))] +#[derive(Debug, Default, Clone, PartialEq, Eq)] +struct Row<T: MatrixElement, C: ArrayLength> { + a: generic_array::GenericArray<T, C>, +} + /// A memory-aligned dense matrix with a constant number of columns. -#[derive(Eq)] -pub struct DenseMatrix<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo = DefaultAlignment> { - data: Vec<T>, - offset: usize, +#[derive(Clone, Eq)] +pub struct DenseMatrix<T: MatrixElement, C: ArrayLength> { + data: Vec<Row<T, C>>, rows: usize, - _columns: std::marker::PhantomData<C>, - _alignment: std::marker::PhantomData<A>, } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> DenseMatrix<T, C, A> { +impl<T: MatrixElement, C: ArrayLength> DenseMatrix<T, C> { /// Create a new matrix with the given number of rows. pub fn new(rows: usize) -> Self { let data = Vec::new(); - let mut matrix = Self { - data, - offset: 0, - rows: 0, - _columns: std::marker::PhantomData, - _alignment: std::marker::PhantomData, - }; + let mut matrix = Self { data, rows: 0 }; matrix.resize(rows); matrix } /// Create a new *uninitialized* matrix with the given number of rows. pub unsafe fn uninitialized(rows: usize) -> Self { - // Always over-allocate columns to avoid alignment issues. let mut m = Self::new(0); - let c = m.stride(); - - // NOTE: this is unsafe but given that we require `T` to be - // copy, this should be fine, as `Copy` prevents the - // type to be `Drop` as well. - // reserve the vector without initializing the data - m.data.reserve((rows + 1) * c); - m.data.set_len((rows + 1) * c); - - // compute offset to aligned memory - m.offset = 0; - while m.data[m.offset..].as_ptr() as usize & (A::USIZE - 1) > 0 { - m.offset += 1 - } - + m.data.reserve(rows); + m.data.set_len(rows); m.rows = rows; m } @@ -137,17 +102,14 @@ impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> DenseMatrix<T, C, /// /// # Example /// ```rust - /// # use typenum::{U43, U32}; + /// # use lightmotif::num::U43; /// # use lightmotif::dense::DenseMatrix; - /// let d = DenseMatrix::<u8, U43, U32>::new(0); + /// let d = DenseMatrix::<u8, U43>::new(0); /// assert_eq!(d.stride(), 64); /// ``` #[inline] pub const fn stride(&self) -> usize { - let x = std::mem::size_of::<T>(); - let c = C::USIZE * x; - let b = c + (A::USIZE - c % A::USIZE) * ((c % A::USIZE) > 0) as usize; - b / x + ((b % x) > 0) as usize + std::mem::size_of::<Row<T, C>>() / std::mem::size_of::<T>() } /// The number of rows of the matrix. @@ -157,151 +119,88 @@ impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> DenseMatrix<T, C, } /// Change the number of rows of the matrix. + #[inline] pub fn resize(&mut self, rows: usize) { - // Always over-allocate columns to avoid alignment issues. - let c: usize = self.stride(); - - // Cache previous dimensions - let previous_rows = self.rows; - let previous_offset = self.offset; - - // Only reallocate if needed - if previous_rows > rows { - // Truncate rows - self.data.truncate((rows + 1) * c); - } else if previous_rows < rows { - // Allocate data block - self.data.resize_with((rows + 1) * c, T::default); - // Compute offset to aligned memory - self.offset = 0; - while self.data[self.offset..].as_ptr() as usize & (A::USIZE - 1) > 0 { - self.offset += 1 - } - // Copy data in case alignment offset changed - if previous_offset != self.offset { - self.data.as_mut_slice().copy_within( - previous_offset..previous_offset + (previous_rows * c), - self.offset, - ); - } - } - - // Update row count + self.data.resize_with(rows, Default::default); self.rows = rows; } /// Iterate over the rows of the matrix. #[inline] - pub fn iter(&self) -> Iter<'_, T, C, A> { + pub fn iter(&self) -> Iter<'_, T, C> { Iter::new(self) } - /// Returns an iterator that allows modifying each row. + /// Returns an it,erator that allows modifying each row. #[inline] - pub fn iter_mut(&mut self) -> IterMut<'_, T, C, A> { + pub fn iter_mut(&mut self) -> IterMut<'_, T, C> { IterMut::new(self) } /// Fill the entire matrix with a constant value. #[inline] pub fn fill(&mut self, value: T) { - self.data.fill(value); + for row in self.data.iter_mut() { + row.a.fill(value) + } } } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> AsRef<DenseMatrix<T, C, A>> - for DenseMatrix<T, C, A> -{ - fn as_ref(&self) -> &DenseMatrix<T, C, A> { +impl<T: MatrixElement, C: ArrayLength> AsRef<DenseMatrix<T, C>> for DenseMatrix<T, C> { + #[inline] + fn as_ref(&self) -> &DenseMatrix<T, C> { self } } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> Clone for DenseMatrix<T, C, A> { - fn clone(&self) -> Self { - let mut clone = unsafe { Self::uninitialized(self.rows) }; - let l = self.rows() * self.stride(); - clone.data[clone.offset..clone.offset + l] - .copy_from_slice(&self.data[self.offset..self.offset + l]); - clone - } -} - -impl<T: MatrixElement + Debug, C: Unsigned, A: Unsigned + PowerOfTwo> Debug - for DenseMatrix<T, C, A> -{ +impl<T: MatrixElement + Debug, C: ArrayLength> Debug for DenseMatrix<T, C> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { f.debug_list().entries(self.iter()).finish() } } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> Index<usize> - for DenseMatrix<T, C, A> -{ +impl<T: MatrixElement, C: ArrayLength> Index<usize> for DenseMatrix<T, C> { type Output = [T]; #[inline] fn index(&self, index: usize) -> &Self::Output { - let c = self.stride(); - let row = self.offset + c * index; - debug_assert!(row + C::USIZE <= self.data.len()); - let row = &self.data[row..row + C::USIZE]; - debug_assert_eq!(row.as_ptr() as usize & (A::USIZE - 1), 0); - row + self.data[index].a.as_slice() } } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> IndexMut<usize> - for DenseMatrix<T, C, A> -{ +impl<T: MatrixElement, C: ArrayLength> IndexMut<usize> for DenseMatrix<T, C> { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { - let c = self.stride(); - let row = self.offset + c * index; - debug_assert!(row + C::USIZE <= self.data.len()); - let row = &mut self.data[row..row + C::USIZE]; - debug_assert_eq!(row.as_ptr() as usize & (A::USIZE - 1), 0); - row + self.data[index].a.as_mut_slice() } } -impl<T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> Index<MatrixCoordinates> - for DenseMatrix<T, C, A> -{ +impl<T: MatrixElement, C: ArrayLength> Index<MatrixCoordinates> for DenseMatrix<T, C> { type Output = T; #[inline] fn index(&self, index: MatrixCoordinates) -> &Self::Output { - let c = self.stride(); - let i = self.offset + c * index.row + index.col; - debug_assert!(i < self.data.len()); - &self.data[i] + &self.data[index.row].a[index.col] } } -impl<'a, T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> IntoIterator - for &'a DenseMatrix<T, C, A> -{ +impl<'a, T: MatrixElement, C: ArrayLength> IntoIterator for &'a DenseMatrix<T, C> { type Item = &'a [T]; - type IntoIter = Iter<'a, T, C, A>; + type IntoIter = Iter<'a, T, C>; #[inline] fn into_iter(self) -> Self::IntoIter { Iter::new(self) } } -impl<'a, T: MatrixElement, C: Unsigned, A: Unsigned + PowerOfTwo> IntoIterator - for &'a mut DenseMatrix<T, C, A> -{ +impl<'a, T: MatrixElement, C: ArrayLength> IntoIterator for &'a mut DenseMatrix<T, C> { type Item = &'a mut [T]; - type IntoIter = IterMut<'a, T, C, A>; + type IntoIter = IterMut<'a, T, C>; #[inline] fn into_iter(self) -> Self::IntoIter { IterMut::new(self) } } -impl<'a, T: MatrixElement + PartialEq, C: Unsigned, A: Unsigned + PowerOfTwo> PartialEq - for DenseMatrix<T, C, A> -{ +impl<'a, T: MatrixElement + PartialEq, C: ArrayLength> PartialEq for DenseMatrix<T, C> { fn eq(&self, other: &Self) -> bool { if self.rows() != other.rows() { return false; @@ -325,75 +224,57 @@ impl<'a, T: MatrixElement + PartialEq, C: Unsigned, A: Unsigned + PowerOfTwo> Pa // --- Iter -------------------------------------------------------------------- -pub struct Iter<'a, T, C, A> +pub struct Iter<'a, T, C> where T: 'a + MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { - matrix: &'a DenseMatrix<T, C, A>, + matrix: &'a DenseMatrix<T, C>, indices: Range<usize>, - data: std::ptr::NonNull<T>, } -impl<'a, T, C, A> Iter<'a, T, C, A> +impl<'a, T, C> Iter<'a, T, C> where T: 'a + MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { - fn new(matrix: &'a DenseMatrix<T, C, A>) -> Self { + #[inline] + fn new(matrix: &'a DenseMatrix<T, C>) -> Self { let indices = 0..matrix.rows(); - let data = unsafe { NonNull::new_unchecked(matrix.data.as_ptr() as *mut T) }; - Self { - indices, - matrix, - data, - } + Self { indices, matrix } } #[inline] fn get(&mut self, i: usize) -> &'a [T] { - let c = self.matrix.stride(); - let row = self.matrix.offset + c * i; - unsafe { std::slice::from_raw_parts(self.data.as_ptr().add(row), C::USIZE) } + self.matrix.data[i].a.as_slice() } } // --- IterMut ----------------------------------------------------------------- -pub struct IterMut<'a, T, C, A> +pub struct IterMut<'a, T, C> where T: 'a + MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { - matrix: &'a mut DenseMatrix<T, C, A>, + matrix: &'a mut DenseMatrix<T, C>, indices: Range<usize>, - data: std::ptr::NonNull<T>, } -impl<'a, T, C, A> IterMut<'a, T, C, A> +impl<'a, T, C> IterMut<'a, T, C> where T: 'a + MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { - fn new(matrix: &'a mut DenseMatrix<T, C, A>) -> Self { + #[inline] + fn new(matrix: &'a mut DenseMatrix<T, C>) -> Self { let indices = 0..matrix.rows(); - let data = unsafe { NonNull::new_unchecked(matrix.data.as_mut_ptr()) }; - Self { - indices, - data, - matrix, - } + Self { indices, matrix } } #[inline] fn get(&mut self, i: usize) -> &'a mut [T] { - let c = self.matrix.stride(); - let row = self.matrix.offset + c * i; - unsafe { std::slice::from_raw_parts_mut(self.data.as_ptr().add(row), C::USIZE) } + unsafe { std::slice::from_raw_parts_mut(self.matrix.data[i].a.as_mut_ptr(), C::USIZE) } } } @@ -401,23 +282,22 @@ where macro_rules! iterator { ($t:ident, $T:ident, $($item:tt)*) => { - impl<'a, $T, C, A> Iterator for $t<'a, $T, C, A> + impl<'a, $T, C> Iterator for $t<'a, $T, C> where $T: MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { type Item = &'a $($item)*; + #[inline] fn next(&mut self) -> Option<Self::Item> { self.indices.next().map(|i| self.get(i)) } } - impl<'a, $T, C, A> ExactSizeIterator for $t<'a, $T, C, A> + impl<'a, $T, C> ExactSizeIterator for $t<'a, $T, C> where $T: MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { #[inline] fn len(&self) -> usize { @@ -425,19 +305,18 @@ macro_rules! iterator { } } - impl<'a, $T, C, A> FusedIterator for $t<'a, $T, C, A> + impl<'a, $T, C> FusedIterator for $t<'a, $T, C> where $T: MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, {} - impl<'a, $T, C, A> DoubleEndedIterator for $t<'a, $T, C, A> + impl<'a, $T, C> DoubleEndedIterator for $t<'a, $T, C> where $T: MatrixElement, - C: Unsigned, - A: Unsigned + PowerOfTwo, + C: ArrayLength, { + #[inline] fn next_back(&mut self) -> Option<Self::Item> { self.indices.next_back().map(|i| self.get(i)) } @@ -450,36 +329,32 @@ iterator!(IterMut, T, mut [T]); #[cfg(test)] mod test { - use typenum::consts::U15; use typenum::consts::U16; - use typenum::consts::U3; use typenum::consts::U32; + use typenum::consts::U33; use typenum::consts::U8; use super::*; #[test] fn stride() { - let d1 = DenseMatrix::<u8, U32, U32>::new(0); + let d1 = DenseMatrix::<u8, U32>::new(0); assert_eq!(d1.stride(), 32); - let d2 = DenseMatrix::<u8, U16, U32>::new(0); + let d2 = DenseMatrix::<u8, U16>::new(0); assert_eq!(d2.stride(), 32); - let d3 = DenseMatrix::<u32, U32, U32>::new(0); + let d3 = DenseMatrix::<u32, U32>::new(0); assert_eq!(d3.stride(), 32); - let d4 = DenseMatrix::<u32, U8, U32>::new(0); + let d4 = DenseMatrix::<u32, U8>::new(0); assert_eq!(d4.stride(), 8); - let d5 = DenseMatrix::<u32, U16, U32>::new(0); + let d5 = DenseMatrix::<u32, U16>::new(0); assert_eq!(d5.stride(), 16); - let d6 = DenseMatrix::<u32, U3, U16>::new(0); - assert_eq!(d6.stride(), 4); - - let d7 = DenseMatrix::<u8, U15, U8>::new(0); - assert_eq!(d7.stride(), 16); + let d7 = DenseMatrix::<u8, U33>::new(0); + assert_eq!(d7.stride(), 64); } #[test] diff --git a/lightmotif/src/num.rs b/lightmotif/src/num.rs index 851846f745085b44fadde6393d04b941e9436337..dd76631d52a9d109596482fd64d732b012416852 100644 --- a/lightmotif/src/num.rs +++ b/lightmotif/src/num.rs @@ -3,6 +3,8 @@ use std::ops::Div; use std::ops::Rem; +#[doc(no_inline)] +pub use generic_array::ArrayLength; #[doc(no_inline)] pub use typenum::*; diff --git a/lightmotif/src/pli/mod.rs b/lightmotif/src/pli/mod.rs index f594b9188880f4ed83e2a30a5e21eb1d425235bd..f10c8292f240b5ceb2a242fac5f6a4b7e5b41ba3 100644 --- a/lightmotif/src/pli/mod.rs +++ b/lightmotif/src/pli/mod.rs @@ -69,7 +69,7 @@ pub trait Encode<A: Alphabet> { } /// Used computing sequence scores with a PSSM. -pub trait Score<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive> { +pub trait Score<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive + ArrayLength> { /// Compute the PSSM scores into the given striped score matrix. fn score_rows_into<S, M>( &self, @@ -132,7 +132,7 @@ pub trait Score<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive> } /// Used for finding the highest scoring site in a striped score matrix. -pub trait Maximum<T: MatrixElement + PartialOrd, C: StrictlyPositive> { +pub trait Maximum<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> { /// Find the matrix coordinates with the highest score. fn argmax(&self, scores: &StripedScores<T, C>) -> Option<MatrixCoordinates> { if scores.is_empty() { @@ -163,7 +163,7 @@ pub trait Maximum<T: MatrixElement + PartialOrd, C: StrictlyPositive> { } /// Used for converting an encoded sequence into a striped sequence. -pub trait Stripe<A: Alphabet, C: StrictlyPositive> { +pub trait Stripe<A: Alphabet, C: StrictlyPositive + ArrayLength> { /// Stripe a sequence into a striped, column-major order matrix. fn stripe<S: AsRef<[A::Symbol]>>(&self, seq: S) -> StripedSequence<A, C> { let s = seq.as_ref(); @@ -199,7 +199,7 @@ pub trait Stripe<A: Alphabet, C: StrictlyPositive> { } /// Used for finding positions above a score threshold in a striped score matrix. -pub trait Threshold<T: MatrixElement + PartialOrd, C: StrictlyPositive> { +pub trait Threshold<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> { /// Return the coordinates of positions with score equal to or greater than the threshold. /// /// # Note @@ -242,19 +242,19 @@ impl<A: Alphabet> Pipeline<A, Generic> { impl<A: Alphabet> Encode<A> for Pipeline<A, Generic> {} -impl<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive> Score<T, A, C> +impl<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive + ArrayLength> Score<T, A, C> for Pipeline<A, Generic> { } -impl<T: MatrixElement + PartialOrd, A: Alphabet, C: StrictlyPositive> Maximum<T, C> +impl<T: MatrixElement + PartialOrd, A: Alphabet, C: StrictlyPositive + ArrayLength> Maximum<T, C> for Pipeline<A, Generic> { } -impl<A: Alphabet, C: StrictlyPositive> Stripe<A, C> for Pipeline<A, Generic> {} +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> Stripe<A, C> for Pipeline<A, Generic> {} -impl<T: MatrixElement + PartialOrd, A: Alphabet, C: StrictlyPositive> Threshold<T, C> +impl<T: MatrixElement + PartialOrd, A: Alphabet, C: StrictlyPositive + ArrayLength> Threshold<T, C> for Pipeline<A, Generic> { } @@ -336,7 +336,7 @@ impl<A: Alphabet> Encode<A> for Pipeline<A, Sse2> { impl<A, C> Score<f32, A, C> for Pipeline<A, Sse2> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { #[inline] fn score_rows_into<S, M>( @@ -356,7 +356,7 @@ where impl<A, C> Score<u8, A, C> for Pipeline<A, Sse2> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } @@ -374,21 +374,21 @@ where impl<A, C> Maximum<u8, C> for Pipeline<A, Sse2> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } impl<A, C> Threshold<f32, C> for Pipeline<A, Sse2> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } impl<A, C> Threshold<u8, C> for Pipeline<A, Sse2> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } @@ -538,7 +538,7 @@ impl<A: Alphabet> Encode<A> for Pipeline<A, Neon> { impl<A, C> Score<f32, A, C> for Pipeline<A, Neon> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { #[inline] fn score_rows_into<S, M>( @@ -557,7 +557,7 @@ where impl<C> Score<u8, Dna, C> for Pipeline<Dna, Neon> where - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { #[inline] fn score_rows_into<S, M>( @@ -577,28 +577,28 @@ where impl<A, C> Maximum<f32, C> for Pipeline<A, Neon> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } impl<A, C> Maximum<u8, C> for Pipeline<A, Neon> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } impl<A, C> Threshold<f32, C> for Pipeline<A, Neon> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } impl<A, C> Threshold<u8, C> for Pipeline<A, Neon> where A: Alphabet, - C: StrictlyPositive + MultipleOf<U16>, + C: StrictlyPositive + MultipleOf<U16> + ArrayLength, { } diff --git a/lightmotif/src/pli/platform/generic.rs b/lightmotif/src/pli/platform/generic.rs index 365374d8d7f89e176801cf523294cd5a3b401405..faf731e4ce38a03f038d1b8b12b6b2fdca4f8ab9 100644 --- a/lightmotif/src/pli/platform/generic.rs +++ b/lightmotif/src/pli/platform/generic.rs @@ -1,5 +1,7 @@ use std::ops::AddAssign; +use generic_array::ArrayLength; + use crate::abc::Alphabet; use crate::dense::MatrixElement; use crate::num::StrictlyPositive; @@ -22,10 +24,13 @@ impl Backend for Generic { impl<A: Alphabet> Encode<A> for Generic {} -impl<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive> Score<T, A, C> for Generic {} +impl<T: MatrixElement + AddAssign, A: Alphabet, C: StrictlyPositive + ArrayLength> Score<T, A, C> + for Generic +{ +} -impl<T: MatrixElement + PartialOrd, C: StrictlyPositive> Maximum<T, C> for Generic {} +impl<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> Maximum<T, C> for Generic {} -impl<A: Alphabet, C: StrictlyPositive> Stripe<A, C> for Generic {} +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> Stripe<A, C> for Generic {} -impl<T: MatrixElement + PartialOrd, C: StrictlyPositive> Threshold<T, C> for Generic {} +impl<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> Threshold<T, C> for Generic {} diff --git a/lightmotif/src/pli/platform/neon.rs b/lightmotif/src/pli/platform/neon.rs index 0a1c9a35407c93c87296d59e3a77b95d580e8394..2bddb8a5bb78a6fa08b8ea54ad1574349fc130d5 100644 --- a/lightmotif/src/pli/platform/neon.rs +++ b/lightmotif/src/pli/platform/neon.rs @@ -9,6 +9,8 @@ use std::ops::Mul; use std::ops::Range; use std::ops::Rem; +use generic_array::ArrayLength; + use super::Backend; use crate::abc::Alphabet; use crate::abc::Symbol; @@ -125,7 +127,7 @@ where #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] #[target_feature(enable = "neon")] -unsafe fn score_f32_neon<A: Alphabet, C: MultipleOf<U16>>( +unsafe fn score_f32_neon<A: Alphabet, C: MultipleOf<U16> + ArrayLength>( pssm: &DenseMatrix<f32, A::K>, seq: &StripedSequence<A, C>, rows: Range<usize>, @@ -185,7 +187,7 @@ unsafe fn score_f32_neon<A: Alphabet, C: MultipleOf<U16>>( #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] #[target_feature(enable = "neon")] -unsafe fn score_u8_neon<A: Alphabet, C: MultipleOf<U16>>( +unsafe fn score_u8_neon<A: Alphabet, C: MultipleOf<U16> + ArrayLength>( pssm: &DenseMatrix<u8, A::K>, seq: &StripedSequence<A, C>, rows: Range<usize>, @@ -248,7 +250,7 @@ impl Neon { scores: &mut StripedScores<f32, C>, ) where A: Alphabet, - C: MultipleOf<U16>, + C: MultipleOf<U16> + ArrayLength, S: AsRef<StripedSequence<A, C>>, M: AsRef<DenseMatrix<f32, A::K>>, { @@ -286,7 +288,7 @@ impl Neon { <A as Alphabet>::K: IsLessOrEqual<U16>, <<A as Alphabet>::K as IsLessOrEqual<U16>>::Output: NonZero, A: Alphabet, - C: MultipleOf<U16>, + C: MultipleOf<U16> + ArrayLength, S: AsRef<StripedSequence<A, C>>, M: AsRef<DenseMatrix<u8, A::K>>, { diff --git a/lightmotif/src/pli/platform/sse2.rs b/lightmotif/src/pli/platform/sse2.rs index 0c614ec2ae5284445e55aab398e4485e0c418707..fad275f83dfc7155a089b1f9c18a76c35b08abef 100644 --- a/lightmotif/src/pli/platform/sse2.rs +++ b/lightmotif/src/pli/platform/sse2.rs @@ -104,7 +104,7 @@ where #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[target_feature(enable = "sse2")] -unsafe fn score_sse2<A: Alphabet, C: MultipleOf<<Sse2 as Backend>::LANES>>( +unsafe fn score_sse2<A: Alphabet, C: MultipleOf<<Sse2 as Backend>::LANES> + ArrayLength>( pssm: &DenseMatrix<f32, A::K>, seq: &StripedSequence<A, C>, rows: Range<usize>, @@ -278,7 +278,7 @@ impl Sse2 { scores: &mut StripedScores<f32, C>, ) where A: Alphabet, - C: MultipleOf<<Sse2 as Backend>::LANES>, + C: MultipleOf<<Sse2 as Backend>::LANES> + ArrayLength, S: AsRef<StripedSequence<A, C>>, M: AsRef<DenseMatrix<f32, A::K>>, { diff --git a/lightmotif/src/pwm.rs b/lightmotif/src/pwm.rs index 5550d02c507a8157a7e86ffdeaa93de05026797f..432225b60f68a43e02b23c9d0502dbd610c70f66 100644 --- a/lightmotif/src/pwm.rs +++ b/lightmotif/src/pwm.rs @@ -2,8 +2,6 @@ use std::ops::Index; -use typenum::marker_traits::Unsigned; - use crate::abc::Alphabet; use crate::abc::Background; use crate::abc::ComplementableAlphabet; @@ -11,7 +9,9 @@ use crate::abc::Pseudocounts; use crate::abc::Symbol; use crate::dense::DenseMatrix; use crate::err::InvalidData; +use crate::num::ArrayLength; use crate::num::StrictlyPositive; +use crate::num::Unsigned; use crate::pli::dispatch::Dispatch; use crate::pli::Pipeline; use crate::pli::Score; @@ -481,7 +481,7 @@ impl<A: Alphabet> ScoringMatrix<A> { /// Uses platform-accelerated implementation when available. pub fn score<S, C>(&self, seq: S) -> StripedScores<f32, C> where - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, S: AsRef<StripedSequence<A, C>>, Pipeline<A, Dispatch>: Score<f32, A, C>, { @@ -492,7 +492,7 @@ impl<A: Alphabet> ScoringMatrix<A> { /// Compute the score for a single sequence position. pub fn score_position<S, C>(&self, seq: S, pos: usize) -> f32 where - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, S: AsRef<StripedSequence<A, C>>, { let mut score = 0.0; @@ -588,7 +588,7 @@ impl<A: Alphabet> DiscreteMatrix<A> { /// Compute the score for a single sequence position. pub fn score_position<S, C>(&self, seq: S, pos: usize) -> u8 where - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, S: AsRef<StripedSequence<A, C>>, { let mut score = 0; diff --git a/lightmotif/src/scan.rs b/lightmotif/src/scan.rs index d9adc162f68d916a034ac1a1578c4aff68f60732..41235266ca00cc3fb594cc69a2309ec0f5c4d831 100644 --- a/lightmotif/src/scan.rs +++ b/lightmotif/src/scan.rs @@ -5,6 +5,7 @@ use super::abc::Alphabet; use super::pli::dispatch::Dispatch; use super::pwm::ScoringMatrix; use super::seq::StripedSequence; +use crate::num::ArrayLength; use crate::num::StrictlyPositive; use crate::pli::Maximum; use crate::pli::Pipeline; @@ -98,7 +99,7 @@ pub struct Scanner< A: Alphabet, M: AsRef<ScoringMatrix<A>>, S: AsRef<StripedSequence<A, C>>, - C: StrictlyPositive = DefaultColumns, + C: StrictlyPositive + ArrayLength = DefaultColumns, > { pssm: M, dm: DiscreteMatrix<A>, @@ -115,7 +116,7 @@ pub struct Scanner< impl<'a, A, M, S, C> Scanner<'a, A, M, S, C> where A: Alphabet, - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, M: AsRef<ScoringMatrix<A>>, S: AsRef<StripedSequence<A, C>>, { @@ -157,7 +158,7 @@ where impl<'a, A, M, S, C> Iterator for Scanner<'a, A, M, S, C> where A: Alphabet, - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, M: AsRef<ScoringMatrix<A>>, S: AsRef<StripedSequence<A, C>>, Pipeline<A, Dispatch>: Score<u8, A, C> + Threshold<u8, C> + Maximum<u8, C>, @@ -255,7 +256,7 @@ mod test { const SEQUENCE: &str = "ATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCG"; const PATTERNS: &[&str] = &["GTTGACCTTATCAAC", "GTTGATCCAGTCAAC"]; - fn seq<C: StrictlyPositive>() -> StripedSequence<Dna, C> { + fn seq<C: StrictlyPositive + ArrayLength>() -> StripedSequence<Dna, C> { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); Pipeline::generic().stripe(encoded) } diff --git a/lightmotif/src/scores.rs b/lightmotif/src/scores.rs index 380d7d2b93b361230b48d095d123a2f44bff81c9..8c96d8664d5abf2393f33da3223e2ececdf7d4b8 100644 --- a/lightmotif/src/scores.rs +++ b/lightmotif/src/scores.rs @@ -10,6 +10,7 @@ use crate::dense::DenseMatrix; use crate::dense::MatrixCoordinates; use crate::dense::MatrixElement; use crate::err::InvalidData; +use crate::num::ArrayLength; use crate::num::StrictlyPositive; use crate::pli::dispatch::Dispatch; use crate::pli::Maximum; @@ -86,14 +87,14 @@ impl<T> From<Scores<T>> for Vec<T> { /// Striped matrix storing scores for an equally striped sequence. #[derive(Clone, Debug)] -pub struct StripedScores<T: MatrixElement, C: StrictlyPositive> { +pub struct StripedScores<T: MatrixElement, C: StrictlyPositive + ArrayLength> { /// The raw data matrix storing the scores. data: DenseMatrix<T, C>, /// The total length of the `StripedSequence` these scores were obtained from. max_index: usize, } -impl<T: MatrixElement, C: StrictlyPositive> StripedScores<T, C> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> StripedScores<T, C> { /// Create a new striped score matrix with the given length and data. fn new(data: DenseMatrix<T, C>, max_index: usize) -> Result<Self, InvalidData> { Ok(Self { data, max_index }) @@ -149,7 +150,7 @@ impl<T: MatrixElement, C: StrictlyPositive> StripedScores<T, C> { } } -impl<T: MatrixElement + PartialOrd, C: StrictlyPositive> StripedScores<T, C> +impl<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> StripedScores<T, C> where Pipeline<Dna, Dispatch>: Maximum<T, C>, { @@ -170,7 +171,7 @@ where } } -impl<T: MatrixElement + PartialOrd, C: StrictlyPositive> StripedScores<T, C> +impl<T: MatrixElement + PartialOrd, C: StrictlyPositive + ArrayLength> StripedScores<T, C> where Pipeline<Dna, Dispatch>: Threshold<T, C>, { @@ -191,25 +192,29 @@ where } } -impl<T: MatrixElement, C: StrictlyPositive> AsRef<DenseMatrix<T, C>> for StripedScores<T, C> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> AsRef<DenseMatrix<T, C>> + for StripedScores<T, C> +{ fn as_ref(&self) -> &DenseMatrix<T, C> { self.matrix() } } -impl<T: MatrixElement, C: StrictlyPositive> AsMut<DenseMatrix<T, C>> for StripedScores<T, C> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> AsMut<DenseMatrix<T, C>> + for StripedScores<T, C> +{ fn as_mut(&mut self) -> &mut DenseMatrix<T, C> { self.matrix_mut() } } -impl<T: MatrixElement, C: StrictlyPositive> Default for StripedScores<T, C> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> Default for StripedScores<T, C> { fn default() -> Self { StripedScores::empty() } } -impl<T: MatrixElement, C: StrictlyPositive> Index<usize> for StripedScores<T, C> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> Index<usize> for StripedScores<T, C> { type Output = T; #[inline] fn index(&self, index: usize) -> &T { @@ -219,7 +224,7 @@ impl<T: MatrixElement, C: StrictlyPositive> Index<usize> for StripedScores<T, C> } } -impl<T: MatrixElement, C: StrictlyPositive> From<StripedScores<T, C>> for Vec<T> { +impl<T: MatrixElement, C: StrictlyPositive + ArrayLength> From<StripedScores<T, C>> for Vec<T> { fn from(scores: StripedScores<T, C>) -> Self { scores.iter().cloned().collect() } @@ -227,12 +232,12 @@ impl<T: MatrixElement, C: StrictlyPositive> From<StripedScores<T, C>> for Vec<T> // --- Iter -------------------------------------------------------------------- -pub struct Iter<'a, T: MatrixElement, C: StrictlyPositive> { +pub struct Iter<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> { scores: &'a StripedScores<T, C>, indices: Range<usize>, } -impl<'a, T: MatrixElement, C: StrictlyPositive> Iter<'a, T, C> { +impl<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> Iter<'a, T, C> { fn new(scores: &'a StripedScores<T, C>) -> Self { // Compute the last index let end = scores @@ -250,22 +255,24 @@ impl<'a, T: MatrixElement, C: StrictlyPositive> Iter<'a, T, C> { } } -impl<'a, T: MatrixElement, C: StrictlyPositive> Iterator for Iter<'a, T, C> { +impl<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> Iterator for Iter<'a, T, C> { type Item = &'a T; fn next(&mut self) -> Option<Self::Item> { self.indices.next().map(|i| self.get(i)) } } -impl<'a, T: MatrixElement, C: StrictlyPositive> ExactSizeIterator for Iter<'a, T, C> { +impl<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> ExactSizeIterator for Iter<'a, T, C> { fn len(&self) -> usize { self.indices.len() } } -impl<'a, T: MatrixElement, C: StrictlyPositive> FusedIterator for Iter<'a, T, C> {} +impl<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> FusedIterator for Iter<'a, T, C> {} -impl<'a, T: MatrixElement, C: StrictlyPositive> DoubleEndedIterator for Iter<'a, T, C> { +impl<'a, T: MatrixElement, C: StrictlyPositive + ArrayLength> DoubleEndedIterator + for Iter<'a, T, C> +{ fn next_back(&mut self) -> Option<Self::Item> { self.indices.next_back().map(|i| self.get(i)) } diff --git a/lightmotif/src/seq.rs b/lightmotif/src/seq.rs index 0a0347662547ee2f0a6ac4fc28151980c8b16ea4..b91bb6f0bd97f654b05e92bfd5bb4b7b1dda948c 100644 --- a/lightmotif/src/seq.rs +++ b/lightmotif/src/seq.rs @@ -20,6 +20,7 @@ use super::pli::Encode; use super::pli::Pipeline; use super::pli::Stripe; use super::pwm::ScoringMatrix; +use crate::num::ArrayLength; // --- SymbolCount ------------------------------------------------------------- @@ -91,7 +92,7 @@ impl<A: Alphabet> EncodedSequence<A> { /// Uses platform-accelerated implementation when available. pub fn to_striped<C>(&self) -> StripedSequence<A, C> where - C: StrictlyPositive, + C: StrictlyPositive + ArrayLength, Pipeline<A, Dispatch>: Stripe<A, C>, { let pli = Pipeline::<A, _>::dispatch(); @@ -195,14 +196,14 @@ where /// An encoded sequence stored in a striped matrix with a fixed column count. #[derive(Clone, Debug)] -pub struct StripedSequence<A: Alphabet, C: StrictlyPositive> { +pub struct StripedSequence<A: Alphabet, C: StrictlyPositive + ArrayLength> { alphabet: std::marker::PhantomData<A>, length: usize, wrap: usize, data: DenseMatrix<A::Symbol, C>, } -impl<A: Alphabet, C: StrictlyPositive> StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> StripedSequence<A, C> { /// Create a new striped sequence from the given dense matrix. /// /// # Errors @@ -283,31 +284,38 @@ impl<A: Alphabet, C: StrictlyPositive> StripedSequence<A, C> { } } -impl<A: Alphabet, C: StrictlyPositive> AsRef<StripedSequence<A, C>> for StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> AsRef<StripedSequence<A, C>> + for StripedSequence<A, C> +{ fn as_ref(&self) -> &Self { self } } -impl<A: Alphabet, C: StrictlyPositive> AsRef<DenseMatrix<A::Symbol, C>> for StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> AsRef<DenseMatrix<A::Symbol, C>> + for StripedSequence<A, C> +{ fn as_ref(&self) -> &DenseMatrix<A::Symbol, C> { &self.data } } -impl<A: Alphabet, C: StrictlyPositive> Default for StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> Default for StripedSequence<A, C> { fn default() -> Self { Self::new(DenseMatrix::new(0), 0).unwrap() } } -impl<A: Alphabet, C: StrictlyPositive> From<StripedSequence<A, C>> for DenseMatrix<A::Symbol, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> From<StripedSequence<A, C>> + for DenseMatrix<A::Symbol, C> +{ fn from(striped: StripedSequence<A, C>) -> Self { striped.into_matrix() } } -impl<A: Alphabet, C: StrictlyPositive> From<EncodedSequence<A>> for StripedSequence<A, C> +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> From<EncodedSequence<A>> + for StripedSequence<A, C> where Pipeline<A, Dispatch>: Stripe<A, C>, { @@ -316,7 +324,7 @@ where } } -impl<A: Alphabet, C: StrictlyPositive> Index<usize> for StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> Index<usize> for StripedSequence<A, C> { type Output = <A as Alphabet>::Symbol; #[inline] fn index(&self, index: usize) -> &Self::Output { @@ -327,7 +335,7 @@ impl<A: Alphabet, C: StrictlyPositive> Index<usize> for StripedSequence<A, C> { } } -impl<A: Alphabet, C: StrictlyPositive> SymbolCount<A> for &StripedSequence<A, C> { +impl<A: Alphabet, C: StrictlyPositive + ArrayLength> SymbolCount<A> for &StripedSequence<A, C> { fn count_symbol(&self, symbol: <A as Alphabet>::Symbol) -> usize { self.data .iter() diff --git a/lightmotif/tests/argmax.rs b/lightmotif/tests/argmax.rs index fdab04e8cc488ff5d62522c0e61be5eeceae7d27..f2526bc57db149ce730e54319def2fc884c00008 100644 --- a/lightmotif/tests/argmax.rs +++ b/lightmotif/tests/argmax.rs @@ -2,6 +2,7 @@ extern crate lightmotif; use lightmotif::abc::Background; use lightmotif::abc::Dna; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U1; use lightmotif::num::U16; @@ -19,7 +20,7 @@ const SEQUENCE: &str = include_str!("../benches/ecoli.txt"); const PATTERNS: &[&str] = &["GTTGACCTTATCAAC", "GTTGATCCAGTCAAC"]; const N: usize = SEQUENCE.len() / 10; -fn test_argmax_f32<C: StrictlyPositive, P: Maximum<f32, C>>(pli: &P) { +fn test_argmax_f32<C: StrictlyPositive + ArrayLength, P: Maximum<f32, C>>(pli: &P) { let generic = Pipeline::generic(); let seq = &SEQUENCE[..N]; diff --git a/lightmotif/tests/dna.rs b/lightmotif/tests/dna.rs index 9776677c6817f6a8cfb280cc701b0d42b7ee1253..bb97feed402d5edf354a1e717adc4aa385db101d 100644 --- a/lightmotif/tests/dna.rs +++ b/lightmotif/tests/dna.rs @@ -2,6 +2,7 @@ extern crate lightmotif; extern crate typenum; use lightmotif::abc::Dna; +use lightmotif::num::ArrayLength; use lightmotif::num::StrictlyPositive; use lightmotif::num::U1; use lightmotif::num::U16; @@ -36,7 +37,7 @@ const EXPECTED: &[f32] = &[ -30.922688 , -18.678621 ]; -fn test_score_rows<C: StrictlyPositive, P: Score<f32, Dna, C>>(pli: &P) { +fn test_score_rows<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C>>(pli: &P) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -61,7 +62,7 @@ fn test_score_rows<C: StrictlyPositive, P: Score<f32, Dna, C>>(pli: &P) { assert_eq!(scores.matrix()[0][0], EXPECTED[1]); } -fn test_score<C: StrictlyPositive, P: Score<f32, Dna, C>>(pli: &P) { +fn test_score<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C>>(pli: &P) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -89,7 +90,7 @@ fn test_score<C: StrictlyPositive, P: Score<f32, Dna, C>>(pli: &P) { } } -fn test_score_discrete<C: StrictlyPositive, P: Score<u8, Dna, C>>(pli: &P) { +fn test_score_discrete<C: StrictlyPositive + ArrayLength, P: Score<u8, Dna, C>>(pli: &P) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -118,7 +119,9 @@ fn test_score_discrete<C: StrictlyPositive, P: Score<u8, Dna, C>>(pli: &P) { } } -fn test_argmax<C: StrictlyPositive, P: Score<f32, Dna, C> + Maximum<f32, C>>(pli: &P) { +fn test_argmax<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C> + Maximum<f32, C>>( + pli: &P, +) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); @@ -135,7 +138,9 @@ fn test_argmax<C: StrictlyPositive, P: Score<f32, Dna, C> + Maximum<f32, C>>(pli assert_eq!(pli.argmax(&result).map(|c| result.offset(c)), Some(18)); } -fn test_threshold<C: StrictlyPositive, P: Score<f32, Dna, C> + Threshold<f32, C>>(pli: &P) { +fn test_threshold<C: StrictlyPositive + ArrayLength, P: Score<f32, Dna, C> + Threshold<f32, C>>( + pli: &P, +) { let encoded = EncodedSequence::<Dna>::encode(SEQUENCE).unwrap(); let mut striped = Pipeline::generic().stripe(encoded); diff --git a/lightmotif/tests/stripe.rs b/lightmotif/tests/stripe.rs index e60ffc86083894aa2789ac0b2298b23ad4c3b019..f03986823cf7a7447bcb5b8f816079ce63388739 100644 --- a/lightmotif/tests/stripe.rs +++ b/lightmotif/tests/stripe.rs @@ -3,8 +3,8 @@ extern crate typenum; use lightmotif::abc::Dna; use lightmotif::abc::Nucleotide; +use lightmotif::num::ArrayLength; use lightmotif::num::NonZero; -use lightmotif::num::Unsigned; use lightmotif::num::U16; use lightmotif::num::U32; use lightmotif::pli::Pipeline; @@ -14,7 +14,7 @@ use lightmotif::seq::EncodedSequence; const S1: &str = "ATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCGTTATTAT"; const S2: &str = "ATGTCCCAACAACGATACCCCGAGCCCATCGCCGTCATCGGCTCGGCATGCAGATTCCCAGGCG"; -fn test_stripe<C: Unsigned + NonZero, P: Stripe<Dna, C>>(pli: &P, sequence: &str) { +fn test_stripe<C: ArrayLength + NonZero, P: Stripe<Dna, C>>(pli: &P, sequence: &str) { let encoded = EncodedSequence::<Dna>::encode(sequence).unwrap(); let striped = pli.stripe(&encoded);