Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ndarray-0.16.1/src/arrayformat.rs
Line
Count
Source
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.
8
use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer};
9
use crate::aliases::{Ix1, IxDyn};
10
use alloc::format;
11
use std::fmt;
12
13
/// Default threshold, below this element count, we don't ellipsize
14
const ARRAY_MANY_ELEMENT_LIMIT: usize = 500;
15
/// Limit of element count for non-last axes before overflowing with an ellipsis.
16
const 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.
19
const 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.
22
const AXIS_LIMIT_ROW: usize = 11;
23
24
#[cfg(test)]
25
// Test value to use for size of overflowing 2D arrays
26
const AXIS_2D_OVERFLOW_LIMIT: usize = 22;
27
28
/// The string used as an ellipsis.
29
const ELLIPSIS: &str = "...";
30
31
#[derive(Clone, Debug)]
32
struct FormatOptions
33
{
34
    axis_collapse_limit: usize,
35
    axis_collapse_limit_next_last: usize,
36
    axis_collapse_limit_last: usize,
37
}
38
39
impl FormatOptions
40
{
41
0
    pub(crate) fn default_for_array(nelem: usize, no_limit: bool) -> Self
42
    {
43
0
        let default = Self {
44
0
            axis_collapse_limit: AXIS_LIMIT_STACKED,
45
0
            axis_collapse_limit_next_last: AXIS_LIMIT_COL,
46
0
            axis_collapse_limit_last: AXIS_LIMIT_ROW,
47
0
        };
48
0
        default.set_no_limit(no_limit || nelem < ARRAY_MANY_ELEMENT_LIMIT)
49
0
    }
50
51
0
    fn set_no_limit(mut self, no_limit: bool) -> Self
52
    {
53
0
        if no_limit {
54
0
            self.axis_collapse_limit = usize::MAX;
55
0
            self.axis_collapse_limit_next_last = usize::MAX;
56
0
            self.axis_collapse_limit_last = usize::MAX;
57
0
        }
58
0
        self
59
0
    }
60
61
    /// Axis length collapse limit before ellipsizing, where `axis_rindex` is
62
    /// the index of the axis from the back.
63
0
    pub(crate) fn collapse_limit(&self, axis_rindex: usize) -> usize
64
    {
65
0
        match axis_rindex {
66
0
            0 => self.axis_collapse_limit_last,
67
0
            1 => self.axis_collapse_limit_next_last,
68
0
            _ => self.axis_collapse_limit,
69
        }
70
0
    }
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.
85
0
fn format_with_overflow(
86
0
    f: &mut fmt::Formatter<'_>, length: usize, limit: usize, separator: &str, ellipsis: &str,
87
0
    fmt_elem: &mut dyn FnMut(&mut fmt::Formatter, usize) -> fmt::Result,
88
0
) -> fmt::Result
89
{
90
0
    if length == 0 {
91
0
        // no-op
92
0
    } else if length <= limit {
93
0
        fmt_elem(f, 0)?;
94
0
        for i in 1..length {
95
0
            f.write_str(separator)?;
96
0
            fmt_elem(f, i)?
97
        }
98
    } else {
99
0
        let edge = limit / 2;
100
0
        fmt_elem(f, 0)?;
101
0
        for i in 1..edge {
102
0
            f.write_str(separator)?;
103
0
            fmt_elem(f, i)?;
104
        }
105
0
        f.write_str(separator)?;
106
0
        f.write_str(ellipsis)?;
107
0
        for i in length - edge..length {
108
0
            f.write_str(separator)?;
109
0
            fmt_elem(f, i)?
110
        }
111
    }
112
0
    Ok(())
113
0
}
114
115
0
fn format_array<A, S, D, F>(
116
0
    array: &ArrayBase<S, D>, f: &mut fmt::Formatter<'_>, format: F, fmt_opt: &FormatOptions,
117
0
) -> fmt::Result
118
0
where
119
0
    F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone,
120
0
    D: Dimension,
121
0
    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
0
    format_array_inner(array.view().into_dyn(), f, format, fmt_opt, 0, array.ndim())
126
0
}
Unexecuted instantiation: ndarray::arrayformat::format_array::<f64, ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<[usize; 1]>, <f64 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array::<f32, ndarray::data_repr::OwnedRepr<f32>, ndarray::dimension::dim::Dim<[usize; 1]>, <f32 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array::<i32, ndarray::data_repr::OwnedRepr<i32>, ndarray::dimension::dim::Dim<[usize; 1]>, <i32 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array::<i16, ndarray::data_repr::OwnedRepr<i16>, ndarray::dimension::dim::Dim<[usize; 1]>, <i16 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array::<i64, ndarray::data_repr::OwnedRepr<i64>, ndarray::dimension::dim::Dim<[usize; 1]>, <i64 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array::<_, _, _, _>
127
128
0
fn format_array_inner<A, F>(
129
0
    view: ArrayView<A, IxDyn>, f: &mut fmt::Formatter<'_>, mut format: F, fmt_opt: &FormatOptions, depth: usize,
130
0
    full_ndim: usize,
131
0
) -> fmt::Result
132
0
where
133
0
    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
