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);