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