From e21ff75bad8c2a117a8b4b269195b5d49ff6bb3f Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 18 Jun 2024 08:26:08 +0100 Subject: [PATCH] Moved my extension files from subproject to main project --- extension | 1 - extension/src/Makefile | 18 ++++ extension/src/ann.c | 81 ++++++++++++++++ extension/src/ann.h | 41 ++++++++ extension/src/mymath.c | 166 +++++++++++++++++++++++++++++++++ extension/src/mymath.h | 58 ++++++++++++ extension/src/test/test_ann | Bin 0 -> 31552 bytes extension/src/test/test_ann.c | 28 ++++++ extension/src/test/test_math | Bin 0 -> 24200 bytes extension/src/test/test_math.c | 20 ++++ 10 files changed, 412 insertions(+), 1 deletion(-) delete mode 160000 extension create mode 100644 extension/src/Makefile create mode 100644 extension/src/ann.c create mode 100644 extension/src/ann.h create mode 100644 extension/src/mymath.c create mode 100644 extension/src/mymath.h create mode 100755 extension/src/test/test_ann create mode 100644 extension/src/test/test_ann.c create mode 100755 extension/src/test/test_math create mode 100644 extension/src/test/test_math.c diff --git a/extension b/extension deleted file mode 160000 index 2dc6ce7..0000000 --- a/extension +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2dc6ce7eabce9d86c0f5f44606d0cb18fc64d983 diff --git a/extension/src/Makefile b/extension/src/Makefile new file mode 100644 index 0000000..3d728fc --- /dev/null +++ b/extension/src/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CFLAGS = -std=c17 -g\ + -D_POSIX_SOURCE -D_DEFAULT_SOURCE\ + -Wall -Werror -pedantic\ + +LDLIBS = -lm + +.SUFFIXES: .c .o + +.PHONY: all clean + +all: test/test_math test/test_ann + +test/test_math: test/test_math.o mymath.o +test/test_ann: test/test_ann.o ann.o mymath.o + +clean: + $(RM) *.o test/*.o diff --git a/extension/src/ann.c b/extension/src/ann.c new file mode 100644 index 0000000..47ec042 --- /dev/null +++ b/extension/src/ann.c @@ -0,0 +1,81 @@ +#include +#include "ann.h" + +// Helper function that simulate 'bias' term by setting a neuron that always outputs 1.0 +static void network_fillbias(Network network, unsigned int layerIndex) { + + for (int j = 0; j < network->trainingWidth; j++) { + *(network->outputs[layerIndex]->data + network->layers[layerIndex].neuronCount * network->trainingWidth + j) = 1.0; + } +} + +// Defines a sequence of random numbers sampled from a standard normal distribution +double normalseq(unsigned int i) { + return stdnormal(); +} + +// Creates a new network instance given an array of layers and the size of the array +Network network_create(Layer *layers, unsigned int noLayers, unsigned int trainingWidth) { + + // Initialize network struct and its fields + Network network = malloc(sizeof(struct Network)); + if (network == NULL) { + fprintf(stderr, "ERROR: Couldn't allocate sufficient memory for Network struct!\n"); + abort(); + } + + network->layers = layers; + network->noLayers = noLayers; + network->trainingWidth = trainingWidth; + + network->outputs = malloc(sizeof(struct Matrix) * noLayers); + if (network->outputs == NULL) { + fprintf(stderr, "ERROR: Couldn't allocate sufficient memory for Network output matrix array!\n"); + abort(); + } + + network->weights = malloc(sizeof(struct Matrix) * (noLayers - 1)); + if (network->weights == NULL) { + fprintf(stderr, "ERROR: Couldn't allocate sufficient memory for Network weight matrix array!\n"); + abort(); + } + + // Initialize output and weight matrix array data + for (unsigned int i = 0; i < noLayers; i++) { + network->outputs[i] = matrix_create(layers[i].neuronCount + 1, trainingWidth); + + network_fillbias(network, i); + + if (i < noLayers - 1) { + network->weights[i] = matrix_seqcreate(layers[i + 1].neuronCount + 1, layers[i].neuronCount + 1, &normalseq); + } + } + + return network; +} + + +// Returns the output of the ANN given the specified input +Matrix network_pass(Network network, Matrix features) { + + Matrix currentOut = features; + for (int i = 0; i < network->noLayers; i++) { + + // Update current layer's outputs + matrix_free(network->outputs[i]); + network->outputs[i] = currentOut; + network_fillbias(network, i); + + // Calculate outputs of next layer if not in last layer + if (i < network->noLayers - 1) { + currentOut = matrix_apply(matrix_multiply(network->weights[i], currentOut), network->layers[i].activation); + } + } + + return currentOut; +} + + +Matrix log_loss(Matrix result, Matrix expected) { + +} diff --git a/extension/src/ann.h b/extension/src/ann.h new file mode 100644 index 0000000..189ae3e --- /dev/null +++ b/extension/src/ann.h @@ -0,0 +1,41 @@ +/* @file ann.h + @brief Data structures and functions for feedforward neural networks. + + @author Themis Demetriades */ + +#ifndef __ANN__ +#define __ANN__ + +#include "mymath.h" + +// Defines function pointer type for activation functions +typedef double (*activationFunc)(double); + +// Specifies structure of a given layer within a network +typedef struct { + unsigned int neuronCount; + activationFunc activation; +} Layer; + +// Defines a specific instance of an active network +struct Network { + Layer *layers; // Array of layers specifying network structure + unsigned int noLayers; + Matrix *weights; // Array of matrices specifying weights of *outputs* to each layer + Matrix *outputs; + + unsigned int trainingWidth; // Number of training examples to train per gradient descent step +}; + +typedef struct Network *Network; + +// Creates a new network instance given an array of layers and the size of the array +Network network_create(Layer *layers, unsigned int noLayers, unsigned int trainingWidth); + +// Returns the output of the ANN given the specified input +Matrix network_pass(Network network, Matrix features); + +// Calculates the log loss of a result wrt to the expected result +Matrix log_loss(Matrix result, Matrix expected); + +#endif diff --git a/extension/src/mymath.c b/extension/src/mymath.c new file mode 100644 index 0000000..caf814a --- /dev/null +++ b/extension/src/mymath.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include "mymath.h" + +#define LRELU_SFACTOR 0.001 + +// Maximum number of characters that would ever be required to represent a valid matrix entry +#define MAX_ENTRY_LENGTH 100 + +// Defines the format used to print matrix entries +#define VALUE_PRINT_FORMAT "%.2lf" + +// Pretty print matrix data to the given output stream +void matrix_print(Matrix m, FILE *stream) { + + double (*data)[m->cols] = (double (*)[m->cols]) m->data; + char valstr[MAX_ENTRY_LENGTH]; + unsigned int maxlen = 1; + + // Get maximum length of a matrix entry + for (int i = 0; i < m->rows; i++) { + for (int j = 0; j < m->cols; j++) { + sprintf(valstr, VALUE_PRINT_FORMAT, data[i][j]); + unsigned int curlen = strlen(valstr); + if (curlen > maxlen) maxlen = curlen; + } + } + + // Print matrix entries + for (int i = 0; i < m->rows; i++) { + fputc('[', stream); + for (int j = 0; j < m->cols; j++) { + sprintf(valstr, VALUE_PRINT_FORMAT, data[i][j]); + fprintf(stream, "%s", valstr); + for (int k = 0; k < maxlen - strlen(valstr); k++) fputc(' ', stream); + if (j < m->cols - 1) fputc(' ', stream); + } + fprintf(stream, "]\n"); + } +} + +// Return matrix with specified dimensions and random values as its entries +Matrix matrix_create(unsigned int rows, unsigned int cols) { + + // Allocate memory for matrix struct, aborting if couldn't allocate memory + Matrix m = malloc(sizeof(struct Matrix)); + if (m == NULL) { + fprintf(stderr, "ERROR: Couldn't allocate sufficient memory for matrix struct!\n"); + abort(); + } + + // Allocate memory for matrix data (values), aborting if couldn't allocate memory + m->data = malloc(rows * cols * sizeof(double)); + if (m->data == NULL) { + fprintf(stderr, "ERROR: Couldn't allocate sufficient memory for matrix data!\n"); + abort(); + } + + // Initialize matrix struct data + m->rows = rows; + m->cols = cols; + + return m; +} + +// Free data associated with the specified matrix +void matrix_free(Matrix m) { + + free(m->data); + free(m); +} + +// Return matrix with specified dimensions and entries whose values are the first values of the specified matrix sequence +Matrix matrix_seqcreate(unsigned int rows, unsigned int cols, matrix_sequence seq) { + + // Create matrix with specified dimensions containing entries with random values + Matrix m = matrix_create(rows, cols); + + double (*data)[cols] = (double (*)[cols]) m->data; + // Fill matrix with correct entries + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + data[i][j] = seq(i * cols + j); + } + } + + return m; +} + +// Multiply left matrix (l) with right matrix (r), returning a new instance representing the result +Matrix matrix_multiply(Matrix l, Matrix r) { + + // Ensure that dimensions of matrices are compatible for multiplication + if (l->cols != r->rows) { + fprintf(stderr, "ERROR: Attempting to multiply matrices with incompatible dimensions!\n"); + abort(); + } + + // Create matrix instance to store result of product + Matrix prod = matrix_create(l->rows, r->cols); + + double (*prod_data)[prod->cols] = (double (*)[prod->cols]) prod->data; + double (*l_data)[l->cols] = (double (*)[l->cols]) l->data; + double (*r_data)[r->cols] = (double (*)[r->cols]) r->data; + // Perform matrix multiplication, storing result in prod + for (int i = 0; i < l->rows; i++) { + for (int j = 0; j < r->cols; j++) { + + prod_data[i][j] = 0.0; + for (int k = 0; k < l->cols; k++) { + prod_data[i][j] += l_data[i][k] * r_data[k][j]; + } + } + } + + // Return result + return prod; +} + +// Return result of applying given function to each entry in the matrix independently +Matrix matrix_apply(Matrix m, matrix_entrytrans f) { + + Matrix result = matrix_create(m->rows, m->cols); + double (*result_data)[result->cols] = (double (*)[result->cols])result->data; + double (*m_data)[m->cols] = (double (*)[m->cols])m->data; + + for (int i = 0; i < m->rows; i++) { + for (int j = 0; j < m->cols; j++) { + result_data[i][j] = f(m_data[i][j]); + } + } + + return result; +} + +// Draws a value from the standard normal distribution +double stdnormal() { + + // Generate 2 random numbers in the interval [0, 1) + double s1 = ((double)rand() / RAND_MAX); + double s2 = ((double)rand() / RAND_MAX); + + // Peform box-muller transform + return sqrt(-2 * log(s1)) * cos(2 * PI * s2); +} + +// Defines the leaky rectified linear unit activation function +double lrelu(double x) { + if (x > 0) { + return x; + } else { + return LRELU_SFACTOR * x; + } +} + +// Defines the identity activation function f(x) = x +double identity(double x) { + return x; +} + +// Defines a simple counting sequence +double countseq(unsigned int i) { + return i + 1; +} diff --git a/extension/src/mymath.h b/extension/src/mymath.h new file mode 100644 index 0000000..4487d3b --- /dev/null +++ b/extension/src/mymath.h @@ -0,0 +1,58 @@ +/* @file math.h + @brief Math functions and types for feedforward ANNs. + + @author Themis Demetriades */ + +#ifndef __MATH__ +#define __MATH__ + +#include + +#define PI 3.1415926535 + +// Definition of matrix types +struct Matrix { + unsigned int rows; + unsigned int cols; + double *data; +}; + +typedef struct Matrix *Matrix; + +// Pretty print matrix data to the given output stream +void matrix_print(Matrix m, FILE *stream); + +// Defines a sequence that maps matrix entry indices to floating point values +typedef double (*matrix_sequence)(unsigned int); + +// Defines a function that transforms matrix entries +typedef double (*matrix_entrytrans)(double); + +// Return matrix with specified dimensions and random values as its entries +Matrix matrix_create(unsigned int rows, unsigned int cols); + +// Free data associated with the specified matrix +void matrix_free(Matrix m); + +// Return matrix with specified dimensions and entries whose values are the first values of the specified matrix sequence +Matrix matrix_seqcreate(unsigned int rows, unsigned int cols, matrix_sequence seq); + +// Multiply left matrix (l) with right matrix (r), returning a new instance representing the result +Matrix matrix_multiply(Matrix l, Matrix r); + +// Return result of applying given function to each entry in the matrix independently +Matrix matrix_apply(Matrix m, matrix_entrytrans f); + +// Draws a value from the standard normal distribution +double stdnormal(); + +// Defines the identity activation function f(x) = x +double identity(double x); + +// Defines the rectified linear unit activation function +double lrelu(double x); + +// Defines a simple counting sequence +double countseq(unsigned int i); + +#endif diff --git a/extension/src/test/test_ann b/extension/src/test/test_ann new file mode 100755 index 0000000000000000000000000000000000000000..80b301e76f89a43f32b333691e2a856b02513fd5 GIT binary patch literal 31552 zcmeHwdwi7Do%eZW<|LE*L<9jzl+g)-LUw(tJ6 zpPYR1ob$V$-}#+$e&;;TJeTdRr8im(gXv^t*D->eMG{l12|-<8td`AXc{omI7qJYW zZTPQMMH~lU3H7GgfEU70w|E5GUo$LB;g&g_iznXM6 z-=^&xr5{cxf9hP1v+6eg`Z=?!+nQ#y`2&$HGq%i~Gh@!|s!&IjG@R^m;-9+zrdw80 zck~lZxsh3RNLcG5T8W|)|F7Sf>;A!#+xzpMesx^+y5V#4e4oBUJY+Y?5Dz8Nr@LIk zq=$HfKa8CK92UZr5d+et6CaxJqVHGj^M+%3`ba|3@nMwJkWa!g_S7hN|0wv!N5PYQ zPW-2*2Z0!=-o2yXe>w{Oi=*Ig90k986#R}+@DqV|;y*pD2Vx}q9~%Y#<5BQe0`J6s zdRhX+Nc!&^1^*E6g=`#iHb_l+Uf&LIszjw6p9DnwwQ2m!Q@>)Fr^y%ewfI9}UvR~; z8`?Soz7^i}Z9eAlw6u2wJfW~R81{H1>xhhP9W5+$PcY0HJ3^3Z+~V~#`vcxK|Ghre z?rm%9Xap8Bt5NA{_xb}Y=nXWn=FUjCQ5-`o6mIH>gjsXY=R-Nz<_oY;XV4!AH#6`0 z4rm91FBoJb(&`Pe=FLHWn5=|>jT=3Uts6bfUVj@yMeQ_W=TNCpmTp>FfBg-fSyi*D zu4ZO=o>`o2madu&Pg(G1#lIm+HXJ!-orWnVNd8GT6X#1P(mbAt|HwFh7R}T_g^Tt* zifPN)hkz*=(EmDe;-^&N_vcY0kE2Yurv$&1Wnn@QEcIE0K7dTGE4trVF<}|2RqKYv z_p3o=Z;*72*YGKtAV?HbbPOZ-bP`@Ib%bVvNq87+rgKU7LKDl_`6PU45?+s6(p{2- z*W;7$I<66UozjzuGF)P&)+Bs#yzETEQ+(BFOA?;itkaGpJk_Doo+P~X9npG|@aSkW z?M=d~Es3BVNW$ls+>AYugwIXFA4zEx^M=M@^VE6vIRRY{Ik<4-b9AglUl<9_lk; zT9Ai_cA79P#KS}Pm@qBC!$V#ZriFKS=vEV^1$TI;&V*^99UiJNVOn5^ho+b?ZD59n z3Qd?6+TkHX!)X04ucOv4W}^Lor>DUa)8NuHI4=$6Y4E2wJx$jCQ5yV*H2AGF_}|mu zm($>1roqpp!Ox_@KTL*e{!kx%@eA(go9^y2=NeYHYWiz_=I&Ye0=yJ2eHfe{Hdhr) zegGf_P|w1rfpPcn?^8DKe7F=tYZH|*w6fx-3nuR%zMrZb{87Pw^)AXT`^+6Z=RW$! zMed{Lt#0Fa_luu}OQ67|6xidZn}wgWJdM8{3%7yHB3G<*cQ2euMR)YAaIQPH@L~Xi z^FE8m2b<8D&-0aljkS<9>nHi4%^*@?CFC&lcSN^6ymG`VB8>6Z$1uJbkh1Fl0f z(9yJSVSu=!uEPVaej3`qJR&hC23#iVQX5;N%TaUD8Bntnp_z#SbJ zJO~K-_71on0fwE8xMQW=3xJEc_PS&4ikRyW_g?qW)9}a%cMPnrkkl;@f0l;&;O0-` z@$PMpShmlF;F5%(V`RZn2*RE$TpS=ht4Z4Rhye}OuH7IQickx}Psq?`sRe^)FfC!_ z0a%6qTKjN;gMTz0Go_#qmaZiHUS--b2!QnonDe9gD8^8fMt=?NISg$ialXlYMTu~5 zm=AvNNj(0upPIc8-8LAFoEdO^LcC}1goZ(PtO1@lBmHoa{19^^ZV>?uCA`gToQydL z6{~d?eD7HFSj_baJZGF#&LfjAN9)MsZr3MTV|IpjJHeo>bdyeR~PlTz1 z1qc|;?t-p<90L6bD{n{Sywn}tb}AZqDZ29Hvoux)??pq<_Ca^|wm}xT)E(oet|f0A zJ%R|zgg@cqnfh*XLSjtPNi zLxmKqt-$;ewQW$fElsNJQB~V#sAzCC4p7%UXhi$9&gaO2sMaYgKo>i-&ax47ep%`K zC(_Ar7;v3Im2BvHIOzTmDo;_ju$~6tZaJQ1FZN6@Vy=_X=cBIhRGu{1WOQ;31Iv_E`FgAh?QhM}FtGj1HnY*WS9Ku2LSMVcU zyF-=Tt}~=$zU!reT`mLy>Cd(2N9bk*1&lk_N$OtR+Jk7Vs8o$kHBZ4O`o4 zr!BI*r(}EM)Un{j-0EpS%g@X^wrQyp76Y7A(-3#ZR?)~HohBZkK~zaimfCVf^IoSx z_7WCQvYDDHDrm3^?FA2BKVpOHR@SY!-M#a@6V$foGnW!m^oLGl$szGnO}{&~n~1Sh zw&*E029!Ixdllg5sru-#x*tIrZI>JkwkUQLf@2+VoUD)b*FBxYK@kPwtsoBUUVtM7 zo`K!9C=u7t4+OYagS!F71l7Ga`WrVUySu04IpRc(q{M9;i|rP&ksJlA>&;&-g zbVdcWjKb()s%P-!^I()LFzZlN9i)D4u?%{x}`U?T*( zg>fd?A&n*K98d>#yKy9Qhi<3fAKOjdbw{6n_HHugV$?sdd#PsmBXBVx@p+9U_7NLf zTb|n3!H>Zh`--Shw^^(x+d&xE-Jq&HJ3h%QCz2`z$=%$p?;=NPt7ph)?m}@1rPowCax)R^a!m< zI+`}&5)t*=B%y&^YifYw2`0xs3I)AxOdPB`a$(21bKjq#b?0#!>UY-UNHyoppD}S>OF0#P&raSjt!S##Zi)x%Ne0fxz43{iy3u zZ0%k>*IkEcqCa2vEG%VU)id1HPt*H&-7|!T0f(dkF6@q;Ak^8_11<`i?Cj#0>j^k# zFD=vuF=4Sy*c*Kfv-zmICs)m8*NLS)7oj^{z0p_WC&e-xTY1pk`0M(p?WJyrL3EyL z@8+kvT~DC=#5~u&&5wy%yN|m?m)3ou&Xed?-BiT4L$CqyZ3~Ux=npAAV0;l2BX^2` z5o7a?g=rBlzDoAB3o?4xZN?Q#a^~Y7qFXFDXdxjk6fxnvZ(}8c^Jwt(#%gWRWA5&E z5iH@dWA5lzC?L8AMARa$VA<-8EwM#kP)r9S|Y@Pv#GHSSoC;Je2beP8h%Mk(4eQ}WFJ7N| zi1G(G#v%{68~+>~K;M7t?pg2=5!|uJ6K><{qz$F|M(@qp_gA@$9K)T?Py z{X*&?NMXa53k6h+{%aZ+_6bTixNIK}7py+<|FlAIeh$}g!K$OuUSVsu>miKX9}2H` z*XRW4=8SvqVw`=ZEb^`s zw8D!MqnPa&rVJv22pumXbi6EEu=3E-o+}G6pLU3id;HfbdORYc$Ksc94)6#?7V;BR z;T+)MZdb3wU}x1!i$(+T?_>!Hy3WJSpEVa$AKjEGz_W#>&a4Y6P6W*)dGkCdLB)v@PNC#Be0Tqr9N`Oh z!R7sDE9s=-#do_;8}6)Q8hs42gifW@`PABhuR1JK8(FVL$HWbvF6i zeSwg_BM_2`SU)asyiq6H$@&+U*RA-=l*-yqzWx5Mm#uGDWQ@1Yrz>sZ-oV%6@l(Y3 z1}+id`kezgUB_dm{@=wmh<4+;~!&}gU{DVR0 z!SFjY6puTRzk$3K`3vvH<88?Q@elF%BgiXoWuqVYv&c^)k0Ym>R43xHh?9P9N5Yj@ zk&Jt9W5yPTF+MlbPIVFZMD88st`O5 z&}!lL_mg#i$MSorN3)+dY_(K`pnUHmcO)BXjZzY2P7GJUhOiR9OS z{xRs2lIbfG^!q{o2y}NceY>O+YAlU;V9Wz!9vJh$mk7_Qxqi?~KQpywsw7k@x_+Ju_f?97Eul!b*-j+=To>(2C~5jfpT#=}KBV@; zoB$-ddbmkt?6jim6PXfaxPBH1_eF_>8%|P^5@T-lyb!iLBDE@c+7DCG&rIQ#Basd% z12w*16|~)Y@2sDl()EkI7Bpx+{B$kahw20hKZy&tLFtPtSlfkD13{ml=>MT$-412m ze_LigpPi<0raEb;Re6KT*QvZy`f!r_#yW)jH8dct3o*^G=CgQRv&){jQ||R zFTiV?D}V}v&WUXE1mHAQ5Zko^xYSrhZ1V*$)3}Ey3j{D15&#wopw<{7wpszWjqegr zCx8ay5@Nev0IQ7s1S~GQ1`O+rZNzqC37s3Y8Xptj7FKr}KOvxA0AVASWR~QFk!>-4 zL%_14TaoQBenV`x6s!WU%b+`^Y|HI+z;zn~#CB`JtpN5I)IYY>c{`Bx8uLl!?((~l z?KQqaz?w=QvIE960@ez1o-m#wnJ;9yksUH>h~mkv0&v)Po`7}2wtnMPs&u`518~O~ ze;5$YtlSH}!UF2;EAs6>0M0TCbPJ(#sME-*EE*I*UXHSTE|Kq`(wC{U4hO+_FA9RO zm|3W6i{d!gd-DmO*#&V&Mn2s*Z~Pr9$tWnQBb7!oFc}U3*olg3$ga!&=(g`YAgZe(07uvI3utQ<@R z=QI=3{tk%tJkhqkJ=?P< zL8v5`T50X;-JVBJvzIGy@AmQ@6(}D77o|Ku%U1O~upKRl9z*{PxDg^-QA*H4>{T0`+ zb61jM*Mkdjt`3ISQm~oB( zGtRkSry1v#05IbmS#8ES0?atK6@VG%)&el&+(rOqoLdfUW}Nc?FykCe2Q$w3K{4Z8 z2*3dy=g1s0&QVwzInI%7W}MpsnM9oX7Dy#3&Si->R|~p@(0LT>$f|r5=P1Nwi8$9p zB@yQWC<(?rnh|l1y0-KLjm*A$!rN7x`z6Xc&NV@~8RrNv;~a4z&ixu$TAX_eD9hJy z;2WVlV_ean3Go*k3Wz%!NUPAx?<4xeqB3Nb@i++jhXvQIPKMq$C zX%Gb~6|B@mmU%ahml15(G=U&i{v8l9rezdsG|TJ(=3*k&5RU4Uhj)oT^8p;4L|u|X zWflJdG5Z~syvlJ@m|)4L!L@;yXaQy8{*@}Kwv#jO2X;KmrV%^ePP!(jP5t}CiDc}1 z8!QK6F5J!adv+MF{3|soJt;we7 zUX(?Ou2!cX;tIE@=?e&f8Pq97lc`UrCR(YAW;Y4(#Tm3972PbMS_j!wnkQ{qm2H(Bzxv5BvN-QamT^zJlyg(vvM zs@9At;NuHaH97lBBws+W=Wbw`s_kt+xw62F5I+GzWg^5|&;$zc>DykhHI%#0?CU_s z9<~md+QXKckzRy&hi#z^wAB6VNRd8UZDeT_WN(Bov5}>6h28QPX_s5sN>P^KUW5{x z&2~3cAh#_=Y6Z9%@_GfJ<-%M6zK*iF0uW%X00fvT00HI-K!CXd5MZtV1ehxT0p9!^K{@ObU)FlKUiKp;<8y8L`W{hW-k2h}YGnq^UzN;{mTKlHv>q5SJHc}mJDsRfGWNX$c5A4H{e7`K^NQ@OFy} zh0H!D^dLPVGiLR(o%!ToYu}FTnO}EG^d?Q+z;+c$D(%l%J}uL0$+&mbWjOI`B`C(e z7c$VUHnw)Mw0*G49%O4Tlfdb&j5}aVvuf84*{&=|sCMlkd%a+3&94B~+P8PRS!*~mJ}q;o#$B3wT0OqNoMuG9=3G3MGS-;+pX8`m@q1+|9m(HPY&A$m) zYahDzA`~*)Rkv(V6{CH(tM={Pp1Da;S8D18wnDXUA9ZgjZMIw|mGRYz%h>l6RAb1x zDyeNWlk#boHG`mH#Vmdyhk&u~Q!tB`&X^`==^D|{8FM7G3Jsen8b*r5>8?XB^y24u zp=1Fz1*p+6PL7|wUAgbVG{-cGDmbz168&9oHyv`K3;j(FDav03thMh{m*r{{GL{2Z zoK5PieHevKfF(uJm=)E<;rD;x-y?s90wH#hD3#O*;8GaKUP%H z{ou%$1O4O1N&UwOo4HwC-`XwKW6ejf zElXmC;Z??>N-cd!Wqt92N&^C!#fCLMCr2oqVkeBf7;+0>b=DN9tVS)_vq{qwL)L47 zM{*3KzL=QtAhsk;;barh^1y9R;m$8Krso&uSSOF4Txb+!IWQ0Agj3KQm{ zk425Dp^GZXn&MJ}tfop!iVbCP4uPeqEtBmkOGVZfQ_Zy%_lriC=NJUit_YkDTk4>>BoNd3r*|<6*ot>>^gqKMq+29;)aP9@p&C^|xue+-t;VH)j zJy&>PUlb)ep;&fHNpfG5Uf369sU1+B>TB5n6;(`)H;jx+DjzgNFIJkY0;@;iI1??L zC^d|ysW$=Mwd)~I&Yf6=0V@%gR7xM+OH=Igy6^(0B~KGMaWXFORHpX1U6_zO{Ij&r zvlEV@ag-yv07jbA!W8udIm`=GPGaiWGTCF#FQsSOobdVl^2WfGcMr|Y^5(8I1@}Sz%hw=F)?+l z(5S#h)#Mc(la@|Si&%^(E{O`v9ck%zf@ozCETMDwUd%?*v9ezr^yck!Yhb8c_tx%RubvD#7w+y8(TP}9ih5u3*8)H}IZ zW|OkT&rjk&O){uS7HX1}nq;LWF=`U~5B%GxT{fHxWLfm}f-;`}HZ`UQhFYunc*=J1 zODH?Ruc2%SUqo4$-%Qzl?xn1Xuad}nC|kfcQD!gVvnYR>JCUK;qV-{JZ01v!@!Yq# z@fN>pGcULMx&2k16|qb!=B0P@@+bL($9Tm7US@Z4M>n^_qpOKlcQ>!t#mmm5Aj{W~ zxmT^`b5PynD(+aoD|hk92l>P!JnK3>&R)WEoB8V1d=2Q+s`$bM{Muc-?iDJREZ`G& z@o5M7lwm#tCR(ibF3`5-TCyBEl=|rF>eL z7cAhp3;4R5d25)DJHoG9!f)C|1*v$meOPN&UdXlP9Yh6|40JKamV`RI1^w|?c6bh5 ziNSEjVbl)K0o9V|@N$4Qeg%46Z|bZChGl9IFU6QV!mqTi;`|6k=PF)gpUU&U!TEk( zw3=t_=U1=hdG<4Wnx(p!k3&DS@XM%YUl9Yu@-KW6L18g!jQxBXx%6c|P9jCKdwIS! z>lIR%wHn$NCX|xOGJ7}A+b_pg6`v0|t9=2VEahni8NK}SBnaa}5Sw|~YCds4FJ8bM z&3r0xERiPJ=cd_|1)}A*(lqN9%QPd+Jj0s(3SVHER>~drX^CMuehn|^<#}g#cG7sv zThqsL56~c)P{VUR;1@=V1i>tRr9Q{uov^H5@uL?F^!R} zk`P$QMVMw6QTC70i%Z0)vFy~5BXO`&5q(Ve4-s4*vqf6 zALJaKMpphK>d`7fP>%xfmPAxZM3tQE=-eNycuv!dWE0FUDJjfSN z2CzngQz%;^JZNo3cmz}>A25DfT{UZ&An)1ZO7DgKb%!oj@?JSb|n4$J8FofKQb za)g9ZY-#4X-zQ5--r?h(;YF)>E+)9WSe43PU+ya~?+l-ee*+U36qQrOHC0sL}|4p6I0()zudDv((Li!rPH2{wkA(Ub92ZSW^F-V zTZA?Hyx~aDhnH7_E#%$g6MUgoymcD4(c{h2c$2j!%)E_Z|0di}-x0Vm62LpH!7ScE z?dc2$nWwqU+Y(~xQ3pY!3fFr>KDJCeu)qTHF$hnmHxvR833deV1O@ba+P%SzzM!l> z=<_y7JLy%}u!;<4OTAlts08oQ-iUW<)AJ7=@p5eDX^aFtjU8=~_5j1{!-U1#1QM_P#MrW`i>}w2n1R(}Sh$}*4n>W;|$#4z`jm=3g^9EZsG5PF9hy^<~ z%XZ#aztqJdcqpMI;A?VvQ2K>=L|2d-5^+W=ZkgsVLlTUIaIgq+U z`@0b?#hb!qf0{K?$BH+Rw~=chs@>g&SE1vz;+@{6t3`c{9ZkN*O=0G5!ecG|@YbYp zkYo>yEOZ0((Ab(Y8{QJyz$gt{2C`ccp zsBUR&tj3J>%$cn|NzoFBRM*s0;2)-e}SbsytNb2Pgq-3l_EeM zZ}K%)wKBnj91X`qTppUffZDgB^IB1$1`@H!-yw5YpP)BVx3)IoIkAwS;=TSYD2$e9 z*JWex$J6P!l!dbp8+*tqDNe;eCl4d>PXgY8-_shBUw#gpQ{i`{;jdD7eSarFk?L_Y z@cjgLgM`UGN^~*Nz?>nHqcD>FbmeU%JpGbD z`t{kxPNj%;sw44_<{vtXG4NE=I`M0UQlhev^!!Hfm$UTy9)B-nikbedi`MjK!CztC zKdSM$a9|Pa*ZX9B@v~CkHCH0Pd=&h3qu}oz1>X+5GojWjMS&mbdm40=+Q};MOQOjt z3iNCf*`NN~cq#bPhLqs{HuxRT<4DtUNa;!c<@;H}TMF5psj2loC-_rw1f3cM|AEq< z{)>fG*y*_7T7AhV_Ft^{(|^&qY83wKN5S7V3cd+=@=v;-?-Bft3x43D`@)EnTJnV@l{uZHNGYF}6Q^j{q4msR3V|B;Svq#0=(()}hQ;U@x5eoMFK zGT@y_?bk)RcVZ+xD+J!b(tk!-2mDkmoRrg#yG52M2E_r?=$_cUUer&9n=Q-`Oetz*3xTL|oS zLmqEr3wCzxoo&9buc>P0$Q<;=8^1?9l8ntewmSHbjkg`UyGVQcR){1)9&lnqKu<3# z)}$SR-m{wf8MVODCvRalT)!zU#cKsfgTT$JMZ)2XDmM*`( zZmDPajW^!zTH#qycl}bANAIiTSp)5^YRxa<;Hx<5t2!yT3qIOoQt_D_u{ARh^kJRP z`<4*)1vmjnVb?7cXG0#J*amBy-XoJ!X~TiNS&D4>M}JJ>Y~9QewxdcZ?chSD02!XL z{lr}Y3F18Zq)`F{uh{>kU@%~?gO{H+N}MC4e>}<46zcG_;+seGVI?}t#6~ILp_3Pu z*jUTGc&c_fuaIY{9?$wvNYx`wT$J6aUC^lZ#Okw2DSG7Bl2T9}4?g##hZB7VYQ&E_ z(TAN<#8jOE}Z;1v^<) z04JeU*aKH#@7?JO;%qE|S|9P_%WeK9g{r&09_O$vOt81&9Fhw3KZ`bY~ny@3|QCkG3$+Y> z1x-nF042+(f4}ge6mHrRrzYCZC(G;e37tDr*)Nd46Lh?kw?nsIKYyijwas9-?Lwq< z`@O*8M_#l2r?Gxf()p!IG1*9d*7Edg4kbVSNkrGLpZC(azKMf)DUpukbPoV}c1p|Z z=cRN`_W)AT_G>>+=+y z=V?Zjr~B_YC9nHm@5^=WGzn6H?mw-T9uy(}Yc_q}sq=4YMwO@6PrunE%b%Df8Fju- zD^~L9^}hu?ZX^+NkXZEdoBF%2>HHej`TLM5NRrpr4{8^Zw#0aqPy*KSpMpSRSA`Ap zd|ZD&Ry#&bD|7toZv75qsr{z>asWu~MKV7uGxMnH)p-VlljY6xwpuBo>(L6doQCQA zpK!WWfmHAAWnMbEtl7&K5e>$I|R?@FX<0o4w>3p1$m)OK{eyuF`CQzcJ*VsG^fnd<*yz^{>2rN|7QB_JSnBi-!O{&guA5B%VuDcaJu|*C7outputs[i], stdout); + printf("\n"); + if (i < TEST1_LAYERS - 1) { + matrix_print(network->weights[i], stdout); + printf("\n ------------- \n"); + } + } + printf("===========================\n"); + + Matrix features = matrix_create(2, 1); + *(features->data + 0) = 1; + + Matrix out = network_pass(network, features); + + matrix_print(out, stdout); + + return 0; +} \ No newline at end of file diff --git a/extension/src/test/test_math b/extension/src/test/test_math new file mode 100755 index 0000000000000000000000000000000000000000..77f595a5c58e56b726bc49420a2942eded0cb28e GIT binary patch literal 24200 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 TJ^PKVfA)4EagRm8g0lY$tSB$N literal 0 HcmV?d00001 diff --git a/extension/src/test/test_math.c b/extension/src/test/test_math.c new file mode 100644 index 0000000..9a6ec7e --- /dev/null +++ b/extension/src/test/test_math.c @@ -0,0 +1,20 @@ +#include "../mymath.h" + +int main(int argc, char **argv) { + + Matrix l = matrix_seqcreate(4, 3, &countseq); + Matrix r = matrix_seqcreate(3, 2, &countseq); + + matrix_print(l, stdout); + printf("\n"); + matrix_print(r, stdout); + printf("\n"); + + Matrix p = matrix_multiply(l, r); + matrix_print(p, stdout); + + matrix_free(l); + matrix_free(r); + matrix_free(p); + return 0; +} \ No newline at end of file