classdef Learner < matlab.mixin.internal.Scalar ...
         & matlab.mixin.CustomDisplay & matlab.mixin.CustomCompactDisplayProvider
%LEARNER Abstract interface class for incremental models.

    %   Copyright 2020-2022 The MathWorks, Inc.
    properties (Dependent,GetAccess = public, SetAccess = protected)
        %NUMPREDICTORS Positive scalar specifying the number of
        %    predictors. Default: 'NumPredictors' is inferred
        %    when fit is called.
        NumPredictors(1,1) {mustBeNumeric,mustBeReal,mustBeNonNan,mustBeFinite,mustBeGreaterThanOrEqual(NumPredictors,0),mustBeInteger, mustBeNonsparse}

        %NUMTRAININGOBSERVATIONS  Scalar specifying the number of
        %    training observations the incremental model has seen so far.
        NumTrainingObservations(1,1) {mustBeNumeric,mustBeReal,mustBeFinite,mustBeGreaterThanOrEqual(NumTrainingObservations,0),mustBeInteger, mustBeNonsparse}

        %METRICSWARMUPPERIOD Number of observations that are used for training
        %    prior to metrics tracking.
        %    METRICSWARMUPPERIOD is a nonnegative integer specifying the number of
        %    observations that are used for training the model prior to metrics tracking.
        %
        %   See also Metrics, Metrics, MetricsWindowSize.
        MetricsWarmupPeriod(1,1) {mustBeNumeric,mustBeReal,mustBeNonNan,mustBeFinite,mustBeGreaterThanOrEqual(MetricsWarmupPeriod,0),mustBeInteger, mustBeNonsparse}

        %METRICSWINDOWSIZE Window size for window metrics tracking.
        %    METRICSWINDOWSIZE is a positive integer specifying the window
        %    size that is used for window metrics tracking.
        %
        %   See also updateMetrics, Metrics, MetricsWarmupPeriod.
        MetricsWindowSize(1,1) {mustBeNumeric,mustBeReal,mustBeNonNan,mustBeFinite,mustBeGreaterThan(MetricsWindowSize,0),mustBeInteger, mustBeNonsparse} 

        %ISWARM Indicate if incremental model is warmed-up.
        %    ISWARM is a read-only logical to indicate whether the incremental model has
        %    been trained with 'EstimationPeriod' + 'MetricsWarmupPeriod' observations.
        %
        %   See also updateMetrics, Metrics, MetricsWarmupPeriod, MetricsWindowSize.   
        IsWarm(1,1) logical

        %METRICS Metrics information.
        %    METRICS is a table to display the performance metrics
        %    for the incremental model. METRICS has 2 columns, 'Cumulative' and
        %    'Window', corresponding to cumulative metrics and metrics evaluated
        %    over a window specified by 'MetricsWindowSize' respectively.
        %    METRICS has m rows, where m is equal to the number of specified
        %    metrics.
        %    'Window' values are periodically updated when 'MetricsWindowSize'
        %    observations have been collected.
        %
        %   See also updateMetrics, MetricsWarmupPeriod, MetricsWindowSize.
        Metrics
    end

    properties (Access = protected)
        pNumTrainingObservations = 0

        pIsWarm  = false

        pMetrics

        pNumPredictors  = 0

        pMetricsWarmupPeriod = 1000

        pMetricsWindowSize = 200
    end

    methods(Abstract)
        this = fit(this,varargin)
        this = updateMetrics(this,varargin)
        this = updateMetricsAndFit(this,varargin)
        l  = loss(this,varargin)
        varargout  = predict(this,varargin)
        this = reset(this)
        l = perObservationLoss(this,varargin)
    end

    methods(Abstract,Access = protected)
        % Abstract method for display
        props = propertiesForDisplay(this,varargin)
    end

    
    methods(Access = protected)
        
        function propGrp = getPropertyGroups(this)
            propList = struct;
            propList.IsWarm = this.IsWarm;
            propList.Metrics = this.Metrics;
            propList = propertiesForDisplay(this,propList);
            propGrp = matlab.mixin.util.PropertyGroup(propList);
        end

        function header = getHeader(this)
            header = [];
            internal.stats.displayClassName(this);
        end
        function footer = getFooter(obj)
            footer =[];
            internal.stats.displayMethodsProperties(obj);
        end


        function metrics = getMetrics(this)
            metrics = this.pMetrics;
        end

        function numpredictors = getNumPredictors(this)
            numpredictors = this.pNumPredictors;
        end

        function numobs = getNumTrainingObservations(this)
            numobs = this.pNumTrainingObservations;
        end 


        function warmupperriod = getMetricsWarmupPeriod(this)
            warmupperriod = this.pMetricsWarmupPeriod;
        end

        function wsize = getMetricsWindowSize(this)
            wsize = this.pMetricsWindowSize;
        end  

        function iswarm = getIsWarm(this)
            iswarm = this.pIsWarm;
        end 

        function this = setNumPredictors(this,numPredictors)
            this.pNumPredictors = double(numPredictors);
        end    

        function this = setIsWarm(this,iswarm)
            this.pIsWarm = iswarm;
        end          

        function this = setMetrics(this,metrics)
            this.pMetrics = metrics;
        end     

        function this = setMetricsWarmupPeriod(this,period)
            this.pMetricsWarmupPeriod = double(period);
        end

        function this = setMetricsWindowSize(this,wsize)
            this.pMetricsWindowSize = double(wsize);
        end 

        function this = setNumTrainingObservations(this,numobs)
            this.pNumTrainingObservations = double(numobs);
        end         
    end

    methods
        function this = set.NumPredictors(this,numPredictors)
            this = setNumPredictors(this,numPredictors);
        end    

        function this = set.IsWarm(this,iswarm)
            this = setIsWarm(this,iswarm);
        end          

        function this = set.Metrics(this,metrics)
            this = setMetrics(this,metrics);
        end     

        function this = set.MetricsWarmupPeriod(this,period)
            this = setMetricsWarmupPeriod(this,period);
        end

        function this = set.MetricsWindowSize(this,wsize)
            this = setMetricsWindowSize(this,wsize);
        end 

        function this = set.NumTrainingObservations(this,numobs)
            this = setNumTrainingObservations(this,numobs);
        end 

        function numpredictors = get.NumPredictors(this)
            numpredictors = getNumPredictors(this);
        end        

        function numobs = get.NumTrainingObservations(this)
            numobs = getNumTrainingObservations(this);
        end    

        function wsize = get.MetricsWindowSize(this)
            wsize = getMetricsWindowSize(this);
        end         
        function period = get.MetricsWarmupPeriod(this)
            period = getMetricsWarmupPeriod(this);
        end 

        function iswarm = get.IsWarm(this)
            iswarm = getIsWarm(this);
        end

        function metrics = get.Metrics(this)
            metrics = getMetrics(this);
        end 
    end

    methods(Abstract,Hidden)
        obsinsupported = ObservationsInSupported(this)
    end

    methods(Static,Hidden)
        % Backwards compatibility function
        function [MetricParameters,LearnerParameters] = serialize(this)
            % Convert incremental learner struct to deserializeable
            % struct.
            [MetricParameters,LearnerParameters] = serializeHelper(this);
        end
    end

    methods(Hidden)
        function rep = compactRepresentationForSingleLine(obj, varargin)
            % Hidden method to dispatch to compactRepresentationForSingleLine
            %   for matlab.mixin.CustomCompactDisplayProvider.
            rep = compactRepresentationForSingleLine@matlab.mixin.CustomCompactDisplayProvider(obj, varargin{:});
        end

        function rep = compactRepresentationForColumn(obj, varargin)
            % Hidden method to dispatch to compactRepresentationForColumn
            %   for matlab.mixin.CustomCompactDisplayProvider.
            rep = compactRepresentationForColumn@matlab.mixin.CustomCompactDisplayProvider(obj, varargin{:});
        end
    end
end


function [MetricParameters,LearnerParameters] = serializeHelper(this)
% serialize helper function
    MetricParameters = struct;
    LearnerParameters = struct;
    if isstruct(this)
        MetricParameters.MetricsWarmupPeriod = this.MetricsWarmupPeriod;
        MetricParameters.MetricsWindowSize = this.MetricsWindowSize;
        LearnerParameters.NumPredictors = this.NumPredictors;
        LearnerParameters.NumTrainingObservations = this.NumTrainingObservations;
        MetricParameters.Metrics = this.Metrics;
        MetricParameters.IsWarm = this.IsWarm;        
    else
        MetricParameters.MetricsWarmupPeriod = this.pMetricsWarmupPeriod;
        MetricParameters.MetricsWindowSize = this.pMetricsWindowSize;
        LearnerParameters.NumPredictors = this.pNumPredictors;
        LearnerParameters.NumTrainingObservations = this.pNumTrainingObservations;
        MetricParameters.Metrics = this.pMetrics;
        MetricParameters.IsWarm = this.pIsWarm;        
    end
end
