Xmipp  v3.23.11-Nereus
MSSolver.cpp
Go to the documentation of this file.
1 /*
2 
3 CONDOR 1.06 - COnstrained, Non-linear, Direct, parallel Optimization
4  using trust Region method for high-computing load,
5  noisy functions
6 Copyright (C) 2004 Frank Vanden Berghen
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation version 2
11 of the License.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 
22 If you want to include this tools in any commercial product,
23 you can contact the author at fvandenb@iridia.ulb.ac.be
24 
25 */
26 
27 // model step solver
28 
29 #include <stdio.h>
30 #include <memory.h>
31 
32 #include "Matrix.h"
33 #include "tools.h"
34 #include "Poly.h"
35 
36 
37 //int lagmax_(int *n, double *g, double *h__, double *rho,
38 // double *d__, double *v, double *vmax);
39 
40 Vector LAGMAXModified(Vector G, Matrix H, double rho,double &VMAX)
41 {
42  //not tested in depth but running already quite good
43 
44 // SUBROUTINE LAGMAX (N,G,H,RHO,D,V,VMAX)
45 // IMPLICIT REAL*8 (A-H,O-Z)
46 // DIMENSION G(*),H(N,*),D(*),V(*)
47 //
48 // N is the number of variables of a quadratic objective function, Q say.
49 // G is the gradient of Q at the origin.
50 // H is the symmetric Hessian matrix of Q. Only the upper triangular and
51 // diagonal parts need be set.
52 // RHO is the trust region radius, and has to be positive.
53 // D will be set to the calculated vector of variables.
54 // The array V will be used for working space.
55 // VMAX will be set to |Q(0)-Q(D)|.
56 //
57 // Calculating the D that maximizes |Q(0)-Q(D)| subject to ||D|| .EQ. RHO
58 // requires of order N**3 operations, but sometimes it is adequate if
59 // |Q(0)-Q(D)| is within about 0.9 of its greatest possible value. This
60 // subroutine provides such a solution in only of order N**2 operations,
61 // where the claim of accuracy has been tested by numerical experiments.
62 /*
63  int n=G.sz();
64  Vector D(n), V(n);
65  lagmax_(&n, (double *)G, *((double**)H), &rho,
66  (double*)D, (double*)V, &VMAX);
67  return D;
68 */
69  int i,n=G.sz();
70  Vector D(n);
71 
72  Vector V=H.getMaxColumn();
73  D=H.multiply(V);
74  double vv=V.square(),
75  dd=D.square(),
76  vd=V.scalarProduct(D),
77  dhd=D.scalarProduct(H.multiply(D)),
78  *d=D, *v=V, *g=G;
79 
80 //
81 // Set D to a vector in the subspace spanned by V and HV that maximizes
82 // |(D,HD)|/(D,D), except that we set D=HV if V and HV are nearly parallel.
83 //
84  if (sqr(vd)<0.9999*vv*dd)
85  {
86  double a=dhd*vd-dd*dd,
87  b=.5*(dhd*vv-dd*vd),
88  c=dd*vv-vd*vd,
89  tmp1=-b/a;
90  if (b*b>a*c)
91  {
92  double tmp2=sqrt(b*b-a*c)/a, dd1, dd2, dhd1, dhd2;
93  Vector D1=D.clone();
94  D1.multiply(tmp1+tmp2);
95  D1+=V;
96  dd1=D1.square();
97  dhd1=D1.scalarProduct(H.multiply(D1));
98 
99  Vector D2=D.clone();
100  D2.multiply(tmp1-tmp2);
101  D2+=V;
102  dd2=D2.square();
103  dhd2=D2.scalarProduct(H.multiply(D2));
104 
105  if (condorAbs(dhd1/dd1)>condorAbs(dhd2/dd2)) { D=D1; dd=dd1; dhd=dhd1; }
106  else { D=D2; dd=dd2; dhd=dhd2; }
107  d=(double*)D;
108  }
109  };
110 
111 
112 //
113 // We now turn our attention to the subspace spanned by G and D. A multiple
114 // of the current D is returned if that choice seems to be adequate.
115 //
116  double gg=G.square(),
117  normG=sqrt(gg),
118  gd=G.scalarProduct(D),
119  temp=gd/gg,
120  scale=sign(rho/sqrt(dd), gd*dhd);
121 
122  i=n; while (i--) v[i]=d[i]-temp*g[i];
123  vv=V.square();
124 
125  if ((normG*dd)<(0.5-2*rho*condorAbs(dhd))||(vv/dd<1e-4))
126  {
127  D.multiply(scale);
128  VMAX=condorAbs(scale*(gd+0.5*scale*dhd));
129  return D;
130  }
131 
132 //
133 // G and V are now orthogonal in the subspace spanned by G and D. Hence
134 // we generate an orthonormal basis of this subspace such that (D,HV) is
135 // negligible or zero, where D and V will be the basis vectors.
136 //
137  H.multiply(D,G); // D=HG;
138  double ghg=G.scalarProduct(D),
139  vhg=V.scalarProduct(D),
140  vhv=V.scalarProduct(H.multiply(V));
141  double theta, cosTheta, sinTheta;
142 
143  if (condorAbs(vhg)<0.01*mmax(condorAbs(vhv),condorAbs(ghg)))
144  {
145  cosTheta=1.0;
146  sinTheta=0.0;
147  } else
148  {
149  theta=0.5*atan(0.5*vhg/(vhv-ghg));
150  cosTheta=cos(theta);
151  sinTheta=sin(theta);
152  }
153  i=n;
154  while(i--)
155  {
156  d[i]= cosTheta*g[i]+ sinTheta*v[i];
157  v[i]=-sinTheta*g[i]+ cosTheta*v[i];
158  };
159 
160 //
161 // The final D is a multiple of the current D, V, D+V or D-V. We make the
162 // choice from these possibilities that is optimal.
163 //
164 
165  double norm=rho/D.euclidianNorm();
166  D.multiply(norm);
167  dhd=(ghg*sqr(cosTheta)+vhv*sqr(sinTheta))*sqr(norm);
168 
169  norm=rho/V.euclidianNorm();
170  V.multiply(norm);
171  vhv=(ghg*sqr(sinTheta)+vhv*sqr(cosTheta)*sqr(norm));
172 
173  double halfRootTwo=sqrt(0.5), // =sqrt(2)/2=cos(PI/4)
174  t1=normG*cosTheta*rho, // t1=condorAbs(D.scalarProduct(G));
175  t2=normG*sinTheta*rho, // t2=condorAbs(V.scalarProduct(G));
176  at1=condorAbs(t1),
177  at2=condorAbs(t2),
178  t3=0.25*(dhd+vhv),
179  q1=condorAbs(at1+0.5*dhd),
180  q2=condorAbs(at2+0.5*vhv),
181  q3=condorAbs(halfRootTwo*(at1+at2)+t3),
182  q4=condorAbs(halfRootTwo*(at1-at2)+t3);
183  if ((q4>q3)&&(q4>q2)&&(q4>q1))
184  {
185  double st1=sign(t1*t3), st2=sign(t2*t3);
186  i=n; while (i--) d[i]=halfRootTwo*(st1*d[i]-st2*v[i]);
187  VMAX=q4;
188  return D;
189  }
190  if ((q3>q2)&&(q3>q1))
191  {
192  double st1=sign(t1*t3), st2=sign(t2*t3);
193  i=n; while (i--) d[i]=halfRootTwo*(st1*d[i]+st2*v[i]);
194  VMAX=q3;
195  return D;
196  }
197  if (q2>q1)
198  {
199  if (t2*vhv<0) V.multiply(-1);
200  VMAX=q2;
201  return V;
202  }
203  if (t1*dhd<0) D.multiply(-1);
204  VMAX=q1;
205  return D;
206 }
207 
208 Vector LAGMAXModified(Polynomial q, Vector pointXk, double rho,double &VMAX)
209 {
210  int n=q.dim();
211  Matrix H(n,n);
212  Vector G(n), D(n);
213  q.gradientHessian(pointXk,G,H);
214  return LAGMAXModified(G,H,rho,VMAX);
215 }
216 
217 Vector LAGMAXModified(Polynomial q, double rho,double &VMAX)
218 {
219  return LAGMAXModified(q,Vector::emptyVector,rho,VMAX);
220 }
double dhd
int * mmax
double sign
doublereal * c
doublereal * g
double rho
void sqrt(Image< double > &op)
Matrix multiply(Matrix B)
Definition: Matrix.cpp:633
Definition: Vector.h:37
unsigned dim()
Definition: Poly.h:62
double euclidianNorm()
Definition: Vector.cpp:222
T norm(const std::vector< T > &v)
Definition: vector_ops.h:399
#define q1
Vector clone()
Definition: Vector.cpp:207
#define i
doublereal * d
double theta
double vv
unsigned sz()
Definition: Vector.h:79
double sqr(const double &t)
Definition: tools.h:99
doublereal * b
void gradientHessian(Vector P, Vector G, Matrix H)
Definition: Poly.cpp:515
Vector getMaxColumn()
Definition: Matrix.cpp:1073
double condorAbs(const double t1)
Definition: tools.h:47
double square()
Definition: Vector.cpp:236
Definition: Matrix.h:38
void multiply(double a)
Definition: Vector.cpp:281
#define q2
double scalarProduct(Vector v)
Definition: Vector.cpp:332
static Vector emptyVector
Definition: Vector.h:119
Vector LAGMAXModified(Vector G, Matrix H, double rho, double &VMAX)
Definition: MSSolver.cpp:40
int * n
#define q3
doublereal * a