Main Content

incrementalDriftAwareLearner

Construct drift-aware model for incremental learning

Since R2022b

    Description

    incrementalDriftAwareLearner creates an incrementalDriftAwareLearner model object, which incorporates an incremental classification or regression learner and an incremental concept drift detector to provide a self-adjusting incremental machine learning model. incrementalDriftAwareLearner supports all classification and regression models for incremental learning and all concept drift detection methods supported by Statistics and Machine Learning Toolbox™.

    Unlike most Statistics and Machine Learning Toolbox model objects, incrementalDriftAwareLearner can be called directly. After you create an incrementalDriftAwareLearner object, it is prepared for incremental drift-aware learning.

    incrementalDriftAwareLearner is best suited for incremental learning that adapts for concept drift. For a traditional approach to batch drift detection, see detectdrift.

    Creation

    You can create an incrementalDriftAwareLearner model object in the following ways:

    • Initiate an incremental classification or regression learner using any incremental learner. Pass the incremental learning model as an input in the call to incrementalDriftAwareLearner. For example,

      BaseLearner = incrementalClassificationLinear();
      Mdl = incrementalDriftAwareLearner(BaseLearner);

    • Initiate an incremental classification or regression learner using any incremental learner. Initiate an incremental concept drift detector using incrementalConceptDriftDetector. Pass both the incremental learning model and concept drift detector as inputs in the call to incrementalDriftAwareLearner. For example,

      BaseLearner = incrementalRegressionKernel();
      DDM = incrementalConceptDriftDetector("ddm");
      Mdl = incrementalDriftAwareLearner(BaseLearner,DriftDetector=DDM);

    Description

    Mdl = incrementalDriftAwareLearner(BaseLearner) returns a drift-aware model Mdl for incremental learning with default model parameters and default drift detector.

    example

    Mdl = incrementalDriftAwareLearner(BaseLearner,Name=Value) sets additional options using name-value arguments. For example, incrementalDriftAwareLearner(BaseLearner,DriftDetector=CDDetector,TrainingPeriod=1000) specifies the concept drift detector as a predefined CDDetector and sets the training period to 1000 observations.

    example

    Input Arguments

    expand all

    Underlying incremental classification or regression model, specified as one of the following.

    To learn how to create these learners, refer to the corresponding reference page.

    Name-Value Arguments

    Specify optional pairs of arguments as Name1=Value1,...,NameN=ValueN, where Name is the argument name and Value is the corresponding value. Name-value arguments must appear after other arguments, but the order of the pairs does not matter.

    Example: BufferSize=5000,TrainingPeriod=8000,StableCountLimit=6000 specifies the buffer size as 5000, the training period as 8000, and the limit of consecutive stable states before a reset as 6000 observations.

    Size of the buffer to store the loss values of BaseLearner for each training observation, specified as a scalar integer.

    Example: BufferSize=5000

    Data Types: single | double

    Incremental concept drift detector used for monitoring and detecting drift, specified as a HoeffdingDriftDetectionMethod or DriftDetectionMethod object.

    • If BaseLearner is an incremental classification object, then the default detector is HoeffdingDriftDetectionMethod that uses the moving average method. That is, incrementalDriftAwareLearner creates the drift detector using incrementalConceptDriftDetector("hddma").

    • If BaseLearner is an incremental regression object, then the default is HoeffdingDriftDetectionMethod that uses the moving average method for continuous variables. That is, incrementalDriftAwareLearner creates the drift detector using incrementalConceptDriftDetector("hddma",InputType="continuous").

    To specify an incremental concept drift detector that uses a different method, see the incrementalConceptDriftDetector reference page.

    Example: DriftDetector=dd

    Number of observations used for training, specified as a scalar integer.

    If you specify the TrainingPeriod value as Inf, then the software always trains with incoming data.

    If the TrainingPeriod value is smaller than the BaseLearner.MetricsWarmupPeriod value, then incrementalDriftAwareLearner sets the TrainingPeriod value as BaseLearner.MetricsWarmupPeriod.

    Example: TrainingPeriod=7000

    Data Types: single | double

    Maximum number of consecutive 'Stable' observations before a soft reset, specified as a scalar integer.

    Example: StableCountLimit=35000

    Data Types: single | double

    Maximum number of consecutive 'Warning' observations before a reset, specified as a scalar integer.

    Example: WarningCountLimit=1000

    Data Types: single | double

    Properties

    expand all

    This property is read-only.

    Underlying incremental classification or regression model, specified as one of the following model objects.

    This property is set by the BaseLearner input argument.

    Access the properties of BaseLearner using the dot operator, for example, Mdl.BaseLearner.Solver.

    This property is read-only.

    Underlying incremental concept drift detector, specified as either a HoeffdingDriftDetectionMethod or DriftDetectionMethod object.

    This property is set by the DriftDetector name-value argument.

    Access the properties of DriftDetector using the dot operator, for example, Mdl.DriftDetector.WarningThreshold.

    This property is read-only.

    Number of observations used for training before the software starts monitoring for potential drift, specified as a scalar integer.

    This property is set by the TrainingPeriod name-value argument.

    Data Types: double

    This property is read-only.

    Maximum number of consecutive 'Stable' observations before a soft reset, specified as a scalar integer.

    This property is set by the StableCountLimit name-value argument.

    Data Types: double

    This property is read-only.

    Status of DriftDetector prior to training most recent data, specified as 'Stable', 'Warning', or 'Drift'.

    Data Types: char

    This property is read-only.

    Current status of DriftDetector after training with the most recent data, specified as 'Stable', 'Warning', or 'Drift'.

    Data Types: char

    This property is read-only.

    Flag indicating whether DriftStatus is 'Drift', specified as logical 0 (false) or 1 (true).

    Data Types: logical

    This property is read-only.

    Maximum number of consecutive 'Warning' observations before a reset, specified as a scalar integer.

    Data Types: double

    This property is read-only.

    Flag indicating whether DriftStatus is 'Warning', specified as logical 0 (false) or 1 (true).

    Data Types: logical

    This property is read-only.

    Flag indicating whether BaseLearner continues training with incoming data, specified as logical 0 (false) or 1 (true).

    Data Types: logical

    This property is read-only.

    Flag indicating whether the incremental model tracks performance metrics, specified as logical 0 (false) or 1 (true).

    incrementalDriftAwareLearner takes this property from Mdl.BaseLearner.

    The incremental model Mdl is warm (IsWarm becomes true) after incremental fitting functions fit (Mdl.BaseLearner.EstimationPeriod + MetricsWarmupPeriod) observations to the incremental model.

    ValueDescription
    true or 1The incremental model Mdl is warm. Consequently, updateMetrics and updateMetricsAndFit track performance metrics in the Metrics property of Mdl.
    false or 0The incremental model Mdl is not warm. updateMetrics and updateMetricsAndFit do not track performance metrics, and all metrics values are NaN.

    Data Types: logical

    This property is read-only.

    Number of predictor variables, specified as a nonnegative numeric scalar.

    incrementalDriftAwareLearner takes this property from Mdl.BaseLearner. You can specify the number of predictor variables during the initiation of BaseLearner.

    Data Types: double

    This property is read-only.

    Number of observations fit to the incremental model Mdl, specified as a nonnegative numeric scalar.

    incrementalDriftAwareLearner pulls this property from Mdl.BaseLearner.

    NumTrainingObservations increases when you pass Mdl and training data to fit or updateMetricsAndFit.

    Note

    If you convert a traditionally trained model to create Mdl.BaseLearner, incrementalDriftAwareLearner does not add the number of observations fit to the traditionally trained model to NumTrainingObservations.

    Data Types: double

    This property is read-only.

    Model performance metrics updated during incremental learning by updateMetrics or updateMetricsAndFit, specified as a table with two columns and m rows, where m is the number of metrics specified by the Metrics name-value argument during the initiation of BaseLearner.

    incrementalDriftAwareLearner takes this property from Mdl.BaseLearner.

    The columns of Metrics are labeled Cumulative and Window.

    • Cumulative – Element j is the model performance, as measured by metric j, from the time the model becomes warm (IsWarm is 1).

    • Window – Element j is the model performance, as measured by metric j, evaluated over all observations within the window specified by the MetricsWindowSize property. The software updates Window after it processes MetricsWindowSize observations.

    Rows are labeled by the specified metrics.

    Data Types: table

    This property is read-only.

    Number of observations to which the incremental model must be fit before it tracks performance metrics in its Metrics property, specified as a nonnegative integer.

    incrementalDriftAwareLearner takes this property from Mdl.BaseLearner. You can specify the metrics warm up period during the initiation of BaseLearner.

    Data Types: double

    This property is read-only.

    Number of observations to use to compute window performance metrics, specified as a positive integer.

    incrementalDriftAwareLearner pulls this property from Mdl.BaseLearner. You can specify the metrics window size during the initiation of the BaseLearner.

    Data Types: double

    Object Functions

    fitTrain drift-aware learner for incremental learning with new data
    lossRegression or classification error of incremental drift-aware learner
    perObservationLossPer observation regression or classification error of incremental drift-aware learner
    predictPredict responses for new observations from incremental drift-aware learning model
    resetReset incremental drift-aware learner
    updateMetricsUpdate performance metrics in incremental drift-aware learning model given new data
    updateMetricsAndFitUpdate performance metrics in incremental drift-aware learning model given new data and train model

    Examples

    collapse all

    Load the human activity dataset. Randomly shuffle the data.

    load humanactivity;
    n = numel(actid);
    rng(1) % For reproducibility
    idx = randsample(n,n);

    For details on the data set, enter Description at the command line.

    Define the predictor and response variables.

    X = feat(idx,:);
    Y = actid(idx);

    Responses can be one of five classes: Sitting, Standing, Walking, Running, or Dancing. Dichotomize the response by identifying whether the subject is moving (actid > 2).

    Y = Y > 2;

    Flip labels for the second half of the dataset to simulate drift.

    Y(floor(numel(Y)/2):end,:) = ~Y(floor(numel(Y)/2):end,:);

    Initiate a default incremental drift-aware model for classification as follows:

    1. Create a default incremental linear SVM model for binary classification.

    2. Initiate a default incremental drift-aware model using the incremental linear SVM model.

    incMdl = incrementalClassificationLinear();
    idaMdl = incrementalDriftAwareLearner(incMdl);

    idaMdl is an incrementalDriftAwareLearner model. All its properties are read-only.

    Preallocate the number of variables in each chunk for creating a stream of data and the variable to store the classification error.

    numObsPerChunk = 50;
    nchunk = floor(n/numObsPerChunk);
    ce = array2table(zeros(nchunk,2),'VariableNames',["Cumulative" "Window"]);

    Preallocate variables for tracking drift status.

    status = zeros(nchunk,1);
    statusname = strings(nchunk,1);

    Simulate a data stream with incoming chunks of 50 observations each. At each iteration:

    1. Call updateMetricsAndFit to update the performance metrics and fit the drift-aware model to the incoming data. Overwrite the previous incremental model with the new one.

    2. Store the cumulative and per iteration classification error in ce. The Metrics property of idaMdl stores the cumulative and window classification error, which is updated at each iteration.

    for j = 1:nchunk
     ibegin = min(n,numObsPerChunk*(j-1)+1);
     iend   = min(n,numObsPerChunk*j);
     idx = ibegin:iend;    
    
     idaMdl = updateMetricsAndFit(idaMdl,X(idx,:),Y(idx));
    
     statusname(j) = string(idaMdl.DriftStatus);
     if idaMdl.DriftDetected
           status(j) = 2;  
        elseif idaMdl.WarningDetected
           status(j) = 1;
        else 
           status(j) = 0;
        end   
     ce{j,:} = idaMdl.Metrics{"ClassificationError",:};
    end

    The updateMetricsAndFit function first evaluates the performance of the model by calling updateMetrics on incoming data, and then fits the model to data by calling fit:

    The updateMetrics function evaluates the performance of the model as it processes incoming observations. The function writes specified metrics, measured cumulatively and within a specified window of processed observations, to the Metrics model property.

    The fit function fits the model by updating the base learner and monitoring for drift given an incoming batch of data. When you call fit, the software performs the following procedure:

    • Trains the model up to NumTrainingObservations observations.

    • After training, the software starts tracking the model loss to see if any concept drift has occurred and updates drift status accordingly.

    • When the drift status is Warning, the software trains a temporary model to replace theBaseLearner in preparation for an imminent drift.

    • When the drift status is Drift, temporary model replaces the BaseLearner.

    • When the drift status is Stable, the software discards the temporary model.

    For more information, see the Algorithms section.

    Plot the cumulative and per window classification error. Mark the warmup and training periods, and where the drift was introduced.

    h = plot(ce.Variables);
    
    xlim([0 nchunk])
    ylabel("Classification Error")
    xlabel("Iteration")
    
    xline(idaMdl.MetricsWarmupPeriod/numObsPerChunk,"g-.","Warmup Period",LineWidth= 1.5)
    xline(idaMdl.TrainingPeriod/numObsPerChunk,"b-.","Training Period",LabelVerticalAlignment="middle",LineWidth= 1.5)
    xline(floor(numel(Y)/2)/numObsPerChunk,"m--","Drift",LabelVerticalAlignment="middle",LineWidth= 1.5)
    
    legend(h,ce.Properties.VariableNames)
    legend(h,Location="best")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Classification Error contains 5 objects of type line, constantline. These objects represent Cumulative, Window.

    Plot the drift status versus the iteration number.

    figure()
    gscatter(1:nchunk,status,statusname,'gmr','*ox',[4 5 5],'on',"Iteration","Drift Status","filled")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Drift Status contains 2 objects of type line. One or more of the lines displays its values using only markers These objects represent Stable, Drift.

    Create the random concept data and concept drift generator using the helper functions, HelperSineGenerator and HelperConceptDriftGenerator, respectively.

    concept1 = HelperSineGenerator(ClassificationFunction=1,IrrelevantFeatures=true,TableOutput=false);
    concept2 = HelperSineGenerator(ClassificationFunction=3,IrrelevantFeatures=true,TableOutput=false);
    driftGenerator = HelperConceptDriftGenerator(concept1,concept2,15000,1000);

    When ClassificationFunction is 1, HelperSineGenerator labels all points that satisfy x1 < sin(x2) as 1, otherwise the function labels them as 0. When ClassificationFunction is 3, this is reversed. That is, HelperSineGenerator labels all points that satisfy x1 >= sin(x2) as 1, otherwise the function labels them as 0 [2]. The software returns the data in matrices for using in incremental learners.

    HelperConceptDriftGenerator establishes the concept drift. The object uses a sigmoid function 1./(1+exp(-4*(numobservations-position)./width)) to decide the probability of choosing the first stream when generating data [3]. In this case, the position argument is 15000 and the width argument is 1000. As the number of observations exceeds the position value minus half of the width, the probability of sampling from the first stream when generating data decreases. The sigmoid function allows a smooth transition from one stream to the other. Larger width values indicate a larger transition period where both streams are approximately equally likely to be selected.

    Initiate an incremental drift-aware model for classification as follows:

    1. Create an incremental Naive Bayes classification model for binary classification.

    2. Initiate an incremental concept drift detector that uses the Hoeffding's Bounds Drift Detection Method with moving average (HDDMA).

    3. Using the incremental linear model and the concept drift detector, initiate an incremental drift-aware model. Specify the training period as 5000 observations.

    BaseLearner = incrementalClassificationNaiveBayes(MaxNumClasses=2,Metrics="classiferror");
    dd = incrementalConceptDriftDetector("hddma");
    idal = incrementalDriftAwareLearner(BaseLearner,DriftDetector=dd,TrainingPeriod=5000);

    Preallocate the number of variables in each chunk and number of iterations for creating a stream of data.

    numObsPerChunk = 10;
    numIterations = 4000;

    Preallocate the variables for tracking the drift status and drift time, and storing the classification error.

    dstatus = zeros(numIterations,1);
    statusname = strings(numIterations,1);
    driftTimes = [];
    ce = array2table(zeros(numIterations,2),VariableNames=["Cumulative" "Window"]);

    Simulate a data stream with incoming chunks of 10 observations each and perform incremental drift-aware learning. At each iteration:

    1. Simulate predictor data and labels, and update driftGenerator using the helper function hgenerate.

    2. Call updateMetricsAndFit to update the performance metrics and fit the incremental drift-aware model to the incoming data.

    3. Track and record the drift status and the classification error for visualization purposes.

    rng(12); % For reproducibility
    
    for j = 1:numIterations
     
     % Generate data
     [driftGenerator,X,Y] = hgenerate(driftGenerator,numObsPerChunk); 
    
     % Update performance metrics and fit
     idal = updateMetricsAndFit(idal,X,Y); 
    
     % Record drift status and classification error
     statusname(j) = string(idal.DriftStatus); 
     ce{j,:} = idal.Metrics{"ClassificationError",:};
     if idal.DriftDetected
           dstatus(j) = 2;  
        elseif idal.WarningDetected
           dstatus(j) = 1;
        else 
           dstatus(j) = 0;
        end   
     if idal.DriftDetected
        driftTimes(end+1) = j; 
     end
     
    end

    Plot the cumulative and per window classification error. Mark the warmup and training periods, and where the drift was introduced.

    h = plot(ce.Variables);
    
    xlim([0 numIterations])
    ylim([0 0.22])
    ylabel("Classification Error")
    xlabel("Iteration")
    
    xline(idal.MetricsWarmupPeriod/numObsPerChunk,"g-.","Warmup Period",LineWidth=1.5)
    xline(idal.MetricsWarmupPeriod/numObsPerChunk+driftTimes,"g-.","Warmup Period",LineWidth=1.5)
    xline(idal.TrainingPeriod/numObsPerChunk,"b-.","Training Period",LabelVerticalAlignment="middle",LineWidth=1.5)
    xline(driftTimes,"m--","Drift",LabelVerticalAlignment="middle",LineWidth=1.5)
    
    legend(h,ce.Properties.VariableNames)
    legend(h,Location="best")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Classification Error contains 6 objects of type line, constantline. These objects represent Cumulative, Window.

    The updateMetricsAndFit function first evaluates the performance of the model by calling updateMetrics on incoming data, and then fits the model to data by calling fit:

    The updateMetrics function evaluates the performance of the model as it processes incoming observations. The function writes specified metrics, measured cumulatively and within a specified window of processed observations, to the Metrics model property.

    The fit function fits the model by updating the base learner and monitoring for drift given an incoming batch of data. When you call fit, the software performs the following procedure:

    • Trains the model up to NumTrainingObservations observations.

    • After training, the software starts tracking the model loss to see if any concept drift has occurred and updates drift status accordingly.

    • When the drift status is Warning, the software trains a temporary model to replace theBaseLearner in preparation for an imminent drift.

    • When the drift status is Drift, temporary model replaces the BaseLearner.

    • When the drift status is Stable, the software discards the temporary model.

    For more information, see the Algorithms section.

    Plot the drift status versus the iteration number.

    gscatter(1:numIterations,dstatus,statusname,"gmr","o",5,"on","Iteration","Drift Status","filled")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Drift Status contains 3 objects of type line. One or more of the lines displays its values using only markers These objects represent Stable, Warning, Drift.

    Create the random concept data and the concept drift generator using the helper functions HelperRegrGenerator and HelperConceptDriftGenerator, respectively.

    concept1 = HelperRegrGenerator(NumFeatures=100,NonZeroFeatures=[1,20,40,50,55], ...
        FeatureCoefficients=[4,5,10,-2,-6],NoiseStd=1.1,TableOutput=false);
    concept2 = HelperRegrGenerator(NumFeatures=100,NonZeroFeatures=[10,20,45,56,80], ...
        FeatureCoefficients=[4,5,10,-2,-6],NoiseStd=1.1,TableOutput=false);
    driftGenerator = HelperConceptDriftGenerator(concept1,concept2,15000,1000);

    HelperRegrGenerator generates streaming data using features and feature coefficients for regression specified in the call to the function. At each step, the function samples the predictors from a normal distribution. Then, the function computes the response using the feature coefficients and predictor values and adding a random noise from a normal distribution with mean zero and specified noise standard deviation. The software returns the data in matrices for using in incremental learners.

    HelperConceptDriftGenerator establishes the concept drift. The object uses a sigmoid function 1./(1+exp(-4*(numobservations-position)./width)) to decide the probability of choosing the first stream when generating data [3]. In this case, the position argument is 15000 and the width argument is 1000. As the number of observations exceeds the position value minus half of the width, the probability of sampling from the first stream when generating data decreases. The sigmoid function allows a smooth transition from one stream to the other. Larger width values indicate a larger transition period where both streams are approximately equally likely to be selected.

    Initiate an incremental drift-aware model for regression as follows:

    1. Create an incremental linear model for regression. Specify the linear regression model type and solver type.

    2. Initiate an incremental concept drift detector that uses the Hoeffding's Bounds Drift Detection Method with moving average (HDDMA).

    3. Using the incremental linear model and the concept drift detector, instantiate an incremental drift-aware model. Specify the training period as 6000 observations.

    baseMdl = incrementalRegressionLinear(Learner="leastsquares",Solver="sgd",EstimationPeriod=1000,Standardize=false);
    dd = incrementalConceptDriftDetector("hddma",Alternative="greater",InputType="continuous",WarmupPeriod=1000);
    idal = incrementalDriftAwareLearner(baseMdl,DriftDetector=dd,TrainingPeriod=6000);

    Preallocate the number of variables in each chunk and number of iterations for creating a stream of data.

    numObsPerChunk = 10;
    numIterations = 4000;

    Preallocate the variables for tracking the drift status and drift time, and storing the regression error.

    dstatus = zeros(numIterations,1);
    statusname = strings(numIterations,1);
    driftTimes = [];
    ce = array2table(zeros(numIterations,2),VariableNames=["Cumulative" "Window"]);

    Simulate a data stream with incoming chunks of 10 observations each and perform incremental drift-aware learning. At each iteration:

    1. Simulate predictor data and labels, and update the drift generator using the helper function hgenerate.

    2. Call updateMetricsAndFit to update the performance metrics and fit the incremental drift-aware model to the incoming data.

    3. Track and record the drift status and the regression error for visualization purposes.

    rng(12); % For reproducibility
    
    for j = 1:numIterations
     
     % Generate data
     [driftGenerator,X,Y] = hgenerate(driftGenerator,numObsPerChunk); 
    
     % Update performance metrics and fit
     idal = updateMetricsAndFit(idal,X,Y); 
    
     % Record drift status and regression error
     statusname(j) = string(idal.DriftStatus); 
     ce{j,:} = idal.Metrics{"MeanSquaredError",:};
     if idal.DriftDetected
           dstatus(j) = 2;  
        elseif idal.WarningDetected
           dstatus(j) = 1;
        else 
           dstatus(j) = 0;
        end   
     if idal.DriftDetected
        driftTimes(end+1) = j; 
     end
    end

    Plot the cumulative and per window regression error. Mark the warmup and training periods, and where the drift was introduced.

    h = plot(ce.Variables);
    
    xlim([0 numIterations])
    ylabel("Mean Squared Error")
    xlabel("Iteration")
    
    xline((idal.MetricsWarmupPeriod+idal.BaseLearner.EstimationPeriod)/numObsPerChunk,"g-.","Warmup Period",LineWidth=1.5)
    xline(idal.TrainingPeriod/numObsPerChunk,"b-.","Training Period",LabelVerticalAlignment="middle",LineWidth=1.5)
    xline(driftTimes,"m--","Drift",LabelVerticalAlignment="middle",LineWidth=1.5)
    
    legend(h,ce.Properties.VariableNames)
    legend(h,Location="best")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Mean Squared Error contains 5 objects of type line, constantline. These objects represent Cumulative, Window.

    Plot the drift status versus the iteration number.

    gscatter(1:numIterations,dstatus,statusname,'gmr','o',5,'on',"Iteration","Drift Status","filled")

    Figure contains an axes object. The axes object with xlabel Iteration, ylabel Drift Status contains 2 objects of type line. One or more of the lines displays its values using only markers These objects represent Stable, Drift.

    Algorithms

    expand all

    References

    [1] Barros, Roberto S.M. , et al. "RDDM: Reactive drift detection method." Expert Systems with Applications. vol. 90, Dec. 2017, pp. 344-55. https://doi.org/10.1016/j.eswa.2017.08.023.

    [2] Bifet, Albert, et al. "New Ensemble Methods for Evolving Data Streams." Proceedings of the 15th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining. ACM Press, 2009, p. 139. https://doi.org/10.1145/1557019.1557041.

    [3] Gama, João, et al. "Learning with drift detection". Advances in Artificial Intelligence – SBIA 2004, edited by Ana L. C. Bazzan and Sofiane Labidi, vol. 3171, Springer Berlin Heidelberg, 2004, pp. 286–95. https://doi.org/10.1007/978-3-540-28645-5_29.

    Version History

    Introduced in R2022b