Esempio n. 1
0
    EndCriteria::Type Simplex::minimize(Problem& P,
                                        const EndCriteria& endCriteria) {
        // set up of the problem
        //Real ftol = endCriteria.functionEpsilon();    // end criteria on f(x) (see Numerical Recipes in C++, p.410)
        Real xtol = endCriteria.rootEpsilon();          // end criteria on x (see GSL v. 1.9, http://www.gnu.org/software/gsl/)
        Size maxStationaryStateIterations_
            = endCriteria.maxStationaryStateIterations();
        EndCriteria::Type ecType = EndCriteria::None;
        P.reset();
        Array x_ = P.currentValue();
        Integer iterationNumber_=0;

        // Initialize vertices of the simplex
        bool end = false;
        Size n = x_.size(), i;
        vertices_ = std::vector<Array>(n+1, x_);
        for (i=0; i<n; i++) {
            Array direction(n, 0.0);
            direction[i] = 1.0;
            P.constraint().update(vertices_[i+1], direction, lambda_);
        }
        // Initialize function values at the vertices of the simplex
        values_ = Array(n+1, 0.0);
        for (i=0; i<=n; i++)
            values_[i] = P.value(vertices_[i]);
        // Loop looking for minimum
        do {
            sum_ = Array(n, 0.0);
            Size i;
            for (i=0; i<=n; i++)
                sum_ += vertices_[i];
            // Determine the best (iLowest), worst (iHighest)
            // and 2nd worst (iNextHighest) vertices
            Size iLowest = 0;
            Size iHighest, iNextHighest;
            if (values_[0]<values_[1]) {
                iHighest = 1;
                iNextHighest = 0;
            } else {
                iHighest = 0;
                iNextHighest = 1;
            }
            for (i=1;i<=n; i++) {
                if (values_[i]>values_[iHighest]) {
                    iNextHighest = iHighest;
                    iHighest = i;
                } else {
                    if ((values_[i]>values_[iNextHighest]) && i!=iHighest)
                        iNextHighest = i;
                }
                if (values_[i]<values_[iLowest])
                    iLowest = i;
            }
            // Now compute accuracy, update iteration number and check end criteria
            //// Numerical Recipes exit strategy on fx (see NR in C++, p.410)
            //Real low = values_[iLowest];
            //Real high = values_[iHighest];
            //Real rtol = 2.0*std::fabs(high - low)/
            //    (std::fabs(high) + std::fabs(low) + QL_EPSILON);
            //++iterationNumber_;
            //if (rtol < ftol ||
            //    endCriteria.checkMaxIterations(iterationNumber_, ecType)) {
            // GSL exit strategy on x (see GSL v. 1.9, http://www.gnu.org/software/gsl
            Real simplexSize = computeSimplexSize(vertices_);
            ++iterationNumber_;
            if (simplexSize < xtol ||
                endCriteria.checkMaxIterations(iterationNumber_, ecType)) {
                endCriteria.checkStationaryPoint(0.0, 0.0,
                maxStationaryStateIterations_, ecType);   // PC this is probably not meant like this ? Use separate counter ?
                endCriteria.checkMaxIterations(iterationNumber_, ecType);
                x_ = vertices_[iLowest];
                Real low = values_[iLowest];
                P.setFunctionValue(low);
                P.setCurrentValue(x_);
                return ecType;
            }
            // If end criteria is not met, continue
            Real factor = -1.0;
            Real vTry = extrapolate(P, iHighest, factor);
            if ((vTry <= values_[iLowest]) && (factor == -1.0)) {
                factor = 2.0;
                extrapolate(P, iHighest, factor);
            } else if (std::fabs(factor) > QL_EPSILON) {
                if (vTry >= values_[iNextHighest]) {
                    Real vSave = values_[iHighest];
                    factor = 0.5;
                    vTry = extrapolate(P, iHighest, factor);
                    if (vTry >= vSave && std::fabs(factor) > QL_EPSILON) {
                        for (Size i=0; i<=n; i++) {
                            if (i!=iLowest) {
                                #if defined(QL_ARRAY_EXPRESSIONS)
                                vertices_[i] =
                                    0.5*(vertices_[i] + vertices_[iLowest]);
                                #else
                                vertices_[i] += vertices_[iLowest];
                                vertices_[i] *= 0.5;
                                #endif
                                values_[i] = P.value(vertices_[i]);
                            }
                        }
                    }
                }
            }
            // If can't extrapolate given the constraints, exit
            if (std::fabs(factor) <= QL_EPSILON) {
                x_ = vertices_[iLowest];
                Real low = values_[iLowest];
                P.setFunctionValue(low);
                P.setCurrentValue(x_);
                return EndCriteria::StationaryFunctionValue;
            }
        } while (end == false);
        QL_FAIL("optimization failed: unexpected behaviour");
    }
    EndCriteria::Type DifferentialEvolution::minimize(Problem& P,
											const EndCriteria& endCriteria) {

		EndCriteria::Type ecType = EndCriteria::MaxIterations;
	    QL_REQUIRE(P.currentValue().size() == nParam_,
			"Number of parameters mismatch between problem and DE optimizer");
        P.reset();		
		init();

		Real bestCost = QL_MAX_REAL;
		Size bestPop  = 0;
		for (Size p = 0; p < nPop_; ++p) {
			Array tmp(currGen_[p].pop_);
			try {
				currGen_[p].cost_ = P.costFunction().value(tmp);
			} catch (Error&) {
				currGen_[p].cost_ = QL_MAX_REAL;
			}
			if (currGen_[p].cost_ < bestCost) {
				bestPop = p;
				bestCost = currGen_[p].cost_;
			}
		}

		Size lastChange = 0;
		Size lastParamChange = 0;
		for(Size i=0; i<endCriteria.maxIterations(); ++i) {

			Size newBestPop = bestPop;
			Real newBestCost = bestCost;

			for (Size p=0; p<nPop_; ++p) {
				// Find 3 different populations randomly
				Size r1;
				do {
					r1 = static_cast <Size> (uniformRng_.nextInt32() % nPop_);
				}		
				while(r1 == p || r1 == bestPop);

				Size r2;
				do {
					r2 = static_cast <Size> (uniformRng_.nextInt32() % nPop_);
				}
				while ( r2 == p || r2 == bestPop || r2 == r1);

				Size r3;
				do {
					r3 = static_cast <Size> (uniformRng_.nextInt32() % nPop_);
				} while ( r3 == p || r3 == bestPop || r3 == r1 || r3 == r2);

				for(Size j=0; j<nParam_; ++j) {
					nextGen_[p].pop_[j] = currGen_[p].pop_[j];
				}

				Size j = static_cast <Size> (uniformRng_.nextInt32() % nParam_);
				Size L = 0;
				do {
					const double tmp = 
						currGen_[      p].pop_[j] * a0_
					  + currGen_[     r1].pop_[j] * a1_
					  + currGen_[     r2].pop_[j] * a2_
					  + currGen_[     r3].pop_[j] * a3_
					  + currGen_[bestPop].pop_[j] * aBest_;

					nextGen_[p].pop_[j] =
						std::min(maxParams_[j], std::max(minParams_[j], tmp));

					j = (j+1)%nParam_;
					++L;
				} while ((uniformRng_.nextReal() < CR_) && (L < nParam_));

				// Evaluate the new population
				Array tmp(nextGen_[p].pop_);
				try {
					nextGen_[p].cost_ = P.costFunction().value(tmp);
                } catch (Error&) {
					nextGen_[p].cost_ = QL_MAX_REAL;
                }

				// Not better, discard it and keep the old one.
				if (nextGen_[p].cost_ >= currGen_[p].cost_) {
					nextGen_[p] = currGen_[p];
				}
				// Better, keep it.
				else {
					// New best?
					if (nextGen_[p].cost_ < newBestCost) {
						newBestPop = p;
						newBestCost = nextGen_[p].cost_;
					}
				}
			}

			if(std::abs(newBestCost-bestCost) > endCriteria.functionEpsilon()) {
				lastChange = i;
			}
			const Array absDiff = Abs(nextGen_[newBestPop].pop_-currGen_[bestPop].pop_);
			if(*std::max_element(absDiff.begin(), absDiff.end()) > endCriteria.rootEpsilon()) {
				lastParamChange = i;
			}

			bestPop = newBestPop;
			bestCost = newBestCost;
			currGen_ = nextGen_;

            if(i-lastChange > endCriteria.maxStationaryStateIterations()) {
				ecType = EndCriteria::StationaryFunctionValue;
				break;
			}
			if(i-lastParamChange > endCriteria.maxStationaryStateIterations()) {
				ecType = EndCriteria::StationaryPoint;
				break;
			}

            if (adaptive_) adaptParameters();
		}
		
		const Array res(currGen_[bestPop].pop_);
        P.setCurrentValue(res);
        P.setFunctionValue(bestCost);
        
        return ecType;
    }