com.meliorbis.numerics.fixedpoint.AlternateApproachFixedPointFinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Numerics Show documentation
Show all versions of Numerics Show documentation
A library for working with large multi-dimensional arrays and the functions they represent
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_;
}
}