0
    if view.is_empty() {
138
0
        write!(f, "{}{}", "[".repeat(view.ndim()), "]".repeat(view.ndim()))?;
139
0
        return Ok(());
140
0
    }
141
0
    match view.shape() {
142
        // If it's 0 dimensional, we just print out the scalar
143
0
        &[] => format(&view[[]], f)?,
144
        // We handle 1-D arrays as a special case
145
0
        &[len] => {
146
0
            let view = view.view().into_dimensionality::<Ix1>().unwrap();
147
0
            f.write_str("[")?;
148
0
            format_with_overflow(f, len, fmt_opt.collapse_limit(0), ", ", ELLIPSIS, &mut |f, index| {
149
0
                format(&view[index], f)
150
0
            })?;
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f64, <f64 as core::fmt::Debug>::fmt>::{closure#0}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f32, <f32 as core::fmt::Debug>::fmt>::{closure#0}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i32, <i32 as core::fmt::Debug>::fmt>::{closure#0}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i16, <i16 as core::fmt::Debug>::fmt>::{closure#0}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i64, <i64 as core::fmt::Debug>::fmt>::{closure#0}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<_, _>::{closure#0}
151
0
            f.write_str("]")?;
152
        }
153
        // For n-dimensional arrays, we proceed recursively
154
0
        shape => {
155
0
            let blank_lines = "\n".repeat(shape.len() - 2);
156
0
            let indent = " ".repeat(depth + 1);
157
0
            let separator = format!(",\n{}{}", blank_lines, indent);
158
159
0
            f.write_str("[")?;
160
0
            let limit = fmt_opt.collapse_limit(full_ndim - depth - 1);
161
0
            format_with_overflow(f, shape[0], limit, &separator, ELLIPSIS, &mut |f, index| {
162
0
                format_array_inner(view.index_axis(Axis(0), index), f, format.clone(), fmt_opt, depth + 1, full_ndim)
163
0
            })?;
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f64, <f64 as core::fmt::Debug>::fmt>::{closure#1}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f32, <f32 as core::fmt::Debug>::fmt>::{closure#1}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i32, <i32 as core::fmt::Debug>::fmt>::{closure#1}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i16, <i16 as core::fmt::Debug>::fmt>::{closure#1}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i64, <i64 as core::fmt::Debug>::fmt>::{closure#1}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<_, _>::{closure#1}
164
0
            f.write_str("]")?;
165
        }
166
    }
167
0
    Ok(())
168
0
}
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f64, <f64 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<f32, <f32 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i32, <i32 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i16, <i16 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<i64, <i64 as core::fmt::Debug>::fmt>
Unexecuted instantiation: ndarray::arrayformat::format_array_inner::<_, _>
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.
175
impl<A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
176
where S: Data<Elem = A>
177
{
178
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
179
    {
180
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
181
0
        format_array(self, f, <_>::fmt, &fmt_opt)
182
0
    }
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.
189
impl<A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
190
where S: Data<Elem = A>
191
{
192
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
193
    {
194
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
195
0
        format_array(self, f, <_>::fmt, &fmt_opt)?;
196
197
        // Add extra information for Debug
198
0
        write!(
199
0
            f,
200
0
            ", shape={:?}, strides={:?}, layout={:?}",
201
0
            self.shape(),
202
0
            self.strides(),
203
0
            self.view().layout(),
204
0
        )?;
205
0
        match D::NDIM {
206
0
            Some(ndim) => write!(f, ", const ndim={}", ndim)?,
207
0
            None => write!(f, ", dynamic ndim={}", self.ndim())?,
208
        }
209
0
        Ok(())
210
0
    }
Unexecuted instantiation: <ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<[usize; 1]>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f32>, ndarray::dimension::dim::Dim<[usize; 1]>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<i32>, ndarray::dimension::dim::Dim<[usize; 1]>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<i16>, ndarray::dimension::dim::Dim<[usize; 1]>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<i64>, ndarray::dimension::dim::Dim<[usize; 1]>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <ndarray::ArrayBase<_, _> as core::fmt::Debug>::fmt
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.
217
impl<A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
218
where S: Data<Elem = A>
219
{
220
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
221
    {
222
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
223
0
        format_array(self, f, <_>::fmt, &fmt_opt)
224
0
    }
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.
231
impl<A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
232
where S: Data<Elem = A>
233
{
234
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
235
    {
236
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
237
0
        format_array(self, f, <_>::fmt, &fmt_opt)
238
0
    }
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.
244
impl<A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase<S, D>
245
where S: Data<Elem = A>
246
{
247
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
248
    {
249
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
250
0
        format_array(self, f, <_>::fmt, &fmt_opt)
251
0
    }
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.
258
impl<A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase<S, D>
259
where S: Data<Elem = A>
260
{
261
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
262
    {
263
0
        let fmt_opt = FormatOptions::default_for_array(self.len(), f.alternate());
264
0
        format_array(self, f, <_>::fmt, &fmt_opt)
265
0
    }
266
}
267
268
#[cfg(test)]
269
mod 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
}