-
Notifications
You must be signed in to change notification settings - Fork 12
add support for passing separate kwargs #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,17 +4,20 @@ using BenchmarkProfiles, Plots | |
| export performance_profile, profile_solvers | ||
|
|
||
| """ | ||
| performance_profile(stats, cost, args...; b = PlotsBackend(), kwargs...) | ||
| performance_profile(stats, cost; b = PlotsBackend(), kwargs...) | ||
|
|
||
| Produce a performance profile comparing solvers in `stats` using the `cost` function. | ||
|
|
||
| Inputs: | ||
| - `stats::AbstractDict{Symbol,DataFrame}`: pairs of `:solver => df`; | ||
| - `cost::Function`: cost function applyed to each `df`. Should return a vector with the cost of solving the problem at each row; | ||
| - `cost::Function`: cost function applied to each `df`. Should return a vector with the cost of solving the problem at each row; | ||
| - 0 cost is not allowed; | ||
| - If the solver did not solve the problem, return Inf or a negative number. | ||
| - If the solver did not solve the problem, return `Inf` or a negative number. | ||
| - `b::BenchmarkProfiles.AbstractBackend` : backend used for the plot. | ||
|
|
||
| Keyword arguments: | ||
| - `kwargs...` : keyword arguments forwarded to `BenchmarkProfiles.performance_profile` (backend-specific options). | ||
| Example: `logscale = false` to disable log-scaling when supported by the backend. | ||
| If several profiles will be produced with variants of the same solvers, `stats` may be an `OrderedDict`, as defined in the | ||
| OrderedCollections.jl package. | ||
|
|
||
|
|
@@ -24,21 +27,20 @@ Examples of cost functions: | |
| """ | ||
| function performance_profile( | ||
| stats::AbstractDict{Symbol, DataFrame}, | ||
| cost::Function, | ||
| args...; | ||
| cost::Function; | ||
| b::BenchmarkProfiles.AbstractBackend = PlotsBackend(), | ||
| kwargs..., | ||
| ) | ||
| solvers = keys(stats) | ||
| dfs = (stats[s] for s in solvers) | ||
| P = hcat([cost(df) for df in dfs]...) | ||
| performance_profile(b, P, string.(solvers), args...; kwargs...) | ||
| BenchmarkProfiles.performance_profile(b, P, string.(solvers); kwargs...) | ||
| end | ||
|
|
||
| """ | ||
| p = profile_solvers(stats, costs, costnames; | ||
| width = 400, height = 400, | ||
| b = PlotsBackend(), kwargs...) | ||
| b = PlotsBackend(), bp_kwargs = Dict(), kwargs...) | ||
|
|
||
| Produce performance profiles comparing `solvers` based on the data in `stats`. | ||
|
|
||
|
|
@@ -52,11 +54,9 @@ Keyword inputs: | |
| - `width::Int`: Width of each individual plot (Default: 400) | ||
| - `height::Int`: Height of each individual plot (Default: 400) | ||
| - `b::BenchmarkProfiles.AbstractBackend` : backend used for the plot. | ||
| - `bp_kwargs::Dict` : a `Dict` of keyword arguments forwarded to the `performance_profile` backend calls. | ||
|
|
||
| Additional `kwargs` are passed to the `plot` call. | ||
|
|
||
| Output: | ||
| A Plots.jl plot representing a set of performance profiles comparing the solvers. | ||
| Additional `kwargs` are passed to the final `plot` call that assembles the profiles. | ||
| The set contains performance profiles comparing all the solvers together on the | ||
| measures given in `costs`. | ||
| If there are more than two solvers, additional profiles are produced comparing the | ||
|
|
@@ -69,6 +69,7 @@ function profile_solvers( | |
| width::Int = 400, | ||
| height::Int = 400, | ||
| b::BenchmarkProfiles.AbstractBackend = PlotsBackend(), | ||
| bp_kwargs::Dict = Dict(), | ||
| kwargs..., | ||
|
Comment on lines
69
to
73
|
||
| ) | ||
| solvers = collect(keys(stats)) | ||
|
|
@@ -83,24 +84,26 @@ function profile_solvers( | |
|
|
||
| # profiles with all solvers | ||
| ps = [ | ||
| performance_profile( | ||
| BenchmarkProfiles.performance_profile( | ||
| b, | ||
| Ps[1], | ||
| string.(solvers), | ||
| string.(solvers); | ||
| palette = colors, | ||
| title = costnames[1], | ||
| legend = :bottomright, | ||
| bp_kwargs..., | ||
| ), | ||
|
Comment on lines
+87
to
95
|
||
| ] | ||
| nsolvers > 2 && xlabel!(ps[1], "") | ||
| for k = 2:ncosts | ||
| p = performance_profile( | ||
| p = BenchmarkProfiles.performance_profile( | ||
| b, | ||
| Ps[k], | ||
| string.(solvers), | ||
| string.(solvers); | ||
| palette = colors, | ||
| title = costnames[k], | ||
| legend = false, | ||
| bp_kwargs..., | ||
| ) | ||
| nsolvers > 2 && xlabel!(p, "") | ||
| ylabel!(p, "") | ||
|
|
@@ -118,11 +121,25 @@ function profile_solvers( | |
| Ps = [hcat([Float64.(cost(df)) for df in dfs]...) for cost in costs] | ||
|
|
||
| clrs = [colors[i], colors[j]] | ||
| p = performance_profile(b, Ps[1], string.(pair), palette = clrs, legend = :bottomright) | ||
| p = BenchmarkProfiles.performance_profile( | ||
| b, | ||
| Ps[1], | ||
| string.(pair); | ||
| palette = clrs, | ||
| legend = :bottomright, | ||
| bp_kwargs..., | ||
| ) | ||
| ipairs < npairs && xlabel!(p, "") | ||
| push!(ps, p) | ||
| for k = 2:ncosts | ||
| p = performance_profile(b, Ps[k], string.(pair), palette = clrs, legend = false) | ||
| p = BenchmarkProfiles.performance_profile( | ||
| b, | ||
| Ps[k], | ||
| string.(pair); | ||
| palette = clrs, | ||
| legend = false, | ||
| bp_kwargs..., | ||
| ) | ||
| ipairs < npairs && xlabel!(p, "") | ||
| ylabel!(p, "") | ||
| push!(ps, p) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| using Test | ||
| using DataFrames | ||
| using SolverBenchmark | ||
| using BenchmarkProfiles | ||
| using Plots | ||
|
|
||
| struct CaptureBackend <: BenchmarkProfiles.AbstractBackend end | ||
|
|
||
| struct CapturedPlot | ||
| labels::Vector{String} | ||
| kwargs::Any | ||
| end | ||
|
|
||
| # Extend BenchmarkProfiles.performance_profile for our CaptureBackend | ||
| function BenchmarkProfiles.performance_profile( | ||
| ::CaptureBackend, | ||
| P::Matrix{<:Number}, | ||
| labels::Vector{<:AbstractString}; | ||
| kwargs..., | ||
| ) | ||
| labs = string.(labels) | ||
| CapturedPlot(labs, kwargs) | ||
| end | ||
|
|
||
| function Plots.plot(ps::CapturedPlot...; kwargs...) | ||
| return (plots = ps, plot_kwargs = kwargs) | ||
| end | ||
|
|
||
| @testset "profiles: bp_kwargs and kwargs forwarding" begin | ||
| df1 = DataFrame(a = [1.0, 2.0]) | ||
| df2 = DataFrame(a = [2.0, 3.0]) | ||
| stats = Dict(:s1 => df1, :s2 => df2) | ||
|
|
||
| costs = [df -> df.a] | ||
| costnames = ["a"] | ||
|
|
||
| result = profile_solvers( | ||
| stats, | ||
| costs, | ||
| costnames; | ||
| b = CaptureBackend(), | ||
| bp_kwargs = Dict(:logscale => false), | ||
| ) | ||
| @test isa(result, NamedTuple) | ||
| # The inner performance_profile returns CapturedPlot objects stored in result.plots | ||
| plots = result[:plots] | ||
| @test length(plots) >= 1 | ||
| first_plot = plots[1] | ||
| @test (:logscale in keys(first_plot.kwargs)) && first_plot.kwargs[:logscale] == false | ||
|
|
||
| result2 = profile_solvers( | ||
| stats, | ||
| costs, | ||
| costnames; | ||
| b = CaptureBackend(), | ||
| bp_kwargs = Dict(:logscale => true), | ||
| title = "T", | ||
| legend = false, | ||
| ) | ||
| @test isa(result2, NamedTuple) | ||
| @test (:title in keys(result2[:plot_kwargs])) && result2[:plot_kwargs][:title] == "T" | ||
| @test (:legend in keys(result2[:plot_kwargs])) && result2[:plot_kwargs][:legend] == false | ||
|
|
||
| result3 = profile_solvers( | ||
| stats, | ||
| costs, | ||
| costnames; | ||
| b = CaptureBackend(), | ||
| bp_kwargs = Dict(:foo => 1), | ||
| bar = 2, | ||
| extra = 3, | ||
| ) | ||
| @test (:foo in keys(result3[:plots][1].kwargs)) && result3[:plots][1].kwargs[:foo] == 1 | ||
| @test (:bar in keys(result3[:plot_kwargs])) && result3[:plot_kwargs][:bar] == 2 | ||
| @test (:extra in keys(result3[:plot_kwargs])) && result3[:plot_kwargs][:extra] == 3 | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exported
performance_profilewrapper previously accepted extra positional arguments (args...) and forwarded them toBenchmarkProfiles.performance_profile, but this method signature now removes that capability. Since this is part of the public API, this is a breaking change for any callers passing additional positional parameters; consider keepingargs...(and forwarding them) or providing a deprecation path instead of removing it outright.