Chemical Data Processing Library C++ API - Version 1.2.0
BFGSMinimizer.hpp
Go to the documentation of this file.
1 /*
2  * BFGSMinimizer.hpp
3  *
4  * Copyright (C) 2003 Thomas Seidel <thomas.seidel@univie.ac.at>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
27 #ifndef CDPL_MATH_BFGSMINIMIZER_HPP
28 #define CDPL_MATH_BFGSMINIMIZER_HPP
29 
30 #include <cstddef>
31 #include <limits>
32 #include <functional>
33 
35 #include "CDPL/Math/TypeTraits.hpp"
36 
37 
38 namespace CDPL
39 {
40 
41  namespace Math
42  {
43 
52  template <typename VA, typename VT = typename MinimizerVariableArrayTraits<VA>::ValueType, typename FVT = VT>
54  {
55 
56  public:
57  typedef VA VariableArrayType;
58  typedef VT ValueType;
59  typedef FVT FunctionValueType;
60 
61  typedef typename std::function<FVT(const VA&, VA&)> GradientFunction;
62  typedef typename std::function<FVT(const VA&)> ObjectiveFunction;
63 
64  enum Status
65  {
66 
67  SUCCESS = 0, // general success indicator
68  NO_PROGRESS = 1, // no more progress towards solution
69  ITER_LIMIT_REACHED = 2, // the maximum number of minimization iterations has been reached
70  GNORM_REACHED = 4, // the specified gradient norm has been reached
71  DELTAF_REACHED = 8 // the specified function value delta between successive iterations has been reached
72  };
73 
74  BFGSMinimizer(const ObjectiveFunction& func, const GradientFunction& grad_func):
75  rho(0.01), tau1(9), tau2(0.05), tau3(0.5), order(3), sigma(0.1), func(func), gradFunc(grad_func), status(SUCCESS) {}
76 
78  {
79  return g0Norm;
80  }
81 
83  {
84  return -deltaF;
85  }
86 
88  {
89  return fValue;
90  }
91 
92  std::size_t getNumIterations() const
93  {
94  return numIter;
95  }
96 
97  Status getStatus() const
98  {
99  return status;
100  }
101 
102  Status minimize(VariableArrayType& x, VariableArrayType& g, std::size_t max_iter,
103  const ValueType& g_norm, const ValueType& delta_f, bool do_setup = true)
104  {
105  if (do_setup)
106  setup(x, g);
107 
108  fValue = ValueType(0);
109 
110  for (std::size_t i = 0; max_iter == 0 || i < max_iter; i++) {
111  status = iterate(fValue, x, g);
112 
113  if (status != SUCCESS)
114  return status;
115 
116  if (g_norm >= ValueType(0) && g0Norm <= g_norm)
117  status = GNORM_REACHED;
118 
119  if (delta_f >= ValueType(0) && deltaF <= delta_f)
120  status = Status(status | DELTAF_REACHED);
121 
122  if (status != SUCCESS)
123  return status;
124  }
125 
126  return (status = ITER_LIMIT_REACHED);
127  }
128 
130  const ValueType& step_size = 0.001, const ValueType& tol = 0.15)
131  {
132  numIter = 0;
133  step = step_size;
134  deltaF = ValueType(0);
135 
136  startF = gradFunc(x, g);
137 
138  /* Use the gradient as the initial direction */
139 
140  assign(x0, x);
141  assign(g0, g);
142  g0Norm = norm2(g0);
143 
144  assign(p, g);
145  multiply(p, -1 / g0Norm);
146 
147  pNorm = norm2(p); /* should be 1 */
148  fp0 = -g0Norm;
149 
150  /* Prepare the function evaluation cache */
151 
152  initFuncEvalCache();
153 
154  /* Prepare 1d minimisation parameters */
155 
156  sigma = tol;
157 
158  return startF;
159  }
160 
162  {
163  if (numIter == 0)
164  f = startF;
165 
166  ValueType alpha = ValueType(0), alpha1;
167  ValueType f0 = f;
168 
169  if (pNorm == ValueType(0) || g0Norm == ValueType(0) || fp0 == ValueType(0)) {
170  clear(dx);
171  return NO_PROGRESS;
172  }
173 
174  if (deltaF < ValueType(0)) {
175  ValueType del = std::max(-deltaF, 10 * std::numeric_limits<ValueType>::epsilon() * TypeTraits<ValueType>::abs(f0));
176  alpha1 = std::min(ValueType(1), 2 * del / -fp0);
177 
178  } else
179  alpha1 = TypeTraits<ValueType>::abs(step);
180 
181  /* line minimisation, with cubic interpolation (order = 3) */
182 
183  Status status = minimize(alpha1, alpha);
184 
185  if (status != SUCCESS)
186  return status;
187 
188  updatePosition(alpha, x, f, g);
189 
190  deltaF = f - f0;
191 
192  /* Choose a new direction for the next step */
193 
194  /* This is the BFGS update: */
195  /* p' = g1 - A dx - B dg */
196  /* A = - (1 + dg.dg / dx.dg) B + dg.g / dx.dg */
197  /* B = dx.g / dx.dg */
198 
199  /* dx0 = x - x0 */
200 
201  assign(dx0, x);
202  sub(dx0, x0);
203  assign(dx, dx0); /* keep a copy */
204 
205  /* dg0 = g - g0 */
206 
207  assign(dg0, g);
208  sub(dg0, g0);
209 
210  ValueType dxg = dot(dx0, g);
211  ValueType dgg = dot(dg0, g);
212  ValueType dxdg = dot(dx0, dg0);
213  ValueType dgnorm = norm2(dg0);
214 
215  ValueType A = ValueType(0);
216  ValueType B = ValueType(0);
217 
218  if (dxdg != 0) {
219  B = dxg / dxdg;
220  A = -(1 + dgnorm * dgnorm / dxdg) * B + dgg / dxdg;
221  }
222 
223  assign(p, g);
224 
225  axpy(-A, dx0, p);
226  axpy(-B, dg0, p);
227 
228  assign(g0, g);
229  assign(x0, x);
230  g0Norm = norm2(g0);
231  pNorm = norm2(p);
232 
233  /* update direction and fp0 */
234 
235  ValueType pg = dot(p, g);
236  ValueType dir(pg >= ValueType(0) ? -1 : +1);
237 
238  multiply(p, dir / pNorm);
239 
240  pNorm = norm2(p);
241 
242  fp0 = dot(p, g0);
243 
244  changeDirection();
245 
246  numIter++;
247 
248  return SUCCESS;
249  }
250 
251  private:
252  void initFuncEvalCache()
253  {
254  assign(xAlpha, x0);
255  assign(gAlpha, g0);
256 
257  xCacheKey = ValueType(0);
258  fAlpha = startF;
259  fCacheKey = ValueType(0);
260  gCacheKey = ValueType(0);
261  dfAlpha = slope();
262  dfCacheKey = ValueType(0);
263  }
264 
265  void assign(VariableArrayType& v1, const VariableArrayType& v2)
266  {
268  }
269 
270  void clear(VariableArrayType& v)
271  {
273  }
274 
275  void multiply(VariableArrayType& v, const ValueType& f)
276  {
278  }
279 
280  void sub(VariableArrayType& v1, const VariableArrayType& v2)
281  {
283  }
284 
285  ValueType norm2(const VariableArrayType& v) const
286  {
287  return MinimizerVariableArrayTraits<VA>::template norm2<ValueType>(v);
288  }
289 
290  ValueType dot(const VariableArrayType& v1, const VariableArrayType& v2) const
291  {
292  return MinimizerVariableArrayTraits<VA>::template dot<ValueType>(v1, v2);
293  }
294 
295  void axpy(const ValueType& alpha, const VariableArrayType& x, VariableArrayType& y) const
296  {
298  }
299 
300  ValueType slope() const
301  { /* compute gradient . direction */
302  return dot(gAlpha, p);
303  }
304 
305  void moveTo(const ValueType& alpha)
306  {
307  if (alpha == xCacheKey) /* using previously cached position */
308  return;
309 
310  /* set xAlpha = x + alpha * p */
311 
312  assign(xAlpha, x0);
313 
314  axpy(alpha, p, xAlpha);
315 
316  xCacheKey = alpha;
317  }
318 
319  ValueType getF(const ValueType& alpha)
320  {
321  if (alpha == fCacheKey) /* using previously cached f(alpha) */
322  return fAlpha;
323 
324  moveTo(alpha);
325 
326  fAlpha = func(xAlpha);
327  fCacheKey = alpha;
328 
329  return fAlpha;
330  }
331 
332  ValueType getDF(const ValueType& alpha)
333  {
334  if (alpha == dfCacheKey) /* using previously cached df(alpha) */
335  return dfAlpha;
336 
337  moveTo(alpha);
338 
339  if (alpha != gCacheKey) {
340  fAlpha = gradFunc(xAlpha, gAlpha);
341  gCacheKey = alpha;
342  fCacheKey = alpha;
343  }
344 
345  dfAlpha = slope();
346  dfCacheKey = alpha;
347 
348  return dfAlpha;
349  }
350 
351  void getFDF(const ValueType& alpha, ValueType& f, ValueType& df)
352  {
353  /* Check for previously cached values */
354 
355  if (alpha == fCacheKey && alpha == dfCacheKey) {
356  f = fAlpha;
357  df = dfAlpha;
358  return;
359  }
360 
361  if (alpha == fCacheKey || alpha == dfCacheKey) {
362  df = getDF(alpha);
363  f = getF(alpha);
364  return;
365  }
366 
367  moveTo(alpha);
368 
369  fAlpha = gradFunc(xAlpha, gAlpha);
370  fCacheKey = alpha;
371  gCacheKey = alpha;
372 
373  dfAlpha = slope();
374  dfCacheKey = alpha;
375 
376  f = fAlpha;
377  df = dfAlpha;
378  }
379 
380  void updatePosition(const ValueType& alpha, VariableArrayType& x, ValueType& f, VariableArrayType& g)
381  {
382  ValueType f_alpha, df_alpha;
383 
384  /* ensure that everything is fully cached */
385 
386  getFDF(alpha, f_alpha, df_alpha);
387 
388  f = f_alpha;
389  assign(x, xAlpha);
390  assign(g, gAlpha);
391  }
392 
393  void changeDirection()
394  {
395  /* Convert the cache values from the end of the current minimisation
396  to those needed for the start of the next minimisation, alpha = 0 */
397 
398  /* The new xAlpha for alpha = 0 is the current position */
399 
400  assign(xAlpha, x0);
401  xCacheKey = ValueType(0);
402 
403  /* The function value does not change */
404 
405  fCacheKey = ValueType(0);
406 
407  /* The new gAlpha for alpha = 0 is the current gradient at the endpoint */
408 
409  assign(gAlpha, g0);
410  gCacheKey = ValueType(0);
411 
412  /* Calculate the slope along the new direction vector, p */
413 
414  dfAlpha = slope();
415  dfCacheKey = ValueType(0);
416  }
417 
418  std::size_t solveQuadratic(const ValueType& a, const ValueType& b, const ValueType& c,
419  ValueType& x0, ValueType& x1) const
420  {
421 
422  ValueType disc = b * b - 4 * a * c;
423 
424  if (a == ValueType(0)) { /* Handle linear case */
425  if (b == ValueType(0))
426  return 0;
427 
428  else {
429  x0 = -c / b;
430  return 1;
431  };
432  }
433 
434  if (disc > ValueType(0)) {
435  if (b == ValueType(0)) {
437  x0 = -r;
438  x1 = r;
439 
440  } else {
441  ValueType sgnb(b > ValueType(0) ? 1 : -1);
442  ValueType temp = -(b + sgnb * TypeTraits<ValueType>::sqrt(disc)) / 2;
443  ValueType r1 = temp / a;
444  ValueType r2 = c / temp;
445 
446  if (r1 < r2) {
447  x0 = r1;
448  x1 = r2;
449 
450  } else {
451  x0 = r2;
452  x1 = r1;
453  }
454  }
455 
456  return 2;
457 
458  } else if (disc == ValueType(0)) {
459  x0 = -b / (2 * a);
460  x1 = -b / (2 * a);
461  return 2;
462 
463  } else
464  return 0;
465  }
466 
467  /*
468  * Find a minimum in x = [0, 1] of the interpolating quadratic through
469  * (0, f0) (1, f1) with derivative fp0 at x = 0. The interpolating
470  * polynomial is q(x) = f0 + fp0 * z + (f1 - f0 - fp0) * z^2
471  */
472  ValueType interpolateQuadratic(const ValueType& f0, const ValueType& fp0, const ValueType& f1,
473  const ValueType& zl, const ValueType& zh) const
474  {
475 
476  ValueType fl = f0 + zl * (fp0 + zl * (f1 - f0 - fp0));
477  ValueType fh = f0 + zh * (fp0 + zh * (f1 - f0 - fp0));
478  ValueType c = 2 * (f1 - f0 - fp0); /* curvature */
479 
480  ValueType zmin = zl, fmin = fl;
481 
482  if (fh < fmin) {
483  zmin = zh;
484  fmin = fh;
485  }
486 
487  if (c > ValueType(0)) { /* positive curvature required for a minimum */
488  ValueType z = -fp0 / c; /* location of minimum */
489 
490  if (z > zl && z < zh) {
491  ValueType f = f0 + z * (fp0 + z * (f1 - f0 - fp0));
492 
493  if (f < fmin) {
494  zmin = z;
495  fmin = f;
496  }
497  }
498  }
499 
500  return zmin;
501  }
502 
503  /*
504  * Find a minimum in x = [0, 1] of the interpolating cubic through
505  * (0, f0) (1, f1) with derivatives fp0 at x = 0 and fp1 at x = 1.
506  *
507  * The interpolating polynomial is:
508  *
509  * c(x) = f0 + fp0 * z + eta * z^2 + xi * z^3
510  *
511  * where eta = 3 * (f1 - f0) - 2 * fp0 - fp1, xi = fp0 + fp1 - 2 * (f1 - f0).
512  */
513  ValueType cubic(const ValueType& c0, const ValueType& c1, const ValueType& c2,
514  const ValueType& c3, const ValueType& z) const
515  {
516 
517  return c0 + z * (c1 + z * (c2 + z * c3));
518  }
519 
520  void checkExtremum(const ValueType& c0, const ValueType& c1, const ValueType& c2,
521  const ValueType& c3, const ValueType& z, ValueType& zmin, ValueType& fmin) const
522  {
523  /* could make an early return by testing curvature > 0 for minimum */
524 
525  ValueType y = cubic(c0, c1, c2, c3, z);
526 
527  if (y < fmin) {
528  zmin = z; /* accepted new point*/
529  fmin = y;
530  }
531  }
532 
533  ValueType interpolateCubic(const ValueType& f0, const ValueType& fp0, const ValueType& f1,
534  const ValueType& fp1, const ValueType& zl, const ValueType& zh) const
535  {
536 
537  ValueType eta = 3 * (f1 - f0) - 2 * fp0 - fp1;
538  ValueType xi = fp0 + fp1 - 2 * (f1 - f0);
539  ValueType c0 = f0, c1 = fp0, c2 = eta, c3 = xi;
540 
541  ValueType zmin = zl;
542  ValueType fmin = cubic(c0, c1, c2, c3, zl);
543 
544  checkExtremum(c0, c1, c2, c3, zh, zmin, fmin);
545 
546  ValueType z0, z1;
547  std::size_t n = solveQuadratic(3 * c3, 2 * c2, c1, z0, z1);
548 
549  if (n == 2) { /* found 2 roots */
550  if (z0 > zl && z0 < zh)
551  checkExtremum(c0, c1, c2, c3, z0, zmin, fmin);
552 
553  if (z1 > zl && z1 < zh)
554  checkExtremum(c0, c1, c2, c3, z1, zmin, fmin);
555 
556  } else if (n == 1) { /* found 1 root */
557  if (z0 > zl && z0 < zh)
558  checkExtremum(c0, c1, c2, c3, z0, zmin, fmin);
559  }
560 
561  return zmin;
562  }
563 
564  ValueType interpolate(const ValueType& a, const ValueType& fa, const ValueType& fpa,
565  const ValueType& b, const ValueType& fb, const ValueType& fpb,
566  const ValueType& xmin, const ValueType& xmax) const
567  {
568  /* Map [a, b] to [0, 1] */
569 
570  ValueType zmin = (xmin - a) / (b - a);
571  ValueType zmax = (xmax - a) / (b - a);
572 
573  if (zmin > zmax) {
574  ValueType tmp(zmin);
575  zmin = zmax;
576  zmax = tmp;
577  }
578 
579  ValueType z;
580 
581  if (order > 2 && std::isfinite(fpb))
582  z = interpolateCubic(fa, fpa * (b - a), fb, fpb * (b - a), zmin, zmax);
583  else
584  z = interpolateQuadratic(fa, fpa * (b - a), fb, zmin, zmax);
585 
586  ValueType alpha = a + z * (b - a);
587 
588  return alpha;
589  }
590 
591  Status minimize(const ValueType& alpha1, ValueType& alpha_new)
592  {
593  ValueType falpha, fpalpha, delta, alpha_next;
594  ValueType alpha = alpha1, alpha_prev = ValueType(0);
595  ValueType a = ValueType(0), fb = ValueType(0), fpb = ValueType(0);
596 
597  ValueType f0, fp0;
598 
599  getFDF(ValueType(0), f0, fp0);
600 
601  ValueType falpha_prev = f0;
602  ValueType fpalpha_prev = fp0;
603 
604  ValueType b = alpha;
605  ValueType fa = f0;
606  ValueType fpa = fp0;
607 
608  /* Begin bracketing */
609 
610  const std::size_t num_brack_iter = 100, section_iters = 100;
611  std::size_t i = 0;
612 
613  while (i++ < num_brack_iter) {
614  falpha = getF(alpha);
615 
616  /* Fletcher's rho test */
617 
618  if (falpha > f0 + alpha * rho * fp0 || falpha >= falpha_prev) {
619  a = alpha_prev;
620  fa = falpha_prev;
621  fpa = fpalpha_prev;
622  b = alpha;
623  fb = falpha;
624  fpb = std::numeric_limits<ValueType>::quiet_NaN();
625  break; /* goto sectioning */
626  }
627 
628  fpalpha = getDF(alpha);
629 
630  /* Fletcher's sigma test */
631 
632  if (TypeTraits<ValueType>::abs(fpalpha) <= -sigma * fp0) {
633  alpha_new = alpha;
634  return SUCCESS;
635  }
636 
637  if (fpalpha >= ValueType(0)) {
638  a = alpha;
639  fa = falpha;
640  fpa = fpalpha;
641  b = alpha_prev;
642  fb = falpha_prev;
643  fpb = fpalpha_prev;
644  break; /* goto sectioning */
645  }
646 
647  delta = alpha - alpha_prev;
648 
649  ValueType lower = alpha + delta;
650  ValueType upper = alpha + tau1 * delta;
651 
652  alpha_next = interpolate(alpha_prev, falpha_prev, fpalpha_prev,
653  alpha, falpha, fpalpha, lower, upper);
654 
655  alpha_prev = alpha;
656  falpha_prev = falpha;
657  fpalpha_prev = fpalpha;
658  alpha = alpha_next;
659  }
660 
661  /* Sectioning of bracket [a, b] */
662 
663  while (i++ < section_iters) {
664  delta = b - a;
665 
666  ValueType lower = a + tau2 * delta;
667  ValueType upper = b - tau3 * delta;
668 
669  alpha = interpolate(a, fa, fpa, b, fb, fpb, lower, upper);
670  falpha = getF(alpha);
671 
672  if ((a - alpha) * fpa <= std::numeric_limits<ValueType>::epsilon()) {
673  /* roundoff prevents progress */
674  return NO_PROGRESS;
675  }
676 
677  if (falpha > f0 + rho * alpha * fp0 || falpha >= fa) {
678  /* a_next = a; */
679  b = alpha;
680  fb = falpha;
681  fpb = std::numeric_limits<ValueType>::quiet_NaN();
682 
683  } else {
684  fpalpha = getDF(alpha);
685 
686  if (TypeTraits<ValueType>::abs(fpalpha) <= -sigma * fp0) {
687  alpha_new = alpha;
688  return SUCCESS; /* terminate */
689  }
690 
691  if (((b - a) >= ValueType(0) && fpalpha >= ValueType(0)) || ((b - a) <= ValueType(0) && fpalpha <= ValueType(0))) {
692  b = a;
693  fb = fa;
694  fpb = fpa;
695  a = alpha;
696  fa = falpha;
697  fpa = fpalpha;
698 
699  } else {
700  a = alpha;
701  fa = falpha;
702  fpa = fpalpha;
703  }
704  }
705  }
706 
707  return SUCCESS;
708  }
709 
710  const ValueType rho;
711  const ValueType tau1;
712  const ValueType tau2;
713  const ValueType tau3;
714  const std::size_t order;
715  std::size_t numIter;
716  ValueType step;
717  ValueType g0Norm;
718  ValueType pNorm;
719  ValueType startF;
720  ValueType deltaF;
721  ValueType fValue;
722  ValueType fp0;
727  VariableArrayType dx0;
728  VariableArrayType dg0;
729  VariableArrayType xAlpha;
730  VariableArrayType gAlpha;
731  ValueType sigma;
732  ValueType fAlpha;
733  ValueType dfAlpha;
734  ValueType fCacheKey;
735  ValueType dfCacheKey;
736  ValueType xCacheKey;
737  ValueType gCacheKey;
738  ObjectiveFunction func;
739  GradientFunction gradFunc;
740  Status status;
741  };
742  } // namespace Math
743 } // namespace CDPL
744 
745 #endif // CDPL_MATH_BFGSMINIMIZER_HPP
Provides traits to flexibly handle different types of variable arrays in function optimization algori...
Definition of type traits.
Fletcher's implementation of the BFGS method.
Definition: BFGSMinimizer.hpp:54
Status iterate(ValueType &f, VariableArrayType &x, VariableArrayType &g)
Definition: BFGSMinimizer.hpp:161
std::function< FVT(const VA &)> ObjectiveFunction
Definition: BFGSMinimizer.hpp:62
ValueType getFunctionValue() const
Definition: BFGSMinimizer.hpp:87
Status getStatus() const
Definition: BFGSMinimizer.hpp:97
Status minimize(VariableArrayType &x, VariableArrayType &g, std::size_t max_iter, const ValueType &g_norm, const ValueType &delta_f, bool do_setup=true)
Definition: BFGSMinimizer.hpp:102
Status
Definition: BFGSMinimizer.hpp:65
@ NO_PROGRESS
Definition: BFGSMinimizer.hpp:68
@ SUCCESS
Definition: BFGSMinimizer.hpp:67
@ GNORM_REACHED
Definition: BFGSMinimizer.hpp:70
@ ITER_LIMIT_REACHED
Definition: BFGSMinimizer.hpp:69
@ DELTAF_REACHED
Definition: BFGSMinimizer.hpp:71
BFGSMinimizer(const ObjectiveFunction &func, const GradientFunction &grad_func)
Definition: BFGSMinimizer.hpp:74
ValueType getGradientNorm() const
Definition: BFGSMinimizer.hpp:77
std::function< FVT(const VA &, VA &)> GradientFunction
Definition: BFGSMinimizer.hpp:61
ValueType setup(const VariableArrayType &x, VariableArrayType &g, const ValueType &step_size=0.001, const ValueType &tol=0.15)
Definition: BFGSMinimizer.hpp:129
FVT FunctionValueType
Definition: BFGSMinimizer.hpp:59
ValueType getFunctionDelta() const
Definition: BFGSMinimizer.hpp:82
std::size_t getNumIterations() const
Definition: BFGSMinimizer.hpp:92
VT ValueType
Definition: BFGSMinimizer.hpp:58
VA VariableArrayType
Definition: BFGSMinimizer.hpp:57
constexpr unsigned int A
A generic type that covers any element except hydrogen.
Definition: AtomType.hpp:637
constexpr unsigned int B
Specifies Boron.
Definition: AtomType.hpp:87
constexpr unsigned int r
Specifies that the stereocenter has r configuration.
Definition: CIPDescriptor.hpp:76
The namespace of the Chemical Data Processing Library.
static void axpy(const T &alpha, const ArrayType &x, ArrayType &y)
Definition: MinimizerVariableArrayTraits.hpp:91
static void multiply(ArrayType &a, const T &v)
Definition: MinimizerVariableArrayTraits.hpp:107
static void sub(ArrayType &a1, const ArrayType &a2)
Definition: MinimizerVariableArrayTraits.hpp:112
static void assign(ArrayType &a1, const ArrayType &a2)
Definition: MinimizerVariableArrayTraits.hpp:101
static void clear(ArrayType &a)
Definition: MinimizerVariableArrayTraits.hpp:96
static RealType abs(ConstReference t)
Definition: TypeTraits.hpp:89
static ValueType sqrt(ConstReference t)
Definition: TypeTraits.hpp:94
Definition: TypeTraits.hpp:171