Skip to content

Commit fe4365c

Browse files
author
andrei.papou
committed
Implemented a function for smarter debug formatting.
1 parent 20d372a commit fe4365c

File tree

1 file changed

+190
-2
lines changed

1 file changed

+190
-2
lines changed

src/arrayformat.rs

Lines changed: 190 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,197 @@ use super::{
1111
Data,
1212
Dimension,
1313
NdProducer,
14+
Ix
1415
};
1516
use crate::dimension::IntoDimension;
1617

18+
#[derive(Debug)]
19+
enum ArrayDisplayMode {
20+
// Array is small enough to me printed without omitting any values.
21+
Full,
22+
// Omit central values of the nth axis. Since we print that axis horizontally, ellipses
23+
// on each row do something like a split of the array into 2 parts vertically.
24+
VSplit,
25+
// Omit central values of the certain axis. Since we do it only once, ellipses on each row
26+
// do something like a split of the array into 2 parts horizontally.
27+
HSplit(Ix),
28+
// Both `VSplit` and `HSplit` hold.
29+
DoubleSplit(Ix),
30+
}
31+
32+
const PRINT_ELEMENTS_LIMIT: Ix = 5;
33+
34+
impl ArrayDisplayMode {
35+
fn from_array<A, S, D>(arr: &ArrayBase<S, D>, limit: usize) -> ArrayDisplayMode
36+
where S: Data<Elem=A>,
37+
D: Dimension
38+
{
39+
let last_dim = arr.shape().len() - 1;
40+
41+
let mut overflow_axis_pair: (Option<usize>, Option<usize>) = (None, None);
42+
for (axis, axis_size) in arr.shape().iter().enumerate().rev() {
43+
if *axis_size >= 2 * limit + 1 {
44+
match overflow_axis_pair.0 {
45+
Some(_) => {
46+
if let None = overflow_axis_pair.1 {
47+
overflow_axis_pair.1 = Some(axis);
48+
}
49+
},
50+
None => {
51+
if axis != last_dim {
52+
return ArrayDisplayMode::HSplit(axis);
53+
}
54+
overflow_axis_pair.0 = Some(axis);
55+
}
56+
}
57+
}
58+
}
59+
60+
match overflow_axis_pair {
61+
(Some(_), Some(h_axis)) => ArrayDisplayMode::DoubleSplit(h_axis),
62+
(Some(_), None) => ArrayDisplayMode::VSplit,
63+
(None, _) => ArrayDisplayMode::Full,
64+
}
65+
}
66+
67+
fn h_split_offset(&self) -> Option<Ix> {
68+
match self {
69+
ArrayDisplayMode::DoubleSplit(axis) | ArrayDisplayMode::HSplit(axis) => {
70+
Some(axis + 1usize)
71+
},
72+
_ => None
73+
}
74+
}
75+
}
76+
77+
fn format_array_v2<A, S, D, F>(view: &ArrayBase<S, D>,
78+
f: &mut fmt::Formatter,
79+
mut format: F,
80+
limit: usize) -> fmt::Result
81+
where F: FnMut(&A, &mut fmt::Formatter) -> fmt::Result,
82+
D: Dimension,
83+
S: Data<Elem=A>,
84+
{
85+
let display_mode = ArrayDisplayMode::from_array(view, limit);
86+
87+
let ndim = view.dim().into_dimension().slice().len();
88+
let nth_idx_max = view.shape().iter().last().unwrap();
89+
90+
// None will be an empty iter.
91+
let mut last_index = match view.dim().into_dimension().first_index() {
92+
None => view.dim().into_dimension().clone(),
93+
Some(ix) => ix,
94+
};
95+
for _ in 0..ndim {
96+
write!(f, "[")?;
97+
}
98+
let mut first = true;
99+
// Shows if ellipses for vertical split were printed.
100+
let mut printed_ellipses_v = false;
101+
// Shows if ellipses for horizontal split were printed.
102+
let mut printed_ellipses_h = false;
103+
// Shows if the row was printed for the first time after horizontal split.
104+
let mut no_rows_after_skip_yet = false;
105+
106+
// Simply use the indexed iterator, and take the index wraparounds
107+
// as cues for when to add []'s and how many to add.
108+
for (index, elt) in view.indexed_iter() {
109+
let index = index.into_dimension();
110+
let take_n = if ndim == 0 { 1 } else { ndim - 1 };
111+
let mut update_index = false;
112+
113+
let mut print_row = true;
114+
match display_mode {
115+
ArrayDisplayMode::HSplit(axis) | ArrayDisplayMode::DoubleSplit(axis) => {
116+
let sa_idx_max = view.shape().iter().skip(axis).next().unwrap();
117+
let sa_idx_val = index.slice().iter().skip(axis).next().unwrap();
118+
if sa_idx_val >= &limit && sa_idx_val < &(sa_idx_max - &limit) {
119+
print_row = false;
120+
no_rows_after_skip_yet = true;
121+
}
122+
},
123+
_ => {}
124+
}
125+
126+
for (i, (a, b)) in index.slice()
127+
.iter()
128+
.take(take_n)
129+
.zip(last_index.slice().iter())
130+
.enumerate() {
131+
if a != b {
132+
if print_row {
133+
printed_ellipses_v = false;
134+
// New row.
135+
// # of ['s needed
136+
let n = ndim - i - 1;
137+
if !no_rows_after_skip_yet {
138+
for _ in 0..n {
139+
write!(f, "]")?;
140+
}
141+
write!(f, ",")?;
142+
write!(f, "\n")?;
143+
}
144+
no_rows_after_skip_yet = false;
145+
for _ in 0..ndim - n {
146+
write!(f, " ")?;
147+
}
148+
for _ in 0..n {
149+
write!(f, "[")?;
150+
}
151+
} else if !printed_ellipses_h {
152+
let n = ndim - i - 1;
153+
for _ in 0..n {
154+
write!(f, "]")?;
155+
}
156+
write!(f, ",")?;
157+
write!(f, "\n")?;
158+
for _ in 0..display_mode.h_split_offset().unwrap() {
159+
write!(f, " ")?;
160+
}
161+
write!(f, "...,\n")?;
162+
printed_ellipses_h = true;
163+
}
164+
first = true;
165+
update_index = true;
166+
break;
167+
}
168+
}
169+
170+
if print_row {
171+
let mut print_elt = true;
172+
let nth_idx_val = index.slice().iter().last().unwrap();
173+
match display_mode {
174+
ArrayDisplayMode::VSplit | ArrayDisplayMode::DoubleSplit(_) => {
175+
if nth_idx_val >= &limit && nth_idx_val < &(nth_idx_max - &limit) {
176+
print_elt = false;
177+
if !printed_ellipses_v {
178+
write!(f, ", ...")?;
179+
printed_ellipses_v = true;
180+
}
181+
}
182+
}
183+
_ => {}
184+
}
185+
186+
if print_elt {
187+
if !first {
188+
write!(f, ", ")?;
189+
}
190+
first = false;
191+
format(elt, f)?;
192+
}
193+
}
194+
195+
if update_index {
196+
last_index = index;
197+
}
198+
}
199+
for _ in 0..ndim {
200+
write!(f, "]")?;
201+
}
202+
Ok(())
203+
}
204+
17205
fn format_array<A, S, D, F>(view: &ArrayBase<S, D>, f: &mut fmt::Formatter,
18206
mut format: F)
19207
-> fmt::Result
@@ -92,7 +280,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
92280
where S: Data<Elem=A>,
93281
{
94282
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95-
format_array(self, f, <_>::fmt)
283+
format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT)
96284
}
97285
}
98286

@@ -105,7 +293,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
105293
{
106294
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107295
// Add extra information for Debug
108-
format_array(self, f, <_>::fmt)?;
296+
format_array_v2(self, f, <_>::fmt, PRINT_ELEMENTS_LIMIT)?;
109297
write!(f, " shape={:?}, strides={:?}, layout={:?}",
110298
self.shape(), self.strides(), layout=self.view().layout())?;
111299
match D::NDIM {

0 commit comments

Comments
 (0)