From 5ec40e2e229332080c6122c4bf2e7eab6e467407 Mon Sep 17 00:00:00 2001
From: capoe <cp605@cam.ac.uk>
Date: Mon, 27 Feb 2017 15:53:17 +0000
Subject: [PATCH] Added atomic rematch kernel.

---
 src/soap/linalg/kernel.hpp | 86 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 src/soap/linalg/kernel.hpp

diff --git a/src/soap/linalg/kernel.hpp b/src/soap/linalg/kernel.hpp
new file mode 100644
index 0000000..8bedc9f
--- /dev/null
+++ b/src/soap/linalg/kernel.hpp
@@ -0,0 +1,86 @@
+#ifndef _SOAP_LINALG_KERNEL_H
+#define	_SOAP_LINALG_KERNEL_H
+
+#include <iostream>
+#include <cmath>
+#include <stdexcept>
+#include <string>
+#include <boost/numeric/ublas/lu.hpp>
+#include <boost/python.hpp>
+#include <boost/python/numeric.hpp>
+#include "soap/linalg/numpy.hpp"
+
+namespace soap { namespace linalg {
+
+namespace ub = boost::numeric::ublas;
+
+boost::python::object kernel_rematch_atomic(boost::python::object &kmat_npy, double gamma, double eps) {
+    // CONVERT NUMPY KERNEL MATRIX TO UBLAS
+    soap::linalg::numpy_converter npc("float64");
+    ub::matrix<double> kmat;
+    npc.numpy_to_ublas<double>(kmat_npy, kmat);
+    // INITIALIZE OPTIMIZATION
+    int nx = kmat.size1();
+    int ny = kmat.size2();
+    std::vector<double> u(nx), ou(nx), v(ny);
+    double ax = 1.0/nx, ay=1.0/ny;
+    ub::matrix<double> Kg(nx,ny);
+    for (int i=0; i<nx; ++i) u[i]=1.0;
+    for (int i=0; i<ny; ++i) v[i]=1.0;
+    double lambda=1.0/gamma, terr=eps*eps, derr;
+    for (int i=0; i<nx; ++i) 
+        for (int j=0; j<ny; ++j) 
+            Kg(i,j)=std::exp(-(1-kmat(i,j))*lambda);
+    // OPTIMIZE 
+    do {
+        // u<-1.0/Kg.v
+        for (int i=0; i<nx; ++i) { ou[i]=u[i]; u[i]=0.0; }
+        for (int i=0; i<nx; ++i) for (int j=0; j<ny; ++j) u[i]+=Kg(i,j)*v[j];
+        // at this point we can compute how far off unity we are
+        derr = 0.0;
+        for (int i=0; i<nx; ++i) derr+=(ax-ou[i]*u[i])*(ax-ou[i]*u[i]);        
+        for (int i=0; i<nx; ++i) u[i]=ax/u[i];
+        // v<-1.0/Kg.u
+        for (int i=0; i<ny; ++i) v[i]=0.0; 
+        for (int i=0; i<ny; ++i) for (int j=0; j<nx; ++j) v[i]+=Kg(j,i)*u[j];
+        for (int i=0; i<ny; ++i) v[i]=ay/v[i];
+        //std::cerr<<derr<<"\n";
+    } while (derr>terr);
+    /* 
+    // COMPUTE KERNEL VALUE
+    double rval=0, rrow; 
+    for (int i=0; i<nx; ++i) 
+    {
+       std::cout << "Row " << i << std::endl;
+       rrow=0;
+       for (int j=0; j<ny; ++j) {
+          rrow+=Kg(i,j)*kmat(i,j)*v[j];
+          std::cout << Kg(i,j) << "   " << kmat(i,j) << "   " << v[j] << " u*K*v " << u[i]*Kg(i,j)*v[j] << std::endl;
+       }
+       rval+=u[i]*rrow;
+    }   
+    */
+    // RETURN REGULARIZED PERMUTATION MATRIX
+    ub::matrix<double> Pij(nx, ny);
+    for (int i=0; i<nx; ++i) {
+        for (int j=0; j<ny; ++j) {
+            Pij(i,j) = u[i]*Kg(i,j)*v[j];
+        }
+    }
+    return npc.ublas_to_numpy<double>(Pij);
+};
+
+class KernelModule {
+public:
+    KernelModule();
+    static void registerPython() {
+        using namespace boost::python;
+        def("kernel_rematch_atomic", kernel_rematch_atomic);
+    }
+private:
+};
+
+}}
+
+#endif	
+
-- 
GitLab