Skip to content

Commit be1d742

Browse files
committed
cleanup
1 parent 0ae1638 commit be1d742

File tree

6 files changed

+338
-340
lines changed

6 files changed

+338
-340
lines changed

src/FixedSizeShortestPath/FixedSizeShortestPath.jl

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,158 @@ using LinearAlgebra
99
using Random
1010
using SparseArrays
1111

12-
include("shortest_paths.jl")
12+
"""
13+
$TYPEDEF
14+
15+
Benchmark problem for the shortest path problem.
16+
In this benchmark, all graphs are acyclic directed grids, all of the same size `grid_size`.
17+
Features are given at instance level (one dimensional vector of length `p` for each graph).
18+
19+
Data is generated using the process described in: <https://arxiv.org/abs/2307.13565>.
20+
21+
# Fields
22+
$TYPEDFIELDS
23+
"""
24+
struct FixedSizeShortestPathBenchmark <: AbstractBenchmark
25+
"grid graph instance"
26+
graph::SimpleDiGraph{Int64}
27+
"grid size of graphs"
28+
grid_size::Tuple{Int,Int}
29+
"size of feature vectors"
30+
p::Int
31+
"degree of formula between features and true weights"
32+
deg::Int
33+
"multiplicative noise for true weights sampled between [1-ν, 1+ν], should be between 0 and 1"
34+
ν::Float32
35+
end
36+
37+
function Base.show(io::IO, bench::FixedSizeShortestPathBenchmark)
38+
(; grid_size, p, deg, ν) = bench
39+
return print(
40+
io, "FixedSizeShortestPathBenchmark(grid_size=$grid_size, p=$p, deg=$deg, ν=)"
41+
)
42+
end
43+
44+
"""
45+
$TYPEDSIGNATURES
46+
47+
Constructor for [`FixedSizeShortestPathBenchmark`](@ref).
48+
"""
49+
function FixedSizeShortestPathBenchmark(;
50+
grid_size::Tuple{Int,Int}=(5, 5), p::Int=5, deg::Int=1, ν=0.0f0
51+
)
52+
@assert ν >= 0.0 && ν <= 1.0
53+
g = DiGraph(collect(edges(Graphs.grid(grid_size))))
54+
return FixedSizeShortestPathBenchmark(g, grid_size, p, deg, ν)
55+
end
56+
57+
"""
58+
$TYPEDSIGNATURES
59+
60+
Outputs a function that computes the longest path on the grid graph, given edge weights θ as input.
61+
62+
```julia
63+
maximizer = generate_maximizer(bench)
64+
maximizer(θ)
65+
```
66+
"""
67+
function Utils.generate_maximizer(bench::FixedSizeShortestPathBenchmark; use_dijkstra=true)
68+
g = bench.graph
69+
V = Graphs.nv(g)
70+
E = Graphs.ne(g)
71+
72+
I = [src(e) for e in edges(g)]
73+
J = [dst(e) for e in edges(g)]
74+
algo =
75+
use_dijkstra ? Graphs.dijkstra_shortest_paths : Graphs.bellman_ford_shortest_paths
76+
77+
function shortest_path_maximizer(θ; kwargs...)
78+
weights = sparse(I, J, -θ, V, V)
79+
parents = algo(g, 1, weights).parents
80+
y = falses(V, V)
81+
u = V
82+
while u != 1
83+
prev = parents[u]
84+
y[prev, u] = true
85+
u = prev
86+
end
87+
88+
solution = falses(E)
89+
for (i, edge) in enumerate(edges(g))
90+
if y[src(edge), dst(edge)]
91+
solution[i] = true
92+
end
93+
end
94+
return solution
95+
end
96+
97+
return shortest_path_maximizer
98+
end
99+
100+
"""
101+
$TYPEDSIGNATURES
102+
103+
Generate dataset for the shortest path problem.
104+
"""
105+
function Utils.generate_dataset(
106+
bench::FixedSizeShortestPathBenchmark,
107+
dataset_size::Int=10;
108+
seed::Int=0,
109+
type::Type=Float32,
110+
)
111+
# Set seed
112+
rng = MersenneTwister(seed)
113+
(; graph, p, deg, ν) = bench
114+
115+
E = Graphs.ne(graph)
116+
117+
# Features
118+
features = [randn(rng, type, p) for _ in 1:dataset_size]
119+
120+
# True weights
121+
B = rand(rng, Bernoulli(0.5), E, p)
122+
ξ = if ν == 0.0
123+
[ones(type, E) for _ in 1:dataset_size]
124+
else
125+
[rand(rng, Uniform{type}(1 - ν, 1 + ν), E) for _ in 1:dataset_size]
126+
end
127+
costs = [
128+
(1 .+ (3 .+ B * zᵢ ./ type(sqrt(p))) .^ deg) .* ξᵢ for (ξᵢ, zᵢ) in zip(ξ, features)
129+
]
130+
131+
shortest_path_maximizer = Utils.generate_maximizer(bench)
132+
133+
# Label solutions
134+
solutions = shortest_path_maximizer.(.-costs)
135+
return [DataSample(; x=x, θ=θ, y=y) for (x, θ, y) in zip(features, costs, solutions)]
136+
end
137+
138+
"""
139+
$TYPEDSIGNATURES
140+
141+
Initialize a linear model for `bench` using `Flux`.
142+
"""
143+
function Utils.generate_statistical_model(bench::FixedSizeShortestPathBenchmark)
144+
(; p, graph) = bench
145+
return Chain(Dense(p, ne(graph)))
146+
end
147+
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
13164

14165
export FixedSizeShortestPathBenchmark
15166

src/FixedSizeShortestPath/shortest_paths.jl

Lines changed: 0 additions & 152 deletions
This file was deleted.

0 commit comments

Comments
 (0)