VinaLC: Parallel Molecular Docking Program

Biochemical and Biophysical Systems Group
VinaLC version: 1.1.2

bfgs.h
Go to the documentation of this file.
1 /*
2 
3  Copyright (c) 2006-2010, The Scripps Research Institute
4 
5  Licensed under the Apache License, Version 2.0 (the "License");
6  you may not use this file except in compliance with the License.
7  You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11  Unless required by applicable law or agreed to in writing, software
12  distributed under the License is distributed on an "AS IS" BASIS,
13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  See the License for the specific language governing permissions and
15  limitations under the License.
16 
17  Author: Dr. Oleg Trott <ot14@columbia.edu>,
18  The Olson Lab,
19  The Scripps Research Institute
20 
21 */
22 
23 #ifndef VINA_BFGS_H
24 #define VINA_BFGS_H
25 
26 #include "matrix.h"
27 
29 
30 template<typename Change>
31 void minus_mat_vec_product(const flmat& m, const Change& in, Change& out) {
32  sz n = m.dim();
33  VINA_FOR(i, n) {
34  fl sum = 0;
35  VINA_FOR(j, n)
36  sum += m(m.index_permissive(i, j)) * in(j);
37  out(i) = -sum;
38  }
39 }
40 
41 template<typename Change>
42 inline fl scalar_product(const Change& a, const Change& b, sz n) {
43  fl tmp = 0;
44  VINA_FOR(i, n)
45  tmp += a(i) * b(i);
46  return tmp;
47 }
48 
49 template<typename Change>
50 inline bool bfgs_update(flmat& h, const Change& p, const Change& y, const fl alpha) {
51  const fl yp = scalar_product(y, p, h.dim());
52  if(alpha * yp < epsilon_fl) return false; // FIXME?
53  Change minus_hy(y); minus_mat_vec_product(h, y, minus_hy);
54  const fl yhy = - scalar_product(y, minus_hy, h.dim());
55  const fl r = 1 / (alpha * yp); // 1 / (s^T * y) , where s = alpha * p // FIXME ... < epsilon
56  const sz n = p.num_floats();
57  VINA_FOR(i, n)
58  VINA_RANGE(j, i, n) // includes i
59  h(i, j) += alpha * r * (minus_hy(i) * p(j)
60  + minus_hy(j) * p(i)) +
61  + alpha * alpha * (r*r * yhy + r) * p(i) * p(j); // s * s == alpha * alpha * p * p
62  return true;
63 }
64 
65 template<typename F, typename Conf, typename Change>
66 fl line_search(F& f, sz n, const Conf& x, const Change& g, const fl f0, const Change& p, Conf& x_new, Change& g_new, fl& f1) { // returns alpha
67  const fl c0 = 0.0001;
68  const unsigned max_trials = 10;
69  const fl multiplier = 0.5;
70  fl alpha = 1;
71 
72  const fl pg = scalar_product(p, g, n);
73 
74  VINA_U_FOR(trial, max_trials) {
75  x_new = x; x_new.increment(p, alpha);
76  f1 = f(x_new, g_new);
77  if(f1 - f0 < c0 * alpha * pg) // FIXME check - div by norm(p) ? no?
78  break;
79  alpha *= multiplier;
80  }
81  return alpha;
82 }
83 
84 inline void set_diagonal(flmat& m, fl x) {
85  VINA_FOR(i, m.dim())
86  m(i, i) = x;
87 }
88 
89 template<typename Change>
90 void subtract_change(Change& b, const Change& a, sz n) { // b -= a
91  VINA_FOR(i, n)
92  b(i) -= a(i);
93 }
94 
95 template<typename F, typename Conf, typename Change>
96 fl bfgs(F& f, Conf& x, Change& g, const unsigned max_steps, const fl average_required_improvement, const sz over) { // x is I/O, final value is returned
97  sz n = g.num_floats();
98  flmat h(n, 0);
99  set_diagonal(h, 1);
100 
101  Change g_new(g);
102  Conf x_new(x);
103  fl f0 = f(x, g);
104 
105  fl f_orig = f0;
106  Change g_orig(g);
107  Conf x_orig(x);
108 
109  Change p(g);
110 
111  flv f_values; f_values.reserve(max_steps+1);
112  f_values.push_back(f0);
113 
114  VINA_U_FOR(step, max_steps) {
115  minus_mat_vec_product(h, g, p);
116  fl f1 = 0;
117  const fl alpha = line_search(f, n, x, g, f0, p, x_new, g_new, f1);
118  Change y(g_new); subtract_change(y, g, n);
119 
120  f_values.push_back(f1);
121  f0 = f1;
122  x = x_new;
123  //if(!(std::sqrt(scalar_product(g, g, n)) >= 1e-5)) break; // breaks for nans too // FIXME !!??
124  if(scalar_product(g, g, n) < 1e-10 ) break;
125  g = g_new; // ?
126 
127  if(step == 0) {
128  const fl yy = scalar_product(y, y, n);
129  if(std::abs(yy) > epsilon_fl)
130  set_diagonal(h, alpha * scalar_product(y, p, n) / yy);
131  }
132 
133  bool h_updated = bfgs_update(h, p, y, alpha);
134  }
135  if(!(f0 <= f_orig)) { // succeeds for nans too
136  f0 = f_orig;
137  x = x_orig;
138  g = g_orig;
139  }
140  return f0;
141 }
142 
143 #endif