// Copyright (C) 2015 - IIT Bombay - FOSSEE
//
// This file must be used under the terms of the CeCILL.
// This source file is licensed as described in the file COPYING, which
// you should have received as part of this distribution. The terms
// are also available at
// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
// Author: Salman Anis, Harpreet Singh
// Organization: FOSSEE, IIT Bombay
// Email: toolbox@scilab.in
function [xopt,fopt,exitflag,output,lambda,gradient,hessian] = fseminf (varargin)
// Solves a multi-variable constrainted optimization problem
//
// Calling Sequence
// xopt = fseminf(fun,x0,ntheta,seminfcon)
// xopt = fseminf(fun,x0,ntheta,seminfcon,A,b)
// xopt = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq)
// xopt = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq,lb,ub)
// xopt = fseminf(fun,x0,ntheta,seminfcon,A,b,Aeq,beq,lb,ub,options)
// [xopt,fopt] = fseminf(.....)
// [xopt,fopt,exitflag]= fseminf(.....)
// [xopt,fopt,exitflag,output]= fseminf(.....)
// [xopt,fopt,exitflag,output,lambda]=fseminf(.....)
// [xopt,fopt,exitflag,output,lambda]=fseminf(.....)
// [xopt,fopt,exitflag,output,lambda]=fseminf(.....)
//
// Parameters
// fun : a function, representing the objective function of the problem
// x0 : a vector of doubles, containing the starting values of variables of size (1 X n) or (n X 1) where 'n' is the number of Variables
// ntheta : The number of semi-infinite constraints.
// seminfcon : a function that calculates the vector of nonlinear inequality constraints c, a vector of nonlinear equality constraints ceq, and ntheta semi-infinite constraints. See below for details.
// A : a matrix of double, represents the linear coefficients in the inequality constraints A⋅x ≤ b.
// b : a vector of double, represents the linear coefficients in the inequality constraints A⋅x ≤ b.
// Aeq : a matrix of double, represents the linear coefficients in the equality constraints Aeq⋅x = beq.
// beq : a vector of double, represents the linear coefficients in the equality constraints Aeq⋅x = beq.
// lb : a vector of double, contains lower bounds of the variables.
// ub : a vector of double, contains upper bounds of the variables.
// options : a list, containing the option for user to specify. See below for details.
// xopt : a vector of double, the computed solution of the optimization problem.
// fopt : a double, the value of the function at x.
// exitflag : The exit status. See below for details.
// output : The structure consist of statistics about the optimization. See below for details.
// lambda : The structure consist of the Lagrange multipliers at the solution of problem. See below for details.
//
// Description
// Search the minimum of a constrained optimization problem specified by :
// Find the minimum of f(x) such that
//
//
// \begin{eqnarray}
// &\mbox{min}_{x}
// & f(x) \\
// & \text{subject to} & A*x \leq b \\
// & & Aeq*x \ = beq\\
// & & lb \leq x \leq ub \\
// & & c(x) \leq 0\\
// & & ceq(x) \ = 0\\
// & & K_i(x,w_i) \leq 0, 1 \leq i \leq n.
// \end{eqnarray}
//
//
// The routine calls Ipopt for solving the Constrained Optimization problem, Ipopt is a library written in C++.
//
// The options allows the user to set various parameters of the Optimization problem.
// It should be defined as type "list" and contains the following fields.
//
// Syntax : options= list("MaxIter", [---], "CpuTime", [---], "GradObj", ---);
// MaxIter : a Scalar, containing the Maximum Number of Iteration that the solver should take.
// CpuTime : a Scalar, containing the Maximum amount of CPU Time that the solver should take.
// GradObj : a function, representing the gradient function of the Objective in Vector Form.
// Default Values : options = list("MaxIter", [3000], "CpuTime", [600]);
//
//
// The exitflag allows to know the status of the optimization which is given back by Ipopt.
//
// exitflag=0 : Optimal Solution Found
// exitflag=1 : Maximum Number of Iterations Exceeded. Output may not be optimal.
// exitflag=2 : Maximum amount of CPU Time exceeded. Output may not be optimal.
// exitflag=3 : Stop at Tiny Step.
// exitflag=4 : Solved To Acceptable Level.
// exitflag=5 : Converged to a point of local infeasibility.
//
//
// For more details on exitflag see the ipopt documentation, go to http://www.coin-or.org/Ipopt/documentation/
//
// The output data structure contains detailed informations about the optimization process.
// It has type "struct" and contains the following fields.
//
// output.Iterations: The number of iterations performed during the search
// output.Cpu_Time: The total cpu-time spend during the search
// output.Objective_Evaluation: The number of Objective Evaluations performed during the search
// output.Dual_Infeasibility: The Dual Infeasiblity of the final soution
//
//
// The lambda data structure contains the Lagrange multipliers at the end
// of optimization. In the current version the values are returned only when the the solution is optimal.
// It has type "struct" and contains the following fields.
//
// lambda.lower: The Lagrange multipliers for the lower bound constraints.
// lambda.upper: The Lagrange multipliers for the upper bound constraints.
// lambda.eqlin: The Lagrange multipliers for the linear equality constraints.
// lambda.ineqlin: The Lagrange multipliers for the linear inequality constraints.
// lambda.eqnonlin: The Lagrange multipliers for the non-linear equality constraints.
// lambda.ineqnonlin: The Lagrange multipliers for the non-linear inequality constraints.
//
//
// Examples
// function [y] = obj(x)
// y = (x-1)^2;
// endfunction
// function [c, ceq, K1, s] = seminfcon(x,s)
// // No finite nonlinear inequality and equality constraints
// c = [];
// ceq = [];
// // Sample set
// if isnan(s)
// // Initial sampling interval
// s = [0.01 0];
// end
// t = 0:s(1):1;
// // Evaluate the semi-infinite constraint
// K1 = (x - 0.5) - (t - 0.5).^2;
// endfunction
// x = fseminf(obj,0.2,1,seminfcon)
//
// Authors
// Salman Anis, Harpreet Singh
//To check the number of input and output arguments
[lhs , rhs] = argn();
//To check the number of arguments given by the user
if ( rhs<4 | rhs==5 | rhs==7 | rhs>13 ) then
errmsg = msprintf(gettext("%s: Unexpected number of input arguments : %d provided while it should be 4,6,8,10,11"), "fseminf", rhs);
error(errmsg)
end
//Storing the Input Parameters
_fun = varargin(1);
x0 = varargin(2);
ntheta = varargin(3);
seminfcon = varargin(4);
nbVar = size(x0,'*');
if(nbVar == 0) then
errmsg = msprintf(gettext("%s: Cannot determine the number of variables because input initial guess is empty"), "lsqcurvefit");
error(errmsg);
end
A = [];
b = [];
Aeq = [];
beq = [];
lb = [];
ub = [];
nlc = [];
param = list();
if (rhs>4) then
A = varargin(5);
b = varargin(6);
end
if (rhs>6) then
Aeq = varargin(7);
beq = varargin(8);
end
if (rhs>8) then
lb = varargin(9);
ub = varargin(10);
end
if (rhs>10) then
param = varargin(10);
end
if (size(lb,2)==0) then
lb = repmat(-%inf,nbVar,1);
end
if (size(ub,2)==0) then
ub = repmat(%inf,nbVar,1);
end
//Check type of variables
Checktype("fseminf", _fun, "fun", 1, "function")
Checktype("fseminf", x0, "x0", 2, "constant")
Checktype("fseminf", ntheta, "ntheta", 3, "constant")
Checktype("fseminf", seminfcon, "seminfcon", 4, ["function","constant"])
Checktype("fseminf", A, "A", 5, "constant")
Checktype("fseminf", b, "b", 6, "constant")
Checktype("fseminf", Aeq, "Aeq", 7, "constant")
Checktype("fseminf", beq, "beq", 8, "constant")
Checktype("fseminf", lb, "lb", 9, "constant")
Checktype("fseminf", ub, "ub", 10, "constant")
Checktype("fseminf", param, "param", 10, "list")
//To check the user entry for options and storing it
for i = 1:(size(param))/2
select convstr(param(2*i-1),'l')
case "maxiter" then
Checktype("fseminf", param(2*i), "maxiter", 10, "constant")
options(2) = param(2*i); //Setting the maximum number of iterations as per user entry
case "cputime" then
Checktype("fseminf", param(2*i), "cputime", 10, "constant")
options(4) = param(2*i); //Setting the maximum CPU time as per user entry
case "gradobj" then
Checktype("fseminf", param(2*i), "gradobj", 10, "string")
if(convstr(param(2*i),'l') == "on") then
function dy = graObj(x)
endfunction
end
else
errmsg = msprintf(gettext("%s: Unrecognized parameter name %s."), "fmincon", param(2*i-1));
error(errmsg);
end
end
//To check and convert the 2nd Input argument (x0) to a row vector
if((size(x0,1)~=1) & (size(x0,2)~=1)) then
errmsg = msprintf(gettext("%s: Expected Vector for initial guess"), "fseminf");
error(errmsg);
end
if(size(x0,2)==1) then
x0=x0(:);
end
//To check the match between fun (1st Parameter) and x0 (2nd Parameter)
if(execstr('init=_fun(x0)','errcatch')==21) then
errmsg = msprintf(gettext("%s: Objective function and x0 did not match"), "fseminf");
error(errmsg);
end
//Check the size of inequality constraint which should be equal to the number of variables
if ( size(A,2) ~= nbVar & size(A,2) ~= 0) then
errmsg = msprintf(gettext("%s: The number of columns in A must be the same as the number of elements of x0"), "fseminf");
error(errmsg);
end
nbConInEq = size(A,"r");
//Check the size of equality constraint which should be equal to the number of variables
if ( size(Aeq,2) ~= nbVar & size(Aeq,2) ~= 0 ) then
errmsg = msprintf(gettext("%s: The number of columns in Aeq must be the same as the number of elements of f"), "fseminf");
error(errmsg);
end
b = b(:);
beq = beq(:);
lb = lb(:);
ub = ub(:);
//To check the contents of lb & ub
for i = 1:nbVar
if(ub(i) 0 then
lamsg = lasterror();
lclmsg = "%s: Error while evaluating the function: ""%s""\n";
error(msprintf(gettext(lclmsg), "fseminf", lamsg));
end
S = %nan;
ierr = execstr('init=seminfcon(x0,S)', "errcatch")
if ierr <> 0 then
lamsg = lasterror();
lclmsg = "%s: Error while evaluating the function: ""%s""\n";
error(msprintf(gettext(lclmsg), "fseminf", lamsg));
end
function [c, ceq] = _seminfcon(x)
[c, ceq, K, S] = seminfcon(x,S)
K_max = max(K,"c");
c= [c;K_max];
ceq = ceq;
endfunction
//Calling the fmincon function for solving the above problem
[xopt,fopt,exitflag,output,lambda,gradient] = fmincon(_fun,x0,A,b,Aeq,beq,lb,ub,_seminfcon,param)
endfunction