double invpower(MAT A,VEC q,int maxiter,double eps,double &v,int aw){
        double tol = 1+eps;
        int k=0;
        int n=A.dim();
        VEC y(n);
        VEC z(n);
        VEC r(n);
        VEC Aq(n);
        VEC u(n);
        VEC w(n);
        MAT A1(n);
        MAT S(n);
        for(int i=0;i<n;i++){
        	S[i][i] = aw;			//define the shifting matrix
        }
        A1 = A-S;
        luFact(A1);					//use LU to solve the equation
        while((tol>=eps) && (k<=maxiter)){
            k = k+1;
            y = fwdSubs(A1,q);		//forward subsitution
            z = bckSubs(A1,y);		//backward substitution
            q = z/norm2(z);
            Aq = A*q;
            v = q*Aq;
            r = Aq - v*q;
            u = Aq;
            w = u/norm2(u);
            tol = norm2(r)/fabs(q*w);
        }
        printf("accuracy of lambda min = %e\n",norm2(r));
        return k;
}
double power(MAT A,VEC q,int maxiter,double eps,double &v){
        double tol = 1 + eps;
        int k = 0;
        int n = A.dim();
        VEC z(n);
        VEC r(n);
        VEC Aq(n);
        VEC u(n);
        VEC w(n);
        while((tol>=eps) && (k<=maxiter)){

                Aq = A*q;
                k = k+1;
                q = Aq/norm2(Aq);
                Aq = A*q;
                v = q*Aq;
                r = Aq-v*q;
                u = Aq;
                w = u/norm2(u);
                tol = norm2(r)/fabs(q*w);

        }
        printf("accuracy of lambda max = %e\n",norm2(r));		//set 2-norm error of residue as accuracy term
        return k;
}
Exemple #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;
}