Thanks to visit codestin.com
Credit goes to docs.rs

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