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