diff toolboxes/distance_learning/mlr/util/qplcprog.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolboxes/distance_learning/mlr/util/qplcprog.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,315 @@
+function [x, fval, status] = qplcprog(H, f, Ai, bi, Ae, be, lb, ub, varargin)
+%QPLCPROG Positive-semidefinite quadratic programming based on linear complementary programming.
+%
+%	x = qplcprog(H, f);
+%	[x, fval, status] = qplcprog(H, f, Ai, bi, Ae, be, lb, ub, varargin);
+%
+% Inputs:
+%	H - Hessian for objective function (n x n matrix)
+%
+% Optional Inputs:
+%	f - Vector for objective function, default is 0 (n x 1 vector)
+%	Ai - Linear inequality constraint matrix, default is [] (ni x n matrix)
+%	bi - Linear inequality constraint vector, default is [] (ni x 1 vector)
+%	Ae - Linear equality constraint matrix, default is [] (ne x n matrix)
+%	be - Linear equality constraint vector, default is [] (ne x 1 vector)
+%	lb - Lower-bound constraint, default is 0 (n x 1 vector)
+%	ub - Upper-bound constraint, default is [] (n x 1 vector)
+%
+%	maxiter - LCP maximum iterations, default is 100000
+%	tiebreak - Method to break ties for pivot selection (default is 'first'). Options are:
+%			'first'		Select pivot with lowest index.
+%			'last'		Select pivot with highest index.
+%			'random'	Select a pivot at random.
+%	tolpiv - LCP pivot selection tolerance, default is 1.0e-9
+%	tolcon - QP constraint tolerance, default is 1.0e-6
+%
+% Outputs:
+%	x - Solution vector (n x 1 vector)
+%	fval - Value of objective function at solution (scalar)
+%	status - Status of optimization with values (integer)
+%		 6		Ray termination
+%		 1		Convergence to a solution (normal termination)
+%		 0		Termination prior to convergence
+%		-2		Infeasible problem
+%		-3		Bad pivot to an infeasible solution
+%
+% Notes:
+%	Depending upon the inputs, various types of positive-semidefinite quadratic programs can be
+%	solved. The general problem is
+%
+%		min  0.5 * x' * H * x + f' * x
+%		 x
+%
+%	subject to any or all of the following constraints
+%
+%		Ai * x <= bi
+%		Ae * x = be
+%		lb <= x <= ub
+%
+%	with the current requirement that lb must be specified and finite.
+%
+%	It is assumed that H is positive-semidefinite. Note that if H = 0, qplcp solves a linear
+%	program.
+
+% Copyright 2008 The MathWorks, Inc.
+% $Revision: 1.1.6.3 $   $ Date: $
+
+if nargin < 1
+   error('Finance:qplcprog:MissingInputArgument', ...
+      'Missing required Hessian matrix for QP.');
+end
+H = full(H);
+n = size(H,1);
+
+if nargin < 2 || isempty(f)
+   f = zeros(n,1);
+else
+   f = full(f);
+   f = f(:);
+end
+
+if nargin == 3
+   error('Finance:qplcprog:IncompleteConstraintSpecification', ...
+      'Incomplete specification for linear inequality constraints.');
+end
+if nargin < 3
+   Ai = [];
+   bi = [];
+else
+   Ai = full(Ai);
+   bi = full(bi);
+   bi = bi(:);
+end
+
+if nargin == 5
+   error('Finance:qplcprog:IncompleteConstraintSpecification', ...
+      'Incomplete specification for linear equality constraints.');
+end
+if nargin < 5
+   Ae = [];
+   be = [];
+else
+   Ae = full(Ae);
+   be = full(be);
+   be = be(:);
+end
+
+if nargin < 7 || isempty(lb)
+   error('Finance:qplcprog:MissingBoundConstraint', ...
+      'Lower-bound constraint required.');
+else
+   lb = full(lb);
+   lb = lb(:);
+   if any(~isfinite(lb))
+      error('Finance:qplcprog:MissingBoundConstraint', ...
+         'Finite lower-bound constraint required.');
+   end
+end
+
+if nargin < 8
+   ub = [];
+else
+   ub = full(ub);
+   ub = ub(:);
+   if all(ub == Inf)
+      ub = [];
+   end
+end
+if any(~isfinite(ub))
+   error('Finance:qplcprog:InvalidBoundConstraint', ...
+      'If specified, finite upper-bound constraint required.');
+end
+
+% process name-value pairs (if any)
+
+if nargin > 8
+   if mod(nargin-8,2) ~= 0
+      error('Finance:qplcprog:InvalidNameValuePair', ...
+         'Invalid name-value pairs with either a missing name or value.');
+   end
+
+   names = { 'maxiter', 'tiebreak', 'tolcon', 'tolpiv' };			% names
+   values = { 10000, 'first', 1.0e-4, 1.0e-9 };					% default values
+   try
+      [maxiter, tiebreak, tolcon, tolpiv] = parsepvpairs(names, values, varargin{:});
+
+   catch E
+      E.throw
+   end
+else
+   maxiter = 100000;
+   tiebreak = 'first';
+   tolpiv = 1.0e-9;
+   tolcon = 1.0e-6;
+end
+
+% check arguments
+
+if maxiter <= 0
+   error('Finance:qplcprog:NonPositiveInteger', ...
+      'Maximum number of iterations (maxiter) must be a positive integer.');
+end
+
+if tolcon < 2*eps
+   error('Finance:qplcprog:InvalidTolerance', ...
+      'Unrealistically small constraint tolerance (tolcon) specified.');
+end
+
+if tolpiv < 2*eps
+   error('Finance:qplcprog:InvalidTolerance', ...
+      'Unrealistically small pivot tolerance (tolpiv) specified.');
+end
+
+% set translation if necessary
+
+if norm(lb) ~= 0
+   fx = f + H*lb;
+   if ~isempty(Ai) && ~isempty(bi)
+      bxi = bi - Ai*lb;
+   end
+   if ~isempty(Ae) && ~isempty(be)
+      bxe = be - Ae*lb;
+   end
+   if ~isempty(ub)
+      uxb = ub - lb;
+   end
+   translate = true;
+else
+   fx = f;
+   if ~isempty(Ai) && ~isempty(bi)
+      bxi = bi;
+   end
+   if ~isempty(Ae) && ~isempty(be)
+      bxe = be;
+   end
+   if ~isempty(ub)
+      uxb = ub;
+   end
+   translate = false;
+end
+
+% set up constraints
+
+if ~isempty(Ai) && ~isempty(bi)
+   if ~isempty(Ae) && ~isempty(be)
+      if ~isempty(ub)
+         A = [ Ai; Ae; -Ae; eye(n,n) ];
+         b = [ bxi; bxe; -bxe; uxb ];
+      else
+         A = [ Ai; Ae; -Ae ];
+         b = [ bxi; bxe; -bxe ];
+      end
+   else
+      if ~isempty(ub)
+         A = [ Ai; eye(n,n) ];
+         b = [ bxi; uxb ];
+      else
+         A = Ai;
+         b = bxi;
+      end
+   end
+else
+   if ~isempty(Ae) && ~isempty(be)
+      if ~isempty(ub)
+         A = [ Ae; -Ae; eye(n,n) ];
+         b = [ bxe; -bxe; uxb ];
+      else
+         A = [ Ae; -Ae ];
+         b = [ bxe; -bxe ];
+      end
+   else
+      if ~isempty(ub)
+         A = eye(n,n);
+         b = uxb;
+      else
+         error('Finance:qplcprog:InvalidConstraints', ...
+            'Insufficient or invalid constraints.');
+      end
+   end
+end
+
+% set up lcp problem
+
+ns = size(A,1);
+
+M = [ zeros(ns,ns) -A; A' H ];
+q = [ b; fx ];
+
+% solve lcp problem
+
+if isempty(varargin)
+   [z, w, status] = lcprog(M, q); %#ok
+else
+   [z, w, status] = lcprog(M, q, 'maxiter', maxiter, 'tiebreak', tiebreak, 'tolpiv', tolpiv); %#ok
+end
+
+% solve qp problem
+
+if status > 0
+   x = z(end-n+1:end);
+   if translate
+      x = x + lb;
+   end
+   fval = 0.5*x'*H*x + f'*x;
+
+   if qplcprogrealitycheck(Ai, bi, Ae, be, lb, ub, x)
+      status = -2;
+      x = NaN(n,1);
+      fval = NaN;
+   end
+else
+   x = NaN(n,1);
+   fval = NaN;
+end
+
+function notok = qplcprogrealitycheck(Ai, bi, Ae, be, lb, ub, x, tolcon)
+%QPLCPROGREALITYCHECK - Make sure candidate solution x is feasible.
+
+if nargin < 7
+   error('Finance:qplcprog:MissingInputArgument', ...
+      'Missing required input arguments Ai, bi, Ae, be, lb, ub, x.');
+end
+if nargin < 8 || isempty(tolcon)
+   tolcon = 1.0e-6;
+end
+
+notok = false;
+
+if ~isempty(Ai)
+   u = max(Ai*x - bi,0);
+   if u > tolcon
+      warning('Finance:qplcprog:InfeasibleProblem', ...
+         'Candidate solution violates inequality constraints.');
+      notok = true;
+   end
+end
+
+if ~isempty(Ae)
+   if norm(be - Ae*x,inf) > tolcon
+      warning('Finance:qplcprog:InfeasibleProblem', ...
+         'Candidate solution violates equality constraints.');
+      notok = true;
+   end
+end
+
+if ~isempty(lb)
+   u = x - lb;
+   if min(u) < -tolcon
+      warning('Finance:qplcprog:InfeasibleProblem', ...
+         'Candidate solution violates lower-bound constraints.');
+      notok = true;
+   end
+end
+
+if ~isempty(ub)
+   u = ub - x;
+   if min(u) < -tolcon
+      warning('Finance:qplcprog:InfeasibleProblem', ...
+         'Candidate solution violates upper-bound constraints.');
+      notok = true;
+   end
+end
+
+
+% [EOF]