All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.search.aggregations.pipeline.SimulatedAnealingMinimizer Maven / Gradle / Ivy

There is a newer version: 8.14.0
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.search.aggregations.pipeline;

import org.elasticsearch.common.collect.EvictingQueue;

/**
 * A cost minimizer which will fit a MovAvgModel to the data.
 *
 * This optimizer uses naive simulated annealing.  Random solutions in the problem space
 * are generated, compared against the last period of data, and the least absolute deviation
 * is recorded as a cost.
 *
 * If the new cost is better than the old cost, the new coefficients are chosen.  If the new
 * solution is worse, there is a temperature-dependent probability it will be randomly selected
 * anyway.  This allows the algo to sample the problem space widely.  As iterations progress,
 * the temperature decreases and the algorithm rejects poor solutions more regularly,
 * theoretically honing in on a global minimum.
 */
public class SimulatedAnealingMinimizer {

    /**
     * Runs the simulated annealing algorithm and produces a model with new coefficients that, theoretically
     * fit the data better and generalizes to future forecasts without overfitting.
     *
     * @param model         The MovAvgModel to be optimized for
     * @param train         A training set provided to the model, which predictions will be
     *                      generated from
     * @param test          A test set of data to compare the predictions against and derive
     *                      a cost for the model
     * @return              A new, minimized model that (theoretically) better fits the data
     */
    public static MovAvgModel minimize(MovAvgModel model, EvictingQueue train, double[] test) {

        double temp = 1;
        double minTemp = 0.0001;
        int iterations = 100;
        double alpha = 0.9;

        MovAvgModel bestModel = model;
        MovAvgModel oldModel = model;

        double oldCost = cost(model, train, test);
        double bestCost = oldCost;

        while (temp > minTemp) {
            for (int i = 0; i < iterations; i++) {
                MovAvgModel newModel = oldModel.neighboringModel();
                double newCost = cost(newModel, train, test);

                double ap = acceptanceProbability(oldCost, newCost, temp);
                if (ap > Math.random()) {
                    oldModel = newModel;
                    oldCost = newCost;

                    if (newCost < bestCost) {
                        bestCost = newCost;
                        bestModel = newModel;
                    }
                }
            }

            temp *= alpha;
        }

        return bestModel;
    }

    /**
     * If the new cost is better than old, return 1.0.  Otherwise, return a double that increases
     * as the two costs are closer to each other.
     *
     * @param oldCost   Old model cost
     * @param newCost   New model cost
     * @param temp      Current annealing temperature
     * @return          The probability of accepting the new cost over the old
     */
    private static double acceptanceProbability(double oldCost, double newCost, double temp) {
        return newCost < oldCost ? 1.0 : Math.exp(-(newCost - oldCost) / temp);
    }

    /**
     * Calculates the "cost" of a model.  E.g. when run on the training data, how closely do the  predictions
     * match the test data
     *
     * Uses Least Absolute Differences to calculate error.  Note that this is not scale free, but seems
     * to work fairly well in practice
     *
     * @param model     The MovAvgModel we are fitting
     * @param train     A training set of data given to the model, which will then generate predictions from
     * @param test      A test set of data to compare against the predictions
     * @return          A cost, or error, of the model
     */
    private static double cost(MovAvgModel model, EvictingQueue train, double[] test) {
        double error = 0;
        double[] predictions = model.predict(train, test.length);

        assert (predictions.length == test.length);

        for (int i = 0; i < predictions.length; i++) {
            error += Math.abs(test[i] - predictions[i]);
        }

        return error;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy