classdef (Sealed) LsqlinWarmStart < optim.warmstart.base.QPActiveSetWarmStart
%LSQLINWARMSTART Warm start object to accelerate the LSQLIN solver.
%   A LSQLINWARMSTART object can reduce the total time to solve
%   sequence of linear least squares programming problems of the form:
%
%           min  0.5*NORM(C*x-d)^2     subject to
%            x                            A*x <= b 
%                                         Aeq*x = beq
%                                         lb <= x <= ub
% 
%   when the objective or constraints change slightly between
%   consecutive solves.
% 
%   WS = OPTIMWARMSTART(X0,OPTIONS) creates a warm start object for the
%   LSQLIN algorithm specified in OPTIONS.  X0 is an initial point to begin
%   the warm start process.  OPTIONS is a linear least squares options
%   object created with OPTIMOPTIONS.
% 
%   WS = OPTIMWARMSTART(X0,OPTIONS,PROP,VAL,...) specifies a set of
%   property-value pairs that are applied to the warm start object before
%   creation.  For code generation, set the 'MaxLinearEqualities' and
%   'MaxLinearInequalities' properties.
%   
%   LsqlinWarmStart properties:
%     Read-only:
%      X                      - Initial point for the linear
%                               least squares programming problem.
%      Options                - Algorithm-specific options for the LSQLIN
%                               solver. 
%      MaxLinearEqualities    - Upper bound on the number of linear
%                               equality constraints over all linear least
%                               squares programming problems solved using
%                               warm start. Applies to code generation.
%      MaxLinearInequalities  - Upper bound on the number of linear
%                               inequality constraints over all linear
%                               least squares programming problems solved
%                               using warm start. Applies to code generation.
%
%   Example:
% 
%   Create a constrained linear least squares problem:
%      t = linspace(0,1,11); % time samples
%      C = t(:).^(3:-1:0); % prepare cubic fit on [0, 1]
%      d = sin(pi/2*t); % initial data to fit to
%      ub = ones(4,1); % saturate coefficients if they exceed [-1, 1]
%      lb = -ones(4,1);
% 
%   Create a warm start object using OPTIMWARMSTART:
%      options = optimoptions('lsqlin','Algorithm','active-set');
%      x0 = zeros(4,1); % feasible starting point
%      ws = optimwarmstart(x0,options);
%   
%   Solve the problem using the warm start syntax with LSQLIN:
%      [ws,fval,exitflag,output,lambda] = lsqlin(C,d,[],[],[],[],lb,ub,ws);
%   
%   Shift input data forward in time and solve again:
%      d = sin(pi/2*(t+0.1)); % shift input data in time
%      C = (t(:) + 0.1).^(3:-1:0); % shift cubic basis in time
%      [ws,fval,exitflag,output,lambda] = lsqlin(C,d,[],[],[],[],lb,ub,ws);
%
%   See also OPTIMWARMSTART, LSQLIN, OPTIMOPTIONS
        
%   Copyright 2020 The MathWorks, Inc.
    
    properties (Constant, Access = protected)
        SolverName = "lsqlin";
    end
        
    methods
        function obj = LsqlinWarmStart(x0, options, CoderOpts)
            
            % Arguments block is faster for validating arguments than an 
            % input parser.  We cannot do argument validation with varargin
            % on base classes.
            arguments
                x0 double {mustBeReal, mustBeNonempty}
                options {optim.warmstart.validate.optionsValidate(options, 'lsqlin', 'active-set')}
                CoderOpts.MaxLinearEqualities {optim.warmstart.validate.maxLinearValidate(CoderOpts.MaxLinearEqualities, 'MaxLinearEqualities')} = Inf
                CoderOpts.MaxLinearInequalities {optim.warmstart.validate.maxLinearValidate(CoderOpts.MaxLinearInequalities, 'MaxLinearInequalities')} = Inf
            end
            
            % Call the base class constructor.
            obj = obj@optim.warmstart.base.QPActiveSetWarmStart(x0, options, ...
                CoderOpts.MaxLinearEqualities, CoderOpts.MaxLinearInequalities);
            
            obj.Version = 1;
            obj = setConvex(obj);
        end
    end
    
end

