View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.numerics;
39  
40  import javax.annotation.Nullable;
41  import java.util.Collections;
42  import java.util.List;
43  
44  /**
45   * The OptimizationInterface defines methods required by an optimizer.
46   *
47   * @author Michael J. Schnieders
48   * @since 1.0
49   */
50  public interface OptimizationInterface {
51  
52    /**
53     * Destroys this Potential and frees up any associated resources, particularly worker Threads.
54     * Default implementation is to return true (assume destruction successful).
55     *
56     * @return If resource reclamation successful, or resources already reclaimed.
57     */
58    default boolean destroy() {
59      return true;
60    }
61  
62    /**
63     * This method is called repeatedly to compute the function energy.
64     *
65     * @param x Input parameters.
66     * @return Function value at <code>x</code>.
67     * @since 1.0
68     */
69    double energy(double[] x);
70  
71    /**
72     * This method is called repeatedly to compute the function energy. The verbose flag may not be
73     * used by all implementations.
74     *
75     * @param x       Input parameters.
76     * @param verbose Display extra information.
77     * @return Function value at <code>x</code>
78     */
79    default double energy(double[] x, boolean verbose) {
80      return energy(x);
81    }
82  
83    /**
84     * This method is called repeatedly to compute the function energy and gradient.
85     *
86     * @param x Input parameters.
87     * @param g Output gradients with respect to each parameter.
88     * @return Function value at <code>x</code>.
89     * @since 1.0
90     */
91    double energyAndGradient(double[] x, double[] g);
92  
93    /**
94     * This method is called repeatedly to compute the function energy and gradient. The verbose flag
95     * may not be used by all implementations.
96     *
97     * @param x       Input parameters.
98     * @param g       Output gradients with respect to each parameter.
99     * @param verbose Display extra information.
100    * @return Function value at <code>x</code>.
101    * @since 1.0
102    */
103   default double energyAndGradient(double[] x, double[] g, boolean verbose) {
104     return energyAndGradient(x, g);
105   }
106 
107   /**
108    * Load the current value of the parameters. If the supplied array is null or not large enough, a
109    * new one should be created. The filled array is returned.
110    *
111    * @param parameters Supplied array.
112    * @return The array filled with parameter values.
113    */
114   double[] getCoordinates(double[] parameters);
115 
116   /**
117    * Set the current value of the parameters. If the supplied array is null or not large enough,
118    * no action is taken.
119    *
120    * @param parameters The array with parameter values.
121    */
122   void setCoordinates(double[] parameters);
123 
124   /**
125    * Get the number of variables being operated on.
126    *
127    * @return Number of variables.
128    */
129   int getNumberOfVariables();
130 
131   /**
132    * Get the problem scaling.
133    *
134    * @return The scaling value used for each variable.
135    * @since 1.0
136    */
137   double[] getScaling();
138 
139   /**
140    * Scale the problem. A good choice for optimization is the square root of the median eigenvalue of
141    * a typical Hessian.
142    *
143    * @param scaling The scaling value to use for each variable.
144    * @since 1.0
145    */
146   void setScaling(@Nullable double[] scaling);
147 
148   /**
149    * Get the total energy of the system
150    *
151    * @return the total energy
152    */
153   double getTotalEnergy();
154 
155   /**
156    * Returns a List of Potentials this Potential depends on with a recursive search, excluding the
157    * top level of this call. May not be implemented for all Potentials.
158    *
159    * @return By default, an empty list.
160    */
161   default List<Potential> getUnderlyingPotentials() {
162     return Collections.emptyList();
163   }
164 
165   /**
166    * Default method to scale coordinates.
167    *
168    * @param x Input parameters.
169    */
170   default void scaleCoordinates(double[] x) {
171     double[] scaling = getScaling();
172     if (scaling != null) {
173       int nParams = x.length;
174       for (int i = 0; i < nParams; i++) {
175         x[i] *= scaling[i];
176       }
177     }
178   }
179 
180   /**
181    * Default method to unscale coordinates.
182    *
183    * @param x Input parameters.
184    * @param g Gradient array.
185    */
186   default void scaleCoordinatesAndGradient(double[] x, double[] g) {
187     double[] scaling = getScaling();
188     if (scaling != null) {
189       int len = x.length;
190       for (int i = 0; i < len; i++) {
191         x[i] *= scaling[i];
192         g[i] /= scaling[i];
193       }
194     }
195   }
196 
197   /**
198    * Default method to unscale coordinates.
199    *
200    * @param x Input parameters.
201    */
202   default void unscaleCoordinates(double[] x) {
203     double[] scaling = getScaling();
204     if (scaling != null) {
205       int nParams = x.length;
206       for (int i = 0; i < nParams; i++) {
207         x[i] /= scaling[i];
208       }
209     }
210   }
211 }