Пример #1
0
Matrix<double> DeJongFunction::getInverseHessian(Vector<double> argument)
{
   Matrix<double> inverseHessian(numberOfVariables, numberOfVariables, 0.0);

   for(int i = 0; i < numberOfVariables; i++)
   {
      for(int j = 0; j < numberOfVariables; j++)
      {
         if(i == j)
         {
            inverseHessian[i][j] = 0.5;
         }
         else
         {
            inverseHessian[i][j] = 0.0;
         }
      }
   }

   return(inverseHessian);
}
Пример #2
0
void BFGS::optimize() {
  Printer::getInstance().printStatusBegin("Optimizing (BFGS)...");

  const size_t d = f.getNumberOfParameters();

  xOpt.resize(0);
  fOpt = NAN;
  xHist.resize(0, d);
  fHist.resize(0);

  base::DataVector x(x0);
  float_t fx = NAN;
  base::DataVector gradFx(d);

  base::DataVector xNew(d);
  float_t fxNew;
  base::DataVector gradFxNew(d);

  base::DataVector delta(d);
  base::DataVector y(d);

  base::DataMatrix inverseHessian(d, d);
  base::DataMatrix inverseHessianNew(d, d);
  base::DataMatrix M(d, d);

  for (size_t i = 0; i < d; i++) {
    for (size_t j = 0; j < d; j++) {
      inverseHessian(i, j) = (i == j ? 1.0 : 0.0);
    }
  }

  size_t k = 0;
  float_t alpha = 1.0;
  base::DataVector dir(d);
  bool inDomain;

  size_t breakIterationCounter = 0;
  const size_t BREAK_ITERATION_COUNTER_MAX = 10;

  while (k < N) {
    // calculate gradient
    fx = fGradient.eval(x, gradFx);
    k++;

    if (k == 1) {
      xHist.appendRow(x);
      fHist.append(fx);
    }

    const float_t gradFxNorm = gradFx.l2Norm();

    if (gradFxNorm == 0.0) {
      break;
    }

    for (size_t i = 0; i < d; i++) {
      dir[i] = 0.0;

      for (size_t j = 0; j < d; j++) {
        dir[i] -= inverseHessian(i, j) * gradFx[j];
      }
    }

    if (dir.dotProduct(gradFx) > 0.0) {
      for (size_t t = 0; t < d; t++) {
        dir[t] = -gradFx[t] / gradFxNorm;
      }
    }

    inDomain = true;

    for (size_t t = 0; t < d; t++) {
      xNew[t] = x[t] + alpha * dir[t];

      if ((xNew[t] < 0.0) || (xNew[t] > 1.0)) {
        inDomain = false;
        break;
      }
    }

    // evaluate at new point
    fxNew = (inDomain ? f.eval(xNew) : INFINITY);
    k++;

    // inner product of gradient and search direction
    const float_t gradFxTimesDir = gradFx.dotProduct(dir);

    // line search
    while (fxNew > fx + rhoLs * alpha * gradFxTimesDir) {
      alpha *= rhoAlphaMinus;
      inDomain = true;

      // recalculate new point
      for (size_t t = 0; t < d; t++) {
        xNew[t] = x[t] + alpha * dir[t];

        if ((xNew[t] < 0.0) || (xNew[t] > 1.0)) {
          inDomain = false;
          break;
        }
      }

      // evaluate at new point
      fxNew = (inDomain ? fGradient.eval(xNew, gradFxNew) : INFINITY);
      k++;
    }

    for (size_t t = 0; t < d; t++) {
      delta[t] = alpha * dir[t];
      y[t] = gradFxNew[t] - gradFx[t];
    }

    // save new point
    x = xNew;
    fx = fxNew;
    gradFx = gradFxNew;
    xHist.appendRow(x);
    fHist.append(fx);

    // increase step size
    alpha *= rhoAlphaPlus;

    const float_t deltaTimesY = delta.dotProduct(y);

    if (deltaTimesY != 0.0) {
      for (size_t i = 0; i < d; i++) {
        for (size_t j = 0; j < d; j++) {
          M(i, j) = (i == j ? 1.0 : 0.0) - y[i] * delta[j] / deltaTimesY;
        }
      }

      for (size_t i = 0; i < d; i++) {
        for (size_t j = 0; j < d; j++) {
          float_t entry = delta[i] * delta[j] / deltaTimesY;

          for (size_t p = 0; p < d; p++) {
            for (size_t q = 0; q < d; q++) {
              entry += M(p, i) * inverseHessian(p, q) * M(q, j);
            }
          }

          inverseHessianNew(i, j) = entry;
        }
      }

      inverseHessian = inverseHessianNew;
    }

    // status printing
    Printer::getInstance().printStatusUpdate(std::to_string(k) + " evaluations, x = " +
                                             x.toString() + ", f(x) = " + std::to_string(fx));

    // stopping criterion:
    // stop if delta is smaller than tolerance theta
    // in BREAK_ITERATION_COUNTER_MAX consecutive iterations
    if (delta.l2Norm() < theta) {
      breakIterationCounter++;

      if (breakIterationCounter >= BREAK_ITERATION_COUNTER_MAX) {
        break;
      }
    } else {
      breakIterationCounter = 0;
    }
  }

  xOpt.resize(d);
  xOpt = x;
  fOpt = fx;
  Printer::getInstance().printStatusEnd();
}
Пример #3
0
SolutionInfo
Alignment::align(bool n)
{
	// create initial solution
	SolutionInfo si;
	si.volume = -1000.0;
	si.iterations = 0;
	si.center1 = _refCenter;
	si.center2 = _dbCenter;
	si.rotation1 = _refRotMat;
	si.rotation2 = _dbRotMat;
	
	// scaling of the exclusion spheres
	double scale(1.0);
	if (_nbrExcl != 0)
	{
		scale /= _nbrExcl;
	}

	// try 4 different start orientations
	for (unsigned int _call(0); _call < 4; ++_call )
	{
		// create initial rotation quaternion
		SiMath::Vector rotor(4,0.0);
		rotor[_call] = 1.0;
		
		double volume(0.0), oldVolume(-999.99), v(0.0);
		SiMath::Vector dG(4,0.0);  // gradient update
		SiMath::Matrix hessian(4,4,0.0), dH(4,4,0.0); // hessian and hessian update
		unsigned int ii(0);
		for ( ; ii < 100; ++ii)
		{			
			// compute gradient of volume
			_grad = 0.0;
			volume = 0.0;
			hessian = 0.0;
			for (unsigned int i(0); i < _refMap.size(); ++i)
			{
				// compute the volume overlap of the two pharmacophore points
				SiMath::Vector Aq(4,0.0);
				SiMath::Matrix * AkA = _AkA[i];
				Aq[0] = (*AkA)[0][0] * rotor[0] + (*AkA)[0][1] * rotor[1] + (*AkA)[0][2] * rotor[2] + (*AkA)[0][3] * rotor[3];
				Aq[1] = (*AkA)[1][0] * rotor[0] + (*AkA)[1][1] * rotor[1] + (*AkA)[1][2] * rotor[2] + (*AkA)[1][3] * rotor[3];
				Aq[2] = (*AkA)[2][0] * rotor[0] + (*AkA)[2][1] * rotor[1] + (*AkA)[2][2] * rotor[2] + (*AkA)[2][3] * rotor[3];
				Aq[3] = (*AkA)[3][0] * rotor[0] + (*AkA)[3][1] * rotor[1] + (*AkA)[3][2] * rotor[2] + (*AkA)[3][3] * rotor[3];
				
				double qAq = Aq[0] * rotor[0] + Aq[1] * rotor[1] + Aq[2] * rotor[2] +Aq[3] * rotor[3];
				
				v = GCI2 * pow(PI/(_refMap[i].alpha+_dbMap[i].alpha),1.5) * exp(-qAq);

				double c(1.0);
				
				// add normal if AROM-AROM
				// in this case the absolute value of the angle is needed
				if (n 
					&&  (_refMap[i].func == AROM) && (_dbMap[i].func == AROM)
					&&  (_refMap[i].hasNormal) && (_dbMap[i].hasNormal))
				{
					// for aromatic rings only the planar directions count
					// therefore the absolute value of the cosine is taken
					c = _normalContribution(_refMap[i].normal, _dbMap[i].normal, rotor);
				
					// update based on the sign of the cosine
					if (c < 0)
					{
						c *= -1.0;
						_dCdq *= -1.0;
						_d2Cdq2 *= -1.0;
					} 
					
					for (unsigned int hi(0); hi < 4; hi++)
					{
						_grad[hi] += v * ( _dCdq[hi] - 2.0 * c * Aq[hi] );
						for (unsigned int hj(0); hj < 4; hj++)
						{
							hessian[hi][hj] += v * (_d2Cdq2[hi][hj] - 2.0 * _dCdq[hi]*Aq[hj] + 2.0 * c * (2.0*Aq[hi]*Aq[hj] - (*AkA)[hi][hj])); 
						}
					}
					v *= c;
				}
				else if (n 
					&& ((_refMap[i].func == HACC) || (_refMap[i].func == HDON) || (_refMap[i].func == HYBH)) 
					&& ((_dbMap[i].func == HYBH) || (_dbMap[i].func == HACC)  || (_dbMap[i].func == HDON))
					&& (_refMap[i].hasNormal)
					&& (_dbMap[i].hasNormal))
				{
					// hydrogen donors and acceptor also have a direction
					// in this case opposite directions have negative impact 

					c = _normalContribution(_refMap[i].normal, _dbMap[i].normal, rotor);
						
					for (unsigned int hi(0); hi < 4; hi++)
					{
						_grad[hi] += v * ( _dCdq[hi] - 2.0 * c * Aq[hi] );
						for (unsigned int hj(0); hj < 4; hj++)
						{
							hessian[hi][hj] += v * (_d2Cdq2[hi][hj] - 2.0 * _dCdq[hi]*Aq[hj] + 2.0 * c * (2.0*Aq[hi]*Aq[hj] - (*AkA)[hi][hj])); 
						}
					}
					
					v *= c;
				}
				else if (_refMap[i].func == EXCL)
				{
					// scale volume overlap of exclusion sphere with a negative scaling factor
					// => exclusion spheres have a negative impact
					v *= -scale;
					// update gradient and hessian directions
					for (unsigned int hi=0; hi < 4; hi++)
					{
						_grad[hi] -= 2.0 * v * Aq[hi];
						for (unsigned int hj(0); hj < 4; hj++)
						{
							hessian[hi][hj] += 2.0 * v * (2.0*Aq[hi]*Aq[hj] - (*AkA)[hi][hj]); 
						}
					}
				}
				else
				{
					// update gradient and hessian directions
					for (unsigned int hi(0); hi < 4; hi++)
					{
						_grad[hi] -= 2.0 * v * Aq[hi];
						for (unsigned int hj(0); hj < 4; hj++)
						{
							hessian[hi][hj] += 2.0 * v * (2.0*Aq[hi]*Aq[hj] - (*AkA)[hi][hj]); 
						}
					}
				}
				
				volume += v;
			}

			// stop iterations if the increase in volume overlap is too small (gradient ascent)
			// or if the volume is not defined
			if (std::isnan(volume) || (volume - oldVolume < 1e-5))
			{
				break; 
			}
			
			// reset old volume	
			oldVolume = volume;
					
			inverseHessian(hessian);
			// update gradient based on inverse hessian
			_grad = rowProduct(hessian,_grad);
			// small scaling of the gradient
			_grad *= 0.9;

			// update rotor based on gradient information
			rotor += _grad;

			// normalise rotor such that it has unit norm
			normalise(rotor);
		}

		// save result in info structure
		if (oldVolume > si.volume)
		{
			si.rotor = rotor;
			si.volume = oldVolume;
			si.iterations = ii;
		}	
	}

	return si;
}
Пример #4
0
Matrix<double> ObjectiveFunction::getInverseHessian(Vector<double> argument)
{
   Matrix<double> inverseHessian(numberOfVariables, numberOfVariables, 0.0);
   
   Matrix<double> hessian = getHessian(argument);

   
   double hessianDeterminant = getDeterminant(hessian);

   if(hessianDeterminant == 0.0)
   {
      std::cout << "Error: ObjectiveFunction class. "
                << "Matrix<double> getInverseHessian(Vector<double>) method." 
                << std::endl
                << "Hessian matrix is singular." << std::endl
                << std::endl;
      
      exit(1);
   }
   
   // Get cofactor matrix
   
   Matrix<double> cofactor(numberOfVariables, numberOfVariables, 0.0);
                  
   Matrix<double> c(numberOfVariables-1, numberOfVariables-1, 0.0);

   for(int j = 0; j < numberOfVariables; j++) 
   {
      for (int i = 0; i < numberOfVariables; i++) 
      {
//         Form the adjoint a_ij
         int i1 = 0;

         for(int ii = 0; ii < numberOfVariables; ii++) 
         {
            if(ii == i)
            {
               continue;
            }
            
            int j1 = 0;

            for(int jj = 0; jj < numberOfVariables; jj++) 
            {
               if (jj == j)
               {
                  continue;
               }

               c[i1][j1] = hessian[ii][jj];
               j1++;
            }
            i1++;
         }

         double determinant = getDeterminant(c);

         cofactor[i][j] = pow(-1.0, i+j+2.0)*determinant;
      }
   }

   // Adjoint matrix is the transpose of cofactor matrix

   Matrix<double> adjoint(numberOfVariables, numberOfVariables, 0.0);
   
   double temp = 0.0;

   for(int i = 0; i < numberOfVariables; i++) 
   {
      for (int j = 0; j < numberOfVariables; j++) 
      {
         adjoint[i][j] = cofactor[j][i];
      }
   }

   // Inverse matrix is adjoint matrix divided by matrix determinant
   
   for(int i = 0; i < numberOfVariables; i++)
   {
      for(int j = 0; j < numberOfVariables; j++)
      {
         inverseHessian[i][j] = adjoint[i][j]/hessianDeterminant;
      }        
   } 
   
   
   return(inverseHessian);               
}