feat: add m.dualize()#626
Conversation
…None) instead of 0.
…k for deep copy independence.
There was a problem hiding this comment.
@bobbyxng I can't comment on the actual dualisation so I'm focussing on cleanliness and efficiency of code. I've opened another PR (#629) in which I've made some suggestions (I started writing them in comments but they became a bit too verbose).
I feel like it shouldn't be necessary to have your lookup dictionary or rule and that you should be able to store your coefficients your mapping from constraint name to dual variables. I haven't investigated it in detail but the linear expression rule is probably reasonably slow to build compared to a vectorised array operation. I tried with a dummy model with 10000 timesteps and 2 active spatial nodes and it took 20 seconds to build. I can see dualisation therefore exploding on practical models, so more vectorisation is probably necessary.
You still also need:
- unit tests
- docs
BTW, for ease of review, it would be easier if you opened this PR with the copy branch as the base, rather than master. It will automatically revert to master when copy is merged.
|
@bobbyxng Im not really getting what this PR does, as im not that deep into the LP world, but maybe you could use the new features from #634 to do EDIT: Probably not, just needed if a user wants to dualize a MILP. He would call Variables.relax() BEFORE |
Quick review:
But I'd defer the |
|
Thank you all @brynpickering @FBumann @FabianHofmann! Sorry for the delay, I wanted to make sure the dualisation table was solid (also in my ARO workflow). I am confident that the rules all apply correctly. All PyPSA example networks yield the same results in primal and dual formulation (both on the objective and on the variable level, if dual degeneracy is accounted for). I have also added plenty of unit tests. And thanks @brynpickering for the comment on (not) using the linear expression rule, I refactored everything to use numpy operations. Runtime dropped from ~6 minutes to ~2 seconds for a typical 50-node PyPSA network. But I think all this refactoring could use a careful look by someone more experienced with linopy internals, xarray and numpy operations. The From my side, the PR is ready for review. :) |
…edupe lookups Use con.indexes[dim] (pd.Index) for dual variable coords so dualizing dimensioned models no longer raises TypeError. Collapse the duplicated bounded-gather and bound-lifting blocks into shared helpers.
for more information, see https://pre-commit.ci
|
@bobbyxng thanks, I will pull this as soon as CI passes and you give a go on my last commit. what I did
|



Changes proposed in this Pull Request
Model.dualize(), a method that constructs the LP dual of a linopy model,andModel.bounds_to_constraints(), a preprocessing step that converts variable bounds to explicit constraints so they are correctly reflected in the dual.bounds_to_constraints(), so that they appear in the constraint matrix and are correctly reflected in the dual.m2.variables[con_name].solutionandm1.constraints[con_name].dualwithout sign adjustments.m.copy()The motivation behind this was an automated LP dualizer (originally developed for adaptive robust optimization for energy system planning) which requires constructing an independent dual model without modifying the original. While similar implementations exist in other modelling frameworks, notably JuMP's
Dualization.jlhttps://jump.dev/JuMP.jl/stable/packages/Dualization/, this feature was still missing in linopy.Checklist
doc.doc/release_notes.rstof the upcoming release is included.