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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy