com.meliorbis.numerics.fixedpoint.MultivariateBoundedFPFinder 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 java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.math3.util.Precision;
import com.meliorbis.numerics.NumericsException;
import com.meliorbis.numerics.function.MultiVariateVectorFunction;
/**
* Allows bounds to be defined on a per-input basis and dampens all adjustments uniformly to
* maintain those bounds
*
* @author Tobias Grasl
*/
public class MultivariateBoundedFPFinder extends MultiVariateNewtonFixedPointFinder
{
Logger LOG = Logger.getLogger(MultivariateBoundedFPFinder.class.getName());
private double[][] _bounds;
public MultivariateBoundedFPFinder(double precision_, double adjust_)
{
super(precision_, adjust_);
}
/**
* @param bounds_ The bounds for each input. If the i'th array is null then the i'th input is
* not bounded, and if either the lower (index 0) or upper (index 1) bound are NaN then the
* variable is not bounded in that direction
*/
public void setBounds(double[][] bounds_) {
_bounds = bounds_;
}
@Override
public double[] findFixedPoint(MultiVariateVectorFunction function_, double[] initialVals_)
{
// Check whether bounds are defined
if(_bounds == null)
{
LOG.warning("No bounds set, performing unbounded adjustment");
}
else
{
for(int i = 0; i < initialVals_.length; i++)
{
// This input is not bounded
if(_bounds[i] == null) {
continue;
}
// Check lower bound
if(!Double.isNaN(_bounds[i][0]) && initialVals_[i] < _bounds[i][0])
{
throw new NumericsException(String.format("Input [%s] out of bounds: %.2f < %.2f",i,
initialVals_[i],_bounds[i][0]));
}
// Check upper bound
if(!Double.isNaN(_bounds[i][1]) && initialVals_[i] > _bounds[i][1])
{
throw new NumericsException(String.format("Input [%s] out of bounds: %.2f > %.2f",i,
initialVals_[i],_bounds[i][1]));
}
}
}
return super.findFixedPoint(function_, initialVals_);
}
@Override
protected void adjustAdjustment(Double[] currentInputs_, double[] adjustment_)
{
assert currentInputs_.length == adjustment_.length :
"Number of adjustments must equal number of inputs";
// Check whether bounds are defined
if(_bounds == null)
{
LOG.warning("No bounds set, performing unbounded adjustment");
return;
}
assert currentInputs_.length == _bounds.length :
"Number of bounds must equal number of inputs";
double factor = 1;
for(int i = 0; i < currentInputs_.length; i++)
{
// This input is not bounded
if(_bounds[i] == null) {
continue;
}
double adjustedVal = currentInputs_[i] + adjustment_[i];
// Only need to check one bound depending on sign of adjustment
if(adjustment_[i] < 0)
{
// Check lower bound, if defined
if(!Double.isNaN(_bounds[i][0]) && adjustedVal < _bounds[i][0])
{
double requiredFactor = (_bounds[i][0] - currentInputs_[i])/(adjustment_[i]);
if(Precision.equals(requiredFactor, 0,1e-10)) {
LOG.info(String.format("Not adjutsting input %s, already at "
+ "lower bound", i));
adjustment_[i] = 0;
continue;
} else if(LOG.isLoggable(Level.INFO))
{
LOG.info(String.format("Adjustmenent will be damped by %.2f to maintain "
+ "lower bound of input %s", requiredFactor, i));
}
factor = Math.min(factor, requiredFactor);
}
}
else
{
if(!Double.isNaN(_bounds[i][1]) && adjustedVal > _bounds[i][1])
{
double requiredFactor = (_bounds[i][1] - currentInputs_[i])/adjustment_[i];
if(Precision.equals(requiredFactor, 0,1e-10)) {
LOG.info(String.format("Not adjutsting input %s, already at "
+ "upper bound", i));
adjustment_[i] = 0;
continue;
} else if(LOG.isLoggable(Level.INFO))
{
LOG.info(String.format("Adjustment will be damped by %.2f to maintain "
+ "upper bound of input %s", requiredFactor, i));
}
factor = Math.min(factor, requiredFactor);
}
}
}
// Finally, adjust the adjustment appropriately
for(int i = 0; i < currentInputs_.length; i++)
{
adjustment_[i] *= factor;
}
}
}