classdef incrementalClassificationLinear < incremental.classif.ClassificationModel
    %incrementalClassificationLinear Binary classification linear model
    %   for incremental learning. This model can train with and predict responses 
    %   for new data.
    %
    %   incrementalClassificationLinear properties:
    %       ClassNames               - Names of classes in Y.
    %       Prior                    - Prior class probabilities.
    %       ScoreTransform           - Transformation applied to predicted classification scores.
    %       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 'logistic'.
    %       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, 'hinge' or 'logit'.
    %       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.
    %
    %   incrementalClassificationLinear methods:
    %       incrementalClassificationLinear   - Construct incremental
    %                                           binary classification linear model.
    %       fit                               - Train model with new data.     
    %       loss                              - Classification loss.
    %       perObservationLoss                - Per observation classification 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  = incrementalClassificationLinear();
    %       mdl  = updateMetricsAndFit(mdl,X,Y);
    %
    %   Example 2: Initialize an incremental linear model using a traditionally trained model
    %   and continue incremental training.
    %
    %       ttModel = fitclinear(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 ClassificationLinear.incrementalLearner, classreg.learning.classif.CompactClassificationSVM.incrementalLearner.

    %   Copyright 2020-2023 The MathWorks, Inc.

    properties (Constant,Access = protected)
        IsBinary = true
        IsAdaptive = false
        LabelPredictor = @incremental.classif.ClassificationModel.maxScore
        HasCost = false
        HasAdditionalPredictionInputs = false
        CanSupportCategorical = false
    end

    properties (Access = protected, Constant)
        Mode(1,1) = 2
    end    

    properties(Constant, Access = protected)
        DefaultLoss = 'classiferror'
    end

    properties (SetAccess = protected,Hidden)
        Impl = [];
    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 = incrementalClassificationLinear(varargin)
            %INCREMENTALCLASSIFICATIONLINEAR Construct a binary classification linear
            %   model for incremental learning.
            %
            %   MODEL=INCREMENTALCLASSIFICATIONLINEAR() returns a binary classification
            %   linear model for incremental learning with default model parameters.
            %   Default model is created with placeholders for unknown parameters.
            %
            %   MODEL=incrementalLearner(TTMODEL) returns an incremental binary
            %   classification 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
            %   classification model, see the incrementalLearner reference for supported models.
            %
            %   MODEL=INCREMENTALCLASSIFICATIONLINEAR('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.
            %                                   'BatchSize' is not supported for scale-invariant solver.
            %       '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.
            %       'ClassNames'              - Array of class names, specified as a categorical array, logical
            %                                   vector, numeric vector, string array or
            %                                   cell array of strings.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.ClassNames is used.
            %                                   Default: 'ClassNames' is inferred from data when fit is called.
            %       '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'
            %                                       - 'logistic'
            %                                   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 during '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 classification:
            %                                   'binodeviance', 'classiferror', 'exponential',
            %                                   'hinge', 'logit', and 'quadratic'.
            %                                   If you pass a function handle FUN, it
            %                                   is called as shown below:
            %                                       FUN(C,S)
            %                                   where C is an N-by-K logical matrix for N
            %                                   elements in Y and K classes in the ClassNames
            %                                   property, S is an N-by-K numeric matrix.
            %                                   C has one true per row for the true class.
            %                                   S is a matrix of predicted scores for classes
            %                                   with one row per observation, similar to score
            %                                   output from predict.
            %                                   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: 'classiferror'.
            %       '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.
            %       'Prior'                   - Prior probabilities for each class. Specify as one
            %                                   of:
            %                                      * A string:
            %                                          - 'empirical' determines class probabilities
            %                                            from class frequencies in Y
            %                                          - 'uniform' sets all class probabilities equal
            %                                      * A vector (one scalar value for each class)
            %                                        If you pass numeric values, they are normalized to
            %                                        add up to 1.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.Prior is used.
            %                                   Default: 'empirical'.
            %                                   If 'ClassNames' is not provided, Prior must be 'empirical'.
            %       'ScoreTransform'          - Function handle for transforming scores, or
            %                                   string representing a built-in transformation
            %                                   function. Available functions: 'symmetric',
            %                                   'invlogit', 'ismax', 'symmetricismax', 'none',
            %                                   'logit', 'doublelogit', 'symmetriclogit', and
            %                                   'sign'.
            %                                   If MODEL is initialized from TTMODEL,
            %                                   TTMODEL.ScoreTransform is used.
            %                                   Default: 'none' if Learner is
            %                                   'svm'; otherwise, default is 'logit'.
            %       '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({'MaxNumClasses'},{'MaxNumClasses'}, varargin{:});
            this = this@incremental.classif.ClassificationModel(varargin{:});   
        end

        function [varargout] = predict(this,X,varargin)
            %PREDICT Predict responses of the model.
            %   [LABEL,SCORE]=PREDICT(MODEL,X) returns predicted class labels and
            %   scores for MODEL and predictors X. Pass X as a matrix with
            %   N observations from P predictors. Classification labels are a N-by-1
            %   array of the same data type as Y used for training, where N is the number of
            %   observations (rows in X). Scores are an N-by-K numeric matrix for N observations
            %   and K classes. The predicted label is assigned to the class with
            %   the largest score.
            %
            %   [LABEL,SCORE]=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 incrementalClassificationLinear, fit.
            [varargout{1:nargout}] = predict@incremental.classif.ClassificationModel(this,X,varargin{:});
        end

        function this = fit(this,X,Y,varargin)
            %FIT Train model with new data.
            %   MODEL=FIT(MODEL,X,Y) returns the modified MODEL
            %   trained incrementally with new data X and labels Y.
            %   MODEL.Metrics are not updated inside fit. Pass X as a matrix with 
            %   N observations from P predictors. Pass Y as a categorical array, 
            %   character array, logical vector, numeric vector, string array or 
            %   cell array of strings. If Y is a character array, it must have one 
            %   class label per row. Otherwise Y must be a vector with N elements.
            %   If MODEL.ClassNames is specified, Y must be of the same data type as
            %   MODEL.ClassNames. If MODEL.ClassNames is not defined,
            %   'ClassNames' is inferred from data.
            %
            %   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 incrementalClassificationLinear, updateMetricsAndFit, updateMetrics, loss.
            this = fit@incremental.SimpleLearner(this,X,Y,varargin{:});
        end


        function l = loss(this,X,Y,varargin)
            %LOSS Classification error.
            %   ERR=LOSS(MODEL,X,Y) returns classification error for model MODEL computed
            %   using predictors X and true class labels Y. Pass X as a matrix with
            %   N observations from P predictors. Y must be of the same data type as 
            %   MODEL.ClassNames and have 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 classification:
            %                            'binodeviance', 'classiferror', 'exponential',
            %                            'hinge', 'logit', and 'quadratic'.
            %                            If you pass a function handle FUN, it
            %                            is called as shown below:
            %                                  FUN(C,S,W)
            %                            where C is an N-by-K logical matrix for N
            %                            elements in Y and K classes in the ClassNames
            %                            property, S is an N-by-K numeric matrix and W is
            %                            a numeric vector with N elements. C has one true per
            %                            row for the true class. S is a matrix of
            %                            predicted scores for classes with one row per
            %                            observation, similar to SCORE output from
            %                            PREDICT. W is a vector of observation weights.
            %                            Default: 'classiferror'.
            %       '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 incrementalClassificationLinear, updateMetrics, updateMetricsAndFit, fit, predict.
            l = loss@incremental.SimpleLearner(this,X,Y,varargin{:});
        end

        function l = perObservationLoss(this,X,Y,varargin)
            %PEROBSERVATIONLOSS Model per observation classification error.
            %   ERR=PEROBSERVATIONLOSS(MODEL,X,Y) returns per observation
            %   classification error for model MODEL computed using predictors X and
            %   true labels Y. Pass X as a matrix with N observations from P predictors. 
            %   Y must be of the same data type as MODEL.ClassNames and have 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 classification:
            %                            'binodeviance', 'classiferror', 'exponential',
            %                            'hinge', 'logit', and 'quadratic'.
            %                            If you pass a function handle FUN, it
            %                            is called as shown below:
            %                                  FUN(C,S)
            %                            where C is an N-by-K logical matrix for N
            %                            elements in Y and K classes in the ClassNames
            %                            property and S is an N-by-K numeric matrix. 
            %                            C has one true per row for the true class. 
            %                            S is a matrix of predicted scores for classes
            %                            with one row per observation, similar to SCORE 
            %                            output from PREDICT.
            %                            Default: 'classiferror'.
            %
            %   See also incrementalClassificationLinear, 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 IncrementalClassificationLinear, are updated with new data
            %   X and labels Y. Pass X as an N-by-P matrix for N observations and P
            %   predictors. Pass Y as a categorical array, character array, logical
            %   vector, numeric vector, string array or cell array of strings. If Y is
            %   a character array, it must have one class label per row. Otherwise Y
            %   must be a vector with N elements. Y must be of the same data type as MODEL.ClassNames.
            %
            %   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 incrementalClassificationLinear, 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 IncrementalClassificationLinear, are updated.
            %           2. Model incrementally trained with new data X and labels Y.
            %   Pass X as an N-by-P matrix for N observations and P
            %   predictors. Pass Y as a categorical array, character array, logical
            %   vector, numeric vector, string array or cell array of strings. If Y is
            %   a character array, it must have one class label per row. Otherwise Y
            %   must be a vector with N elements.
            %   If MODEL.ClassNames is specified, Y must be of the same data type as
            %   MODEL.ClassNames. If MODEL.ClassNames is not defined,
            %   'ClassNames' is inferred from data.
            %
            %   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 incrementalClassificationLinear, updateMetrics, fit, loss, predict.
            this = updateMetricsAndFit@incremental.SimpleLearner(this,X,Y,varargin{:});
        end
    end

    methods
        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)
            C = classCount(this,Y);
            [this.Impl,X,Y,W] = prepareDataAndUpdateEstimationState(this.Impl,X,Y,W,obsInRows,numObservations,C);
        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)
            % overload configureForEstimation to handle known prior values
            if this.PriorDefined
                [this.Impl,remainingArgs] = configureForEstimation(this.Impl,parametersAreFromOffline,numPredictors,predictorClass,args,this.Prior);   
            else
                [this.Impl,remainingArgs] = configureForEstimation(this.Impl,parametersAreFromOffline,numPredictors,predictorClass,args);
            end
        end

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

        function this = setScoreTransform(this,st)
            % set ScoreTransform
            st = convertStringsToChars(st);
            tempst = classreg.learning.internal.convertScoreTransform(st,...
                'handle',this.NumClasses);
            if isequal(tempst,@classreg.learning.transform.identity) && isequal(this.Learner,'logistic')
                tempst = 'logit';
            end
            this = setScoreTransform@incremental.classif.ClassificationModel(this,tempst);
        end

        function s = score(this,X,obsInRows,~,~)
            % score for incremental binary classification model
            f = score(this.Impl,X,obsInRows);
            if this.NumClasses == 2
                s = [-f f];
            else
                s = f;
            end
        end

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

        function [this,X,Y,W,WisRaw,C] = prepareDataAndUpdateState(this,Xraw,Yraw,Wraw,obsInRows,numObservations)
            % update Prior, ClassNames and Weights if needed
            [this,X,Y,W,WisRaw,C] = prepareDataAndUpdateState@incremental.classif.ClassificationModel(this,Xraw,Yraw,Wraw,obsInRows,numObservations);
            if ~this.pPriorisState
                W = adjustWeights(this,C,W,this.Prior);
                WisRaw = false;
            end
        end

        function this = resetModel(this,varargin)
            % Reset states
            this.Impl = reset(this.Impl,varargin{:});
            this = resetModel@incremental.classif.ClassificationModel(this,varargin{:});
        end

        function propList = propertiesForDisplay(this,propList)
            propList = propertiesForDisplay@incremental.classif.ClassificationModel(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.classif.ClassificationModel(this);
            if ~readyforCodegen
                tmp = sprintf(' %s,',undefinedParameters{:});
                error(message('stats:incremental:coder:Learner:ModelNotFullyDefinedForCodegen',tmp(2:end-1)));
            end
        end

        function this = fitModelWithoutValidation(this,X,Y,W,WisRaw,obsInRows,numObservations)
            this.Impl = fit(this.Impl,X,Y,W,WisRaw,obsInRows,numObservations);
        end
        
        function [modelArgs,remainingArgs] = parseMakeParameters(this,params)
           [modelArgs,remainingArgs] = incremental.impl.LinearImpl.parseMakeParameters(this.Mode,params);
        end

        function this = makeModel(this,parametersAreFromOffline,implParams)
           this.Impl = incremental.impl.LinearImpl.make(this.Mode,parametersAreFromOffline,implParams);
        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 [numPredictors,predictorClass] = predictorAttributes(this)
                [numPredictors,predictorClass] = predictorAttributes(this.Impl);
        end
        
        function statesdefined = statesDefined(this)
            statesdefined = statesDefined(this.Impl);
        end

    end

    methods (Hidden)
        function obsinsupported = ObservationsInSupported(~)
        % Hidden method used for tab completion
            obsinsupported = true;
        end 
        function str = serialize(this)
            % Convert incremental model to deserializeable struct
            str = serializeHelper(this);
        end

        function this = resetTemplateProperties(this)
            this = resetTemplateProperties@incremental.classif.ClassificationModel(this);
        end   
    end
    methods (Static,Hidden)
        function this = deserialize(deserializeableStr)
            % construct incremental model from a given deserializable struct
            this = incrementalClassificationLinear();
            this = deserialize@incremental.classif.ClassificationModel(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
            inputStruct = isstruct(obj);
            if inputStruct
                deserializeableStr = incrementalClassificationLinear.serializeStruct(obj);
                this = incrementalClassificationLinear.deserialize(deserializeableStr);
            else
                this = obj;
            end

            if isempty(this.MaxNumClasses) % MaxNumClasses will be nonempty for linear models
                this = setMaxNumClasses(this);
            end

            if isempty(this.WeightsPerClass)
                this = setWeightsPerClass(this);
                % If loaded incremental linear model has empirical prior
                % and prior is not defined, we only have 1 class; thus,
                % we assign WeightsPerClass to NumTrainingObservations
                % for the known class.
                if this.pPriorisState && ~this.PriorDefined
                    this.WeightsPerClass = [this.NumTrainingObservations 0];
                end
            end
            
            if inputStruct
                if this.pPriorisState && ~this.PriorDefined
                    this.WeightsPerClass = [this.NumTrainingObservations 0];
                end
            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.classif.ClassificationModel(this,tunableStr,nontunableStr);
            nontunableStr.FromStructFcn = 'incrementalClassificationLinear.fromStruct';
        end   
    end

    methods (Static,Hidden) %static methods used for code generation
        function this = fromStruct(tunableStr,nontunableStr)
            nontunableStr = rmfield(nontunableStr,'FromStructFcn');
            params = incremental.classif.ClassificationModel.mergeClassifStructs(tunableStr,nontunableStr);
            params = incremental.classif.ClassificationModel.mergeScoreTransformStructs(params,tunableStr,nontunableStr);
            modelparams = struct;
            modelparams = incremental.impl.LinearImpl.mergeStructs(modelparams,tunableStr,nontunableStr);
            params.ModelParameters = modelparams;            
            this = incrementalClassificationLinear.deserialize(params);           
        end

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

    end
end


function str = serializeHelper(this)
    str = incremental.SimpleLearner.serialize(this);
    str = incremental.classif.ClassificationModel.serialize(this,str);
    if isstruct(this)
        str.ModelParameters = serialize(this.Impl,this);
    else
        str.ModelParameters = serialize(this.Impl);
    end
end
