From d4e90b92410c0ba09a1160e0162a22618ab54c48 Mon Sep 17 00:00:00 2001 From: Bart Arendarczyk <s1924442@ed.ac.uk> Date: Fri, 8 Jul 2022 13:10:31 +0100 Subject: [PATCH] Merged demand optimisation improvements. --- GAMS/elasticDemand.gms | 76 ++++++++++++------- .../country/gams/GamsDemandOptimiser.java | 27 +++++-- .../lurg/country/gams/GamsDemandOutput.java | 6 -- .../ed/lurg/demand/ElasticDemandManager.java | 14 +--- 4 files changed, 73 insertions(+), 50 deletions(-) diff --git a/GAMS/elasticDemand.gms b/GAMS/elasticDemand.gms index 9d62dd08..b5b40b36 100755 --- a/GAMS/elasticDemand.gms +++ b/GAMS/elasticDemand.gms @@ -20,7 +20,10 @@ $load i, alpha, beta, kappa, delta, tau, omega $gdxin VARIABLE - u Utility; + u Utility + error Error term for NLS + ressq Residual squared +; POSITIVE VARIABLE DiscretionaryC(i) Discretionary consumption @@ -49,35 +52,45 @@ EQUATIONS EQ_u "Implicit definition of utility" EQ_DiscretionaryC(i) EQ_SubsistenceC(j) + EQ_u_NLS "Relaxed constraint for NLS" + EQ_ressq_NLS ; EQ_w(j).. - w(j) =e= (SubsistenceC(j)+DiscretionaryC(j))*p(j)/m; - -EQ_u.. - sum(i, (alpha(i)+beta(i)*exp(u))/(1+exp(u))*log(DiscretionaryC(i)))-u =e= kappa ; - -EQ_DiscretionaryC(i)$p(i).. DiscretionaryC(i) =e= - [(alpha(i)+beta(i)*exp(u))/(1+exp(u))]/p(i)* - [m-sum(j,p(j)*SubsistenceC(j))]; - -EQ_SubsistenceC(j).. - SubsistenceC(j) =e= (delta(j)+tau(j)*exp(omega*u))/(1+exp(omega*u)); - -model MAIDADS_Sim "MAIDADS model for simulation" / - EQ_w.w - EQ_u.u - EQ_DiscretionaryC.DiscretionaryC - EQ_SubsistenceC.SubsistenceC - / ; - -MAIDADS_Sim.optfile = 1; + w(j) =e= (SubsistenceC(j) + DiscretionaryC(j)) * p(j) / m; + +EQ_u .. sum(i, (alpha(i)+ beta(i)* exp(u)) / (1 + exp(u)) * log(DiscretionaryC(i))) - u =e= kappa; + +EQ_u_NLS .. sum(i, (alpha(i)+ beta(i)* exp(u)) / (1 + exp(u)) * log(DiscretionaryC(i))) - u =e= kappa + error; + +EQ_DiscretionaryC(i)$p(i).. DiscretionaryC(i) =e= [(alpha(i) + beta(i) * exp(u))/(1 + exp(u))] / p(i) * [m - sum(j, p(j) * SubsistenceC(j))]; + +EQ_SubsistenceC(j).. SubsistenceC(j) =e= (delta(j) + tau(j) * exp(omega * u)) / (1 + exp(omega * u)); + +EQ_ressq_NLS .. ressq =e= sqr(error); + +model MAIDADS_Sim_CNS "MAIDADS model for simulation" / + EQ_w + EQ_u + EQ_DiscretionaryC + EQ_SubsistenceC +/ ; + +model MAIDADS_Sim_NLP / + EQ_w + EQ_u_NLS + EQ_DiscretionaryC + EQ_SubsistenceC + EQ_ressq_NLS +/ ; + +MAIDADS_Sim_CNS.optfile = 1; option cns=path; desiredConsumpFactor = m * maxIncomePropFoodSpend / sum(i, p(i)*delta(i)); display desiredConsumpFactor; -Scalar ms 'model status', ss 'solve status'; +Scalar ms 'model status', ss 'solve status'; u = previousU; If (desiredConsumpFactor > 1.0, @@ -87,14 +100,23 @@ If (desiredConsumpFactor > 1.0, SubsistenceC.LO(j) = 0; w(j) = (SubsistenceC(j)+DiscretionaryC(j))*p(j)/m; desiredConsumpFactor = 1; - - solve MAIDADS_Sim using cns; - - ms=MAIDADS_Sim.modelstat; - ss=MAIDADS_Sim.solvestat; + +* Initial solution by maximinsing u to get a better start for CNS. If no solution then use least squares + solve MAIDADS_Sim_CNS using nlp maximising u; + solve MAIDADS_Sim_CNS using cns; + + ms=MAIDADS_Sim_CNS.modelstat; + ss=MAIDADS_Sim_CNS.solvestat; + + if ((MAIDADS_Sim_CNS.modelstat ne 16), + solve MAIDADS_Sim_NLP using nlp minimising ressq; + ms=MAIDADS_Sim_NLP.modelstat; + ss=MAIDADS_Sim_NLP.solvestat; + ); else SubsistenceC(i) = delta(i) * desiredConsumpFactor; ); + display SubsistenceC.l, DiscretionaryC.l; diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java index 287a6054..80d55c7d 100755 --- a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java @@ -21,6 +21,7 @@ import com.gams.api.GAMSVariable; import com.gams.api.GAMSVariableRecord; import com.gams.api.GAMSWorkspace; import com.gams.api.GAMSWorkspaceInfo; +import com.gams.api.GAMSGlobals.ModelStat; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.types.CommodityType; @@ -157,15 +158,31 @@ public class GamsDemandOptimiser { } private GamsDemandOutput handleResults(GAMSDatabase outDB) { - int modelStatus = (int) outDB.getParameter("ms").findRecord().getValue(); - String status = GAMSGlobals.ModelStat.lookup(modelStatus).toString(); + int modelStatusInt = (int) outDB.getParameter("ms").findRecord().getValue(); + ModelStat modelStatus = GAMSGlobals.ModelStat.lookup(modelStatusInt); + LogWriter.println(String.format("\nDemand %s: Modelstatus (%d) %s, Solvestatus %s", inputData.getCountry(), - modelStatus, status, GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) )); + modelStatusInt, modelStatus.toString(), GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) )); GAMSVariable varU = outDB.getVariable("u"); double utility = varU.getFirstRecord().getLevel(); LogWriter.println(String.format("u = %.4f", utility)); + double leastSquareError = Math.abs(outDB.getVariable("error").getFirstRecord().getLevel()); + + switch (modelStatus) { + case SOLVED: break; + case UNDEFINED_STAT: break; + case OPTIMAL_LOCAL: + if (leastSquareError < 1e-5) + LogWriter.printlnWarning("No exact solution. Approximate solution found. Residual = " + leastSquareError); + else + LogWriter.printlnError("Critical! No exact solution. Approximate solution found with high error. Residual = " + leastSquareError); + break; + default: + LogWriter.printlnError("Critical! Solution failed."); + } + GAMSVariable varSubs = outDB.getVariable("SubsistenceC"); GAMSVariable varDisc = outDB.getVariable("DiscretionaryC"); @@ -180,7 +197,7 @@ public class GamsDemandOptimiser { LogWriter.println(String.format("Can't find commodity from Gams demand, so ignoring: " + commodityName)); else { double subsGams = rec.getLevel(); - double discGams = modelStatus==0 ? 0 : varDisc.findRecord(commodityName).getLevel(); //modelStatus==0 is optimiser not run, i.e. too low GDP + double discGams = modelStatusInt==0 ? 0 : varDisc.findRecord(commodityName).getLevel(); //modelStatus==0 is optimiser not run, i.e. too low GDP GamsCommodityDemand demand = new GamsCommodityDemand(commodity, subsGams, discGams,inputData.getKcalPerT(commodity)); LogWriter.println(demand.toString()); demandMap.add(demand); @@ -197,7 +214,7 @@ public class GamsDemandOptimiser { double desiredConsumpFactor = parConsumpFact.getFirstRecord().getValue(); LogWriter.println(String.format("desiredConsumpFactor=%.4f", desiredConsumpFactor)); - return new GamsDemandOutput(status, demandMap, utility, desiredConsumpFactor); + return new GamsDemandOutput(modelStatus.toString(), demandMap, utility, desiredConsumpFactor); } diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOutput.java b/src/ac/ed/lurg/country/gams/GamsDemandOutput.java index 06a2c353..5e793e53 100644 --- a/src/ac/ed/lurg/country/gams/GamsDemandOutput.java +++ b/src/ac/ed/lurg/country/gams/GamsDemandOutput.java @@ -46,10 +46,4 @@ public class GamsDemandOutput { public String getStatus() { return status; } - - public void resetForNewAttempt(int i, double inputUtility) { - - if ((i & 1) == 0) utility = inputUtility * -1.0; - else utility = inputUtility + 0.8*i; - } } diff --git a/src/ac/ed/lurg/demand/ElasticDemandManager.java b/src/ac/ed/lurg/demand/ElasticDemandManager.java index e59eb112..eb88edfe 100755 --- a/src/ac/ed/lurg/demand/ElasticDemandManager.java +++ b/src/ac/ed/lurg/demand/ElasticDemandManager.java @@ -59,18 +59,8 @@ public class ElasticDemandManager extends AbstractSSPDemandManager { GamsDemandInput inputData = new GamsDemandInput(c, year, gdpPc, consumerPrices,kcalPerT, usaGdpPc, previousGamsDemands.get(c)); // Do the projection - GamsDemandOutput gamsOutput = null; - for (int i = 1; i < 50; ++i) { - gamsOutput = new GamsDemandOptimiser(inputData).getDemandPc(); - if (gamsOutput.getStatus().equals("SOLVED") || gamsOutput.getStatus().equals("UNDEFINED_STAT")) - break; - else { - LogWriter.printlnError(i + ": Problem solving " + c + ", " + year + " got " + gamsOutput.getStatus()); - double inputUtility = inputData.getPreviousDemands() == null ? 0 : inputData.getPreviousDemands().getUtility(); - gamsOutput.resetForNewAttempt(i, inputUtility); - inputData = new GamsDemandInput(c, year, gdpPc, consumerPrices, kcalPerT,usaGdpPc, gamsOutput); - } - } + GamsDemandOptimiser gamsDemandOptimiser = new GamsDemandOptimiser(inputData); + GamsDemandOutput gamsOutput = gamsDemandOptimiser.getDemandPc(); previousGamsDemands.put(c, gamsOutput); Map<CommodityType, Double> foodPc = gamsOutput.getPlumDemands(); -- GitLab