No BSD License  

Highlights from
GPOPS

from GPOPS by Camila Francolin
Solves multiple phase optimal control problems.

gpopsNlp2oc(setup);
function setup = gpopsNlp2oc(setup);
%------------------------------------------------------------------%
% Convert the NLP solution to trajectory format                    %
%------------------------------------------------------------------%
% GPOPS Copyright (c) Anil V. Rao, Geoffrey T. Huntington, David   %
% Benson, Michael Patterson, Christopher Darby, & Camila Francolin %
%------------------------------------------------------------------%

clear snoptcmex
ps = setup.ps;
result = setup.result;
variable_indices = setup.variable_indices;
constraint_indices = setup.constraint_indices;
variables = setup.variables;
constraints = setup.constraints;
sizes = setup.sizes;
nodes = setup.nodes;
numvars   = setup.numvars;
numlin    = setup.numlin;
numnonlin = setup.numnonlin;
numphases = setup.numphases;
numlinks = setup.numlinks;
x = result.x;
lamvars = result.xmul;        % Get the lagrange multipliers for
                              % the variables
lamlin  = result.Amul;        % Get the lagrange multipliers for
                              % the linear constraints
lambda  = result.Fmul(1:numnonlin-numlinks);
solution = cell(numphases,9); % Set up a cell array to store the solution
cost = 0;
varshift = 0;
conshift = 0;
for i=1:numphases;
    %--------------------------------------------------------------------%
    % First construct the primal solution to the optimal control         %
    % problem (i.e., states, controls, and parameters)                   %
    %--------------------------------------------------------------------%
    xcurr = x(variable_indices{i});
    nstates = sizes(i,1);
    ncontrols = sizes(i,2);
    nparameters = sizes(i,3);
    npaths = sizes(i,4);
    nevents = sizes(i,5);
    state_indices = 1:(nodes(i)+2)*nstates;
    if ncontrols>0,
        control_indices = state_indices(end)+1:state_indices(end)+nodes(i)*ncontrols;
        t0_index = control_indices(end)+1;
    else
        control_indices = [];
        t0_index = state_indices(end)+1;
    end;
    tf_index = t0_index+1;   
    parameter_indices = tf_index+1:tf_index+nparameters;
    t0 = xcurr(t0_index);
    tf = xcurr(tf_index);
    state_vector = xcurr(state_indices);
    control_vector = xcurr(control_indices);
    tau_all = [-1; ps{i,2}; 1];
    t_all = (tf-t0)*(tau_all+1)/2+t0;
    t_gauss = t_all(2:end-1);
    if nstates>0,
	state_matrix = reshape(state_vector,nodes(i)+2,nstates);
	state_gauss = state_matrix(2:end-1,:);
    else
	state_matrix = [];
    end;
    if ncontrols>0,
        control_matrix = reshape(control_vector,nodes(i),ncontrols);
        control_t0 = zeros(1,ncontrols);
        control_tf = control_t0;
        if ~isequal(t0,tf),
            for j=1:ncontrols
                control_t0(j) = interp1(t_gauss,control_matrix(:,j),t0,'spline','extrap');
                control_tf(j) = interp1(t_gauss,control_matrix(:,j),tf,'spline','extrap');
            end;
        else
            control_t0 = control_matrix(1,:);
            control_tf = control_matrix(end,:);
        end;
        control_matrix = [control_t0; control_matrix; control_tf];
    else
        control_matrix = [];
    end;
    parameters = xcurr(parameter_indices);
    %------------------------------%
    % Next, construct the costates %
    %------------------------------%
    lamcurr = lambda(conshift+1:conshift+(nodes(i)+1)*nstates);
    lamcurr = reshape(lamcurr,nodes(i)+1,nstates);
    costatef = lamcurr(end,:);
    costate_gauss = zeros(nodes(i),nstates);
    Inverse_Weight_Matrix = diag(1./ps{i,3});
    costate_gauss = Inverse_Weight_Matrix*lamcurr(1:end-1,:);
    costatef_matrix = repmat(costatef,nodes(i),1);
    DD = ps{i,1}(:,1);
    DD = repmat(DD,1,nstates);
    costate0 = sum(-DD.*lamcurr(1:end-1,:),1);
    alpha0 = ps{i,3}*ps{i,1}(:,1);
    costate0 = costate0+(1+alpha0)*costatef;
    costates = [costate0; costate_gauss; costatef];
    %--------------------------------------------%
    % Solve for the initial and terminal control %
    %--------------------------------------------%
    if ncontrols>0,
        ss0 =      '---------------------------------------------------';
        ss=strcat(['BEGIN:  Computation of Endpoint Controls in Phase ',num2str(i)]);
        disp(' ');
        disp(' ');
        disp(ss0);
        disp(ss);
        disp(ss0);
        ulow = setup.limits{1}{i,3};
        uupp = setup.limits{2}{i,3};
        if npaths>0,
            pathmin = setup.limits{1}{i,5};
            pathmax = setup.limits{2}{i,5};
        else
            pathmin = [];
            pathmax = [];
        end;
        Flow = [-Inf; pathmin];
        Fupp = [ Inf; pathmax];
        global extras funcs;
        extras{1} = t_all(1);
        extras{2} = state_matrix(1,:);
        extras{3} = parameters;
        extras{4} = costate0;
        extras{5} = i;
        funcs = setup.funcs;
        usrfun = 'gpopsEndPointControl';
        snscreen on
        uguess = control_t0.';
        snseti('Derivative Option',0);
        snprint('snoptmain0.out');
        snseti('Timing level',3);
        % ---------------------------------------%
        % Compute the Control at Initial Time    %
        % Using the Pontryagin Minimum Principle %
        % ---------------------------------------%
        m = length(Flow); n = length(uguess);
        umul   = zeros(n,1); ustate = zeros(n,1);
        Fmul   = zeros(m,1); Fstate = zeros(m,1);
        ObjAdd = 0; ObjRow = 1; solveopt = 1;
        Sjacobian = ones(m-1,n);
        Alinear = [];
        S_all = [ones(1,n); Sjacobian; zeros(size(Alinear))];
        [iGfun,jGvar,SS]=find(S_all);
        iGfun = iGfun(:);
        jGvar = jGvar(:);
        A = []; iAfun = []; jAvar = [];
        [u0out,F0out,xmul0out,Fmul0out,inform0] = snoptcmex(solveopt,uguess,ulow,uupp,umul,ustate,Flow,Fupp,Fmul,Fstate,ObjAdd,ObjRow,A,iAfun,jAvar,iGfun,jGvar,usrfun);
        extras{1} = t_all(end);
        extras{2} = state_matrix(end,:);
        extras{3} = parameters;
        extras{4} = costatef;
        extras{5} = i;
        funcs = setup.funcs;
        uguess = control_tf.';
        snseti('Derivative Option',0);
        snprint('snoptmainF.out');
        snseti('Timing level',3);
        % ---------------------------------------%
        % Compute the Control at Initial Time    %
        % Using the Pontryagin Minimum Principle %
        % ---------------------------------------%
        m = length(Flow); n = length(uguess);
        umul   = zeros(n,1); ustate = zeros(n,1);
        Fmul   = zeros(m,1); Fstate = zeros(m,1);
        ObjAdd = 0; ObjRow = 1; solveopt = 1;
        [uFout,FFout,umulFout,FmulFout,informF] = snoptcmex(solveopt,uguess,ulow,uupp,umul,ustate,Flow,Fupp,Fmul,Fstate,ObjAdd,ObjRow,A,iAfun,jAvar,iGfun,jGvar,usrfun);
        ss0 =      '------------------------------------------------';
        ss=strcat(['END: Computation of Endpoint Controls in Phase ',num2str(i)]);
        disp(' ');
        disp(' ');
        disp(ss0);
        disp(ss);
        disp(ss0);
        control_matrix(1,:) = u0out;
        control_matrix(end,:) = uFout;
    else
        if npaths>0,
            pathmin = setup.limits{1}{i,5};
            pathmax = setup.limits{2}{i,5};
        else
            pathmin = [];
            pathmax = [];
        end;
        Fmul0out = [0; zeros(size(pathmax))];
        FmulFout = [0; zeros(size(pathmax))];
    end;
    if npaths>0,
        pathmults = [];
        pathmults = lambda(conshift+(nodes(i)+1)*nstates+1:conshift+(nodes(i)+1)*nstates+npaths*nodes(i));
        pathmults = reshape(pathmults,nodes(i),npaths);
        for j=1:npaths
            pathmults(:,j) = 2*pathmults(:,j)/(tf-t0)./setup.ps{i,3}.';
        end;
        if ncontrols>0,
            pathmults = [Fmul0out(2:end).'; pathmults; FmulFout(2:end).'];
        else
            pathmults0 = zeros(1,npaths);
            pathmultsF = zeros(1,npaths);
            for k=1:npaths
                pathmult0(k) = interp1(t_all(2:end-1),pathmults(:,k),t_all(1),'spline','extrap');
                pathmultF(k) = interp1(t_all(2:end-1),pathmults(:,k),t_all(end),'spline','extrap');
            end;
        end;
    else
        pathmults = [];
    end;    
    % -------------------------------------------------------------------%
    % Put all of the information from the primal and dual solutions      %
    % into the appropriate location in the cell array SOLUTION           %
    % i = phase number                                                   %
    % solution{i,1}: vector containing time                              %
    % solution{i,2}: N+2 by nx matrix containing states                  %
    % solution{i,3}: N+2 by nu matrix containing controls                %
    % solution{i,4}: vector of length q containing static parameters     %
    % solution{i,5}: N+2 by np matrix containing path multipliers        %
    % solution{i,6}: N+2 by np matrix containing costates                %
    % solution{i,7}: vector of length N+2 containing Hamiltonian         %
    % solution{i,8}: scalar containing the Mayer cost                    %
    % solution{i,9}: scalar containing the Lagrange cost                 %
    solphase{1,1} = t_all(1);
    solphase{1,2} = state_matrix(1,:).';
    solphase{1,3} = t_all(end);
    solphase{1,4} = state_matrix(end,:).';
    solphase{2,1} = t_all;
    solphase{2,2} = state_matrix;
    solphase{2,3} = control_matrix;
    solphase{2,4} = parameters;
    [Mayer,Lagrange] = feval(setup.funcs{1},solphase,i);
    soldae{1,1} = t_all;
    soldae{1,2} = state_matrix;
    soldae{1,3} = control_matrix;
    soldae{1,4} = parameters;
    dae = feval(setup.funcs{2},soldae,i);
    Hamiltonian = zeros(nodes(i)+2,1);
    Hamiltonian = Lagrange+sum(costates.*dae(:,1:nstates),2);
    varshift = varshift+length(variable_indices{1,i});
    conshift = conshift+length(constraint_indices{1,i});
    Lagrange_Cost = (tf-t0)*setup.ps{i,3}*Lagrange(2:end-1)/2;
    cost = cost + Mayer + Lagrange_Cost;
    solution(i,:) = {t_all,state_matrix,control_matrix,parameters,costates,pathmults,Hamiltonian,Mayer,Lagrange_Cost};
end;
solution(end+1,:) = {'time','states','controls','parameters','costates','path_multipliers','Hamiltonian','Mayer_cost','Lagrange_cost'};
setup.solution = solution;
setup.cost     = cost;

Contact us at files@mathworks.com