Skip to content

Commit eaf05f5

Browse files
authored
Merge pull request #24 from OptimalTransportNetworks/development
Development
2 parents 0c414c0 + ee98b97 commit eaf05f5

12 files changed

Lines changed: 992 additions & 99 deletions

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OptimalTransportNetworks"
22
uuid = "e2b46e68-897f-4e4e-ba36-a93c9789fd96"
33
authors = ["Sebastian Krantz <sebastian.krantz@graduateinstitute.ch>"]
4-
version = "0.1.6"
4+
version = "0.1.7"
55

66
[deps]
77
Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94"

src/OptimalTransportNetworks.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ module OptimalTransportNetworks
7575

7676
using LinearAlgebra, JuMP, Plots
7777
using Statistics: mean
78+
using SparseArrays: sparse, findnz
7879
# using MathOptInterface: Parameter
7980
using Dierckx: Spline2D, evaluate
8081
using NearestNeighbors: KDTree, knn

src/main/annealing.jl

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function annealing(param, graph, I0; kwargs...)
106106
model, recover_allocation = get_model(auxdata)
107107
end
108108

109-
if !options.verbose
109+
if !options.verbose && model !== nothing
110110
set_silent(model)
111111
end
112112

@@ -139,8 +139,12 @@ function annealing(param, graph, I0; kwargs...)
139139

140140
# rng(0) # set the seed of random number generator for replicability
141141
acceptance_str = ["rejected", "accepted"]
142-
all_vars = all_variables_except_kappa_ex(model)
143-
start_values = start_value.(all_vars)
142+
if model === nothing
143+
start_values = []
144+
else
145+
all_vars = all_variables_except_kappa_ex(model)
146+
start_values = start_value.(all_vars)
147+
end
144148
while T > T_min
145149
accepted = false
146150

@@ -161,26 +165,40 @@ function annealing(param, graph, I0; kwargs...)
161165
end
162166

163167
k = 0
164-
set_start_value.(all_vars, start_values) # reset start values
168+
# reset start values
169+
if model === nothing
170+
start_values = []
171+
else
172+
set_start_value.(all_vars, start_values)
173+
end
165174
while k <= num_deepening - 1
166175

167176
auxdata = create_auxdata(param, graph, edges, I1)
168-
set_parameter_value.(model.obj_dict[:kappa_ex], auxdata.kappa_ex)
169-
170-
optimize!(model)
171-
172-
results = recover_allocation(model, auxdata)
173-
score = results[:welfare]
174-
175-
if (!is_solved_and_feasible(model, allow_almost = true) || isnan(score)) && param.verbose # optimization failed
176-
println("optimization failed! k=$(k), return flag=$(termination_status(model))")
177-
k = num_deepening - 1
178-
score = -Inf
179-
end
180-
181-
if param.warm_start
182-
vars_solution = value.(all_vars)
183-
set_start_value.(all_vars, vars_solution)
177+
if model === nothing
178+
results, status, start_values = recover_allocation(start_values, auxdata, options.verbose)
179+
score = results[:welfare]
180+
if (!any(status .== [0, 1]) || isnan(score)) && param.verbose # optimization failed
181+
println("optimization failed! k=$(k), return flag=$(status)")
182+
k = num_deepening - 1
183+
score = -Inf
184+
end
185+
if !param.warm_start
186+
start_values = []
187+
end
188+
else
189+
set_parameter_value.(model.obj_dict[:kappa_ex], auxdata.kappa_ex)
190+
optimize!(model)
191+
results = recover_allocation(model, auxdata)
192+
score = results[:welfare]
193+
if (!is_solved_and_feasible(model, allow_almost = true) || isnan(score)) && param.verbose # optimization failed
194+
println("optimization failed! k=$(k), return flag=$(termination_status(model))")
195+
k = num_deepening - 1
196+
score = -Inf
197+
end
198+
if param.warm_start
199+
vars_solution = value.(all_vars)
200+
set_start_value.(all_vars, vars_solution)
201+
end
184202
end
185203

