/
solver_trace.jl
114 lines (97 loc) · 3.75 KB
/
solver_trace.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
SolverTrace(num_steps, i, print_interval, io, progress, columns, callbacks)
Represents a solver trace for `num_steps` iterations, `i` being the
current one. Each time [`next!`](@ref) is called, `i` is incremented
by one, and if a multiple of `print_interval` is reached, a line is
printed in the trace. Optionally (default), a `ProgressMeter.Progress`
is shown as well, providing progress information between solver trace
printouts.
"""
mutable struct SolverTrace{P,TCs,Callbacks,IOt<:IO}
num_steps::Int
i::Int
print_interval::Int
io::IOt
progress::P
columns::TCs
callbacks::Callbacks
end
"""
SolverTrace(num_steps[, column=CurrentStep(num_steps), columns...;
io=stdout, num_printouts=10, progress_meter=true,
print_interval, kwargs...])
Construct a [`SolverTrace`](@ref) for `num_steps` iterations, with the
`columns` that are to appear in the solver trace. The solver trace is
printed to `io`, `num_printouts` lines will appear; alternatively, the
`print_interval` can be specified directly. Below the solver trace, a
progressbar is displayed, unless `!progress_meter`. `kwargs...` are
passed on to `ProgressMeter.Progress`.
"""
function SolverTrace(num_steps::Int,
column::TraceColumn = CurrentStep(num_steps),
columns::TraceColumn...;
io::IO=stdout,
num_printouts::Integer=min(num_steps,10),
progress_meter::Bool=true,
callbacks=(),
print_interval = num_printouts > num_steps ? 1 : num_steps÷num_printouts,
kwargs...)
columns = (column,columns...)
progress = if progress_meter
Progress(num_steps; kwargs...)
else
nothing
end
SolverTrace(num_steps, 0, print_interval, io, progress, columns, callbacks)
end
clear_current_line(io::IO=stdout) = print(io, "\r\u1b[K")
"""
print_header(s)
Print the associated header of the [`SolverTrace`](@ref) `s`.
"""
print_header(s::SolverTrace) =
println(s.io,
crayon"underline",
join(map(column -> column.header, s.columns), " "),
crayon"reset")
print_header(::Nothing) = nothing
Formatting.format(s::SolverTrace) =
join(map(column -> format(column, s.i), s.columns), " ")
next!(::Nothing; kwargs...) = nothing
next!(progress::Progress; kwargs...) = ProgressMeter.next!(progress; kwargs...)
"""
next!(fun, s::SolverTrace; kwargs...)
Signal to the [`SolverTrace`](@ref) `s` that the next iteration has
been performed, increasing the internal counter `s.i`. If a multiple
of `s.print_interval` is reached, a line in the solver trace is
printed, formatting each and every trace column, the callback function
`fun` is called, as well as all the registered callbacks.
`kwargs` are passed on to `ProgressMeter.next!` to allow
e.g. `showvalues` functionality.
"""
function next!(fun::Function, s::SolverTrace; kwargs...)
s.i += 1
if s.i%s.print_interval == 0 || s.i==1
fun()
# Carriage return & clearing has to be done on stderr since
# ProgressMeter prints to that stream; this is important on
# Windows.
isnothing(s.progress) || clear_current_line(stderr)
println(s.io, format(s))
foreach(f -> f(s.i), s.callbacks)
end
next!(s.progress; kwargs...)
end
next!(s::SolverTrace; kwargs...) = next!(() -> nothing, s; kwargs...)
"""
ColumnSeparator(fmt, header)
Simple separator between columns, that by default simply prints a
pipe.
"""
struct ColumnSeparator <: TraceColumn
fmt::FormatExpr
header::String
end
ColumnSeparator() = ColumnSeparator(FormatExpr("│"), " ")
(c::ColumnSeparator)(i::Integer) = ()
export SolverTrace, print_header, ColumnSeparator