diff --git a/Project.toml b/Project.toml index c6588f0..1bef4ba 100644 --- a/Project.toml +++ b/Project.toml @@ -26,7 +26,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" DataDeps = "0.7" Distributions = "0.25" DocStringExtensions = "0.9" -Flux = "0.14" +Flux = "0.16" Graphs = "1.11" HiGHS = "1.9" Images = "0.26" diff --git a/src/DecisionFocusedLearningBenchmarks.jl b/src/DecisionFocusedLearningBenchmarks.jl index 21265e3..118da5b 100644 --- a/src/DecisionFocusedLearningBenchmarks.jl +++ b/src/DecisionFocusedLearningBenchmarks.jl @@ -38,7 +38,7 @@ using .PortfolioOptimization export AbstractBenchmark, DataSample export generate_dataset export generate_statistical_model -export generate_maximizer +export generate_maximizer, maximizer_kwargs export plot_data export compute_gap diff --git a/src/Utils/Utils.jl b/src/Utils/Utils.jl index 65f17d8..1426a04 100644 --- a/src/Utils/Utils.jl +++ b/src/Utils/Utils.jl @@ -15,6 +15,7 @@ export DataSample export AbstractBenchmark export generate_dataset, generate_statistical_model, generate_maximizer, plot_data, compute_gap +export maximizer_kwargs export grid_graph, get_path, path_to_matrix export neg_tensor, squeeze_last_dims, average_tensor diff --git a/src/Utils/data_sample.jl b/src/Utils/data_sample.jl index 33b7bb4..1afefbb 100644 --- a/src/Utils/data_sample.jl +++ b/src/Utils/data_sample.jl @@ -6,7 +6,9 @@ Data sample data structure. # Fields $TYPEDFIELDS """ -@kwdef struct DataSample{F,S,C,I} +@kwdef struct DataSample{ + F<:AbstractArray,S<:Union{AbstractArray,Nothing},C<:Union{AbstractArray,Nothing},I +} "features" x::F "target cost parameters (optional)" diff --git a/src/Utils/interface.jl b/src/Utils/interface.jl index 44b21fa..c750c97 100644 --- a/src/Utils/interface.jl +++ b/src/Utils/interface.jl @@ -55,10 +55,52 @@ function compute_gap end """ $TYPEDSIGNATURES +For simple benchmarks where there is no instance object, maximizer does not need any keyword arguments. +""" +function maximizer_kwargs( + ::AbstractBenchmark, sample::DataSample{F,S,C,Nothing} +) where {F,S,C} + return NamedTuple() +end + +""" +$TYPEDSIGNATURES + +For benchmarks where there is an instance object, maximizer needs the instance object as a keyword argument. +""" +function maximizer_kwargs(::AbstractBenchmark, sample::DataSample) + return (; instance=sample.instance) +end + +""" +$TYPEDSIGNATURES + Default behaviour of `objective_value`. """ -function objective_value(::AbstractBenchmark, θ̄::AbstractArray, y::AbstractArray) - return dot(θ̄, y) +function objective_value(::AbstractBenchmark, θ::AbstractArray, y::AbstractArray) + return dot(θ, y) +end + +""" +$TYPEDSIGNATURES + +Compute the objective value of the target in the sample (needs to exist). +""" +function objective_value( + bench::AbstractBenchmark, sample::DataSample{F,S,C,I} +) where {F,S<:AbstractArray,C<:AbstractArray,I} + return objective_value(bench, sample.θ_true, sample.y_true) +end + +""" +$TYPEDSIGNATURES + +Compute the objective value of given solution `y`. +""" +function objective_value( + bench::AbstractBenchmark, sample::DataSample{F,S,C,I}, y::AbstractArray +) where {F,S,C<:AbstractArray,I} + return objective_value(bench, sample.θ_true, y) end """ @@ -72,13 +114,11 @@ function compute_gap( res = 0.0 for sample in dataset + target_obj = objective_value(bench, sample) x = sample.x - θ̄ = sample.θ_true - ȳ = sample.y_true θ = statistical_model(x) - y = maximizer(θ) - target_obj = objective_value(bench, θ̄, ȳ) - obj = objective_value(bench, θ̄, y) + y = maximizer(θ; maximizer_kwargs(bench, sample)...) + obj = objective_value(bench, sample, y) res += (target_obj - obj) / abs(target_obj) end return res / length(dataset)