diff --git a/Makefile b/Makefile index f54fe5e7ade136929fbe46c90940a19214a62143..c26c27042dae4be62ea2aea2eeb9a27e133c1584 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ all: make -C src/methods/naive_bayes_classifier splfr=$(SPLFR_PATH) make -C src/methods/perceptron splfr=$(SPLFR_PATH) make -C src/methods/random_forest splfr=$(SPLFR_PATH) + make -C src/methods/softmac_regression splfr=$(SPLFR_PATH) clean: make -C src/methods/ada_boost clean @@ -28,3 +29,4 @@ clean: make -C src/methods/naive_bayes_classifier clean make -C src/methods/perceptron clean make -C src/methods/random_forest clean + make -C src/methods/softmac_regression clean diff --git a/src/methods/softmax_regression/Makefile b/src/methods/softmax_regression/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bd460779f5e0384b52f2902db4f9187be22874c0 --- /dev/null +++ b/src/methods/softmax_regression/Makefile @@ -0,0 +1,8 @@ +splfr=/usr/local/sicstus4.7.1/bin/splfr + +METHOD_NAME=softmax_regression + +$(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/softmax_regression/softmax_regression.cpp b/src/methods/softmax_regression/softmax_regression.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56049bc9897f2c6a8f1a52ea1a78a7d5ccdf9aff --- /dev/null +++ b/src/methods/softmax_regression/softmax_regression.cpp @@ -0,0 +1,158 @@ +#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 "softmax_regression_glue.h" +#include <mlpack/methods/softmax_regression/softmax_regression.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::regression; + +// Global Variable of the SoftmaxRegression object so it can be accessed from all functions +SoftmaxRegression softmaxRegression; + +// TODO: +// input: const size_t inputSize = 0, +// const size_t numClasses = 0, +// const bool fitIntercept = false// +// output: +// description: +void initModelNoTrain(SP_integer inputSize, SP_integer numClasses, SP_integer fitIntercept) +{ + softmaxRegression = SoftmaxRegression(inputSize, numClasses, (fitIntercept == 1)); +} + +// TODO: +// input: const arma::mat & data, +// const arma::Row< size_t > & labels, +// const size_t numClasses, +// const double lambda = 0.0001, +// const bool fitIntercept = false, +// OptimizerType optimizer = OptimizerType() +// output: +// description: +void initModelWithTrain(float *dataMatArr, SP_integer dataMatSize, SP_integer dataMatRowNum, float *labelsArr, SP_integer labelsArrSize, SP_integer numClasses, double lambda, SP_integer fitIntercept) +{ + // convert the Prolog arrays to arma::mat + mat data = convertArrayToMat(dataMatArr, dataMatSize, dataMatRowNum); + + // convert the Prolog arrays to arma::rowvec + Row< size_t > labelsVector = convertArrayToVec(labelsArr, labelsArrSize); + + softmaxRegression = SoftmaxRegression(data, labelsVector, numClasses, lambda, (fitIntercept == 1)); +} + +// TODO: +// input: const VecType & point +// +// output: size_t predicted label of point +// description: +SP_integer classifyPoint(float *pointArr, SP_integer pointArrSize) +{ + // convert the Prolog arrays to arma::rowvec + rowvec pointVector = convertArrayToRowvec(pointArr, pointArrSize); + + return softmaxRegression.Classify(pointVector); +} + +// TODO: +// input: const arma::mat & dataset, +// arma::Row< size_t > & labels <-, +// arma::mat & probabilities <- +// output: +// description: +void classifyMatrix(float *dataMatArr, SP_integer dataMatSize, SP_integer dataMatRowNum, float **labelsArr, SP_integer *labelsArrSize, float **probsMatArr, SP_integer *probsMatColNum, SP_integer *probsMatRowNum) +{ + // convert the Prolog arrays to arma::mat + mat data = convertArrayToMat(dataMatArr, dataMatSize, dataMatRowNum); + + // create the ReturnVector + Row< size_t > labelsReturnVector; + + // create the ReturnMat + mat probsReturnMat; + + softmaxRegression.Classify(data, labelsReturnVector, probsReturnMat); + + // return the Vector lenght + *labelsArrSize = labelsReturnVector.n_elem; + + // return the Vector as Array + *labelsArr = convertToArray(labelsReturnVector); + + // return the Matrix dimensions + *probsMatColNum = probsReturnMat.n_cols; + *probsMatRowNum = probsReturnMat.n_rows; + + // return the Matrix as one long Array + *probsMatArr = convertToArray(probsReturnMat); +} + +// TODO: +// input: const arma::mat & testData, +// const arma::Row< size_t > & labels +// +// output: double accuracy +// description: +double computeAccuracy(float *dataMatArr, SP_integer dataMatSize, SP_integer dataMatRowNum, float *labelsArr, SP_integer labelsArrSize) +{ + // convert the Prolog arrays to arma::mat + mat data = convertArrayToMat(dataMatArr, dataMatSize, dataMatRowNum); + + // convert the Prolog arrays to arma::rowvec + Row< size_t > labelsVector = convertArrayToVec(labelsArr, labelsArrSize); + + return softmaxRegression.ComputeAccuracy(data, labelsVector); +} + +// TODO: +// input: +// output: size_t +// description: +SP_integer featureSize() +{ + return softmaxRegression.FeatureSize(); +} + +// TODO: +// input: +// output: arma::mat& +// description: +void parameters(float **parametersMatArr, SP_integer *parametersMatColNum, SP_integer *parametersMatRowNum) +{ + // create the ReturnMat + mat parametersReturnMat = softmaxRegression.Parameters(); + + // return the Matrix dimensions + *parametersMatColNum = parametersReturnMat.n_cols; + *parametersMatRowNum = parametersReturnMat.n_rows; + + // return the Matrix as one long Array + *parametersMatArr = convertToArray(parametersReturnMat); +} + +// TODO: +// input: const arma::mat & data, +// const arma::Row< size_t > & labels, +// const size_t numClasses, +// OptimizerType optimizer = OptimizerType() +// +// output: double objective value of final point +// description: +double train(float *dataMatArr, SP_integer dataMatSize, SP_integer dataMatRowNum, float *labelsArr, SP_integer labelsArrSize, SP_integer numClasses) +{ + // convert the Prolog arrays to arma::mat + mat data = convertArrayToMat(dataMatArr, dataMatSize, dataMatRowNum); + + // convert the Prolog arrays to arma::rowvec + Row< size_t > labelsVector = convertArrayToVec(labelsArr, labelsArrSize); + + return softmaxRegression.Train(data, labelsVector, numClasses); +} diff --git a/src/methods/softmax_regression/softmax_regression.pl b/src/methods/softmax_regression/softmax_regression.pl new file mode 100644 index 0000000000000000000000000000000000000000..fbd09c4a883c68b2a9eefa1e7c17142c048ce018 --- /dev/null +++ b/src/methods/softmax_regression/softmax_regression.pl @@ -0,0 +1,114 @@ +:- module(softmax_regression, [ initModelNoTrain/3, + initModelWithTrain/8, + classifyPoint/3, + classifyMatrix/8, + computeAccuracy/6, + featureSize/1, + parameters/3, + train/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 + +%% --Input-- +%% int inputSize => 0, +%% int numClasses => 0, +%% bool fitIntercept => (1)true / (0)false +%% +%% --Output-- +%% +%% --Description-- +foreign(initModelNoTrain, c, initModelNoTrain(+integer, +integer, +integer)). + +%% --Input-- +%% mat data, +%% vec labels, +%% int numClasses, +%% float32 lambda => 0.0001, +%% bool fitIntercept => (1)true / (0)false +%% +%% --Output-- +%% +%% --Description-- +foreign(initModelWithTrain, c, initModelWithTrain(+pointer(float_array), +integer, +integer, +pointer(float_array), +integer, +integer, +float32, +integer)). + +%% --Input-- +%% vec point +%% +%% --Output-- +%% int predicted label +%% +%% --Description-- +foreign(classifyPoint, c, classifyPoint(+pointer(float_array), +integer, [-integer])). + +%% --Input-- +%% mat data +%% +%% --Output-- +%% vec predicted labels, +%% mat probabilities +%% +%% --Description-- +foreign(classifyMatrix, c, classifyMatrix(+pointer(float_array), +integer, +integer, -pointer(float_array), -integer, -pointer(float_array), -integer, -integer)). + +%% --Input-- +%% mat data, +%% vec labels +%% +%% --Output-- +%% float32 accuracy +%% +%% --Description-- +foreign(computeAccuracy, c, computeAccuracy(+pointer(float_array), +integer, +integer, +pointer(float_array), +integer, [-float32])). + +%% --Input-- +%% +%% --Output-- +%% int size of the features +%% +%% --Description-- +foreign(featureSize, c, featureSize([-integer])). + +%% --Input-- +%% +%% --Output-- +%% mat parameters +%% +%% --Description-- +foreign(parameters, c, parameters(-pointer(float_array), -integer, -integer)). + +%% --Input-- +%% mat data, +%% vec labels, +%% int numClasses +%% +%% --Output-- +%% float32 objective value of final point +%% +%% --Description-- +foreign(train, c, train(+pointer(float_array), +integer, +integer, +pointer(float_array), +integer, +integer, [-float32])). + + +%% Defines the functions that get connected from main.cpp +foreign_resource(softmax_regression, [ initModelNoTrain, + initModelWithTrain, + classifyPoint, + classifyMatrix, + computeAccuracy, + featureSize, + parameters, + train]). + +:- load_foreign_resource(softmax_regression). \ No newline at end of file diff --git a/src/methods/softmax_regression/softmax_regression_test.pl b/src/methods/softmax_regression/softmax_regression_test.pl new file mode 100644 index 0000000000000000000000000000000000000000..b09ee2acd83ea906f80effcd092b436e099b684d --- /dev/null +++ b/src/methods/softmax_regression/softmax_regression_test.pl @@ -0,0 +1,56 @@ +:- use_module(library(plunit)). + +:- use_module(softmax_regression). +:- 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