dogs 1.3.0

Discrete Optimization Global Search framework. Implements various search algorithms that can be found in combinatorial optimization or heuristic search.
Documentation
module ParetoDiagram

using Plots
using LaTeXStrings
using Statistics
using ColorSchemes
using Crayons
using Crayons.Box


"""
given some arpd point lists, draw the curves
"""
function draw_arpd_diagrams(solvers_arpd_points, inst_class, output_dir, name="")
    # create plot
    if name == ""
        name = "pareto_diagram"
    end
    output_filename = "$(output_dir)/$(name)_$(inst_class).pdf"
    p = plot(fontfamily="serif-roman")
    xlabel!("CPU time in seconds on instances of type `$(inst_class)'")
    ylabel!("average relative percentage deviation")
    for solver in keys(solvers_arpd_points)
        if "curve" in keys(solvers_arpd_points[solver])
            points = collect(zip(solvers_arpd_points[solver]["curve"]...))
            x = collect(points[1])
            y = collect(points[2])
            plot!(p, x, y, label=solver, linetype=:steppost)
        elseif "multiple_y" in keys(solvers_arpd_points[solver])
            tmp = solvers_arpd_points[solver]["multiple_y"]
            x = tmp[1]
            ys = tmp[2]
            mean_y = mean(ys)
            # scatter!(
            #     [ x ],[ mean_y ],
            #     marker=:xcross,
            #     label=false,
            #     yerror=ys,
            #     markerstrokecolor=:auto
            # )
            scatter!(
                fill(x, length(ys)), ys,
                marker=:xcross,
                label=false,
                markerstrokecolor=:auto
            )
            annotate!(x, mean_y, text(solver, :top, 5))
        elseif "single_y" in keys(solvers_arpd_points[solver])
            tmp = solvers_arpd_points[solver]["single_y"]
            x = tmp[1]
            y = tmp[2]
            scatter!(
                [ x ],[ y ],
                marker=:xcross,
                label=false,
                markerstrokecolor=:auto
            )
            annotate!(x, y, text(solver, :top, 5))
        else
            println(RED_FG("'best_primal' nor 'primal_list' is found"))
        end
    end
    # export it
    gr()
    # pgfplotsx()
    savefig(p, output_filename)
end

"""
given a list of statistics for a specific algorithm on each instance of an
instance class, compute a set of points representing the evolution of the ARPD.
"""
function create_arpd_points(performances, references_primal, time_limit, nb_steps=200)
    step_size = float(time_limit)/nb_steps
    arpd_y = zeros(nb_steps+1) # one for each step
    step_where_all_have_solution = 1
    for (perf_id, perf) in enumerate(performances)
        previous_objective = 0.
        found_solution = false
        current_step = 1
        for point in perf["primal_pareto_diagram"]
            while point["time"] > current_step*step_size && current_step <= nb_steps
                arpd_y[current_step] += previous_objective
                if !found_solution
                    step_where_all_have_solution = max(
                        step_where_all_have_solution,
                        current_step
                    )
                end
                current_step += 1
            end
            found_solution = true
            previous_objective = (float(point["primal"])-references_primal[perf_id])/references_primal[perf_id]
        end
        while current_step <= nb_steps+1
            arpd_y[current_step] += previous_objective
            current_step += 1
        end
    end
    arpd_y = arpd_y .* (100. / length(performances))
    arpd_points = []
    for i in step_where_all_have_solution:nb_steps+1
        push!(arpd_points, (i*step_size, arpd_y[i]))
    end
    res = Dict()
    res["curve"] = arpd_points
    return res
end

"""
create pareto diagrams. They plot for each instance class, the evolution
of the solution quality (ARPD) relative to the time.
"""
function generate_pareto_diagrams(instance_classes, arpd_refs, custom_arpds_data, solver_variants, solver_variant_and_instance, output_dir, name="")
    # for each instance class
    for inst_class in keys(instance_classes)
        references_primal = []
        for inst in instance_classes[inst_class]
            push!(references_primal, float(arpd_refs[inst.name]))
        end
        arpd_points = Dict()
        for s in solver_variants # for each solver
            performances = []
            solver_id = "$(s["name"])$(s["solver_params_compact"])"
            # if primal pareto diagram data exists
            time_limit = 0
            for inst in instance_classes[inst_class]
                time_limit = inst.time_limit
                inst_solver_id = "$(solver_id)_$(inst.name)"
                stats = solver_variant_and_instance[inst_solver_id]["stats"]
                push!(performances, stats)
            end
            if "primal_pareto_diagram" in keys(performances[1])
                arpd_points[solver_id] = create_arpd_points(performances, references_primal, time_limit)
            elseif "primal_list" in keys(performances[1])
                x = float(performances[1]["time_searched"])
                ys = collect(map((e)->e["primal_list"], performances))
                # ARPD computation
                tmp_ys = []
                for (i,a) in enumerate(ys)
                    push!(tmp_ys, collect(map((b)-> begin
                        ref_value = float(references_primal[i])
                        rpd = (float(b)-ref_value)/ref_value*100
                        rpd
                    end, a)))
                end
                ys = tmp_ys
                # collecting to the correct format
                ys = collect(zip(ys...))
                ys = collect(map((e)->mean(e), ys))
                res = Dict()
                res["multiple_y"] = [x, ys]
                arpd_points[solver_id] = res
            else
                println(RED_FG("'best_primal' nor 'primal_list' is found"))
            end
        end
        for algo_name in keys(custom_arpds_data)
            res = Dict()
            x = custom_arpds_data[algo_name][inst_class]["time"]
            ys = custom_arpds_data[algo_name][inst_class]["arpd"]
            res["single_y"] = [x, ys]
            arpd_points[algo_name] = res
        end
        draw_arpd_diagrams(arpd_points, inst_class, output_dir, name)
    end
end

end # module