From fe4365c9035ebf268d9d0c0e0d3e6100426e1527 Mon Sep 17 00:00:00 2001 From: "andrei.papou" Date: Sun, 24 Mar 2019 21:53:33 +0300 Subject: [PATCH 01/29] Implemented a function for smarter debug formatting. --- src/arrayformat.rs | 192 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 2 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index d13add8f7..ccd93454d 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -11,9 +11,197 @@ use super::{ Data, Dimension, NdProducer, + Ix }; use crate::dimension::IntoDimension; +#[derive(Debug)] +enum ArrayDisplayMode { + // Array is small enough to me printed without omitting any values. + Full, + // Omit central values of the nth axis. Since we print that axis horizontally, ellipses + // on each row do something like a split of the array into 2 parts vertically. + VSplit, + // Omit central values of the certain axis. Since we do it only once, ellipses on each row + // do something like a split of the array into 2 parts horizontally. + HSplit(Ix), + // Both `VSplit` and `HSplit` hold. + DoubleSplit(Ix), +} + +const PRINT_ELEMENTS_LIMIT: Ix = 5; + +impl ArrayDisplayMode { + fn from_array(arr: &ArrayBase, limit: usize) -> ArrayDisplayMode + where S: Data, + D: Dimension + { + let last_dim = arr.shape().len() - 1; + + let mut overflow_axis_pair: (Option, Option) = (None, None); + for (axis, axis_size) in arr.shape().iter().enumerate().rev() { + if *axis_size >= 2 * limit + 1 { + match overflow_axis_pair.0 { + Some(_) => { + if let None = overflow_axis_pair.1 { + overflow_axis_pair.1 = Some(axis); + } + }, + None => { + if axis != last_dim { + return ArrayDisplayMode::HSplit(axis); + } + overflow_axis_pair.0 = Some(axis); + } + } + } + } + + match overflow_axis_pair { + (Some(_), Some(h_axis)) => ArrayDisplayMode::DoubleSplit(h_axis), + (Some(_), None) => ArrayDisplayMode::VSplit, + (None, _) => ArrayDisplayMode::Full, + } + } + + fn h_split_offset(&self) -> Option { + match self { + ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => { + Some(axis + 1usize) + }, + _ => None + } + } +} + +fn format_array_v2(view: &ArrayBase, + f: &mut fmt::Formatter, + mut format: F, + limit: usize) -> fmt::Result + where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, + D: Dimension, + S: Data, +{ + let display_mode = ArrayDisplayMode::from_array(view, limit); + + let ndim = view.dim().into_dimension().slice().len(); + let nth_idx_max = view.shape().iter().last().unwrap(); + + // None will be an empty iter. + let mut last_index = match view.dim().into_dimension().first_index() { + None => view.dim().into_dimension().clone(), + Some(ix) => ix, + }; + for _ in 0..ndim { + write!(f, "[")?; + } + let mut first = true; + // Shows if ellipses for vertical split were printed. + let mut printed_ellipses_v = false; + // Shows if ellipses for horizontal split were printed. + let mut printed_ellipses_h = false; + // Shows if the row was printed for the first time after horizontal split. + let mut no_rows_after_skip_yet = false; + + // Simply use the indexed iterator, and take the index wraparounds + // as cues for when to add []'s and how many to add. + for (index, elt) in view.indexed_iter() { + let index = index.into_dimension(); + let take_n = if ndim == 0 { 1 } else { ndim - 1 }; + let mut update_index = false; + + let mut print_row = true; + match display_mode { + ArrayDisplayMode::HSplit(axis) | ArrayDisplayMode::DoubleSplit(axis) => { + let sa_idx_max = view.shape().iter().skip(axis).next().unwrap(); + let sa_idx_val = index.slice().iter().skip(axis).next().unwrap(); + if sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) { + print_row = false; + no_rows_after_skip_yet = true; + } + }, + _ => {} + } + + for (i, (a, b)) in index.slice() + .iter() + .take(take_n) + .zip(last_index.slice().iter()) + .enumerate() { + if a != b { + if print_row { + printed_ellipses_v = false; + // New row. + // # of ['s needed + let n = ndim - i - 1; + if !no_rows_after_skip_yet { + for _ in 0..n { + write!(f, "]")?; + } + write!(f, ",")?; + write!(f, "\n")?; + } + no_rows_after_skip_yet = false; + for _ in 0..ndim - n { + write!(f, " ")?; + } + for _ in 0..n { + write!(f, "[")?; + } + } else if !printed_ellipses_h { + let n = ndim - i - 1; + for _ in 0..n { + write!(f, "]")?; + } + write!(f, ",")?; + write!(f, "\n")?; + for _ in 0..display_mode.h_split_offset().unwrap() { + write!(f, " ")?; + } + write!(f, "...,\n")?; + printed_ellipses_h = true; + } + first = true; + update_index = true; + break; + } + } + + if print_row { + let mut print_elt = true; + let nth_idx_val = index.slice().iter().last().unwrap(); + match display_mode { + ArrayDisplayMode::VSplit | ArrayDisplayMode::DoubleSplit(_) => { + if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) { + print_elt = false; + if !printed_ellipses_v { + write!(f, ", ...")?; + printed_ellipses_v = true; + } + } + } + _ => {} + } + + if print_elt { + if !first { + write!(f, ", ")?; + } + first = false; + format(elt, f)?; + } + } + + if update_index { + last_index = index; + } + } + for _ in 0..ndim { + write!(f, "]")?; + } + Ok(()) +} + fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F) -> fmt::Result @@ -92,7 +280,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array(self, f, <_>::fmt) + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -105,7 +293,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Add extra information for Debug - format_array(self, f, <_>::fmt)?; + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT)?; write!(f, " shape={:?}, strides={:?}, layout={:?}", self.shape(), self.strides(), layout=self.view().layout())?; match D::NDIM { From 2450f5090c407425681839eab9d21f1c28d5d26f Mon Sep 17 00:00:00 2001 From: "andrei.papou" Date: Sun, 24 Mar 2019 22:37:20 +0300 Subject: [PATCH 02/29] Fixed existing tests --- src/arrayformat.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index ccd93454d..40f86e71d 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -36,7 +36,12 @@ impl ArrayDisplayMode { where S: Data, D: Dimension { - let last_dim = arr.shape().len() - 1; + let last_dim = match arr.shape().len().checked_sub(1) { + Some(v) => v, + None => { + return ArrayDisplayMode::Full; + } + }; let mut overflow_axis_pair: (Option, Option) = (None, None); for (axis, axis_size) in arr.shape().iter().enumerate().rev() { @@ -85,7 +90,7 @@ fn format_array_v2(view: &ArrayBase, let display_mode = ArrayDisplayMode::from_array(view, limit); let ndim = view.dim().into_dimension().slice().len(); - let nth_idx_max = view.shape().iter().last().unwrap(); + let nth_idx_max = if ndim > 0 { Some(view.shape().iter().last().unwrap()) } else { None }; // None will be an empty iter. let mut last_index = match view.dim().into_dimension().first_index() { @@ -169,10 +174,11 @@ fn format_array_v2(view: &ArrayBase, if print_row { let mut print_elt = true; - let nth_idx_val = index.slice().iter().last().unwrap(); + let nth_idx_op = index.slice().iter().last(); match display_mode { ArrayDisplayMode::VSplit | ArrayDisplayMode::DoubleSplit(_) => { - if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) { + let nth_idx_val = nth_idx_op.unwrap(); + if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max.unwrap() - &limit) { print_elt = false; if !printed_ellipses_v { write!(f, ", ...")?; From 3474d3f43302f91e0c773f06002f6e80389966dc Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Tue, 26 Mar 2019 14:34:15 +0300 Subject: [PATCH 03/29] Some fixes: - fixed typo in ArrayDisplayMode comment - updated ArrayDisplayMode constructor to use shape instead of array - fixed output for complex dimensions --- src/arrayformat.rs | 86 ++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 40f86e71d..0414e78c9 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -17,7 +17,7 @@ use crate::dimension::IntoDimension; #[derive(Debug)] enum ArrayDisplayMode { - // Array is small enough to me printed without omitting any values. + // Array is small enough to be printed without omitting any values. Full, // Omit central values of the nth axis. Since we print that axis horizontally, ellipses // on each row do something like a split of the array into 2 parts vertically. @@ -32,62 +32,66 @@ enum ArrayDisplayMode { const PRINT_ELEMENTS_LIMIT: Ix = 5; impl ArrayDisplayMode { - fn from_array(arr: &ArrayBase, limit: usize) -> ArrayDisplayMode - where S: Data, - D: Dimension + fn from_shape(shape: &[Ix], limit: Ix) -> ArrayDisplayMode { - let last_dim = match arr.shape().len().checked_sub(1) { + let last_dim = match shape.len().checked_sub(1) { Some(v) => v, None => { return ArrayDisplayMode::Full; } }; - let mut overflow_axis_pair: (Option, Option) = (None, None); - for (axis, axis_size) in arr.shape().iter().enumerate().rev() { + let mut overflow_axes: Vec = Vec::with_capacity(shape.len()); + for (axis, axis_size) in shape.iter().enumerate().rev() { if *axis_size >= 2 * limit + 1 { - match overflow_axis_pair.0 { - Some(_) => { - if let None = overflow_axis_pair.1 { - overflow_axis_pair.1 = Some(axis); - } - }, - None => { - if axis != last_dim { - return ArrayDisplayMode::HSplit(axis); - } - overflow_axis_pair.0 = Some(axis); - } - } + overflow_axes.push(axis); } } - match overflow_axis_pair { - (Some(_), Some(h_axis)) => ArrayDisplayMode::DoubleSplit(h_axis), - (Some(_), None) => ArrayDisplayMode::VSplit, - (None, _) => ArrayDisplayMode::Full, + if overflow_axes.is_empty() { + return ArrayDisplayMode::Full; + } + + let min_ovf_axis = *overflow_axes.iter().min().unwrap(); + let max_ovf_axis = *overflow_axes.iter().max().unwrap(); + + if max_ovf_axis == last_dim { + if min_ovf_axis != max_ovf_axis { + ArrayDisplayMode::DoubleSplit(min_ovf_axis) + } else { + ArrayDisplayMode::VSplit + } + } else { + ArrayDisplayMode::HSplit(min_ovf_axis) } } - fn h_split_offset(&self) -> Option { + fn h_split_axis(&self) -> Option { match self { ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => { - Some(axis + 1usize) + Some(*axis) }, _ => None } } + + fn h_split_offset(&self) -> Option { + match self.h_split_axis() { + Some(axis) => Some(axis + 1usize), + None => None + } + } } fn format_array_v2(view: &ArrayBase, - f: &mut fmt::Formatter, - mut format: F, - limit: usize) -> fmt::Result + f: &mut fmt::Formatter, + mut format: F, + limit: Ix) -> fmt::Result where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, D: Dimension, S: Data, { - let display_mode = ArrayDisplayMode::from_array(view, limit); + let display_mode = ArrayDisplayMode::from_shape(view.shape(), limit); let ndim = view.dim().into_dimension().slice().len(); let nth_idx_max = if ndim > 0 { Some(view.shape().iter().last().unwrap()) } else { None }; @@ -134,6 +138,12 @@ fn format_array_v2(view: &ArrayBase, .zip(last_index.slice().iter()) .enumerate() { if a != b { + if let Some(axis) = display_mode.h_split_axis() { + if i < axis { + printed_ellipses_h = false; + } + } + if print_row { printed_ellipses_v = false; // New row. @@ -356,3 +366,19 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase format_array(self, f, <_>::fmt) } } + +#[cfg(test)] +mod format_tests { + use super::*; + + fn test_array_display_mode_from_shape() { + let mode = ArrayDisplayMode::from_shape(&[4, 4], 2); + assert_eq!(mode, ArrayDisplayMode::Full); + + let mode = ArrayDisplayMode::from_shape(&[3, 6], 2); + assert_eq!(mode, ArrayDisplayMode::VSplit); + + let mode = ArrayDisplayMode::from_shape(&[5, 6, 3], 2); + assert_eq!(mode, ArrayDisplayMode::HSplit(1)); + } +} From 2a8a7c7ec0c913db7046cbde8f368d8c963229a8 Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Tue, 26 Mar 2019 19:04:35 +0300 Subject: [PATCH 04/29] Implemented axis shrinking for n-dim arrays --- src/arrayformat.rs | 111 +++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 0414e78c9..9fc4e6b2b 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; +use std::slice::Iter; use super::{ ArrayBase, Data, @@ -15,25 +16,24 @@ use super::{ }; use crate::dimension::IntoDimension; -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum ArrayDisplayMode { // Array is small enough to be printed without omitting any values. Full, - // Omit central values of the nth axis. Since we print that axis horizontally, ellipses - // on each row do something like a split of the array into 2 parts vertically. - VSplit, - // Omit central values of the certain axis. Since we do it only once, ellipses on each row - // do something like a split of the array into 2 parts horizontally. - HSplit(Ix), - // Both `VSplit` and `HSplit` hold. - DoubleSplit(Ix), + // Omit central values of the nth axis. + OmitV, + // Omit central values of certain axes (but not the last one). + // Vector is guaranteed to be non-empty. + OmitH(Vec), + // Both `OmitV` and `OmitH` hold. + OmitBoth(Vec), } -const PRINT_ELEMENTS_LIMIT: Ix = 5; +const PRINT_ELEMENTS_LIMIT: Ix = 2; impl ArrayDisplayMode { - fn from_shape(shape: &[Ix], limit: Ix) -> ArrayDisplayMode - { + + fn from_shape(shape: &[Ix], limit: Ix) -> ArrayDisplayMode { let last_dim = match shape.len().checked_sub(1) { Some(v) => v, None => { @@ -41,46 +41,36 @@ impl ArrayDisplayMode { } }; + let last_axis_ovf = shape[last_dim] >= 2 * limit + 1; let mut overflow_axes: Vec = Vec::with_capacity(shape.len()); for (axis, axis_size) in shape.iter().enumerate().rev() { + if axis == last_dim { + continue; + } if *axis_size >= 2 * limit + 1 { overflow_axes.push(axis); } } - if overflow_axes.is_empty() { - return ArrayDisplayMode::Full; - } - - let min_ovf_axis = *overflow_axes.iter().min().unwrap(); - let max_ovf_axis = *overflow_axes.iter().max().unwrap(); - - if max_ovf_axis == last_dim { - if min_ovf_axis != max_ovf_axis { - ArrayDisplayMode::DoubleSplit(min_ovf_axis) - } else { - ArrayDisplayMode::VSplit - } + if !overflow_axes.is_empty() && last_axis_ovf { + ArrayDisplayMode::OmitBoth(overflow_axes) + } else if !overflow_axes.is_empty() { + ArrayDisplayMode::OmitH(overflow_axes) + } else if last_axis_ovf { + ArrayDisplayMode::OmitV } else { - ArrayDisplayMode::HSplit(min_ovf_axis) + ArrayDisplayMode::Full } } - fn h_split_axis(&self) -> Option { + fn h_axes_iter(&self) -> Option> { match self { - ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => { - Some(*axis) + ArrayDisplayMode::OmitH(v) | ArrayDisplayMode::OmitBoth(v) => { + Some(v.iter()) }, _ => None } } - - fn h_split_offset(&self) -> Option { - match self.h_split_axis() { - Some(axis) => Some(axis + 1usize), - None => None - } - } } fn format_array_v2(view: &ArrayBase, @@ -108,7 +98,7 @@ fn format_array_v2(view: &ArrayBase, // Shows if ellipses for vertical split were printed. let mut printed_ellipses_v = false; // Shows if ellipses for horizontal split were printed. - let mut printed_ellipses_h = false; + let mut printed_ellipses_h = vec![false; ndim]; // Shows if the row was printed for the first time after horizontal split. let mut no_rows_after_skip_yet = false; @@ -119,17 +109,20 @@ fn format_array_v2(view: &ArrayBase, let take_n = if ndim == 0 { 1 } else { ndim - 1 }; let mut update_index = false; - let mut print_row = true; - match display_mode { - ArrayDisplayMode::HSplit(axis) | ArrayDisplayMode::DoubleSplit(axis) => { - let sa_idx_max = view.shape().iter().skip(axis).next().unwrap(); - let sa_idx_val = index.slice().iter().skip(axis).next().unwrap(); - if sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) { - print_row = false; - no_rows_after_skip_yet = true; - } + let skip_row_for_axis = match display_mode.h_axes_iter() { + Some(iter) => { + iter.filter(|axis| { + let sa_idx_max = view.shape().iter().skip(**axis).next().unwrap(); + let sa_idx_val = index.slice().iter().skip(**axis).next().unwrap(); + sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) + }) + .min() + .map(|v| *v) }, - _ => {} + None => None + }; + if let Some(_) = skip_row_for_axis { + no_rows_after_skip_yet = true; } for (i, (a, b)) in index.slice() @@ -138,13 +131,9 @@ fn format_array_v2(view: &ArrayBase, .zip(last_index.slice().iter()) .enumerate() { if a != b { - if let Some(axis) = display_mode.h_split_axis() { - if i < axis { - printed_ellipses_h = false; - } - } + printed_ellipses_h.iter_mut().skip(i + 1).for_each(|e| { *e = false; }); - if print_row { + if skip_row_for_axis.is_none() { printed_ellipses_v = false; // New row. // # of ['s needed @@ -163,18 +152,19 @@ fn format_array_v2(view: &ArrayBase, for _ in 0..n { write!(f, "[")?; } - } else if !printed_ellipses_h { + } else if !printed_ellipses_h[skip_row_for_axis.unwrap()] { + let ax = skip_row_for_axis.unwrap(); let n = ndim - i - 1; for _ in 0..n { write!(f, "]")?; } write!(f, ",")?; write!(f, "\n")?; - for _ in 0..display_mode.h_split_offset().unwrap() { + for _ in 0..(ax + 1) { write!(f, " ")?; } write!(f, "...,\n")?; - printed_ellipses_h = true; + printed_ellipses_h[ax] = true; } first = true; update_index = true; @@ -182,11 +172,11 @@ fn format_array_v2(view: &ArrayBase, } } - if print_row { + if skip_row_for_axis.is_none() { let mut print_elt = true; let nth_idx_op = index.slice().iter().last(); match display_mode { - ArrayDisplayMode::VSplit | ArrayDisplayMode::DoubleSplit(_) => { + ArrayDisplayMode::OmitV | ArrayDisplayMode::OmitBoth(_) => { let nth_idx_val = nth_idx_op.unwrap(); if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max.unwrap() - &limit) { print_elt = false; @@ -371,14 +361,15 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase mod format_tests { use super::*; + #[test] fn test_array_display_mode_from_shape() { let mode = ArrayDisplayMode::from_shape(&[4, 4], 2); assert_eq!(mode, ArrayDisplayMode::Full); let mode = ArrayDisplayMode::from_shape(&[3, 6], 2); - assert_eq!(mode, ArrayDisplayMode::VSplit); + assert_eq!(mode, ArrayDisplayMode::OmitV); let mode = ArrayDisplayMode::from_shape(&[5, 6, 3], 2); - assert_eq!(mode, ArrayDisplayMode::HSplit(1)); + assert_eq!(mode, ArrayDisplayMode::OmitH(vec![1, 0])); } } From 1b5da678ca2fe27adf67454b2133ee02da5c9b32 Mon Sep 17 00:00:00 2001 From: "andrei.papou" Date: Wed, 27 Mar 2019 09:57:38 +0300 Subject: [PATCH 05/29] All the PR issues are fixed. Tests are needed. --- src/arrayformat.rs | 163 +++++++++++---------------------------------- 1 file changed, 40 insertions(+), 123 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 9fc4e6b2b..c7b7421a6 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; -use std::slice::Iter; use super::{ ArrayBase, Data, @@ -16,63 +15,8 @@ use super::{ }; use crate::dimension::IntoDimension; -#[derive(Debug, PartialEq)] -enum ArrayDisplayMode { - // Array is small enough to be printed without omitting any values. - Full, - // Omit central values of the nth axis. - OmitV, - // Omit central values of certain axes (but not the last one). - // Vector is guaranteed to be non-empty. - OmitH(Vec), - // Both `OmitV` and `OmitH` hold. - OmitBoth(Vec), -} - const PRINT_ELEMENTS_LIMIT: Ix = 2; -impl ArrayDisplayMode { - - fn from_shape(shape: &[Ix], limit: Ix) -> ArrayDisplayMode { - let last_dim = match shape.len().checked_sub(1) { - Some(v) => v, - None => { - return ArrayDisplayMode::Full; - } - }; - - let last_axis_ovf = shape[last_dim] >= 2 * limit + 1; - let mut overflow_axes: Vec = Vec::with_capacity(shape.len()); - for (axis, axis_size) in shape.iter().enumerate().rev() { - if axis == last_dim { - continue; - } - if *axis_size >= 2 * limit + 1 { - overflow_axes.push(axis); - } - } - - if !overflow_axes.is_empty() && last_axis_ovf { - ArrayDisplayMode::OmitBoth(overflow_axes) - } else if !overflow_axes.is_empty() { - ArrayDisplayMode::OmitH(overflow_axes) - } else if last_axis_ovf { - ArrayDisplayMode::OmitV - } else { - ArrayDisplayMode::Full - } - } - - fn h_axes_iter(&self) -> Option> { - match self { - ArrayDisplayMode::OmitH(v) | ArrayDisplayMode::OmitBoth(v) => { - Some(v.iter()) - }, - _ => None - } - } -} - fn format_array_v2(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F, @@ -81,19 +25,27 @@ fn format_array_v2(view: &ArrayBase, D: Dimension, S: Data, { - let display_mode = ArrayDisplayMode::from_shape(view.shape(), limit); + if view.shape().is_empty() { + // Handle weird 0-dimensional array case first + return writeln!(f, "[]") + } + + let overflow_axes: Vec = view.shape().iter() + .enumerate() + .rev() + .filter(|(_, axis_size)| **axis_size > 2 * limit) + .map(|(axis, _)| axis) + .collect(); let ndim = view.dim().into_dimension().slice().len(); - let nth_idx_max = if ndim > 0 { Some(view.shape().iter().last().unwrap()) } else { None }; + let nth_idx_max = view.shape().iter().last().unwrap(); // None will be an empty iter. let mut last_index = match view.dim().into_dimension().first_index() { None => view.dim().into_dimension().clone(), Some(ix) => ix, }; - for _ in 0..ndim { - write!(f, "[")?; - } + write!(f, "{}", "[".repeat(ndim))?; let mut first = true; // Shows if ellipses for vertical split were printed. let mut printed_ellipses_v = false; @@ -109,18 +61,17 @@ fn format_array_v2(view: &ArrayBase, let take_n = if ndim == 0 { 1 } else { ndim - 1 }; let mut update_index = false; - let skip_row_for_axis = match display_mode.h_axes_iter() { - Some(iter) => { - iter.filter(|axis| { - let sa_idx_max = view.shape().iter().skip(**axis).next().unwrap(); - let sa_idx_val = index.slice().iter().skip(**axis).next().unwrap(); - sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) - }) - .min() - .map(|v| *v) - }, - None => None - }; + let skip_row_for_axis = overflow_axes.iter() + .filter(|axis| { + if **axis == ndim - 1 { + return false + }; + let sa_idx_max = view.shape().iter().skip(**axis).next().unwrap(); + let sa_idx_val = index.slice().iter().skip(**axis).next().unwrap(); + sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) + }) + .min() + .map(|v| *v); if let Some(_) = skip_row_for_axis { no_rows_after_skip_yet = true; } @@ -139,31 +90,19 @@ fn format_array_v2(view: &ArrayBase, // # of ['s needed let n = ndim - i - 1; if !no_rows_after_skip_yet { - for _ in 0..n { - write!(f, "]")?; - } - write!(f, ",")?; - write!(f, "\n")?; + write!(f, "{}", "]".repeat(n))?; + writeln!(f, ",")?; } no_rows_after_skip_yet = false; - for _ in 0..ndim - n { - write!(f, " ")?; - } - for _ in 0..n { - write!(f, "[")?; - } + write!(f, "{}", " ".repeat(ndim - n))?; + write!(f, "{}", "[".repeat(n))?; } else if !printed_ellipses_h[skip_row_for_axis.unwrap()] { let ax = skip_row_for_axis.unwrap(); let n = ndim - i - 1; - for _ in 0..n { - write!(f, "]")?; - } - write!(f, ",")?; - write!(f, "\n")?; - for _ in 0..(ax + 1) { - write!(f, " ")?; - } - write!(f, "...,\n")?; + write!(f, "{}", "]".repeat(n))?; + writeln!(f, ",")?; + write!(f, "{}", " ".repeat(ax + 1))?; + writeln!(f, "...,")?; printed_ellipses_h[ax] = true; } first = true; @@ -175,18 +114,15 @@ fn format_array_v2(view: &ArrayBase, if skip_row_for_axis.is_none() { let mut print_elt = true; let nth_idx_op = index.slice().iter().last(); - match display_mode { - ArrayDisplayMode::OmitV | ArrayDisplayMode::OmitBoth(_) => { - let nth_idx_val = nth_idx_op.unwrap(); - if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max.unwrap() - &limit) { - print_elt = false; - if !printed_ellipses_v { - write!(f, ", ...")?; - printed_ellipses_v = true; - } + if overflow_axes.contains(&(ndim - 1)) { + let nth_idx_val = nth_idx_op.unwrap(); + if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) { + print_elt = false; + if !printed_ellipses_v { + write!(f, ", ...")?; + printed_ellipses_v = true; } } - _ => {} } if print_elt { @@ -202,9 +138,7 @@ fn format_array_v2(view: &ArrayBase, last_index = index; } } - for _ in 0..ndim { - write!(f, "]")?; - } + write!(f, "{}", "]".repeat(ndim))?; Ok(()) } @@ -356,20 +290,3 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase format_array(self, f, <_>::fmt) } } - -#[cfg(test)] -mod format_tests { - use super::*; - - #[test] - fn test_array_display_mode_from_shape() { - let mode = ArrayDisplayMode::from_shape(&[4, 4], 2); - assert_eq!(mode, ArrayDisplayMode::Full); - - let mode = ArrayDisplayMode::from_shape(&[3, 6], 2); - assert_eq!(mode, ArrayDisplayMode::OmitV); - - let mode = ArrayDisplayMode::from_shape(&[5, 6, 3], 2); - assert_eq!(mode, ArrayDisplayMode::OmitH(vec![1, 0])); - } -} From fbf8cac8235a1561358a1a0458472426a1fdb97e Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Wed, 27 Mar 2019 11:20:46 +0300 Subject: [PATCH 06/29] Fixed the tests --- src/arrayformat.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index c7b7421a6..f751330c9 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -26,8 +26,8 @@ fn format_array_v2(view: &ArrayBase, S: Data, { if view.shape().is_empty() { - // Handle weird 0-dimensional array case first - return writeln!(f, "[]") + // Handle 0-dimensional array case first + return format(view.iter().next().unwrap(), f) } let overflow_axes: Vec = view.shape().iter() From 51c4e11fb6888eb73bfeac03ee842fa1d6e4eed0 Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Wed, 27 Mar 2019 12:53:04 +0300 Subject: [PATCH 07/29] Added tests for 1- and 2-dimensional array with overflow --- src/arrayformat.rs | 11 ++-- src/lib.rs | 2 + tests/format.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index f751330c9..bfdaf8068 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -15,7 +15,7 @@ use super::{ }; use crate::dimension::IntoDimension; -const PRINT_ELEMENTS_LIMIT: Ix = 2; +pub const PRINT_ELEMENTS_LIMIT: Ix = 3; fn format_array_v2(view: &ArrayBase, f: &mut fmt::Formatter, @@ -142,6 +142,7 @@ fn format_array_v2(view: &ArrayBase, Ok(()) } +#[allow(dead_code)] fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F) -> fmt::Result @@ -252,7 +253,7 @@ impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array(self, f, <_>::fmt) + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -264,7 +265,7 @@ impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array(self, f, <_>::fmt) + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } /// Format the array using `LowerHex` and apply the formatting parameters used @@ -275,7 +276,7 @@ impl<'a, A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array(self, f, <_>::fmt) + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -287,6 +288,6 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array(self, f, <_>::fmt) + format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } diff --git a/src/lib.rs b/src/lib.rs index 7be810f9b..846d01452 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,6 +149,8 @@ mod array_serde; mod arrayformat; mod data_traits; +pub use arrayformat::PRINT_ELEMENTS_LIMIT; + pub use crate::aliases::*; #[allow(deprecated)] diff --git a/tests/format.rs b/tests/format.rs index 4dbc939cc..335326ae5 100644 --- a/tests/format.rs +++ b/tests/format.rs @@ -1,7 +1,7 @@ extern crate ndarray; use ndarray::prelude::*; -use ndarray::rcarr1; +use ndarray::{rcarr1, PRINT_ELEMENTS_LIMIT}; #[test] fn formatting() @@ -36,6 +36,132 @@ fn formatting() assert_eq!(s, "[01, ff, fe]"); } +#[cfg(test)] +mod formatting_with_omit { + use super::*; + + fn print_output_diff(expected: &str, actual: &str) { + println!("Expected output:\n{}\nActual output:\n{}", expected, actual); + } + + #[test] + fn dim_1() { + let overflow: usize = 5; + let a = Array1::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, ), 1); + let mut expected_output = String::from("["); + a.iter() + .take(PRINT_ELEMENTS_LIMIT) + .for_each(|elem| { expected_output.push_str(format!("{}, ", elem).as_str()) }); + expected_output.push_str("..."); + a.iter() + .skip(PRINT_ELEMENTS_LIMIT + overflow) + .for_each(|elem| { expected_output.push_str(format!(", {}", elem).as_str()) }); + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_last_axis_overflow() { + let overflow: usize = 3; + let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i < PRINT_ELEMENTS_LIMIT - 1 { "],\n " } else { "]" }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_non_last_axis_overflow() { + let overflow: usize = 5; + let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT), 1); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str("],\n "); + } + expected_output.push_str("...,\n "); + for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { + "]" + } else { + "],\n " + }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_multi_directional_overflow() { + let overflow: usize = 5; + let a = Array2::from_elem( + (PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1 + ); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str("],\n "); + } + expected_output.push_str("...,\n "); + for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { + "]" + } else { + "],\n " + }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } +} + #[test] fn debug_format() { let a = Array2::::zeros((3, 4)); From 0d11708851a973e469b548a6139c95c4267db019 Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Wed, 27 Mar 2019 13:16:14 +0300 Subject: [PATCH 08/29] Try to fix 1.31 build failing --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 846d01452..d8032be7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,8 +149,6 @@ mod array_serde; mod arrayformat; mod data_traits; -pub use arrayformat::PRINT_ELEMENTS_LIMIT; - pub use crate::aliases::*; #[allow(deprecated)] @@ -192,6 +190,7 @@ pub use crate::zip::{ }; pub use crate::layout::Layout; +pub use crate::arrayformat::PRINT_ELEMENTS_LIMIT; /// Implementation's prelude. Common types used everywhere. mod imp_prelude { From 18c868a8195d38a459ab008f887c9bc5029effa1 Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Thu, 28 Mar 2019 12:04:05 +0300 Subject: [PATCH 09/29] PRINT_ELEMENTS_LIMIT is now private --- src/arrayformat.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 1 - tests/format.rs | 128 +------------------------------------------- 3 files changed, 129 insertions(+), 129 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index bfdaf8068..a6028ebdd 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -15,7 +15,7 @@ use super::{ }; use crate::dimension::IntoDimension; -pub const PRINT_ELEMENTS_LIMIT: Ix = 3; +const PRINT_ELEMENTS_LIMIT: Ix = 3; fn format_array_v2(view: &ArrayBase, f: &mut fmt::Formatter, @@ -291,3 +291,130 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } + +#[cfg(test)] +mod formatting_with_omit { + use crate::prelude::*; + use super::*; + + fn print_output_diff(expected: &str, actual: &str) { + println!("Expected output:\n{}\nActual output:\n{}", expected, actual); + } + + #[test] + fn dim_1() { + let overflow: usize = 5; + let a = Array1::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, ), 1); + let mut expected_output = String::from("["); + a.iter() + .take(PRINT_ELEMENTS_LIMIT) + .for_each(|elem| { expected_output.push_str(format!("{}, ", elem).as_str()) }); + expected_output.push_str("..."); + a.iter() + .skip(PRINT_ELEMENTS_LIMIT + overflow) + .for_each(|elem| { expected_output.push_str(format!(", {}", elem).as_str()) }); + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_last_axis_overflow() { + let overflow: usize = 3; + let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i < PRINT_ELEMENTS_LIMIT - 1 { "],\n " } else { "]" }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_non_last_axis_overflow() { + let overflow: usize = 5; + let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT), 1); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str("],\n "); + } + expected_output.push_str("...,\n "); + for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { + "]" + } else { + "],\n " + }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } + + #[test] + fn dim_2_multi_directional_overflow() { + let overflow: usize = 5; + let a = Array2::from_elem( + (PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1 + ); + let mut expected_output = String::from("["); + + for i in 0..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str("],\n "); + } + expected_output.push_str("...,\n "); + for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); + for j in 1..PRINT_ELEMENTS_LIMIT { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(", ..."); + for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { + expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); + } + expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { + "]" + } else { + "],\n " + }); + } + expected_output.push(']'); + let actual_output = format!("{}", a); + + print_output_diff(&expected_output, &actual_output); + assert_eq!(actual_output, expected_output); + } +} diff --git a/src/lib.rs b/src/lib.rs index d8032be7d..7be810f9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -190,7 +190,6 @@ pub use crate::zip::{ }; pub use crate::layout::Layout; -pub use crate::arrayformat::PRINT_ELEMENTS_LIMIT; /// Implementation's prelude. Common types used everywhere. mod imp_prelude { diff --git a/tests/format.rs b/tests/format.rs index 335326ae5..4dbc939cc 100644 --- a/tests/format.rs +++ b/tests/format.rs @@ -1,7 +1,7 @@ extern crate ndarray; use ndarray::prelude::*; -use ndarray::{rcarr1, PRINT_ELEMENTS_LIMIT}; +use ndarray::rcarr1; #[test] fn formatting() @@ -36,132 +36,6 @@ fn formatting() assert_eq!(s, "[01, ff, fe]"); } -#[cfg(test)] -mod formatting_with_omit { - use super::*; - - fn print_output_diff(expected: &str, actual: &str) { - println!("Expected output:\n{}\nActual output:\n{}", expected, actual); - } - - #[test] - fn dim_1() { - let overflow: usize = 5; - let a = Array1::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, ), 1); - let mut expected_output = String::from("["); - a.iter() - .take(PRINT_ELEMENTS_LIMIT) - .for_each(|elem| { expected_output.push_str(format!("{}, ", elem).as_str()) }); - expected_output.push_str("..."); - a.iter() - .skip(PRINT_ELEMENTS_LIMIT + overflow) - .for_each(|elem| { expected_output.push_str(format!(", {}", elem).as_str()) }); - expected_output.push(']'); - let actual_output = format!("{}", a); - - print_output_diff(&expected_output, &actual_output); - assert_eq!(actual_output, expected_output); - } - - #[test] - fn dim_2_last_axis_overflow() { - let overflow: usize = 3; - let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1); - let mut expected_output = String::from("["); - - for i in 0..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); - for j in 1..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(", ..."); - for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(if i < PRINT_ELEMENTS_LIMIT - 1 { "],\n " } else { "]" }); - } - expected_output.push(']'); - let actual_output = format!("{}", a); - - print_output_diff(&expected_output, &actual_output); - assert_eq!(actual_output, expected_output); - } - - #[test] - fn dim_2_non_last_axis_overflow() { - let overflow: usize = 5; - let a = Array2::from_elem((PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT), 1); - let mut expected_output = String::from("["); - - for i in 0..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); - for j in 1..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str("],\n "); - } - expected_output.push_str("...,\n "); - for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { - expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); - for j in 1..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { - "]" - } else { - "],\n " - }); - } - expected_output.push(']'); - let actual_output = format!("{}", a); - - print_output_diff(&expected_output, &actual_output); - assert_eq!(actual_output, expected_output); - } - - #[test] - fn dim_2_multi_directional_overflow() { - let overflow: usize = 5; - let a = Array2::from_elem( - (PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT * 2 + overflow), 1 - ); - let mut expected_output = String::from("["); - - for i in 0..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); - for j in 1..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(", ..."); - for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str("],\n "); - } - expected_output.push_str("...,\n "); - for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { - expected_output.push_str(format!("[{}", a[(i, 0)]).as_str()); - for j in 1..PRINT_ELEMENTS_LIMIT { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(", ..."); - for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow { - expected_output.push_str(format!(", {}", a[(i, j)]).as_str()); - } - expected_output.push_str(if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 { - "]" - } else { - "],\n " - }); - } - expected_output.push(']'); - let actual_output = format!("{}", a); - - print_output_diff(&expected_output, &actual_output); - assert_eq!(actual_output, expected_output); - } -} - #[test] fn debug_format() { let a = Array2::::zeros((3, 4)); From 3aa8abe2ccb1c3d6f5e5f764597b7ac12efc573e Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 20:39:59 +0100 Subject: [PATCH 10/29] Remove dead code --- src/arrayformat.rs | 70 ---------------------------------------------- 1 file changed, 70 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index a6028ebdd..04c5f70b8 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -142,76 +142,6 @@ fn format_array_v2(view: &ArrayBase, Ok(()) } -#[allow(dead_code)] -fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, - mut format: F) - -> fmt::Result - where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, - D: Dimension, - S: Data, -{ - let ndim = view.dim.slice().len(); - /* private nowadays - if ndim > 0 && f.width.is_none() { - f.width = Some(4) - } - */ - // None will be an empty iter. - let mut last_index = match view.dim.first_index() { - None => view.dim.clone(), - Some(ix) => ix, - }; - for _ in 0..ndim { - write!(f, "[")?; - } - let mut first = true; - // Simply use the indexed iterator, and take the index wraparounds - // as cues for when to add []'s and how many to add. - for (index, elt) in view.indexed_iter() { - let index = index.into_dimension(); - let take_n = if ndim == 0 { 1 } else { ndim - 1 }; - let mut update_index = false; - for (i, (a, b)) in index.slice() - .iter() - .take(take_n) - .zip(last_index.slice().iter()) - .enumerate() { - if a != b { - // New row. - // # of ['s needed - let n = ndim - i - 1; - for _ in 0..n { - write!(f, "]")?; - } - write!(f, ",")?; - write!(f, "\n")?; - for _ in 0..ndim - n { - write!(f, " ")?; - } - for _ in 0..n { - write!(f, "[")?; - } - first = true; - update_index = true; - break; - } - } - if !first { - write!(f, ", ")?; - } - first = false; - format(elt, f)?; - - if update_index { - last_index = index; - } - } - for _ in 0..ndim { - write!(f, "]")?; - } - Ok(()) -} - // NOTE: We can impl other fmt traits here /// Format the array using `Display` and apply the formatting parameters used /// to each element. From 17f86bb2c76e0c42123d58af18bbe753c7ba4ca5 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 20:43:09 +0100 Subject: [PATCH 11/29] Rename format_array_v2 to format_array --- src/arrayformat.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 04c5f70b8..e89d9e9b1 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -17,10 +17,10 @@ use crate::dimension::IntoDimension; const PRINT_ELEMENTS_LIMIT: Ix = 3; -fn format_array_v2(view: &ArrayBase, - f: &mut fmt::Formatter, - mut format: F, - limit: Ix) -> fmt::Result +fn format_array(view: &ArrayBase, + f: &mut fmt::Formatter, + mut format: F, + limit: Ix) -> fmt::Result where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, D: Dimension, S: Data, @@ -151,7 +151,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -164,7 +164,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Add extra information for Debug - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT)?; + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT)?; write!(f, " shape={:?}, strides={:?}, layout={:?}", self.shape(), self.strides(), layout=self.view().layout())?; match D::NDIM { @@ -183,7 +183,7 @@ impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -195,7 +195,7 @@ impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } /// Format the array using `LowerHex` and apply the formatting parameters used @@ -206,7 +206,7 @@ impl<'a, A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } @@ -218,7 +218,7 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase where S: Data, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) + format_array(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT) } } From d48c5a9265efaf4d9b570c863087d3d7211d5c22 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 20:46:32 +0100 Subject: [PATCH 12/29] Simplify code using ndim --- src/arrayformat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index e89d9e9b1..440aa9828 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -37,7 +37,7 @@ fn format_array(view: &ArrayBase, .map(|(axis, _)| axis) .collect(); - let ndim = view.dim().into_dimension().slice().len(); + let ndim = view.ndim(); let nth_idx_max = view.shape().iter().last().unwrap(); // None will be an empty iter. From 6c636dc3f3381750f7165a9222cd07a08fb283eb Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 20:47:33 +0100 Subject: [PATCH 13/29] Access last element directly --- src/arrayformat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 440aa9828..174f9fce3 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -38,7 +38,7 @@ fn format_array(view: &ArrayBase, .collect(); let ndim = view.ndim(); - let nth_idx_max = view.shape().iter().last().unwrap(); + let nth_idx_max = view.shape()[ndim-1]; // None will be an empty iter. let mut last_index = match view.dim().into_dimension().first_index() { From 88d53e38bb48ae2ca27476bb84341983e05472cd Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 21:48:06 +0100 Subject: [PATCH 14/29] Add a test to specify behaviour for zero-dimensional arrays --- src/arrayformat.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 174f9fce3..286fb30f9 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -231,6 +231,15 @@ mod formatting_with_omit { println!("Expected output:\n{}\nActual output:\n{}", expected, actual); } + #[test] + fn dim_0() { + let element = 12; + let a = arr0(element); + let actual_output = format!("{}", a); + let expected_output = format!("{}", element); + assert_eq!(actual_output, expected_output); + } + #[test] fn dim_1() { let overflow: usize = 5; From b962a7bb1aed8b8e0eb4cf02a22924c86dd5a5dd Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 21:55:33 +0100 Subject: [PATCH 15/29] Add a test for empty arrays --- src/arrayformat.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 286fb30f9..8767248ca 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -231,6 +231,14 @@ mod formatting_with_omit { println!("Expected output:\n{}\nActual output:\n{}", expected, actual); } + #[test] + fn empty_arrays() { + let a: Array2 = arr2(&[[], []]); + let actual_output = format!("{}", a); + let expected_output = String::from("[[]]"); + assert_eq!(actual_output, expected_output); + } + #[test] fn dim_0() { let element = 12; From 29a8f7037c2812bb9855806ba45b76eef5d964a2 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 21:59:13 +0100 Subject: [PATCH 16/29] Test zero-length axes --- src/arrayformat.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 8767248ca..54fc27595 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -239,6 +239,14 @@ mod formatting_with_omit { assert_eq!(actual_output, expected_output); } + #[test] + fn zero_length_axes() { + let a = Array3::::zeros((3, 0, 4)); + let actual_output = format!("{}", a); + let expected_output = String::from("[[[]]]"); + assert_eq!(actual_output, expected_output); + } + #[test] fn dim_0() { let element = 12; From 27c4a92c18033d79233d4bde34091e67999a307e Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 16 Apr 2019 22:02:25 +0100 Subject: [PATCH 17/29] We already know that ndim > 0 --- src/arrayformat.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 54fc27595..f11827b5a 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -58,7 +58,6 @@ fn format_array(view: &ArrayBase, // as cues for when to add []'s and how many to add. for (index, elt) in view.indexed_iter() { let index = index.into_dimension(); - let take_n = if ndim == 0 { 1 } else { ndim - 1 }; let mut update_index = false; let skip_row_for_axis = overflow_axes.iter() @@ -78,7 +77,7 @@ fn format_array(view: &ArrayBase, for (i, (a, b)) in index.slice() .iter() - .take(take_n) + .take(ndim-1) .zip(last_index.slice().iter()) .enumerate() { if a != b { From b535f28440a2c6fdcc8cd9fdfc5dd267cb6eb4a6 Mon Sep 17 00:00:00 2001 From: andrei-papou Date: Wed, 17 Apr 2019 13:52:21 +0300 Subject: [PATCH 18/29] Made the formatting logic more modular --- src/arrayformat.rs | 137 +++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index f11827b5a..35a8a2a20 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -17,6 +17,42 @@ use crate::dimension::IntoDimension; const PRINT_ELEMENTS_LIMIT: Ix = 3; +fn get_overflow_axes(shape: &[Ix], limit: usize) -> Vec { + shape.iter() + .enumerate() + .rev() + .filter(|(_, axis_size)| **axis_size > 2 * limit) + .map(|(axis, _)| axis) + .collect() +} + +fn get_highest_axis_to_skip(overflow_axes: &Vec, + shape: &[Ix], + index: &[Ix], + limit: &usize) -> Option { + overflow_axes.iter() + .filter(|axis| { + if **axis == shape.len() - 1 { + return false + }; + let sa_idx_max = shape.iter().skip(**axis).next().unwrap(); + let sa_idx_val = index.iter().skip(**axis).next().unwrap(); + sa_idx_val >= limit && sa_idx_val < &(sa_idx_max - limit) + }) + .min() + .map(|v| *v) +} + +fn get_highest_changed_axis(index: &[Ix], prev_index: &[Ix]) -> Option { + index.iter() + .take(index.len() - 1) + .zip(prev_index.iter()) + .enumerate() + .filter(|(_, (a, b))| a != b) + .map(|(i, _)| i) + .next() +} + fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F, @@ -30,12 +66,7 @@ fn format_array(view: &ArrayBase, return format(view.iter().next().unwrap(), f) } - let overflow_axes: Vec = view.shape().iter() - .enumerate() - .rev() - .filter(|(_, axis_size)| **axis_size > 2 * limit) - .map(|(axis, _)| axis) - .collect(); + let overflow_axes: Vec = get_overflow_axes(view.shape(), limit); let ndim = view.ndim(); let nth_idx_max = view.shape()[ndim-1]; @@ -46,9 +77,6 @@ fn format_array(view: &ArrayBase, Some(ix) => ix, }; write!(f, "{}", "[".repeat(ndim))?; - let mut first = true; - // Shows if ellipses for vertical split were printed. - let mut printed_ellipses_v = false; // Shows if ellipses for horizontal split were printed. let mut printed_ellipses_h = vec![false; ndim]; // Shows if the row was printed for the first time after horizontal split. @@ -58,83 +86,60 @@ fn format_array(view: &ArrayBase, // as cues for when to add []'s and how many to add. for (index, elt) in view.indexed_iter() { let index = index.into_dimension(); - let mut update_index = false; - - let skip_row_for_axis = overflow_axes.iter() - .filter(|axis| { - if **axis == ndim - 1 { - return false - }; - let sa_idx_max = view.shape().iter().skip(**axis).next().unwrap(); - let sa_idx_val = index.slice().iter().skip(**axis).next().unwrap(); - sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) - }) - .min() - .map(|v| *v); - if let Some(_) = skip_row_for_axis { + + let skip_row_for_axis = get_highest_axis_to_skip( + &overflow_axes, + view.shape(), + index.slice(), + &limit + ); + if skip_row_for_axis.is_some() { no_rows_after_skip_yet = true; } - for (i, (a, b)) in index.slice() - .iter() - .take(ndim-1) - .zip(last_index.slice().iter()) - .enumerate() { - if a != b { - printed_ellipses_h.iter_mut().skip(i + 1).for_each(|e| { *e = false; }); - - if skip_row_for_axis.is_none() { - printed_ellipses_v = false; - // New row. - // # of ['s needed - let n = ndim - i - 1; - if !no_rows_after_skip_yet { - write!(f, "{}", "]".repeat(n))?; - writeln!(f, ",")?; - } - no_rows_after_skip_yet = false; - write!(f, "{}", " ".repeat(ndim - n))?; - write!(f, "{}", "[".repeat(n))?; - } else if !printed_ellipses_h[skip_row_for_axis.unwrap()] { - let ax = skip_row_for_axis.unwrap(); - let n = ndim - i - 1; + let max_changed_idx = get_highest_changed_axis(index.slice(), last_index.slice()); + if let Some(i) = max_changed_idx { + printed_ellipses_h.iter_mut().skip(i + 1).for_each(|e| { *e = false; }); + + if skip_row_for_axis.is_none() { + // New row. + // # of ['s needed + let n = ndim - i - 1; + if !no_rows_after_skip_yet { write!(f, "{}", "]".repeat(n))?; writeln!(f, ",")?; - write!(f, "{}", " ".repeat(ax + 1))?; - writeln!(f, "...,")?; - printed_ellipses_h[ax] = true; } - first = true; - update_index = true; - break; + no_rows_after_skip_yet = false; + write!(f, "{}", " ".repeat(ndim - n))?; + write!(f, "{}", "[".repeat(n))?; + } else if !printed_ellipses_h[skip_row_for_axis.unwrap()] { + let ax = skip_row_for_axis.unwrap(); + let n = ndim - i - 1; + write!(f, "{}", "]".repeat(n))?; + writeln!(f, ",")?; + write!(f, "{}", " ".repeat(ax + 1))?; + writeln!(f, "...,")?; + printed_ellipses_h[ax] = true; } + last_index = index.clone(); } if skip_row_for_axis.is_none() { - let mut print_elt = true; let nth_idx_op = index.slice().iter().last(); if overflow_axes.contains(&(ndim - 1)) { let nth_idx_val = nth_idx_op.unwrap(); if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) { - print_elt = false; - if !printed_ellipses_v { + if nth_idx_val == &limit { write!(f, ", ...")?; - printed_ellipses_v = true; } + continue; } } - if print_elt { - if !first { - write!(f, ", ")?; - } - first = false; - format(elt, f)?; + if max_changed_idx.is_none() && !index.slice().iter().all(|x| *x == 0) { + write!(f, ", ")?; } - } - - if update_index { - last_index = index; + format(elt, f)?; } } write!(f, "{}", "]".repeat(ndim))?; From 2a8a3b0918781476d882bb7077ca12ec4de0ca52 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sat, 20 Apr 2019 15:17:32 +0100 Subject: [PATCH 19/29] Simplify element access --- src/arrayformat.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 35a8a2a20..0bd274f0f 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -31,13 +31,13 @@ fn get_highest_axis_to_skip(overflow_axes: &Vec, index: &[Ix], limit: &usize) -> Option { overflow_axes.iter() - .filter(|axis| { - if **axis == shape.len() - 1 { + .filter(|&axis| { + if *axis == shape.len() - 1 { return false }; - let sa_idx_max = shape.iter().skip(**axis).next().unwrap(); - let sa_idx_val = index.iter().skip(**axis).next().unwrap(); - sa_idx_val >= limit && sa_idx_val < &(sa_idx_max - limit) + let sa_idx_max = shape[*axis]; + let sa_idx_val = index[*axis]; + sa_idx_val >= *limit && sa_idx_val < sa_idx_max - *limit }) .min() .map(|v| *v) From 5fd9b2f77d7f447356fd1aa225296309ddd57449 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sat, 20 Apr 2019 17:03:14 +0100 Subject: [PATCH 20/29] Almost there --- src/arrayformat.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 0bd274f0f..9b238aeeb 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -8,12 +8,14 @@ use std::fmt; use super::{ ArrayBase, + Axis, Data, Dimension, NdProducer, Ix }; use crate::dimension::IntoDimension; +use crate::aliases::ArrayViewD; const PRINT_ELEMENTS_LIMIT: Ix = 3; @@ -53,6 +55,73 @@ fn get_highest_changed_axis(index: &[Ix], prev_index: &[Ix]) -> Option { .next() } +fn format_1d_array( + view: &ArrayBase, + f: &mut fmt::Formatter, + mut format: F, + limit: Ix) -> fmt::Result + where + F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, + D: Dimension, + S: Data, +{ + unimplemented!() +} + +fn format_multidimensional_array( + view: &ArrayBase, + f: &mut fmt::Formatter, + mut format: F, + limit: Ix) -> fmt::Result + where + F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, + D: Dimension, + S: Data, +{ + unimplemented!() +} + +fn format_array_v2( + view: &ArrayBase, + f: &mut fmt::Formatter, + mut format: F, + limit: Ix) -> fmt::Result +where + F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, + D: Dimension, + S: Data, +{ + let view = view.view().into_dyn(); + match view.shape() { + [] => format(view.iter().next().unwrap(), f)?, + [_] => format_1d_array(&view, f, format, limit)?, + shape => { + let first_axis_length = shape[0]; + let indexes_to_be_printed: Vec> = if first_axis_length <= 2 * limit { + (0..first_axis_length).map(|x| Some(x)).collect() + } else { + let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); + v.push(None); + v.extend((first_axis_length-limit..first_axis_length).map(|x| Some(x))); + v + }; + write!(f, "[")?; + for index in indexes_to_be_printed { + match index { + Some(i) => format_array_v2( + &view.index_axis(Axis(0), i), f, format, limit + )?, + None => { + writeln!(f, "...,")? + } + } + } + write!(f, "]")?; + } + } + Ok(()) +} + fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F, From f60185ce59415de3e008f9ef4e36f238c127855e Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sat, 20 Apr 2019 17:07:57 +0100 Subject: [PATCH 21/29] Clone for the win --- src/arrayformat.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 9b238aeeb..32bf90286 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -87,7 +87,7 @@ fn format_array_v2( mut format: F, limit: Ix) -> fmt::Result where - F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, + F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result + Clone, D: Dimension, S: Data, { @@ -109,7 +109,7 @@ where for index in indexes_to_be_printed { match index { Some(i) => format_array_v2( - &view.index_axis(Axis(0), i), f, format, limit + &view.index_axis(Axis(0), i), f, format.clone(), limit )?, None => { writeln!(f, "...,")? From 198d6899ac83347836143d921d10429bd3d3d4c7 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sat, 20 Apr 2019 17:11:49 +0100 Subject: [PATCH 22/29] Cast to 1d array --- src/arrayformat.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 32bf90286..a0a4b0c2c 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -15,7 +15,7 @@ use super::{ Ix }; use crate::dimension::IntoDimension; -use crate::aliases::ArrayViewD; +use crate::aliases::Ix1; const PRINT_ELEMENTS_LIMIT: Ix = 3; @@ -55,27 +55,13 @@ fn get_highest_changed_axis(index: &[Ix], prev_index: &[Ix]) -> Option { .next() } -fn format_1d_array( - view: &ArrayBase, - f: &mut fmt::Formatter, - mut format: F, - limit: Ix) -> fmt::Result - where - F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, - D: Dimension, - S: Data, -{ - unimplemented!() -} - -fn format_multidimensional_array( - view: &ArrayBase, +fn format_1d_array( + view: &ArrayBase, f: &mut fmt::Formatter, mut format: F, limit: Ix) -> fmt::Result where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, - D: Dimension, S: Data, { unimplemented!() @@ -94,7 +80,7 @@ where let view = view.view().into_dyn(); match view.shape() { [] => format(view.iter().next().unwrap(), f)?, - [_] => format_1d_array(&view, f, format, limit)?, + [_] => format_1d_array(&view.into_dimensionality::().unwrap(), f, format, limit)?, shape => { let first_axis_length = shape[0]; let indexes_to_be_printed: Vec> = if first_axis_length <= 2 * limit { From c1036fb273e017bce2d138b562d02020af531aeb Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sat, 20 Apr 2019 17:30:04 +0100 Subject: [PATCH 23/29] First and last elements have to be special cased. Done for multidimensional --- src/arrayformat.rs | 167 ++++++++------------------------------------- 1 file changed, 29 insertions(+), 138 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index a0a4b0c2c..d0dec54ed 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -14,47 +14,10 @@ use super::{ NdProducer, Ix }; -use crate::dimension::IntoDimension; use crate::aliases::Ix1; const PRINT_ELEMENTS_LIMIT: Ix = 3; -fn get_overflow_axes(shape: &[Ix], limit: usize) -> Vec { - shape.iter() - .enumerate() - .rev() - .filter(|(_, axis_size)| **axis_size > 2 * limit) - .map(|(axis, _)| axis) - .collect() -} - -fn get_highest_axis_to_skip(overflow_axes: &Vec, - shape: &[Ix], - index: &[Ix], - limit: &usize) -> Option { - overflow_axes.iter() - .filter(|&axis| { - if *axis == shape.len() - 1 { - return false - }; - let sa_idx_max = shape[*axis]; - let sa_idx_val = index[*axis]; - sa_idx_val >= *limit && sa_idx_val < sa_idx_max - *limit - }) - .min() - .map(|v| *v) -} - -fn get_highest_changed_axis(index: &[Ix], prev_index: &[Ix]) -> Option { - index.iter() - .take(index.len() - 1) - .zip(prev_index.iter()) - .enumerate() - .filter(|(_, (a, b))| a != b) - .map(|(i, _)| i) - .next() -} - fn format_1d_array( view: &ArrayBase, f: &mut fmt::Formatter, @@ -64,10 +27,27 @@ fn format_1d_array( F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, S: Data, { - unimplemented!() + let n = view.len(); + let indexes_to_be_printed: Vec> = if n <= 2 * limit { + (0..n).map(|x| Some(x)).collect() + } else { + let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); + v.push(None); + v.extend((n-limit..n).map(|x| Some(x))); + v + }; + write!(f, "[")?; + for index in indexes_to_be_printed { + match index { + Some(i) => format(&view[i], f)?, + None => write!(f, ", ..., ")?, + } + } + write!(f, "]")?; + Ok(()) } -fn format_array_v2( +fn format_array( view: &ArrayBase, f: &mut fmt::Formatter, mut format: F, @@ -91,113 +71,24 @@ where v.extend((first_axis_length-limit..first_axis_length).map(|x| Some(x))); v }; - write!(f, "[")?; + writeln!(f, "[")?; for index in indexes_to_be_printed { match index { - Some(i) => format_array_v2( - &view.index_axis(Axis(0), i), f, format.clone(), limit - )?, + Some(i) => { + write!(f, " ")?; + format_array( + &view.index_axis(Axis(0), i), f, format.clone(), limit + )?; + writeln!(f, ",")? + }, None => { - writeln!(f, "...,")? + writeln!(f, " ...,")? } } } - write!(f, "]")?; - } - } - Ok(()) -} - -fn format_array(view: &ArrayBase, - f: &mut fmt::Formatter, - mut format: F, - limit: Ix) -> fmt::Result - where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, - D: Dimension, - S: Data, -{ - if view.shape().is_empty() { - // Handle 0-dimensional array case first - return format(view.iter().next().unwrap(), f) - } - - let overflow_axes: Vec = get_overflow_axes(view.shape(), limit); - - let ndim = view.ndim(); - let nth_idx_max = view.shape()[ndim-1]; - - // None will be an empty iter. - let mut last_index = match view.dim().into_dimension().first_index() { - None => view.dim().into_dimension().clone(), - Some(ix) => ix, - }; - write!(f, "{}", "[".repeat(ndim))?; - // Shows if ellipses for horizontal split were printed. - let mut printed_ellipses_h = vec![false; ndim]; - // Shows if the row was printed for the first time after horizontal split. - let mut no_rows_after_skip_yet = false; - - // Simply use the indexed iterator, and take the index wraparounds - // as cues for when to add []'s and how many to add. - for (index, elt) in view.indexed_iter() { - let index = index.into_dimension(); - - let skip_row_for_axis = get_highest_axis_to_skip( - &overflow_axes, - view.shape(), - index.slice(), - &limit - ); - if skip_row_for_axis.is_some() { - no_rows_after_skip_yet = true; - } - - let max_changed_idx = get_highest_changed_axis(index.slice(), last_index.slice()); - if let Some(i) = max_changed_idx { - printed_ellipses_h.iter_mut().skip(i + 1).for_each(|e| { *e = false; }); - - if skip_row_for_axis.is_none() { - // New row. - // # of ['s needed - let n = ndim - i - 1; - if !no_rows_after_skip_yet { - write!(f, "{}", "]".repeat(n))?; - writeln!(f, ",")?; - } - no_rows_after_skip_yet = false; - write!(f, "{}", " ".repeat(ndim - n))?; - write!(f, "{}", "[".repeat(n))?; - } else if !printed_ellipses_h[skip_row_for_axis.unwrap()] { - let ax = skip_row_for_axis.unwrap(); - let n = ndim - i - 1; - write!(f, "{}", "]".repeat(n))?; - writeln!(f, ",")?; - write!(f, "{}", " ".repeat(ax + 1))?; - writeln!(f, "...,")?; - printed_ellipses_h[ax] = true; - } - last_index = index.clone(); - } - - if skip_row_for_axis.is_none() { - let nth_idx_op = index.slice().iter().last(); - if overflow_axes.contains(&(ndim - 1)) { - let nth_idx_val = nth_idx_op.unwrap(); - if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) { - if nth_idx_val == &limit { - write!(f, ", ...")?; - } - continue; - } - } - - if max_changed_idx.is_none() && !index.slice().iter().all(|x| *x == 0) { - write!(f, ", ")?; - } - format(elt, f)?; + writeln!(f, "]")?; } } - write!(f, "{}", "]".repeat(ndim))?; Ok(()) } From 5336b1065db9b1f2434beab36ca23b0cb83a2a14 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 21 Apr 2019 09:56:13 +0100 Subject: [PATCH 24/29] Extract in a separate function --- src/arrayformat.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index d0dec54ed..1ebbc76a3 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -28,14 +28,7 @@ fn format_1d_array( S: Data, { let n = view.len(); - let indexes_to_be_printed: Vec> = if n <= 2 * limit { - (0..n).map(|x| Some(x)).collect() - } else { - let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); - v.push(None); - v.extend((n-limit..n).map(|x| Some(x))); - v - }; + let indexes_to_be_printed = indexes_to_be_printed(n, limit); write!(f, "[")?; for index in indexes_to_be_printed { match index { @@ -47,6 +40,17 @@ fn format_1d_array( Ok(()) } +fn indexes_to_be_printed(length: usize, limit: usize) -> Vec> { + if length <= 2 * limit { + (0..length).map(|x| Some(x)).collect() + } else { + let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); + v.push(None); + v.extend((length-limit..length).map(|x| Some(x))); + v + } +} + fn format_array( view: &ArrayBase, f: &mut fmt::Formatter, @@ -63,14 +67,7 @@ where [_] => format_1d_array(&view.into_dimensionality::().unwrap(), f, format, limit)?, shape => { let first_axis_length = shape[0]; - let indexes_to_be_printed: Vec> = if first_axis_length <= 2 * limit { - (0..first_axis_length).map(|x| Some(x)).collect() - } else { - let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); - v.push(None); - v.extend((first_axis_length-limit..first_axis_length).map(|x| Some(x))); - v - }; + let indexes_to_be_printed = indexes_to_be_printed(first_axis_length, limit); writeln!(f, "[")?; for index in indexes_to_be_printed { match index { From 4fa8a62d6295017e10549bbdc652e91841d1a27a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 21 Apr 2019 15:56:34 +0100 Subject: [PATCH 25/29] Tests are passing --- src/arrayformat.rs | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 1ebbc76a3..b6018734d 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -29,11 +29,17 @@ fn format_1d_array( { let n = view.len(); let indexes_to_be_printed = indexes_to_be_printed(n, limit); + let last_index = indexes_to_be_printed.len(); write!(f, "[")?; - for index in indexes_to_be_printed { + for (j, index) in indexes_to_be_printed.into_iter().enumerate() { match index { - Some(i) => format(&view[i], f)?, - None => write!(f, ", ..., ")?, + Some(i) => { + format(&view[i], f)?; + if j != (last_index-1) { + write!(f, ", ")?; + } + }, + None => write!(f, "..., ")?, } } write!(f, "]")?; @@ -61,29 +67,35 @@ where D: Dimension, S: Data, { - let view = view.view().into_dyn(); + if view.shape().iter().any(|&x| x == 0) { + write!(f, "{}{}", "[".repeat(view.ndim()), "]".repeat(view.ndim()))?; + return Ok(()) + } match view.shape() { [] => format(view.iter().next().unwrap(), f)?, - [_] => format_1d_array(&view.into_dimensionality::().unwrap(), f, format, limit)?, + [_] => format_1d_array(&view.view().into_dimensionality::().unwrap(), f, format, limit)?, shape => { + let view = view.view().into_dyn(); let first_axis_length = shape[0]; let indexes_to_be_printed = indexes_to_be_printed(first_axis_length, limit); - writeln!(f, "[")?; - for index in indexes_to_be_printed { + let n_to_be_printed = indexes_to_be_printed.len(); + write!(f, "[")?; + for (j, index) in indexes_to_be_printed.into_iter().enumerate() { match index { Some(i) => { - write!(f, " ")?; format_array( &view.index_axis(Axis(0), i), f, format.clone(), limit )?; - writeln!(f, ",")? + if j != (n_to_be_printed -1) { + write!(f, ",\n ")? + } }, None => { - writeln!(f, " ...,")? + write!(f, "...,\n ")? } } } - writeln!(f, "]")?; + write!(f, "]")?; } } Ok(()) @@ -183,7 +195,8 @@ mod formatting_with_omit { let a: Array2 = arr2(&[[], []]); let actual_output = format!("{}", a); let expected_output = String::from("[[]]"); - assert_eq!(actual_output, expected_output); + print_output_diff(&expected_output, &actual_output); + assert_eq!(expected_output, actual_output); } #[test] @@ -191,7 +204,8 @@ mod formatting_with_omit { let a = Array3::::zeros((3, 0, 4)); let actual_output = format!("{}", a); let expected_output = String::from("[[[]]]"); - assert_eq!(actual_output, expected_output); + print_output_diff(&expected_output, &actual_output); + assert_eq!(expected_output, actual_output); } #[test] @@ -200,7 +214,8 @@ mod formatting_with_omit { let a = arr0(element); let actual_output = format!("{}", a); let expected_output = format!("{}", element); - assert_eq!(actual_output, expected_output); + print_output_diff(&expected_output, &actual_output); + assert_eq!(expected_output, actual_output); } #[test] From e659390e57827c1191d887ece1a21f542ed4db93 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 21 Apr 2019 16:10:01 +0100 Subject: [PATCH 26/29] Minor improvements --- src/arrayformat.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index b6018734d..a7e87f32f 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -28,14 +28,15 @@ fn format_1d_array( S: Data, { let n = view.len(); - let indexes_to_be_printed = indexes_to_be_printed(n, limit); - let last_index = indexes_to_be_printed.len(); + let to_be_printed = to_be_printed(n, limit); + let n_to_be_printed = to_be_printed.len(); + let is_last = |j| j == n_to_be_printed - 1; write!(f, "[")?; - for (j, index) in indexes_to_be_printed.into_iter().enumerate() { + for (j, index) in to_be_printed.into_iter().enumerate() { match index { Some(i) => { format(&view[i], f)?; - if j != (last_index-1) { + if !is_last(j) { write!(f, ", ")?; } }, @@ -46,7 +47,10 @@ fn format_1d_array( Ok(()) } -fn indexes_to_be_printed(length: usize, limit: usize) -> Vec> { +// Returns what indexes should be printed for a certain axis. +// If the axis is longer than 2 * limit, a `None` is inserted +// where indexes are being omitted. +fn to_be_printed(length: usize, limit: usize) -> Vec> { if length <= 2 * limit { (0..length).map(|x| Some(x)).collect() } else { @@ -67,32 +71,44 @@ where D: Dimension, S: Data, { + // If any of the axes has 0 length, we return the same empty array representation + // e.g. [[]] for 2-d arrays if view.shape().iter().any(|&x| x == 0) { write!(f, "{}{}", "[".repeat(view.ndim()), "]".repeat(view.ndim()))?; return Ok(()) } match view.shape() { + // If it's 0 dimensional, we just print out the scalar [] => format(view.iter().next().unwrap(), f)?, + // We delegate 1-dimensional arrays to a specialized function [_] => format_1d_array(&view.view().into_dimensionality::().unwrap(), f, format, limit)?, + // For n-dimensional arrays, we proceed recursively shape => { + // Cast into a dynamically dimensioned view + // This is required to be able to use `index_axis` let view = view.view().into_dyn(); - let first_axis_length = shape[0]; - let indexes_to_be_printed = indexes_to_be_printed(first_axis_length, limit); - let n_to_be_printed = indexes_to_be_printed.len(); + // We start by checking what indexes from the first axis should be printed + // We put a `None` in the middle if we are omitting elements + let to_be_printed = to_be_printed(shape[0], limit); + + let n_to_be_printed = to_be_printed.len(); + let is_last = |j| j == n_to_be_printed - 1; + write!(f, "[")?; - for (j, index) in indexes_to_be_printed.into_iter().enumerate() { + for (j, index) in to_be_printed.into_iter().enumerate() { match index { Some(i) => { + // Proceed recursively with the (n-1)-dimensional slice format_array( &view.index_axis(Axis(0), i), f, format.clone(), limit )?; - if j != (n_to_be_printed -1) { + // We need to add a separator after each slice, + // apart from the last one + if !is_last(j) { write!(f, ",\n ")? } }, - None => { - write!(f, "...,\n ")? - } + None => write!(f, "...,\n ")? } } write!(f, "]")?; From 0abff2ad521b115d519ae32f3f9abe957e3717f0 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 21 Apr 2019 16:12:42 +0100 Subject: [PATCH 27/29] Formatting --- src/arrayformat.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index a7e87f32f..c2af80ef7 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -27,10 +27,11 @@ fn format_1d_array( F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result, S: Data, { - let n = view.len(); - let to_be_printed = to_be_printed(n, limit); + let to_be_printed = to_be_printed(view.len(), limit); + let n_to_be_printed = to_be_printed.len(); let is_last = |j| j == n_to_be_printed - 1; + write!(f, "[")?; for (j, index) in to_be_printed.into_iter().enumerate() { match index { From e049abd1ddef2ae2e2ab9d50445ff04528d32270 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 23 Apr 2019 20:16:42 +0100 Subject: [PATCH 28/29] Remove closure --- src/arrayformat.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index c2af80ef7..7613e863b 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -30,14 +30,13 @@ fn format_1d_array( let to_be_printed = to_be_printed(view.len(), limit); let n_to_be_printed = to_be_printed.len(); - let is_last = |j| j == n_to_be_printed - 1; write!(f, "[")?; for (j, index) in to_be_printed.into_iter().enumerate() { match index { Some(i) => { format(&view[i], f)?; - if !is_last(j) { + if j != n_to_be_printed - 1 { write!(f, ", ")?; } }, @@ -93,7 +92,6 @@ where let to_be_printed = to_be_printed(shape[0], limit); let n_to_be_printed = to_be_printed.len(); - let is_last = |j| j == n_to_be_printed - 1; write!(f, "[")?; for (j, index) in to_be_printed.into_iter().enumerate() { @@ -105,7 +103,7 @@ where )?; // We need to add a separator after each slice, // apart from the last one - if !is_last(j) { + if j != n_to_be_printed - 1 { write!(f, ",\n ")? } }, From 83c9f08cbf332bff28f0f87b9642950fbacc8370 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 23 Apr 2019 20:22:11 +0100 Subject: [PATCH 29/29] Use custom enum --- src/arrayformat.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 7613e863b..894215d8c 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -34,29 +34,34 @@ fn format_1d_array( write!(f, "[")?; for (j, index) in to_be_printed.into_iter().enumerate() { match index { - Some(i) => { + PrintableCell::ElementIndex(i) => { format(&view[i], f)?; if j != n_to_be_printed - 1 { write!(f, ", ")?; } }, - None => write!(f, "..., ")?, + PrintableCell::Ellipses => write!(f, "..., ")?, } } write!(f, "]")?; Ok(()) } +enum PrintableCell { + ElementIndex(usize), + Ellipses, +} + // Returns what indexes should be printed for a certain axis. -// If the axis is longer than 2 * limit, a `None` is inserted +// If the axis is longer than 2 * limit, a `Ellipses` is inserted // where indexes are being omitted. -fn to_be_printed(length: usize, limit: usize) -> Vec> { +fn to_be_printed(length: usize, limit: usize) -> Vec { if length <= 2 * limit { - (0..length).map(|x| Some(x)).collect() + (0..length).map(|x| PrintableCell::ElementIndex(x)).collect() } else { - let mut v: Vec> = (0..limit).map(|x| Some(x)).collect(); - v.push(None); - v.extend((length-limit..length).map(|x| Some(x))); + let mut v: Vec = (0..limit).map(|x| PrintableCell::ElementIndex(x)).collect(); + v.push(PrintableCell::Ellipses); + v.extend((length-limit..length).map(|x| PrintableCell::ElementIndex(x))); v } } @@ -96,7 +101,7 @@ where write!(f, "[")?; for (j, index) in to_be_printed.into_iter().enumerate() { match index { - Some(i) => { + PrintableCell::ElementIndex(i) => { // Proceed recursively with the (n-1)-dimensional slice format_array( &view.index_axis(Axis(0), i), f, format.clone(), limit @@ -107,7 +112,7 @@ where write!(f, ",\n ")? } }, - None => write!(f, "...,\n ")? + PrintableCell::Ellipses => write!(f, "...,\n ")? } } write!(f, "]")?;