////////////////////////////////////////////////////////////////////// // // AdaptiveDirectionRandomSearchOptimizer.cpp: Implementation of the // ADRS Optimizer // // ////////////////////////////////////////////////////////////////////// #include "AdaptiveDirectionRandomSearchOptimizer.h" #include #include #include #include "numbase.h" // ice random #include "optimization/AdditionalIceUtils.h" #include "optimization/Opt_Namespace.h" using namespace optimization; AdaptiveDirectionRandomSearchOptimizer::AdaptiveDirectionRandomSearchOptimizer( unsigned int numOfPoints,OptLogBase *loger) : SuperClass(loger) { m_numberOfParallelPoints = numOfPoints; m_b0 = 1.0; m_bfac = 0.5; m_bThresTimesNotDecreased = 0; m_bk = new double[m_numberOfParallelPoints]; m_pointsAccepted = new bool[m_numberOfParallelPoints]; for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_bk[j] = m_b0; m_pointsAccepted[j]= false; } m_bBreak = 0.1; m_backupActive = false; m_c0f = 0.75; m_c0s = 0.75; m_c1f = -0.75; m_c1s = 1.25; m_D = 3; m_initFuncThreshActive = false; m_initFuncTresh = 0.0; // advanced initialization is turned off per default m_advancedInit= false; } AdaptiveDirectionRandomSearchOptimizer::AdaptiveDirectionRandomSearchOptimizer( const AdaptiveDirectionRandomSearchOptimizer &opt) : SuperClass(opt) { m_numberOfParallelPoints = opt.m_numberOfParallelPoints; m_Parameters = opt.m_Parameters; m_b0 = opt.m_b0; m_bfac = opt.m_bfac; m_bk = new double[m_numberOfParallelPoints]; for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_bk[j] = opt.m_bk[j]; } m_pointsAccepted = new bool[m_numberOfParallelPoints]; for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_pointsAccepted[j] = opt.m_pointsAccepted[j]; } m_bBreak = opt.m_bBreak; m_backupActive = opt.m_backupActive; m_backupPoint = opt.m_backupPoint; m_backupPointValue = opt.m_backupPointValue; m_bThresTimesNotDecreased = opt.m_bThresTimesNotDecreased; m_c0f = opt.m_c0f; m_c0s = opt.m_c0s; m_c1f = opt.m_c1f; m_c1s = opt.m_c1s; m_D = opt.m_D; m_initFuncThreshActive = opt.m_initFuncThreshActive; m_initFuncTresh = opt.m_initFuncTresh; // advanced init setup m_advancedInit= opt.m_advancedInit; m_advancedinitLowerBounds= opt.m_advancedinitLowerBounds; m_advancedinitUpperBounds= opt.m_advancedinitUpperBounds; } /* operator= */ AdaptiveDirectionRandomSearchOptimizer & AdaptiveDirectionRandomSearchOptimizer::operator=(const AdaptiveDirectionRandomSearchOptimizer &opt) { /* avoid self-copy */ if(this != &opt) { delete[] m_bk; delete[] m_pointsAccepted; /* =operator of SuperClass */ SuperClass::operator=(opt); /* own values: */ m_numberOfParallelPoints = opt.m_numberOfParallelPoints; m_Parameters = opt.m_Parameters; m_b0 = opt.m_b0; m_bfac = opt.m_bfac; m_bBreak = opt.m_bBreak; m_backupActive = opt.m_backupActive; m_backupPoint = opt.m_backupPoint; m_backupPointValue = opt.m_backupPointValue; m_bk = new double[m_numberOfParallelPoints]; for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_bk[j] = opt.m_bk[j]; } m_pointsAccepted = new bool[m_numberOfParallelPoints]; for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_pointsAccepted[j] = opt.m_pointsAccepted[j]; } m_bThresTimesNotDecreased = opt.m_bThresTimesNotDecreased; m_c0f = opt.m_c0f; m_c0s = opt.m_c0s; m_c1f = opt.m_c1f; m_c1s = opt.m_c1s; m_D = opt.m_D; m_initFuncThreshActive = opt.m_initFuncThreshActive; m_initFuncTresh = opt.m_initFuncTresh; // advanced init setup m_advancedInit= opt.m_advancedInit; m_advancedinitLowerBounds= opt.m_advancedinitLowerBounds; m_advancedinitUpperBounds= opt.m_advancedinitUpperBounds; } return *this; } AdaptiveDirectionRandomSearchOptimizer::~AdaptiveDirectionRandomSearchOptimizer() { delete[] m_bk; delete[] m_pointsAccepted; } void AdaptiveDirectionRandomSearchOptimizer::init() { m_Parameters = matrix_type(m_numberOfParameters,m_numberOfParallelPoints); // if not set before, set default value if(m_bThresTimesNotDecreased == 0) m_bThresTimesNotDecreased = static_cast(m_numberOfParameters * m_numberOfParameters* 5.0); SuperClass::init(); // "reset" for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_bk[j] = m_b0; m_pointsAccepted[j]= false; } m_backupActive = false; /* seed rand */ ice::Randomize(); /* check if bounds are active! bounds are needed to generate usefull random start points */ if(!(m_upperParameterBoundActive == true && m_lowerParameterBoundActive == true)) { if(m_loger) { m_loger->logError("parameter bounds are not active! Please set proper parameter bounds for the random start point generation. This event is has no further exception handling"); } m_lowerParameterBound = m_parameters; m_upperParameterBound = m_parameters; m_lowerParameterBoundActive = true; m_upperParameterBoundActive = true; } /* generate random start points */ if(m_advancedInit == false) { for(int k = 0; k < static_cast(m_numberOfParameters);k++) { for(int l = 0; l < static_cast(m_numberOfParallelPoints);l++) { m_Parameters[k][l] = m_parameters[k][0] + m_scales[k][0] *2.0* (ice::RandomD() - 0.5); } } } else { // dimension check assert(m_advancedinitLowerBounds.rows() == (int)m_numberOfParameters && m_advancedinitUpperBounds.rows() == (int)m_numberOfParameters); for(int k = 0; k < static_cast(m_numberOfParameters);k++) { for(int l = 0; l < static_cast(m_numberOfParallelPoints);l++) { m_Parameters[k][l] = m_advancedinitLowerBounds[k][0] +ice::RandomD() * (m_advancedinitUpperBounds[k][0] - m_advancedinitLowerBounds[k][0] ) ; } } } /* evaluate SET !! */ m_CurrentCostFunctionValues = evaluateSetCostFunction(m_Parameters); /* If the threshold was set, check if all points are below the threshold */ if(m_initFuncThreshActive) { bool pointOk=false; for(int u = 0; u < static_cast(m_numberOfParallelPoints); u++) { /* if the are not ok ... generate new points for those, who arent.. */ if(m_CurrentCostFunctionValues[u][0] < m_initFuncTresh) { pointOk = true; } else { pointOk = false; } while(pointOk == false) { for(int k = 0; k < static_cast(m_numberOfParameters);k++) { m_Parameters[k][u] = m_parameters[k][0] + m_scales[k][0] * 2.0*(ice::RandomD() - 0.5); } /* reevaluate the value and check against threshold */ //double tmpNewValue = evaluateCostFunction(m_Parameters.Sub(m_numberOfParameters,1,0,u)); double tmpNewValue = evaluateCostFunction(m_Parameters(0,u,m_numberOfParameters-1,u)); /* if point is ok now go to next point */ if(tmpNewValue < m_initFuncTresh) { m_CurrentCostFunctionValues[u][0] = tmpNewValue; pointOk = true; } } // while point not ok } // for all points } // if threshold active /*if(m_verbose) { std::cout << "AdaptiveDirectionRandomSearch :: Initial parameterSet: "; for(int l=0;l(m_numberOfParameters); r++) { std::cout<< m_Parameters[r][l] << " "; } std::cout << m_CurrentCostFunctionValues[l][0] << std::endl; } std::cout << std::endl; std::cout << "Number of Evaluations needed for a proper initilization: " << m_costFunction->getNumberOfEvaluations() << std::endl; }*/ /* (re)set m_bk */ for(int j = 0; j < static_cast(m_numberOfParallelPoints); j++) { m_bk[j] = m_b0; } } bool AdaptiveDirectionRandomSearchOptimizer::setControlSeqParams(double b0, double bfac, unsigned int bThresTimesNotDecreased,double bBreak) { if(b0 <= 0 || bfac <= 0 || bfac > 1 || bThresTimesNotDecreased == 0 || bBreak <= 0) { return false; } m_b0 = b0; m_bfac = bfac; m_bThresTimesNotDecreased = bThresTimesNotDecreased; m_bBreak = bBreak; return true; } void AdaptiveDirectionRandomSearchOptimizer::activateAdvancedInit(bool enable, matrix_type& lowerBounds, matrix_type& upperBounds) { m_advancedInit= enable; m_advancedinitLowerBounds= lowerBounds; m_advancedinitUpperBounds= upperBounds; } matrix_type AdaptiveDirectionRandomSearchOptimizer::generatePoint() { matrix_type newPoint(m_numberOfParameters,1); for(int i = 0; i < static_cast(m_numberOfParameters); i++) { if(m_scales[i][0] > 0.0 ) { newPoint[i][0] = m_scales[i][0] * 2.0*(ice::RandomD() - 0.5); } } //double div=newPoint.Norm(0); double div=newPoint.Norm(0); if (div > 1.0e-50) { newPoint = newPoint * (1.0/div); } else { newPoint=this->generatePoint(); } return newPoint; } matrix_type AdaptiveDirectionRandomSearchOptimizer::generatePoints() { matrix_type newPoints(m_numberOfParameters,m_numberOfParallelPoints); matrix_type newPoint(m_numberOfParameters,1); for(int j = 0; j < static_cast(m_numberOfParallelPoints);j++) { newPoint = this->generatePoint(); for(int i = 0; i < static_cast(m_numberOfParameters); i++) { newPoints[i][j] = newPoint[i][0]; } } return newPoints; } bool AdaptiveDirectionRandomSearchOptimizer::setRecallParams( double c0s, double c1s, double c0f, double c1f, double D) { if (c0s < 0 || c0s >=1 || c1s <0 || c0s+c1s <= 1 || c0f <= 0 || c0f >= 1 || c1f >= 0 || c0f + c1f < -1.0|| c0f + c1f > 1.0 || D <= 0.0) { return false; } m_c0s = c0s; m_c1s = c1s; m_c0f = c0f; m_c1f = c1f; m_D = D; return true; } void AdaptiveDirectionRandomSearchOptimizer::acceptPoints(matrix_type oldValues, matrix_type newValues) { for(int i = 0;i< static_cast(m_numberOfParallelPoints);i++) { if(newValues[i][0] < oldValues[i][0]) { m_pointsAccepted[i]=true; } else { m_pointsAccepted[i]=false; } } } int AdaptiveDirectionRandomSearchOptimizer::optimize() { init(); if(m_loger) m_loger->logTrace("ADRS: starting optimization ... \n"); /* start time criteria */ m_startTime = clock(); bool abort = false; /* declare and initialize algorithm specific local variables */ matrix_type newPoints; matrix_type newValues; //matrix_type oldValues; matrix_type deltaX(m_numberOfParameters,m_numberOfParallelPoints); matrix_type deltaXold(m_numberOfParameters,m_numberOfParallelPoints); matrix_type dk(m_numberOfParameters,m_numberOfParallelPoints); matrix_type dkold(m_numberOfParameters,m_numberOfParallelPoints); int i = 0; int j = 0; /* begin with the first step outside the loop */ m_numIter++; unsigned int *timesNotDecreased = new unsigned int[m_numberOfParallelPoints]; for(int k = 0; k< static_cast(m_numberOfParallelPoints);k++) { timesNotDecreased[k] = 0; } /* generate a new delta X (potential step) */ matrix_type tmp = generatePoints(); for(j = 0; j< static_cast(m_numberOfParallelPoints);j++) { for(i = 0;i < static_cast(m_numberOfParameters);i++) { deltaX[i][j] = tmp[i][j] * m_bk[j] ; } } /* check costfunction at potential new point */ newPoints = m_Parameters + deltaX; newValues = evaluateSetCostFunction(newPoints); /* are the new points better? */ acceptPoints(m_CurrentCostFunctionValues,newValues); for(j = 0; j < static_cast(m_numberOfParallelPoints);j++) { if(m_pointsAccepted[j] == true) { for(i =0;i < static_cast(m_numberOfParameters);i++) { /* set the new point */ m_Parameters[i][j] = newPoints[i][j]; /* update the recall factor */ dk[i][j] = dkold[i][j] * m_c0s + deltaXold[i][j] * m_c1s; } m_CurrentCostFunctionValues[j][0] = newValues[j][0]; /* reset the counter for failed attempts */ timesNotDecreased[j] = 0; } else { for(i =0; i < static_cast(m_numberOfParameters);i++) { /* update the recall factor */ dk[i][j] = dkold[i][j] * m_c0f + deltaXold[i][j] * m_c1f; } /* raise the counter for failed attempts */ timesNotDecreased[j] ++; } } /* do the optimization in the main loop */ while(abort == false) { /* increase iteration counter */ m_numIter++; /* Check iteration limit */ if(m_maxNumIterActive) { if(m_numIter >= m_maxNumIter) { /* set according return status and return */ m_returnReason = SUCCESS_MAXITER; abort = true; continue; } } /* save the old deltaX */ deltaXold = deltaX; /* generate a new delta X (potential step) */ matrix_type tmp = generatePoints(); for(j = 0; j< static_cast(m_numberOfParallelPoints);j++) { for(i = 0; i < static_cast(m_numberOfParameters);i++) { deltaX[i][j] = dk[i][j] + tmp[i][j] * m_bk[j] ; } } /* check costfunction at potential new point */ newPoints = m_Parameters + deltaX; newValues = evaluateSetCostFunction(newPoints); /* save the old dk */ dkold = dk; /* are the new points better? */ acceptPoints(m_CurrentCostFunctionValues,newValues); for(j = 0; j < static_cast(m_numberOfParallelPoints);j++) { if(m_pointsAccepted[j] == true) { for(i =0; i < static_cast(m_numberOfParameters);i++) { /* set the new point */ m_Parameters[i][j] = newPoints[i][j]; /* update the recall factor */ dk[i][j] = dkold[i][j] * m_c0s + deltaXold[i][j] * m_c1s; } m_CurrentCostFunctionValues[j][0] = newValues[j][0]; /* reset the counter for failed attempts */ timesNotDecreased[j] = 0; } else { for(i =0;i < static_cast(m_numberOfParameters);i++) { /* update the recall factor */ dk[i][j] = dkold[i][j] * m_c0f + deltaXold[i][j] * m_c1f; } /* raise the counter for failed attempts */ timesNotDecreased[j] ++; } /* scaledown m_bk if there was no improvement for a certain time */ if(timesNotDecreased[j] >= m_bThresTimesNotDecreased) { m_bk[j] = m_bk[j] * m_bfac; timesNotDecreased[j] = 0; } /* if m_bk < m_bBreak .. */ if( m_bk[j] < m_bBreak ) { /* */ if(m_backupActive) { if(m_CurrentCostFunctionValues[j][0] < m_backupPointValue) { //m_backupPoint = m_Parameters.Sub(m_numberOfParameters,1,0,j); m_backupPoint = m_Parameters(0,j,m_numberOfParameters-1,j); m_backupPointValue = m_CurrentCostFunctionValues[j][0]; } } else { //m_backupPoint = m_Parameters.Sub(m_numberOfParameters,1,0,j); m_backupPoint = m_Parameters(0,j,m_numberOfParameters-1,j); m_backupPointValue = m_CurrentCostFunctionValues[j][0]; m_backupActive = true; } /* reset counters */ m_bk[j] = m_b0; timesNotDecreased[j] = 0; matrix_type resProb = m_CurrentCostFunctionValues; double maxVal=m_CurrentCostFunctionValues.MaxVal(); for(int i=0; i < (int)m_numberOfParallelPoints; ++i) { resProb[i][0] -= maxVal; } double denom = MatrixSum(resProb); /* ensure numerical stability */ if( fabs(denom) < 1.0e-50) { denom = denom < 0.0 ? -1.0e-50 : 1.0e-50; } resProb = resProb * (1.0/denom); double sum = 0.0; for(int u = 0; u < static_cast(m_numberOfParallelPoints); u++) { sum += resProb[u][0]; resProb[u][0] = sum; } /* generate random number [0,1] */ double choice = ice::RandomD(); int u_chosen = 0; for(int u = 0; u < static_cast(m_numberOfParallelPoints); u++) { u_chosen = u; if( choice < resProb[u][0] ) { break; } } /* set m_parameters */ for(int v = 0; v < static_cast(m_numberOfParameters); v++) { m_Parameters[v][j]=m_Parameters[v][u_chosen]; } m_CurrentCostFunctionValues[j][0] = m_CurrentCostFunctionValues[u_chosen][0]; } /* dk has to be <= D * m_bk */ //double norm= dk(0,j,m_numberOfParameters-1,j).Norm(0); double norm= dk(0,j,m_numberOfParameters-1,j).Norm(0); if( norm >= m_D * m_bk[j]) { if(norm < 1.0e-50) { //m_loger->logWarning("ADRS Optimizer: Warning Computation gets unstable"); norm = 1.0e-50; } for(i =0;i < static_cast(m_numberOfParameters);i++) { /* update the recall factor */ dk[i][j] = dk[i][j] * 1.0/norm; } } } if(m_verbose) { std::cout << "# AdaptiveDirectionRandomSearch :: parameterSet: "; for(int l=0;l < static_cast(m_numberOfParallelPoints);l++) { for(int r = 0; r < static_cast(m_numberOfParameters); r++) { std::cout<< m_Parameters[r][l] << " "; } std::cout << m_bk[l] << " "<< m_CurrentCostFunctionValues[l][0] << std::endl; } std::cout <<"# "<< std::endl; } // fixme wacker for plotting /* for(int l=0;l 1 ) { /* check if distance from one point to all others is below a the threshold */ matrix_type paramSet = m_Parameters; bool abortNow = true; for(int e = 0; e < static_cast(m_numberOfParallelPoints);e++) { if( (paramSet(0,e,m_numberOfParameters-1,e) - paramSet(0,0,m_numberOfParameters-1,0)).Norm(0) > m_paramTol) { abortNow = false; } } if(abortNow) { abort = true; m_returnReason = SUCCESS_PARAMTOL; } } } /* Check Optimization Timelimit, if active */ if(m_maxSecondsActive) { m_currentTime = clock(); /* time limit exceeded ? */ if(((float)(m_currentTime - m_startTime )/CLOCKS_PER_SEC) >= m_maxSeconds ) { /* set according return status and the last parameters and return */ m_returnReason = SUCCESS_TIMELIMIT; abort = true; continue; } } } /* find the best value.. */ unsigned int u_best = 0; for(int u = 0; u < static_cast(m_numberOfParallelPoints); u++) { if( m_CurrentCostFunctionValues[u][0] < m_CurrentCostFunctionValues[u_best][0] ) { u_best = u; } } /* regular points include the best one */ //m_parameters = m_Parameters.Sub(m_numberOfParameters,1,0,u_best); m_parameters = m_Parameters(0,u_best,m_numberOfParameters-1,u_best); m_currentCostFunctionValue = m_CurrentCostFunctionValues[u_best][0]; if (m_backupActive) { /* compare with backup point */ if( m_backupPointValue < m_CurrentCostFunctionValues[u_best][0] ) { /* backup point is best */ m_parameters = m_backupPoint; m_currentCostFunctionValue = m_backupPointValue; } } delete[] timesNotDecreased; return m_returnReason; }