186204
if score > best_score
@@ -242,18 +260,31 @@ function annealing(param, graph, I0; kwargs...)
242260
# Last deepening before returning found optimum
243261
has_converged = false
244262
I0 = best_I
245-
set_start_value.(all_vars, start_values) # reset start values
263+
# reset start values
264+
if model === nothing
265+
start_values = []
266+
else
267+
set_start_value.(all_vars, start_values)
268+
end
246269
while !has_converged && counter < 100
247270
# Update auxdata
248271
auxdata = create_auxdata(param, graph, edges, I0)
249-
set_parameter_value.(model.obj_dict[:kappa_ex], auxdata.kappa_ex)
250272

251273
# Solve allocation
252-
optimize!(model)
253-
if !is_solved_and_feasible(model, allow_almost = true)
254-
println("Solver returned with error code $(termination_status(model)).")
274+
if model === nothing
275+
results, status, start_values = recover_allocation(start_values, auxdata, options.verbose)
276+
if !any(status .== [0, 1])
277+
println("Solver returned with error code $(status).")
278+
end
279+
else
280+
set_parameter_value.(model.obj_dict[:kappa_ex], auxdata.kappa_ex)
281+
optimize!(model)
282+
if !is_solved_and_feasible(model, allow_almost = true)
283+
println("Solver returned with error code $(termination_status(model)).")
284+
end
285+
results = recover_allocation(model, auxdata)
255286
end
256-
results = recover_allocation(model, auxdata)
287+
257288
score = results[:welfare]
258289

259290
# # Fajgelbaum & Schaal always use initial values here.

src/main/helper.jl

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ function namedtuple_to_dict(namedtuple)
3939
if namedtuple isa Dict
4040
return namedtuple
4141
else
42-
return Dict(pairs(namedtuple))
42+
# return Dict(Symbol(k) => v for (k, v) in pairs(namedtuple))
43+
return Dict(pairs(namedtuple)) # Can be of fixed type
4344
end
4445
end
4546

@@ -243,7 +244,10 @@ function get_model(auxdata)
243244
recover_allocation = recover_allocation_partial_mobility_cgc
244245
end
245246
elseif param.mobility == 0 && param.cong
246-
if all(sum(graph.Zjn .> 0, dims = 2) .<= 1) # Armington case
247+
if param.beta <= 1 && param.duality # && param.a < 1
248+
model = nothing # model_fixed_duality_cgc(optimizer, auxdata)
249+
recover_allocation = solve_allocation_by_duality_cgc #recover_allocation_fixed_duality_cgc
250+
elseif all(sum(graph.Zjn .> 0, dims = 2) .<= 1) # Armington case
247251
model = model_fixed_cgc_armington(optimizer, auxdata)
248252
recover_allocation = recover_allocation_fixed_cgc_armington
249253
else
@@ -267,12 +271,12 @@ function get_model(auxdata)
267271
recover_allocation = recover_allocation_partial_mobility
268272
end
269273
elseif param.mobility == 0 && !param.cong
270-
if all(sum(graph.Zjn .> 0, dims = 2) .<= 1) # Armington case
274+
if param.beta <= 1 && param.duality # && param.a < 1
275+
model = nothing # model_fixed_duality(optimizer, auxdata)
276+
recover_allocation = solve_allocation_by_duality # recover_allocation_fixed_duality
277+
elseif all(sum(graph.Zjn .> 0, dims = 2) .<= 1) # Armington case
271278
model = model_fixed_armington(optimizer, auxdata)
272279
recover_allocation = recover_allocation_fixed_armington
273-
elseif param.beta <= 1 && param.a < 1 && param.duality
274-
model = model_fixed_duality(optimizer, auxdata)
275-
recover_allocation = recover_allocation_fixed_duality
276280
else
277281
model = model_fixed(optimizer, auxdata)
278282
recover_allocation = recover_allocation_fixed
@@ -283,26 +287,27 @@ function get_model(auxdata)
283287

284288
# --------------
285289
# CUSTOMIZATIONS
286-
287-
if haskey(param, :optimizer_attr)
288-
for (key, value) in param.optimizer_attr
289-
set_optimizer_attribute(model, String(key), value)
290+
if model !== nothing
291+
if haskey(param, :optimizer_attr)
292+
for (key, value) in param.optimizer_attr
293+
set_optimizer_attribute(model, String(key), value)
294+
end
290295
end
291-
end
292296

293-
if haskey(param, :model_attr)
294-
for value in values(param.model_attr)
295-
if !(value isa Tuple)
296-
error("model_attr must be a dict of tuples.")
297+
if haskey(param, :model_attr)
298+
for value in values(param.model_attr)
299+
if !(value isa Tuple)
300+
error("model_attr must be a dict of tuples.")
301+
end
302+
set_optimizer_attribute(model, value[1], value[2])
297303
end
298-
set_optimizer_attribute(model, value[1], value[2])
299304
end
305+
# E.g.:
306+
# set_attribute(model,
307+
# MOI.AutomaticDifferentiationBackend(),
308+
# MathOptSymbolicAD.DefaultBackend(),
309+
# )
300310
end
301-
# E.g.:
302-
# set_attribute(model,
303-
# MOI.AutomaticDifferentiationBackend(),
304-
# MathOptSymbolicAD.DefaultBackend(),
305-
# )
306311
return model, recover_allocation
307312
end
308313

src/main/init_parameters.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Returns a `param` dict with the model parameters. These are independent of the g
1616
- `N::Int64=1`: Number of goods traded in the economy (used for checks in `create_graph()`)
1717
- `labor_mobility::Any=false`: Switch for labor mobility (true/false or 'partial')
1818
- `cross_good_congestion::Bool=false`: Switch for cross-good congestion
19-
- `nu::Float64=1`: Elasticity of substitution b/w goods in transport costs if cross-good congestion
19+
- `nu::Float64=1.5`: Elasticity of substitution b/w goods in transport costs if cross-good congestion
2020
- `m::Vector{Float64}=ones(N)`: Vector of weights Nx1 in the cross congestion cost function
2121
- `annealing::Bool=true`: Switch for the use of annealing at the end of iterations (only if gamma > beta)
2222
- `verbose::Bool=true`: Switch to turn on/off text output (from Ipopt or other optimizers)
@@ -40,7 +40,7 @@ param = init_parameters(K = 10, labor_mobility = true)
4040
```
4141
"""
4242
function init_parameters(; alpha = 0.5, beta = 1, gamma = 1, K = 1, sigma = 5, rho = 2, a = 0.8, N = 1,
43-
labor_mobility = false, cross_good_congestion=false, nu = 1, m = ones(N),
43+
labor_mobility = false, cross_good_congestion=false, nu = 1.5, m = ones(N),
4444
annealing=true,
4545
verbose = true, duality = false, warm_start = true,
4646
kappa_min = 1e-5, min_iter = 20, max_iter = 200, tol = 1e-5, kwargs...)
@@ -93,7 +93,8 @@ function init_parameters(; alpha = 0.5, beta = 1, gamma = 1, K = 1, sigma = 5, r
9393
param[:u] = (c, h) -> ((c / alpha)^alpha * (h / (1 - alpha))^(1 - alpha))^(1 - rho) / (1 - rho)
9494
param[:uprime] = (c, h) -> ((c / alpha)^alpha * (h / (1 - alpha))^(1 - alpha))^-rho * ((c / alpha)^(alpha - 1) * (h / (1 - alpha))^(1 - alpha))
9595
param[:usecond] = (c, h) -> -rho * ((c / alpha)^alpha * (h / (1 - alpha))^(1 - alpha))^(-rho - 1) * ((c / alpha)^(alpha - 1) * (h / (1 - alpha))^(1 - alpha))^2 + (alpha - 1) / alpha * ((c / alpha)^alpha * (h / (1 - alpha))^(1 - alpha))^-rho * ((c / alpha)^(alpha - 2) * (h / (1 - alpha))^(1 - alpha))
96-
param[:uprimeinv] = (x, h) -> alpha * x^(-1 / (1 + alpha * (rho - 1))) * (h / (1 - alpha))^-((1 - alpha) * (rho - 1) / (1 + alpha * (rho - 1)))
96+
param[:uprimeinv] = (x, h) -> alpha * x^(-1 / (1 + alpha * (rho - 1))) * (h / (1 - alpha))^((1 - alpha) * (1 - rho) / (1 + alpha * (rho - 1)))
97+
param[:uprimeinvprime] = (x, h) -> -alpha / (1 + alpha * (rho - 1)) * x^(-1 / (1 + alpha * (rho - 1)) - 1) * (h / (1 - alpha))^((1 - alpha) * (1 - rho) / (1 + alpha * (rho - 1)))
9798

9899
# Define production function
99100
param[:F] = (L, a) -> L^a

0 commit comments

Comments
 (0)