ObjectiveFunction.cpp

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*   O B J E C T I V E   F U N C T I O N   C L A S S                          */
00004 /*                                                                            */
00005 /*   Roberto Lopez                                                            */
00006 /*   International Center for Numerical Methods in Engineering (CIMNE)        */
00007 /*   Technical University of Catalonia (UPC)                                  */
00008 /*   Barcelona, Spain                                                         */
00009 /*   E-mail: rlopez@cimne.upc.edu                                             */
00010 /*                                                                            */
00011 /******************************************************************************/
00012 
00013 
00014 #include "ObjectiveFunction.h"
00015 
00016 #include<iostream>
00017 #include <math.h>
00018 #include <sstream>
00019 #include <stdexcept>
00020 
00021 namespace Purple
00022 {
00023 
00024 // GENERAL CONSTRUCTOR
00025 
00026 /// General constructor. It creates an objective function object. 
00027 /// It also initializes all the rest of class members to their default values:
00028 ///
00029 /// <ul>
00030 /// <li> Number of evaluations = 0.
00031 /// <li> Epsilon: 1.0e-6.
00032 /// </ul> 
00033 
00034 ObjectiveFunction::ObjectiveFunction(void)
00035 {
00036    numberOfEvaluations = 0;
00037 
00038    epsilon = 1.0e-6;
00039 }
00040 
00041 
00042 // DESTRUCTOR
00043 
00044 /// Destructor.
00045 
00046 ObjectiveFunction::~ObjectiveFunction(void)
00047 {
00048 
00049 }
00050 
00051 
00052 // METHODS
00053 
00054 // int getNumberOfVariables(void) method
00055 
00056 /// This method returns the number of variables in the objective function.
00057 
00058 int ObjectiveFunction::getNumberOfVariables(void)
00059 {
00060    return(numberOfVariables);
00061 }
00062 
00063 
00064 // Vector<double> getLowerBound(void)
00065 
00066 /// This method returns the lower bound of the objective function domain.
00067 ///
00068 /// @see getUpperBound(void)
00069 /// @see getDomain(void)
00070 
00071 Vector<double> ObjectiveFunction::getLowerBound(void)
00072 {
00073    return(lowerBound);               
00074 }
00075 
00076 // Vector<double> getUpperBound(void)
00077 
00078 /// This method returns the upper bound of the objective function domain.
00079 ///
00080 /// @see getLowerBound(void)
00081 /// @see getDomain(void)
00082 
00083 Vector<double> ObjectiveFunction::getUpperBound(void)
00084 {
00085    return(upperBound);               
00086 }
00087 
00088 // Matrix<double> getDomain(void)
00089 
00090 /// This method returns the objective function domain in a single Matrix.
00091 /// Row 0 contains the lower bound of the domain.
00092 /// Row 1 contains the upper bound of the domain.
00093 ///
00094 /// @see getLowerBound(void)
00095 /// @see getUpperBound(void)
00096 
00097 Matrix<double> ObjectiveFunction::getDomain(void)
00098 {
00099    Matrix<double> domain(2, numberOfVariables, 0.0);
00100    
00101    for(int i = 0; i< numberOfVariables; i++)
00102    {
00103       domain[0][i] = lowerBound[i];
00104       domain[1][i] = upperBound[i];              
00105    }
00106 
00107    return(domain);               
00108 }
00109 
00110 
00111 // double getEpsilon(void) method
00112 
00113 /// This method returns the epsilon value to be used for  numerical 
00114 /// differentiation.
00115 ///
00116 /// @see getGradient(void)
00117 /// @see getHessian(void)
00118 
00119 double ObjectiveFunction::getEpsilon(void)
00120 {
00121    return(epsilon);
00122 }
00123 
00124 
00125 // int getNumberOfEvaluations(void) method
00126 
00127 /// This method returns the number of calls to the getEvaluation(Vector<double>) 
00128 /// method.
00129 ///
00130 /// @see getEvaluation(Vector<double>).
00131 
00132 int ObjectiveFunction::getNumberOfEvaluations(void)
00133 {
00134    return(numberOfEvaluations);
00135 }
00136 
00137 
00138 // void setNumberOfVariables(int) method
00139 
00140 /// This method sets a new number of variables in the objective function
00141 ///
00142 /// @param newNumberOfVariables: New number of variables in the objective function.
00143 
00144 void ObjectiveFunction::setNumberOfVariables(int newNumberOfVariables)
00145 {
00146    if(newNumberOfVariables < 0)
00147    {
00148       std::cout << std::endl
00149                 << "Error: ObjectiveFunction class. "
00150                 << "void setNumberOfVariables(int) method."
00151                 << std::endl
00152                 << "Number of variables must be equal or greater than zero." 
00153                 << std::endl
00154                 << std::endl;
00155 
00156       exit(1);
00157    }
00158 
00159    numberOfVariables = newNumberOfVariables;
00160 
00161    // Initialize lower bound of domain to -1
00162 
00163    Vector<double> newLowerBound(numberOfVariables, -1.0);
00164    
00165    lowerBound = newLowerBound;
00166 
00167    // Initialize lower bound of domain to +1
00168    
00169    Vector<double> newUpperBound(numberOfVariables, 1.0);
00170 
00171    upperBound =  newUpperBound;
00172 }
00173 
00174 
00175 // void setLowerBound(Vector<double>)
00176 
00177 /// This method sets a new lower bound in the objective function domain.
00178 ///
00179 /// @param newLowerBound: New lower bound in the objective function domain.
00180 ///
00181 /// @see setUpperBound(Vector<double>)
00182 /// @see setDomain(Matrix<double>)
00183 
00184 void ObjectiveFunction::setLowerBound(Vector<double> newLowerBound)
00185 {
00186    if(newLowerBound.getSize() != numberOfVariables)
00187    {
00188       std::cout << std::endl
00189                 << "Error: ObjectiveFunction class. "
00190                 << "void setLowerBound(Vector<double>) method."
00191                 << std::endl
00192                 << "Size must be equal to number of variables." << std::endl
00193                 << std::endl;
00194 
00195       exit(1);
00196    }
00197    else
00198    {
00199       // Check that lower bound of all variables is not greater than upper bound
00200 
00201       for(int i = 0; i < numberOfVariables; i++)
00202       {
00203          if(newLowerBound[i] > upperBound[i])
00204          {
00205             std::cout << std::endl
00206                       << "Error: ObjectiveFunction class. "
00207                       << "void setLowerBound(Vector<double>) method."
00208                       << std::endl
00209                       << "Lower bound of variable "<< i 
00210                       << " is greater than upper bound of that variable."
00211                       << std::endl << std::endl;
00212 
00213             exit(1);
00214          }
00215       }
00216    }
00217    
00218    // Set lower bound 
00219 
00220    lowerBound = newLowerBound;
00221 }
00222 
00223 
00224 // void setUpperBound(Vector<double>)
00225 
00226 /// This method sets a new upper bound in the objective function domain.
00227 ///
00228 /// @param newUpperBound: New upper bound in the objective function domain.
00229 ///
00230 /// @see setLowerBound(Vector<double>)
00231 /// @see setDomain(Matrix<double>)
00232 
00233 void ObjectiveFunction::setUpperBound(Vector<double> newUpperBound)
00234 {
00235    if(newUpperBound.getSize() != numberOfVariables)
00236    {
00237       std::cout << std::endl
00238                 << "Error: ObjectiveFunction class. "
00239                 << "void setUpperBound(Vector<double>) method."
00240                 << std::endl
00241                 << "Size must be equal to number of variables." << std::endl
00242                 << std::endl;
00243 
00244       exit(1);
00245    }
00246    else
00247    {
00248       // Check that upper bound of all variables is not less than lower bound
00249 
00250       for(int i = 0; i < numberOfVariables; i++)
00251       {
00252          if(newUpperBound[i] < lowerBound[i])
00253          {
00254             std::cout << std::endl
00255                       << "Error: ObjectiveFunction class. "
00256                       << "void setUpperBound(Vector<double>) method."
00257                       << std::endl
00258                       << "Upper bound of variable "<< i 
00259                       << " is less than lower bound of that variable."
00260                       << std::endl << std::endl;
00261 
00262             exit(1);
00263          }
00264       }
00265    }
00266    
00267    // Set upper bound 
00268 
00269    upperBound = newUpperBound;
00270 }
00271 
00272 // void setDomain(Matrix<double>)
00273 
00274 /// This method sets a new objective function domain from a single Matrix.
00275 /// Row 0 must contain the lower bound of the domain.
00276 /// Row 1 must contain the upper bound of the domain.
00277 ///
00278 /// @param newDomain: New objective function domain.
00279 ///
00280 /// @see setLowerBound(Vector<double>)
00281 /// @see setUpperBound(Vector<double>)
00282 
00283 void ObjectiveFunction::setDomain(Matrix<double> newDomain)
00284 {
00285    if(newDomain.getNumberOfRows() != 2)
00286    {
00287       std::cout << std::endl
00288                 << "Error: ObjectiveFunction class. "
00289                 << "void setDomain(Matrix<double>) method."
00290                 << std::endl
00291                 << "Number of rows must be 2." 
00292                 << std::endl << std::endl;
00293 
00294       exit(1);
00295    }
00296    else if(newDomain.getNumberOfColumns() != numberOfVariables)
00297    {
00298       std::cout << std::endl
00299                 << "Error: ObjectiveFunction class. "
00300                 << "void setDomain(Matrix<double>) method."
00301                 << std::endl
00302                 << "Number of columns must be equal to number of variables." 
00303                 << std::endl
00304                 << std::endl;
00305 
00306       exit(1);
00307    }
00308    else
00309    {
00310       // Check that minimum of input variables is not greater than their maximum
00311 
00312       for(int i = 0; i < numberOfVariables; i++)
00313       {
00314          if(newDomain[0][i] > newDomain[1][i])
00315          {
00316             std::cout << std::endl
00317                       << "Error: ObjectiveFunction class. "
00318                       << "void setDomain(Matrix<double>) method."
00319                       << std::endl
00320                       << "Lower bound of input variable "<< i 
00321                       << " is greater than upper bound of that variable."
00322                       << std::endl << std::endl;
00323 
00324             exit(1);
00325          }
00326       }
00327    }
00328    
00329    // Set domain 
00330 
00331    for(int i = 0; i < numberOfVariables; i++)
00332    {
00333       lowerBound[i] = newDomain[0][i];
00334       upperBound[i] = newDomain[1][i];
00335    }   
00336 }
00337 
00338 
00339 
00340 // void setEpsilon(double) method
00341 
00342 /// This method sets a new epsilon value to be used for numerical differentiation.
00343 ///
00344 /// @param newEpsilon: New value for epsilon.
00345 ///
00346 /// @see getGradient(Vector<double>)
00347 /// @see getHessian(Vector<double>)
00348 
00349 void ObjectiveFunction::setEpsilon(double newEpsilon)
00350 {
00351    if(newEpsilon <= 0.0)
00352    {
00353       std::stringstream buffer;
00354 
00355       buffer << std::endl
00356              << "Error: ObjectiveFunction class. "
00357              << "void setEpsilon(double) method." << std::endl
00358              << "Epsilon must be greater than 0." << std::endl
00359              << std::endl;
00360 
00361       throw std::invalid_argument(buffer.str());
00362       //exit(1);
00363    }
00364    else
00365    {
00366       epsilon = newEpsilon;
00367    }
00368 }
00369 
00370 
00371 // void setNumberOfEvaluations(int) method
00372 
00373 /// This method sets the number of calls to the getEvaluation(Vector<double>)
00374 /// method to a new value. 
00375 ///
00376 /// @param newNumberOfEvaluations: New number of calls
00377 /// to the getEvaluation(Vector<double>) method.
00378 ///
00379 /// @see getEvaluation(Vector<double>).
00380 
00381 void ObjectiveFunction::setNumberOfEvaluations(int newNumberOfEvaluations)
00382 {
00383    numberOfEvaluations = newNumberOfEvaluations;
00384 }
00385 
00386 
00387 // Vector<double> getGradient(void) method
00388 
00389 /// This method returns the objective function gradient vector at a given argument.
00390 /// It uses numerical differentiation.
00391 ///
00392 /// @param argument: Point at which the gradient is to be computed.
00393 ///
00394 /// @see getEvaluation(Vector<double>).
00395 /// @see getHessian(Vector<double>).
00396 
00397 Vector<double> ObjectiveFunction::getGradient(Vector<double> argument)
00398 {
00399    Vector<double> gradient(numberOfVariables, 0.0);
00400 
00401    double evaluation1 = 0.0, evaluation2 = 0.0;
00402 
00403    for (int i = 0; i < numberOfVariables; i++)
00404    {
00405       // Add epsilon to argument
00406 
00407       argument[i] += epsilon;
00408 
00409       // Get evaluation
00410 
00411       evaluation2 = getEvaluation(argument);
00412 
00413       // Restart original argument
00414 
00415       argument[i] -= epsilon;
00416 
00417       // Substract epsilon from argument
00418 
00419       argument[i] -= epsilon;
00420 
00421       // Get evaluation
00422 
00423       evaluation1 = getEvaluation(argument);
00424 
00425       // Restart original argument
00426 
00427       argument[i] += epsilon;
00428 
00429       // Calculate derivative
00430 
00431       gradient[i] = (evaluation2 - evaluation1)/(2.0*epsilon);
00432    }
00433 
00434    return(gradient);
00435 }
00436 
00437 
00438 // double getGradientNorm(Vector<double>) method
00439 
00440 /// This method returns the norm of the objective function gradient.
00441 ///
00442 /// @param gradient: Objective function gradient Vector.
00443 ///
00444 /// @see getGradient(Vector<double>).
00445 
00446 double ObjectiveFunction::getGradientNorm(Vector<double> gradient)
00447 {
00448    double gradientNorm = 0.0;
00449 
00450    int numberOfDimensions = gradient.getSize();
00451 
00452    double sum = 0.0;
00453 
00454    for(int i = 0; i < numberOfDimensions; i++)
00455    {
00456       sum += pow(gradient[i], 2);
00457    }
00458 
00459    gradientNorm = sqrt(sum);
00460 
00461    return(gradientNorm);
00462 }
00463 
00464 
00465 // Matrix<double> getHessian(Vector<double>)
00466 
00467 /// This method returns the objective function Hessian matrix at a given argument.
00468 /// It uses numerical differentiation.
00469 ///
00470 /// @param argument: Point at which the Hessian is to be computed.
00471 ///
00472 /// @see getEvaluation(Vector<double>).
00473 /// @see getGradient(Vector<double>).
00474 
00475 Matrix<double> ObjectiveFunction::getHessian(Vector<double> argument)
00476 {
00477    Matrix<double> hessian(numberOfVariables, numberOfVariables, 0.0);
00478 
00479    double evaluation11 = 0.0, evaluation12 = 0.0;
00480    double evaluation21 = 0.0, evaluation22 = 0.0;
00481 
00482    // Obtain the upper part of the Hessian matrix
00483 
00484    for(int i = 0; i < numberOfVariables; i++)
00485    {
00486       for(int j = i; j < numberOfVariables; j++)
00487       {
00488          // Perturb argument components i and j
00489 
00490          argument[i] += epsilon;
00491          argument[j] += epsilon;
00492 
00493          // Calculate evaluation
00494 
00495          evaluation22 = getEvaluation(argument);
00496 
00497          // Restart argument components i and j
00498 
00499          argument[i] -= epsilon;
00500          argument[j] -= epsilon;
00501 
00502 
00503          // Perturb argument components i and j
00504 
00505          argument[i] += epsilon;
00506          argument[j] -= epsilon;
00507 
00508          // Calculate evaluation
00509 
00510          evaluation21 = getEvaluation(argument);
00511 
00512          // Restart argument components i and j
00513 
00514          argument[i] -= epsilon;
00515          argument[j] += epsilon;
00516 
00517 
00518          // Perturb argument components i and j
00519 
00520          argument[i] -= epsilon;
00521          argument[j] += epsilon;
00522 
00523          // Calculate evaluation
00524 
00525          evaluation12 = getEvaluation(argument);
00526 
00527          // Restart potential free parameters i and j
00528 
00529          argument[i] += epsilon;
00530          argument[j] -= epsilon;
00531 
00532 
00533          // Perturb potential free parameters i and j
00534 
00535          argument[i] -= epsilon;
00536          argument[j] -= epsilon;
00537 
00538          // Calculate evaluation
00539 
00540          evaluation11 = getEvaluation(argument);
00541 
00542          // Restart potential free parameters i and j
00543 
00544          argument[i] += epsilon;
00545          argument[j] += epsilon;
00546 
00547          // Calculate second derivative
00548 
00549          hessian[i][j]
00550          = (evaluation22 - evaluation21 - evaluation12 + evaluation11)/(4.0*pow(epsilon,2));
00551       }
00552    }
00553 
00554    // Obtain the rest of elements by symmetry
00555 
00556    for(int i = 0; i < numberOfVariables; i++)
00557    {
00558       for(int j = 0; j < i; j++)
00559       {
00560          hessian[i][j] = hessian[j][i];
00561       }
00562    }
00563 
00564    return(hessian);
00565 }
00566 
00567 
00568 // Matrix<double> getInverseHessian(Vector<double>) method
00569 
00570 /// This method computes the Hessian at a given argument and then returns its
00571 /// inverse.
00572 ///
00573 /// @param argument: Point at which the inverse Hessian is to be computed.
00574 ///
00575 /// @see getHessian(Vector<double>).
00576 
00577 Matrix<double> ObjectiveFunction::getInverseHessian(Vector<double> argument)
00578 {
00579    Matrix<double> inverseHessian(numberOfVariables, numberOfVariables, 0.0);
00580    
00581    Matrix<double> hessian = getHessian(argument);
00582 
00583    
00584    double hessianDeterminant = getDeterminant(hessian);
00585 
00586    if(hessianDeterminant == 0.0)
00587    {
00588       std::cout << "Error: ObjectiveFunction class. "
00589                 << "Matrix<double> getInverseHessian(Vector<double>) method." 
00590                 << std::endl
00591                 << "Hessian matrix is singular." << std::endl
00592                 << std::endl;
00593       
00594       exit(1);
00595    }
00596    
00597    // Get cofactor matrix
00598    
00599    Matrix<double> cofactor(numberOfVariables, numberOfVariables, 0.0);
00600                   
00601    Matrix<double> c(numberOfVariables-1, numberOfVariables-1, 0.0);
00602 
00603    for(int j = 0; j < numberOfVariables; j++) 
00604    {
00605       for (int i = 0; i < numberOfVariables; i++) 
00606       {
00607 //         Form the adjoint a_ij
00608          int i1 = 0;
00609 
00610          for(int ii = 0; ii < numberOfVariables; ii++) 
00611          {
00612             if(ii == i)
00613             {
00614                continue;
00615             }
00616             
00617             int j1 = 0;
00618 
00619             for(int jj = 0; jj < numberOfVariables; jj++) 
00620             {
00621                if (jj == j)
00622                {
00623                   continue;
00624                }
00625 
00626                c[i1][j1] = hessian[ii][jj];
00627                j1++;
00628             }
00629             i1++;
00630          }
00631 
00632          double determinant = getDeterminant(c);
00633 
00634          cofactor[i][j] = pow(-1.0, i+j+2.0)*determinant;
00635       }
00636    }
00637 
00638    // Adjoint matrix is the transpose of cofactor matrix
00639 
00640    Matrix<double> adjoint(numberOfVariables, numberOfVariables, 0.0);
00641    
00642    double temp = 0.0;
00643 
00644    for(int i = 0; i < numberOfVariables; i++) 
00645    {
00646       for (int j = 0; j < numberOfVariables; j++) 
00647       {
00648          adjoint[i][j] = cofactor[j][i];
00649       }
00650    }
00651 
00652    // Inverse matrix is adjoint matrix divided by matrix determinant
00653    
00654    for(int i = 0; i < numberOfVariables; i++)
00655    {
00656       for(int j = 0; j < numberOfVariables; j++)
00657       {
00658          inverseHessian[i][j] = adjoint[i][j]/hessianDeterminant;
00659       }        
00660    } 
00661    
00662    
00663    return(inverseHessian);               
00664 }
00665 
00666 
00667 // void print(void) method
00668 
00669 void ObjectiveFunction::print(Vector<double> argument)
00670 {
00671    // Do nothing
00672 }
00673 
00674 
00675 // double getDeterminant(Matrix<double>) method
00676 
00677 /// This method returns the determinant of a Matrix.
00678 ///
00679 /// @param matrix: Matrix.
00680 
00681 double ObjectiveFunction::getDeterminant(Matrix<double> matrix)
00682 {
00683    double determinant = 0.0;
00684 
00685    int numberOfRows = matrix.getNumberOfRows();
00686    int numberOfColumns = matrix.getNumberOfColumns();
00687 
00688    if(numberOfRows != numberOfColumns)
00689    {
00690       std::cout << "Error: NewtonMethod class. "
00691                 << "getDeterminant(Matrix<double>) method." << std::endl
00692                 << "Matrix must be square" << std::endl
00693                 << std::endl;
00694       
00695       exit(1);
00696    }
00697 
00698    if(numberOfRows == 0)
00699    {
00700       std::cout << "Error: NewtonMethod class. "
00701                 << "getDeterminant(Matrix<double>) method." << std::endl
00702                 << "Size of matrix is zero." << std::endl
00703                 << std::endl;
00704       
00705       exit(1);                   
00706    }
00707    else if(numberOfRows == 1)
00708    {
00709 //      std::cout << "Warning: NewtonMethod class. "
00710 //                << "getDeterminant(Matrix<double>) method." << std::endl
00711 //                << "Size of matrix is one." << std::endl;
00712 
00713       determinant = matrix[0][0];                   
00714    }
00715    else if(numberOfRows == 2)
00716    {
00717       determinant = matrix[0][0]*matrix[1][1] - matrix[1][0]*matrix[0][1];
00718    }
00719    else
00720    {
00721       for(int j1 = 0; j1 < numberOfRows; j1++) 
00722       {
00723          Matrix<double> subMatrix(numberOfRows-1, numberOfColumns-1, 0.0);     
00724      
00725          for(int i = 1; i < numberOfRows; i++) 
00726          {
00727             int j2 = 0;
00728       
00729             for (int j = 0; j < numberOfColumns; j++) 
00730             {
00731                if (j == j1)
00732                {
00733                   continue;
00734                }
00735 
00736                subMatrix[i-1][j2] = matrix[i][j];
00737 
00738                j2++;
00739             }
00740          }
00741    
00742          determinant += pow(-1.0, j1+2.0)*matrix[0][j1]*getDeterminant(subMatrix);    
00743       }
00744    }
00745       
00746 
00747    return(determinant);
00748 }
00749 
00750 }
00751 
00752 
00753 // Purple: An Open Source Numerical Optimization C++ Library.
00754 // Copyright (C) 2006 Roberto Lopez
00755 //
00756 // This library is free software; you can redistribute it and/or
00757 // modify it under the terms of the GNU Lesser General Public
00758 // License as published by the Free Software Foundation; either
00759 // version 2.1 of the License, or any later version.
00760 //
00761 // This library is distributed in the hope that it will be useful,
00762 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00763 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00764 // Lesser General Public License for more details.
00765 
00766 // You should have received a copy of the GNU Lesser General Public
00767 // License along with this library; if not, write to the Free Software
00768 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

Generated on Wed Jun 21 13:10:38 2006 for Purple by  doxygen 1.4.7