classdef ClassificationMetric < deep.Metric
    % Metric   Interface for metric for deep neural networks.
    
    %   Copyright 2022-2023 The MathWorks, Inc.

    properties (Abstract, SetAccess = private)
        % AverageType  (string scalar) Type of averaging when calculating
        % the metric. Can be either "micro", "macro", or "weighted".
        AverageType

        % ClassificationMode (string) Type of classification task. 
        % Can be either "single-label" or "multilabel".
        ClassificationMode
    end

    properties (Access = protected)
        ChannelDim
        NumClasses
        Threshold = 0.5
        Weights
    end

    methods
        function this = initialize(this,Y,T,varargin)
            deep.internal.util.validateDataSuitableForClassificationMetric(T, this.Name);

            this.ChannelDim = finddim(Y, 'C');
            this.NumClasses = size(Y, this.ChannelDim);

            deep.internal.util.validateDataSuitableForSingleLabelClassification(this.NumClasses, this.ClassificationMode, this.Name);

            if this.AverageType == "micro"
                % There are no weights for "micro", so set weights to 1 for
                % a no-op.
                this.Weights = 1;
            elseif this.AverageType == "macro"
                % For "macro", the weights are all equal to 1/numClasses
                this.Weights = ones(this.NumClasses, 1)./this.NumClasses;
            end
        end
    end

    methods (Abstract, Access = {?deep.metric.AccuracyMetric, ?deep.metric.FScoreMetric, ?deep.metric.PrecisionMetric, ?deep.metric.RecallMetric, ?deep.internal.metric.SharedClassificationMetric})
        this = evaluateMetricWithSharedData(this,tp,fp,fn,tn);
    end
end
