From c4e3e7450d2e083cf4983622987e00ab7fdf212e Mon Sep 17 00:00:00 2001 From: d-monnet Date: Wed, 11 Oct 2023 18:24:16 -0400 Subject: [PATCH 01/17] add plot data export function as .csv --- Project.toml | 2 + src/profiles.jl | 120 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9cde33f9..7df212db 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] BenchmarkProfiles = "0.4.2" @@ -42,6 +43,7 @@ PrettyTables = "0.12, 1.0" SolverCore = "0.3" UnicodePlots = "3.1" julia = "^1.6.0" +CSV = "0.10" [extras] ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a" diff --git a/src/profiles.jl b/src/profiles.jl index dd9d2c80..563a153a 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -1,5 +1,5 @@ import BenchmarkProfiles: performance_profile -using BenchmarkProfiles, Plots +using BenchmarkProfiles, Plots, CSV export performance_profile, profile_solvers @@ -137,3 +137,121 @@ function profile_solvers( end p end + +""" + get_profile_solvers_data(stats, costs; kwargs) + +Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. +Data are padded with NaN to ensure .csv consistency. + +Inputs: +- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the + benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) +- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles + +Keyword arguments: +`kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. + +Output: +x_mat, y_mat: vector #costs elements containing matrices of #problems x #solvers containing the x and y coordinate of the plots. +""" +function get_profile_solvers_data( + stats::Dict{Symbol, DataFrame}, + costs::Vector{<:Function}, + kwargs... + ) + + solvers = collect(keys(stats)) + dfs = (stats[solver] for solver in solvers) + Ps = [hcat([Float64.(cost(df)) for df in dfs]...) for cost in costs] + + nprobs = size(stats[first(solvers)], 1) + nsolvers = length(solvers) + ncosts = length(costs) + npairs = div(nsolvers * (nsolvers - 1), 2) + x_data, y_data = performance_profile_data(Ps[1],kwargs...) + max_length = max([length(d) for d in x_data]...) + for i in eachindex(x_data) + append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) + append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) + end + x_mat = [hcat(x_data...)] + y_mat = [hcat(y_data...)] + for k in 2:ncosts + x_data, y_data = performance_profile_data(Ps[k],kwargs...) + max_length = max(max_length,max([length(d) for d in x_data]...)) + for i in eachindex(x_data) + append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) + append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) + end + push!(x_mat, hcat(x_data...)) + push!(y_mat, hcat(y_data...)) + end + return x_mat, y_mat +end + +""" + export_profile_solvers_data(stats, costs, costnames, filename; one_file=true, two_by_two=false, kwargs...) + +Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. +Data are padded with NaN to ensure .csv consistency. + +Inputs: +- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the + benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) +- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles +- `costnames::Vector{String}`: names to be used as titles of the profiles. +- `filename::String`: path to the export file. Do not add .csv extention to the file name. + +Keyword arguments: +- one_file::Bool: export one file per cost +Additional `kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. + +Output: +File(s) containing profile data in .csv format. +* If one_file=true, returns one file containing the data for all solvers and cost. + Columns are cost1_solver1_x, cost1_solver1_y, cost1_solver2_x, ... cost2_solver1_x, cost2_solver1_y, ... +* If one_file=false, returns as many files as the number of cost. + The names of the files contain the name of the cost, and the columns are + solver1_x, solver1_y, solver2_x, ... +""" +function export_profile_solvers_data( + stats::Dict{Symbol, DataFrame}, + costs::Vector{<:Function}, + costnames::Vector{String}, + filename::String; + one_file=true, + two_by_two=false, + kwargs... + ) + solvers = collect(keys(stats)) + nprobs = size(stats[first(solvers)], 1) + nsolvers = length(solvers) + ncosts = length(costs) + solver_names = String.(keys(stats)) + + x_mat, y_mat = get_profile_solvers_data(stats,costs) + if one_file + header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) + x_mat = hcat(x_mat...) + y_mat = hcat(y_mat...) + ncol = size(x_mat)[2] + nrow = size(x_mat)[1] + data = Matrix{Float64}(undef,nrow,ncol*2) + for i =0:ncol-1 + data[:,2*i+1] .= x_mat[:,i+1] + data[:,2*i+2] .= y_mat[:,i+1] + end + CSV.write(filename*".csv",Tables.table(data),header=header) + else + header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) + data = Matrix{Float64}(undef,nprobs,nsolvers*2) + for k in eachindex(costs) + for i =0:nsolvers-1 + data[:,2*i+1] .= x_mat[k][:,i+1] + data[:,2*i+2] .= y_mat[k][:,i+1] + end + CSV.write(filename*"$(costnames[k]).csv",Tables.table(data),header=header) + end + end +end \ No newline at end of file From b1db0e42f2090d04afa29e5a7ea19f4660418730 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Wed, 11 Oct 2023 18:38:17 -0400 Subject: [PATCH 02/17] Revert "add plot data export function as .csv" This reverts commit c4e3e7450d2e083cf4983622987e00ab7fdf212e. --- Project.toml | 2 - src/profiles.jl | 120 +----------------------------------------------- 2 files changed, 1 insertion(+), 121 deletions(-) diff --git a/Project.toml b/Project.toml index 7df212db..9cde33f9 100644 --- a/Project.toml +++ b/Project.toml @@ -24,7 +24,6 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" -CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] BenchmarkProfiles = "0.4.2" @@ -43,7 +42,6 @@ PrettyTables = "0.12, 1.0" SolverCore = "0.3" UnicodePlots = "3.1" julia = "^1.6.0" -CSV = "0.10" [extras] ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a" diff --git a/src/profiles.jl b/src/profiles.jl index 563a153a..dd9d2c80 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -1,5 +1,5 @@ import BenchmarkProfiles: performance_profile -using BenchmarkProfiles, Plots, CSV +using BenchmarkProfiles, Plots export performance_profile, profile_solvers @@ -137,121 +137,3 @@ function profile_solvers( end p end - -""" - get_profile_solvers_data(stats, costs; kwargs) - -Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. -Data are padded with NaN to ensure .csv consistency. - -Inputs: -- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the - benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) -- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles - -Keyword arguments: -`kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. - -Output: -x_mat, y_mat: vector #costs elements containing matrices of #problems x #solvers containing the x and y coordinate of the plots. -""" -function get_profile_solvers_data( - stats::Dict{Symbol, DataFrame}, - costs::Vector{<:Function}, - kwargs... - ) - - solvers = collect(keys(stats)) - dfs = (stats[solver] for solver in solvers) - Ps = [hcat([Float64.(cost(df)) for df in dfs]...) for cost in costs] - - nprobs = size(stats[first(solvers)], 1) - nsolvers = length(solvers) - ncosts = length(costs) - npairs = div(nsolvers * (nsolvers - 1), 2) - x_data, y_data = performance_profile_data(Ps[1],kwargs...) - max_length = max([length(d) for d in x_data]...) - for i in eachindex(x_data) - append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) - append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) - end - x_mat = [hcat(x_data...)] - y_mat = [hcat(y_data...)] - for k in 2:ncosts - x_data, y_data = performance_profile_data(Ps[k],kwargs...) - max_length = max(max_length,max([length(d) for d in x_data]...)) - for i in eachindex(x_data) - append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) - append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) - end - push!(x_mat, hcat(x_data...)) - push!(y_mat, hcat(y_data...)) - end - return x_mat, y_mat -end - -""" - export_profile_solvers_data(stats, costs, costnames, filename; one_file=true, two_by_two=false, kwargs...) - -Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. -Data are padded with NaN to ensure .csv consistency. - -Inputs: -- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the - benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) -- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles -- `costnames::Vector{String}`: names to be used as titles of the profiles. -- `filename::String`: path to the export file. Do not add .csv extention to the file name. - -Keyword arguments: -- one_file::Bool: export one file per cost -Additional `kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. - -Output: -File(s) containing profile data in .csv format. -* If one_file=true, returns one file containing the data for all solvers and cost. - Columns are cost1_solver1_x, cost1_solver1_y, cost1_solver2_x, ... cost2_solver1_x, cost2_solver1_y, ... -* If one_file=false, returns as many files as the number of cost. - The names of the files contain the name of the cost, and the columns are - solver1_x, solver1_y, solver2_x, ... -""" -function export_profile_solvers_data( - stats::Dict{Symbol, DataFrame}, - costs::Vector{<:Function}, - costnames::Vector{String}, - filename::String; - one_file=true, - two_by_two=false, - kwargs... - ) - solvers = collect(keys(stats)) - nprobs = size(stats[first(solvers)], 1) - nsolvers = length(solvers) - ncosts = length(costs) - solver_names = String.(keys(stats)) - - x_mat, y_mat = get_profile_solvers_data(stats,costs) - if one_file - header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) - x_mat = hcat(x_mat...) - y_mat = hcat(y_mat...) - ncol = size(x_mat)[2] - nrow = size(x_mat)[1] - data = Matrix{Float64}(undef,nrow,ncol*2) - for i =0:ncol-1 - data[:,2*i+1] .= x_mat[:,i+1] - data[:,2*i+2] .= y_mat[:,i+1] - end - CSV.write(filename*".csv",Tables.table(data),header=header) - else - header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) - data = Matrix{Float64}(undef,nprobs,nsolvers*2) - for k in eachindex(costs) - for i =0:nsolvers-1 - data[:,2*i+1] .= x_mat[k][:,i+1] - data[:,2*i+2] .= y_mat[k][:,i+1] - end - CSV.write(filename*"$(costnames[k]).csv",Tables.table(data),header=header) - end - end -end \ No newline at end of file From 2872d2e134443babc384b4741ad8002cd63cb61f Mon Sep 17 00:00:00 2001 From: d-monnet Date: Thu, 12 Oct 2023 10:00:26 -0400 Subject: [PATCH 03/17] export profile data --- src/profiles.jl | 120 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index dd9d2c80..563a153a 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -1,5 +1,5 @@ import BenchmarkProfiles: performance_profile -using BenchmarkProfiles, Plots +using BenchmarkProfiles, Plots, CSV export performance_profile, profile_solvers @@ -137,3 +137,121 @@ function profile_solvers( end p end + +""" + get_profile_solvers_data(stats, costs; kwargs) + +Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. +Data are padded with NaN to ensure .csv consistency. + +Inputs: +- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the + benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) +- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles + +Keyword arguments: +`kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. + +Output: +x_mat, y_mat: vector #costs elements containing matrices of #problems x #solvers containing the x and y coordinate of the plots. +""" +function get_profile_solvers_data( + stats::Dict{Symbol, DataFrame}, + costs::Vector{<:Function}, + kwargs... + ) + + solvers = collect(keys(stats)) + dfs = (stats[solver] for solver in solvers) + Ps = [hcat([Float64.(cost(df)) for df in dfs]...) for cost in costs] + + nprobs = size(stats[first(solvers)], 1) + nsolvers = length(solvers) + ncosts = length(costs) + npairs = div(nsolvers * (nsolvers - 1), 2) + x_data, y_data = performance_profile_data(Ps[1],kwargs...) + max_length = max([length(d) for d in x_data]...) + for i in eachindex(x_data) + append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) + append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) + end + x_mat = [hcat(x_data...)] + y_mat = [hcat(y_data...)] + for k in 2:ncosts + x_data, y_data = performance_profile_data(Ps[k],kwargs...) + max_length = max(max_length,max([length(d) for d in x_data]...)) + for i in eachindex(x_data) + append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) + append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) + end + push!(x_mat, hcat(x_data...)) + push!(y_mat, hcat(y_data...)) + end + return x_mat, y_mat +end + +""" + export_profile_solvers_data(stats, costs, costnames, filename; one_file=true, two_by_two=false, kwargs...) + +Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. +Data are padded with NaN to ensure .csv consistency. + +Inputs: +- `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the + benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) +- `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles +- `costnames::Vector{String}`: names to be used as titles of the profiles. +- `filename::String`: path to the export file. Do not add .csv extention to the file name. + +Keyword arguments: +- one_file::Bool: export one file per cost +Additional `kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. + +Output: +File(s) containing profile data in .csv format. +* If one_file=true, returns one file containing the data for all solvers and cost. + Columns are cost1_solver1_x, cost1_solver1_y, cost1_solver2_x, ... cost2_solver1_x, cost2_solver1_y, ... +* If one_file=false, returns as many files as the number of cost. + The names of the files contain the name of the cost, and the columns are + solver1_x, solver1_y, solver2_x, ... +""" +function export_profile_solvers_data( + stats::Dict{Symbol, DataFrame}, + costs::Vector{<:Function}, + costnames::Vector{String}, + filename::String; + one_file=true, + two_by_two=false, + kwargs... + ) + solvers = collect(keys(stats)) + nprobs = size(stats[first(solvers)], 1) + nsolvers = length(solvers) + ncosts = length(costs) + solver_names = String.(keys(stats)) + + x_mat, y_mat = get_profile_solvers_data(stats,costs) + if one_file + header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) + x_mat = hcat(x_mat...) + y_mat = hcat(y_mat...) + ncol = size(x_mat)[2] + nrow = size(x_mat)[1] + data = Matrix{Float64}(undef,nrow,ncol*2) + for i =0:ncol-1 + data[:,2*i+1] .= x_mat[:,i+1] + data[:,2*i+2] .= y_mat[:,i+1] + end + CSV.write(filename*".csv",Tables.table(data),header=header) + else + header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) + data = Matrix{Float64}(undef,nprobs,nsolvers*2) + for k in eachindex(costs) + for i =0:nsolvers-1 + data[:,2*i+1] .= x_mat[k][:,i+1] + data[:,2*i+2] .= y_mat[k][:,i+1] + end + CSV.write(filename*"$(costnames[k]).csv",Tables.table(data),header=header) + end + end +end \ No newline at end of file From 0f55098ac5ea53aafb6f24a57925ece8001d4cfa Mon Sep 17 00:00:00 2001 From: d-monnet Date: Thu, 12 Oct 2023 10:37:14 -0400 Subject: [PATCH 04/17] add CSV deps --- Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Project.toml b/Project.toml index 9cde33f9..7df212db 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] BenchmarkProfiles = "0.4.2" @@ -42,6 +43,7 @@ PrettyTables = "0.12, 1.0" SolverCore = "0.3" UnicodePlots = "3.1" julia = "^1.6.0" +CSV = "0.10" [extras] ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a" From d3890569bfbb18ff9601517ed89ba6a30810742d Mon Sep 17 00:00:00 2001 From: d-monnet Date: Fri, 13 Oct 2023 10:07:47 -0400 Subject: [PATCH 05/17] Limits NaN padding in exported files add export function test --- Project.toml | 4 ++-- src/profiles.jl | 13 ++++++------- test/profiles.jl | 13 +++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Project.toml b/Project.toml index 7df212db..d7d29431 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.5.5" BenchmarkProfiles = "ecbce9bc-3e5e-569d-9e29-55181f61f8d0" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" GitHub = "bc5e4493-9b4d-5f90-b8aa-2b2bcaad7a26" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" @@ -24,12 +25,12 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" -CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] BenchmarkProfiles = "0.4.2" BenchmarkTools = "^0.4.2, 0.5, 0.6, 0.7, 1" ColorSchemes = "^3.9" +CSV = "0.10" DataFrames = "^0.21, 1" GitHub = "^5.0.2" JLD2 = "0.1.12, 0.2, 0.3, 0.4" @@ -43,7 +44,6 @@ PrettyTables = "0.12, 1.0" SolverCore = "0.3" UnicodePlots = "3.1" julia = "^1.6.0" -CSV = "0.10" [extras] ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a" diff --git a/src/profiles.jl b/src/profiles.jl index 563a153a..a4898537 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -1,7 +1,7 @@ import BenchmarkProfiles: performance_profile using BenchmarkProfiles, Plots, CSV -export performance_profile, profile_solvers +export performance_profile, profile_solvers, export_profile_solvers_data """ performance_profile(stats, cost, args...; b = PlotsBackend(), kwargs...) @@ -153,7 +153,7 @@ Keyword arguments: `kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. Output: -x_mat, y_mat: vector #costs elements containing matrices of #problems x #solvers containing the x and y coordinate of the plots. +x_mat, y_mat: vector #costs elements containing matrices containing the x and y coordinate of the plots. Matrices are padded with NaN if necessary (plots do not have the same number of points). """ function get_profile_solvers_data( stats::Dict{Symbol, DataFrame}, @@ -170,7 +170,7 @@ function get_profile_solvers_data( ncosts = length(costs) npairs = div(nsolvers * (nsolvers - 1), 2) x_data, y_data = performance_profile_data(Ps[1],kwargs...) - max_length = max([length(d) for d in x_data]...) + nmaxrow = maximum(length.(x_data)) for i in eachindex(x_data) append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) @@ -179,7 +179,7 @@ function get_profile_solvers_data( y_mat = [hcat(y_data...)] for k in 2:ncosts x_data, y_data = performance_profile_data(Ps[k],kwargs...) - max_length = max(max_length,max([length(d) for d in x_data]...)) + nmaxrow = max(nmaxrow,maximum(length.(x_data))) for i in eachindex(x_data) append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) append!(y_data[i],[NaN for i=1:nprobs-length(y_data[i])]) @@ -187,7 +187,7 @@ function get_profile_solvers_data( push!(x_mat, hcat(x_data...)) push!(y_mat, hcat(y_data...)) end - return x_mat, y_mat + return [m[1:nmaxrow,:] for m in x_mat], [m[1:nmaxrow,:] for m in y_mat] end """ @@ -221,7 +221,6 @@ function export_profile_solvers_data( costnames::Vector{String}, filename::String; one_file=true, - two_by_two=false, kwargs... ) solvers = collect(keys(stats)) @@ -251,7 +250,7 @@ function export_profile_solvers_data( data[:,2*i+1] .= x_mat[k][:,i+1] data[:,2*i+2] .= y_mat[k][:,i+1] end - CSV.write(filename*"$(costnames[k]).csv",Tables.table(data),header=header) + CSV.write(filename*"_$(costnames[k]).csv",Tables.table(data),header=header) end end end \ No newline at end of file diff --git a/test/profiles.jl b/test/profiles.jl index 33088a11..e4b6117a 100644 --- a/test/profiles.jl +++ b/test/profiles.jl @@ -18,6 +18,19 @@ function test_profiles() b = SolverBenchmark.BenchmarkProfiles.PGFPlotsXBackend(), ) end + @info "Exporting perfomance profiles" + filename = "profiles" + @show stats + export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles") + @test isfile(filename * ".csv") + rm(filename * ".csv") + + export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles",one_file=false) + @test isfile(filename * "_Time.csv") + @test isfile(filename * "_Iterations.csv") + rm(filename * "_Time.csv") + rm(filename * "_Iterations.csv") + nothing end From d87582a782665d13a27a08c24433e11ed841a943 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Mon, 16 Oct 2023 10:13:23 -0400 Subject: [PATCH 06/17] add .csv header as kwarg correct kwargs passing --- src/profiles.jl | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index a4898537..a98f79e5 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -86,7 +86,7 @@ function profile_solvers( string.(solvers), palette = colors, title = costnames[1], - legend = :bottomright, + legend = :bottomright ), ] nsolvers > 2 && xlabel!(ps[1], "") @@ -157,7 +157,7 @@ x_mat, y_mat: vector #costs elements containing matrices containing the x and y """ function get_profile_solvers_data( stats::Dict{Symbol, DataFrame}, - costs::Vector{<:Function}, + costs::Vector{<:Function}; kwargs... ) @@ -169,7 +169,7 @@ function get_profile_solvers_data( nsolvers = length(solvers) ncosts = length(costs) npairs = div(nsolvers * (nsolvers - 1), 2) - x_data, y_data = performance_profile_data(Ps[1],kwargs...) + x_data, y_data = performance_profile_data(Ps[1]; kwargs...) nmaxrow = maximum(length.(x_data)) for i in eachindex(x_data) append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) @@ -178,7 +178,7 @@ function get_profile_solvers_data( x_mat = [hcat(x_data...)] y_mat = [hcat(y_data...)] for k in 2:ncosts - x_data, y_data = performance_profile_data(Ps[k],kwargs...) + x_data, y_data = performance_profile_data(Ps[k];kwargs...) nmaxrow = max(nmaxrow,maximum(length.(x_data))) for i in eachindex(x_data) append!(x_data[i],[NaN for i=1:nprobs-length(x_data[i])]) @@ -204,7 +204,9 @@ Inputs: - `filename::String`: path to the export file. Do not add .csv extention to the file name. Keyword arguments: -- one_file::Bool: export one file per cost +- `one_file::Bool`: export one file per cost if false, otherwise profiles for all costs are exported in a single file +- `header::Vector{Vector{String}}`: Contains .csv file(s) column names for each files. Example for two costs exported in two files and two solvers "alpha" and "beta": `[ ["alpha_x","alpha_y","beta_x","beta_y"] for _=1:2]`. Note that `header` value does not change columns order in .csv exported files (see Output). + Additional `kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. Output: @@ -220,6 +222,7 @@ function export_profile_solvers_data( costs::Vector{<:Function}, costnames::Vector{String}, filename::String; + header = Vector{Vector{String}}[]; one_file=true, kwargs... ) @@ -228,10 +231,15 @@ function export_profile_solvers_data( nsolvers = length(solvers) ncosts = length(costs) solver_names = String.(keys(stats)) + csv_header = Vector{String}[] - x_mat, y_mat = get_profile_solvers_data(stats,costs) + x_mat, y_mat = get_profile_solvers_data(stats,costs;kwargs) if one_file - header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) + if isempty(header) + csv_header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) + else + csv_header = header[1] + end x_mat = hcat(x_mat...) y_mat = hcat(y_mat...) ncol = size(x_mat)[2] @@ -243,9 +251,12 @@ function export_profile_solvers_data( end CSV.write(filename*".csv",Tables.table(data),header=header) else - header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) + csv_header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) data = Matrix{Float64}(undef,nprobs,nsolvers*2) for k in eachindex(costs) + if !isempty(header) + csv_header = header[k] + end for i =0:nsolvers-1 data[:,2*i+1] .= x_mat[k][:,i+1] data[:,2*i+2] .= y_mat[k][:,i+1] From d0c284db5630b4326f2fab33678ff85fd5b9e518 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Mon, 16 Oct 2023 15:23:42 -0400 Subject: [PATCH 07/17] some fixes --- src/profiles.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index a98f79e5..f6e08a6c 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -222,7 +222,7 @@ function export_profile_solvers_data( costs::Vector{<:Function}, costnames::Vector{String}, filename::String; - header = Vector{Vector{String}}[]; + header::Vector{Vector{String}}=[], one_file=true, kwargs... ) @@ -233,7 +233,7 @@ function export_profile_solvers_data( solver_names = String.(keys(stats)) csv_header = Vector{String}[] - x_mat, y_mat = get_profile_solvers_data(stats,costs;kwargs) + x_mat, y_mat = get_profile_solvers_data(stats,costs;kwargs...) if one_file if isempty(header) csv_header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) From 1bbe0263bceb3bd4098429e278f5b7ac687fb9b9 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Wed, 18 Oct 2023 10:43:30 -0400 Subject: [PATCH 08/17] some fixes --- src/profiles.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index f6e08a6c..f7a9da6d 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -222,7 +222,7 @@ function export_profile_solvers_data( costs::Vector{<:Function}, costnames::Vector{String}, filename::String; - header::Vector{Vector{String}}=[], + header=[], one_file=true, kwargs... ) @@ -249,7 +249,7 @@ function export_profile_solvers_data( data[:,2*i+1] .= x_mat[:,i+1] data[:,2*i+2] .= y_mat[:,i+1] end - CSV.write(filename*".csv",Tables.table(data),header=header) + CSV.write(filename*".csv",Tables.table(data),header=csv_header) else csv_header = vcat([[sname*"_x",sname*"_y"] for sname in solver_names]...) data = Matrix{Float64}(undef,nprobs,nsolvers*2) @@ -261,7 +261,7 @@ function export_profile_solvers_data( data[:,2*i+1] .= x_mat[k][:,i+1] data[:,2*i+2] .= y_mat[k][:,i+1] end - CSV.write(filename*"_$(costnames[k]).csv",Tables.table(data),header=header) + CSV.write(filename*"_$(costnames[k]).csv",Tables.table(data),header=csv_header) end end end \ No newline at end of file From 024562433946bb6fea076e6a6c4f4cd5a6efe516 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Thu, 19 Oct 2023 11:14:37 -0400 Subject: [PATCH 09/17] add header tests for export --- src/profiles.jl | 9 ++++----- test/profiles.jl | 12 ++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index f7a9da6d..74c9f9d2 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -220,16 +220,15 @@ File(s) containing profile data in .csv format. function export_profile_solvers_data( stats::Dict{Symbol, DataFrame}, costs::Vector{<:Function}, - costnames::Vector{String}, + costnames::S, filename::String; - header=[], + header = [], one_file=true, kwargs... - ) + ) where {S <: Vector{String}} solvers = collect(keys(stats)) nprobs = size(stats[first(solvers)], 1) nsolvers = length(solvers) - ncosts = length(costs) solver_names = String.(keys(stats)) csv_header = Vector{String}[] @@ -238,7 +237,7 @@ function export_profile_solvers_data( if isempty(header) csv_header = vcat([vcat([[cname*"_"*sname*"_x",cname*"_"*sname*"_y"] for sname in solver_names]...) for cname in costnames]...) else - csv_header = header[1] + csv_header = vcat(header...) end x_mat = hcat(x_mat...) y_mat = hcat(y_mat...) diff --git a/test/profiles.jl b/test/profiles.jl index e4b6117a..52c1bbb6 100644 --- a/test/profiles.jl +++ b/test/profiles.jl @@ -18,14 +18,22 @@ function test_profiles() b = SolverBenchmark.BenchmarkProfiles.PGFPlotsXBackend(), ) end + @info "Exporting perfomance profiles" filename = "profiles" - @show stats export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles") @test isfile(filename * ".csv") rm(filename * ".csv") + export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles";header=[["x" for _ in 1:6] for _ in 1:2]) + @test isfile(filename * ".csv") + rm(filename * ".csv") - export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles",one_file=false) + export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles";one_file=false) + @test isfile(filename * "_Time.csv") + @test isfile(filename * "_Iterations.csv") + rm(filename * "_Time.csv") + rm(filename * "_Iterations.csv") + export_profile_solvers_data(stats,[df -> df.t, df -> df.iter],["Time", "Iterations"],"profiles";one_file=false,header=[["x" for _ in 1:6] for _ in 1:2]) @test isfile(filename * "_Time.csv") @test isfile(filename * "_Iterations.csv") rm(filename * "_Time.csv") From 9b9f7c9be1e19939e5d41d7a2b5598f3938f8ebe Mon Sep 17 00:00:00 2001 From: d-monnet <70266099+d-monnet@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:28:26 -0400 Subject: [PATCH 10/17] Update src/profiles.jl Co-authored-by: tmigot --- src/profiles.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index 74c9f9d2..1da3aca3 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -201,7 +201,7 @@ Inputs: benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) - `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles - `costnames::Vector{String}`: names to be used as titles of the profiles. -- `filename::String`: path to the export file. Do not add .csv extention to the file name. +- `filename::String`: path to the export file without the .csv extention. Keyword arguments: - `one_file::Bool`: export one file per cost if false, otherwise profiles for all costs are exported in a single file From 449695e6d544b23a591eb77f301194477ef4db75 Mon Sep 17 00:00:00 2001 From: d-monnet <70266099+d-monnet@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:29:17 -0400 Subject: [PATCH 11/17] Update src/profiles.jl Co-authored-by: tmigot --- src/profiles.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index 1da3aca3..0ebf7072 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -149,8 +149,7 @@ Inputs: benchmark results per solver (e.g., produced by `bmark_results_to_dataframes()`) - `costs::Vector{Function}`: a vector of functions specifying the measures to use in the profiles -Keyword arguments: -`kwargs` are passed to `BenchmarkProfiles.performance_profile_data()`. +Keyword arguments are passed to `BenchmarkProfiles.performance_profile_data()`. Output: x_mat, y_mat: vector #costs elements containing matrices containing the x and y coordinate of the plots. Matrices are padded with NaN if necessary (plots do not have the same number of points). From b8ac47d84c6d40f8478d408eefefdf8ab880afa7 Mon Sep 17 00:00:00 2001 From: d-monnet <70266099+d-monnet@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:29:34 -0400 Subject: [PATCH 12/17] Update src/profiles.jl Co-authored-by: tmigot --- src/profiles.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index 0ebf7072..127c6c72 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -139,7 +139,7 @@ function profile_solvers( end """ - get_profile_solvers_data(stats, costs; kwargs) + get_profile_solvers_data(stats, costs; kwargs...) Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. Data are padded with NaN to ensure .csv consistency. From 58773c76db726c9dc3654b8359b68e418ad337d1 Mon Sep 17 00:00:00 2001 From: d-monnet <70266099+d-monnet@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:30:50 -0400 Subject: [PATCH 13/17] Update src/profiles.jl Co-authored-by: tmigot --- src/profiles.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index 127c6c72..73e9edad 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -152,7 +152,8 @@ Inputs: Keyword arguments are passed to `BenchmarkProfiles.performance_profile_data()`. Output: -x_mat, y_mat: vector #costs elements containing matrices containing the x and y coordinate of the plots. Matrices are padded with NaN if necessary (plots do not have the same number of points). +x_mat, y_mat: vectors #costs elements containing matrices containing the x and y coordinate of the plots. +Matrices are padded with NaN if necessary, e.g., plots do not have the same number of points. """ function get_profile_solvers_data( stats::Dict{Symbol, DataFrame}, From 23be284c57aec67e60d95bc15c1f7574c38738b7 Mon Sep 17 00:00:00 2001 From: d-monnet Date: Mon, 23 Oct 2023 11:36:13 -0400 Subject: [PATCH 14/17] update doc --- src/profiles.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index 73e9edad..ef68e555 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -142,7 +142,6 @@ end get_profile_solvers_data(stats, costs; kwargs...) Exports performance profiles plot data comparing `solvers` based on the data in `stats` in a .csv file. -Data are padded with NaN to ensure .csv consistency. Inputs: - `stats::Dict{Symbol,DataFrame}`: a dictionary of `DataFrame`s containing the @@ -152,8 +151,8 @@ Inputs: Keyword arguments are passed to `BenchmarkProfiles.performance_profile_data()`. Output: -x_mat, y_mat: vectors #costs elements containing matrices containing the x and y coordinate of the plots. -Matrices are padded with NaN if necessary, e.g., plots do not have the same number of points. +x_mat, y_mat: vectors which elements are matrices containing the x and y coordinate of the plots. Each matrix correspond to a cost, matrices columns correspond to solvers. +Matrices are padded with NaN if necessary (happens if plots do not have the same number of points). """ function get_profile_solvers_data( stats::Dict{Symbol, DataFrame}, From c05ba15b8fbff3240d9394c2177a8b71db242aad Mon Sep 17 00:00:00 2001 From: tmigot Date: Mon, 23 Oct 2023 18:33:57 +0200 Subject: [PATCH 15/17] Switch test order --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 5238ed76..5518d3a1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,6 +13,6 @@ using SolverBenchmark include("data.jl") include("tables.jl") -include("profiles.jl") include("pkgbmark.jl") include("test_bmark.jl") +include("profiles.jl") From d574f62eb3927a8c41a089af2d76d7acf591a8ed Mon Sep 17 00:00:00 2001 From: tmigot Date: Mon, 23 Oct 2023 19:18:01 +0200 Subject: [PATCH 16/17] Update src/profiles.jl --- src/profiles.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index ef68e555..967629ef 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -86,7 +86,7 @@ function profile_solvers( string.(solvers), palette = colors, title = costnames[1], - legend = :bottomright + legend = :bottomright, ), ] nsolvers > 2 && xlabel!(ps[1], "") From 4faf56cd3ac0bfed177eec522b61b81e1bb59718 Mon Sep 17 00:00:00 2001 From: tmigot Date: Mon, 23 Oct 2023 19:18:44 +0200 Subject: [PATCH 17/17] Update src/profiles.jl --- src/profiles.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiles.jl b/src/profiles.jl index 967629ef..5c4cc0f5 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -262,4 +262,4 @@ function export_profile_solvers_data( CSV.write(filename*"_$(costnames[k]).csv",Tables.table(data),header=csv_header) end end -end \ No newline at end of file +end