ndarray/
arrayformat.rs

1// Copyright 2014-2016 bluss and ndarray developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer};
9use crate::aliases::{Ix1, IxDyn};
10use std::fmt;
11use alloc::format;
12
13/// Default threshold, below this element count, we don't ellipsize
14const ARRAY_MANY_ELEMENT_LIMIT: usize = 500;
15/// Limit of element count for non-last axes before overflowing with an ellipsis.
16const AXIS_LIMIT_STACKED: usize = 6;
17/// Limit for next to last axis (printed as column)
18/// An odd number because one element uses the same space as the ellipsis.
19const AXIS_LIMIT_COL: usize = 11;
20/// Limit for last axis (printed as row)
21/// An odd number because one element uses approximately the space of the ellipsis.
22const AXIS_LIMIT_ROW: usize = 11;
23
24#[cfg(test)]
25// Test value to use for size of overflowing 2D arrays
26const AXIS_2D_OVERFLOW_LIMIT: usize = 22;
27
28/// The string used as an ellipsis.
29const ELLIPSIS: &str = "...";
30
31#[derive(Clone, Debug)]
32struct FormatOptions {
33    axis_collapse_limit: usize,
34    axis_collapse_limit_next_last: usize,
35    axis_collapse_limit_last: usize,
36}
37
38impl FormatOptions {
39    pub(crate) fn default_for_array(nelem: usize, no_limit: bool) -> Self {
40        let default = Self {
41            axis_collapse_limit: AXIS_LIMIT_STACKED,
42            axis_collapse_limit_next_last: AXIS_LIMIT_COL,
43            axis_collapse_limit_last: AXIS_LIMIT_ROW,
44        };
45        default.set_no_limit(no_limit || nelem < ARRAY_MANY_ELEMENT_LIMIT)
46    }
47
48    fn set_no_limit(mut self, no_limit: bool) -> Self {
49        if no_limit {
50            self.axis_collapse_limit = std::usize::MAX;
51            self.axis_collapse_limit_next_last = std::usize::MAX;
52            self.axis_collapse_limit_last = std::usize::MAX;
53            self
54        } else {
55            self
56        }
57    }
58
59    /// Axis length collapse limit before ellipsizing, where `axis_rindex` is
60    /// the index of the axis from the back.
61    pub(crate) fn collapse_limit(&self, axis_rindex: usize) -> usize {
62        match axis_rindex {
63            0 => self.axis_collapse_limit_last,
64            1 => self.axis_collapse_limit_next_last,
65            _ => self.axis_collapse_limit,
66        }
67    }
68}
69
70/// Formats the contents of a list of items, using an ellipsis to indicate when
71/// the `length` of the list is greater than `limit`.
72///
73/// # Parameters
74///
75/// * `f`: The formatter.
76/// * `length`: The length of the list.
77/// * `limit`: The maximum number of items before overflow.
78/// * `separator`: Separator to write between items.
79/// * `ellipsis`: Ellipsis for indicating overflow.
80/// * `fmt_elem`: A function that formats an element in the list, given the
81///   formatter and the index of the item in the list.
82fn format_with_overflow(
83    f: &mut fmt::Formatter<'_>,
84    length: usize,
85    limit: usize,
86    separator: &str,
87    ellipsis: &str,
88    fmt_elem: &mut dyn FnMut(&mut fmt::Formatter, usize) -> fmt::Result,
89) -> fmt::Result {
90    if length == 0 {
91        // no-op
92    } else if length <= limit {
93        fmt_elem(f, 0)?;
94        for i in 1..length {
95            f.write_str(separator)?;
96            fmt_elem(f, i)?
97        }
98    } else {
99        let edge = limit / 2;
100        fmt_elem(f, 0)?;
101        for i in 1..edge {
102            f.write_str(separator)?;
103            fmt_elem(f, i)?;
104        }
105        f.write_str(separator)?;
106        f.write_str(ellipsis)?;
107        for i in length - edge..length {
108            f.write_str(separator)?;
109            fmt_elem(f, i)?
110        }
111    }
112    Ok(())
113}
114
115fn format_array<A, S, D, F>(
116    array: &ArrayBase<S, D>,
117    f: &mut fmt::Formatter<'_>,
118    format: F,
119    fmt_opt: &FormatOptions,
120) -> fmt::Result
121where
122    F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone,
123    D: Dimension,
124    S: Data<Elem = A>,
125{
126    // Cast into a dynamically dimensioned view
127    // This is required to be able to use `index_axis` for the recursive case
128    format_array_inner(array.view().into_dyn(), f, format, fmt_opt, 0, array.ndim())
129}
130
131fn format_array_inner<A, F>(
132    view: ArrayView<A, IxDyn>,
133    f: &mut fmt::Formatter<'_>,
134    mut format: F,
135    fmt_opt: &FormatOptions,
136    depth: usize,
137    full_ndim: usize,
138) -> fmt::Result
139where
140    F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone,
141{
142    // If any of the axes has 0 length, we return the same empty array representation
143    // e.g. [[]] for 2-d arrays
144    if view.is_empty() {
145        write!(f, "{}{}", "[".repeat(view.ndim()), "]".repeat(view.ndim()))?;
146        return Ok(());
147    }
148    match view.shape() {
149        // If it's 0 dimensional, we just print out the scalar
150        &[] => format(&view[[]], f)?,
151        // We handle 1-D arrays as a special case
152        &[len] => {
153            let view = view.view().into_dimensionality::<Ix1>().unwrap();
154            f.write_str("[")?;
155            format_with_overflow(
156                f,
157                len,
158                fmt_opt.collapse_limit(0),
159                ", ",
160                ELLIPSIS,
161                &mut |f, index| format(&view[index], f),
162            )?;
163            f.write_str("]")?;
164        }
165        // For n-dimensional arrays, we proceed recursively
166        shape => {
167            let blank_lines = "\n".repeat(shape.len() - 2);
168            let indent = " ".repeat(depth + 1);
169            let separator = format!(",\n{}{}", blank_lines, indent);
170
171            f.write_str("[")?;
172            let limit = fmt_opt.collapse_limit(full_ndim - depth - 1);
173            format_with_overflow(f, shape[0], limit, &separator, ELLIPSIS, &mut |f, index| {
174                format_array_inner(
175                    view.index_axis(Axis(0), index),
176                    f,
177                    format.clone(),
178                    fmt_opt,
179                    depth + 1,
180                    full_ndim,
181                )
182            })?;
183            f.write_str("]")?;
184        }
185    }
186    Ok(())
187}
188
189// NOTE: We can impl other fmt traits here
190/// Format the array using `Display` and apply the formatting parameters used
191/// to each element.
192///
193/// The array is shown in multiline style.
194impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
195where
196    S: Data<Elem = A>,
197{
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
200        format_array(self, f, <_>::fmt, &fmt_opt)
201    }
202}
203
204/// Format the array using `Debug` and apply the formatting parameters used
205/// to each element.
206///
207/// The array is shown in multiline style.
208impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
209where
210    S: Data<Elem = A>,
211{
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
214        format_array(self, f, <_>::fmt, &fmt_opt)?;
215
216        // Add extra information for Debug
217        write!(
218            f,
219            ", shape={:?}, strides={:?}, layout={:?}",
220            self.shape(),
221            self.strides(),
222            layout = self.view().layout()
223        )?;
224        match D::NDIM {
225            Some(ndim) => write!(f, ", const ndim={}", ndim)?,
226            None => write!(f, ", dynamic ndim={}", self.ndim())?,
227        }
228        Ok(())
229    }
230}
231
232/// Format the array using `LowerExp` and apply the formatting parameters used
233/// to each element.
234///
235/// The array is shown in multiline style.
236impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
237where
238    S: Data<Elem = A>,
239{
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
242        format_array(self, f, <_>::fmt, &fmt_opt)
243    }
244}
245
246/// Format the array using `UpperExp` and apply the formatting parameters used
247/// to each element.
248///
249/// The array is shown in multiline style.
250impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
251where
252    S: Data<Elem = A>,
253{
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
256        format_array(self, f, <_>::fmt, &fmt_opt)
257    }
258}
259/// Format the array using `LowerHex` and apply the formatting parameters used
260/// to each element.
261///
262/// The array is shown in multiline style.
263impl<'a, A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase<S, D>
264where
265    S: Data<Elem = A>,
266{
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
269        format_array(self, f, <_>::fmt, &fmt_opt)
270    }
271}
272
273/// Format the array using `Binary` and apply the formatting parameters used
274/// to each element.
275///
276/// The array is shown in multiline style.
277impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase<S, D>
278where
279    S: Data<Elem = A>,
280{
281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
283        format_array(self, f, <_>::fmt, &fmt_opt)
284    }
285}
286
287#[cfg(test)]
288mod formatting_with_omit {
289    use itertools::Itertools;
290    use std::fmt;
291    use alloc::string::String;
292    use alloc::vec::Vec;
293
294    use super::*;
295    use crate::prelude::*;
296
297    fn assert_str_eq(expected: &str, actual: &str) {
298        // use assert to avoid printing the strings twice on failure
299        assert!(
300            expected == actual,
301            "formatting assertion failed\nexpected:\n{}\nactual:\n{}\n",
302            expected,
303            actual,
304        );
305    }
306
307    fn ellipsize(
308        limit: usize,
309        sep: &str,
310        elements: impl IntoIterator<Item = impl fmt::Display>,
311    ) -> String {
312        let elements = elements.into_iter().collect::<Vec<_>>();
313        let edge = limit / 2;
314        if elements.len() <= limit {
315            format!("{}", elements.iter().format(sep))
316        } else {
317            format!(
318                "{}{}{}{}{}",
319                elements[..edge].iter().format(sep),
320                sep,
321                ELLIPSIS,
322                sep,
323                elements[elements.len() - edge..].iter().format(sep)
324            )
325        }
326    }
327
328    #[test]
329    fn empty_arrays() {
330        let a: Array2<u32> = arr2(&[[], []]);
331        let actual = format!("{}", a);
332        let expected = "[[]]";
333        assert_str_eq(expected, &actual);
334    }
335
336    #[test]
337    fn zero_length_axes() {
338        let a = Array3::<f32>::zeros((3, 0, 4));
339        let actual = format!("{}", a);
340        let expected = "[[[]]]";
341        assert_str_eq(expected, &actual);
342    }
343
344    #[test]
345    fn dim_0() {
346        let element = 12;
347        let a = arr0(element);
348        let actual = format!("{}", a);
349        let expected = "12";
350        assert_str_eq(expected, &actual);
351    }
352
353    #[test]
354    fn dim_1() {
355        let overflow: usize = 2;
356        let a = Array1::from_elem(ARRAY_MANY_ELEMENT_LIMIT + overflow, 1);
357        let actual = format!("{}", a);
358        let expected = format!("[{}]", ellipsize(AXIS_LIMIT_ROW, ", ", a.iter()));
359        assert_str_eq(&expected, &actual);
360    }
361
362    #[test]
363    fn dim_1_alternate() {
364        let overflow: usize = 2;
365        let a = Array1::from_elem(ARRAY_MANY_ELEMENT_LIMIT + overflow, 1);
366        let actual = format!("{:#}", a);
367        let expected = format!("[{}]", a.iter().format(", "));
368        assert_str_eq(&expected, &actual);
369    }
370
371    #[test]
372    fn dim_2_last_axis_overflow() {
373        let overflow: usize = 2;
374        let a = Array2::from_elem(
375            (AXIS_2D_OVERFLOW_LIMIT, AXIS_2D_OVERFLOW_LIMIT + overflow),
376            1,
377        );
378        let actual = format!("{}", a);
379        let expected = "\
380[[1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
381 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
382 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
383 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
384 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
385 ...,
386 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
387 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
388 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
389 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1],
390 [1, 1, 1, 1, 1, ..., 1, 1, 1, 1, 1]]";
391        assert_str_eq(expected, &actual);
392    }
393
394    #[test]
395    fn dim_2_non_last_axis_overflow() {
396        let a = Array2::from_elem((ARRAY_MANY_ELEMENT_LIMIT / 10, 10), 1);
397        let actual = format!("{}", a);
398        let row = format!("{}", a.row(0));
399        let expected = format!(
400            "[{}]",
401            ellipsize(AXIS_LIMIT_COL, ",\n ", (0..a.nrows()).map(|_| &row))
402        );
403        assert_str_eq(&expected, &actual);
404    }
405
406    #[test]
407    fn dim_2_non_last_axis_overflow_alternate() {
408        let a = Array2::from_elem((AXIS_LIMIT_COL * 4, 6), 1);
409        let actual = format!("{:#}", a);
410        let row = format!("{}", a.row(0));
411        let expected = format!("[{}]", (0..a.nrows()).map(|_| &row).format(",\n "));
412        assert_str_eq(&expected, &actual);
413    }
414
415    #[test]
416    fn dim_2_multi_directional_overflow() {
417        let overflow: usize = 2;
418        let a = Array2::from_elem(
419            (
420                AXIS_2D_OVERFLOW_LIMIT + overflow,
421                AXIS_2D_OVERFLOW_LIMIT + overflow,
422            ),
423            1,
424        );
425        let actual = format!("{}", a);
426        let row = format!("[{}]", ellipsize(AXIS_LIMIT_ROW, ", ", a.row(0)));
427        let expected = format!(
428            "[{}]",
429            ellipsize(AXIS_LIMIT_COL, ",\n ", (0..a.nrows()).map(|_| &row))
430        );
431        assert_str_eq(&expected, &actual);
432    }
433
434    #[test]
435    fn dim_2_multi_directional_overflow_alternate() {
436        let overflow: usize = 2;
437        let a = Array2::from_elem(
438            (
439                AXIS_2D_OVERFLOW_LIMIT + overflow,
440                AXIS_2D_OVERFLOW_LIMIT + overflow,
441            ),
442            1,
443        );
444        let actual = format!("{:#}", a);
445        let row = format!("{}", a.row(0));
446        let expected = format!("[{}]", (0..a.nrows()).map(|_| &row).format(",\n "));
447        assert_str_eq(&expected, &actual);
448    }
449
450    #[test]
451    fn dim_3_overflow_most() {
452        let a = Array3::from_shape_fn(
453            (AXIS_LIMIT_STACKED + 1, AXIS_LIMIT_COL, AXIS_LIMIT_ROW + 1),
454            |(i, j, k)| {
455                1000. + (100. * ((i as f64).sqrt() + (j as f64).sin() + k as f64)).round() / 100.
456            },
457        );
458        let actual = format!("{:6.1}", a);
459        let expected = "\
460[[[1000.0, 1001.0, 1002.0, 1003.0, 1004.0, ..., 1007.0, 1008.0, 1009.0, 1010.0, 1011.0],
461  [1000.8, 1001.8, 1002.8, 1003.8, 1004.8, ..., 1007.8, 1008.8, 1009.8, 1010.8, 1011.8],
462  [1000.9, 1001.9, 1002.9, 1003.9, 1004.9, ..., 1007.9, 1008.9, 1009.9, 1010.9, 1011.9],
463  [1000.1, 1001.1, 1002.1, 1003.1, 1004.1, ..., 1007.1, 1008.1, 1009.1, 1010.1, 1011.1],
464  [ 999.2, 1000.2, 1001.2, 1002.2, 1003.2, ..., 1006.2, 1007.2, 1008.2, 1009.2, 1010.2],
465  [ 999.0, 1000.0, 1001.0, 1002.0, 1003.0, ..., 1006.0, 1007.0, 1008.0, 1009.0, 1010.0],
466  [ 999.7, 1000.7, 1001.7, 1002.7, 1003.7, ..., 1006.7, 1007.7, 1008.7, 1009.7, 1010.7],
467  [1000.7, 1001.7, 1002.7, 1003.7, 1004.7, ..., 1007.7, 1008.7, 1009.7, 1010.7, 1011.7],
468  [1001.0, 1002.0, 1003.0, 1004.0, 1005.0, ..., 1008.0, 1009.0, 1010.0, 1011.0, 1012.0],
469  [1000.4, 1001.4, 1002.4, 1003.4, 1004.4, ..., 1007.4, 1008.4, 1009.4, 1010.4, 1011.4],
470  [ 999.5, 1000.5, 1001.5, 1002.5, 1003.5, ..., 1006.5, 1007.5, 1008.5, 1009.5, 1010.5]],
471
472 [[1001.0, 1002.0, 1003.0, 1004.0, 1005.0, ..., 1008.0, 1009.0, 1010.0, 1011.0, 1012.0],
473  [1001.8, 1002.8, 1003.8, 1004.8, 1005.8, ..., 1008.8, 1009.8, 1010.8, 1011.8, 1012.8],
474  [1001.9, 1002.9, 1003.9, 1004.9, 1005.9, ..., 1008.9, 1009.9, 1010.9, 1011.9, 1012.9],
475  [1001.1, 1002.1, 1003.1, 1004.1, 1005.1, ..., 1008.1, 1009.1, 1010.1, 1011.1, 1012.1],
476  [1000.2, 1001.2, 1002.2, 1003.2, 1004.2, ..., 1007.2, 1008.2, 1009.2, 1010.2, 1011.2],
477  [1000.0, 1001.0, 1002.0, 1003.0, 1004.0, ..., 1007.0, 1008.0, 1009.0, 1010.0, 1011.0],
478  [1000.7, 1001.7, 1002.7, 1003.7, 1004.7, ..., 1007.7, 1008.7, 1009.7, 1010.7, 1011.7],
479  [1001.7, 1002.7, 1003.7, 1004.7, 1005.7, ..., 1008.7, 1009.7, 1010.7, 1011.7, 1012.7],
480  [1002.0, 1003.0, 1004.0, 1005.0, 1006.0, ..., 1009.0, 1010.0, 1011.0, 1012.0, 1013.0],
481  [1001.4, 1002.4, 1003.4, 1004.4, 1005.4, ..., 1008.4, 1009.4, 1010.4, 1011.4, 1012.4],
482  [1000.5, 1001.5, 1002.5, 1003.5, 1004.5, ..., 1007.5, 1008.5, 1009.5, 1010.5, 1011.5]],
483
484 [[1001.4, 1002.4, 1003.4, 1004.4, 1005.4, ..., 1008.4, 1009.4, 1010.4, 1011.4, 1012.4],
485  [1002.3, 1003.3, 1004.3, 1005.3, 1006.3, ..., 1009.3, 1010.3, 1011.3, 1012.3, 1013.3],
486  [1002.3, 1003.3, 1004.3, 1005.3, 1006.3, ..., 1009.3, 1010.3, 1011.3, 1012.3, 1013.3],
487  [1001.6, 1002.6, 1003.6, 1004.6, 1005.6, ..., 1008.6, 1009.6, 1010.6, 1011.6, 1012.6],
488  [1000.7, 1001.7, 1002.7, 1003.7, 1004.7, ..., 1007.7, 1008.7, 1009.7, 1010.7, 1011.7],
489  [1000.5, 1001.5, 1002.5, 1003.5, 1004.5, ..., 1007.5, 1008.5, 1009.5, 1010.5, 1011.5],
490  [1001.1, 1002.1, 1003.1, 1004.1, 1005.1, ..., 1008.1, 1009.1, 1010.1, 1011.1, 1012.1],
491  [1002.1, 1003.1, 1004.1, 1005.1, 1006.1, ..., 1009.1, 1010.1, 1011.1, 1012.1, 1013.1],
492  [1002.4, 1003.4, 1004.4, 1005.4, 1006.4, ..., 1009.4, 1010.4, 1011.4, 1012.4, 1013.4],
493  [1001.8, 1002.8, 1003.8, 1004.8, 1005.8, ..., 1008.8, 1009.8, 1010.8, 1011.8, 1012.8],
494  [1000.9, 1001.9, 1002.9, 1003.9, 1004.9, ..., 1007.9, 1008.9, 1009.9, 1010.9, 1011.9]],
495
496 ...,
497
498 [[1002.0, 1003.0, 1004.0, 1005.0, 1006.0, ..., 1009.0, 1010.0, 1011.0, 1012.0, 1013.0],
499  [1002.8, 1003.8, 1004.8, 1005.8, 1006.8, ..., 1009.8, 1010.8, 1011.8, 1012.8, 1013.8],
500  [1002.9, 1003.9, 1004.9, 1005.9, 1006.9, ..., 1009.9, 1010.9, 1011.9, 1012.9, 1013.9],
501  [1002.1, 1003.1, 1004.1, 1005.1, 1006.1, ..., 1009.1, 1010.1, 1011.1, 1012.1, 1013.1],
502  [1001.2, 1002.2, 1003.2, 1004.2, 1005.2, ..., 1008.2, 1009.2, 1010.2, 1011.2, 1012.2],
503  [1001.0, 1002.0, 1003.0, 1004.0, 1005.0, ..., 1008.0, 1009.0, 1010.0, 1011.0, 1012.0],
504  [1001.7, 1002.7, 1003.7, 1004.7, 1005.7, ..., 1008.7, 1009.7, 1010.7, 1011.7, 1012.7],
505  [1002.7, 1003.7, 1004.7, 1005.7, 1006.7, ..., 1009.7, 1010.7, 1011.7, 1012.7, 1013.7],
506  [1003.0, 1004.0, 1005.0, 1006.0, 1007.0, ..., 1010.0, 1011.0, 1012.0, 1013.0, 1014.0],
507  [1002.4, 1003.4, 1004.4, 1005.4, 1006.4, ..., 1009.4, 1010.4, 1011.4, 1012.4, 1013.4],
508  [1001.5, 1002.5, 1003.5, 1004.5, 1005.5, ..., 1008.5, 1009.5, 1010.5, 1011.5, 1012.5]],
509
510 [[1002.2, 1003.2, 1004.2, 1005.2, 1006.2, ..., 1009.2, 1010.2, 1011.2, 1012.2, 1013.2],
511  [1003.1, 1004.1, 1005.1, 1006.1, 1007.1, ..., 1010.1, 1011.1, 1012.1, 1013.1, 1014.1],
512  [1003.1, 1004.1, 1005.1, 1006.1, 1007.1, ..., 1010.1, 1011.1, 1012.1, 1013.1, 1014.1],
513  [1002.4, 1003.4, 1004.4, 1005.4, 1006.4, ..., 1009.4, 1010.4, 1011.4, 1012.4, 1013.4],
514  [1001.5, 1002.5, 1003.5, 1004.5, 1005.5, ..., 1008.5, 1009.5, 1010.5, 1011.5, 1012.5],
515  [1001.3, 1002.3, 1003.3, 1004.3, 1005.3, ..., 1008.3, 1009.3, 1010.3, 1011.3, 1012.3],
516  [1002.0, 1003.0, 1004.0, 1005.0, 1006.0, ..., 1009.0, 1010.0, 1011.0, 1012.0, 1013.0],
517  [1002.9, 1003.9, 1004.9, 1005.9, 1006.9, ..., 1009.9, 1010.9, 1011.9, 1012.9, 1013.9],
518  [1003.2, 1004.2, 1005.2, 1006.2, 1007.2, ..., 1010.2, 1011.2, 1012.2, 1013.2, 1014.2],
519  [1002.6, 1003.6, 1004.6, 1005.6, 1006.6, ..., 1009.6, 1010.6, 1011.6, 1012.6, 1013.6],
520  [1001.7, 1002.7, 1003.7, 1004.7, 1005.7, ..., 1008.7, 1009.7, 1010.7, 1011.7, 1012.7]],
521
522 [[1002.5, 1003.5, 1004.5, 1005.5, 1006.5, ..., 1009.5, 1010.5, 1011.5, 1012.5, 1013.5],
523  [1003.3, 1004.3, 1005.3, 1006.3, 1007.3, ..., 1010.3, 1011.3, 1012.3, 1013.3, 1014.3],
524  [1003.4, 1004.4, 1005.4, 1006.4, 1007.4, ..., 1010.4, 1011.4, 1012.4, 1013.4, 1014.4],
525  [1002.6, 1003.6, 1004.6, 1005.6, 1006.6, ..., 1009.6, 1010.6, 1011.6, 1012.6, 1013.6],
526  [1001.7, 1002.7, 1003.7, 1004.7, 1005.7, ..., 1008.7, 1009.7, 1010.7, 1011.7, 1012.7],
527  [1001.5, 1002.5, 1003.5, 1004.5, 1005.5, ..., 1008.5, 1009.5, 1010.5, 1011.5, 1012.5],
528  [1002.2, 1003.2, 1004.2, 1005.2, 1006.2, ..., 1009.2, 1010.2, 1011.2, 1012.2, 1013.2],
529  [1003.1, 1004.1, 1005.1, 1006.1, 1007.1, ..., 1010.1, 1011.1, 1012.1, 1013.1, 1014.1],
530  [1003.4, 1004.4, 1005.4, 1006.4, 1007.4, ..., 1010.4, 1011.4, 1012.4, 1013.4, 1014.4],
531  [1002.9, 1003.9, 1004.9, 1005.9, 1006.9, ..., 1009.9, 1010.9, 1011.9, 1012.9, 1013.9],
532  [1001.9, 1002.9, 1003.9, 1004.9, 1005.9, ..., 1008.9, 1009.9, 1010.9, 1011.9, 1012.9]]]";
533        assert_str_eq(expected, &actual);
534    }
535
536    #[test]
537    fn dim_4_overflow_outer() {
538        let a = Array4::from_shape_fn((10, 10, 3, 3), |(i, j, k, l)| i + j + k + l);
539        let actual = format!("{:2}", a);
540        // Generated using NumPy with:
541        // np.set_printoptions(threshold=500, edgeitems=3)
542        // np.fromfunction(lambda i, j, k, l: i + j + k + l, (10, 10, 3, 3), dtype=int)
543        //
544        let expected = "\
545[[[[ 0,  1,  2],
546   [ 1,  2,  3],
547   [ 2,  3,  4]],
548
549  [[ 1,  2,  3],
550   [ 2,  3,  4],
551   [ 3,  4,  5]],
552
553  [[ 2,  3,  4],
554   [ 3,  4,  5],
555   [ 4,  5,  6]],
556
557  ...,
558
559  [[ 7,  8,  9],
560   [ 8,  9, 10],
561   [ 9, 10, 11]],
562
563  [[ 8,  9, 10],
564   [ 9, 10, 11],
565   [10, 11, 12]],
566
567  [[ 9, 10, 11],
568   [10, 11, 12],
569   [11, 12, 13]]],
570
571
572 [[[ 1,  2,  3],
573   [ 2,  3,  4],
574   [ 3,  4,  5]],
575
576  [[ 2,  3,  4],
577   [ 3,  4,  5],
578   [ 4,  5,  6]],
579
580  [[ 3,  4,  5],
581   [ 4,  5,  6],
582   [ 5,  6,  7]],
583
584  ...,
585
586  [[ 8,  9, 10],
587   [ 9, 10, 11],
588   [10, 11, 12]],
589
590  [[ 9, 10, 11],
591   [10, 11, 12],
592   [11, 12, 13]],
593
594  [[10, 11, 12],
595   [11, 12, 13],
596   [12, 13, 14]]],
597
598
599 [[[ 2,  3,  4],
600   [ 3,  4,  5],
601   [ 4,  5,  6]],
602
603  [[ 3,  4,  5],
604   [ 4,  5,  6],
605   [ 5,  6,  7]],
606
607  [[ 4,  5,  6],
608   [ 5,  6,  7],
609   [ 6,  7,  8]],
610
611  ...,
612
613  [[ 9, 10, 11],
614   [10, 11, 12],
615   [11, 12, 13]],
616
617  [[10, 11, 12],
618   [11, 12, 13],
619   [12, 13, 14]],
620
621  [[11, 12, 13],
622   [12, 13, 14],
623   [13, 14, 15]]],
624
625
626 ...,
627
628
629 [[[ 7,  8,  9],
630   [ 8,  9, 10],
631   [ 9, 10, 11]],
632
633  [[ 8,  9, 10],
634   [ 9, 10, 11],
635   [10, 11, 12]],
636
637  [[ 9, 10, 11],
638   [10, 11, 12],
639   [11, 12, 13]],
640
641  ...,
642
643  [[14, 15, 16],
644   [15, 16, 17],
645   [16, 17, 18]],
646
647  [[15, 16, 17],
648   [16, 17, 18],
649   [17, 18, 19]],
650
651  [[16, 17, 18],
652   [17, 18, 19],
653   [18, 19, 20]]],
654
655
656 [[[ 8,  9, 10],
657   [ 9, 10, 11],
658   [10, 11, 12]],
659
660  [[ 9, 10, 11],
661   [10, 11, 12],
662   [11, 12, 13]],
663
664  [[10, 11, 12],
665   [11, 12, 13],
666   [12, 13, 14]],
667
668  ...,
669
670  [[15, 16, 17],
671   [16, 17, 18],
672   [17, 18, 19]],
673
674  [[16, 17, 18],
675   [17, 18, 19],
676   [18, 19, 20]],
677
678  [[17, 18, 19],
679   [18, 19, 20],
680   [19, 20, 21]]],
681
682
683 [[[ 9, 10, 11],
684   [10, 11, 12],
685   [11, 12, 13]],
686
687  [[10, 11, 12],
688   [11, 12, 13],
689   [12, 13, 14]],
690
691  [[11, 12, 13],
692   [12, 13, 14],
693   [13, 14, 15]],
694
695  ...,
696
697  [[16, 17, 18],
698   [17, 18, 19],
699   [18, 19, 20]],
700
701  [[17, 18, 19],
702   [18, 19, 20],
703   [19, 20, 21]],
704
705  [[18, 19, 20],
706   [19, 20, 21],
707   [20, 21, 22]]]]";
708        assert_str_eq(expected, &actual);
709    }
710}