Skip to content

Commit 116a1cc

Browse files
authored
Merge pull request #7 from JuliaDecisionFocusedLearning/more-tests
Add more tests for better coverage
2 parents 2f05c85 + 29434e7 commit 116a1cc

6 files changed

Lines changed: 93 additions & 121 deletions

File tree

src/FixedSizeShortestPath/FixedSizeShortestPath.jl

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ function Utils.generate_dataset(
125125
[rand(rng, Uniform{type}(1 - ν, 1 + ν), E) for _ in 1:dataset_size]
126126
end
127127
costs = [
128-
(1 .+ (3 .+ B * zᵢ ./ type(sqrt(p))) .^ deg) .* ξᵢ for (ξᵢ, zᵢ) in zip(ξ, features)
128+
-(1 .+ (3 .+ B * zᵢ ./ type(sqrt(p))) .^ deg) .* ξᵢ for (ξᵢ, zᵢ) in zip(ξ, features)
129129
]
130130

131131
shortest_path_maximizer = Utils.generate_maximizer(bench)
132132

133133
# Label solutions
134-
solutions = shortest_path_maximizer.(.-costs)
134+
solutions = shortest_path_maximizer.(costs)
135135
return [DataSample(; x=x, θ=θ, y=y) for (x, θ, y) in zip(features, costs, solutions)]
136136
end
137137

@@ -145,23 +145,6 @@ function Utils.generate_statistical_model(bench::FixedSizeShortestPathBenchmark)
145145
return Chain(Dense(p, ne(graph)))
146146
end
147147

148-
function objective_value(::FixedSizeShortestPathBenchmark, θ, y)
149-
return dot(θ, y)
150-
end
151-
152-
function Utils.compute_gap(
153-
bench::FixedSizeShortestPathBenchmark, model, features, costs, solutions, maximizer
154-
)
155-
res = 0.0
156-
for (x, ȳ, θ̄) in zip(features, solutions, costs)
157-
θ = model(x)
158-
y = maximizer(θ)
159-
val = objective_value(bench, θ̄, ȳ)
160-
res += (objective_value(bench, θ̄, y) - val) / val
161-
end
162-
return res / length(features)
163-
end
164-
165148
export FixedSizeShortestPathBenchmark
166149

167150
end

src/PortfolioOptimization/PortfolioOptimization.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Initialize a linear model for `bench` using `Flux`.
120120
"""
121121
function Utils.generate_statistical_model(bench::PortfolioOptimizationBenchmark)
122122
(; p, d) = bench
123-
return Chain(Dense(p, d))
123+
return Dense(p, d)
124124
end
125125

126126
export PortfolioOptimizationBenchmark

test/fixed_size_shortest_path.jl

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,35 @@
1-
module FixedSizeShortestPathTest
2-
3-
using DecisionFocusedLearningBenchmarks.FixedSizeShortestPath
4-
5-
# using Flux
6-
# using InferOpt
7-
# using ProgressMeter
8-
# using UnicodePlots
9-
# using Zygote
10-
11-
bench = FixedSizeShortestPathBenchmark()
12-
13-
(; features, costs, solutions) = generate_dataset(bench)
14-
15-
model = generate_statistical_model(bench)
16-
maximizer = generate_maximizer(bench)
17-
18-
# perturbed = PerturbedAdditive(maximizer; nb_samples=10, ε=0.1)
19-
# fyl = FenchelYoungLoss(perturbed)
20-
21-
# opt_state = Flux.setup(Adam(), model)
22-
# loss_history = Float64[]
23-
# gap_history = Float64[]
24-
# E = 100
25-
# @showprogress for epoch in 1:E
26-
# loss = 0.0
27-
# for (x, y) in zip(features, solutions)
28-
# val, grads = Flux.withgradient(model) do m
29-
# θ = m(x)
30-
# fyl(θ, y)
31-
# end
32-
# loss += val
33-
# Flux.update!(opt_state, model, grads[1])
34-
# end
35-
# push!(loss_history, loss ./ E)
36-
# push!(
37-
# gap_history, compute_gap(bench, model, features, costs, solutions, maximizer) .* 100
38-
# )
39-
# end
40-
41-
# println(lineplot(loss_history; title="Loss"))
42-
# println(lineplot(gap_history; title="Gap"))
43-
1+
@testitem "FixedSizeShortestPath" begin
2+
using DecisionFocusedLearningBenchmarks.FixedSizeShortestPath
3+
using Graphs
4+
5+
p = 5
6+
grid_size = (5, 5)
7+
A = (grid_size[1] - 1) * grid_size[2] + grid_size[1] * (grid_size[2] - 1)
8+
b = FixedSizeShortestPathBenchmark(; p=p, grid_size=grid_size)
9+
10+
@test nv(b.graph) == grid_size[1] * grid_size[2]
11+
@test ne(b.graph) == A
12+
13+
dataset = generate_dataset(b, 50)
14+
model = generate_statistical_model(b)
15+
maximizer = generate_maximizer(b)
16+
17+
gap = compute_gap(b, dataset, model, maximizer)
18+
@test gap >= 0
19+
20+
for sample in dataset
21+
x = sample.x
22+
θ_true = sample.θ
23+
y_true = sample.y
24+
@test all(θ_true .< 0)
25+
@test size(x) == (p,)
26+
@test length(θ_true) == A
27+
@test length(y_true) == A
28+
@test isnothing(sample.instance)
29+
@test all(y_true .== maximizer(θ_true))
30+
θ = model(x)
31+
@test length(θ) == length(θ_true)
32+
y = maximizer(θ)
33+
@test length(y) == length(y_true)
34+
end
4435
end

test/portfolio_optimization.jl

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,29 @@
11
@testitem "Portfolio Optimization" begin
22
using DecisionFocusedLearningBenchmarks
3-
using InferOpt
4-
using Flux
5-
using Zygote
63

7-
b = PortfolioOptimizationBenchmark()
4+
d = 50
5+
p = 5
6+
b = PortfolioOptimizationBenchmark(; d=d, p=p)
87

9-
dataset = generate_dataset(b, 100)
8+
dataset = generate_dataset(b, 50)
109
model = generate_statistical_model(b)
1110
maximizer = generate_maximizer(b)
1211

13-
# train_dataset, test_dataset = dataset[1:50], dataset[50:100]
14-
# X_train = train_dataset.features
15-
# Y_train = train_dataset.solutions
16-
17-
# perturbed_maximizer = PerturbedAdditive(maximizer; ε=0.1, nb_samples=1)
18-
# loss = FenchelYoungLoss(perturbed_maximizer)
19-
20-
# starting_gap = compute_gap(b, test_dataset, model, maximizer)
21-
22-
# opt_state = Flux.setup(Adam(), model)
23-
# loss_history = Float64[]
24-
# for epoch in 1:50
25-
# val, grads = Flux.withgradient(model) do m
26-
# sum(loss(m(x), y) for (x, y) in zip(X_train, Y_train)) / length(train_dataset)
27-
# end
28-
# Flux.update!(opt_state, model, grads[1])
29-
# push!(loss_history, val)
30-
# end
31-
32-
# final_gap = compute_gap(b, test_dataset, model, maximizer)
33-
34-
# @test loss_history[end] < loss_history[1]
35-
# @test final_gap < starting_gap / 10
12+
for sample in dataset
13+
x = sample.x
14+
θ_true = sample.θ
15+
y_true = sample.y
16+
@test size(x) == (p,)
17+
@test length(θ_true) == d
18+
@test length(y_true) == d
19+
@test isnothing(sample.instance)
20+
@test all(y_true .== maximizer(θ_true))
21+
22+
θ = model(x)
23+
@test length(θ) == d
24+
25+
y = maximizer(θ)
26+
@test length(y) == d
27+
@test sum(y) <= 1
28+
end
3629
end

test/subset_selection.jl

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
@testitem "Subset selection" begin
22
using DecisionFocusedLearningBenchmarks
3-
using InferOpt
4-
using Flux
5-
using UnicodePlots
6-
using Zygote
73

8-
b = SubsetSelectionBenchmark()
4+
n = 25
5+
k = 5
96

10-
dataset = generate_dataset(b, 500)
11-
model = generate_statistical_model(b)
12-
maximizer = generate_maximizer(b)
13-
14-
# train_dataset, test_dataset = dataset[1:450], dataset[451:500]
15-
# X_train = train_dataset.features
16-
# Y_train = train_dataset.solutions
17-
18-
# perturbed_maximizer = PerturbedAdditive(maximizer; ε=1.0, nb_samples=100)
19-
# loss = FenchelYoungLoss(perturbed_maximizer)
7+
b = SubsetSelectionBenchmark(; n=n, k=k)
208

21-
# starting_gap = compute_gap(b, test_dataset, model, maximizer)
9+
io = IOBuffer()
10+
show(io, b)
11+
@test String(take!(io)) == "SubsetSelectionBenchmark(n=25, k=5)"
2212

23-
# opt_state = Flux.setup(Adam(0.1), model)
24-
# loss_history = Float64[]
25-
# for epoch in 1:50
26-
# val, grads = Flux.withgradient(model) do m
27-
# sum(loss(m(x), y) for (x, y) in zip(X_train, Y_train)) / length(train_dataset)
28-
# end
29-
# Flux.update!(opt_state, model, grads[1])
30-
# push!(loss_history, val)
31-
# end
32-
33-
# final_gap = compute_gap(b, test_dataset, model, maximizer)
13+
dataset = generate_dataset(b, 50)
14+
model = generate_statistical_model(b)
15+
maximizer = generate_maximizer(b)
3416

35-
# lineplot(loss_history)
36-
# @test loss_history[end] < loss_history[1]
37-
# @test final_gap < starting_gap / 10
17+
for (i, sample) in enumerate(dataset)
18+
x = sample.x
19+
θ_true = sample.θ
20+
y_true = sample.y
21+
@test size(x) == (n,)
22+
@test length(θ_true) == n
23+
@test length(y_true) == n
24+
@test isnothing(sample.instance)
25+
@test all(y_true .== maximizer(θ_true))
26+
27+
# Features and true weights should be equal
28+
@test all(θ_true .== x)
29+
30+
θ = model(x)
31+
@test length(θ) == n
32+
33+
y = maximizer(θ)
34+
@test length(y) == n
35+
@test sum(y) == k
36+
end
3837
end

test/warcraft.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@testitem "Warcraft" begin
22
using DecisionFocusedLearningBenchmarks
33
using DecisionFocusedLearningBenchmarks.Utils: objective_value
4+
using Plots
45

56
b = WarcraftBenchmark()
67

@@ -12,6 +13,11 @@
1213
bellman_maximizer = generate_maximizer(b; dijkstra=false)
1314
dijkstra_maximizer = generate_maximizer(b; dijkstra=true)
1415

16+
figure = plot_data(b, dataset[1])
17+
@test figure isa Plots.Plot
18+
gap = compute_gap(b, dataset, model, dijkstra_maximizer)
19+
@test gap >= 0
20+
1521
for (i, sample) in enumerate(dataset)
1622
x = sample.x
1723
θ_true = sample.θ

0 commit comments

Comments
 (0)