/* $Revision$ $Author$ $Date$ * * Copyright (C) 2005-2007 Violeta Labarta <vlabarta@users.sf.net> * * Contact: cdk-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.modeling.forcefield; import javax.vecmath.GVector; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; /** * Find a decrease direction of the energy fuction from a point of the 3xN coordinates space using the conjugate gradient approach. * *@author vlabarta *@cdk.module forcefield * @cdk.githash * */ public class ConjugateGradientMethod { double uk_FletcherReeves = 0; double uk_PolankRibiere = 0; GVector conjugatedGradientDirection = null; GVector previousConjugatedGradientDirection = null; boolean orthogonalDirectionsProperty = true; GVector diffgk_gkminus1 = null; private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(ConjugateGradientMethod.class); /** * Constructor for the ConjugateGradientMethod object */ public ConjugateGradientMethod() { } /** * Fletcher-Reeves: uk = gk gk / gk-1 gk-1 * */ public void initialize(GVector gradient) { conjugatedGradientDirection = new GVector(gradient); //conjugatedGradientDirection.normalize(); conjugatedGradientDirection.scale(-1); previousConjugatedGradientDirection = new GVector(gradient.getSize()); diffgk_gkminus1 = new GVector(gradient.getSize()); } /** * Fletcher-Reeves: uk = gk gk / gk-1 gk-1 * */ public void setFletcherReeves_uk(GVector gkminus1, GVector gk) { uk_FletcherReeves = gk.dot(gk) / gkminus1.dot(gkminus1); logger.debug("uk_FletcherReeves = " + uk_FletcherReeves); return; } /** * Polak-Ribiere plus: uk = Max(0, (gk - gk-1) gk / gk-1 gk-1) * */ public void setPolankRibierePlus_uk(GVector gkminus1, GVector gk) { diffgk_gkminus1.set(gk); diffgk_gkminus1.sub(gkminus1); uk_PolankRibiere = Math.max(0, diffgk_gkminus1.dot(gk) / gkminus1.dot(gkminus1)); if (uk_PolankRibiere == 0) { //logger.debug("uk_PolankRibiere == 0"); } return; } /** * Check if two consecutive conjugate gradient direction are mutually orthogonal. * * @param pkminus1 Conjugate Gradient direction at coordinates Xk-1 * @param pk Conjugate Gradient direction at coordinates Xk */ private void checkingOrthogonality(GVector pkminus1, GVector pk) { //logger.debug("Math.abs(pk.dot(pkminus1)) / Math.pow(pk.norm(),2) = " + Math.abs(pk.dot(pkminus1)) / Math.pow(pk.norm(),2)); //logger.debug("Math.abs(pk.dot(pkminus1)) / Math.pow(pk.normSquared(),2) = " + Math.abs(pk.dot(pkminus1)) / Math.pow(pk.normSquared(),2)); if (Math.abs(pk.dot(pkminus1)) / Math.pow(pk.normSquared(),2) >= 0.1) { orthogonalDirectionsProperty = false; //logger.debug("orthogonalDirectionsProperty = false"); } else {orthogonalDirectionsProperty = true;} } /** * Restart conjugate gradient direction: assign the gradient of xk as conjugate gradient direction. * * @param gk gradient at coordinates Xk */ private void restartConjugateGradient(GVector gk) { conjugatedGradientDirection.set(gk); //conjugatedGradientDirection.normalize(); conjugatedGradientDirection.scale(-1); //logger.debug("vectorvk : " + direction); } /** * Set the new direction conjugated to the previous direction: vk=-gk + uk vk-1 * * @param gradient gradient at coordinates Xk * @param previousGradient gradient at coordinates Xk-1 */ private void setConjugateGradientDirection(GVector gradient, GVector previousGradient) { setPolankRibierePlus_uk(previousGradient,gradient); previousConjugatedGradientDirection.scale(uk_PolankRibiere); conjugatedGradientDirection.set(gradient); //conjugatedGradientDirection.normalize(); conjugatedGradientDirection.scale(-1); conjugatedGradientDirection.add(previousConjugatedGradientDirection); previousConjugatedGradientDirection.scale(1/uk_PolankRibiere); //direction.normalize(); //logger.debug("vector direction : " + direction); } /** * Calculate the conjugate gradient direction. * * @param gradient Energy function gradient at coordinates Xk * @param previousGradient Energy function gradient at coordinates Xk-1 */ public void setDirection(GVector gradient, GVector previousGradient) { previousConjugatedGradientDirection.set(conjugatedGradientDirection); setConjugateGradientDirection(gradient, previousGradient); checkingOrthogonality(previousConjugatedGradientDirection,conjugatedGradientDirection); if (orthogonalDirectionsProperty == false) {restartConjugateGradient(gradient);} } }