classdef incrementalRegressionKernel < incremental.regr.RegressionModel
    %incrementalRegressionKernel Regression kernel model for incremental learning. 
    %   This model can train with and predict responses for new data.
    %
    %   incrementalRegressionKernel 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.
    %       KernelScale              - Kernel scale.
    %       NumExpansionDimensions   - Number of dimensions of expanded space.
    %       Learner                  - Learned model, 'svm' or 'leastsquares'.
    %       Solver                   - Solver used for training, 'sgd', 'asgd' or 'scale-invariant'.
    %       Mu                       - Predictor means.
    %       Sigma                    - Predictor standard deviations.
    %       SolverOptions            - Linear solver options.
    %       EstimationPeriod         - Number of observations that are used for
    %                                  parameter estimation prior to training.
    %
    %   incrementalRegressionKernel methods:
    %       incrementalRegressionKernel       - Construct incremental regression kernel 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 kernel model without providing any
    %   information.
    %       load carbig
    %       X = [Acceleration,Cylinders,Displacement,Horsepower,Weight];
    %       Y = MPG;
    %       mdl  = incrementalRegressionKernel();
    %       mdl  = updateMetricsAndFit(mdl,X,Y);
    %
    %   Example 2: Initialize an incremental kernel model using a traditionally trained model
    %   and continue incremental training.
    %       load carbig
    %       X = [Acceleration,Cylinders,Displacement,Horsepower,Weight];
    %       Y = MPG;
    %       ttModel = fitrkernel(X(1:100,:),Y(1:100));
    %       mdl = incrementalLearner(ttModel);
    %       mdl = updateMetrics(mdl,X(101:end,:),Y(101:end));
    %       mdl = fit(mdl,X(101:end),Y(101:end));
    %
    %   See also RegressionKernel.incrementalLearner.

    %   Copyright 2021-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 incrementalRegressionKernel, Regressionkernel.
        Epsilon
    end
    properties (Access = private)
        pModelSpecificMetrics
        pEpsilonMetricAdjusted = false
    end
    properties (Constant,Access  =protected)
        CanSupportCategorical = false
        Mode(1,1) = 0 % 0 for regression
    end

    properties (SetAccess=protected, Dependent)
        %SOLVEROPTIONS Linear Solver Options.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Solver.
        SolverOptions
    end    

    properties (Dependent, Access=protected)
        %SOLVEROPTIONS Linear Solver Options.
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Solver.
        OriginalNumPredictors
    end

    properties (Hidden)
        Impl = [];
    end

    properties (Access = private, Dependent)
        parametersAdjusted
    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

       %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 incrementalClassificationKernel, incrementalRegressionKernel,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 incrementalClassificationKernel, incrementalRegressionKernel,EstimationPeriod, predict.        
        Sigma
    end      

    properties(Dependent, SetAccess = protected)
        % KERNELSCALE Kernel Scale.
        %     The KernelScale property is a non negative scalar used to
        %     amplify the Gaussian kernel.
        KernelScale

        % NUMEXPANSIONDIMENSIONS Number of dimensions.
        %     The NumExpansionDimensions property is an integer representing the
        %     number of dimensions in transformed space after explicitly
        %     mapping the predictor matrix.
        NumExpansionDimensions


        %LEARNER Linear model type
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear.
        Learner

        %SOLVER Linear solver type
        %
        %   See also incrementalClassificationLinear, incrementalRegressionLinear.
        Solver

        %FITTEDLOSS Fitted loss function.
        %   The FittedLoss property is a string specifying the fitted loss
        %   function.
        %  
        %   See also incrementalClassificationLinear, incrementalRegressionLinear, Learner.
        FittedLoss    
    end    
    
    methods
        function this = incrementalRegressionKernel(varargin)
            %INCREMENTALREGRESSIONKERNEL Construct an incremental regression kernel model.
            %
            %   MODEL=INCREMENTALREGRESSIONKERNEL() returns an incremental regression kernel model
            %   with default model parameters.
            %   Default model is created with placeholders for unknown parameters.
            %
            %   MODEL=incrementalLearner(TTMODEL) returns an incremental regression
            %   kernel 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 RegressionKernel.
            %
            %   MODEL=INCREMENTALREGRESSIONKERNEL('PARAM1',val1,'PARAM2',val2,...) specifies optional
            %   parameter name/value pairs:
            %       'KernelScale'             - Either 'auto' or positive scalar specifying
            %                                   the value for the scale parameter. If you pass
            %                                   'auto', incrementalRegressionKernel estimates the scale using
            %                                   a heuristic procedure. Default: 1.
            %       'NumExpansionDimensions'  - Number of dimensions in the expanded space.
            %                                   Either 'auto' or a positive integer. If you pass
            %                                   'auto', the following formula is used to
            %                                   compute the number of expanded dimensions:
            %                                   2.^ceil(min(log2(NumPredictors)+5,15)
            %                                   Default: 'auto'
            %       'RandomStream'            - A random number stream to control reproducibility
            %                                   of the random basis functions used for
            %                                   transforming X to a high dimensional space.
            %       'BatchSize'               - Mini-batch size for the stochastic
            %                                   solvers, specified as a positive
            %                                   scalar.
            %                                   Default is 10 for stochastic solvers.
            %                                   'BatchSize' is not supported for scale-invariant solver.
            %       '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.
            %       'Lambda'                  - Ridge (L2) regularization strength specified as a
            %                                   nonnegative scalar.
            %                                   '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.
            %                                   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.
            %                                   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.
            varargin = incremental.utils.parseUnsupportedConstructionParameters({'Beta','Bias','FitBias'},{},varargin{:});
            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.
            %
            %   See also incrementalRegressionKernel, fit.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            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 an N-by-P matrix for N observations and 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:
            %       '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 incrementalRegressionKernel, updateMetricsAndFit, updateMetrics.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            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 an N-by-P matrix for N observations
            %   and P predictors.
            %   Y must be a vector of floating-point numbers with N elements, where N is the number
            %   of observations in X. ERR is a scalar.
            %
            %   ERR=LOSS(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies
            %   optional parameter name/value pairs:
            %       '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 incrementalRegressionKernel, updateMetrics, updateMetricsAndFit, fit,
            %   predict, perObservationLoss.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            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 an N-by-P matrix for N observations
            %   and P predictors. Y must be a vector of floating-point numbers with N elements,
            %   where N is the number of observations in X. ERR is a N-by-1 vector.
            %
            %   ERR=PEROBSERVATIONLOSS(MODEL,X,Y,'PARAM1',val1,'PARAM2',val2,...) specifies optional
            %   parameter name/value pairs:
            %       '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 incrementalRegressionKernel, updateMetrics, updateMetricsAndFit, fit,
            %   predict, loss.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            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 incrementalRegressionKernel, are updated with new data
            %   X and observed response Y.
            %   Pass X as an N-by-P matrix for N observations and 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:
            %       '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 incrementalRegressionKernel, updateMetricsAndFit, fit, loss, predict.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            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 IncrementalRegressionKernel, are updated.
            %           2. Model trained incrementally with new data X and observed response Y.
            %   Pass X as an N-by-P matrix for N observations and 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:
            %       '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 incrementalRegressionKernel, updateMetrics, fit, loss, predict.
            varargin = incremental.utils.parseUnsupportedParameters('ObservationsIn', varargin{:});
            this = updateMetricsAndFit@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

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

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

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

        function ks = get.KernelScale(this)
            ks = this.Impl.KernelScale;
        end

        function nexp = get.NumExpansionDimensions(this)
            nexp = this.Impl.NumExpansionDimensions;
        end

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

        function solver = get.Solver(this)
            solver = this.Impl.SolverImpl.Solver;
        end

        function solveroptions = get.SolverOptions(this)
            solveroptions = this.Impl.SolverImpl.SolverOptions;
        end

        function d = get.OriginalNumPredictors(this)
            d = this.Impl.OriginalNumPredictors;
        end

        function lossfcn = get.FittedLoss(this)
            lossfcn = this.Impl.SolverImpl.LossFunction;
        end

        function mu = get.Mu(this)
           mu = this.Impl.Mu; 
        end
        
        function sigma = get.Sigma(this)
           sigma = this.Impl.Sigma; 
        end
    end

    
    methods(Access = protected)

        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.KernelImpl.parseMakeParameters(params,this.NumPredictors);
        end

        function this = makeModel(this,parametersAreFromOffline,implParams)
           this.Impl = incremental.impl.KernelImpl.make(this.Mode,parametersAreFromOffline,implParams); 
            if isequal(this.Learner,'svm')
                this.pModelSpecificMetrics = {'epsiloninsensitive'};
            end           
        end

        function [trainingArgs,remainingArgs] = parseTrainingParameters(this,params) % this is a method defined in the solver classes : SGDImpl, ScaleInvariantImpl
            [trainingArgs,remainingArgs] = parseTrainingParameters(this.Impl,params);
        end

        function this = fillTrainingParameters(this,parametersAreFromOffline,trainingParams) % this is a method defined in the solver classes : SGDImpl, ScaleInvariantImpl
            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,~,stateParams)
            this.Impl = fillStateParameters(this.Impl,parametersAreFromOffline,stateParams);
        end

        function this = updateStateParameters(this, dataNumPredictors, predictorClass)
             this.Impl = updateStateParameters(this.Impl, dataNumPredictors, predictorClass);
        end

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

        function statesdefined = statesDefined(this)
            statesdefined = statesDefined(this.Impl);
        end  

        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,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,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 = 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 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 kernel 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 l = modelLoss(this,X,Y,W,obsInRows,lossFun,~)
            % Model loss for incremental regression kernel 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 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 kernel 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 propList = propertiesForDisplay(this,propList)
            propList = propertiesForDisplay@incremental.regr.RegressionModel(this,propList);
            propList.NumExpansionDimensions = this.NumExpansionDimensions;
            propList.KernelScale = this.KernelScale;  
        end
    end

    % The following methods need to be redefined here because of the
    % current incremental architecture. The two base classes : Estimator
    % and Learner, both define their own versions of these methods, causing
    % conflicted definitions.
    methods(Access = protected)
        function this = resetModel(this,varargin)
            % Reset states
            this.Impl = reset(this.Impl,varargin{:});
            this = resetModel@incremental.regr.RegressionModel(this,varargin{:});
            this.pEpsilonMetricAdjusted = false;
        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 = incrementalRegressionKernel();
            this = deserialize@incremental.regr.RegressionModel(this,deserializeableStr);
            this.Impl = deserialize(this.Impl,deserializeableStr.ModelParameters);
            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(obj)
            % custom load method for backwards compatibility
            if isstruct(obj)
                deserializeableStr = incrementalRegressionKernel.serializeStruct(obj);
                this = incrementalRegressionKernel.deserialize(deserializeableStr);
            elseif isempty(obj.Impl.StandardizeImpl) %starting 23b, standardize support was added 
                deserializeableStr = incrementalRegressionKernel.serializeStruct(obj);
                this = incrementalRegressionKernel.deserialize(deserializeableStr);
            else
                this = obj;
            end

            % reset on load if loadobj(Impl) requires reset
            if this.Impl.ResetOnLoad
                this = reset(this);
            end            
        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
end
