-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
export AbstractExecutionStats, GenericExecutionStats, | ||
AbstractExtraStats, DictExtraStats, | ||
set_stat!, get_stat, statshead, statsline | ||
|
||
const STATUSES = Dict(:unknown => "unknown", | ||
:first_order => "first-order stationary", | ||
:max_eval => "maximum number of function evaluations", | ||
:max_time => "maximum elapsed time", | ||
:max_iter => "maximum iteration", | ||
:neg_pred => "negative predicted reduction", | ||
:unbounded => "objective function may be unbounded from below", | ||
:exception => "unhandled exception", | ||
:stalled => "stalled" | ||
) | ||
|
||
abstract type AbstractExecutionStats end | ||
|
||
abstract type AbstractExtraStats <: AbstractExecutionStats end | ||
|
||
type GenericExecutionStats <: AbstractExecutionStats | ||
status :: Symbol | ||
solution :: Vector # x | ||
objective :: Float64 # f(x) | ||
dual_feas :: Float64 # ‖∇f(x)‖₂ for unc, ‖P[x - ∇f(x)] - x‖₂ for bnd, etc. | ||
iter :: Int | ||
counters :: NLPModels.Counters | ||
elapsed_time :: Float64 | ||
solver_specific :: AbstractExtraStats | ||
end | ||
|
||
function GenericExecutionStats(status :: Symbol, | ||
nlp :: AbstractNLPModel; | ||
solution :: Vector=Float64[], | ||
objective :: Float64=Inf, | ||
dual_feas :: Float64=Inf, | ||
iter :: Int=-1, | ||
elapsed_time :: Float64=Inf, | ||
solver_specific :: AbstractExtraStats=DictExtraStats()) | ||
if !(status in keys(STATUSES)) | ||
s = join(keys(STATUSES, ", ")) | ||
error("$status is not a valid status. Use one of the following: $s") | ||
end | ||
c = Counters() | ||
for counter in fieldnames(Counters) | ||
setfield!(c, counter, eval(parse("$counter"))(nlp)) | ||
end | ||
return GenericExecutionStats(status, solution, objective, dual_feas, iter, | ||
c, elapsed_time, solver_specific) | ||
end | ||
|
||
|
||
type DictExtraStats <: AbstractExtraStats | ||
stats_dict :: Dict{Symbol,Any} | ||
end | ||
|
||
function DictExtraStats() | ||
return DictExtraStats(Dict{Symbol,Any}()) | ||
end | ||
|
||
function set_stat!(stats :: DictExtraStats, stat :: Symbol, value :: Any) | ||
stats.stats_dict[stat] = value | ||
end | ||
|
||
function get_stat(stats :: DictExtraStats, stat :: Symbol) | ||
return stats.stats_dict[stat] | ||
end | ||
|
||
import Base.show, Base.print, Base.println | ||
|
||
function show(io :: IO, stats :: AbstractExecutionStats) | ||
show(io, "Execution stats: $(getStatus(stats))") | ||
end | ||
|
||
# TODO: Expose NLPModels dsp in nlp_types.jl function print | ||
function disp_vector(io :: IO, x :: Vector) | ||
if length(x) == 0 | ||
@printf(io, "∅") | ||
elseif length(x) <= 5 | ||
Base.show_delim_array(io, x, "[", " ", "]", false) | ||
else | ||
Base.show_delim_array(io, x[1:4], "[", " ", "", false) | ||
@printf(io, " ⋯ %s]", x[end]) | ||
end | ||
end | ||
|
||
function print(io :: IO, stats :: GenericExecutionStats; showvec :: Function=disp_vector) | ||
# TODO: Show evaluations | ||
@printf(io, "Generic Execution stats\n") | ||
@printf(io, " status: "); show(io, getStatus(stats)); @printf(io, "\n") | ||
@printf(io, " objective value: "); show(io, stats.objective); @printf(io, "\n") | ||
@printf(io, " dual feasibility: "); show(io, stats.dual_feas); @printf(io, "\n") | ||
@printf(io, " solution: "); showvec(io, stats.solution); @printf(io, "\n") | ||
@printf(io, " iterations: "); show(io, stats.iter); @printf(io, "\n") | ||
@printf(io, " elapsed time: "); show(io, stats.elapsed_time); @printf(io, "\n") | ||
print(io, stats.solver_specific) | ||
end | ||
|
||
print(stats :: AbstractExecutionStats; showvec :: Function=disp_vector) = | ||
print(STDOUT, stats, showvec=showvec) | ||
println(io :: IO, stats :: AbstractExecutionStats; showvec :: | ||
Function=disp_vector) = print(io, stats, showvec=showvec) | ||
println(stats :: AbstractExecutionStats; showvec :: Function=disp_vector) = | ||
print(STDOUT, stats, showvec=showvec) | ||
|
||
function print(io :: IO, stats :: DictExtraStats; showvec :: | ||
Function=disp_vector) | ||
for (k,v) in stats.stats_dict | ||
@printf(io, "%s: ", k) | ||
if isa(v, Vector) | ||
showvec(io, v) | ||
else | ||
show(io, v) | ||
end | ||
@printf(io, "\n") | ||
end | ||
end | ||
|
||
const headsym = Dict(:status => " Status", | ||
:iter => " Iter", | ||
:neval_obj => " #obj", | ||
:neval_grad => " #grad", | ||
:neval_cons => " #cons", | ||
:neval_jcon => " #jcon", | ||
:neval_jgrad => " #jgrad", | ||
:neval_jac => " #jac", | ||
:neval_jprod => " #jprod", | ||
:neval_jtprod => "#jtprod", | ||
:neval_hess => " #hess", | ||
:neval_hprod => " #hprod", | ||
:neval_jhprod => "#jhprod", | ||
:objective => " f", | ||
:dual_feas => " ‖∇f‖", | ||
:elapsed_time => " Elaspsed time") | ||
|
||
function statsgetfield(stats :: AbstractExecutionStats, name :: Symbol) | ||
t = Int | ||
if name == :status | ||
v = getStatus(stats) | ||
t = String | ||
elseif name in fieldnames(NLPModels.Counters) | ||
v = getfield(stats.counters, name) | ||
elseif name in fieldnames(AbstractExecutionStats) | ||
v = getfield(stats, name) | ||
t = fieldtype(AbstractExecutionStats, name) | ||
end | ||
if t == Int | ||
@sprintf("%7d", v) | ||
elseif t == Float64 | ||
@sprintf("%15.8e", v) | ||
else | ||
@sprintf("%8s", v) | ||
end | ||
end | ||
|
||
function statshead(line :: Array{Symbol}) | ||
return join([headsym[x] for x in line], " ") | ||
end | ||
|
||
function statsline(stats :: AbstractExecutionStats, line :: Array{Symbol}) | ||
return join([statsgetfield(stats, x) for x in line], " ") | ||
end | ||
|
||
function getStatus(stats :: AbstractExecutionStats) | ||
return STATUSES[stats.status] | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,3 +44,6 @@ end | |
|
||
# Test TRON | ||
include("solvers/tron.jl") | ||
|
||
# Test ExecutionStats | ||
include("test_stats.jl") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
function test_stats() | ||
nlp = ADNLPModel(x->dot(x,x), zeros(2)) | ||
stats = GenericExecutionStats(:first_order, nlp, objective=1.0, dual_feas=1e-12, | ||
solution=ones(100)) | ||
extra_stats = DictExtraStats() | ||
set_stat!(extra_stats, :matvec, 10) | ||
set_stat!(extra_stats, :dot, 25) | ||
set_stat!(extra_stats, :axpy, 20) | ||
set_stat!(extra_stats, :ray, -1 ./ (1:100)) | ||
stats = GenericExecutionStats(:first_order, nlp, objective=1.0, dual_feas=1e-12, | ||
solution=ones(100), solver_specific=extra_stats) | ||
|
||
println(stats) | ||
open("teststats.out", "w") do f | ||
println(f, stats) | ||
end | ||
|
||
println(stats, showvec=(io,x)->print(io,x)) | ||
open("teststats.out", "a") do f | ||
println(f, stats, showvec=(io,x)->print(io,x)) | ||
end | ||
end | ||
|
||
test_stats() |