source: src/FunctionApproximation/FunctionApproximation.cpp@ c62f96

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since c62f96 was c62f96, checked in by Frederik Heber <heber@…>, 13 years ago

LevMartester uses now FunctionApproximation.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Please see the COPYING file or "Copyright notice" in builder.cpp for details.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * FunctionApproximation.cpp
26 *
27 * Created on: 02.10.2012
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include "FunctionApproximation.hpp"
39
40#include <algorithm>
41#include <boost/bind.hpp>
42#include <boost/function.hpp>
43#include <iostream>
44#include <iterator>
45#include <numeric>
46#include <sstream>
47
48#include <levmar.h>
49
50#include "CodePatterns/Assert.hpp"
51#include "CodePatterns/Log.hpp"
52
53#include "FunctionApproximation/FunctionModel.hpp"
54
55void FunctionApproximation::setTrainingData(const inputs_t &input, const outputs_t &output)
56{
57 ASSERT( input.size() == output.size(),
58 "FunctionApproximation::setTrainingData() - the number of input and output tuples differ: "+toString(input.size())+"!="
59 +toString(output.size())+".");
60 if (input.size() != 0) {
61 ASSERT( input[0].size() == input_dimension,
62 "FunctionApproximation::setTrainingData() - the dimension of the input tuples and input dimension differ: "+toString(input[0].size())+"!="
63 +toString(input_dimension)+".");
64 input_data = input;
65 ASSERT( output[0].size() == output_dimension,
66 "FunctionApproximation::setTrainingData() - the dimension of the output tuples and output dimension differ: "+toString(output[0].size())+"!="
67 +toString(output_dimension)+".");
68 output_data = output;
69 } else {
70 ELOG(2, "Given vectors of training data are empty, clearing internal vectors accordingly.");
71 input_data.clear();
72 output_data.clear();
73 }
74}
75
76void FunctionApproximation::setModelFunction(FunctionModel &_model)
77{
78 model= _model;
79}
80
81
82/* Meyer's (reformulated) problem, minimum at (2.48, 6.18, 3.45) */
83void meyer(double *p, double *x, int m, int n, void *data)
84{
85register int i;
86double ui;
87
88 for(i=0; i<n; ++i){
89 ui=0.45+0.05*i;
90 x[i]=p[0]*exp(10.0*p[1]/(ui+p[2]) - 13.0);
91 }
92}
93
94void jacmeyer(double *p, double *jac, int m, int n, void *data)
95{
96register int i, j;
97double ui, tmp;
98
99 for(i=j=0; i<n; ++i){
100 ui=0.45+0.05*i;
101 tmp=exp(10.0*p[1]/(ui+p[2]) - 13.0);
102
103 jac[j++]=tmp;
104 jac[j++]=10.0*p[0]*tmp/(ui+p[2]);
105 jac[j++]=-10.0*p[0]*p[1]*tmp/((ui+p[2])*(ui+p[2]));
106 }
107}
108
109/** Callback to circumvent boost::bind, boost::function and function pointer problem.
110 *
111 * See here (second answer!) to the nature of the problem:
112 * http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer
113 *
114 * We cannot use a boost::bind bounded boost::function as a function pointer.
115 * boost::function::target() will just return NULL because the signature does not
116 * match. We have to use a C-style callback function and our luck is that
117 * the levmar signature provides for a void* additional data pointer which we
118 * can cast back to our FunctionApproximation class, as we need access to the
119 * data contained, e.g. the FunctionModel reference FunctionApproximation::model.
120 *
121 */
122void FunctionApproximation::LevMarCallback(double *p, double *x, int m, int n, void *data)
123{
124 FunctionApproximation *approximator = static_cast<FunctionApproximation *>(data);
125 ASSERT( approximator != NULL,
126 "LevMarCallback() - received data does not represent a FunctionApproximation object.");
127 boost::function<void(double*,double*,int,int,void*)> function =
128 boost::bind(&FunctionApproximation::evaluate, approximator, _1, _2, _3, _4, _5);
129 function(p,x,m,n,data);
130}
131
132void FunctionApproximation::operator()()
133{
134 // let levmar optimize
135 register int i, j;
136 int ret;
137 double *p;
138 double *x; // we set zero vector by giving NULL
139 int m, n;
140 double opts[LM_OPTS_SZ], info[LM_INFO_SZ];
141
142 opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20;
143 opts[4]= LM_DIFF_DELTA; // relevant only if the Jacobian is approximated using finite differences; specifies forward differencing
144 //opts[4]=-LM_DIFF_DELTA; // specifies central differencing to approximate Jacobian; more accurate but more expensive to compute!
145
146 m = model.getParameterDimension();
147 n = output_data.size();
148 const FunctionModel::parameters_t params = model.getParameters();
149 {
150 p = new double[m];
151 size_t index = 0;
152 for(FunctionModel::parameters_t::const_iterator paramiter = params.begin();
153 paramiter != params.end();
154 ++paramiter, ++index) {
155 p[index] = *paramiter;
156 }
157 }
158 {
159 x = new double[n];
160 size_t index = 0;
161 for(outputs_t::const_iterator outiter = output_data.begin();
162 outiter != output_data.end();
163 ++outiter, ++index) {
164 x[index] = (*outiter)[0];
165 }
166 }
167
168 {
169 double *work, *covar;
170 work=(double *)malloc((LM_DIF_WORKSZ(m, n)+m*m)*sizeof(double));
171 if(!work){
172 ELOG(0, "FunctionApproximation::operator() - memory allocation request failed.");
173 return;
174 }
175 covar=work+LM_DIF_WORKSZ(m, n);
176
177 // give this pointer as additional data to construct function pointer in
178 // LevMarCallback and call
179 ret=dlevmar_dif(&FunctionApproximation::LevMarCallback, p, x, m, n, 1000, opts, info, work, covar, this); // no Jacobian, caller allocates work memory, covariance estimated
180
181 {
182 std::stringstream covar_msg;
183 covar_msg << "Covariance of the fit:\n";
184 for(i=0; i<m; ++i){
185 for(j=0; j<m; ++j)
186 covar_msg << covar[i*m+j] << " ";
187 covar_msg << std::endl;
188 }
189 covar_msg << std::endl;
190 LOG(1, "INFO: " << covar_msg.str());
191 }
192
193 free(work);
194 }
195
196// {
197// double err[16];
198// dlevmar_chkjac(meyer, jacmeyer, p, m, n, NULL, err);
199// for(i=0; i<n; ++i) printf("gradient %d, err %g\n", i, err[i]);
200// }
201
202 {
203 std::stringstream result_msg;
204 result_msg << "Levenberg-Marquardt returned " << ret << " in " << info[5] << " iter, reason " << info[6] << "\nSolution: ";
205 for(i=0; i<m; ++i)
206 result_msg << p[i] << " ";
207 result_msg << "\n\nMinimization info:\n";
208 std::vector<std::string> infonames(LM_INFO_SZ);
209 infonames[0] = std::string("||e||_2 at initial p");
210 infonames[1] = std::string("||e||_2");
211 infonames[2] = std::string("||J^T e||_inf");
212 infonames[3] = std::string("||Dp||_2");
213 infonames[4] = std::string("mu/max[J^T J]_ii");
214 infonames[5] = std::string("# iterations");
215 infonames[6] = std::string("reason for termination");
216 infonames[7] = std::string(" # function evaluations");
217 infonames[8] = std::string(" # Jacobian evaluations");
218 infonames[9] = std::string(" # linear systems solved");
219 for(i=0; i<LM_INFO_SZ; ++i)
220 result_msg << infonames[i] << ": " << info[i] << " ";
221 result_msg << std::endl;
222 LOG(1, "INFO: " << result_msg.str());
223 }
224
225 delete[] p;
226 delete[] x;
227}
228
229double SquaredDifference(const double res1, const double res2)
230{
231 return (res1-res2)*(res1-res2);
232}
233
234void FunctionApproximation::evaluate(double *p, double *x, int m, int n, void *data)
235{
236 // first set parameters
237 ASSERT( (size_t)m == model.getParameterDimension(),
238 "FunctionApproximation::evaluate() - LevMar expects "+toString(m)
239 +" parameters but the model function expects "+toString(model.getParameterDimension())+".");
240 ASSERT( (size_t)n == output_data.size(),
241 "FunctionApproximation::evaluate() - LevMar expects "+toString(n)
242 +" outputs but we provide "+toString(output_data.size())+".");
243 FunctionModel::parameters_t params(m, 0.);
244 std::copy(p, p+m, params.begin());
245 model.setParameters(params);
246
247 // then evaluate
248 if (!output_data.empty()) {
249 inputs_t::const_iterator initer = input_data.begin();
250 outputs_t::const_iterator outiter = output_data.begin();
251 size_t index = 0;
252 for (; initer != input_data.end(); ++initer, ++outiter, ++index) {
253 // result may be a vector, calculate L2 norm
254 const FunctionModel::results_t functionvalue =
255 model(*initer);
256 std::vector<double> differences(functionvalue.size(), 0.);
257 std::transform(
258 functionvalue.begin(), functionvalue.end(), outiter->begin(),
259 differences.begin(),
260 &SquaredDifference);
261 x[index] = std::accumulate(differences.begin(), differences.end(), 0.);
262 }
263 }
264}
Note: See TracBrowser for help on using the repository browser.