content: /*
   * Copyright (C) 2015 Martin Berger
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
   */
  package edu.stanford.rsl.conrad.optimization;
  
  import edu.stanford.rsl.jpop.GradientOptimizableFunction;
  
  /**
   * This class wraps an arbitrary number of jpop cost-functions into a combined cost-function value.
   * It uses Lagrange multipliers that can be set for each function individually.
   * Combining analytic gradients is also supported in case all functions provide an analytic gradient.
   * @author Martin Berger
   */
  public class CombinedGradientOptimizableFunction implements
  GradientOptimizableFunction {
  
  	GradientOptimizableFunction[] stackedFunctions;
  	double[] lambdas; 
  
  	@Override
  	public void setNumberOfProcessingBlocks(int number) {
  		for(GradientOptimizableFunction f : stackedFunctions)
  			f.setNumberOfProcessingBlocks(number);
  	}
  
  	@Override
  	public int getNumberOfProcessingBlocks() {
  		return stackedFunctions[0].getNumberOfProcessingBlocks();
  	}
  
  	@Override
  	public double evaluate(double[] x, int block) {
  		double result = 0;
  		for (int i = 0; i < stackedFunctions.length; i++) {
  			if(lambdas[i]!=0)
  				result += lambdas[i]*stackedFunctions[i].evaluate(x, block);
  		}
  		return result;
  	}
  
  	@Override
  	public double[] gradient(double[] x, int block) {
  		double[] grads = null;
  		for (int i = 0; i < this.stackedFunctions.length; i++) {
  			if (lambdas[i]!=0){
  				double[] res = stackedFunctions[i].gradient(x, block);
  				if (res!=null){
  					if(grads==null)
  						grads = new double[x.length];
  					for (int j = 0; j < grads.length; j++) {
  						grads[j]+=lambdas[i]*res[j];
  					}
  				}else
  					return null;
  			}
  		}
  		return grads;
  	}
  
  	public GradientOptimizableFunction[] getStackedFunctions() {
  		return stackedFunctions;
  	}
  
  	public void setStackedFunctions(
  			GradientOptimizableFunction[] stackedFunctions) {
  		this.stackedFunctions = stackedFunctions;
  	}
  
  	public double[] getLambdas() {
  		return lambdas;
  	}
  
  	public void setLambdas(double[] lambdas) {
  		this.lambdas = lambdas;
  	}
  
  }
  