Skip to content

Commit

Permalink
Merge e26859e into 9d98958
Browse files Browse the repository at this point in the history
  • Loading branch information
abelsiqueira committed Dec 10, 2017
2 parents 9d98958 + e26859e commit cef3646
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Compat.String

# Auxiliary.
include("auxiliary/bounds.jl")
include("stats/stats.jl")

# Algorithmic components.
include("linesearch/linesearch.jl")
Expand Down
165 changes: 165 additions & 0 deletions src/stats/stats.jl
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
3 changes: 3 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ end

# Test TRON
include("solvers/tron.jl")

# Test ExecutionStats
include("test_stats.jl")
24 changes: 24 additions & 0 deletions test/test_stats.jl
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()

0 comments on commit cef3646

Please sign in to comment.