tBuLi / symfit

Symbolic Fitting; fitting as it should be.
http://symfit.readthedocs.org
MIT License
234 stars 17 forks source link

First version of `symmip`, which adds tentative MIP support #370

Open tBuLi opened 1 year ago

tBuLi commented 1 year ago

First version of symmip, a symbolic wrapper around MIP solvers. Currently only support the Gurobi API, but the code is setup in such a way that we can easily add other solvers.

Added as a seperate module, because merging it into the existing symfit infrastructure was less than obvious. In particular, the existing Models, objectives and minimizers are only very expensive boilerplate with no added value for MIPs, so for now I cut ties with this formalism. We can always still plug this MIP solver back into the Fit API if we have a good MIP API to begin with.

lesshaste commented 1 year ago

Highs would be wonderful to add as it is open source.

pckroon commented 1 year ago

Oh, and another question. I love the type annotations, but what does it mean for the minimum python version we can use/support?

tBuLi commented 1 year ago

Highs would be wonderful to add as it is open source.

Thanks for the tip, I wasn't aware of that package! I agree that we should have an open solver (as a default). But I tried to include it and found the documentation lacking and moreover, couldn't get the examples to work for Highs. So I've now instead added a wrapper for SCIP and made that the default, and that seems to work beautifully! So thanks for pointing me in this direction.

tBuLi commented 1 year ago

Alright! I mostly like it. I do have some comments and questions though.

  • Can you explain what the problem is with Models and Objectives + MIP? As I see it it should be possible to hook at least Model into this, maybe as MIPModel (see also ODEModel). I agree (for now) to leave out Objectives.

Great question. The main issue is that in order to translate the symbolic definition into a MIP model, I actually need to interact directly with the symbolic definition and use a custom code printer to translate it into the target MIP backend. I found that with our existing models it is actually quite hard to get back to the symbolic expressions, because they are more designed to be easily called with data and parameters. Moreover, with the existing Model classes there is no control over the Printer being used; it is always the default one that sympy offers.

So my idea here was the following: within the symmip module I will make a new Model class, which has way less boilerplate code and allows direct control over the printing. Moreover, I will use the lessons from both symfit and the slymfit brainstorm session to make sure this model can also be dropped back into symfit eventually.

  • What does this mean for Indexed in base symfit?

A bit similar to the previous answer, I think that starting from scratch in a new submodule in a context that is full of indexed symbols will be a good opportunity to learn some best practices for dealing wit these objects, that can then be back ported into symfit.

  • I'm missing tests and docs ;)

Yeah it definitely still needs some work ;).

Oh, and another question. I love the type annotations, but what does it mean for the minimum python version we can use/support?

I'm pretty sure that everything from >3.5 should be okay with this, so I don't expect any problems but let's keep our eyes open.

pckroon commented 1 year ago

Alright, thanks for the explanation. If I understand it Model + Minimizer determine the Printer? Or even just Minimizer? Following this line of thought, does that mean everything should remain as symbolic as possible, right up until the Minimizer touches it? This also has implications for Objectives --- symbolical objectives have been on my wish list for a while.

I think it's a good idea to fix this in code symfit Models now that we (you) know better, similar for Indexed*.

I think its fine to do some trial-and-error prototyping in a submodule like you do here, but I'd strongly prefer the final PR simply improving the symfit classes. This will also have the benefit of being able to use the tests to make sure you're not missing old use cases. I also think it'll result in less work since you'll be able to build on the existing framework. And where that doesn't fit, just break/adapt the old framework.

Can you do MIPODEModels? If no, your design is not good enough yet :D