/*
 * Copyright 2015, Yahoo Inc.
 * Copyrights licensed under the GPL License.
 * See the accompanying LICENSE file for terms.
 */

/*
 * Description: ModelAdapter applies a set of time-series models (algorithms) on a given metric. ModelAdapter provides
 * concrete mechanisms to apply one or more abstract algorithms on a time-series at the execution time; in other words,
 * application of a certain algorithm (model) on a given time series should be carried out via a ModelAdapter object.
 * The direct application of models on time series is discouraged in EGADS unless for test purposes.
 * 
 * Inputs: 1. The 'metric' time series - Either an explicit TimeSeries object - or the String name of the time series
 * which would require the ModelAdapter to connect to ModelDB to load the appropriate models into the memory (under
 * construction)
 * 
 * 2. The model(s) - Either an explicit TimeSeriesModel object via addModel() - or implicitly loaded from ModelDB when
 * the metric name is provided (under construction)
 * 
 * Features: 1. Resetting all the added models via reset() 2. Training all the added models on the 'metric' via train()
 * 3. Updating all the added models for a new time series sequence via update() 4. Forecasting the value of the time
 * series according to all the added models for a given time period via forecast()
 * 
 * Details: 1. The time units for interfacing with a ModelAdapter object is the standard UNIX timestamp; however,
 * ModelAdapter automatically performs logical indexing conversion for the abstract algorithms so that the actual models
 * can conveniently work with the logical index instead of UNIX timestamps. The conversion is:
 * 
 * logical_index = (UNIX_timestamp - firstTimeStamp) div period UNIX_timestamp = logical_index * period + firstTimeStamp
 */

package com.yahoo.egads.control;

import java.util.ArrayList;

import com.yahoo.egads.data.TimeSeries;
import com.yahoo.egads.models.tsmm.TimeSeriesModel;

public class ModelAdapter { // Encapsulates a metric and the models operating on it

    protected TimeSeries metric = null;
    protected ArrayList models = new ArrayList();
    protected ArrayList isTrained = new ArrayList();
    protected long firstTimeStamp = 0;
    protected long period;

    // Construction ///////////////////////////////////////////////////////////

    public ModelAdapter(TimeSeries theMetric, long period, long firstTimeStamp) throws Exception {
        if (theMetric == null) {
            throw new Exception("The input metric is null.");
        }

        metric = theMetric;
        this.period = period;
        this.firstTimeStamp = firstTimeStamp;
    }

    public ModelAdapter(TimeSeries theMetric, long period) throws Exception {
        if (theMetric == null) {
            throw new Exception("The input metric is null.");
        }

        metric = theMetric;
        this.period = period;

        if (metric.data.size() > 0) {
            this.firstTimeStamp = metric.time(0);
        }
    }

    public ModelAdapter(String theMetric, long period) throws Exception {
        this.period = period;
        // TODO:
        // 1 - load the models related to theMetric from ModelDB
        // 2 - push the loaded models into 'models'
        // 3 - create a new TimeSeries for theMetric and set 'metric'
        // 4 - set 'firstTimeStamp'

        int modelNum = models.size();
        for (int i = 0; i < modelNum; ++i) {
            isTrained.set(i, true);
        }
    }

    // Configuration Methods ////////////////////////////////////////////////////////////////

    public void setMetric(TimeSeries theMetric, long period) {
        metric = theMetric;
        this.period = period;

        if (metric.data.size() > 0) {
            this.firstTimeStamp = metric.time(0);
        }

        reset();
    }

    public void setMetric(TimeSeries theMetric, long period, long firstTimeStamp) {
        metric = theMetric;
        this.period = period;
        this.firstTimeStamp = firstTimeStamp;
        reset();
    }

    public void setMetric(String theMetric, long period) {
        this.period = period;
        firstTimeStamp = 0;
        models.clear();
        isTrained.clear();

        // TODO:
        // 1 - load the models related to theMetric from ModelDB
        // 2 - push the loaded models into 'models'
        // 3 - create a new TimeSeries for theMetric and set 'metric'
        // 4 - set 'firstTimeStamp'

        int modelNum = models.size();
        for (int i = 0; i < modelNum; ++i) {
            isTrained.set(i, true);
        }
    }

    public void addModel(TimeSeriesModel model) {
        model.reset();
        models.add(model);
        isTrained.add(false);
    }

    public String[] getModelNames() {
        String[] names = new String[models.size()];
        for (int i = 0; i < models.size(); ++i) {
            names[i] = models.get(i).getModelName();
        }

        return names;
    }

    // Algorithmic Methods ////////////////////////////////////////////////////////////////////

    public void reset() {
        int i = 0;
        for (TimeSeriesModel model : models) {
            model.reset();
            isTrained.set(i, false);
            i++;
        }
    }

    public void train() throws Exception {
        int i = 0;

        metric.data.setLogicalIndices(firstTimeStamp, period);

        for (TimeSeriesModel model : models) {
            if (!isTrained.get(i)) {
                model.train(metric.data);
                isTrained.set(i, true);
            }
            i++;
        }
    }

    public void update(TimeSeries.DataSequence newData) throws Exception {
        if (newData == null) {
            throw new Exception("The input data sequence is null.");
        }

        for (Boolean b : isTrained) {
            if (!b) {
                throw new Exception("All the models need to be trained before updating.");
            }
        }

        if (newData.size() > 0) {
            newData.setLogicalIndices(firstTimeStamp, period);

            for (TimeSeriesModel model : models) {
                model.update(newData);
            }
        }
    }

    public ArrayList forecast(long from, long to) throws Exception {
        for (Boolean b : isTrained) {
            if (!b) {
                throw new Exception("All the models need to be trained before forecasting.");
            }
        }

        ArrayList result = new ArrayList();

        for (TimeSeriesModel model : models) {
        	TimeSeries.DataSequence sequence = null;
        	if (period != -1) {
        		sequence = new TimeSeries.DataSequence(from, to, period);
        		sequence.setLogicalIndices(firstTimeStamp, period);
        	} else {
        		sequence = new TimeSeries.DataSequence(metric.data.getTimes(), metric.data.getValues());
        	}

        	model.predict(sequence);
            result.add(sequence);
        }
        return result;
    }
}

 

Ads help maintain this website.