alexe15 / ALADIN.m

Other
35 stars 13 forks source link

Abstract ALADIN implementation #84

Open alexe15 opened 4 years ago

alexe15 commented 4 years ago

ALADIN implementation independent of CasADi.

timueh commented 4 years ago

Broadly speaking, the goal is to untangle Casadi from Aladin so that we can use Aladin without having to use Casadi. This is necessary for large problems, where Casadi just takes too long to set up the problem.

timueh commented 4 years ago

Let me add some details:

Status quo

Currently, there is no possibility to not use Casadi. In other words, when you use the toolbox, you need to use casadi. The advantages of Casadi, but so are its disadvantages:

It is especially the last point that is painful. For instance, large (optimal) power flow problems simply take too long to set up. Playing with them is no fun 😢

Proposition

Untangle Aladin and Casadi. Essentially, make two repositories: the Aladin core and a Casadi preprocessor. Then, using the Casadi preprocessor together with Aladin core is like using the toolbox now. However, if someone is brave enough to not use Casadi, then use just Aladin core. The goal of this issue is to write Aladin core

Aladin core

The plain Aladin algorithm that does not rely on external packages. It takes a problem formulation as input and returns the solution. The critial point is how to formulate and solve the local NLPs; how to call a solver depends on the solver itself: fmincon is different from ipopt, and so on.

Question: Should the formulation of the NLP be part of Aladin core or not? If it is, we restrict ourselves to the solvers that we support.

Once we have reached consensus on this issue, we should create a file to define the interface.

alexe15 commented 4 years ago

I agree, just for you to know we have a similar feature implemented in ALADIN-M. If you have a look at the ALADIN MPC example (https://alexe15.github.io/ALADIN.m/robotEx/, you can also find this problem in the /examples folder), then you can see that Ruchuan implemented a reuse option. This means that the problem formulation can be reused after one ALADIN run for MPC problems, where only the initial condition for the ODE changes. This reuse is automatically detected within ALADIN-M. This is done here https://github.com/alexe15/ALADIN.m/blob/43dbc9d993d5c7ccb040cf0c2f27c677f8ab02f3/src/core/run_ALADINnew.m#L30 so if NLP solvers, sensitivities etc. are defined in the sProb struct ALADIN-M will use them. So I think to some extent, this is where we could start. If we pass solvers here, which use the same interface as the CasADi solvers as here https://github.com/alexe15/ALADIN.m/blob/43dbc9d993d5c7ccb040cf0c2f27c677f8ab02f3/src/core/parallelStepCentral.m#L27 then I guess we should be able to define the problems more or less completely externally also with non-CasADi solvers. Btw @Ruchuan is working on a similar issue for a machine learning problem in #102 (Yuning suggested to include this as an additional example showing that we can gain some benefits with bi-level ALADIN for machine learning problems)

timueh commented 4 years ago

You agree with what? 🤣

I can ask my question again in ALADIN-M-lingo: should Aladin core be simply iterateAL()? Yes or no?

(that's really a design question i don't know the answer to)

However, I do think that we should not rely on the interface from Casadi, because it's highly customized to Casadi. Instead, can we move to function handles? Check out this prototypical example:

Taking the standard example

import casadi.*
x = SX.sym('x');
y = SX.sym('y');
z = SX.sym('z');
nlp = struct('x',[x;y;z], 'f',x^2+100*z^2, 'g',z+(1-x)^2-y);
S = nlpsol('S', 'ipopt', nlp);

the Casadi way to solve this is

x0 = [2.5,3.0,0.75]
S('x0', x0', 'lbg', 0, 'ubg', 0)

What if, instead, we make this a function handle?

solve_problem = @(x)S('x0', x, 'lbg', 0, 'ubg', 0)
solve_problem(x0)

Thinking about this a little more: this does fix a lot of Casadi dependency. As you said: as long as I provide a valid sProb together with a (function handle solve_problem) way to solve the NLPs, I am fine.. or not?!?!

TimmFaulwasser commented 4 years ago

@Till: this is a valid suggestion, which has been on the table for discussion for some time. At this point, it should not get priority.

timueh commented 4 years ago

Running examples/examples_main.m with use_fmincon = false yields the usual solution:

grafik

Setting now use_mincon = true uses fmincon only to solve the local NLP. The computation of the sensitivities is untouched. The result is

grafik

While overall convergence agrees, the final values differ.

Anyhow, first step taken. Yay 🎉 🎉 🎉

However, we do need to agree on a common interface for calling the NLP solvers. I do think that abstractifying everything will improve readability of the code tremendously. Check out how

https://github.com/alexe15/ALADIN.m/blob/9692c8218cf7e6b7d83454f781ec9c328487fea5/src/core/createLocalSolvers.m#L51

is defined:

https://github.com/alexe15/ALADIN.m/blob/9692c8218cf7e6b7d83454f781ec9c328487fea5/src/core/createLocalSolvers.m#L70-L77

timueh commented 4 years ago

Having talked to @alexe15, the suggestion for the common interface for solving the local NLPs is:

solve_NLP(x0, z, rho, lambda, Sigma, pars)

where pars is a struct containing arbitrary parameters.

timueh commented 4 years ago

I rectified the interface https://github.com/alexe15/ALADIN.m/blob/ff08ccaa927a8f7aa4f60e4ad3ed506803c1fdde/src/core/parallelStepCentral.m#L35-L36

I only tested against runtests('OptProbsTest') with Ipopt. ^^

The next step is to let the user specify the sensititivies.

timueh commented 4 years ago

Big fail from my side: the numerical sensitivies were not used correctly in all previous versions (and the gradient of the cost function was incorrect..). With 075888a it should be correct. Also, for the distributed power flow problem I compared the numerical sensitivities against casadi: they agree.

timueh commented 4 years ago

I wrote a few lines to describe what I did the last couple of days. My preliminary conclusion is that to abstractify aladin is, luckily, less involved than I feared. I got it to work with fmincon and user-supplied sensitivities for a distributed power flow problem, and it can solve cases for which casadi+ipopt simpy takes too long to set up (e.g. coupling three 118-bus systems).

I will stop working on this for now, but @bennerh will take over beginning in May.

@alexe15, please take a look at the document I wrote. This should be the basis for future discussions.

timueh commented 4 years ago

I cleaned up the parallel step tremendously, shifting all the heavy burden to local functions. Readability of the code is increased. I think this more modular approach helps also for the file doing the decentralized step.

timueh commented 4 years ago

Having spoken to @alexe15, the goal of the abstractify branch can be summarized as follows:

When calling iterateAL( sProb, opts, timers ), no information about casadi need to be passed.

In its simplest form, the following check needs to evaluate to true: does iterateAL() run after having deleted all fields in sProb that have cas in their name?

In a more elegant form, sProb should not contain any casadi information to begin with.. ;)

timueh commented 4 years ago

The first draft of the interface for iterateAL() can be found here.

bennerh commented 4 years ago

Proposal for next step: Construct an example file that should run with the abstractified-ALADIN branch version. To do so, I would rebuild the example provided by @timueh for the abstractify branch.

In case there are no objections from your side, I would start doing that now..

Furthermore I would like to test a solver different from fmincon and ipopt, because it's a good task for me and a good test in the end. Any suggestions there?

timueh commented 4 years ago

I would not try to replicate my example; there is simply no need. The best tests are and remain the test that you have written already.

AFAICT either all of them work or all of them fail... ;)

Implementing different solvers is on the agenda, see #106, #107, but I would not do that now. Let's do one thing at a time.