classdef incrementalRegressionLinear <  incremental.regr.RegressionModel
    %incrementalRegressionLinear Regression linear model for incremental learning. 
    %   This model can train with and predict responses for new data.
    %
    %   incrementalRegressionLinear properties:
    %       Epsilon                  - Half of the width of the epsilon-insensitive band for SVM.
    %       ResponseTransform        - Transformation applied to predicted response values.
    %       NumPredictors            - Number of predictors.
    %       NumTrainingObservations  - Number of observations used for training the incremental model.
    %       MetricsWarmupPeriod      - Number of observations that are used for training
    %                                  prior to metrics tracking.
    %       MetricsWindowSize        - Window size for window metrics tracking.
    %       IsWarm                   - Flag to indicate if incremental model is warm.
    %       Metrics                  - Metrics information.
    %       Learner                  - Learned model, 'svm' or 'leastsquares'.
    %       Solver                   - Solver used for training, 'sgd', 'asgd' or 'scale-invariant'.
    %       BatchSize                - Mini-batch size of training data for stochastic solvers.
    %       Beta                     - Linear coefficients.
    %       Bias                     - Bias term.
    %       FitBias                  - Linear model intercept inclusion flag.
    %       FittedLoss               - Fitted loss function, 'epsiloninsensitive' or 'mse'.
    %       Lambda                   - Ridge regularization strength.
    %       LearnRate                - Learning rate for stochastic solvers.
    %       LearnRateSchedule        - Schedule for learning rate for stochastic solvers.
    %       Mu                       - Predictor means.
    %       Sigma                    - Predictor standard deviations.
    %       SolverOptions            - Linear solver options.
    %       EstimationPeriod         - Number of observations that are used for
    %                                  parameter estimation prior to training.
    %
    %   incrementalRegressionLinear methods:
    %       incrementalRegressionLinear       - Construct incremental
    %                                           regression linear model.
    %       fit                               - Train model with new data.     
    %       loss                              - Regression loss.
    %       perObservationLoss                - Per observation regression loss.
    %       predict                           - Predict responses of the model.
    %       reset                             - Reset model.
    %       updateMetrics                     - Update metrics with new data.
    %       updateMetricsAndFit               - Update metrics and train model with new data.
    %
    %
    %   Example 1: Initialize and train an incremental linear model without providing any
    %   information.
    %
    %       mdl  = incrementalRegressionLinear();
    %       mdl  = updateMetricsAndFit(mdl,X,Y);
    %
    %   Example 2: Initialize an incremental linear model using a traditionally trained model
    %   and continue incremental training.
    %
    %       ttModel = fitrlinear(Xoffline,Yoffline,'ObservationsIn','columns');
    %       mdl = incrementalLearner(ttModel);
    %       mdl = updateMetrics(mdl,Xnew,Ynew,'Weights',Wnew,'ObservationsIn','columns');
    %       mdl = fit(mdl,Xnew,Ynew,'Weights',Wnew,'ObservationsIn','columns');
    %
    %   See also RegressionLinear.incrementalLearner, classreg.learning.regr.CompactRegressionSVM.incrementalLearner.

    %   Copyright 2020-2023 The MathWorks, Inc.

    properties (SetAccess = protected, Dependent)
        %Epsilon Half of the width of the epsilon-insensitive band for SVM.
        %   The Epsilon property is a scalar specifying half the width of
        %   the epsilon-insensitive band for SVM. If the Learner property
        %   is not 'svm', this property is empty.
        %
        %   See also incrementalRegressionLinear, RegressionLinear.
        Epsilon
    end
    properties (Access = private)
        pModelSpecificMetrics
        pEpsilonMetricAdjusted = false
    end
    properties (Constant,Access  =protected)
        CanSupportCategorical = false
        Mode(1,1) = 0
    end

    properties (SetAccess = protected,Hidden)
        Impl = [];
    end
    
    properties (Access = private, Dependent)
        parametersAdjusted
    end

    properties(Dependent, SetAccess = protected)    
        %LEARNER Linear model type
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear.         
        Learner
        
        %SOLVER Linear solver type
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear.         
        Solver
    end
    
    properties(Dependent, SetAccess = protected)
        %BATCHSIZE Mini-batch size.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear,  Solver. 
        BatchSize  
        
        %BETA Linear coefficients.
        %   The Beta property is a vector of linear coefficients with P elements
        %   for P predictors. Scores F obtained by this model for predictor matrix
        %   X can be computed using
        %  
        %   F = (Beta'*X)' + Bias
        %  
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Bias.        
        Beta
        
        %BIAS Bias term.
        %   The Bias property is a scalar specifying the bias term in the SVM
        %   model. The PREDICT method computes scores F for predictor matrix X
        %   using
        %
        %   F = (Beta'*X)' + Bias
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Beta.        
        Bias

        %FITBIAS Linear model intercept inclusion flag.
        %   The FitBias property is a logical scalar specifying whether bias
        %   term will be included during training of the linear model. If
        %   false, bias will stay at 0.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Bias.    
        FitBias
        
        %FITTEDLOSS Fitted loss function.
        %   The FittedLoss property is a string specifying the fitted loss
        %   function.
        %  
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Learner.
        FittedLoss    
        
        %LAMBDA Ridge regularization strength.
        %   The Lambda property is a vector of values used to regularize the
        %   objective function.
        %  
        %   See also incrementalClassificationLinear, incrementalRegressionLinear,  Bias.        
        Lambda
        
        %LEARNRATE Learning rate for stochastic solvers.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear,  Solver.         
        LearnRate
        
        %LEARNRATESCHEDULE Schedule for learning rate for stochastic solvers.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear,  LearnRate, Solver.         
        LearnRateSchedule

        %MU Predictor means.
        %   The Mu property is either empty or a vector with P elements, one for
        %   each predictor. If training were done with standarization, the Mu property is
        %   filled with means of predictors used for training. Otherwise the Mu
        %   property is empty. If the Mu property is not empty, the predict method
        %   centers predictor matrix X by subtracting the respective element of Mu
        %   from every column.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, EstimationPeriod, predict.        
        Mu
        
        %SIGMA Predictor standard deviations.
        %   The Sigma property is either empty or a vector with P elements, one for
        %   each predictor. If training were done with standarization, the Sigma property
        %   is filled with standard deviations of predictors used for training.
        %   Otherwise the Sigma property is empty. If the Sigma property is not
        %   empty, the predict method scales predictor matrix X by dividing every
        %   column by the respective element of Sigma (after centering).
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, EstimationPeriod, predict.          
        Sigma
    end
    
    properties (SetAccess = protected, Dependent)
       %SOLVEROPTIONS Linear Solver Options.
       %
       %   See also incrementalClassificationLinear, incrementalRegressionLinear, Solver. 
       SolverOptions 
    end


    properties (SetAccess = protected, Dependent)
       %ESTIMATIONPERIOD Number of observations that are used for
       %    parameter estimation prior to training.
       %    ESTIMATIONPERIOD is a nonnegative integer specifying the number of
       %    observations that are used for parameter estimation prior to 
       %    incremental training.        
       EstimationPeriod
    end    
    
    methods
        function this = incrementalRegressionLinear(varargin)
            %INCREMENTALREGRESSIONLINEAR Construct an incremental regression linear model.
            %
            %   MODEL=INCREMENTALREGRESSIONLINEAR() returns an incremental regression linear model
            %   with default model parameters.
            %   Default model is created with placeholders for unknown parameters.
            %
            %   MODEL=incrementalLearner(TTMODEL) returns an incremental regression
            %   linear model initialized using the parameters provided in
            %   TTMODEL, a traditionally trained model. 
            %   For details on how incrementalLearner is used for initialization of an incremental
            %   regression model, see the incrementalLearner reference for supported models.
            %
            %   MODEL=INCREMENTALREGRESSIONLINEAR('PARAM1',val1,'PARAM2',val2,...) specifies optional
            %   parameter name/value pairs:
            %       'BatchSize'               - Mini-batch size for the stochastic
            %                                   solvers, specified as a positive
            %                                   scalar. If MODEL is initialized
            %                                   from TTMODEL using a stochastic gradient descent (SGD) or
            %                                   average stochastic gradient descent (ASGD) solver,
            %                                   TTMODEL.BatchSize is used. Otherwise,
            %                                   default is 10 for stochastic solvers.
            %       'Beta'                    - Coefficients of the linear model specified
            %                                   as a D-by-1 vector, where D is the number of predictors.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.Beta is used. Otherwise, default
            %                                   is zeros(NumPredictors,1) where
            %                                   'NumPredictors' is inferred from data when fit is called.
            %       'Bias'                    - Bias term for the linear model
            %                                   specified as a scalar. If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.Bias is used. Default: 0.
            %       'Epsilon'                 - Either 'auto' or non-negative scalar specifying
            %                                   half the width of the epsilon-insensitive band.
            %                                   If MODEL is initialized from TTMODEL
            %                                   with 'Learner' set to 'svm',
            %                                   TTMODEL.Epsilon is used. Otherwise, if 'auto',
            %                                   'Epsilon' is estimated during 'EstimationPeriod'.
            %                                   Formula for 'Epsilon' is iqr(Y)/13.49 and 0.1 if iqr(Y)
            %                                   equals 0.
            %                                   'Epsilon' is not supported if 'Learner'
            %                                   is 'leastsquares'.
            %                                   Default: 'auto'.
            %                                   Refer to documentation for info
            %                                   on 'auto' behavior.
            %       'EstimationPeriod'        - Nonnegative integer specifying the number of
            %                                   observations that are used for
            %                                   estimation of hyperparameters prior to
            %                                   training. For a positive integer, if
            %                                   model has unknown hyperparameters
            %                                   that require estimation,
            %                                   hyperparameters are estimated.
            %                                   Default value is 1000 when estimation is needed.
            %                                   Otherwise, default value is 0.
            %                                   Refer to documentation for more information.
            %       'FitBias'                 - Logical flag specifying whether
            %                                   intercept term should be included in
            %                                   the model. If 'FitBias' is false and 'Bias' is 0,
            %                                   then 'Bias' stays as 0. Otherwise, if 'Bias'
            %                                   is specified as a non-zero value, 'FitBias' must be true.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.ModelParameters.FitBias is used
            %                                   if available.
            %                                   Default: true.
            %       'Lambda'                  - Ridge (L2) regularization strength specified as a
            %                                   nonnegative scalar.
            %                                   If MODEL is initialized from TTMODEL using ridge
            %                                   regularization, TTMODEL.Lambda is used.
            %                                   'Lambda' is not supported for scale-invariant solver.
            %                                   Default: 1e-5.
            %       'Learner'                 - String specifying learner type. Specify as one
            %                                   of:
            %                                      - 'svm'
            %                                      - 'leastsquares'
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.Learner is used.
            %                                   Default: 'svm'.
            %       'LearnRate'               - Learning Rate for (SGD) and (ASGD) solvers,
            %                                   specified as either 'auto' or a
            %                                   positive scalar.
            %                                   If MODEL is initialized from TTMODEL using
            %                                   a stochastic gradient descent (SGD) or
            %                                   average stochastic gradient descent (ASGD) solver,
            %                                   TTMODEL.LearnRate is used. Otherwise,
            %                                   for stochastic solvers, if 'auto',
            %                                   value is estimated until the number of observations
            %                                   reach 'EstimationPeriod'. Formula for
            %                                   'LearnRate' is 1/sqrt(1+max((sum(X.^2,obsDim)))),
            %                                   where obsDim is 1 if the observations compose
            %                                   the columns of the predictor data X, and 2 otherwise.
            %                                   'LearnRate' is not supported for scale-invariant solver.
            %                                   Default: 'auto'.
            %                                   Refer to documentation for info on 'auto' behavior.
            %       'LearnRateSchedule'       - String, one of 'decaying' or 'constant'.
            %                                   For stochastic solvers, if 'decaying',
            %                                   learning rate decreases over
            %                                   iterations. If 'constant', learning
            %                                   rate stays constant. If MODEL is initialized
            %                                   from TTMODEL using a stochastic gradient descent (SGD)
            %                                   or average stochastic gradient descent (ASGD) solver,
            %                                   'LearnRateSchedule' is 'decaying'.
            %                                   Default: 'decaying' for stochastic solvers.
            %                                   'LearnRateSchedule' is not supported
            %                                   for scale-invariant solver.
            %       'Metrics'                 - String vector representing built-in
            %                                   metrics, cell array of function handles
            %                                   or a struct of function handles specifying
            %                                   metrics that are tracked during incremental
            %                                   training. 'Metrics' can be a
            %                                   combination of strings, function
            %                                   handles or struct of function handles
            %                                   passed as a cell array.
            %                                   Built-in metrics for regression:
            %                                       - 'epsiloninsensitive'
            %                                       - 'mse'
            %                                   'epsiloninsensitive' can be selected
            %                                   only if 'Solver' is 'svm'.
            %                                   If you pass a function handle FUN, it
            %                                   is called as shown below:
            %                                       FUN(Y,Yfit)
            %                                   where Y and Yfit are numeric vectors of
            %                                   length N. Y is observed response, Yfit is
            %                                   predicted response.
            %                                   Metric name is extracted from provided function
            %                                   handle if it's not an anonymous
            %                                   function handle. If it is an anonymous
            %                                   function handle, metric is named
            %                                   as 'CustomMetric' and it is postfixed
            %                                   with an underscore and an integer
            %                                   identifying its relative position in
            %                                   'Metrics' property.
            %                                   If you pass a struct, fieldnames are
            %                                   treated as the metric names and
            %                                   values must be function handles.
            %                                   Incremental models track two values for
            %                                   each metric; a 'Cumulative' value and a
            %                                   'Window' value. 'MetricsWindowSize' determines
            %                                   the update frequency of 'Window' metrics.
            %                                   Default is 'mse' if 'Learner' is
            %                                   'leastsquares'. Else,default is
            %                                   'epsiloninsensitive'.
            %       'MetricsWarmupPeriod'     - Nonnegative integer specifying the number of
            %                                   observations that are used for
            %                                   training the model prior to metrics
            %                                   update. If MODEL is initialized
            %                                   from TTMODEL, default is 0; otherwise, it is 1000.
            %       'MetricsWindowSize'       - Positive integer specifying the window
            %                                   size that is used for metrics
            %                                   update. Default value is 200.
            %       'NumPredictors'           - Positive scalar specifying the number of
            %                                   predictors.  If MODEL is initialized
            %                                   from TTMODEL, number of predictors from TTMODEL is used.
            %                                   Default: 'NumPredictors' is inferred from data when fit is called.
            %       'ResponseTransform'        - Response transformation function, specified as
            %                                   a function handle or 'none'.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.ResponseTransform is used.
            %                                   Default: 'none'.
            %       'Shuffle'                 - Logical value specifying whether
            %                                   observations are shuffled at each step.
            %                                   Default: true for scale-invariant
            %                                   solver.
            %                                   'Shuffle' is not supported for
            %                                   stochastic solvers. Observations are
            %                                   always shuffled for stochastic
            %                                   solvers.
            %       'Solver'                  - String, one of 'sgd', 'asgd' or 'scale-invariant'.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   corresponding solver is used.
            %                                   If 'sgd', (SGD) solver is used. If
            %                                   'asgd', (ASGD) solver is
            %                                   user. If 'scale-invariant', adaptive
            %                                   scale-invariant solver is used.
            %                                   Default: 'scale-invariant'.
            %       'Standardize'             - Either 'auto' or logical scalar. If true,
            %                                   standardize training data by centering
            %                                   and dividing columns by their standard deviations.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.Mu and TTMODEL.Sigma are used.
            %                                   Otherwise, if 'auto', Mu and Sigma are estimated
            %                                   during 'EstimationPeriod'.
            %                                   Default: 'auto'.
            %                                   Refer to documentation for info
            %                                   on 'auto' behavior.
            %
            %   See also incrementalLearner.
            this = this@incremental.regr.RegressionModel(varargin{:});
        end


        function yfit = predict(this,X,varargin)
            %PREDICT Predict responses of the model.
            %   YFIT=PREDICT(MODEL,X) returns predicted responses for model
            %   MODEL and predictors X. Pass X as a matrix with N observations
            %   from P predictors. YFIT is a vector with N elements, where N is
            %   the number of rows in X.
            %
            %   YFIT=PREDICT(MODEL,X,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %
            %   See also incrementalRegressionLinear, fit.
            yfit = predict@incremental.regr.RegressionModel(this,X,varargin{:});
        end

        function this = fit(this,X,Y,varargin)
            %FIT Train incremental model with new data.
            %   MODEL=FIT(MODEL,X,Y) returns the modified MODEL
            %   trained incrementally with new data X and response Y.
            %   MODEL.Metrics are not updated inside fit.
            %   Pass X as a matrix with N observations from P predictors.
            %   Pass Y as a floating-point vector with N elements.
            %
            %   MODEL=FIT(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %       'Weights'          - Vector of observation weights. By default, the
            %                            weight of every observation is set to 1. The
            %                            length of this vector must be equal to the
            %                            number of observations in X.
            %
            %   See also incrementalRegressionLinear, updateMetricsAndFit, updateMetrics.
            this = fit@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

        function l = loss(this,X,Y,varargin)
            %LOSS Regression error.
            %   ERR=LOSS(MODEL,X,Y) returns mean squared error for MODEL computed using
            %   predictors X and observed response Y. Pass X as a matrix with N observations
            %   from P predictors. Pass Y as a floating-point vector with N elements.
            %   ERR is a scalar.
            %
            %   ERR=LOSS(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %       'LossFun'          - Function handle for loss, or string
            %                            representing a built-in loss function.
            %                            Available loss functions for regression: 'mse'
            %                            and 'epsiloninsensitive'. If you pass a
            %                            function handle FUN, it is called
            %                            as shown below:
            %                               FUN(Y,Yfit,W)
            %                            where Y, Yfit and W are numeric vectors of
            %                            length N. Y is observed response, Yfit is
            %                            predicted response, and W is observation
            %                            weights. Default: 'mse'.
            %       'Weights'          - Vector of observation weights. By default, the
            %                            weight of every observation is set to 1. The
            %                            length of this vector must be equal to the
            %                            number of observations in X.
            %
            %   See also incrementalRegressionLinear, updateMetrics, updateMetricsAndFit, fit,
            %   predict, perObservationLoss.
            l = loss@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

        function l = perObservationLoss(this,X,Y,varargin)
            %PEROBSERVATIONLOSS Model per observation regression error.
            %   ERR=PEROBSERVATIONLOSS(MODEL,X,Y) returns per observation
            %   squared error for model MODEL computed using predictors X and
            %   observed response Y. Pass X as a matrix with N observations from P predictors. 
            %   Pass Y as a floating-point vector with N elements. ERR is a N-by-1 vector.
            %
            %   ERR=PEROBSERVATIONLOSS(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies optional
            %   parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %       'LossFun'          - Function handle for loss, or string
            %                            representing a built-in loss function.
            %                            Available loss functions for regression: 'squarederror'
            %                            and 'epsiloninsensitive'. If you pass a
            %                            function handle FUN, it is called
            %                            as shown below:
            %                               FUN(Y,Yfit)
            %                            where Y, Yfit are numeric vectors of
            %                            length N. Y is observed response and 
            %                            Yfit is predicted response. 
            %                            Default: 'squarederror'.
            %
            %   See also incrementalRegressionLinear, updateMetrics, updateMetricsAndFit, fit,
            %   predict, loss.
            l = perObservationLoss@incremental.SimpleLearner(this,X,Y,varargin{:});
        end          

        function  this = updateMetrics(this,X,Y,varargin)
            %UPDATEMETRICS Update metrics with new data.
            %   MODEL=UPDATEMETRICS(MODEL,X,Y) returns the modified MODEL
            %   for which the metrics, specified by 'Metrics' Name-Value pair
            %   of incrementalRegressionLinear, are updated with new data
            %   X and observed response Y. Pass X as a matrix with N observations from
            %   P predictors. Pass Y as a floating-point vector with N elements.
            %
            %   UPDATEMETRICS updates metrics with new data only if
            %   'IsWarm' is true. Otherwise, it assigns NaN values.
            %
            %   MODEL=UPDATEMETRICS(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %       'Weights'          - Vector of observation weights. By default, the
            %                            weight of every observation is set to 1. The
            %                            length of this vector must be equal to the
            %                            number of observations in X.
            %
            %   See also incrementalRegressionLinear, updateMetricsAndFit, fit, loss, predict.
            this = updateMetrics@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

        function  this = updateMetricsAndFit(this,X,Y,varargin)
            %UPDATEMETRICSANDFIT Update metrics and train model with new data.
            %   MODEL=UPDATEMETRICSANDFIT(MODEL,X,Y) returns the MODEL
            %   with the following modifications:
            %           1. Metrics, specified by 'Metrics' Name-Value pair
            %              of IncrementalRegressionLinear, are updated.
            %           2. Model trained incrementally with new data X and observed response Y.
            %   Pass X as a matrix with N observations from P predictors. 
            %   Pass Y as a floating-point vector with N elements.
            %
            %   UPDATEMETRICSANDFIT updates metrics with new data only if
            %   'IsWarm' is true. Otherwise, it assigns NaN values.
            %
            %   MODEL=UPDATEMETRICSANDFIT(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       'ObservationsIn'   - Orientation of X, specified as either 'rows' or
            %                            'columns'. Default: 'rows'.
            %       'Weights'          - Vector of observation weights. By default, the
            %                            weight of every observation is set to 1. The
            %                            length of this vector must be equal to the
            %                            number of observations in X.
            %
            %   See also incrementalRegressionLinear, updateMetrics, fit, loss, predict.
            this = updateMetricsAndFit@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

        function epsilon = get.Epsilon(this)
            epsilon = this.Impl.Epsilon;
        end

        function parametersadjusted = get.parametersAdjusted(this)
            parametersadjusted = this.Impl.parametersAdjusted;
        end

        function learner = get.Learner(this)
            learner = this.Impl.Learner;
        end

        function estimationperiod = get.EstimationPeriod(this)
            estimationperiod = this.Impl.EstimationPeriod;
        end

        function learner = get.LearnRateSchedule(this)
            learner = this.Impl.LearnRateSchedule;
        end
        
        function solver = get.Solver(this)
            solver = this.Impl.Solver;
        end
        
        function beta = get.Beta(this)
           beta = this.Impl.Beta; 
        end
        
        function bias = get.Bias(this)
           bias = this.Impl.Bias; 
        end

        function fitbias = get.FitBias(this)
           fitbias = this.Impl.FitBias; 
        end        
        
        function lr = get.LearnRate(this)
           lr = this.Impl.LearnRate; 
        end
        
        function lambda = get.Lambda(this)
            lambda = this.Impl.Lambda;
        end
        
        function batchsize = get.BatchSize(this)
            batchsize = this.Impl.BatchSize; 
        end
        
        function mu = get.Mu(this)
           mu = this.Impl.Mu; 
        end
        
        function sigma = get.Sigma(this)
           sigma = this.Impl.Sigma; 
        end
        
        function loss = get.FittedLoss(this)
            loss = this.Impl.LossFunction;
        end
        function solveroptions = get.SolverOptions(this)
           solveroptions = this.Impl.SolverOptions; 
        end
    end     


    methods(Access = protected)

        function this = configureLearner(this,varargin)
            % configure learner for training and prediction
            [this,args,parametersAreFromOffline] = configureForTrainingAndPrediction(this,varargin{:});

            % configure estimation parameters
            [this,args] = configureForEstimation(this,parametersAreFromOffline,this.NumPredictors,this.PredictorClass,args);   

            % configure metrics parameters
            this = configureForMetrics(this,parametersAreFromOffline,args);  
        end         

        function [this,X,Y,W] = prepareDataAndUpdateEstimationState(this,X,Y,W,obsInRows,numObservations)
            [this.Impl,X,Y,W] = prepareDataAndUpdateEstimationState(this.Impl,X,Y,W,obsInRows,numObservations);
        end  

        function [this,X,Yraw,Wraw] = prepareForFit(this,X,Yraw,Wraw,obsInRows)
            
            % allocate estimation buffers if needed
            this = allocateEstimationBuffers(this,this.NumPredictors,this.PredictorClass);

            % prepare data for training and update internal states
            [this,X,Yraw,Wraw] = prepareRawDataAndUpdateState(this,X,Yraw,Wraw,obsInRows);

            % prepare data for estimation and update internal estimation
            % states
            [this,X,Yraw,Wraw] = prepareDataAndUpdateEstimationState(this,X,Yraw,Wraw,obsInRows,this.NumTrainingObservations);
        end         

        function [this,remainingArgs] = configureForEstimation(this,parametersAreFromOffline,numPredictors,predictorClass,args)
                [this.Impl,remainingArgs] = configureForEstimation(this.Impl,parametersAreFromOffline,numPredictors,predictorClass,args);
        end

        function this = allocateEstimationBuffers(this,numPredictors,predictorClass,varargin)
            this.Impl = allocateEstimationBuffers(this.Impl,numPredictors,predictorClass,varargin{:});
        end         

        function this = adjustMetricIfNeeded(this)
            if ~this.pEpsilonMetricAdjusted && this.parametersAdjusted
                for ii = 1:numel(this.MetricsFun)
                    ff = functions(this.MetricsFun{ii});
                    if isequal(ff.function,'@(Y,Yfit)classreg.learning.loss.unnormalized.epsiloninsensitive(Y,Yfit,this.Epsilon)')
                        this.MetricsFun{ii} =  @(Y,Yfit)classreg.learning.loss.unnormalized.epsiloninsensitive(Y,Yfit,this.Epsilon);
                        break;
                    end
                end
                this.pEpsilonMetricAdjusted = true;
            end
        end

        function [numPredictors,predictorClass] = predictorAttributes(this)
                [numPredictors,predictorClass] = predictorAttributes(this.Impl);
        end
        
        function statesdefined = statesDefined(this)
            statesdefined = statesDefined(this.Impl);
        end        

        function f = response(this,X,obsInRows)
            % response of the regression model
            f = score(this.Impl,X,obsInRows);
        end

        function [metricsnames,metricshandles] = parseMetrics(this,metricsnames,metrics)
            % Parsing metrics for the incremental regression linear model
            epsmetrics = cellfun(@(x)isequal(x,'epsiloninsensitive'),metrics);
            if any(epsmetrics)
                if ~isequal(this.Learner,'svm')
                    error(message('stats:RegressionLinear:loss:UseEpsilonInsensitiveForSVM'));
                end
                epsind = find(epsmetrics);
                epshandle = @(Y,Yfit)classreg.learning.loss.unnormalized.epsiloninsensitive(Y,Yfit,this.Epsilon);
                epsname = incremental.internal.mapToMetricName('epsiloninsensitive');
                [metricsnamespartial,metricspartial] = parseMetrics@incremental.regr.RegressionModel(this,metricsnames(~epsmetrics),metrics(~epsmetrics));
                k = 1;
                metricshandles = cell(numel(metrics),1);
                for ii = 1:numel(metrics)
                    if ii == epsind
                        metricsnames{ii} = epsname;
                        metricshandles{ii} = epshandle;
                    else
                        metricsnames{ii} = metricsnamespartial{k};
                        metricshandles{ii} = metricspartial{k};
                        k = k+1;
                    end
                end
            else
                [metricsnames,metricshandles] = parseMetrics@incremental.regr.RegressionModel(this,metricsnames,metrics);
            end
        end


        function this = fitModelWithoutValidation(this,X,Y,W,WisRaw,obsInRows,numObservations)
            this.Impl = fit(this.Impl,X,Y,W,WisRaw,obsInRows,numObservations);
            this = adjustMetricIfNeeded(this);
        end

        function [modelArgs,remainingArgs] = parseMakeParameters(this,params)
           [modelArgs,remainingArgs] = incremental.impl.LinearImpl.parseMakeParameters(this.Mode,params);
        end

        function this = makeModel(this,parametersAreFromOffline,implParams)
           % Make method for the incremental regression linear model
           this.Impl = incremental.impl.LinearImpl.make(this.Mode,parametersAreFromOffline,implParams);
            if isequal(this.Learner,'svm')
                this.pModelSpecificMetrics = {'epsiloninsensitive'};
            end           
        end 
        
        function [trainingArgs,remainingArgs] = parseTrainingParameters(this,params)            
           [trainingArgs,remainingArgs] = parseTrainingParameters(this.Impl,params);
        end 
        
        function this = fillTrainingParameters(this,parametersAreFromOffline,trainingParams)            
           this.Impl = fillTrainingParameters(this.Impl,parametersAreFromOffline,trainingParams);
        end
        
        function [stateArgs,remainingArgs] = parseStateParameters(this,params)            
           [stateArgs,remainingArgs] = parseStateParameters(this.Impl,params);
        end       
        
        function this = fillStateParameters(this,parametersAreFromOffline,numPredictors,stateParams)
            this.Impl = fillStateParameters(this.Impl,parametersAreFromOffline,numPredictors,stateParams);
        end
        
        function this = updateStateParameters(this,numPredictors,predictorClass)
           this.Impl = updateStateParameters(this.Impl,numPredictors,predictorClass);
        end  

        function l = modelLoss(this,X,Y,W,obsInRows,lossFun,~)
            % Model loss for incremental regression linear model.
            if ischar(lossFun) || isstring(lossFun)
                if strncmpi(lossFun,'epsiloninsensitive',length(lossFun))
                    if ~isequal(this.Learner,'svm')
                        error(message('stats:RegressionLinear:loss:UseEpsilonInsensitiveForSVM'));
                    end
                    lossFun = @(Y,Yfit,W)classreg.learning.loss.epsiloninsensitive(Y,Yfit,W,this.Epsilon);
                end
            end
            l = modelLoss@incremental.regr.RegressionModel(this,X,Y,W,obsInRows,lossFun);
        end


        function l = modelPerObservationLoss(this,X,Y,obsInRows,lossFun)
            % Model per observation loss for incremental regression linear model.
            if ischar(lossFun) || isstring(lossFun)
                if strncmpi(lossFun,'epsiloninsensitive',length(lossFun))
                    if ~isequal(this.Learner,'svm')
                        error(message('stats:RegressionLinear:loss:UseEpsilonInsensitiveForSVM'));
                    end
                    lossFun = @(Y,Yfit)classreg.learning.loss.unnormalized.epsiloninsensitive(Y,Yfit,this.Epsilon);
                end
            end
            l = modelPerObservationLoss@incremental.regr.RegressionModel(this,X,Y,obsInRows,lossFun);
        end        


        function metrics = allowedMetrics(this)
            % allowed metrics for metric update
            regrMetrics = allowedMetrics@incremental.regr.RegressionModel(this);
            metrics = [this.pModelSpecificMetrics, regrMetrics];
        end

        function losses = allowedPerObservationLosses(this)
            % allowed per observations losses for incremental regression
            % linear model
            losses = allowedPerObservationLosses@incremental.regr.RegressionModel(this);
            losses = [this.pModelSpecificMetrics, losses];
        end        

        function defaultmetric = defaultMetric(this)
            % Default metric for the incremental regression linear model
            defaultmetric = defaultMetric@incremental.regr.RegressionModel(this);
            if ~isnan(this.Epsilon)
                defaultmetric = 'epsiloninsensitive';
            end
        end

        function cantrain = canTrain(this)
            % can model train
            cantrain = canTrain(this.Impl) && canTrain@incremental.SimpleLearner(this);
        end

        function this = resetModel(this,varargin)
            % Reset states
            this.Impl = reset(this.Impl,varargin{:});
            this = resetModel@incremental.regr.RegressionModel(this,varargin{:});
            this.pEpsilonMetricAdjusted = false;
        end

        function propList = propertiesForDisplay(this,propList)
            propList = propertiesForDisplay@incremental.regr.RegressionModel(this,propList);
            propList.Beta = this.Beta;
            propList.Bias = this.Bias;
            propList.Learner = this.Learner;
        end

        function validateForCoder(this)
            % check whether incremental model is ready for code
            %   generation
            [readyforCodegen,undefinedParameters] = validateForCoder@incremental.regr.RegressionModel(this);
            if ~readyforCodegen
                tmp = sprintf(' %s,',undefinedParameters{:});
                error(message('stats:incremental:coder:Learner:ModelNotFullyDefinedForCodegen',tmp(2:end-1)));
            end
        end

    end
    methods(Hidden)
        function str = serialize(this)
            % Convert incremental model to deserializeable struct
            str = serializeHelper(this);
        end
    end

    methods (Static,Hidden)
        function this = deserialize(deserializeableStr)
            % construct incremental model from a given struct
            this = incrementalRegressionLinear();
            this = deserialize@incremental.regr.RegressionModel(this,deserializeableStr);
            this.Impl = deserialize(this.Impl,deserializeableStr.ModelParameters); 
            this.pEpsilonMetricAdjusted = deserializeableStr.ModelParameters.pEpsilonMetricAdjusted;
            if this.Impl.ResetOnLoad
                this = reset(this);
            end              
        end

       function str = serializeStruct(this)
            % Convert incremental model struct to deserializeable
            % struct. 
            str = serializeHelper(this);
        end

        function this = loadobj(this)
            % custom load method for backwards compatibility
            if isstruct(this)
                deserializeableStr = incrementalRegressionLinear.serializeStruct(this); 
                this = incrementalRegressionLinear.deserialize(deserializeableStr);
            end

            % reset on load if loadobj(Impl) requires reset
            if this.Impl.ResetOnLoad
                this = reset(this);
            end           
        end
    end

    methods(Hidden)  %methods used for code generation
        function [tunableStr, nontunableStr] = toStruct(this)
            validateForCoder(this);
            [tunableStr,nontunableStr] = toStruct(this.Impl);
            nontunableStr.Mode = this.Mode;
            [tunableStr,nontunableStr] = toStruct@incremental.regr.RegressionModel(this,tunableStr,nontunableStr);
            nontunableStr.ModelSpecificMetrics = this.pModelSpecificMetrics;
            nontunableStr.EpsilonMetricAdjusted = this.pEpsilonMetricAdjusted;
            nontunableStr.FromStructFcn = 'incrementalRegressionLinear.fromStruct';
        end

        function obsinsupported = ObservationsInSupported(~)
        % Hidden method used for tab completion
            obsinsupported = true;
        end    
    end

    methods (Static, Hidden) %static methods used for code generation

        function this = fromStruct(tunableStr,nontunableStr)
            nontunableStr = rmfield(nontunableStr,'FromStructFcn');
            params = incremental.regr.RegressionModel.mergeRegrStructs(tunableStr,nontunableStr);
            modelparams = struct;
            modelparams = incremental.impl.LinearImpl.mergeStructs(modelparams,tunableStr,nontunableStr);
            params.ModelParameters = modelparams; 
            %params = incremental.Linear.mergeLinearStructs(params,tunableStr,nontunableStr);

            %process Metrics for epsiloninsensitive
            metricsParams = params.LearnerParameters.MetricParameters;
            metrics = metricsParams.MetricsFun;
            n =  numel(metrics);
            for ii = 1: n
                if ischar(metrics{ii})
                    if isequal(metrics{ii},'EpsilonInsensitiveLoss')
                        epsilon = params.ModelParameters.Epsilon;
                        metricsParams.MetricsFun{ii} = @(Y,Yfit)classreg.learning.loss.unnormalized.epsiloninsensitive(Y,Yfit,epsilon);
                        break;
                    end
                end

            end
            params.LearnerParameters.MetricParameters = metricsParams;
            params.ModelParameters.pEpsilonMetricAdjusted = nontunableStr.EpsilonMetricAdjusted;
            this = incrementalRegressionLinear.deserialize(params);          
        end

        function name = matlabCodegenRedirect(~)
            name = 'incremental.coder.incrementalRegressionLinear';
        end
    end
end

function str = serializeHelper(this)
    str= incremental.SimpleLearner.serialize(this);
    str = incremental.regr.RegressionModel.serialize(this,str);
    if isstruct(this)
        str.ModelParameters = serialize(this.Impl,this);
    else
        str.ModelParameters = serialize(this.Impl);
    end
    str.ModelParameters.pEpsilonMetricAdjusted = this.pEpsilonMetricAdjusted;
end