From a35166f14d68752e0cf35d5356137c4bd29e6164 Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Thu, 14 Oct 2010 14:57:50 +0000
Subject: [PATCH] Use the polarization identity from Absil, Mahony, Sepulchre
 (page 107) to compute an fd approximation of the Riemannian Hessian

[[Imported from SVN: r6431]]
---
 test/unitvectortest.cc | 51 +++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 21 deletions(-)

diff --git a/test/unitvectortest.cc b/test/unitvectortest.cc
index a8ea9692..79a7e5f2 100644
--- a/test/unitvectortest.cc
+++ b/test/unitvectortest.cc
@@ -30,6 +30,11 @@ double energy(const FieldVector<double,dim>& a, const FieldVector<double,dim>& b
     return TargetSpace::distance(a,b) * TargetSpace::distance(a,b);
 }
 
+/** \brief Compute the Riemannian Hessian of the squared distance function in global coordinates
+
+    The formula for the Riemannian Hessian has been taken from Absil, Mahony, Sepulchre:
+    'Optimization algorithms on matrix manifolds', page 107
+*/
 template <class TargetSpace, int dim>
 FieldMatrix<double,dim,dim> getSecondDerivativeOfSecondArgumentFD(const TargetSpace& a, const TargetSpace& b)
 {
@@ -38,34 +43,38 @@ FieldMatrix<double,dim,dim> getSecondDerivativeOfSecondArgumentFD(const TargetSp
     
     for (size_t i=0; i<dim; i++) {
         for (size_t j=0; j<dim; j++) {
+
+            FieldVector<double,dim> epsXi(0);
+            epsXi[i] = eps;
+            FieldVector<double,dim> epsEta(0);
+            epsEta[j] = eps;
             
-            if (i==j) {
+            FieldVector<double,dim> minusEpsXi  = epsXi;   minusEpsXi  *= -1;
+            FieldVector<double,dim> minusEpsEta = epsEta;  minusEpsEta *= -1;
             
-                FieldVector<double,dim> bPlus  = b.globalCoordinates();
-                FieldVector<double,dim> bMinus = b.globalCoordinates();
-                bPlus[i]  += eps;
-                bMinus[i] -= eps;
-
-                d2d2_fd[i][i] = (energy(a,bPlus) - 2*energy(a,b) + energy(a,bMinus)) / (eps*eps);
-            } else {
-                
-                FieldVector<double,dim> bPlusPlus   = b.globalCoordinates();
-                FieldVector<double,dim> bPlusMinus  = b.globalCoordinates();
-                FieldVector<double,dim> bMinusPlus  = b.globalCoordinates();
-                FieldVector<double,dim> bMinusMinus = b.globalCoordinates();
+            double forwardValue  = energy(a,TargetSpace::exp(b,epsXi+epsEta)) - energy(a, TargetSpace::exp(b,epsXi)) - energy(a,TargetSpace::exp(b,epsEta));
+            double centerValue   = energy(a,b)                   - energy(a,b)              - energy(a,b);
+            double backwardValue = energy(a,TargetSpace::exp(b,minusEpsXi + minusEpsEta)) - energy(a, TargetSpace::exp(b,minusEpsXi)) - energy(a,TargetSpace::exp(b,minusEpsEta));
             
-                bPlusPlus[i]   += eps;  bPlusPlus[j]   += eps;
-                bPlusMinus[i]  += eps;  bPlusMinus[j]  -= eps;
-                bMinusPlus[i]  -= eps;  bMinusPlus[j]  += eps;
-                bMinusMinus[i] -= eps;  bMinusMinus[j] -= eps;
+            d2d2_fd[i][j] = 0.5 * (forwardValue - 2*centerValue + backwardValue) / (eps*eps);
             
-                d2d2_fd[i][j] = (energy(a,bPlusPlus) + energy(a,bMinusMinus)
-                                        - energy(a,bPlusMinus) - energy(a,bMinusPlus)) / (4*eps*eps);
-            }
         }
     }
     
-    return d2d2_fd;
+    FieldMatrix<double,dim,dim> B = b.orthonormalFrame();
+    B.invert();
+    FieldMatrix<double,dim,dim> BT;
+    for (int i=0; i<dim; i++)
+        for (int j=0; j<dim; j++)
+            BT[i][j] = B[j][i];
+    
+    
+    FieldMatrix<double,dim,dim> ret1;
+    FMatrixHelp::multMatrix(d2d2_fd,B,ret1);
+    
+    FieldMatrix<double,dim,dim> ret2;
+    FMatrixHelp::multMatrix(BT,ret1,ret2);
+    return ret2;
 }
 
 template <class TargetSpace, int dim>
-- 
GitLab