summaryrefslogtreecommitdiff
path: root/OASIS/c/src
diff options
context:
space:
mode:
authorEric Dao <eric@erickhangdao.com>2023-05-12 14:09:07 -0400
committerEric Dao <eric@erickhangdao.com>2023-05-12 14:09:07 -0400
commit191e4bd8beae134295d481773823142d2fdc6a98 (patch)
treeaaca4e7f8e229f9bd551d9bb1583b8ecd7a59d4a /OASIS/c/src
parent186daed7e179241377c117e9d208ccd301d4d712 (diff)
downloadura-master.tar.gz
ura-master.tar.bz2
ura-master.zip
refactored tool chain setup, able to debug and run from vscode nowHEADmaster
Diffstat (limited to 'OASIS/c/src')
-rw-r--r--OASIS/c/src/ekd_blas.c191
-rw-r--r--OASIS/c/src/ekd_blas.h49
-rw-r--r--OASIS/c/src/ekd_cv.c90
-rw-r--r--OASIS/c/src/ekd_cv.h45
-rw-r--r--OASIS/c/src/ekd_pca.c286
-rw-r--r--OASIS/c/src/ekd_pca.h38
-rw-r--r--OASIS/c/src/ekd_svm.c259
-rw-r--r--OASIS/c/src/ekd_svm.h40
-rw-r--r--OASIS/c/src/main.c108
-rw-r--r--OASIS/c/src/main.h28
10 files changed, 1134 insertions, 0 deletions
diff --git a/OASIS/c/src/ekd_blas.c b/OASIS/c/src/ekd_blas.c
new file mode 100644
index 0000000..8555fbf
--- /dev/null
+++ b/OASIS/c/src/ekd_blas.c
@@ -0,0 +1,191 @@
+#include "ekd_blas.h"
+
+void print_vector(float* vector, uint32_t size) {
+ for (uint32_t i=0; i<size; i++) printf("%.2f ", vector[i]);
+}
+
+void print_matrix(float** matrix, uint32_t rows, uint32_t cols) {
+ for (uint32_t i=0; i<rows; i++) {
+ printf("\n");
+ for (uint32_t j=0; j<cols; j++) printf("%.2f ", matrix[i][j]);
+ }
+}
+
+void copy_vector(float* input_vector, float* resultant_vector, uint32_t size) {
+ for (uint32_t i=0; i<size; i++) resultant_vector[i] = input_vector[i];
+}
+
+void copy_matrix(float** input_matrix, float** resultant_matrix, uint32_t rows, uint32_t cols) {
+ for (uint32_t i=0; i<rows; i++){
+ for (uint32_t j=0; j<cols; j++) resultant_matrix[i][j] = input_matrix[i][j];
+ }
+}
+
+float trace_matrix(float** input_matrix, uint32_t size) {
+ float trace = 0.0f;
+ for (uint32_t i=0; i<size; i++) {
+ for (uint32_t j=0; j< size; j++) {
+ if (i == j) trace += input_matrix[i][j];
+ }
+ }
+
+ return trace;
+}
+
+void shift_matrix(float** input_matrix, uint32_t size, float trace, shift_matrix_operation_e operation) {
+ for (uint32_t i=0; i<size; i++) {
+ for (uint32_t j=0; j<size; j++) {
+ if (i == j) {
+ if (operation == SHIFT_ADD) {
+ input_matrix[i][j] += trace;
+ } else if (operation == SHIFT_SUBTRACT) {
+ input_matrix[i][j] -= trace;
+ }
+ }
+ }
+ }
+}
+
+void eye(float** input_matrix, uint32_t size) {
+ for (uint32_t i=0; i<size; i++) {
+ for (uint32_t j=0; j<size; j++) input_matrix[i][j] = (i == j) ? 1 : 0;
+ }
+}
+
+void outer_product(float* input_vector, uint32_t size, float** resultant_matrix) {
+ // for (uint32_t i=0; i<size; i++) {
+ // for (uint32_t j=0; j<size; j++) resultant_matrix[i][j] = input_vector[i] * input_vector[j];
+ // }
+ for (uint32_t i = 0; i < size; i++) {
+ for (uint32_t j = i; j < size; j++) {
+ float value = input_vector[i] * input_vector[j];
+ resultant_matrix[i][j] = value;
+ resultant_matrix[j][i] = value;
+ }
+ }
+}
+
+float inner_product(float* input_vector_1, float* input_vector_2, uint32_t size) {
+ float resultant_scalar = 0.0;
+ for (uint32_t i=0; i<size; i++) resultant_scalar += input_vector_1[i] * input_vector_2[i];
+ return resultant_scalar;
+}
+
+void transpose(float** input_matrix, uint32_t rows, uint32_t cols, float** transposed_matrix) {
+ for (uint32_t i=0; i<rows; i++){
+ for (uint32_t j=0; j<cols; j++) transposed_matrix[j][i] = input_matrix[i][j];
+ }
+}
+
+void matrix_operation(float** input_matrix_A, uint32_t rows_A, uint32_t cols_A, float** input_matrix_B, uint32_t rows_B, uint32_t cols_B, float** resultant_matrix, matrix_matrix_operation_e operation) {
+ if (operation == MM_ADD) {
+ for (uint32_t i=0; i<rows_A; i++) {
+ for (uint32_t j=0; j<cols_A; j++) resultant_matrix[i][j] = input_matrix_A[i][j] + input_matrix_B[i][j];
+ }
+ } else if (operation == MM_SUBTRACT) {
+ for (uint32_t i=0; i<rows_A; i++) {
+ for (uint32_t j=0; j<cols_A; j++) resultant_matrix[i][j] = input_matrix_A[i][j] - input_matrix_B[i][j];
+ }
+ } else if (operation == MM_MULTIPLY) {
+ for (uint32_t i=0; i<rows_A; i++) {
+ for (uint32_t j=0; j<cols_B; j++) {
+ resultant_matrix[i][j] = 0;
+ for (uint32_t k=0; k<cols_A; k++) resultant_matrix[i][j] += input_matrix_A[i][k] * input_matrix_B[k][j];
+ }
+ }
+ } else if (operation == MM_MULTIPLY_OMP) {
+ uint32_t a, b, c;
+ #pragma omp parallel for private(a, b, c) shared(input_matrix_A, input_matrix_B, resultant_matrix)
+ for (a=0; a<rows_A; a++) {
+ for (b=0; b<cols_B; b++) {
+ resultant_matrix[a][b] = 0;
+ for (c=0; c<cols_A; c++) resultant_matrix[a][b] += input_matrix_A[a][c] * input_matrix_B[c][b];
+ }
+ }
+ } else if (operation == MM_MULTIPLY_GEMM) {
+ float* temp_matrix_A = malloc(rows_A * cols_A * sizeof(float));
+ float* temp_matrix_B = malloc(rows_B * cols_B * sizeof(float));
+ float* temp_resultant_matrix = malloc(rows_A * cols_B * sizeof(float));
+
+ for (uint32_t i = 0; i < rows_A; i++) {
+ for (uint32_t j = 0; j < cols_A; j++) {
+ temp_matrix_A[i * cols_A + j] = input_matrix_A[i][j];
+ }
+ }
+
+ for (uint32_t i = 0; i < rows_B; i++) {
+ for (uint32_t j = 0; j < cols_B; j++) {
+ temp_matrix_B[i * cols_B + j] = input_matrix_B[i][j];
+ }
+ }
+
+ cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, rows_A, cols_B, cols_A, 1.0, temp_matrix_A, cols_A, temp_matrix_B, cols_B, 0.0, temp_resultant_matrix, cols_B);
+
+ for (uint32_t i = 0; i < rows_A; i++) {
+ for (uint32_t j = 0; j < cols_B; j++) {
+ resultant_matrix[i][j] = temp_resultant_matrix[i * cols_B + j];
+ }
+ }
+
+ free(temp_matrix_A);
+ free(temp_matrix_B);
+ free(temp_resultant_matrix);
+ }
+}
+
+uint8_t sign(float num) {
+ return (num > 0) - (num < 0);
+}
+
+void vector_normalize(float* vector, uint32_t size) {
+ float norm = 0.0;
+ for (uint32_t i=0; i<size; i++) norm += vector[i] * vector[i];
+ norm = sqrt(norm);
+ for (uint32_t i=0; i<size; i++) vector[i] = (norm == 0) ? 0 : vector[i]/norm;
+}
+
+float vector_norm(float* vector, uint32_t size) {
+ float norm = 0.0;
+ for (uint32_t i=0; i<size; i++) norm += vector[i] * vector[i];
+
+ return sqrt(norm);
+}
+
+float matrix_norm(float** input_matrix_A1, float** input_matrix_A, uint32_t rows, uint32_t cols) {
+ float norm = 0.0;
+ for (uint32_t i=0; i<rows; i++) {
+ for (uint32_t j=0; j<cols; j++) norm += fabs(input_matrix_A1[i][j] - input_matrix_A[i][j]) * fabs(input_matrix_A1[i][j] - input_matrix_A[i][j]);
+ }
+
+ return sqrt(norm);
+}
+
+float cosine_similarity(float* curr_vector, float* new_vector, uint32_t size) {
+ float dot_product = 0.0f;
+ for (uint32_t i=0; i<size; i++) dot_product += curr_vector[i] * new_vector[i];
+
+ return (vector_norm(curr_vector, size) == 0 || vector_norm(new_vector, size) == 0) ? 1e-6 : dot_product / (vector_norm(curr_vector, size) * vector_norm(new_vector, size));
+}
+
+void matrix_vector_multiply(float** input_matrix, uint32_t rows, uint32_t cols, float* input_vector, float* resultant_vector, matrix_vector_operation_e operation) {
+ if (operation == MV_MULTIPLY) {
+ for (uint32_t i=0; i<rows; i++) {
+ resultant_vector[i] = 0;
+ for (uint32_t j=0; j<cols; j++) {
+ resultant_vector[i] += input_matrix[i][j] * input_vector[j];
+ }
+ }
+ } else if (operation == MV_MULTIPLY_GEMV) {
+ float* temp_matrix = malloc(rows * cols * sizeof(float));
+
+ for (uint32_t i = 0; i < rows; i++) {
+ for (uint32_t j = 0; j < cols; j++) {
+ temp_matrix[i * cols + j] = input_matrix[i][j];
+ }
+ }
+
+ cblas_sgemv(CblasRowMajor, CblasNoTrans, rows, cols, 1.0f, temp_matrix, cols, input_vector, 1, 0.0f, resultant_vector, 1);
+
+ free(temp_matrix);
+ }
+} \ No newline at end of file
diff --git a/OASIS/c/src/ekd_blas.h b/OASIS/c/src/ekd_blas.h
new file mode 100644
index 0000000..4c9919d
--- /dev/null
+++ b/OASIS/c/src/ekd_blas.h
@@ -0,0 +1,49 @@
+#ifndef EKD_BLAS_H
+#define EKD_BLAS_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <omp.h>
+#include <cblas.h>
+
+typedef enum {
+ MM_ADD,
+ MM_SUBTRACT,
+ MM_MULTIPLY,
+ MM_MULTIPLY_OMP,
+ MM_MULTIPLY_GEMM
+} matrix_matrix_operation_e;
+
+typedef enum {
+ MV_MULTIPLY,
+ MV_MULTIPLY_GEMV
+} matrix_vector_operation_e;
+
+typedef enum {
+ SHIFT_ADD,
+ SHIFT_SUBTRACT
+} shift_matrix_operation_e;
+
+// Prototypes
+void print_matrix(float** matrix, uint32_t rows, uint32_t cols);
+void print_vector(float* vector, uint32_t size);
+void copy_matrix(float** input_matrix, float** resultant_matrix, uint32_t rows, uint32_t cols);
+void copy_vector(float* input_vector, float* resultant_vector, uint32_t size);
+void shift_matrix(float** input_matrix, uint32_t size, float trace, shift_matrix_operation_e operation);
+float trace_matrix(float** input_matrix, uint32_t size);
+void eye(float** input_matrix, uint32_t size);
+void outer_product(float* input_vector, uint32_t size, float** resultant_matrix); // outer_productes itself
+float inner_product(float* input_vector_1, float* input_vector_2, uint32_t size); // Dots itself
+void matrix_operation(float** input_matrix_A, uint32_t rows_A, uint32_t cols_A, float** input_matrix_B, uint32_t rows_B, uint32_t cols_B, float** resultant_matrix, matrix_matrix_operation_e operation);
+void transpose(float** input_matrix, uint32_t rows, uint32_t cols, float** transposed_matrix);
+uint8_t sign(float num);
+void vector_normalize(float* vector, uint32_t size);
+float vector_norm(float* vector, uint32_t size);
+float matrix_norm(float** input_matrix_A1, float** input_matrix_A, uint32_t rows, uint32_t cols);
+float cosine_similarity(float* curr_vector, float* new_vector, uint32_t size);
+void matrix_vector_multiply(float** input_matrix, uint32_t rows, uint32_t cols, float* input_vector, float* resultant_vector, matrix_vector_operation_e operation);
+
+#endif /* EKD_BLAS_H */
diff --git a/OASIS/c/src/ekd_cv.c b/OASIS/c/src/ekd_cv.c
new file mode 100644
index 0000000..1f9afad
--- /dev/null
+++ b/OASIS/c/src/ekd_cv.c
@@ -0,0 +1,90 @@
+#include "ekd_cv.h"
+
+void read_bmp(char* filename, uint8_t** data) {
+ bmp_header_t header;
+ bmp_info_t info;
+
+ FILE* file = fopen(filename, "rb");
+ if (file == NULL) {
+ printf("Unable to open file.\n");
+ return;
+ }
+
+ fread(&header.signature, sizeof(uint16_t), 1, file);
+ fread(&header.file_size, sizeof(uint32_t), 1, file);
+ fread(&header.reserved, sizeof(uint32_t), 1, file);
+ fread(&header.data_offset, sizeof(uint32_t), 1, file);
+
+ fread(&info.size, sizeof(uint32_t), 1, file);
+ fread(&info.width, sizeof(uint32_t), 1, file);
+ fread(&info.height, sizeof(uint32_t), 1, file);
+ fread(&info.planes, sizeof(uint16_t), 1, file);
+ fread(&info.bit_depth, sizeof(uint16_t), 1, file);
+ fread(&info.compression, sizeof(uint32_t), 1, file);
+ fread(&info.image_size, sizeof(uint32_t), 1, file);
+ fread(&info.x_pixels_per_meter, sizeof(uint32_t), 1, file);
+ fread(&info.y_pixels_per_meter, sizeof(uint32_t), 1, file);
+ fread(&info.colours_used, sizeof(uint32_t), 1, file);
+ fread(&info.important_colours, sizeof(uint32_t), 1, file);
+
+ uint8_t* raw_data = (uint8_t*) malloc(info.width * info.height * sizeof(uint8_t));
+
+ fseek(file, header.data_offset, SEEK_SET);
+ fread(raw_data, sizeof(uint8_t), info.width * info.height, file);
+
+ fclose(file);
+
+ for (uint8_t i=0; i<info.height; i++) {
+ for (uint8_t j=0; j < info.width; j++) data[i][j] = raw_data[(i * info.width) + j];
+ }
+
+ free(raw_data);
+}
+
+void read_dir(char* dneg_path, char* dpos_path, char** file_name_arr) {
+ DIR* dneg_dir = opendir(dneg_path);
+ DIR* dpos_dir = opendir(dpos_path);
+ struct dirent *entry;
+ uint8_t item_id = 0;
+
+ while ((entry = readdir(dneg_dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+ continue;
+ }
+ strcat(file_name_arr[item_id], entry->d_name);
+ item_id++;
+ }
+
+ while ((entry = readdir(dpos_dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+ continue;
+ }
+ strcat(file_name_arr[item_id], entry->d_name);
+ item_id++;
+ }
+
+ closedir(dneg_dir);
+ closedir(dpos_dir);
+}
+
+void flatten_image(uint8_t** image, float* image_flattened) {
+ for (uint8_t i=0; i<IMAGE_HEIGHT; i++) {
+ for (uint8_t j=0; j<IMAGE_WIDTH; j++) image_flattened[(i*IMAGE_WIDTH)+j] = (float)image[i][j];
+ }
+}
+
+void shuffle_data_labels(float** data, int32_t* labels, uint8_t num_images) {
+ srand(time(NULL)); // initialize random seed
+ for (int i = num_images - 1; i > 0; i--) {
+ // Generate a random index between 0 and i (inclusive)
+ int j = rand() % (i + 1);
+
+ // Swap the rows of data_flatten and labels at indices i and j
+ float* temp_data = data[i];
+ data[i] = data[j];
+ data[j] = temp_data;
+ int32_t temp_label = labels[i];
+ labels[i] = labels[j];
+ labels[j] = temp_label;
+ }
+} \ No newline at end of file
diff --git a/OASIS/c/src/ekd_cv.h b/OASIS/c/src/ekd_cv.h
new file mode 100644
index 0000000..146144c
--- /dev/null
+++ b/OASIS/c/src/ekd_cv.h
@@ -0,0 +1,45 @@
+#ifndef EKD_CV_H
+#define EKD_CV_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+
+#define NUM_DNEG_IMAGES 134
+#define NUM_DPOS_IMAGES 99
+#define NUM_IMAGES 233
+#define IMAGE_WIDTH 144
+#define IMAGE_HEIGHT 176
+#define FEATURE_VECTOR_SIZE 25344
+
+typedef struct {
+ uint16_t signature;
+ uint32_t file_size;
+ uint32_t reserved;
+ uint32_t data_offset;
+} bmp_header_t;
+
+typedef struct {
+ uint32_t size;
+ uint32_t width;
+ uint32_t height;
+ uint16_t planes;
+ uint16_t bit_depth;
+ uint32_t compression;
+ uint32_t image_size;
+ uint32_t x_pixels_per_meter;
+ uint32_t y_pixels_per_meter;
+ uint32_t colours_used;
+ uint32_t important_colours;
+} bmp_info_t;
+
+// Prototypes
+void read_bmp(char* filename, uint8_t** data_flatten);
+void read_dir(char* dneg_path, char* dpos_path, char** file_name_arr);
+void flatten_image(uint8_t** image, float* image_flattened);
+void shuffle_data_labels(float** data, int32_t* labels, uint8_t num_images);
+
+#endif /* EKD_CV_H */ \ No newline at end of file
diff --git a/OASIS/c/src/ekd_pca.c b/OASIS/c/src/ekd_pca.c
new file mode 100644
index 0000000..f76d20e
--- /dev/null
+++ b/OASIS/c/src/ekd_pca.c
@@ -0,0 +1,286 @@
+#include "ekd_pca.h"
+
+void centre_scale(float** input_matrix, uint32_t rows, uint32_t cols, centre_scale_operation_e operation) {
+ float* means = (float*) malloc(cols * sizeof(float));
+ float* std_devs = (float*) malloc(cols * sizeof(float));
+
+ // Iterating column by column
+ for (uint32_t j = 0; j<cols; j++) {
+ float col_sum = 0.0;
+ for (uint32_t i = 0; i<rows; i++){
+ col_sum += input_matrix[i][j];
+ }
+ means[j] = col_sum / (float)rows;
+
+ float variance = 0.0;
+ for (uint32_t i = 0; i<rows; i++) variance += (input_matrix[i][j] - means[j]) * (input_matrix[i][j] - means[j]);
+ std_devs[j] = (variance < 1e-6) ? 1e-6 : sqrtf(variance / (float)rows);
+ }
+
+ // Centering -> subtract means, Scaling -> Divide by std_devs
+ for (uint32_t j=0; j<cols; j++) {
+ for (uint32_t i=0; i<rows; i++) {
+ if (operation == MEAN_UNIT_VARIANCE) {
+ input_matrix[i][j] = (input_matrix[i][j] - means[j]) / std_devs[j];
+ } else if (operation == MEAN) {
+ input_matrix[i][j] = (input_matrix[i][j] - means[j]);
+ }
+ }
+ }
+
+ free(means);
+ free(std_devs);
+}
+
+void covariance(float** input_matrix, uint32_t rows, uint32_t cols, float** covariance_matrix) {
+ float** transposed_matrix = (float**) malloc(cols * sizeof(float*));
+ for (uint32_t i=0; i<cols; i++) transposed_matrix[i] = (float*) malloc(rows * sizeof(float));
+
+ transpose(input_matrix, rows, cols, transposed_matrix);
+
+ matrix_operation(transposed_matrix, cols, rows, input_matrix, rows, cols, covariance_matrix, MM_MULTIPLY_GEMM);
+
+ // Divide by n since we have full population
+ for (uint32_t i=0; i<cols; i++) {
+ for (uint32_t j=0; j<cols; j++) covariance_matrix[i][j] /= rows-1;
+ }
+
+ for (uint32_t i=0; i<cols; i++) free(transposed_matrix[i]);
+ free(transposed_matrix);
+}
+
+void house_holder_vector(float* vector, uint32_t size) {
+
+ // Computes the norm of the input vector
+ float norm_input_vector = 0.0;
+ for (uint32_t i=0; i<size; i++) norm_input_vector += vector[i] * vector[i];
+ norm_input_vector = sqrt(norm_input_vector);
+
+ // Since the rest of output vector already is the input vector, change the first index
+ vector[0] = vector[0] + sign(vector[0]) * norm_input_vector;
+}
+
+void house_holder_transformation(float* house_holder_vector, uint32_t size, float** house_holder_matrix) {
+ float** identity_matrix = (float**) malloc(size * sizeof(float*));
+ for (uint32_t i=0; i<size; i++) identity_matrix[i] = (float*) malloc(size * sizeof(float));
+
+ float** numerator = (float**) malloc(size * sizeof(float*));
+ for (uint32_t i=0; i<size; i++) numerator[i] = (float*) malloc(size * sizeof(float));
+
+ eye(identity_matrix, size);
+
+ float denominator = inner_product(house_holder_vector, house_holder_vector, size);
+
+ outer_product(house_holder_vector, size, numerator);
+
+ for (uint32_t i=0; i<size; i++) {
+ for (uint32_t j=0; j<size; j++) numerator[i][j] = (denominator == 0) ? 0 : (2 / denominator) * numerator[i][j];
+ }
+
+ matrix_operation(identity_matrix, size, size, numerator, size, size, house_holder_matrix, MM_SUBTRACT);
+
+ for (uint32_t i=0; i<size; i++){
+ free(numerator[i]);
+ free(identity_matrix[i]);
+ }
+ free(numerator);
+ free(identity_matrix);
+}
+
+void qr_decomposition(float** input_matrix, uint32_t size, float** resultant_matrix) {
+ float** matrix_Q = (float**) malloc(size * sizeof(float*)); // Has size x size dimensions
+ float** matrix_Q_prime = (float**) malloc(size * sizeof(float*)); // Has size x size dimensions
+ float** matrix_R = (float**) malloc(size * sizeof(float*)); // Has size x size dimensions
+ float** matrix_R_prime = (float**) malloc(size * sizeof(float*)); // Has size x size dimensions
+ for(uint32_t i=0; i<size; i++) {
+ matrix_Q[i] = (float*) malloc(size * sizeof(float));
+ matrix_Q_prime[i] = (float*) malloc(size * sizeof(float));
+ matrix_R[i] = (float*) malloc(size * sizeof(float));
+ matrix_R_prime[i] = (float*) malloc(size * sizeof(float));
+ }
+
+ for (uint32_t i=0; i<size; i++) memcpy(matrix_R[i], input_matrix[i], size * sizeof(float));
+
+ eye(matrix_Q, size);
+
+ for (uint32_t i=0; i<size; i++) {
+ float* current_house_holder_vector = (float*) malloc((size - i) * sizeof(float));
+
+ float** current_house_holder_matrix = (float**) malloc((size - i) * sizeof(float*)); // Has (size-i)x(size-i) dimensions
+ for (uint32_t j=0; j<(size - i); j++) current_house_holder_matrix[j] = (float*) malloc((size - i) * sizeof(float));
+
+ float** matrix_H = (float**) malloc(size * sizeof(float*)); // Has size x size dimensions
+ for (uint32_t j=0; j<size; j++) matrix_H[j] = (float*) malloc(size * sizeof(float));
+
+ eye(matrix_H, size);
+
+ for(uint32_t j=0; j<(size - i); j++) current_house_holder_vector[j] = matrix_R[j+i][i];
+
+ house_holder_vector(current_house_holder_vector, (size - i));
+
+ house_holder_transformation(current_house_holder_vector, (size - i), current_house_holder_matrix);
+
+ // Starting from the ith ith sub matrix
+ for (uint32_t j=i; j<size; j++) {
+ for (uint32_t k=i; k<size; k++) matrix_H[j][k] = current_house_holder_matrix[j-i][k-i];
+ }
+
+ matrix_operation(matrix_H, size, size, matrix_R, size, size, matrix_R_prime, MM_MULTIPLY_GEMM);
+ matrix_operation(matrix_Q, size, size, matrix_H, size, size, matrix_Q_prime, MM_MULTIPLY_GEMM);
+
+ // print_matrix(matrix_H, size, size);
+
+ for (uint32_t j=0; j<size; j++) memcpy(matrix_Q[j], matrix_Q_prime[j], size * sizeof(float));
+ for (uint32_t j=0; j<size; j++) memcpy(matrix_R[j], matrix_R_prime[j], size * sizeof(float));
+
+ for (uint32_t j=0; j<size; j++) free(matrix_H[j]);
+ free(matrix_H);
+ for (uint32_t j=0; j<(size - i); j++) free(current_house_holder_matrix[j]);
+ free(current_house_holder_matrix);
+ free(current_house_holder_vector);
+ }
+
+ matrix_operation(matrix_R, size, size, matrix_Q, size, size, resultant_matrix, MM_MULTIPLY_GEMM);
+ matrix_operation(matrix_Q, size, size, matrix_R, size, size, resultant_matrix, MM_MULTIPLY_GEMM);
+
+ print_matrix(matrix_R, size, size);
+
+ for (uint32_t i=0; i<size; i++) {
+ free(matrix_R[i]);
+ free(matrix_R_prime[i]);
+ free(matrix_Q_prime[i]);
+ free(matrix_Q[i]);
+ }
+ free(matrix_R_prime);
+ free(matrix_R);
+ free(matrix_Q_prime);
+ free(matrix_Q);
+}
+
+void qr_algorithm(float** input_matrix, uint32_t rows, uint32_t cols, float** resultant_matrix) {
+ float** covariance_matrix = (float**) malloc(cols * sizeof(float*)); // Has feature x feature dimensions
+ for (uint32_t i=0; i<cols; i++) covariance_matrix[i] = (float*) malloc(cols * sizeof(float));
+
+ float** covariance_matrix_prime = (float**) malloc(cols * sizeof(float*)); // Has feature x feature dimensions
+ for (uint32_t i=0; i<cols; i++) covariance_matrix_prime[i] = (float*) malloc(cols * sizeof(float));
+
+ centre_scale(input_matrix, rows, cols, MEAN);
+ covariance(input_matrix, rows, cols, covariance_matrix);
+
+ qr_decomposition(covariance_matrix, cols, covariance_matrix_prime);
+ while (matrix_norm(covariance_matrix_prime, covariance_matrix, cols, cols) > TOLERANCE) {
+ for (uint32_t i=0; i<cols; i++) {
+ for (uint32_t j=0; j<cols; j++) {
+ if (i == j) printf("%.2f ", covariance_matrix[i][j]);
+ }
+ }
+
+ memcpy(covariance_matrix, covariance_matrix_prime, cols);
+ qr_decomposition(covariance_matrix, cols, covariance_matrix_prime);
+
+ for (uint32_t i=0; i<cols; i++) free(covariance_matrix[i]);
+ free(covariance_matrix);
+ }
+}
+
+void power_iteration(float** input_matrix, uint32_t size, float* eigen_vector) {
+ // Initialize first guess vector
+ float* new_vector = (float*) malloc(size * sizeof(float));
+ float* curr_vector = (float*) malloc(size * sizeof(float));
+ for (uint32_t i=0; i<size; i++) curr_vector[i] = (float) rand() / RAND_MAX;
+
+ // MAX_INTERATIONS in case the singular vector doesn't converge
+ for (uint32_t i=0; i<MAX_ITERATIONS; i++) {
+ matrix_vector_multiply(input_matrix, size, size, curr_vector, new_vector, MV_MULTIPLY);
+ vector_normalize(curr_vector, size);
+ vector_normalize(new_vector, size);
+ if (fabs(fabs(cosine_similarity(new_vector, curr_vector, size))-1.0) < TOLERANCE) break;
+ memcpy(curr_vector, new_vector, size * sizeof(float));
+ }
+
+ memcpy(eigen_vector, new_vector, size * sizeof(float));
+ free(curr_vector);
+ free(new_vector);
+}
+
+float eigen_value_compute(float* eigen_vector, float** input_matrix, uint32_t size) {
+ if (vector_norm(eigen_vector, size) == 0) return 0;
+
+ float lambda = 0.0f;
+ for (uint32_t i=0; i<size; i++) {
+ lambda += input_matrix[i][i] * eigen_vector[i] * eigen_vector[i];
+ for (uint32_t j=0; j<size; j++) {
+ if (i != j) {
+ lambda += input_matrix[i][j] * eigen_vector[i] * eigen_vector[j];
+ }
+ }
+ }
+ lambda /= vector_norm(eigen_vector, size) * vector_norm(eigen_vector, size);
+ return lambda;
+}
+
+void subtract_eigen(float* eigen_vector, float** input_matrix, float** resultant_matrix, float eigen_value, uint32_t size) {
+ float** outer_product_matrix = (float**) malloc(size * sizeof(float*));
+ for (uint32_t i=0; i<size; i++) outer_product_matrix[i] = (float*) malloc(size * sizeof(float));
+
+ outer_product(eigen_vector, size, outer_product_matrix);
+
+ for (uint32_t i=0; i<size; i++) {
+ for (uint32_t j=0; j<size; j++) outer_product_matrix[i][j] *= eigen_value;
+ }
+
+ matrix_operation(input_matrix, size, size, outer_product_matrix, size, size, resultant_matrix, MM_SUBTRACT);
+
+ for (uint32_t i=0 ; i<size; i++) free(outer_product_matrix[i]);
+ free(outer_product_matrix);
+}
+
+void pca_covariance_method(float** input_matrix, uint32_t rows, uint32_t cols, float** resultant_matrix, uint32_t components) {
+ float** input_matrix_original = (float**) malloc(rows * sizeof(float*)); // Has sample x feature dimensions
+ for (uint32_t i=0; i<rows; i++) input_matrix_original[i] = (float*) malloc(cols * sizeof(float));
+
+ float* eigen_vector = (float*) malloc(cols * sizeof(float)); // Has feature dimensions
+
+ float** covariance_matrix = (float**) malloc(cols * sizeof(float*)); // Has feature x feature dimensions
+ float** covariance_matrix_prime = (float**) malloc(cols * sizeof(float*));
+ float** projection_matrix = (float**) malloc(cols * sizeof(float*)); // Has features x components dimensions
+
+ for (uint32_t i=0; i<cols; i++) {
+ projection_matrix[i] = (float*) malloc(components * sizeof(float));
+ covariance_matrix[i] = (float*) malloc(cols * sizeof(float));
+ covariance_matrix_prime[i] = (float*) malloc(cols * sizeof(float));
+ }
+
+ copy_matrix(input_matrix, input_matrix_original, rows, cols);
+
+ centre_scale(input_matrix, rows, cols, MEAN);
+ covariance(input_matrix, rows, cols, covariance_matrix);
+
+ for (uint32_t i=0; i<components; i++) {
+ power_iteration(covariance_matrix, cols, eigen_vector);
+ float eigen_value = eigen_value_compute(eigen_vector, covariance_matrix, cols);
+ subtract_eigen(eigen_vector, covariance_matrix, covariance_matrix_prime, eigen_value, cols);
+ for (uint32_t j=0; j<cols; j++) projection_matrix[j][i] = eigen_vector[j];
+
+ copy_matrix(covariance_matrix_prime, covariance_matrix, cols, cols);
+ }
+
+ matrix_operation(input_matrix_original, rows, cols, projection_matrix, cols, components, resultant_matrix, MM_MULTIPLY_GEMM); // Has sample x components dimensions
+
+ free(eigen_vector);
+
+ for (uint32_t i=0; i<cols; i++) {
+ free(projection_matrix[i]);
+ free(covariance_matrix_prime[i]);
+ free(covariance_matrix[i]);
+ }
+
+ for (uint32_t i=0; i<rows; i++) {
+ free(input_matrix_original[i]);
+ }
+
+ free(covariance_matrix_prime);
+ free(covariance_matrix);
+ free(input_matrix_original);
+ free(projection_matrix);
+}
diff --git a/OASIS/c/src/ekd_pca.h b/OASIS/c/src/ekd_pca.h
new file mode 100644
index 0000000..842e485
--- /dev/null
+++ b/OASIS/c/src/ekd_pca.h
@@ -0,0 +1,38 @@
+#ifndef EKD_PCA_H
+#define EKD_PCA_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "ekd_blas.h"
+
+#define NUM_DNEG_IMAGES 134
+#define NUM_DPOS_IMAGES 99
+#define NUM_IMAGES 233
+#define IMAGE_WIDTH 144
+#define IMAGE_HEIGHT 176
+#define FEATURE_VECTOR_SIZE 25344
+#define MAX_ITERATIONS 100
+#define TOLERANCE 1e-3
+
+typedef enum {
+ MEAN_UNIT_VARIANCE,
+ MEAN
+} centre_scale_operation_e;
+
+// Prototypes
+void centre_scale(float** input_matrix, uint32_t rows, uint32_t cols, centre_scale_operation_e operation);
+void covariance(float** input_matrix, uint32_t rows, uint32_t cols, float** covariance_matrix);
+void house_holder_vector(float* input_vector, uint32_t size);
+void house_holder_transformation(float* house_holder_vector, uint32_t size, float** house_holder_matrix);
+void qr_decomposition(float** input_matrix, uint32_t size, float** resultant_matrix);
+void qr_algorithm(float** input_matrix, uint32_t rows, uint32_t cols, float** resultant_matrix);
+void power_iteration(float** input_matrix, uint32_t size, float* eigen_vector);
+float eigen_value_compute(float* eigen_vector, float** input_matrix, uint32_t size);
+void subtract_eigen(float* eigen_vector, float** input_matrix, float** resultant_matrix, float eigen_value, uint32_t size);
+void pca_covariance_method(float** input_matrix, uint32_t rows, uint32_t cols, float** resultant_matrix, uint32_t components);
+
+#endif /* EKD_PCA_H */ \ No newline at end of file
diff --git a/OASIS/c/src/ekd_svm.c b/OASIS/c/src/ekd_svm.c
new file mode 100644
index 0000000..13c155d
--- /dev/null
+++ b/OASIS/c/src/ekd_svm.c
@@ -0,0 +1,259 @@
+#include "ekd_svm.h"
+
+void svm_preprocess(float** input_matrix, uint32_t rows, uint32_t cols) {
+ centre_scale(input_matrix, rows, cols, MEAN_UNIT_VARIANCE);
+}
+
+float rbf_kernel(float* sample_1, float* sample_2, uint32_t features, float gamma) {
+ float distance = 0.0f;
+ for (uint32_t i=0; i<features; i++) distance += pow(sample_1[i] - sample_2[i], 2);
+ return exp(-gamma * distance);
+}
+
+void kernel_matrix_transform(float** input_matrix, float** resultant_matrix, uint32_t samples, uint32_t features, float gamma) {
+ for (uint32_t i=0; i<samples; i++) {
+ for (uint32_t j=0; j<samples; j++) {
+ float kernel = rbf_kernel(input_matrix[i], input_matrix[j], features, gamma);
+ resultant_matrix[i][j] = kernel;
+ }
+ }
+}
+
+void kernel_row_transform(float** input_matrix, float* query_row, float* resultant_row, uint32_t samples, uint32_t features, float gamma) {
+ for (uint32_t i=0; i<samples; i++) {
+ float kernel = rbf_kernel(input_matrix[i], query_row, features, gamma);
+ resultant_row[i] = kernel;
+ }
+}
+
+float get_error(uint32_t index, float* alphas, float** kernel_matrix, int32_t* labels, uint32_t samples) {
+ float error = 0.0f;
+
+ for (uint32_t i=0; i<samples; i++) error += alphas[i] * labels[i] * kernel_matrix[i][index];
+
+ error -= labels[index];
+ return error;
+}
+
+uint32_t find_second_alpha(uint32_t first_index, float first_error_val, float* alphas, float** kernel_matrix, int32_t* labels, uint32_t samples) {
+ int32_t second_index = -1;
+ float max_error_diff = 0;
+
+ for (uint32_t i=0; i<samples; i++) {
+ if (i == first_index) continue;
+
+ float second_error_val = get_error(i, alphas, kernel_matrix, labels, samples);
+ float error_diff = fabs(first_error_val - second_error_val);
+ if (error_diff > max_error_diff) {
+ max_error_diff = error_diff;
+ second_index = i;
+ }
+ }
+ return second_index;
+}
+
+void calculate_bounds(float first_label, float second_label, float first_alpha, float second_alpha, float penalty, float* lower_bound, float* upper_bound) {
+ if (first_label != second_label) {
+ *lower_bound = fmax(0, second_alpha - first_alpha);
+ *upper_bound = fmin(penalty, penalty + second_alpha - first_alpha);
+ } else {
+ *lower_bound = fmax(0, second_alpha + first_alpha - penalty);
+ *upper_bound = fmin(penalty, second_alpha + first_alpha);
+ }
+}
+
+float clip_second_alpha_new(float second_alpha_new, float lower_bound, float upper_bound) {
+ if (second_alpha_new < lower_bound) {
+ return lower_bound;
+ } else if (second_alpha_new > upper_bound) {
+ return upper_bound;
+ } else {
+ return second_alpha_new;
+ }
+}
+
+void update_alphas(float first_alpha_new, float second_alpha_new, float* alphas, uint32_t first_index, uint32_t second_index) {
+ alphas[first_index] = first_alpha_new;
+ alphas[second_index] = second_alpha_new;
+}
+
+float calculate_bias(float first_error_val, float second_error_val, float first_alpha_new, float first_alpha, float second_alpha_new, float second_alpha, float kernel_val_ii, float kernel_val_ij, float kernel_val_jj, float first_label, float second_label, float penalty) {
+ float first_bias = first_error_val + first_label * (first_alpha_new - first_alpha) * kernel_val_ii + second_label * (second_alpha_new - second_alpha) * kernel_val_ij;
+ float second_bias = first_error_val + first_label * (first_alpha_new - first_alpha) * kernel_val_ij + second_label * (second_alpha_new - second_alpha) * kernel_val_jj;
+ float bias;
+ if (first_alpha_new > 0 && first_alpha_new < penalty) {
+ bias = first_bias;
+ } else if (second_alpha_new > 0 && second_alpha_new < penalty) {
+ bias = second_bias;
+ } else {
+ bias = (first_bias + second_bias) / 2;
+ }
+ return bias;
+}
+
+void update_errors(float* errors, uint32_t samples, uint32_t first_index, uint32_t second_index, float first_label, float second_label, float first_alpha_new, float first_alpha, float second_alpha_new, float second_alpha, float* bias, float** kernel_matrix) {
+ float bias_temp = *bias;
+ for (uint32_t i=0; i<samples; i++) {
+ if (i == first_index || i == second_index) continue;
+ float error = errors[i];
+ error += first_label * (first_alpha_new - first_alpha) * kernel_matrix[first_index][i];
+ error -= bias_temp - *bias;
+ errors[i] = error;
+ }
+}
+
+uint8_t optimize_alphas(uint32_t first_index, uint32_t second_index, float* alphas, float* bias, float* errors, float** kernel_matrix, int32_t* labels, uint32_t samples, float penalty) {
+ if (first_index == second_index) return 0;
+
+ float first_label = (float) labels[first_index];
+ float second_label = (float) labels[second_index];
+
+ float first_alpha = alphas[first_index];
+ float second_alpha = alphas[second_index];
+
+ float first_error_val = errors[first_index];
+ float second_error_val = errors[second_index];
+
+ float kernel_val_ii = kernel_matrix[first_index][first_index];
+ float kernel_val_jj = kernel_matrix[second_index][second_index];
+ float kernel_val_ij = kernel_matrix[first_index][second_index];
+
+ // Second derivative of objective function
+ float learning_rate = 2 * kernel_val_ij - kernel_val_ii - kernel_val_jj;
+ if (learning_rate >= 0) return 0;
+
+ float second_alpha_new = second_alpha - (second_label * (first_error_val - second_error_val) / learning_rate);
+
+ float lower_bound, upper_bound;
+ calculate_bounds(first_label, second_label, first_alpha, second_alpha, penalty, &lower_bound, &upper_bound);
+ second_alpha_new = clip_second_alpha_new(second_alpha_new, lower_bound, upper_bound);
+
+ if (fabs(second_alpha_new - second_alpha) < SVM_TOLERANCE * (second_alpha_new + second_alpha + SVM_TOLERANCE)) return 0;
+
+ float first_alpha_new = first_alpha + first_label * second_label * (second_alpha - second_alpha_new);
+
+ update_alphas(first_alpha_new, second_alpha_new, alphas, first_index, second_index);
+
+ float bias_new = calculate_bias(first_error_val, second_error_val, first_alpha_new, first_alpha, second_alpha_new, second_alpha, kernel_val_ii, kernel_val_ij, kernel_val_jj, first_label, second_label, penalty);
+ *bias = bias_new;
+
+ update_errors(errors, samples, first_index, second_index, first_label, second_label, first_alpha_new, first_alpha, second_alpha_new, second_alpha, bias, kernel_matrix);
+
+ return 1;
+}
+
+uint8_t verify_kkt(uint32_t first_index, float tolerance, float* alphas, float* bias, float* errors, float** kernel_matrix, int32_t* labels, uint32_t samples, float penalty) {
+ float first_label = (float) labels[first_index];
+ float first_alpha = alphas[first_index];
+ float first_error_val = errors[first_index];
+ float first_residual_error = first_error_val * first_label;
+
+ if ((first_residual_error < -tolerance && first_alpha < penalty) || (first_residual_error > tolerance && first_alpha > 0)) {
+ // Alpha is able be optimized, now find second alpha using heuristic method
+ uint32_t second_index = find_second_alpha(first_index, first_error_val, alphas, kernel_matrix, labels, samples);
+ // If the alphas have been optimized, return
+ if (optimize_alphas(first_index, second_index, alphas, bias, errors, kernel_matrix, labels, samples, penalty)) return 1;
+
+ // Could not find second alpha or couldn't optimize alphas values
+ uint32_t max_index = -1;
+ float max_error = -FLT_MAX;
+ for (uint32_t i=0; i<samples; i++) {
+ if (alphas[i] > 0 && alphas[i] < penalty) {
+ float error = errors[i];
+ if (fabs(error - first_error_val) > max_error) {
+ max_index = i;
+ max_error = fabs(error - first_error_val);
+ }
+ }
+ }
+
+ if (max_index != -1 && optimize_alphas(first_index, max_index, alphas, bias, errors, kernel_matrix, labels, samples, penalty) == 1) return 1;
+
+ // Still couldn't optimize alpha values:w
+ return 0;
+ }
+
+ // Alpha values do not need to be optimized
+ return 0;
+}
+
+void train_svm(float** data_matrix, uint32_t samples, uint32_t features, float* alphas, float* bias, int32_t* labels, float penalty) {
+ // Centre and scale reduced_dimension_matrix
+ svm_preprocess(data_matrix, samples, features);
+
+ float** kernel_matrix = (float**) malloc(samples * sizeof(float*));
+ for (uint32_t i=0; i<samples; i++) kernel_matrix[i] = (float*) malloc(samples * sizeof(float));
+
+ // Compute kernel matrix using RBF
+ kernel_matrix_transform(data_matrix, kernel_matrix, samples, features, GAMMA);
+
+ // Initialize bias to 0, alphas/errors to random numbers between -1 and 1
+ *bias = 0;
+
+ float* errors = (float*) malloc(samples * sizeof(float));
+ for (uint32_t i=0; i<samples; i++) {
+ errors[i] = (float) rand() / (float) RAND_MAX * 2 - 1;
+ alphas[i] = (float) rand() / (float) RAND_MAX * 2 - 1;
+ }
+
+ uint32_t num_changed_alphas = 0;
+ uint32_t search_passes = 0;
+ uint8_t searched_all_flag = 1;
+
+ while ((search_passes < MAX_SVM_PASSES && num_changed_alphas > 0) || searched_all_flag) {
+ num_changed_alphas = 0;
+
+ if (searched_all_flag) {
+ // Loops over all samples
+ for (uint32_t sample_index=0; sample_index<samples; sample_index++)
+ num_changed_alphas += verify_kkt(sample_index, SVM_TOLERANCE, alphas, bias, errors, kernel_matrix, labels, samples, penalty);
+ } else {
+ // Loops over non support vector samples (not 0 and not C -> penalty parameter)
+ for (uint32_t sample_index=0; sample_index<samples; sample_index++) {
+ if (alphas[sample_index] > 0 && alphas[sample_index] < penalty)
+ num_changed_alphas += verify_kkt(sample_index, SVM_TOLERANCE, alphas, bias, errors, kernel_matrix, labels, samples, penalty);
+ }
+ }
+
+ if (searched_all_flag) {
+ searched_all_flag = 0;
+ } else if (num_changed_alphas == 0) {
+ searched_all_flag = 1;
+ }
+ search_passes++;
+ }
+
+ for (uint32_t i=0; i<samples; i++) free (kernel_matrix[i]);
+ free(kernel_matrix);
+ free(errors);
+}
+
+int32_t svm_predict(float** test_data, int32_t* labels_test, uint32_t num_test, uint32_t num_components, float* alphas, float bias, float gamma) {
+ int num_correct = 0;
+ for (int i=0; i<num_test; i++) {
+ float transformed_row[num_test];
+ kernel_row_transform(test_data, test_data[i], transformed_row, num_test, num_components, gamma);
+ float prediction = bias;
+ for (int j = 0; j<num_test; j++) {
+ prediction += alphas[j] * transformed_row[j];
+ }
+ if (prediction >= 0 && labels_test[i] == 1) {
+ num_correct++;
+ } else if (prediction < 0 && labels_test[i] == -1) {
+ num_correct++;
+ }
+ }
+ return num_correct;
+}
+
+float test_svm(float** data_test, int32_t* labels_test, uint32_t num_test, uint32_t num_components, float* alphas, float bias) {
+ uint32_t num_correct = 0;
+ float* prediction = (float*) malloc(num_test * sizeof(float));
+ for (uint8_t i=0; i<num_test; i++) {
+ prediction[i] = svm_predict(data_test, labels_test, num_test, num_components, alphas, bias, GAMMA);
+ if (prediction[i] * labels_test[i] > 0) num_correct++;
+ }
+ float accuracy = ((float) num_correct / num_test) * 100;
+ free(prediction);
+ return accuracy;
+} \ No newline at end of file
diff --git a/OASIS/c/src/ekd_svm.h b/OASIS/c/src/ekd_svm.h
new file mode 100644
index 0000000..259eb5c
--- /dev/null
+++ b/OASIS/c/src/ekd_svm.h
@@ -0,0 +1,40 @@
+#ifndef EKD_SVM_H
+#define EKD_SVM_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "ekd_pca.h"
+#include "ekd_blas.h"
+
+#define NUM_DNEG_IMAGES 134
+#define NUM_DPOS_IMAGES 99
+#define NUM_IMAGES 233
+#define IMAGE_WIDTH 144
+#define IMAGE_HEIGHT 176
+#define FEATURE_VECTOR_SIZE 25344
+#define MAX_SVM_PASSES 100
+#define GAMMA 0.9
+#define SVM_TOLERANCE 1e-3
+
+void svm_preprocess(float** input_matrix, uint32_t rows, uint32_t cols);
+float rbf_kernel(float* sample_1, float* sample_2, uint32_t features, float gamma);
+void kernel_matrix_transform(float** input_matrix, float** resultant_matrix, uint32_t samples, uint32_t features, float gamma);
+void kernel_row_transform(float** input_matrix, float* query_row, float* resultant_row, uint32_t samples, uint32_t features, float gamma);
+float get_error(uint32_t index, float* alphas, float** kernel_matrix, int32_t* labels, uint32_t num_samples);
+uint32_t find_second_alpha(uint32_t first_index, float first_error_val, float* alphas, float** kernel_matrix, int32_t* labels, uint32_t num_samples);
+void calculate_bounds(float first_label, float second_label, float first_alpha, float second_alpha, float penalty, float* lower_bound, float* upper_bound);
+float clip_second_alpha_new(float second_alpha_new, float lower_bound, float upper_bound);
+void update_alphas(float first_alpha_new, float second_alpha_new, float* alphas, uint32_t first_index, uint32_t second_index);
+float calculate_bias(float first_error_val, float second_error_val, float first_alpha_new, float first_alpha, float second_alpha_new, float second_alpha, float kernel_val_ii, float kernel_val_ij, float kernel_val_jj, float first_label, float second_label, float penalty);
+void update_errors(float* errors, uint32_t num_samples, uint32_t first_index, uint32_t second_index, float first_label, float second_label, float first_alpha_new, float first_alpha, float second_alpha_new, float second_alpha, float* bias, float** kernel_matrix);
+uint8_t optimize_alphas(uint32_t first_index, uint32_t second_index, float* alphas, float* bias, float* errors, float** kernel_matrix, int32_t* labels, uint32_t num_samples, float penalty);
+uint8_t verify_kkt(uint32_t first_index, float tolerance, float* alphas, float* bias, float* errors, float** kernel_matrix, int32_t* labels, uint32_t num_samples, float penalty);
+void train_svm(float** data_matrix, uint32_t samples, uint32_t features, float* alphas, float* bias, int32_t* labels, float penalty);
+float test_svm(float** data_test, int32_t* labels_test, uint32_t num_test, uint32_t num_components, float* alphas, float bias);
+
+#endif /* EKD_SVM_H */ \ No newline at end of file
diff --git a/OASIS/c/src/main.c b/OASIS/c/src/main.c
new file mode 100644
index 0000000..ef8918d
--- /dev/null
+++ b/OASIS/c/src/main.c
@@ -0,0 +1,108 @@
+#include "main.h"
+
+// uint64_t seconds() {
+// struct timespec start;
+// clock_gettime(CLOCK_MONOTONIC_RAW, &start);
+// return start.tv_sec;
+// }
+
+int main() {
+ // uint64_t start = seconds();
+ // Allocate memory
+ char** file_names = (char**) malloc((NUM_IMAGES) * sizeof(char*));
+ for (uint8_t i=0; i<NUM_IMAGES; i++) {
+ file_names[i] = (char*) malloc(FILE_NAME_SIZE * sizeof(char));
+ // Populate file name array with file path
+ file_names[i] = (i < NUM_DNEG_IMAGES) ? strcpy(file_names[i], DNEG_FOLDER_PATH) : strcpy(file_names[i], DPOS_FOLDER_PATH);
+ }
+ uint8_t*** data = (uint8_t***) malloc((NUM_IMAGES) * sizeof(uint8_t**));
+ for (uint8_t i=0; i<NUM_IMAGES; i++) {
+ data[i] = (uint8_t**) malloc(IMAGE_HEIGHT * sizeof(uint8_t*));
+ for (uint8_t j=0; j<IMAGE_HEIGHT; j++) data[i][j] = (uint8_t*)malloc(IMAGE_WIDTH * sizeof(uint8_t));
+ }
+
+ float** data_flatten = (float**) malloc((NUM_IMAGES) * sizeof(float*));
+ for (uint8_t i=0; i<NUM_IMAGES; i++) data_flatten[i] = (float*) malloc(FEATURE_VECTOR_SIZE * sizeof(float));
+
+ int32_t* labels = (int32_t*) malloc((NUM_IMAGES) * sizeof(int32_t));
+
+ uint8_t num_train = (uint8_t) (0.8 * NUM_IMAGES);
+ uint8_t num_test = NUM_IMAGES - num_train;
+
+ float** data_train = (float**) malloc (num_train * sizeof(float*));
+ float** data_test = (float**) malloc (num_test * sizeof(float*));
+
+ int32_t* labels_train = (int32_t*) malloc(num_train * sizeof(int32_t));
+ int32_t* labels_test = (int32_t*) malloc(num_test * sizeof(int32_t));
+
+ float** data_reduced_dimensions = (float**) malloc((NUM_IMAGES) * sizeof(float*));
+ for (uint32_t i=0; i<NUM_IMAGES; i++) data_reduced_dimensions[i] = (float*) malloc(NUM_COMPONENTS * sizeof(float));
+
+ float* alphas = (float*) malloc((NUM_IMAGES) * sizeof(float));
+
+ // Concatenate the file name array with the image name
+ read_dir(DNEG_FOLDER_PATH, DPOS_FOLDER_PATH, file_names);
+ printf("read\n");
+
+ // Read in an array of 2D images, then flatten
+ for (uint8_t i=0; i<NUM_IMAGES; i++) {
+ labels[i] = (i < NUM_DNEG_IMAGES) ? -1 : 1;
+ read_bmp(file_names[i], data[i]);
+ flatten_image(data[i], data_flatten[i]);
+ }
+
+ printf("flattened\n");
+
+ // PCA Transform
+ pca_covariance_method(data_flatten, NUM_IMAGES, FEATURE_VECTOR_SIZE, data_reduced_dimensions, NUM_COMPONENTS);
+ printf("pca\n");
+
+ // Shuffle data and labels
+ shuffle_data_labels(data_reduced_dimensions, labels, NUM_IMAGES);
+ printf("shuffled\n");
+
+ // Populate the training and testing data
+ for (uint8_t i=0; i<num_train; i++) {
+ data_train[i] = data_reduced_dimensions[i];
+ labels_train[i] = labels[i];
+ }
+
+ for (uint8_t i=num_train; i<NUM_IMAGES; i++) {
+ data_test[i - num_train] = data_reduced_dimensions[i];
+ labels_test[i - num_train] = labels[i];
+ }
+
+ printf("split\n");
+
+ // Train SVM
+ float bias;
+ train_svm(data_train, num_train, NUM_COMPONENTS, alphas, &bias, labels, PENALTY_PARAM);
+ printf("trained\n");
+
+ // Test SVM
+ float accuracy = test_svm(data_test, labels_test, num_test, NUM_COMPONENTS, alphas, bias);
+ printf("Accuracy: %.2f%%\n", accuracy);
+
+ // Free memory
+ for (uint8_t i=0; i<NUM_IMAGES; i++) {
+ free(file_names[i]);
+ free(data_flatten[i]);
+ free(data_reduced_dimensions[i]);
+ for (uint8_t j=0; j<IMAGE_HEIGHT; j++) free(data[i][j]);
+ free(data[i]);
+ }
+ free(file_names);
+ free(data);
+ free(data_flatten);
+ free(data_reduced_dimensions);
+ free(labels);
+ free(labels_train);
+ free(labels_test);
+ free(data_train);
+ free(data_test);
+ free(alphas);
+
+ // uint64_t end = seconds();
+ // printf("Time Elapsed: %lds\n", end-start);
+ return 0;
+} \ No newline at end of file
diff --git a/OASIS/c/src/main.h b/OASIS/c/src/main.h
new file mode 100644
index 0000000..1aaee54
--- /dev/null
+++ b/OASIS/c/src/main.h
@@ -0,0 +1,28 @@
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <stdint.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "ekd_cv.h"
+#include "ekd_pca.h"
+#include "ekd_blas.h"
+#include "ekd_svm.h"
+
+#define NUM_DNEG_IMAGES 134
+#define NUM_DPOS_IMAGES 99
+#define NUM_IMAGES 233
+#define DNEG_FOLDER_PATH "/home/eric/URA/OASIS/dataset/bmp/dneg/"
+#define DPOS_FOLDER_PATH "/home/eric/URA/OASIS/dataset/bmp/dpos/"
+#define IMAGE_WIDTH 144
+#define IMAGE_HEIGHT 176
+#define FEATURE_VECTOR_SIZE 25344
+#define FILE_NAME_SIZE 150
+#define NUM_COMPONENTS 2
+#define PENALTY_PARAM 1
+
+#endif /* MAIN_H */ \ No newline at end of file