8
8
use std:: fmt;
9
9
use super :: {
10
10
ArrayBase ,
11
+ Axis ,
11
12
Data ,
12
13
Dimension ,
13
14
NdProducer ,
14
15
Ix
15
16
} ;
16
- use crate :: dimension :: IntoDimension ;
17
+ use crate :: aliases :: Ix1 ;
17
18
18
19
const PRINT_ELEMENTS_LIMIT : Ix = 3 ;
19
20
20
- fn get_overflow_axes ( shape : & [ Ix ] , limit : usize ) -> Vec < usize > {
21
- shape. iter ( )
22
- . enumerate ( )
23
- . rev ( )
24
- . filter ( |( _, axis_size) | * * axis_size > 2 * limit)
25
- . map ( |( axis, _) | axis)
26
- . collect ( )
21
+ fn format_1d_array < A , S , F > (
22
+ view : & ArrayBase < S , Ix1 > ,
23
+ f : & mut fmt:: Formatter ,
24
+ mut format : F ,
25
+ limit : Ix ) -> fmt:: Result
26
+ where
27
+ F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result ,
28
+ S : Data < Elem =A > ,
29
+ {
30
+ let to_be_printed = to_be_printed ( view. len ( ) , limit) ;
31
+
32
+ let n_to_be_printed = to_be_printed. len ( ) ;
33
+
34
+ write ! ( f, "[" ) ?;
35
+ for ( j, index) in to_be_printed. into_iter ( ) . enumerate ( ) {
36
+ match index {
37
+ PrintableCell :: ElementIndex ( i) => {
38
+ format ( & view[ i] , f) ?;
39
+ if j != n_to_be_printed - 1 {
40
+ write ! ( f, ", " ) ?;
41
+ }
42
+ } ,
43
+ PrintableCell :: Ellipses => write ! ( f, "..., " ) ?,
44
+ }
45
+ }
46
+ write ! ( f, "]" ) ?;
47
+ Ok ( ( ) )
27
48
}
28
49
29
- fn get_highest_axis_to_skip ( overflow_axes : & Vec < usize > ,
30
- shape : & [ Ix ] ,
31
- index : & [ Ix ] ,
32
- limit : & usize ) -> Option < usize > {
33
- overflow_axes. iter ( )
34
- . filter ( |axis| {
35
- if * * axis == shape. len ( ) - 1 {
36
- return false
37
- } ;
38
- let sa_idx_max = shape. iter ( ) . skip ( * * axis) . next ( ) . unwrap ( ) ;
39
- let sa_idx_val = index. iter ( ) . skip ( * * axis) . next ( ) . unwrap ( ) ;
40
- sa_idx_val >= limit && sa_idx_val < & ( sa_idx_max - limit)
41
- } )
42
- . min ( )
43
- . map ( |v| * v)
50
+ enum PrintableCell {
51
+ ElementIndex ( usize ) ,
52
+ Ellipses ,
44
53
}
45
54
46
- fn get_highest_changed_axis ( index : & [ Ix ] , prev_index : & [ Ix ] ) -> Option < usize > {
47
- index. iter ( )
48
- . take ( index. len ( ) - 1 )
49
- . zip ( prev_index. iter ( ) )
50
- . enumerate ( )
51
- . filter ( |( _, ( a, b) ) | a != b)
52
- . map ( |( i, _) | i)
53
- . next ( )
55
+ // Returns what indexes should be printed for a certain axis.
56
+ // If the axis is longer than 2 * limit, a `Ellipses` is inserted
57
+ // where indexes are being omitted.
58
+ fn to_be_printed ( length : usize , limit : usize ) -> Vec < PrintableCell > {
59
+ if length <= 2 * limit {
60
+ ( 0 ..length) . map ( |x| PrintableCell :: ElementIndex ( x) ) . collect ( )
61
+ } else {
62
+ let mut v: Vec < PrintableCell > = ( 0 ..limit) . map ( |x| PrintableCell :: ElementIndex ( x) ) . collect ( ) ;
63
+ v. push ( PrintableCell :: Ellipses ) ;
64
+ v. extend ( ( length-limit..length) . map ( |x| PrintableCell :: ElementIndex ( x) ) ) ;
65
+ v
66
+ }
54
67
}
55
68
56
- fn format_array < A , S , D , F > ( view : & ArrayBase < S , D > ,
57
- f : & mut fmt:: Formatter ,
58
- mut format : F ,
59
- limit : Ix ) -> fmt:: Result
60
- where F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result ,
61
- D : Dimension ,
62
- S : Data < Elem =A > ,
69
+ fn format_array < A , S , D , F > (
70
+ view : & ArrayBase < S , D > ,
71
+ f : & mut fmt:: Formatter ,
72
+ mut format : F ,
73
+ limit : Ix ) -> fmt:: Result
74
+ where
75
+ F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result + Clone ,
76
+ D : Dimension ,
77
+ S : Data < Elem =A > ,
63
78
{
64
- if view. shape ( ) . is_empty ( ) {
65
- // Handle 0-dimensional array case first
66
- return format ( view. iter ( ) . next ( ) . unwrap ( ) , f)
79
+ // If any of the axes has 0 length, we return the same empty array representation
80
+ // e.g. [[]] for 2-d arrays
81
+ if view. shape ( ) . iter ( ) . any ( |& x| x == 0 ) {
82
+ write ! ( f, "{}{}" , "[" . repeat( view. ndim( ) ) , "]" . repeat( view. ndim( ) ) ) ?;
83
+ return Ok ( ( ) )
67
84
}
68
-
69
- let overflow_axes: Vec < Ix > = get_overflow_axes ( view. shape ( ) , limit) ;
70
-
71
- let ndim = view. ndim ( ) ;
72
- let nth_idx_max = view. shape ( ) [ ndim-1 ] ;
73
-
74
- // None will be an empty iter.
75
- let mut last_index = match view. dim ( ) . into_dimension ( ) . first_index ( ) {
76
- None => view. dim ( ) . into_dimension ( ) . clone ( ) ,
77
- Some ( ix) => ix,
78
- } ;
79
- write ! ( f, "{}" , "[" . repeat( ndim) ) ?;
80
- // Shows if ellipses for horizontal split were printed.
81
- let mut printed_ellipses_h = vec ! [ false ; ndim] ;
82
- // Shows if the row was printed for the first time after horizontal split.
83
- let mut no_rows_after_skip_yet = false ;
84
-
85
- // Simply use the indexed iterator, and take the index wraparounds
86
- // as cues for when to add []'s and how many to add.
87
- for ( index, elt) in view. indexed_iter ( ) {
88
- let index = index. into_dimension ( ) ;
89
-
90
- let skip_row_for_axis = get_highest_axis_to_skip (
91
- & overflow_axes,
92
- view. shape ( ) ,
93
- index. slice ( ) ,
94
- & limit
95
- ) ;
96
- if skip_row_for_axis. is_some ( ) {
97
- no_rows_after_skip_yet = true ;
98
- }
99
-
100
- let max_changed_idx = get_highest_changed_axis ( index. slice ( ) , last_index. slice ( ) ) ;
101
- if let Some ( i) = max_changed_idx {
102
- printed_ellipses_h. iter_mut ( ) . skip ( i + 1 ) . for_each ( |e| { * e = false ; } ) ;
103
-
104
- if skip_row_for_axis. is_none ( ) {
105
- // New row.
106
- // # of ['s needed
107
- let n = ndim - i - 1 ;
108
- if !no_rows_after_skip_yet {
109
- write ! ( f, "{}" , "]" . repeat( n) ) ?;
110
- writeln ! ( f, "," ) ?;
85
+ match view. shape ( ) {
86
+ // If it's 0 dimensional, we just print out the scalar
87
+ [ ] => format ( view. iter ( ) . next ( ) . unwrap ( ) , f) ?,
88
+ // We delegate 1-dimensional arrays to a specialized function
89
+ [ _] => format_1d_array ( & view. view ( ) . into_dimensionality :: < Ix1 > ( ) . unwrap ( ) , f, format, limit) ?,
90
+ // For n-dimensional arrays, we proceed recursively
91
+ shape => {
92
+ // Cast into a dynamically dimensioned view
93
+ // This is required to be able to use `index_axis`
94
+ let view = view. view ( ) . into_dyn ( ) ;
95
+ // We start by checking what indexes from the first axis should be printed
96
+ // We put a `None` in the middle if we are omitting elements
97
+ let to_be_printed = to_be_printed ( shape[ 0 ] , limit) ;
98
+
99
+ let n_to_be_printed = to_be_printed. len ( ) ;
100
+
101
+ write ! ( f, "[" ) ?;
102
+ for ( j, index) in to_be_printed. into_iter ( ) . enumerate ( ) {
103
+ match index {
104
+ PrintableCell :: ElementIndex ( i) => {
105
+ // Proceed recursively with the (n-1)-dimensional slice
106
+ format_array (
107
+ & view. index_axis ( Axis ( 0 ) , i) , f, format. clone ( ) , limit
108
+ ) ?;
109
+ // We need to add a separator after each slice,
110
+ // apart from the last one
111
+ if j != n_to_be_printed - 1 {
112
+ write ! ( f, ",\n " ) ?
113
+ }
114
+ } ,
115
+ PrintableCell :: Ellipses => write ! ( f, "...,\n " ) ?
111
116
}
112
- no_rows_after_skip_yet = false ;
113
- write ! ( f, "{}" , " " . repeat( ndim - n) ) ?;
114
- write ! ( f, "{}" , "[" . repeat( n) ) ?;
115
- } else if !printed_ellipses_h[ skip_row_for_axis. unwrap ( ) ] {
116
- let ax = skip_row_for_axis. unwrap ( ) ;
117
- let n = ndim - i - 1 ;
118
- write ! ( f, "{}" , "]" . repeat( n) ) ?;
119
- writeln ! ( f, "," ) ?;
120
- write ! ( f, "{}" , " " . repeat( ax + 1 ) ) ?;
121
- writeln ! ( f, "...," ) ?;
122
- printed_ellipses_h[ ax] = true ;
123
- }
124
- last_index = index. clone ( ) ;
125
- }
126
-
127
- if skip_row_for_axis. is_none ( ) {
128
- let nth_idx_op = index. slice ( ) . iter ( ) . last ( ) ;
129
- if overflow_axes. contains ( & ( ndim - 1 ) ) {
130
- let nth_idx_val = nth_idx_op. unwrap ( ) ;
131
- if nth_idx_val >= & limit && nth_idx_val < & ( nth_idx_max - & limit) {
132
- if nth_idx_val == & limit {
133
- write ! ( f, ", ..." ) ?;
134
- }
135
- continue ;
136
- }
137
- }
138
-
139
- if max_changed_idx. is_none ( ) && !index. slice ( ) . iter ( ) . all ( |x| * x == 0 ) {
140
- write ! ( f, ", " ) ?;
141
117
}
142
- format ( elt , f ) ?;
118
+ write ! ( f , "]" ) ?;
143
119
}
144
120
}
145
- write ! ( f, "{}" , "]" . repeat( ndim) ) ?;
146
121
Ok ( ( ) )
147
122
}
148
123
@@ -240,15 +215,17 @@ mod formatting_with_omit {
240
215
let a: Array2 < u32 > = arr2 ( & [ [ ] , [ ] ] ) ;
241
216
let actual_output = format ! ( "{}" , a) ;
242
217
let expected_output = String :: from ( "[[]]" ) ;
243
- assert_eq ! ( actual_output, expected_output) ;
218
+ print_output_diff ( & expected_output, & actual_output) ;
219
+ assert_eq ! ( expected_output, actual_output) ;
244
220
}
245
221
246
222
#[ test]
247
223
fn zero_length_axes ( ) {
248
224
let a = Array3 :: < f32 > :: zeros ( ( 3 , 0 , 4 ) ) ;
249
225
let actual_output = format ! ( "{}" , a) ;
250
226
let expected_output = String :: from ( "[[[]]]" ) ;
251
- assert_eq ! ( actual_output, expected_output) ;
227
+ print_output_diff ( & expected_output, & actual_output) ;
228
+ assert_eq ! ( expected_output, actual_output) ;
252
229
}
253
230
254
231
#[ test]
@@ -257,7 +234,8 @@ mod formatting_with_omit {
257
234
let a = arr0 ( element) ;
258
235
let actual_output = format ! ( "{}" , a) ;
259
236
let expected_output = format ! ( "{}" , element) ;
260
- assert_eq ! ( actual_output, expected_output) ;
237
+ print_output_diff ( & expected_output, & actual_output) ;
238
+ assert_eq ! ( expected_output, actual_output) ;
261
239
}
262
240
263
241
#[ test]
0 commit comments