//////////////////////////////////////////////////////////////////////
//
//	AdaptiveDirectionRandomSearchOptimizer.h: interface of the ADRS optimizer.
//
/////////////////////////////////////////////////////////////////////////

#ifndef _ADAPTIVE_DIRECTION_RANDOM_SEARCH_OPTIMIZER_
#define _ADAPTIVE_DIRECTION_RANDOM_SEARCH_OPTIMIZER_

#include "core/optimization/blackbox/SimpleOptimizer.h"
#include "core/optimization/blackbox/Definitions_core_opt.h"

namespace OPTIMIZATION
{
  ///
  ///	Class AdaptiveDirectionRandomSearchOptimizer
  ///
  ///	HowToUse:
  ///	
  ///	  * specify in the constructor call the num of points that are optimized in a "simultanious" way
  ///	  * to use others than the default parameters use the setControlSeqParams call which changes the
  ///		parameters that are responsible for a "scale down" of b_k by b_fac if there was no function
  ///		decrease for b_times times
  ///	  *	to use others than the default parameters use the setRecallParams call wich changes the
  ///		parameters that are responsible for the balance between a new random direction an the old
  ///		successfull iteration directions
  ///	  * use the setLowerParameterBounds and the setUpperParameterBounds to specify the area to generate
  ///		random start points in (THIS IS NESSECARY!)
  ///	  *	to use a function value threshold for the random start points' values to be below - use the
  ///		setInitFunctionValueThresh call
  ///	  *	call init()
  ///	  * call optimize()
  ///
  ///	Implemented Abort criteria:
  ///		
  ///	  * maximum number of iterations
  ///	  * parameter tolerance
  ///	  *	time limit
  ///
  ///
  class AdaptiveDirectionRandomSearchOptimizer : public SimpleOptimizer
  {
    public:

      typedef  SimpleOptimizer SuperClass;
      typedef  OPTIMIZATION::matrix_type matrix_type;
      ///	
      ///		Constructor.
      ///		@param numOfPoints: Number of Points to optimize
      ///		@param loger : OptLogBase * to existing log class
      ///
      AdaptiveDirectionRandomSearchOptimizer(unsigned int numOfPoints, OptLogBase *loger=NULL);
      
      ///
      ///	Copy constructor
      ///	@param opt .. optimizer to copy
      ///
      AdaptiveDirectionRandomSearchOptimizer( const AdaptiveDirectionRandomSearchOptimizer &opt);

      ///
      ///	operator =
      ///
      AdaptiveDirectionRandomSearchOptimizer & operator=(const AdaptiveDirectionRandomSearchOptimizer &opt);

            ///
      ///
      ///		Destructor.
            ///
            ~AdaptiveDirectionRandomSearchOptimizer();

      ///
      ///	enumeration for the return reasons of an optimizer,
      ///	has all elements of the SuperClass optimizer
      ///

    
      ///
      ///	@brief Do internal initializations
      ///
      void init();
      
      ///
      ///	@brief start the optmization
      ///
      int optimize();

