diff --git a/C/Makefile b/C/Makefile index 5217fc5..ad285df 100644 --- a/C/Makefile +++ b/C/Makefile @@ -16,7 +16,13 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CC = clang -CC_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow -lm +CC_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow + +# Detect OS and add -lm on Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LDFLAGS = -lm +endif # Final binary BIN = cmain @@ -25,7 +31,7 @@ BIN = cmain BUILD_DIR = ./build # List of all .c source files. -CCS = main.c $(wildcard *.c) +CCS = $(wildcard *.c) # All .o files go to build dir. OBJ = $(CCS:%.c=$(BUILD_DIR)/%.o) @@ -39,7 +45,7 @@ $(BIN) : $(BUILD_DIR)/$(BIN) # Actual target of the binary - depends on all .o files. $(BUILD_DIR)/$(BIN) : $(OBJ) mkdir -p $(@D) - $(CC) $(CC_FLAGS) $^ -o $@ + $(CC) $(CC_FLAGS) $^ -o $@ $(LDFLAGS) # Include all .d files -include $(DEP) diff --git a/C/main.c b/C/main.c index 359b10c..fe989fc 100644 --- a/C/main.c +++ b/C/main.c @@ -18,110 +18,98 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "neural.h" -#include #include +#include uint32_t P = 2147483647; uint32_t A = 16807; uint32_t current = 1; -double Rand() { - current = current * A % P; - double result = (double)current / P; - return result; +double Rand(void) { + current = current * A % P; + double result = (double)current / P; + return result; } -void print_network(const Network* network); +void print_network(const Network *network); -static uint32_t xor(uint32_t i, uint32_t j) { return i ^ j; } -static uint32_t xnor(uint32_t i, uint32_t j) { return 1 - xor(i, j); } -static uint32_t or(uint32_t i, uint32_t j) { return i | j; } -static uint32_t and(uint32_t i, uint32_t j) { return i & j; } -static uint32_t nor(uint32_t i, uint32_t j) { return 1 - or(i, j); } +static uint32_t xor (uint32_t i, uint32_t j) { return i ^ j; } static uint32_t + xnor(uint32_t i, uint32_t j) { + return 1 - xor(i, j); +} +static uint32_t or (uint32_t i, uint32_t j) { return i | j; } +static uint32_t and (uint32_t i, uint32_t j) { return i & j; } +static uint32_t nor(uint32_t i, uint32_t j) { return 1 - or (i, j); } static uint32_t nand(uint32_t i, uint32_t j) { return 1 - and(i, j); } const int ITERS = 4000; -int main() { - Network network = {0}; - network_init(&network, 2, 2, 6, Rand); - Trainer trainer = {0}; - trainer_init(&trainer, &network); - double inputs[4][2] = { - {0, 0}, - {0, 1}, - {1, 0}, - {1, 1} - }; - double outputs[4][6] = { - { xor(0, 0), xnor(0, 0), or(0, 0), and(0, 0), nor(0, 0), nand(0, 0) }, - { xor(0, 1), xnor(0, 1), or(0, 1), and(0, 1), nor(0, 1), nand(0, 1) }, - { xor(1, 0), xnor(1, 0), or(1, 0), and(1, 0), nor(1, 0), nand(1, 0) }, - { xor(1, 1), xnor(1, 1), or(1, 1), and(1, 1), nor(1, 1), nand(1, 1) } - }; - - for (size_t i = 0; i < ITERS; i++) { - double* input = inputs[i % 4]; - double* output = outputs[i % 4]; - - trainer_train(&trainer, &network, input, output, 1.0); - } - - printf( - "Result after %d iterations\n XOR XNOR OR AND NOR NAND\n", - ITERS); - for (size_t i = 0; i < 4; i++) - { - double* input = inputs[i % 4]; - network_predict(&network, input); - printf( - "%.0f,%.0f = %.3f %.3f %.3f %.3f %.3f %.3f\n", - input[0], - input[1], - network.output[0], - network.output[1], - network.output[2], - network.output[3], - network.output[4], - network.output[5]); - } - - print_network(&network); - trainer_free(&trainer); - network_free(&network); - return 0; +int main(void) { + Network network = {0}; + network_init(&network, 2, 2, 6, Rand); + Trainer trainer = {0}; + trainer_init(&trainer, &network); + double inputs[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + double outputs[4][6] = { + {xor(0, 0), xnor(0, 0), or (0, 0), and(0, 0), nor(0, 0), nand(0, 0)}, + {xor(0, 1), xnor(0, 1), or (0, 1), and(0, 1), nor(0, 1), nand(0, 1)}, + {xor(1, 0), xnor(1, 0), or (1, 0), and(1, 0), nor(1, 0), nand(1, 0)}, + {xor(1, 1), xnor(1, 1), or (1, 1), and(1, 1), nor(1, 1), nand(1, 1)}}; + + for (size_t i = 0; i < ITERS; i++) { + double *input = inputs[i % 4]; + double *output = outputs[i % 4]; + + trainer_train(&trainer, &network, input, output, 1.0); + } + + printf( + "Result after %d iterations\n XOR XNOR OR AND NOR NAND\n", + ITERS); + for (size_t i = 0; i < 4; i++) { + double *input = inputs[i % 4]; + network_predict(&network, input); + printf("%.0f,%.0f = %.3f %.3f %.3f %.3f %.3f %.3f\n", input[0], input[1], + network.output[0], network.output[1], network.output[2], + network.output[3], network.output[4], network.output[5]); + } + + print_network(&network); + trainer_free(&trainer); + network_free(&network); + return 0; } -void print_network(const Network* network) { - printf("weights hidden:\n"); - for (size_t i = 0; i < network->n_inputs; i++) { - for (size_t j = 0; j < network->n_hidden; j++) { - printf(" %9.6f", network->weights_hidden[network->n_inputs * i + j]); - } - - printf("\n"); - } - - printf("biases hidden:\n"); - for (size_t i = 0; i < network->n_hidden; i++) { - printf(" %9.6f", network->biases_hidden[i]); +void print_network(const Network *network) { + printf("weights hidden:\n"); + for (size_t i = 0; i < network->n_inputs; i++) { + for (size_t j = 0; j < network->n_hidden; j++) { + printf(" %9.6f", network->weights_hidden[network->n_inputs * i + j]); } printf("\n"); + } - printf("weights output:\n"); - for (size_t i = 0; i < network->n_hidden; i++) { - for (size_t j = 0; j < network->n_outputs; j++) { - printf(" %9.6f", network->weights_output[i * network->n_outputs + j]); - } + printf("biases hidden:\n"); + for (size_t i = 0; i < network->n_hidden; i++) { + printf(" %9.6f", network->biases_hidden[i]); + } - printf("\n"); - } + printf("\n"); - printf("biases output:\n"); - for (size_t i = 0; i < network->n_outputs; i++) { - printf(" %9.6f", network->biases_output[i]); + printf("weights output:\n"); + for (size_t i = 0; i < network->n_hidden; i++) { + for (size_t j = 0; j < network->n_outputs; j++) { + printf(" %9.6f", network->weights_output[i * network->n_outputs + j]); } printf("\n"); + } + + printf("biases output:\n"); + for (size_t i = 0; i < network->n_outputs; i++) { + printf(" %9.6f", network->biases_output[i]); + } + + printf("\n"); } diff --git a/C/neural.c b/C/neural.c index feb4f03..ebfa934 100644 --- a/C/neural.c +++ b/C/neural.c @@ -18,127 +18,121 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "neural.h" -#include #include +#include static double sigmoid(double f) { return 1.0 / (1.0 + exp(-f)); } static double sigmoid_prim(double f) { return f * (1.0 - f); } -Network* network_init( - Network* network, - uint32_t n_inputs, - uint32_t n_hidden, - uint32_t n_outputs, - RandFcn rand) { - network->n_inputs = n_inputs; - network->n_hidden = n_hidden; - network->n_outputs = n_outputs; - - network->weights_hidden = calloc( - n_inputs * n_hidden, - sizeof(*network->weights_hidden)); - network->biases_hidden = calloc( - n_hidden, - sizeof(*network->biases_hidden)); - network->weights_output = calloc( - n_hidden * n_outputs, - sizeof(*network->weights_output)); - network->biases_output = calloc( - n_outputs, - sizeof(*network->biases_output)); - network->hidden = calloc( - n_hidden, - sizeof(*network->hidden)); - network->output = calloc( - n_outputs, - sizeof(*network->output)); - - // initialize everything but the biases - for (size_t i = 0; i < n_inputs * n_hidden; i++) { - network->weights_hidden[i] = rand() - 0.5; - } - - for (size_t i = 0; i < n_hidden * n_outputs; i++) { - network->weights_output[i] = rand() - 0.5; - } - - return network; +Network *network_init(Network *network, uint32_t n_inputs, uint32_t n_hidden, + uint32_t n_outputs, RandFcn rand) { + network->n_inputs = n_inputs; + network->n_hidden = n_hidden; + network->n_outputs = n_outputs; + + network->weights_hidden = + calloc(n_inputs * n_hidden, sizeof(*network->weights_hidden)); + network->biases_hidden = calloc(n_hidden, sizeof(*network->biases_hidden)); + network->weights_output = + calloc(n_hidden * n_outputs, sizeof(*network->weights_output)); + network->biases_output = calloc(n_outputs, sizeof(*network->biases_output)); + network->hidden = calloc(n_hidden, sizeof(*network->hidden)); + network->output = calloc(n_outputs, sizeof(*network->output)); + + // initialize everything but the biases + for (size_t i = 0; i < n_inputs * n_hidden; i++) { + network->weights_hidden[i] = rand() - 0.5; + } + + for (size_t i = 0; i < n_hidden * n_outputs; i++) { + network->weights_output[i] = rand() - 0.5; + } + + return network; } -void network_free(Network* network) { - free(network->weights_hidden); - free(network->biases_hidden); - free(network->weights_output); - free(network->biases_output); - free(network->hidden); - free(network->output); +void network_free(Network *network) { + free(network->weights_hidden); + free(network->biases_hidden); + free(network->weights_output); + free(network->biases_output); + free(network->hidden); + free(network->output); } -void network_predict(Network* network, double* input) { - for (uint32_t c = 0; c < network->n_hidden; c++) { - double sum = 0; - for (uint32_t r = 0; r < network->n_inputs; r++) { - sum += input[r] * network->weights_hidden[r * network->n_hidden + c]; - } - - network->hidden[c] = sigmoid(sum + network->biases_hidden[c]); +void network_predict(Network *network, const double *input) { + for (uint32_t c = 0; c < network->n_hidden; c++) { + double sum = 0; + for (uint32_t r = 0; r < network->n_inputs; r++) { + sum += input[r] * network->weights_hidden[r * network->n_hidden + c]; } - for (uint32_t c = 0; c < network->n_outputs; c++) { - double sum = 0; - for (uint32_t r = 0; r < network->n_hidden; r++) { - sum += network->hidden[r] * network->weights_output[r * network->n_outputs + c]; - } + network->hidden[c] = sigmoid(sum + network->biases_hidden[c]); + } - network->output[c] = sigmoid(sum + network->biases_output[c]); + for (uint32_t c = 0; c < network->n_outputs; c++) { + double sum = 0; + for (uint32_t r = 0; r < network->n_hidden; r++) { + sum += network->hidden[r] * + network->weights_output[r * network->n_outputs + c]; } + + network->output[c] = sigmoid(sum + network->biases_output[c]); + } } /* trainer */ -Trainer* trainer_init(Trainer* trainer, Network* network) { - trainer->grad_hidden = calloc(network->n_hidden, sizeof(*trainer->grad_hidden)); - trainer->grad_output = calloc(network->n_outputs, sizeof(*trainer->grad_output)); - return trainer; +Trainer *trainer_init(Trainer *trainer, Network *network) { + trainer->grad_hidden = + calloc(network->n_hidden, sizeof(*trainer->grad_hidden)); + trainer->grad_output = + calloc(network->n_outputs, sizeof(*trainer->grad_output)); + return trainer; } -void trainer_train(Trainer* trainer, Network* network, double* input, double* y, double lr) { - network_predict(network, input); - for (uint32_t c = 0; c < network->n_outputs; c++) { - trainer->grad_output[c] = (network->output[c] - y[c]) * sigmoid_prim(network->output[c]); - } - - for (uint32_t r = 0; r < network->n_hidden; r++) { - double sum = 0.0; - for (uint32_t c = 0; c < network->n_outputs; c++) { - sum += trainer->grad_output[c] * network->weights_output[r * network->n_outputs + c]; - } - - trainer->grad_hidden[r] = sum * sigmoid_prim(network->hidden[r]); - } +void trainer_train(Trainer *trainer, Network *network, const double *input, + const double *y, double lr) { + network_predict(network, input); + for (uint32_t c = 0; c < network->n_outputs; c++) { + trainer->grad_output[c] = + (network->output[c] - y[c]) * sigmoid_prim(network->output[c]); + } - for (size_t r = 0; r < network->n_hidden; r++) { - for (size_t c = 0; c < network->n_outputs; c++) { - network->weights_output[r * network->n_outputs + c] -= lr * trainer->grad_output[c] * network->hidden[r]; - } + for (uint32_t r = 0; r < network->n_hidden; r++) { + double sum = 0.0; + for (uint32_t c = 0; c < network->n_outputs; c++) { + sum += trainer->grad_output[c] * + network->weights_output[r * network->n_outputs + c]; } - for (size_t r = 0; r < network->n_inputs; r++) { - for (size_t c = 0; c < network->n_hidden; c++) { - network->weights_hidden[r * network->n_hidden + c] -= lr * trainer->grad_hidden[c] * input[r]; - } - } + trainer->grad_hidden[r] = sum * sigmoid_prim(network->hidden[r]); + } + for (size_t r = 0; r < network->n_hidden; r++) { for (size_t c = 0; c < network->n_outputs; c++) { - network->biases_output[c] -= lr * trainer->grad_output[c]; + network->weights_output[r * network->n_outputs + c] -= + lr * trainer->grad_output[c] * network->hidden[r]; } + } + for (size_t r = 0; r < network->n_inputs; r++) { for (size_t c = 0; c < network->n_hidden; c++) { - network->biases_hidden[c] -= lr * trainer->grad_hidden[c]; + network->weights_hidden[r * network->n_hidden + c] -= + lr * trainer->grad_hidden[c] * input[r]; } + } + + for (size_t c = 0; c < network->n_outputs; c++) { + network->biases_output[c] -= lr * trainer->grad_output[c]; + } + + for (size_t c = 0; c < network->n_hidden; c++) { + network->biases_hidden[c] -= lr * trainer->grad_hidden[c]; + } } -void trainer_free(Trainer* trainer) { - free(trainer->grad_hidden); - free(trainer->grad_output); +void trainer_free(Trainer *trainer) { + free(trainer->grad_hidden); + free(trainer->grad_output); } diff --git a/C/neural.h b/C/neural.h index 2bca1f7..b19a244 100644 --- a/C/neural.h +++ b/C/neural.h @@ -23,34 +23,31 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include typedef struct Network { - double* weights_hidden; - double* biases_hidden; - double* weights_output; - double* biases_output; - double* hidden; - double* output; - uint32_t n_inputs; - uint32_t n_hidden; - uint32_t n_outputs; + double *weights_hidden; + double *biases_hidden; + double *weights_output; + double *biases_output; + double *hidden; + double *output; + uint32_t n_inputs; + uint32_t n_hidden; + uint32_t n_outputs; } Network; -typedef double (*RandFcn)(); -Network* network_init( - Network* network, - uint32_t n_inputs, - uint32_t n_hidden, - uint32_t n_outputs, - RandFcn rand); -void network_free(Network* network); -void network_predict(Network* network, double* input); +typedef double (*RandFcn)(void); +Network *network_init(Network *network, uint32_t n_inputs, uint32_t n_hidden, + uint32_t n_outputs, RandFcn rand); +void network_free(Network *network); +void network_predict(Network *network, const double *input); typedef struct Trainer { - double* grad_hidden; - double* grad_output; + double *grad_hidden; + double *grad_output; } Trainer; -Trainer* trainer_init(Trainer* trainer, Network* network); -void trainer_train(Trainer* trainer, Network* network, double* input, double* output, double lr); -void trainer_free(Trainer* trainer); +Trainer *trainer_init(Trainer *trainer, Network *network); +void trainer_train(Trainer *trainer, Network *network, const double *input, + const double *output, double lr); +void trainer_free(Trainer *trainer); #endif