classdef (CaseInsensitiveProperties, TruncatedProperties) AbstractEstimator< matlab.mixin.SetGet & matlab.mixin.Copyable
   %idestimatorpack.AbstractEstimator class.
   %    Properties:
   %       Model (read only)
   %       Data
   %       Info
   %       Options
   %
   %    Methods:
   %       getIterInfo -  Translate optimization info into a common format.
   %       initialize -  Initializes the properties of an estimator object or its
   %       setOptimizationOptions -  Translate optimization info into a common format.
   %       whyStop -  Describes in words the optimization termination status.
   %       getRegulInfo - IsRegul, R, Rs, xCenter (x0 in lambda*(x-x0)'*R*(x-x0) penalty)
   %       minimize - main method; determine x* that minimizes NLSQ cost;
   %                  the cost may contain an L2 penalty

   % Copyright 1986-2022 The MathWorks, Inc.

   properties (AbortSet, SetObservable, GetObservable)
      Data
      Info
      Options
      Center (:,1) double
   end

   properties (AbortSet, SetObservable, GetObservable)
      %MODEL Property is of type 'MATLAB array' (read only)
      Model      
   end

   methods (Abstract)
      setOptimizationOptions(varargin)
      OptimInfo = minimize(this)
   end

   methods (Static, Abstract)
      IterInfo = getIterInfo(varargin)
      str = whyStop(varargin)
   end

   methods
      function initialize(this, aModel, aData, options, varargin)
         %INITIALIZE Initializes the properties of an estimator object.
         this.Model = aModel;
         this.Data = aData; % iddata, structure or cell array

         % Set optimization options.
         this.setOptimizationOptions(options,varargin{:});
         this.Info = obj2var(aModel,this.Options); % Serialize parameter information.
      end
   end

   methods (Access = protected)
      function [IsRegul, R, Rs, xCenter] = getRegulInfo(this,x)
         % fetch information needed for L2 regularization.
         opt = this.Options;
         IsRegul = false;
         R = [];
         Rs = [];
         xCenter = [];
         if (isstruct(opt) && isfield(opt,'Regularization')) || ...
               (isobject(opt) && isprop(opt,'Regularization'))
            Regul = this.Options.Regularization;
            IsRegul = Regul.Lambda>0;
         end

         if IsRegul
            R = Regul.R;
            Rs = idoptions.RegularizedEstimation.getRChol(R, numel(x))*sqrt(Regul.Lambda);
            R = Rs'*Rs;
            xCenter = this.Center;
            if isempty(xCenter)
               if strncmpi(opt.Regularization.Nominal,'m',1)
                  xCenter = x;
               else
                  xCenter = zeros(size(x));
               end
            end
         end
      end
   end
end
