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