From fe4365c9035ebf268d9d0c0e0d3e6100426e1527 Mon Sep 17 00:00:00 2001
From: "andrei.papou" <popow.andrej2009@yandex.ru>
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<A, S, D>(arr: &ArrayBase<S, D>, limit: usize) -> ArrayDisplayMode
+        where S: Data<Elem=A>,
+              D: Dimension
+    {
+        let last_dim = arr.shape().len() - 1;
+
+        let mut overflow_axis_pair: (Option<usize>, Option<usize>) = (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<Ix> {
+        match self {
+            ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => {
+                Some(axis + 1usize)
+            },
+            _ => None
+        }
+    }
+}
+
+fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
+                                  f: &mut fmt::Formatter,
+                                  mut format: F,
+                                  limit: usize) -> fmt::Result
+    where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
+          D: Dimension,
+          S: Data<Elem=A>,
+{
+    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<A, S, D, F>(view: &ArrayBase<S, D>, 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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
 {
     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" <popow.andrej2009@yandex.ru>
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<Elem=A>,
               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<usize>, Option<usize>) = (None, None);
         for (axis, axis_size) in arr.shape().iter().enumerate().rev() {
@@ -85,7 +90,7 @@ fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
     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<A, S, D, F>(view: &ArrayBase<S, D>,
 
         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 <popow.andrej2009@yandex.ru>
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<A, S, D>(arr: &ArrayBase<S, D>, limit: usize) -> ArrayDisplayMode
-        where S: Data<Elem=A>,
-              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<usize>, Option<usize>) = (None, None);
-        for (axis, axis_size) in arr.shape().iter().enumerate().rev() {
+        let mut overflow_axes: Vec<Ix> = 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<Ix> {
+    fn h_split_axis(&self) -> Option<Ix> {
         match self {
             ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => {
-                Some(axis + 1usize)
+                Some(*axis)
             },
             _ => None
         }
     }
+
+    fn h_split_offset(&self) -> Option<Ix> {
+        match self.h_split_axis() {
+            Some(axis) => Some(axis + 1usize),
+            None => None
+        }
+    }
 }
 
 fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
-                                  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<Elem=A>,
 {
-    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<A, S, D, F>(view: &ArrayBase<S, D>,
             .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<S, D>
         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 <popow.andrej2009@yandex.ru>
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<Ix>),
+    // Both `OmitV` and `OmitH` hold.
+    OmitBoth(Vec<Ix>),
 }
 
-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<Ix> = 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<Ix> {
+    fn h_axes_iter(&self) -> Option<Iter<Ix>> {
         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<Ix> {
-        match self.h_split_axis() {
-            Some(axis) => Some(axis + 1usize),
-            None => None
-        }
-    }
 }
 
 fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
@@ -108,7 +98,7 @@ fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
     // 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<A, S, D, F>(view: &ArrayBase<S, D>,
         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<A, S, D, F>(view: &ArrayBase<S, D>,
             .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<A, S, D, F>(view: &ArrayBase<S, D>,
                     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<A, S, D, F>(view: &ArrayBase<S, D>,
             }
         }
 
-        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<S, D>
 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" <popow.andrej2009@yandex.ru>
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<Ix>),
-    // Both `OmitV` and `OmitH` hold.
-    OmitBoth(Vec<Ix>),
-}
-
 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<Ix> = 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<Iter<Ix>> {
-        match self {
-            ArrayDisplayMode::OmitH(v) | ArrayDisplayMode::OmitBoth(v) => {
-                Some(v.iter())
-            },
-            _ => None
-        }
-    }
-}
-
 fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
                                f: &mut fmt::Formatter,
                                mut format: F,
@@ -81,19 +25,27 @@ fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
           D: Dimension,
           S: Data<Elem=A>,
 {
-    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<Ix> = 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<A, S, D, F>(view: &ArrayBase<S, D>,
         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<A, S, D, F>(view: &ArrayBase<S, D>,
                     // # 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<A, S, D, F>(view: &ArrayBase<S, D>,
         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<A, S, D, F>(view: &ArrayBase<S, D>,
             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<S, D>
         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 <popow.andrej2009@yandex.ru>
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<A, S, D, F>(view: &ArrayBase<S, D>,
           S: Data<Elem=A>,
 {
     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<Ix> = view.shape().iter()

From 51c4e11fb6888eb73bfeac03ee842fa1d6e4eed0 Mon Sep 17 00:00:00 2001
From: andrei-papou <popow.andrej2009@yandex.ru>
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<A, S, D, F>(view: &ArrayBase<S, D>,
                                f: &mut fmt::Formatter,
@@ -142,6 +142,7 @@ fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
     Ok(())
 }
 
+#[allow(dead_code)]
 fn format_array<A, S, D, F>(view: &ArrayBase<S, D>, 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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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::<i32>::zeros((3, 4));

From 0d11708851a973e469b548a6139c95c4267db019 Mon Sep 17 00:00:00 2001
From: andrei-papou <popow.andrej2009@yandex.ru>
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 <popow.andrej2009@yandex.ru>
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<A, S, D, F>(view: &ArrayBase<S, D>,
                                f: &mut fmt::Formatter,
@@ -291,3 +291,130 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase<S, D>
         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::<i32>::zeros((3, 4));

From 3aa8abe2ccb1c3d6f5e5f764597b7ac12efc573e Mon Sep 17 00:00:00 2001
From: LukeMathWalker <lucapalmieri1993@hotmail.com>
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<A, S, D, F>(view: &ArrayBase<S, D>,
     Ok(())
 }
 
-#[allow(dead_code)]
-fn format_array<A, S, D, F>(view: &ArrayBase<S, D>, f: &mut fmt::Formatter,
-                            mut format: F)
-    -> fmt::Result
-    where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
-          D: Dimension,
-          S: Data<Elem=A>,
-{
-    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 <lucapalmieri1993@hotmail.com>
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<A, S, D, F>(view: &ArrayBase<S, D>,
-                               f: &mut fmt::Formatter,
-                               mut format: F,
-                               limit: Ix) -> fmt::Result
+fn format_array<A, S, D, F>(view: &ArrayBase<S, D>,
+                            f: &mut fmt::Formatter,
+                            mut format: F,
+                            limit: Ix) -> fmt::Result
     where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
           D: Dimension,
           S: Data<Elem=A>,
@@ -151,7 +151,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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<S, D>
     where S: Data<Elem=A>,
 {
     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 <lucapalmieri1993@hotmail.com>
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<A, S, D, F>(view: &ArrayBase<S, D>,
         .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 <lucapalmieri1993@hotmail.com>
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<A, S, D, F>(view: &ArrayBase<S, D>,
         .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 <lucapalmieri1993@hotmail.com>
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 <lucapalmieri1993@hotmail.com>
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<u32> = 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 <lucapalmieri1993@hotmail.com>
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::<f32>::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 <lucapalmieri1993@hotmail.com>
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<A, S, D, F>(view: &ArrayBase<S, D>,
     // 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<A, S, D, F>(view: &ArrayBase<S, D>,
 
         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 <popow.andrej2009@yandex.ru>
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<usize> {
+    shape.iter()
+        .enumerate()
+        .rev()
+        .filter(|(_, axis_size)| **axis_size > 2 * limit)
+        .map(|(axis, _)| axis)
+        .collect()
+}
+
+fn get_highest_axis_to_skip(overflow_axes: &Vec<usize>,
+                            shape: &[Ix],
+                            index: &[Ix],
+                            limit: &usize) -> Option<usize> {
+    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<usize> {
+    index.iter()
+        .take(index.len() - 1)
+        .zip(prev_index.iter())
+        .enumerate()
+        .filter(|(_, (a, b))| a != b)
+        .map(|(i, _)| i)
+        .next()
+}
+
 fn format_array<A, S, D, F>(view: &ArrayBase<S, D>,
                             f: &mut fmt::Formatter,
                             mut format: F,
@@ -30,12 +66,7 @@ fn format_array<A, S, D, F>(view: &ArrayBase<S, D>,
         return format(view.iter().next().unwrap(), f)
     }
 
-    let overflow_axes: Vec<Ix> = view.shape().iter()
-        .enumerate()
-        .rev()
-        .filter(|(_, axis_size)| **axis_size > 2 * limit)
-        .map(|(axis, _)| axis)
-        .collect();
+    let overflow_axes: Vec<Ix> = 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<A, S, D, F>(view: &ArrayBase<S, D>,
         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<A, S, D, F>(view: &ArrayBase<S, D>,
     // 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 <lpalmieri@truelayer.com>
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<usize>,
                             index: &[Ix],
                             limit: &usize) -> Option<usize> {
     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 <lpalmieri@truelayer.com>
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<usize> {
         .next()
 }
 
+fn format_1d_array<A, S, D, F>(
+    view: &ArrayBase<S, D>,
+    f: &mut fmt::Formatter,
+    mut format: F,
+    limit: Ix) -> fmt::Result
+    where
+        F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
+        D: Dimension,
+        S: Data<Elem=A>,
+{
+    unimplemented!()
+}
+
+fn format_multidimensional_array<A, S, D, F>(
+    view: &ArrayBase<S, D>,
+    f: &mut fmt::Formatter,
+    mut format: F,
+    limit: Ix) -> fmt::Result
+    where
+        F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
+        D: Dimension,
+        S: Data<Elem=A>,
+{
+    unimplemented!()
+}
+
+fn format_array_v2<A, S, D, F>(
+    view: &ArrayBase<S, D>,
+    f: &mut fmt::Formatter,
+    mut format: F,
+    limit: Ix) -> fmt::Result
+where
+    F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
+    D: Dimension,
+    S: Data<Elem=A>,
+{
+    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<Option<usize>> = if first_axis_length <= 2 * limit {
+                (0..first_axis_length).map(|x| Some(x)).collect()
+            } else {
+                let mut v: Vec<Option<usize>> = (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<A, S, D, F>(view: &ArrayBase<S, D>,
                             f: &mut fmt::Formatter,
                             mut format: F,

From f60185ce59415de3e008f9ef4e36f238c127855e Mon Sep 17 00:00:00 2001
From: LukeMathWalker <lpalmieri@truelayer.com>
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<A, S, D, F>(
     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<Elem=A>,
 {
@@ -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 <lpalmieri@truelayer.com>
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<usize> {
         .next()
 }
 
-fn format_1d_array<A, S, D, F>(
-    view: &ArrayBase<S, D>,
-    f: &mut fmt::Formatter,
-    mut format: F,
-    limit: Ix) -> fmt::Result
-    where
-        F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
-        D: Dimension,
-        S: Data<Elem=A>,
-{
-    unimplemented!()
-}
-
-fn format_multidimensional_array<A, S, D, F>(
-    view: &ArrayBase<S, D>,
+fn format_1d_array<A, S, F>(
+    view: &ArrayBase<S, Ix1>,
     f: &mut fmt::Formatter,
     mut format: F,
     limit: Ix) -> fmt::Result
     where
         F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
-        D: Dimension,
         S: Data<Elem=A>,
 {
     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::<Ix1>().unwrap(), f, format, limit)?,
         shape => {
             let first_axis_length = shape[0];
             let indexes_to_be_printed: Vec<Option<usize>> = if first_axis_length <= 2 * limit {

From c1036fb273e017bce2d138b562d02020af531aeb Mon Sep 17 00:00:00 2001
From: LukeMathWalker <lpalmieri@truelayer.com>
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<usize> {
-    shape.iter()
-        .enumerate()
-        .rev()
-        .filter(|(_, axis_size)| **axis_size > 2 * limit)
-        .map(|(axis, _)| axis)
-        .collect()
-}
-
-fn get_highest_axis_to_skip(overflow_axes: &Vec<usize>,
-                            shape: &[Ix],
-                            index: &[Ix],
-                            limit: &usize) -> Option<usize> {
-    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<usize> {
-    index.iter()
-        .take(index.len() - 1)
-        .zip(prev_index.iter())
-        .enumerate()
-        .filter(|(_, (a, b))| a != b)
-        .map(|(i, _)| i)
-        .next()
-}
-
 fn format_1d_array<A, S, F>(
     view: &ArrayBase<S, Ix1>,
     f: &mut fmt::Formatter,
@@ -64,10 +27,27 @@ fn format_1d_array<A, S, F>(
         F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
         S: Data<Elem=A>,
 {
-    unimplemented!()
+    let n = view.len();
+    let indexes_to_be_printed: Vec<Option<usize>> = if n <= 2 * limit {
+        (0..n).map(|x| Some(x)).collect()
+    } else {
+        let mut v: Vec<Option<usize>> = (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<A, S, D, F>(
+fn format_array<A, S, D, F>(
     view: &ArrayBase<S, D>,
     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<A, S, D, F>(view: &ArrayBase<S, D>,
-                            f: &mut fmt::Formatter,
-                            mut format: F,
-                            limit: Ix) -> fmt::Result
-    where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
-          D: Dimension,
-          S: Data<Elem=A>,
-{
-    if view.shape().is_empty() {
-        // Handle 0-dimensional array case first
-        return format(view.iter().next().unwrap(), f)
-    }
-
-    let overflow_axes: Vec<Ix> = 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 <lpalmieri@truelayer.com>
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<A, S, F>(
         S: Data<Elem=A>,
 {
     let n = view.len();
-    let indexes_to_be_printed: Vec<Option<usize>> = if n <= 2 * limit {
-        (0..n).map(|x| Some(x)).collect()
-    } else {
-        let mut v: Vec<Option<usize>> = (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<A, S, F>(
     Ok(())
 }
 
+fn indexes_to_be_printed(length: usize, limit: usize) -> Vec<Option<usize>> {
+    if length <= 2 * limit {
+        (0..length).map(|x| Some(x)).collect()
+    } else {
+        let mut v: Vec<Option<usize>> = (0..limit).map(|x| Some(x)).collect();
+        v.push(None);
+        v.extend((length-limit..length).map(|x| Some(x)));
+        v
+    }
+}
+
 fn format_array<A, S, D, F>(
     view: &ArrayBase<S, D>,
     f: &mut fmt::Formatter,
@@ -63,14 +67,7 @@ where
         [_] => format_1d_array(&view.into_dimensionality::<Ix1>().unwrap(), f, format, limit)?,
         shape => {
             let first_axis_length = shape[0];
-            let indexes_to_be_printed: Vec<Option<usize>> = if first_axis_length <= 2 * limit {
-                (0..first_axis_length).map(|x| Some(x)).collect()
-            } else {
-                let mut v: Vec<Option<usize>> = (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 <lpalmieri@truelayer.com>
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<A, S, F>(
 {
     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<Elem=A>,
 {
-    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::<Ix1>().unwrap(), f, format, limit)?,
+        [_] => format_1d_array(&view.view().into_dimensionality::<Ix1>().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<u32> = 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::<f32>::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 <lpalmieri@truelayer.com>
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<A, S, F>(
         S: Data<Elem=A>,
 {
     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<A, S, F>(
     Ok(())
 }
 
-fn indexes_to_be_printed(length: usize, limit: usize) -> Vec<Option<usize>> {
+// 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<Option<usize>> {
     if length <= 2 * limit {
         (0..length).map(|x| Some(x)).collect()
     } else {
@@ -67,32 +71,44 @@ where
     D: Dimension,
     S: Data<Elem=A>,
 {
+    // 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::<Ix1>().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 <lpalmieri@truelayer.com>
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<A, S, F>(
         F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
         S: Data<Elem=A>,
 {
-    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 <lpalmieri@truelayer.com>
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<A, S, F>(
     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 <lpalmieri@truelayer.com>
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<A, S, F>(
     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<Option<usize>> {
+fn to_be_printed(length: usize, limit: usize) -> Vec<PrintableCell> {
     if length <= 2 * limit {
-        (0..length).map(|x| Some(x)).collect()
+        (0..length).map(|x| PrintableCell::ElementIndex(x)).collect()
     } else {
-        let mut v: Vec<Option<usize>> = (0..limit).map(|x| Some(x)).collect();
-        v.push(None);
-        v.extend((length-limit..length).map(|x| Some(x)));
+        let mut v: Vec<PrintableCell> = (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, "]")?;