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

com.meliorbis.numerics.fixedpoint.MultivariateBoundedFPFinder 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 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;
		}
		
	}
	
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy