/** @(#) updatetrustregion.cpp */ // #include "ap.h" /** @(#) .h */ /** * @author Daniel Alba Cuellar * @author Omar Posada Villarreal * @version 1.0, /03/2002 */ #ifndef UPDATETRUSTREGION_H #define UPDATETRUSTREGION_H //---------------------------------------------------------------------------- #include "../functionnd/functionnd_1d.h" #include "../mathpos/mathpos.h" #include "../matrixdouble/squaredmatrix.h" #include "../matrixdouble/vectordouble.h" #include <iomanip> #include <iostream> #include <string> #include <stdexcept> // runtime_exception using namespace std; /** Dado un paso s, encontrado por el algoritmo Hook Step o DogStep, * decide cuando x+ = xc + s debe ser aceptado para la siguiente iteracion. * Si se elige, escoge la region de confianza inicial para * la siguiente iteracion. * Si no, disminuye o aumenta la region de confianza para la iteracion actual. * Logica uno. * @author Omar Posada Villarreal, Daniel Alba Cuellar * @param n Taman~o de vectores y matrices. No se checan dimensiones. * @param xc Vector con punto de prueba inicial. De aqui se toma la dimension * @param fc Evaluacion de la funcion en xc. * @param theFunction Nombre de la funcion. F:R^n->R. FN. * @param g Gradiente * @param L Triangular inferior de la Hessiana * @param s Paso: dogleg o hook * @param Sx Escala. Valores usuales. * @param Newttaken true: Se tomo el paso de Newton * @param maxstep Maximo taman~o del paso, delta\. Dado por QuasiNewton * @param steptol Precision del paso * @param steptype * 1: hookstep. Necesita a H * 2: dogstep * @param H Modelo Hessiano simetrica. Usada si steptype = 1. * @param delta in/out Radio de la region de confianza. * @param retcode in/out * 0: x+ aceptado como la siguiente iteracion, * delta es la region de confianza para la siguiente iteracion. * 1: x+ no satisfactorio pero el paso global es terminado * debido a que el taman~o relativo de (x+ - xc) * esta dentro de la tolerancia del taman~o de paso para detener * el algoritmo de detencion, indicando en la mayoria de los casos * que no sera posible un progeso. * Ver termcode = 3 de A7.2.1. y A7.2.3. * 2: f(x+) es muy grande, la iteracion actual va a continuar con una * delta reducida. * 3: f(x+) suficientemente pequen~a, pero con la oportunidad de tomar * un paso exitoso mas largo, que parece ser suficientemente * bueno que el de la iteracion actual, * el cual va a continuar con una nueva delta doble. * @param xpprev in/out x+prev xpprev, fpprev tendran valores actuales en la * entrada, o nyuevos valores en la salida solo si retcode = 3, en ese punto. * Es la posicion siguiente aceptable antes de probar con una nueva x+. * @param fpprev in/out f+prev. Es el valor de la funcion aceptable antes * de probar con una nueva x+. * @param xp return x+ Siguiente paso elegido. * @param fp return f+ Valor de la funcion con el siguiente paso elegido. * @param maxtaken return * true: Si el taman~o de paso es mayor que el 99% de maxstep. * Acepta x+ como una nueva iteracion, y escoge nueva delta. * @version 1.0, 20/04/2002, sig vers LowerTriangularMatrix &L * @see Dennis. A6.4.5. TRUSTREGUP pagina 338 */ void updateTrustRegion(int n, VectorDouble &xc, double fc, FunctionND_1D &theFunction, VectorDouble &g, SquaredMatrix &L, VectorDouble &s, VectorDouble &Sx, bool Newttaken, double maxstep, double steptol, int steptype, SquaredMatrix &H, double &delta, int &retcode, VectorDouble &xpprev, double &fpprev, VectorDouble &xp, double &fp, bool &maxtaken, int logType = SHORT_LOG, int waitType = NO_WAIT) throw (invalid_argument) { LLOG << "\n{ updateTrustRegion"; // Var locales de A6.4.3 VectorDouble Dx_s(n, 1); // Es una matriz cuadrada, pero se almacenara como un vector de Sx VectorDouble Dx(Sx); double alfa; double aux; double delta_f; // incremento en f double delta_fpred; double deltatemp; double initslope; double mx; // maximo double rellength; // Longitud relativa del paso double steplen; double sum; double temp; int i, j; // Significa una llamada inicial a A6.4.4 // A6.4.5. maxtaken = false; // 1. // alfa es una constante usada en la prueba de aceptacion del paso // f(x+) <= f(xc) + alfa g^T (x+ - xc). //Puede ser cambiado al modificar este enunciado alfa = 10E-4; // 2. // 3. // ||Dx sN||2 // Dx = diag((Sx)1, ... ,(Sx)n) // se almacena como Sx E R^n.. // Para implementacion sugerida de expresiones // que conciernen a Dx, ver seccion 1.5 del apendice // ??? Dx = Sx.takeDiagonal(); Dx_s = Dx.diagonalProduct(s); steplen = Dx_s.norm2(); xp = xc + s; // 4. fp = theFunction.evaluate(xp); // 5. delta_f = fp - fc; // 6. initslope = g * s; // 7. innerProduct. g^T s LLOG << "\nx+, xp = " << xp; LLOG << "\nf(x+), fp = " << fp; LLOG << "\ndelta_f = " << delta_f; LLOG << "\ninitslope = " << initslope; if (retcode != 3) { // 8. // Puede ser necesario para prevenir un error runtime en la sig linea fpprev = 0.0; } //9a. if( (retcode == 3) && ( (fp >= fpprev) || (delta_f > (alfa * initslope)) ) ) { // Restaura x+ a x+prev y termina el paso global retcode = 0; // 9a.1. xp = xpprev; // 9a.2. fp = fpprev; // 9a.3. delta /= 2.0; // 9a.4. LLOG << "\n --> updateTrustRegion 9a."; // Esta comentado porque manejamos minimizacion, // no buscamos las raices //FVp = Fpprev; // 9a.5. Solo ecuaciones no lineales // A6.4.5. de aqui regresa. } else if (delta_f >= (alfa * initslope)) { // 9b. // 9b.1. // f(x+) es muy grande //rellength = max(i=[1,n]){ |s[i]| / (max{ |x+[i]|, 1/Sx[i])} mx = fabs(s[1]) / max( fabs(xp[1]), 1.0/Sx[1] ); for (i = 1; i <= n; ++i) { aux = fabs(s[i]) / max( fabs(xp[i]), 1.0/Sx[i] ); if (aux > mx) { mx = aux; } } rellength = mx; if (rellength < steptol) { // 9b.2. // xp - xc muy chico, termina el paso global retcode = 1; // 9b.2T.1. xp = xc; // 9b.2T.2. LLOG << "\n --> updateTrustRegion 9b.2"; // A6.4.5. de aqui regresa } else { // 9b.2E // Reduce delta, continua el paso global retcode = 2; // 9b.2E.1 // 9b.2E.2 deltatemp = -(initslope * steplen) / (2.0 * (delta_f - initslope)); if (deltatemp < (0.1 * delta)) { // 9b.2E.3a. delta *= 0.1; } else if (deltatemp > (0.5 * delta)) { // 9b.2E.3b. delta *= 0.5; } else { delta = deltatemp; // 9b.2E.3c. } LLOG << "\n --> updateTrustRegion 9b.2E."; // A6.4.5 de aqui regresa } } else { // 9c. // f(x+) suficientemente chico // 9c.1-2 Asigna delta_fpred = g^T s + 1/2 s^T H s delta_fpred = initslope; // 9c.1. if (steptype == 1) { // 9c.2. // hookstep, calcula s^T H s LLOG << "\nHookstep sin implementar"; } else { // 9c.2E // dogleg step, calcula s^T L L^T s for (i = 1; i <= n; ++i) { // 9c.2E.1. // 9c.2E.1.1. sum = 0.0; for (j = i; j <= n; ++j) { // Checar con [][] sum += L(j, i) * s(j); } temp = sum; delta_fpred += square(temp) / 2.0; // 9c.2E.1.2 } // 9c.2E.1. // 9c.3. if( (retcode != 2) && ( ( fabs(delta_fpred - delta_f) <= (0.1 * fabs(delta_f)) ) || (delta_f <= initslope) ) && (Newttaken == false) && (delta <= 0.99 *maxstep) ) { // 9c.3T. // doblar delta y continuar paso global retcode = 3; // 9c.3T.1. xpprev = xp; // 9c.3T.2. fpprev = fp; // 9c.3T.3. delta = min( (2.0*delta), maxstep); // 9c.3T.4. LLOG << "\n --> updateTrustRegion 9c.3T."; // Esta comentado porque manejamos minimizacion // no buscamos las raices // Solo ecuaciones no lineales //Fpprev = FVp; // 9c.3T.5. // A6.4.5 de aqui regresa } else { // 9c.3E. // Acepta x+ como una nueva iteracion, // y escoge nueva delta retcode = 0; // 9c.3E.1. if (steplen > (0.99 * maxstep)) { // 9c.3E.2. maxtaken = true; } // 9c.3E.3a. if (delta_f >= (0.1 * delta_fpred)) { // decrementa delta para sig iteracion delta /= 2.0; // 9c.3E.3b. } else if (delta_f <= (0.75 * delta_fpred)) { // incrementa delta para sig iteracion delta = min( (2.0*delta), maxstep); } // 9c.3E.3c else { no se cambia la delta } } // 9c.3E. } // 9c.2E. } // 9c. LLOG << "\ndelta_fpred = " << delta_fpred; LLOG << "\n } updateTrustRegion"; } // A6.4.5. //---------------------------------------------------------------------------- #endif // Fin------------------------------------------------------------------------