From e7ae668ef46a2d456debbb2623b1e42810ca4f36 Mon Sep 17 00:00:00 2001
From: Jakhes <dean.schmitz@schmitzbauer.de>
Date: Fri, 16 Sep 2022 22:48:51 +0200
Subject: [PATCH] Adding Fastmks

---
 Makefile                             |   2 +
 src/methods/fastmks/Makefile         |   8 ++
 src/methods/fastmks/fastmks.cpp      | 151 +++++++++++++++++++++++++++
 src/methods/fastmks/fastmks.pl       |  67 ++++++++++++
 src/methods/fastmks/fastmks_test.pl  |  56 ++++++++++
 src/methods/new_method/new_method.pl |   2 +
 6 files changed, 286 insertions(+)
 create mode 100644 src/methods/fastmks/Makefile
 create mode 100644 src/methods/fastmks/fastmks.cpp
 create mode 100644 src/methods/fastmks/fastmks.pl
 create mode 100644 src/methods/fastmks/fastmks_test.pl

diff --git a/Makefile b/Makefile
index 5d58849..c5941fd 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@ all:
 	make -C src/methods/random_forest splfr=$(SPLFR_PATH)
 	make -C src/methods/softmac_regression splfr=$(SPLFR_PATH)
 	make -C src/methods/approx_kfn splfr=$(SPLFR_PATH)
+	make -C src/methods/fastmks splfr=$(SPLFR_PATH)
 
 clean:
 	make -C src/methods/ada_boost clean
@@ -34,5 +35,6 @@ clean:
 	make -C src/methods/random_forest clean
 	make -C src/methods/softmac_regression clean
 	make -C src/methods/approx_kfn clean
