Conversation
69c9cd2 to
b433d3c
Compare
…undleSolver 2.0, whose master is solved by the Solver of MPBCfg.txt
…wn to its units, by a solver per scenario or by decomposing the whole tree at once, and the two pay on different sizes
…a two-stage stochastic problem, in the version that is fastest on the TSSB instances of pypsa2smspp
…ems of a round by 8 threads
…-k assembles the form it applies to
…ison with PyPSA was measured with: the MILP, the dual of the scenarios, the chain of two duals and the recursive dual, with their BlockConfig
…, short headers and README, no authors, and a test that every template names files of its folder; the PrimalProximalHeur gets a template that gives a feasible solution
…e Benders form of tssb_solver -k applies to an MSSB too
…er, 8 threads in a fixed order
…nd with PIPS-IPM++ on the same linear program
…lation, which asks Gurobi less work than T
6c180fa to
2145301
Compare
|
@dmeoli this will be needed in the next release correct? it is not yet in develop or yes? |
|
Right: they need the BundleSolver 2.0, which is not in the develop of SMS++ yet, and that is why this one is a draft. The only red job is the one that installs SMS++ from conda-forge, which stops on |
…nteger recourse, PIPS-IPM++ scales by equilibrium, the InvestmentBlock stops on a relative threshold and gets the Solver of its inner block from its OBlockConfig
…and by Gurobi in MPBCfg_grb.txt
…t of the configurations takes for one that is missing
…ad, as for any other Solver
…grangian recipe being the pair -B SDDPBCfg-LD.txt -S SDDPSCfg-LD.txt, which a test checks on the command line
…ed by the recursive Lagrangian dual, with a MILP or a bundle master, and the InvestmentBlock with it inside
… the BDS of the Lagrangian subproblems, as in the PrimalProximalHeur, whose comments are right again
…he best point of its bundle
…etworks has cuts, and the lazy constraints only cost Gurobi memory
|
@dmeoli CI does not pass, could you trigger manually Tests / Test package with latest SMSpp (pull_request) from your branch? |
|
"pypsa2smspp writes the netCDF file in one of several forms, selected by a few of its knobs. capacity_expansion_ucblock puts the design in the units (the form that BDS and the MILP take), investment_outside states it once in an InvestmentBlock above them, and design_cost_outside leaves it in the units but takes its cost out." design_cost_outside is depcrecated and should not be used SPSUnipi/pypsa2smspp#65 Modular family, continuous design, TSSB and MSSB section has MILP SMS++ in table. Is it a mistake? It should be an LP |
…the UCBlock, and the SVM formulations skip a Solver that the build of SMS++ does not have, as with LIBSVM
|
@AlessandroPampado99 thanks, both points are fixed in the description: About the CI: the job with the latest SMS++ runs only on schedule or workflow_dispatch, so I triggered it on the branch of my fork: https://github.com/dmeoli/pySMSpp/actions/runs/36426995339. It was red on
The job with SMS++ from conda-forge stays red until the release that carries BundleSolver 2.0. |
|
The run with the latest SMS++ is green on macOS and Ubuntu now (https://github.com/dmeoli/pySMSpp/actions/runs/36426995339); Windows still stops on the hash of |
… the components whose primal and dual solution is needed in the Configurations of get_var_solution() and get_dual_solution() of the SDDPSolver, as the LagrangianDualSolver no longer has vstr_LDSl_NoEasy, vstr_LDSl_VarSol and vstr_LDSl_DualSol
… the BundleSolver keeping it integer: InvestmentBlock/BSPar-int.txt and TSSBlock/TSSBSCfg-BDS-CVX-int.txt, the ComputeConfigs of the bundle and of its master shared as fragments
…Eps 1e-9 and dblRelAcc 1e-6: dblNZEps is relative to the first full subgradient, which at a design of 0 is millions, and with 1e-4 the bundle stopped 2.9% above the optimum
…the bundle rounds the point of the master before evaluating it, and with the default 1e-6 the linearization there may not cut it away
…d its Gurobi variant solves the inner LP with the default presolve and numerical focus: on a deterministic capacity expansion with 20 nodes it reaches the optimum in 20 minutes instead of not closing in 50
…es Gurobi 1.4 to 5.4 times faster on these networks than 0, measured on the same machine
This PR brings the configuration templates of pySMSpp to BundleSolver 2.0, which is now in the develop of SMS++, and adds one template per way of solving a two-stage stochastic Block (TSSB) or a multi-stage one (MSSB) with the Solvers of SMS++. The six templates that use the BundleSolver lose the parameters of the master of the 1.0 (
intMPName,intMPlvl,intQPmp1,intQPmp2,intOSImp1-3,dblCtOff), since any of them makes aComputeConfigof the 2.0 fail to load, and they name the Solver of the new master inMPBCfg.txt, one per folder (HiGHS by default, Gurobi inMPBCfg_grb.txt). In exchange, with the SMS++ of conda-forge, which still ships the 1.0 until the next release, the templates that use the BundleSolver do not load (they stop at "Invalid int parameter name intMPStbl"). To say which template fits which network we measured all of them against PyPSA with Gurobi on three families of networks written by pypsa2smspp, and the same networks, in smaller sizes, are now in the test batteries of SMS++.The structure of this description is as follows. We first list the new templates, and then describe the forms in which pypsa2smspp writes a network and the setting of each Solver, since the comparison depends on both. Then we report the measurements family by family, the nested forms (a decomposition solving the subproblems of another one) included, and draw from them the choice of the form and of the Solver for a class of networks. Finally, we list the batteries that check the same networks, the limits of what was measured, and the commands to reproduce it.
Templates
All the new templates are in
TSSBlock/.TSSBSCfg-IP.txtTSSBSCfg-LP.txtTSSBSCfg-PIPS.txtmpirun -np <n>TSSBSCfg-LD-IP.txtTSSBSCfg-LDLD.txtTSSBSCfg-LDrec.txt*-par.txtTSSBSCfg-PPH.txtTSSBSCfg-BDS.txtBDSCfg.txt)-kTSSBSCfg-BDS-LD.txtstrRecoveryBSCinBDSCfg-LD.txt)-kTSSBSCfg-BDS-CVX-LD.txtBDSMCfg-CVX.txt)-kTSSBSCfg-BDS-CVX-int.txtintIntVars,BDSMCfg-CVX-int.txt)TSSBSCfg-BDS.txt-kTSSBSCfg-IB.txtsmspp_investmentblock_solver, with-B InnerBCfg-LD.txtthe inner Block solved by the recursive Lagrangian dualThe integer design is also available in an InvestmentBlock, whose netCDF variable
Integermarks the assets whose design is integer (e.g., the number of modules of a modular asset, which pypsa2smspp writes fromp_nom_modin SPSUnipi/pypsa2smspp#62):InvestmentBlock/BSPar-int.txtis the BundleSolver ofBSPar.txtkeeping it integer, i.e., the stabilized cutting-plane method of van Ackooij, Frangioni and de Oliveira, with a trust region of radius 1 and a master that is a mixed-integer linear program (MPBCfg-IP.txt), which HiGHS solves; the BDS template above uses the same master. Onmod_t168_s5_b1the BDS template gives 8.26022e7, asTSSBSCfg-BDS.txtand PyPSA (82602180.128), while with the continuous design it gives 8.25888e7; the InvestmentBlock gives the value of PyPSA onmod_1n_2c_2gof pypsa2smspp.All the thermal templates need
-B InnerBCfg.txt, and-kis the option ofsmspp_tssb_solver(develop of SMS++) that builds the Benders form. As for anything else a Solver does, a feasible solution is asked for in the configuration: the PrimalProximalHeur ofTSSBSCfg-PPH.txtand the BDS ofTSSBSCfg-BDS-LD.txtand ofTSSBSCfg-BDS-CVX-LD.txtrecover it with the BlockSolverConfig in theirstrRecoveryBSC(hereBSCfg1-IP.txt, i.e., each scenario a MILP at a fixed design), and report its value as their upper bound. For BDS the fixed design is that of the master, which with a bundle master is the best point of the bundle.Forms and setting of the Solvers
pypsa2smspp writes the netCDF file in one of several forms, selected by a few of its knobs.
capacity_expansion_ucblockputs the design in the units (the form that BDS and the MILP take), andinvestment_outsidestates it once in an InvestmentBlock above them. Also,stochastic_typeistssbormssb(withtreegrouping the scenarios), andp_nom_modon a generator makes its design integer. We set the Solvers compared below as follows.MIPGap=1e-6apart, i.e., the concurrent method at the root (primal and dual simplex racing the barrier, crossover on) and then its branch and bound.dblRelAcc). Its optionintCutSepPar 7gives Gurobi a callback, and with itPreCrushandLazyConstraints, which keep more columns after the presolve; in our runs they make it faster: without the callback (intCutSepPar 0), and on the same unloaded machine, the same runs take 1.4 to 5.4 times longer (129.3 against 93.0 s on u80_t96_s5, 465.9 against 87.4 s on s200_b10), and on s200_b20 and u80_t168_s3 they do not end within the hour.TUBCfg.txt: 0 = 3bin, 1 = T, 2 = pt, 3 = DP, 4 = SU, 5 = SD, 6 = SUSD). Our templates use 3bin, which in these runs is usually the faster of the two that Gurobi closes. Against T it takes 12.1 against 16.7 s on u80_t48_s3, 92.6 against 122.8 s on u80_t96_s5 and 2229.0 against more than 3600 s on u80_t168_s3, while it is 6% slower on u40_t96_s10 (78.1 against 73.5 s), with the same optimum. In principle the continuous relaxation of 3bin is weaker than that of T; however, on these instances the two give the same value (5.39874e6 on u10_t24_s3), and the root relaxation of Gurobi brings both to the bound of LD+LD (cf. the table of values below). Of the other five, only DP describes the convex hull of the feasible set of a unit, and hence only its continuous relaxation is in general as strong as the Lagrangian dual. Instead, pt, SU, SD and SUSD approximate it with different trade-offs between size and bound (on u10_t24_s3 the four happen to give the value of DP, 5.40782e6, which need not hold on other instances). Their models are much larger (15.8 million rows for DP against 110 thousand for T on u80_t48_s3): Gurobi does not close DP, SU, SD and SUSD in 1800 s, and pt takes 529.7 work units against the 20.3 of T.ThermalUnitExtDPSolver(TUBSCfg-DP.txt);ThermalUnitDPSolveris as fast within the noise of the machine, and takes twice the memory. In all of them the bundle is that of BundleSolver 2.0, sequential or a ParallelBundleSolver with 8 threads (-par), and its master is solved by Gurobi in all the measurements below (MPBCfg_grb.txt).int_BDSlv_Pareto 2,dbl_BDSlv_ParetoMu 0.1) takes it from 42-73 to 24-56 rounds, and from 120-201 s to 93-105 s, on the four capacity-expansion instances of PyPSA, which is still about 10 times the multi-cut standard.BSCfg-IB.txt).-kit is the design, which is the case it is made for. In fact, each Modification rebuilds its model, and therefore it is best suited to a large LP solved once rather than inside a decomposition. On s50_b10c the setting took it from 477 s to 94 s, at 46 to 51 iterations:OMP_NUM_THREADS=1per rank (without it each rank takes all the cores, and the run is 3 times slower), MUMPS as the linear solver (PARDISO of MKL hangs at the root with 25 or more ranks), 25 ranks and the form of-k. Whether it converges at all depends on the scaler:SCALER equilibrium, that ofPIPSCfg.txt, converges on all the instances here, and it is 7 to 14% faster than Curtis-Reid where both converge, whereas Curtis-Reid does not converge on the relaxation of a unit commitment (it stops at its limit of 300 interior point iterations without a bound).BarConvTol=1e-5,PreDual=0,AggFill=0,TSSBSCfg_grb.txt), which may pay, at least on the modular family: with them, on s200_b10c PyPSA takes 85.3 s and MILP SMS++ 50.7 s, and the optimum is 8e-6 higher in relative terms, since the barrier stops without a crossover. They are not used in the tables below.The parameters one most often changes are all in the templates:
dblRelAccis the relative gap of a :MILPSolver (theMIPGapof Gurobi) anddblMaxTimeits time limit, andintMaxThreadthe threads of BDS and those of a ParallelBundleSolver. Also,strRecoveryBSCis the BlockSolverConfig of the recovery of a feasible solution, in the PrimalProximalHeur and in BDS,intRecoveryThreadsthe threads of the recovery of the PrimalProximalHeur, and the first value ofTUBCfg.txtthe formulation of a thermal unit.Computational results
We ran everything on one machine with 2 AMD EPYC 9654 (192 cores) and 1.5 TB, with Gurobi 13.0.2 in PyPSA 1.2.4 and 13.0.1 in SMS++, and with the BundleSolver 2.0 of 20/09 (
2b77538). The InvestmentBlock was measured with that of 25/09 (86ba410), and the nested forms with the develop of 27/09 (umbrellae6ba4025). We made the runs one at a time, with a limit of 3600 s each (1800 s for the nested forms); the load average of the machine stayed under 60 in all of them, and each run records the load when it ends. A time is that of the complete process in seconds, which includes the reading of the network or of the netCDF file but not the conversion by pypsa2smspp, and "> 3600" means that the run did not end within the limit. Where a cell holds two numbers separated by "/", the second is the peak memory in GiB (for PIPS-IPM++, that of its largest process, the others being about as large). PyPSA and MILP SMS++ set in Gurobi the same relative gap, 1e-6, and reach the same optimum to all the digits Gurobi prints. In the tables, "PyPSA" is Gurobi on the model of PyPSA, and "MILP SMS++" and "LP SMS++ (Gurobi)" are the GRBMILPSolver on the model of SMS++ and on its continuous relaxation, or on the model itself where it is a linear program. "LP SMS++ (PIPS)" is PIPS-IPM++ on the latter, and the other columns are the Solvers of the templates.Thermal family
gen_thermal_tssb.pygenerates a network with 1 bus (units x periods x scenarios in the name). Since PyPSA cannot optimize a network that is at once stochastic and committable,extensive_thermal_tssb.pywrites its deterministic equivalent for PyPSA, i.e., one copy of the network per scenario, with the costs of each copy weighted by the probability of its scenario and the design tied across the copies. This is the same two-stage problem that SMS++ solves, and indeed the two reach the same optimum; however, PyPSA does not offer this form, and hence the column "PyPSA" of this family is Gurobi on the extensive form written with PyPSA rather than a path of PyPSA. We use this family mainly for the Lagrangian duals and the PPH, which have no counterpart on an extensive form. On this family the Solvers do not compute the same thing: the MILPs give the optimum, the three Lagrangian Duals (LD) lower bounds of different strength, the LPs the bound of the continuous relaxation, and the PrimalProximalHeur (PPH) feasible solutions. Hence we report the values first, and we compare the times only among the Solvers that deliver the same value. Values are given to the 6 digits SMS++ prints; the optimum is that of Gurobi at a relative gap of 1e-6, the same for PyPSA and MILP SMS++.LD+LD and the recursive LD give the same bound, i.e., that of the relaxation in which each unit is replaced by the convex hull of its feasible set. The LD of the scenarios keeps the units integer inside a scenario, and hence gives a stronger bound, which on these instances is the optimum to 6 digits (0.0016% below it on u80_t168_s3). In turn, the LP of PyPSA is only slightly weaker than that of SMS++, since the two models write the constraints of the units somewhat differently, and both are 0.07 to 0.1% below the optimum. Note that the root relaxation of Gurobi (after its presolve, before its cuts) is already at the bound of LD+LD on the model of SMS++ (1.046984e7 on u80_t48_s3, 2.860082e7 on u80_t168_s3), which matters for the next table.
Times are grouped by the value delivered, and the column "PyPSA to the LD+LD bound" is Gurobi on the model of PyPSA, stopped as soon as its bound reaches that of LD+LD (
BestBdStop); the peak memory of the same runs follows in the second table.Peak memory in GiB of the same runs.
Among the Solvers that give the optimum, the LD of the scenarios is 1.03 to 3.1 times faster than MILP SMS++ and takes 1.6 to 3.9 times less memory, while MILP SMS++ is 1.2 to 2.2 times faster than PyPSA. The bound of LD+LD and of the recursive LD, instead, is reached sooner by Gurobi on 3 instances out of 5 (u40_t96_s10, u80_t168_s3 and u80_t336_s3, in 21.0 to 40.1 s against 27.7 to 586.7 s), which the root relaxation noted above explains, at least in part. Hence, on this family the two duals are not a faster way to that bound; they win on memory (0.2 to 0.8 GiB against 1.2 to 3.8 GiB), and they are the starting point of the feasible solutions below. With a ParallelBundleSolver of 8 threads (
-par) the same bounds come out, to all the printed digits, in 3.5, 9.1, 47.4, 780.1 and > 3600 s for LD, in 1.4, 6.4, 11.0, 52.4 and 311.3 s for LD+LD, and in 1.5, 13.0, 35.2, 20.8 and 102.2 s for the recursive LD. Threads pay where the components are few and large (2.1 to 3.8 times on LD+LD), and much less where they are many and small (1.2 to 1.4 times on the recursive LD, whose master is the bottleneck). PIPS-IPM++, with one rank per scenario and the form of-k, gives the value of Gurobi on the same relaxation to 6 digits, but 20 to 130 times more slowly.For the feasible solutions, PPH starts from the primal solution of its LD and fixes the design of each scenario to its mean over the scenarios (rounded where it is integer). It then solves each scenario by itself with the BlockSolverConfig of its
strRecoveryBSC(here a MILP,intRecoveryThreadsscenarios at a time), and it reports the sum of their values, i.e., the value of a feasible solution, as its upper bound.On the first three instances PPH gives the optimum to the digits Gurobi prints. On u80_t168_s3 it is 0.0005% above the optimum (2.86139e7 against 2.8613751e7), in 150.8 s against the 2286.5 s of MILP SMS++ and the 2839.5 s of PyPSA. On u80_t336_s3, which neither MILP closes in an hour, it gives 5.12783e7, i.e., 0.028% above the bound of LD+LD; there most of the time goes into the recovery, since each scenario is a MILP of 80 units over two weeks. It is fair to remark that some runs on u80_t336_s3 were interrupted by the license service of Gurobi, which allows 2 sessions at a time. The table reports the runs that were not, which give the same bound to all digits.
Modular family, integer design
gen_modular_tssb.pybuilds modules of solar and wind in the first stage, over 168 periods (scenarios x buses in the name). BDS runs on the Benders form that-kbuilds, with 1, 8 or 32 threads (intMaxThread), and it reaches the optimum exactly in the same number of rounds with any number of threads; "PyPSA, 1 thread" is PyPSA with Gurobi restricted to one thread.Since the rounds of BDS do not depend on the threads, we see 11 to 15 times less time going from 1 to 32 threads; on s200_b20 BDS reaches the optimum in 36.7 s, where PyPSA does not close in an hour with all the threads of the machine. With one thread each, i.e., with the same resources, PyPSA does not close any of the five in an hour at the same gap of 1e-6, while BDS takes 52 to 540 s. The exception is s50_b10, the one cell where SMS++ is the slower of the two: both PyPSA and MILP SMS++ find the optimum at the root in about 30 s, and they spend the rest closing the last millionth of the gap (43347 nodes).
Modular family, continuous design, TSSB and MSSB
With the modules turned off (
cin the name) the same networks are linear programs, so that all the Solvers of SMS++ for a stochastic investment apply, PIPS-IPM++ included. Each is written as a TSSB and as an MSSB whose scenarios are grouped into 5 or 10 outer realizations, with the same deterministic equivalent. BDS is the generic Benders decomposition on the leaves, with 8 threads, and the InvestmentBlock is the ad hoc one, which solves the TSSB or the MSSB in full at each evaluation; PyPSA has no MSSB, hence its cells are empty there.BDS is the fastest of the four on all the instances here. On the tree and on the flat problem it makes the same rounds, and both give the same optimum; also the LP takes the same time on both (10.5 to 52.1 s of Gurobi), the difference in the column coming from the reading of the tree. PIPS-IPM++ takes about 3 times the time of Gurobi on the same linear program (3.4 at 50 scenarios, 2.8 at 100 and 200 on the TSSB), with its memory spread over 25 or 50 processes of 0.7 to 2.6 GiB each. At each evaluation the InvestmentBlock solves the stochastic Block (about 15 s on s50, 50 s on s100 and 190 s on s200). It closes s50 and s100 in 18 to 21 iterations, i.e., in 37 to 65 times the time of BDS, the tree costing it no more than the flat problem, and on s200 the hour ends with its value 0.14% (TSSB) and 0.02% (MSSB) above the optimum. Its stopping test is relative to the norm of the first full subgradient (
intWZNorm 10inTSSBSCfg-IB.txt), since as an absolute one the threshold on the aggregated subgradient is below what it reaches on a design in MW, and the bundle would go on long after the optimum.Deterministic capacity expansion
One scenario of the modular family over a longer horizon (continuous design, periods and buses in the name), where the InvestmentBlock wraps a UCBlock. We compare PyPSA, the LP of the UCBlock with its design in the units, PIPS-IPM++ on the same LP (whose blocks are the units), BDS on the Benders form with one subproblem, and the InvestmentBlock over the UCBlock.
Here the ranking is the opposite of that on the stochastic instances above. With one subproblem BDS has no evaluations to run side by side, and it is the slowest of the four; the InvestmentBlock, which closes in 8 to 10 iterations, is instead as fast as PyPSA or faster. PIPS-IPM++ converges on the smallest of the three only, since the blocks of a UCBlock are its units, i.e., many small ones instead of the few large ones its decomposition is made for.
Nested forms
A decomposition can solve the subproblems of another one. The nested forms that we found to make sense here are BDS whose subproblems are solved by the recursive LD (
TSSBSCfg-BDS-LD.txt), the same with the master solved by a bundle (TSSBSCfg-BDS-CVX-LD.txt, i.e., the convex regime), and the InvestmentBlock whose inner Block is solved by the recursive LD (-B InnerBCfg-LD.txtinstead ofInnerBCfg.txt). For comparison, we also give the rows of BDS and of the InvestmentBlock with Gurobi inside.On the thermal instance, whose subproblems are unit commitments, BDS with the recursive LD gives the bound of LD+LD in about a second, since the units are solved by their dynamic programming; this bound (1.04698e7) is above the 1.04614e7 that BDS gives with the relaxed recourse (cf. the limits below). With
strRecoveryBSCit also recovers a feasible solution at the design of its master, each scenario solved as a MILP, with either master (the bundle one at the best point of its bundle). On u80_t48_s3 both give the optimum (1.0471130e7), i.e., 0.012% above the bound, as PPH does on the extensive form. On the modular family, whose subproblems are linear programs, the results are negative: the nested forms reach the optimum of t48_s10_b2c, but they are 450 to 900 times slower than BDS and about 250 times slower than the InvestmentBlock with Gurobi inside, and none of them closes s50_b10c in 1800 s. This is most likely because the dual works through thousands of small components where Gurobi solves one linear program per scenario. With the dual inside, the InvestmentBlock does not even complete its first evaluation on s50_b10c, and it takes 152 GiB, which we have not investigated yet. Also, BDS with a bundle master and Gurobi in the subproblems reaches the optimum of s50_b10c in 76.4 s, against the 8.2 s of the MILP master.Choice of the form and of the Solver
From the measurements above one obtains, for each class of networks, the form and the Solver to use; the ranges are those of the tables.
TSSBSCfg-LD-IP.txt)TSSBSCfg-PPH.txt) for a solutionp_nom_mod), a linear program per scenario-k)TSSBSCfg-BDS.txt), threads inintMaxThreadOver a TSSB or an MSSB the InvestmentBlock is not in the table, since it solves the stochastic Block in full at each evaluation; its place is rather the deterministic case of the last row, and possibly the cases in which the inner Block is not a linear program (e.g., an SDDPBlock). Similarly, the nested forms may be a choice when the subproblem is not a linear program that Gurobi closes (e.g., a unit commitment), whereas on linear subproblems they are usually much slower than the plain forms.
The networks in the batteries of SMS++
Small instances of the three families are in the batteries of
tests(branchdevelop), each in the battery of the module that reads its form, with the reference value of PyPSA; the data are in thenc4archives of 2026-09-26 of UCBlock and InvestmentBlock in the Package Registry, which their CMake downloads. Each battery cross-checks all the Solvers of one BlockSolverConfig on the same instance, and a Solver that gives a bound is declared as such (-Rof the tester for a relaxation,-E inffor a heuristic, whose interval has to contain the optimum).TwoStageStochasticBlock/batches/batch-pypsaBSPar-2S-LD-IP.txt); on the Benders form, BDS whose subproblems are solved by the recursive LD, with its feasible solution recovered at the design of the master, with a MILP master (BSPar-BDS-2S-LD.txt) and with a bundle master (BSPar-BDS-2S-CVX-LD.txt)TwoStageStochasticBlock/batches/batch-pypsa-modularBSPar-BDS-2S-IP.txt); on the continuous ones also BDS whose subproblems are solved by the recursive LD, with a MILP master (BSPar-BDS-2S-LD.txt) and with a bundle master (BSPar-BDS-2S-CVX-LD.txt), and the recursive LD on the extensive form (BSPar-2S-LDrec-IP.txt)MultiStageStochasticBlock/batches/batch-pypsaInvestmentBlock/batches/batch-stochasticInnerBCfg-LD.txt)InvestmentBlock/batches/batch-pypsaInnerBCfg-LD.txt)UCBlock/batches/batch-pypsaEach configuration has one Lagrangian dual, the recursive one, which relaxes the most at once. Several LagrangianDualSolvers attached to the same Block (a PrimalProximalHeur included) give each the bound it gives when it is the only one, in any order.
Limits and open questions
Our measurements are limited to the Solvers that apply to these networks as pypsa2smspp writes them. BDS with an integer recourse, e.g., a TSSB whose scenarios are unit commitments, gives a bound instead of the optimum, since its subproblems are solved as their continuous relaxation: on the thermal family it gives the LP value (1.04614e7 on u80_t48_s3, 5.12561e7 on u80_t336_s3, in 1.1 and 12.8 s), which is weaker than the Lagrangian bound. Its relaxed binaries have bounds and no OneVarConstraint; hence
BDSSCfg.txtsetsintThrowReducedCostException 0, without which the subproblem throws. A Lagrangian dual over an MSSB does not run yet, since relaxing the non-anticipativity of the outer stage gives each LagBFunction a TSSB as its inner Block, and a LagBFunction requires an Objective of that Block, which TSSB and MSSB do not have. Other Solvers are left out because they answer a different question or give nothing new here: (i) ScenarioReductionSolver solves the problem on K representative scenarios, and its measure would be the error against the full set; (ii) SDDP reads anSDDPBlock, which the converter does not write yet; (iii) BranchAndXSolver works on knapsack problems only, for now; (iv) FrankWolfeSolver is on these problems the Dantzig-Wolfe side of the Lagrangian dual, and hence it gives the same bound. Also,intDoEasy, which keeps the network as an "easy" component of the inner master, matters on networks with many buses, while the thermal family has one. Of course, CPLEX, SCIP and HiGHS can replace Gurobi wherever it appears in the templates, by changing one line of the configuration; we used Gurobi because PyPSA-Eur uses it, so that the two sides are comparable.Two questions remain open. The first is the memory of the InvestmentBlock with the recursive LD inside on s50_b10c (152 GiB before its first evaluation), which we have not explained yet and intend to investigate. The second is whether the nested forms pay on networks whose subproblems are unit commitments of realistic size, which Gurobi does not close. The thermal family here is small enough for Gurobi, and hence it only shows that they give the right bound and solution.
Reproduction
<cfg>is the folderpysmspp/data/configs/TSSBlock/of this PR, withMPBCfg_grb.txtcopied overMPBCfg.txt(the master of the measurements is Gurobi, while the default of the templates is HiGHS). Apart fromgen_thermal_tssb.pyandemit_thermal_tssb.py, which are intest/referencesof pypsa2smspp, the generators are inscripts/smspp_instances/referencesof SPSUnipi/pypsa-eur-instances#16.