content: package edu.stanford.rsl.conrad.fitting;
  
  import java.util.Random;
  
  /**
   * Method for RANSACing with constraints on the parameter bounds.
   * Tries that create out-of-bounds solutions are not counted.
   * 
   * @author Jiang
   *
   */
  public class ConstrainedRANSACFittedFunction extends RANSACFittedFunction {
  
  	/**
  	 * Uneducational Constructor that initializes the bounds in a redandant way.
  	 * Prevents the software from crashing if no bounds are set.
  	 * 
  	 * @param func
  	 */
  	public ConstrainedRANSACFittedFunction(Function func) {
  		super(func);
  		upperbound = new double[func.getNumberOfParameters()];
  		lowerbound = new double[func.getNumberOfParameters()];
  		for (int i=0;i< func.getNumberOfParameters(); i++){
  			upperbound[i] = Double.POSITIVE_INFINITY;
  			lowerbound[i] = Double.NEGATIVE_INFINITY;
  		}
  	}
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = -4078810270398436119L;
  	private double [] upperbound;
  	private double [] lowerbound;
  
  	public void fitToPoints(double[] x, double[] y) {
  		int corresp = baseFunction.getMinimumNumberOfCorrespondences();
  		double bestFit = 0;
  
  		Function bestModel = null;
  		double [] randX = new double [corresp];
  		double [] randY = new double [corresp];
  		Random random = new Random();
  		for (int i = 0; i < numberOfTries; i++){
  			try {
  				Function currentTry = (Function) baseFunction.getClass().newInstance();			
  				// compute next try:
  				for (int j=0;j<corresp;j++){
  					int index = (int) (random.nextDouble() * (x.length-1));
  					randX[j] = x[index];
  					randY[j] = y[index];
  				}
  				currentTry.fitToPoints(randX, randY);
  				boolean parameterCheck = true;
  				double [] param =  currentTry.getParametersAsDoubleArray();
  				for (int j=0; j < currentTry.getNumberOfParameters(); j++){
  					if (param[j] > upperbound[j]) parameterCheck = false;
  					if (param[j] < lowerbound[j]) parameterCheck = false;
  				}
  				if (!parameterCheck) {
  					i--;
  				} else {
  					double fitness = evaluateModelFittnes(x, y, currentTry );
  					if (fitness > bestFit) {
  						bestModel = currentTry;
  						bestFit = fitness;
  					}
  				}
  			} catch (InstantiationException e) {
  				e.printStackTrace();
  			} catch (IllegalAccessException e) {
  				e.printStackTrace();
  			}
  		}
  		if ((bestModel != null)) {
  			baseFunction = bestModel;
  			fittingDone = true;
  		} else {
  			System.err.println("RANSACFittedFunction: Warining increasing epsilon to " + epsilon +"\nChoose a bigger epsilon or more tries in the future!");
  			epsilon *= 1.1;
  			fitToPoints(x, y);			
  		}
  	}
  
  	/**
  	 * @return the upperbound
  	 */
  	public double[] getUpperbound() {
  		return upperbound;
  	}
  
  	/**
  	 * @param upperbound the upperbound to set
  	 */
  	public void setUpperbound(double[] upperbound) {
  		this.upperbound = upperbound;
  	}
  
  	/**
  	 * @return the lowerbound
  	 */
  	public double[] getLowerbound() {
  		return lowerbound;
  	}
  
  	/**
  	 * @param lowerbound the lowerbound to set
  	 */
  	public void setLowerbound(double[] lowerbound) {
  		this.lowerbound = lowerbound;
  	}
  
  
  }
  