
u=zeros(OCP.numControls,round(OCP.timeHorizon/OCP.timeInterval));  %Initial guess for the controls if no combinatorial search is performed before the local optimization framework, any control can be set to any value between 0 and 1 for an initial guess for example ones() instead of zeros()

if(combi_method==1)                                         %Block for the combinatorial method
    fprintf('\n');
    fprintf('Starting combinatorial method...\n');
    A=combinatorial_method(f,xd,tol1,max_Num,T_int,OCP);    %Trys to get external stimuli causing desired switch by trial an error for different combinations of external stimuli, Output: array, left column number of stimuli, right column duration of its application from t=0
    if(isempty(A)==0)                                       %Check if any external stimuli have been found
        u=setControls(A,OCP);                               %Sets u according to the external stimuli returned by function combinatorial_method if the set of external stimuli returned by function combinatorial_method is not empty
        fprintf('\n');                                        
        fprintf('External stimuli from combinatorial method causing desired switch at a tolerance |x-xd|<%d:\n',tol1)       
        [rowA,~]=size(A);                                   %Number of the set of external stimuli which have been found causing the desired switch                                                                                     %Determine rows of A     
        for i=1:rowA                                                                              %Read out each row
            fprintf('External stimulus %i applied at t=0 for %d time units\n', A(i,1),A(i,2));    %Output results of combinatorial_method, that means read out matrix A if not empty
        end
    end
end

if(local_optimization_method==1 || local_optimization_method==2)                             %Block for the local optimization method                                                         
    [df_x,cmx,df_u,cmu]=createJacobian(f,OCP);                                               %Creates derivatives of f with respect to x and u, Jacobian of the right hand side f
    if(local_optimization_method==1)
        u=SQH_method( @get_J_SQH,f,df_x,cmx,df_u,cmu,tol2,u,xd,max_iter,OCP); %Sequential quadratic Hamiltonian method as a local optimization scheme, returns u, u the external stimuli optimizing the target functional
                                                                              %Input: @get_J function handle for the target functional, f right hand-side of the ordinary differential equation corresponding to the network with dx/dt=f(x(t),u(t))
                                                                              %df_x function handle for the derivative of f with respect to x, cmx notes the nonzero elements of df_x, df_u function handle for the derivative of f with respect to u, cmu notes the nonzero elements of df_u, see output function createJacobian
                                                                              %u inital guess for the external stimuli, can be taken from the combinatorial method 
                                                                              %xd desired state for the values x of the corresponding nodes, tol2 stopping criterion, max_iter maximum number of updates on the control u of the sequential quadratic Hamiltonian
    end                                                              
                                                                                                                                                            
    if (local_optimization_method==2)
        [u,~,~]=projected_gradient_method( @get_gradient, @projection, @get_J,f,df_x,cmx,df_u,cmu, u, xd, tol3, max_iter, OCP );    %Prjected gradient method as a local optimization scheme, returns [u,J,count], u the external stimuli optimizing the target functional
                                                                                                                                    %Input:@get_gradient function handle for the gradient of the reduced target funcitonal, @projection function handel of the projection, projects u into [0,1] 
                                                                                                                                    %@get_J function handle for the target functional, f right hand-side of the ordinary differential equation corresponding to the network with dx/dt=f(x(t),u(t))
                                                                                                                                    %df_x function handle for the derivative of f with respect to x, cmx notes the nonzero elements of df_x, df_u function handle for the derivative of f with respect to u, cmu notes the nonzero elements of df_u, see output function createJacobian
                                                                                                                                    %u inital guess for the external stimuli, can be taken from the combinatorial method 
                                                                                                                                    %xd desired state for the values x of the corresponding nodes, tol2 stopping criterion, max_iter maximum iteration number of the projected gradient method  
    end
end

if(max(max(u))~=0)                          %Print the numbers of active external stimuli if there is an external stimulus being different from a constant zero function
    fprintf('\n');
    fprintf('Active external stimuli, that means being different from constant zero function:\n');                      
    for i=1:OCP.numControls                 %Prints out the numbers which correspond to the active external stimuli, can be copied for the function drawStimuli  
        if(max(u(i,:))~=0)
            fprintf('%i,',i);
        end
    end
    fprintf('\n');
else
    fprintf('No active external stimulus\n');
end

x=forward(f,u,OCP);                           %Calculates the state of the network corresponding to the external stimuli u calculated with the schemes above

fprintf('\n');
fprintf('Final values of the state x at final time T\n');         
fprintf('Number node\t Value node\n')
for i=1:OCP.numNodes                          %Output of the value of the state x at final time T
    fprintf('%i\t\t %d\n',i,x(i,end));
end

if(min((abs(x(:,end)-xd(:,end))<tol1)))       %Checks if final external stimuli cause the desired switch up to tolerance tol1
    fprintf('\n');
    fprintf('Each node equals its desired value at final time within its tolerance, that means |x_i(T)-x_d_i|<%d\n',tol1);
else
    fprintf('\n');
    fprintf('There is a node that does not have its desired value at the end, that means |x_i(T)-x_d_i|>=%d\n',tol1);
end

fprintf('\n');
fprintf('Save data to file...\n');
dlmwrite('x.txt',[0:OCP.timeInterval:round(OCP.timeHorizon/OCP.timeInterval)*OCP.timeInterval;x]);               %Writes the state x in a text-file "x.txt" where the first row corresponds to the discrete time steps, separated by commas, row i=2,...,numNode+1 corresponds to state x(i-1), values in the colums, separated by commas, value of x(i) at the corresponding time step  
dlmwrite('u.txt',[0:OCP.timeInterval:(round(OCP.timeHorizon/OCP.timeInterval)-1)*OCP.timeInterval;u]);           %Writes the external stimuli u in a text-file "u.txt" where the first row corresponds to the discrete time steps, separated by commas, row i=2,...,numControls+1 corresponds to external stimlus u(i), values in the colums, separated by commas, value of u(i) at the corresponding time step
fprintf('Done!\n')
end



%%%%%% Network information %%%%%%

 