1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2024-07-18 17:03:43 +02:00
qmckl/org/qmckl_sherman_morrison_woodbury.org

9.6 KiB

Sherman-Morrison-Woodbury

Low- and high-level functions that use the Sherman-Morrison and Woodbury matrix inversion formulas to update the inverse of a non-singualr matrix

Headers

(org-babel-lob-ingest "../tools/lib.org")
#include "qmckl.h"
#include "assert.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#ifndef THRESHOLD
#define THRESHOLD 1e-3
#endif

#include "qmckl.h"

int main() {
qmckl_context context;
context = qmckl_context_create();

Sherman-Morrison Helper Functions

[TODO: FMJC] Add doc

qmckl_sherman_morrison_threshold

[TODO: FMJC] Add doc

double thresh out Threshold

Requirements

Add description of the input variables. (see for e.g. qmckl_distance.org)

C header

// Sherman-Morrison-Woodbury break-down threshold
#ifndef THRESHOLD
#define THRESHOLD 1e-3
#endif

qmckl_exit_code qmckl_sherman_morrison_threshold (
double* const thresh );

Source Fortran

integer function qmckl_sherman_morrison_threshold_f(thresh) result(info) 
use qmckl
implicit none
real*8     , intent(inout)  :: thresh
!logical, external :: qmckl_sherman_morrison_f
info = qmckl_sherman_morrison_threshold(thresh)
end function qmckl_sherman_morrison_threshold_f

Source C

#include <stdbool.h>
#include <math.h>
#include "qmckl.h"

// Sherman-Morrison-Woodbury break-down threshold
static double qmckl_shreman_morrison_threshold(double* const threshold) {
*threshold = THRESHOLD;
#ifdef DEBUG
std::cerr << "Break-down threshold set to: " << threshold << std::endl;
#endif
}

Performance

Naïve Sherman-Morrison

qmckl_sherman_morrison

The Sherman-Morrison formula

\begin{align} S_k^{-1} &= (S_l + U_k)^-1 \\ &= S_l^{-1} - \frac{S_l^{-1}U_kS_l}{1+\underline{v}_k^tS_l^{-1}\underline{u}_k} \end{align}
qmckl_context context in Global state
uint64_t Dim in Leading dimension of Slater_inv
uint64_t N_updates in Number of rank-1 updates to be applied to Slater_inv
double Updates[N_updates*Dim] in Array containing the updates
uint64_t Updates_index[N_updates] in Array containing the rank-1 updates
double Slater_inv[Dim*Dim] inout Array containing the inverse of a Slater-matrix

Requirements

Add description of the input variables. (see for e.g. qmckl_distance.org)

C header

qmckl_exit_code qmckl_sherman_morrison_c (
const qmckl_context context,
const uint64_t Dim,
const uint64_t N_updates,
const double* Updates,
const uint64_t* Updates_index,
double* Slater_inv );

Source Fortran

integer function qmckl_sherman_morrison_f(context, Slater_inv, Dim, N_updates,    &
     Updates, Updates_index) result(info) 
use qmckl
implicit none
integer(qmckl_context)  , intent(in)  :: context
integer*8  , intent(in)  :: Dim, N_updates
integer*8  , intent(in)  :: Updates_index(N_updates)
real*8     , intent(in) :: Updates(N_updates*Dim)
real*8     , intent(inout)  :: Slater_inv(Dim*Dim)
!logical, external :: qmckl_sherman_morrison_f
info = qmckl_sherman_morrison(context, Dim, N_updates, Updates, Updates_index, Slater_inv)
end function qmckl_sherman_morrison_f

Source C

#include <stdbool.h>
#include "qmckl.h"

qmckl_exit_code qmckl_sherman_morrison_c(const qmckl_context context, 
                            const uint64_t Dim,
                            const uint64_t N_updates,
                            const double* Updates,
                            const uint64_t* Updates_index,
                            double * Slater_inv) {
#ifdef DEBUG
std::cerr << "Called qmckl_sherman_morrison with " << N_updates << " updates" << std::endl;
#endif

double C[Dim];
double D[Dim];

double threshold = 0.0;
qmckl_sherman_morrison_threshold(&threshold);

unsigned int l = 0;
// For each update
while (l < N_updates) {
// C = A^{-1} x U_l
for (unsigned int i = 0; i < Dim; i++) {
  C[i] = 0;
  for (unsigned int j = 0; j < Dim; j++) {
    C[i] += Slater_inv[i * Dim + j] * Updates[l * Dim + j];
  }
}

// Denominator
double den = 1 + C[Updates_index[l] - 1];
if (fabs(den) < threshold) {
  return false;
}
double iden = 1 / den;

// D = v^T x A^{-1}
for (unsigned int j = 0; j < Dim; j++) {
  D[j] = Slater_inv[(Updates_index[l] - 1) * Dim + j];
}

// A^{-1} = A^{-1} - C x D / den
for (unsigned int i = 0; i < Dim; i++) {
  for (unsigned int j = 0; j < Dim; j++) {
    double update = C[i] * D[j] * iden;
    Slater_inv[i * Dim + j] -= update;
  }
}

l += 1;
}
return QMCKL_SUCCESS;
}

Performance

End of files

assert (qmckl_context_destroy(context) == QMCKL_SUCCESS);
return 0;
}