      ///
      ///	@brief set the parameters for the control sequence
      ///			
      ///	@param b0 > 0
      ///	@param bfac: 0 < bfac < 1
      ///	@param bThresTimesNotDecreased
      ///
      ///	\return true in case of success
      ///
      bool setControlSeqParams(double b0, double bfac, unsigned int bThresTimesNotDecreased, double bBreak);
      
      
      ///
      /// @brief Enables advanced initialization of random start points. If activated, start points will be randomly distributed according to the upper and lower bound vectors.
      ///
      /// @param enable if true, advanced initialization will be enabled
      /// @param lowerBound matrix containing lower bounds for random initialization (must be nx1 with n= number of Parameters)
      /// @param upperBound matrix containing upper bounds for random initialization (must be nx1 with n= number of Parameters)
      ///
      void activateAdvancedInit(bool enable, matrix_type& lowerBounds, matrix_type& upperBounds);

      
      ///
      ///	@brief set recall parameters that control the incluence of prior iterations on the actual one. This is the key idea of the adaptive direction approach
      ///	
      ///	The update formula for the iteration scheme is
      ///
      ///	$$
      ///		d_k = c_0 * d_{k-1} + c_1 \triangle x_{k-1}
      ///	$$
      ///	with
      ///		if( $\delta_{k-1} == 1$)
      ///		{
      ///			$ c_0 = c0s,\enskip c_1 = c_1s $
      ///			and
      ///			$0 < c0s < 1;\enskip c1s  >0 ;\enskip c0s + c1s > 1 $
      ///		}
      ///		else
      ///		{
      ///					$ c_0 = c0f,\enskip c_1 = c_1f $
      ///			and
      ///			$0 < c0f < 1;\enskip c1f  < 0 ;\enskip | c0s + c1s |  < 1 $
      ///					}
      ///				and 
      ///					\|d_k\| < D * b_k 
      ///			
      ///	@param c0s
      ///	@param c1s
      ///	@param c0f
      ///	@param c1f
      ///	@param D
      ///
      ///	\return true in case of success
      ///
      bool setRecallParams(double c0s, double c1s, double c0f, double c1f, double D);

      ///
      ///	@brief set Number of Points
      ///	@param num number of points
      ///
      inline void setNumberOfPoints(unsigned int num){m_numberOfParallelPoints = num;};

      ///
      ///	@brief set a threshold for the initial points
      ///	@param active is the threshold active?
      ///	@param threshold .. the threshold to be below (above in case of maximization)
      ///
      inline void setInitFunctionValueThresh(bool active, double threshold){m_initFuncThreshActive = active;m_initFuncTresh = threshold;};



    private:

      ///
      ///	number of parallel point optimizations
      ///
      unsigned int m_numberOfParallelPoints;

      ///
      ///	matrix of the whole parameter set
      ///
      matrix_type m_Parameters;

      ///
      ///	matrix of costfunction Values
      ///
      matrix_type m_CurrentCostFunctionValues;

      ///
      ///	generate new points
      ///
      matrix_type generatePoints();

      ///
      ///	generate new points
      ///
      matrix_type generatePoint();

      ///
      ///	@brief accept a new point or reject it
      ///	@param newValue : new objective function value
      ///	@param oldValue : old objective function value
      ///	
      ///
      void acceptPoints(matrix_type oldValues, matrix_type newValues);

      bool *m_pointsAccepted;

      ///
      ///	control sequence parameter b0
      ///
      double m_b0;

      ///
      ///	control sequence parameter bfac
      ///
      double m_bfac;

      ///
      ///	control sequence parameter bk
      ///
      double *m_bk;

      ///
      ///	control sequence multiplikation trigger threshold
      ///
      unsigned int m_bThresTimesNotDecreased;

      ///
      ///	control sequence parameter bBreak
      ///
      double m_bBreak;

      ///
      ///	backup point 
      ///
      matrix_type m_backupPoint;

      ///
      ///	backup point Value
      ///
      double m_backupPointValue;

      ///
      ///	backup point in use?
      ///
      bool m_backupActive;

      ///
      ///	direction parameter c0s
      ///
      double m_c0s;

      ///
      ///	direction parameter c1s
      ///
      double m_c1s;

      ///
      ///	direction parameter c0f
      ///
      double m_c0f;

      ///
      ///	direction parameter c1f
      ///
      double m_c1f;

      ///
      ///	recall limit
      ///
      double m_D;

      ///
      ///	is the initial function value threshold	active		
      ///
      bool m_initFuncThreshActive;

      ///
      ///	the initial function value threshold active		
      ///
      double m_initFuncTresh;
      
      ///
      /// enables advanced initialization
      bool m_advancedInit;
      
      ///
      /// lower bounds for advanced initialization
      ///
      matrix_type m_advancedinitLowerBounds;
      
      ///
      /// upper bounds for advanced initialization
      matrix_type m_advancedinitUpperBounds;

  };//class
} //namespace

#endif