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

com.meliorbis.numerics.fixedpoint.AlternateApproachFixedPointFinder Maven / Gradle / Ivy

Go to download

A library for working with large multi-dimensional arrays and the functions they represent

There is a newer version: 1.2
Show newest version
package com.meliorbis.numerics.fixedpoint;

import org.apache.commons.lang.ArrayUtils;

import com.meliorbis.numerics.NumericsException;
import com.meliorbis.numerics.function.MultiVariateVectorFunction;

/**
 * Created by toby on 28/01/2014.
 */
public class AlternateApproachFixedPointFinder implements FixedPointFinder
{
    private final Double _precision;
    private double _damping;

    public AlternateApproachFixedPointFinder(Double precision_, Double damping__)
    {
        _precision = precision_;
        _damping = damping__;
    }
    @Override
    public double[] findFixedPoint(MultiVariateVectorFunction function_, double[] initialVals_)
    {

        Double error;

        Double[] currentInputs = ArrayUtils.toObject(initialVals_);

        // Makes it easier to switch to relatively sized adjustments
        Double lastDelta = null;
        int backTrack = 0;

        double lastError = Double.POSITIVE_INFINITY;

        int lastAdjustIndex = 0;
        Double lastDiff = null;

        do
        {
            try
            {
                error =0d;

                Double[] implied = function_.call(currentInputs);

                int adjustIndex = -1;

                // Compare each one to the assumed state and update the criterion to be the maximum relative difference
                for(int varIndex = 0; varIndex < currentInputs.length; varIndex++)
                {
                    if(Double.isNaN(implied[varIndex]))
                    {
                        throw new NumericsException("fn returned NaN");
                    }

                    Double currError = Math.abs(implied[varIndex] - currentInputs[varIndex]);

                    if(error < currError)
                    {
                        error = currError;
                    }
                }

                // Solution found!
                if(error < _precision)
                {
                    return ArrayUtils.toPrimitive(currentInputs);
                }

                System.out.println(String.format("Current distance: %s", error));

                // If we moved further from a solution, go half way back
                if(error > lastError)
                {
                    throw new RuntimeException("Error increased");
                }

                // Otherwise, update the calc state
                final double diff = implied[adjustIndex] - currentInputs[adjustIndex];

                // Did the same dimension get updated last time?
                if(lastDelta != null && lastAdjustIndex == adjustIndex &&
                        Math.signum(diff) == Math.signum(lastDelta) && _damping == 1d)
                {
                    // Increasing the input increases the output
                    // Note lastDelta should be greater than diff almost surely otherwise the rel error would have
                    // increased
                    double change = diff/((lastDiff-diff)/lastDelta);

                    if(Math.abs(change) > 2 * Math.abs(diff))
                    {
                        change /= 2d;
                    }

                    lastDelta = change;
                }
                else
                {
                    lastDelta = diff *_damping;
                }

                lastError = error;
                lastDiff = diff;
                lastAdjustIndex = adjustIndex;

                // Update the input to move toward the implied
                currentInputs[adjustIndex] += lastDelta;
                backTrack = 0;

            } catch (Exception e)
            {
                System.out.println("Caught Exception: " + e.getMessage());
                e.printStackTrace();
                System.out.println(String.format("Backtracking (%s times so far)",++backTrack));

                if(backTrack > 8)
                {
                    throw new RuntimeException("Found local maximum but not fixed point");
                }

                if(lastDelta == null)
                {
                    throw new RuntimeException("Failed first time!");
                }

                // Go half way back to last known good
                lastDelta /= 2d;
                currentInputs[lastAdjustIndex] -= lastDelta;
            }

        }
        while(true);
    }

    @Override
    public void setDamping(double damping_)
    {
        _damping = damping_;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy