Skip to content

Commit d10ee3f

Browse files
committed
Final armington case.
1 parent 4137066 commit d10ee3f

2 files changed

Lines changed: 104 additions & 2 deletions

File tree

src/main/optimal_network.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,13 @@ function optimal_network(param, graph; I0=nothing, Il=nothing, Iu=nothing, verbo
8181
recover_allocation = recover_allocation_mobility_cgc
8282
end
8383
elseif param.mobility == 0.5 && param.cong
84-
model = model_partial_mobility_cgc(optimizer, auxdata)
85-
recover_allocation = recover_allocation_partial_mobility_cgc
84+
if all(sum(param.Zjn .> 0, dims = 2) .<= 1) # Armington case
85+
model = model_partial_mobility_cgc_armington(optimizer, auxdata)
86+
recover_allocation = recover_allocation_partial_mobility_cgc_armington
87+
else
88+
model = model_partial_mobility_cgc(optimizer, auxdata)
89+
recover_allocation = recover_allocation_partial_mobility_cgc
90+
end
8691
elseif param.mobility == 0 && param.cong
8792
if all(sum(param.Zjn .> 0, dims = 2) .<= 1) # Armington case
8893
model = model_fixed_cgc_armington(optimizer, auxdata)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# The primal case, with mobility within regions and cross-good congestion, and an Armington (1969) world where each location produces only one good
2+
3+
function model_partial_mobility_cgc_armington(optimizer, auxdata)
4+
5+
# Extract parameters
6+
param = auxdata.param
7+
graph = auxdata.graph
8+
region = graph.region
9+
if length(region) != graph.J
10+
error("length(region) = $(length(region)) does not match number of nodes = $(graph.J)")
11+
end
12+
kappa_ex_init = auxdata.kappa_ex
13+
A = auxdata.edges.A
14+
Apos = auxdata.edges.Apos
15+
Aneg = auxdata.edges.Aneg
16+
m = param.m # Vector of weights on each goods flow for aggregate congestion term
17+
psigma = (param.sigma - 1) / param.sigma
18+
beta_nu = (param.beta + 1) / param.nu
19+
Lr = param.Lr
20+
if length(param.omegar) != param.nregions
21+
error("length(param.omegar) = $(length(param.omegar)) does not match number of regions = $(param.nregions)")
22+
end
23+
if length(Lr) != param.nregions
24+
error("Populations Lr = $(length(Lr)) does not match number of regions = $(param.nregions)")
25+
end
26+
27+
# Model
28+
model = Model(optimizer)
29+
set_string_names_on_creation(model, false)
30+
31+
# Variable declarations
32+
@variable(model, ur[1:param.nregions], container=Array, start = 0.0) # Utility per capita in each region
33+
@variable(model, Djn[1:graph.J, 1:param.N] >= 1e-8, container=Array, start = 1e-6) # Consumption per good pre-transport cost (Dj)
34+
@variable(model, cj[1:graph.J] >= 1e-8, container=Array, start = 1e-6) # Overall consumption bundle, including transport costs
35+
@variable(model, Qin_direct[1:graph.ndeg, 1:param.N] >= 1e-8, container=Array, start = 0.0) # Direct aggregate flow
36+
@variable(model, Qin_indirect[1:graph.ndeg, 1:param.N] >= 1e-8, container=Array, start = 0.0) # Indirect aggregate flow
37+
@variable(model, Lj[1:graph.J] >= 1e-8, container=Array) # Overall labour
38+
# Calculate start values for Lj
39+
pop_start = (Lr ./ gsum(ones(graph.J), param.nregions, region))[region]
40+
set_start_value.(Lj, pop_start)
41+
42+
# Parameters: to be updated between solves
43+
@variable(model, kappa_ex[i = 1:graph.ndeg] in Parameter(i), container=Array)
44+
set_parameter_value.(kappa_ex, kappa_ex_init)
45+
46+
# Objective
47+
@expression(model, U, sum(param.omegar .* Lr .* ur)) # Overall Utility
48+
@objective(model, Max, U)
49+
50+
# Utility constraint (Lj * ur <= ... )
51+
@constraint(model, Lj .* ur[region] - (cj .* Lj ./ param.alpha) .^ param.alpha .* (param.Hj ./ (1 - param.alpha)) .^ (1 - param.alpha) .<= -1e-8)
52+
53+
# Create the matrix B_direct (resp. B_indirect) of transport cost along the direction of the edge (resp. in edge opposite direction)
54+
B_direct = @expression(model, ((Qin_direct .^ param.nu) * m) .^ beta_nu ./ kappa_ex)
55+
B_indirect = @expression(model, ((Qin_indirect .^ param.nu) * m) .^ beta_nu ./ kappa_ex)
56+
# Final good constraints
57+
@expression(model, Dj, sum(Djn .^ psigma, dims=2) .^ (1 / psigma))
58+
@constraint(model, cj .* Lj + Apos * B_direct + Aneg * B_indirect - Dj .<= -1e-8)
59+
60+
# Balanced flow constraints: same as full mobility
61+
@expression(model, Yjn, param.Zjn .* (Lj .^ param.a))
62+
@constraint(model, Pjn, Djn + A * Qin_direct - A * Qin_indirect - Yjn .<= -1e-8)
63+
64+
# Labor resource constraints (within each region)
65+
@constraint(model, -1e-8 .<= gsum(Lj, param.nregions, region) .- Lr .<= 1e-8)
66+
67+
return model
68+
end
69+
70+
function recover_allocation_partial_mobility_cgc_armington(model, auxdata)
71+
param = auxdata.param
72+
graph = auxdata.graph
73+
model_dict = model.obj_dict
74+
results = Dict()
75+
76+
results[:welfare] = value(model_dict[:U])
77+
results[:reg_pc_welfare] = value.(model_dict[:ur])
78+
results[:Yjn] = value.(model_dict[:Yjn])
79+
results[:Yj] = dropdims(sum(results[:Yjn], dims=2), dims = 2)
80+
results[:Lj] = value.(model_dict[:Lj])
81+
results[:Ljn] = (param.Zjn .> 0) .* results[:Lj]
82+
results[:Djn] = value.(model_dict[:Djn]) # Consumption per good pre-transport cost
83+
results[:Dj] = dropdims(value.(model_dict[:Dj]), dims=2)
84+
results[:cj] = value.(model_dict[:cj])
85+
results[:Cj] = results[:cj] .* results[:Lj]
86+
results[:hj] = ifelse.(results[:Lj] .== 0, 0.0, param.Hj ./ results[:Lj])
87+
results[:uj] = param.u.(results[:cj], results[:hj])
88+
# Prices
89+
results[:Pjn] = shadow_price.(model_dict[:Pjn])
90+
results[:PCj] = dropdims(sum(results[:Pjn] .^ (1-param.sigma), dims=2), dims=2) .^ (1/(1-param.sigma))
91+
# Network flows
92+
Qin_direct = value.(model_dict[:Qin_direct])
93+
Qin_indirect = value.(model_dict[:Qin_indirect])
94+
results[:Qin] = ifelse.(Qin_direct .> Qin_indirect, Qin_direct, -Qin_indirect)
95+
results[:Qjkn] = gen_network_flows(results[:Qin], graph, param.N)
96+
return results
97+
end

0 commit comments

Comments
 (0)