Skip to content

Commit 23c41b3

Browse files
committed
Merge branch 'main' into StoVSP
2 parents 12bfef0 + 94eeb79 commit 23c41b3

File tree

23 files changed

+320
-37
lines changed

23 files changed

+320
-37
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
data
44
scripts
55
*heuristic_algorithms
6+
.DS_Store
67

78
# Files generated by invoking Julia with --code-coverage
89
*.jl.cov

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
# DecisionFocusedLearningBenchmarks.jl
22

3+
[![Stable](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaDecisionFocusedLearning.github.io/DecisionFocusedLearningBenchmarks.jl/stable/)
34
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaDecisionFocusedLearning.github.io/DecisionFocusedLearningBenchmarks.jl/dev/)
45
[![Build Status](https://github.com/JuliaDecisionFocusedLearning/DecisionFocusedLearningBenchmarks.jl/actions/workflows/Test.yml/badge.svg?branch=main)](https://github.com/JuliaDecisionFocusedLearning/DecisionFocusedLearningBenchmarks.jl/actions/workflows/Test.yml?query=branch%3Amain)
56
[![Coverage](https://codecov.io/gh/JuliaDecisionFocusedLearning/DecisionFocusedLearningBenchmarks.jl/branch/main/graph/badge.svg)](https://app.codecov.io/gh/JuliaDecisionFocusedLearning/DecisionFocusedLearningBenchmarks.jl)
67
[![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/JuliaDiff/BlueStyle)
78

8-
Set of benchmark problems to be solved with [DecisionFocusedLearning.jl](https://github.com/JuliaDecisionFocusedLearning/DecisionFocusedLearning.jl)
9+
This repository contains a collection of benchmark problems for decision-focused learning algorithms.
10+
It provides a common interface for creating datasets, associated statistical models and combinatorial optimization maximizers for building decision-focused learning pipelines.
11+
They can be used for instance as benchmarks for tools in [InferOpt.jl](https://github.com/JuliaDecisionFocusedLearning/InferOpt.jl), but can be used in any other context as well.
12+
13+
Currently, this package provides the following benchmark problems (many more to come!):
14+
- `SubsetSelectionBenchmark`: a minimalist subset selection problem.
15+
- `FixedSizeShortestPathBenchmark`: shortest path problem with on a graph with fixed size.
16+
- `WarcraftBenchmark`: shortest path problem on image maps
17+
- `PortfolioOptimizationBenchmark`: portfolio optimization problem.
18+
19+
See the [documentation](https://JuliaDecisionFocusedLearning.github.io/DecisionFocusedLearningBenchmarks.jl/stable/) for more details.

docs/src/api/argmax.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Argmax
2+
3+
## Public
4+
5+
```@autodocs
6+
Modules = [DecisionFocusedLearningBenchmarks.Argmax]
7+
Private = false
8+
```
9+
10+
## Private
11+
12+
```@autodocs
13+
Modules = [DecisionFocusedLearningBenchmarks.Argmax]
14+
Public = false
15+
```

docs/src/api/ranking.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Ranking
2+
3+
## Public
4+
5+
```@autodocs
6+
Modules = [DecisionFocusedLearningBenchmarks.Ranking]
7+
Private = false
8+
```
9+
10+
## Private
11+
12+
```@autodocs
13+
Modules = [DecisionFocusedLearningBenchmarks.Ranking]
14+
Public = false
15+
```

docs/src/benchmarks/argmax.md

Whitespace-only changes.

docs/src/benchmarks/ranking.md

Whitespace-only changes.

docs/src/tutorials/warcraft.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ train_dataset, test_dataset = dataset[1:45], dataset[46:50]
2525
sample = test_dataset[1]
2626
# `x` correspond to the input features, i.e. the input image (3D array) in the Warcraft benchmark case:
2727
x = sample.x
28-
# `θ` correspond to the true unknown terrain weights. We use the opposite of the true weights in order to formulate the optimization problem as a maximization problem:
29-
θ_true = sample.θ
30-
# `y` correspond to the optimal shortest path, encoded as a binary matrix:
31-
y_true = sample.y
28+
# `θ_true` correspond to the true unknown terrain weights. We use the opposite of the true weights in order to formulate the optimization problem as a maximization problem:
29+
θ_true = sample.θ_true
30+
# `y_true` correspond to the optimal shortest path, encoded as a binary matrix:
31+
y_true = sample.y_true
3232
# `instance` is not used in this benchmark, therefore set to nothing:
3333
isnothing(sample.instance)
3434

@@ -50,7 +50,7 @@ maximizer = generate_maximizer(b; dijkstra=true)
5050
# In the case o fthe Warcraft benchmark, the method has an additional keyword argument to chose the algorithm to use: Dijkstra's algorithm or Bellman-Ford algorithm.
5151
y = maximizer(θ)
5252
# As we can see, currently the pipeline predicts random noise as cell weights, and therefore the maximizer returns a straight line path.
53-
plot_data(b, DataSample(; x, θ, y))
53+
plot_data(b, DataSample(; x, θ_true=θ, y_true=y))
5454
# We can evaluate the current pipeline performance using the optimality gap metric:
5555
starting_gap = compute_gap(b, test_dataset, model, maximizer)
5656

@@ -70,7 +70,7 @@ opt_state = Flux.setup(Adam(1e-3), model)
7070
loss_history = Float64[]
7171
for epoch in 1:50
7272
val, grads = Flux.withgradient(model) do m
73-
sum(loss(m(sample.x), sample.y) for sample in train_dataset) / length(train_dataset)
73+
sum(loss(m(x), y_true) for (; x, y_true) in train_dataset) / length(train_dataset)
7474
end
7575
Flux.update!(opt_state, model, grads[1])
7676
push!(loss_history, val)
@@ -85,4 +85,4 @@ final_gap = compute_gap(b, test_dataset, model, maximizer)
8585
#
8686
θ = model(x)
8787
y = maximizer(θ)
88-
plot_data(b, DataSample(; x, θ, y))
88+
plot_data(b, DataSample(; x, θ_true=θ, y_true=y))

src/Argmax/Argmax.jl

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
module Argmax
2+
3+
using ..Utils
4+
using DocStringExtensions: TYPEDEF, TYPEDFIELDS, TYPEDSIGNATURES
5+
using Flux: Chain, Dense
6+
using Random
7+
8+
"""
9+
$TYPEDEF
10+
11+
Benchmark problem with an argmax as the CO algorithm.
12+
13+
# Fields
14+
$TYPEDFIELDS
15+
"""
16+
struct ArgmaxBenchmark <: AbstractBenchmark
17+
"iinstances dimension, total number of classes"
18+
instance_dim::Int
19+
"number of features"
20+
nb_features::Int
21+
end
22+
23+
function Base.show(io::IO, bench::ArgmaxBenchmark)
24+
(; instance_dim, nb_features) = bench
25+
return print(
26+
io, "ArgmaxBenchmark(instance_dim=$instance_dim, nb_features=$nb_features)"
27+
)
28+
end
29+
30+
function ArgmaxBenchmark(; instance_dim::Int=10, nb_features::Int=5)
31+
return ArgmaxBenchmark(instance_dim, nb_features)
32+
end
33+
34+
"""
35+
$TYPEDSIGNATURES
36+
37+
One-hot encoding of the argmax function.
38+
"""
39+
function one_hot_argmax(z::AbstractVector{R}; kwargs...) where {R<:Real}
40+
e = zeros(R, length(z))
41+
e[argmax(z)] = one(R)
42+
return e
43+
end
44+
45+
"""
46+
$TYPEDSIGNATURES
47+
48+
Return a top k maximizer.
49+
"""
50+
function Utils.generate_maximizer(bench::ArgmaxBenchmark)
51+
return one_hot_argmax
52+
end
53+
54+
"""
55+
$TYPEDSIGNATURES
56+
57+
Generate a dataset of labeled instances for the subset selection problem.
58+
The mapping between features and cost is identity.
59+
"""
60+
function Utils.generate_dataset(bench::ArgmaxBenchmark, dataset_size::Int=10; seed::Int=0)
61+
(; instance_dim, nb_features) = bench
62+
rng = MersenneTwister(seed)
63+
features = [randn(rng, Float32, nb_features, instance_dim) for _ in 1:dataset_size]
64+
mapping = Chain(Dense(nb_features => 1; bias=false), vec)
65+
costs = mapping.(features)
66+
solutions = one_hot_argmax.(costs)
67+
return [
68+
DataSample(; x, θ_true, y_true) for
69+
(x, θ_true, y_true) in zip(features, costs, solutions)
70+
]
71+
end
72+
73+
"""
74+
$TYPEDSIGNATURES
75+
76+
Initialize a linear model for `bench` using `Flux`.
77+
"""
78+
function Utils.generate_statistical_model(bench::ArgmaxBenchmark; seed=0)
79+
Random.seed!(seed)
80+
(; nb_features) = bench
81+
return Chain(Dense(nb_features => 1; bias=false), vec)
82+
end
83+
84+
export ArgmaxBenchmark
85+
86+
end

src/DecisionFocusedLearningBenchmarks.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,22 @@ end
2323

2424
include("Utils/Utils.jl")
2525

26+
include("Argmax/Argmax.jl")
27+
include("Ranking/Ranking.jl")
28+
include("SubsetSelection/SubsetSelection.jl")
2629
include("Warcraft/Warcraft.jl")
2730
include("FixedSizeShortestPath/FixedSizeShortestPath.jl")
2831
include("PortfolioOptimization/PortfolioOptimization.jl")
29-
include("SubsetSelection/SubsetSelection.jl")
3032

3133
include("StochasticVehicleScheduling/StochasticVehicleScheduling.jl")
3234

3335
using .Utils
36+
using .Argmax
37+
using .Ranking
38+
using .SubsetSelection
3439
using .Warcraft
3540
using .FixedSizeShortestPath
3641
using .PortfolioOptimization
37-
using .SubsetSelection
3842
using .StochasticVehicleScheduling
3943

4044
# Interface
@@ -46,10 +50,12 @@ export plot_data
4650
export compute_gap
4751

4852
# Export all benchmarks
53+
export ArgmaxBenchmark
54+
export RankingBenchmark
55+
export SubsetSelectionBenchmark
4956
export WarcraftBenchmark
5057
export FixedSizeShortestPathBenchmark
5158
export PortfolioOptimizationBenchmark
52-
export SubsetSelectionBenchmark
5359
export StochasticVehicleSchedulingBenchmark
5460

5561
end # module DecisionFocusedLearningBenchmarks

src/FixedSizeShortestPath/FixedSizeShortestPath.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ function Utils.generate_dataset(
132132

133133
# Label solutions
134134
solutions = shortest_path_maximizer.(costs)
135-
return [DataSample(; x=x, θ=θ, y=y) for (x, θ, y) in zip(features, costs, solutions)]
135+
return [
136+
DataSample(; x, θ_true, y_true) for
137+
(x, θ_true, y_true) in zip(features, costs, solutions)
138+
]
136139
end
137140

138141
"""

0 commit comments

Comments
 (0)