+	make -C src/methods/fastmks clean
 
 	
\ No newline at end of file
diff --git a/src/methods/fastmks/Makefile b/src/methods/fastmks/Makefile
new file mode 100644
index 0000000..5295563
--- /dev/null
+++ b/src/methods/fastmks/Makefile
@@ -0,0 +1,8 @@
+splfr=/usr/local/sicstus4.7.1/bin/splfr
+
+METHOD_NAME=fastmks
+
+$(METHOD_NAME).so: $(METHOD_NAME).pl $(METHOD_NAME).cpp
+	$(splfr) -larmadillo -fopenmp -lmlpack -lstdc++ -cxx --struct $(METHOD_NAME).pl $(METHOD_NAME).cpp ../../helper_files/helper.cpp
+clean:
+	rm $(METHOD_NAME).so
diff --git a/src/methods/fastmks/fastmks.cpp b/src/methods/fastmks/fastmks.cpp
new file mode 100644
index 0000000..2641e15
--- /dev/null
+++ b/src/methods/fastmks/fastmks.cpp
@@ -0,0 +1,151 @@
+#include <sicstus/sicstus.h>
+/* ex_glue.h is generated by splfr from the foreign/[2,3] facts.
+   Always include the glue header in your foreign resource code.
+*/
+#include "fastmks_glue.h"
+#include <mlpack/methods/fastmks/fastmks_model.hpp>
+#include <mlpack/core.hpp>
+
+// including helper functions for converting between arma structures and arrays
+#include "../../helper_files/helper.hpp"
+
+// some of the most used namespaces
+using namespace arma;
+using namespace mlpack;
+using namespace std;
+using namespace mlpack::fastmks;
+using namespace mlpack::kernel;
+
+// Global Variable of the FastMKSModel object so it can be accessed from all functions
+FastMKSModel fastMKSModel;
+
+// TODO: 
+// input:   util::Timers & 	timers,
+//          arma::mat && 	referenceData,
+//          TKernelType & 	kernel,
+//			double 			degree,
+//			double 			offset,
+//			double 			bandwidth,
+//			double 			scale
+//          const bool 	    singleMode,
+//          const bool 	    naive,
+//          const double 	base
+// output: 
+// description: 
+void initModel(float *referenceMatArr, SP_integer referenceMatSize, SP_integer referenceMatRowNum, char const *kernel, double degree, double offset, double bandwidth, double scale, SP_integer singleMode, SP_integer naive, double base)
+{
+    // convert the Prolog arrays to arma::mat
+    mat reference = convertArrayToMat(referenceMatArr, referenceMatSize, referenceMatRowNum);
+
+    if (strcmp(kernel, "linear") == 0)        
+    {
+        fastMKSModel = FastMKSModel(0);
+        LinearKernel lk;
+        fastMKSModel.BuildModel(move(reference), lk, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "polynomial") == 0)
+    {
+      PolynomialKernel pk(degree, offset);
+      fastMKSModel.KernelType() = FastMKSModel::POLYNOMIAL_KERNEL;
+      fastMKSModel.BuildModel(move(reference), pk, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "cosine") == 0)
+    {
+      CosineDistance cd;
+      fastMKSModel.KernelType() = FastMKSModel::COSINE_DISTANCE;
+      fastMKSModel.BuildModel(move(reference), cd, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "gaussian") == 0)
+    {
+      GaussianKernel gk(bandwidth);
+      fastMKSModel.KernelType() = FastMKSModel::GAUSSIAN_KERNEL;
+      fastMKSModel.BuildModel(move(reference), gk, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "epanechnikov") == 0)
+    {
+      EpanechnikovKernel ek(bandwidth);
+      fastMKSModel.KernelType() = FastMKSModel::EPANECHNIKOV_KERNEL;
+      fastMKSModel.BuildModel(move(reference), ek, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "triangular") == 0)
+    {
+      TriangularKernel tk(bandwidth);
+      fastMKSModel.KernelType() = FastMKSModel::TRIANGULAR_KERNEL;
+      fastMKSModel.BuildModel(move(reference), tk, (singleMode == 1), (naive == 1), base);
+    }
+    else if (strcmp(kernel, "hyptan") == 0)
+    {
+      HyperbolicTangentKernel htk(scale, offset);
+      fastMKSModel.KernelType() = FastMKSModel::HYPTAN_KERNEL;
+      fastMKSModel.BuildModel(move(reference), htk, (singleMode == 1), (naive == 1), base);
+    }
+}
+
+// TODO: 
+// input:   util::Timers & 	        timers,
+//          const arma::mat & 	    querySet,
+//          const size_t 	        k,
+//          arma::Mat< size_t > & 	indices <-,
+//          arma::mat & 	        kernels <-,
+//          const double 	        base
+// output: 
+// description: 
+void searchWithQuery(float *querySetMatArr, SP_integer querySetMatSize, SP_integer querySetMatRowNum, SP_integer k, float **indicesMatArr, SP_integer *indicesMatColNum, SP_integer *indicesMatRowNum, float **kernelsMatArr, SP_integer *kernelsMatColNum, SP_integer *kernelsMatRowNum, double base)
+{
+    // convert the Prolog arrays to arma::mat
+    mat querySet = convertArrayToMat(querySetMatArr, querySetMatSize, querySetMatRowNum);
+    
+    // create the ReturnMat
+    arma::Mat< size_t > indicesReturnMat;
+
+    // create the ReturnMat
+    mat kernelsReturnMat;
+
+    fastMKSModel.Search(querySet, k, indicesReturnMat, kernelsReturnMat, base);
+    
+    // return the Matrix dimensions
+    *indicesMatColNum = indicesReturnMat.n_cols;
+    *indicesMatRowNum = indicesReturnMat.n_rows;
+    
+    // return the Matrix as one long Array
+    *indicesMatArr = convertToArray(indicesReturnMat);
+    
+    // return the Matrix dimensions
+    *kernelsMatColNum = kernelsReturnMat.n_cols;
+    *kernelsMatRowNum = kernelsReturnMat.n_rows;
+    
+    // return the Matrix as one long Array
+    *kernelsMatArr = convertToArray(kernelsReturnMat);
+}
+
+// TODO: 
+// input:   util::Timers & 	        timers,
+//          const size_t 	        k,
+//          arma::Mat< size_t > & 	indices <-,
+//          arma::mat & 	        kernels <-
+// output: 
+// description: 
+void searchNoQuery(SP_integer k, float **indicesMatArr, SP_integer *indicesMatColNum, SP_integer *indicesMatRowNum, float **kernelsMatArr, SP_integer *kernelsMatColNum, SP_integer *kernelsMatRowNum)
+{
+    // create the ReturnMat
+    arma::Mat< size_t > indicesReturnMat;
+
+    // create the ReturnMat
+    mat kernelsReturnMat;
+
+    fastMKSModel.Search(k, indicesReturnMat, kernelsReturnMat);
+    
+    // return the Matrix dimensions
+    *indicesMatColNum = indicesReturnMat.n_cols;
+    *indicesMatRowNum = indicesReturnMat.n_rows;
+    
+    // return the Matrix as one long Array
+    *indicesMatArr = convertToArray(indicesReturnMat);
+    
+    // return the Matrix dimensions
+    *kernelsMatColNum = kernelsReturnMat.n_cols;
+    *kernelsMatRowNum = kernelsReturnMat.n_rows;
+    
+    // return the Matrix as one long Array
+    *kernelsMatArr = convertToArray(kernelsReturnMat);
+}
diff --git a/src/methods/fastmks/fastmks.pl b/src/methods/fastmks/fastmks.pl
new file mode 100644
index 0000000..7e95f7a
--- /dev/null
+++ b/src/methods/fastmks/fastmks.pl
@@ -0,0 +1,67 @@
+:- module(fastmks, [    initModel/11,
+                        searchWithQuery/11,
+                        searchNoQuery/7]).
+
+%% requirements of library(struct)
+:- load_files(library(str_decl),
+        [when(compile_time), if(changed)]).
+
+%% needed for using the array type
+:- use_module(library(structs)).
+:- use_module('../../helper_files/helper.pl').
+
+%% type definitions for the float array
+:- foreign_type
+        float32          = float_32,
+        float_array      = array(float32).
+
+%% definitions for the connected function
+
+%% TODO: 
+%% --Input--
+%%              mat     referenceData,
+%%              string  kernel          "linear", "polynomial", "cosine", "gaussian", "epanechnikov", "triangular", "hyptan"
+%%              float32 degree,
+%%              float32 offset,
+%%              float32 bandwidth,
+%%              float32 scale,
+%%              bool    singleMode      => (1)true / (0)false,
+%%              bool    naive           => (1)true / (0)false,
+%%              double  base
+%%
+%% --Output--
+%%
+%% --Description--
+foreign(initModel, c, initModel(+pointer(float_array), +integer, +integer, +string, +float32, +float32, +float32, +float32, +integer, +integer, +float32)).
+
+%% TODO: 
+%% --Input--
+%%              mat     querySet,
+%%              int     k,
+%%              double  base
+%%
+%% --Output--
+%%              mat     indices,
+%%              mat     kernels
+%%
+%% --Description--
+foreign(searchWithQuery, c, searchWithQuery(+pointer(float_array), +integer, +integer, +integer, -pointer(float_array), -integer, -integer, -pointer(float_array), -integer, -integer, +float32)).
+
+%% TODO: 
+%% --Input--
+%%              int     k
+%%
+%% --Output--
+%%              mat     indices,
+%%              mat     kernels
+%%
+%% --Description--
+foreign(searchNoQuery, c, searchNoQuery(+integer, -pointer(float_array), -integer, -integer, -pointer(float_array), -integer, -integer)).
+
+
+%% Defines the functions that get connected from main.cpp
+foreign_resource(fastmks, [     initModel,
+                                searchWithQuery,
+                                searchNoQuery]).
+
+:- load_foreign_resource(fastmks).
\ No newline at end of file
diff --git a/src/methods/fastmks/fastmks_test.pl b/src/methods/fastmks/fastmks_test.pl
new file mode 100644
index 0000000..b33843d
--- /dev/null
+++ b/src/methods/fastmks/fastmks_test.pl
@@ -0,0 +1,56 @@
+:- use_module(library(plunit)).
+
+:- use_module(fastmks).
+:- use_module('../../helper_files/helper.pl').
+
+reset_Model :-
+        initModel(1,0,50,0.0001).
+
+:- begin_tests(lists).
+
+%% alpha tests
+test(alpha_std_init) :-
+        reset_Model,
+        alpha(0).
+test(alpha_wrong_input, fail) :-
+        reset_Model,
+        alpha(1).
+test(alpha_after_train, A =:= 9223372036854775808) :-
+        reset_Model,
+        convert_list_to_float_array([5.1,3.5,1.4,4.9,3.0,1.4,4.7,3.2,1.3,4.6,3.1,1.5],3, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize),
+        alpha(A).
+
+%% train tests
+test(correct_train) :-
+        reset_Model,
+        convert_list_to_float_array([5.1,3.5,1.4,4.9,3.0,1.4,4.7,3.2,1.3,4.6,3.1,1.5],3, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+test(false_train, fail) :-
+        reset_Model,
+        convert_list_to_float_array([],3, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+test(false_train2, fail) :-
+        reset_Model,
+        convert_list_to_float_array([],0, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+test(false_train3, fail) :-
+        reset_Model,
+        convert_list_to_float_array([1,2],0, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+test(false_train3, fail) :-
+        reset_Model,
+        convert_list_to_float_array([1,2,44,3],3, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+test(false_train4) :-
+        reset_Model,
+        convert_list_to_float_array([1,2,44,3],2, array(Xsize, Xrownum, X)),
+        convert_list_to_float_array([0.2,0.2,0.2,0.2], array(Ysize, Y)),
+        train(X,Xsize, Xrownum,Y, Ysize).
+:- end_tests(lists).
\ No newline at end of file
diff --git a/src/methods/new_method/new_method.pl b/src/methods/new_method/new_method.pl
index 69edd4f..43f90c4 100644
--- a/src/methods/new_method/new_method.pl
+++ b/src/methods/new_method/new_method.pl
@@ -40,6 +40,8 @@ foreign(function, c, function(arguments)).
 %% array return
 %% -pointer(float_array), -integer
 
+%% bool    name       => (1)true / (0)false
+
 %% Defines the functions that get connected from main.cpp
 foreign_resource(new_method, [function]).
 
-- 
GitLab