106 lines
3.8 KiB
C
106 lines
3.8 KiB
C
#include "unity.h"
|
|
#include "../src/network.h"
|
|
|
|
void setUp(void) {}
|
|
|
|
void tearDown(void) {}
|
|
|
|
void test_network_create(void) {
|
|
int dimensions[] = {2, 3, 1};
|
|
Network *network = network_create(3, dimensions);
|
|
TEST_ASSERT_NOT_NULL(network);
|
|
TEST_ASSERT_EQUAL_INT(3, network->layerCount);
|
|
TEST_ASSERT_EQUAL_INT(2, network->dimensions[0]);
|
|
TEST_ASSERT_EQUAL_INT(3, network->dimensions[1]);
|
|
TEST_ASSERT_EQUAL_INT(1, network->dimensions[2]);
|
|
TEST_ASSERT_NOT_NULL(network->weights);
|
|
TEST_ASSERT_NOT_NULL(network->biases);
|
|
TEST_ASSERT_NOT_NULL(network->outputs);
|
|
for (int i = 0; i < 2; i++) {
|
|
TEST_ASSERT_NOT_NULL(network->weights[i]);
|
|
}
|
|
network_free(network);
|
|
}
|
|
|
|
void test_network_predict(void) {
|
|
// XOR function. Assume it already trained, could it predict the output?
|
|
int dimensions[] = {2, 2, 1};
|
|
Network *network = network_create(3, dimensions);
|
|
|
|
// A correct (trained) weights and biases for the XOR function:
|
|
double weights1[2][2] = {{20, 20}, {-20, -20}};
|
|
double weights2[1][2] = {{20, 20}};
|
|
double biases1[2][1] = {{-10}, {30}};
|
|
double biases2[1][1] = {{-30}};
|
|
|
|
matrix_initialise(network->weights[0], weights1);
|
|
matrix_initialise(network->weights[1], weights2);
|
|
matrix_initialise(network->biases[0], biases1);
|
|
matrix_initialise(network->biases[1], biases2);
|
|
|
|
// Inputs and targets for the XOR function
|
|
double inputs[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
|
|
double targets[4][1] = {{0}, {1}, {1}, {0}};
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
Matrix *input = matrix_create(2, 1);
|
|
matrix_initialise(input, (double[2][1]){inputs[i][0], inputs[i][1]});
|
|
|
|
Matrix *target = matrix_create(1, 1);
|
|
matrix_initialise(target, (double[1][1]){targets[i][0]});
|
|
|
|
network_predict(network, input);
|
|
// The result is correct if it is within 0.0001 of the target
|
|
TEST_ASSERT_FLOAT_WITHIN(0.0001, targets[i][0], network_output(network)[0]);
|
|
|
|
matrix_free(input);
|
|
matrix_free(target);
|
|
}
|
|
}
|
|
|
|
void check_matrix_equality(Matrix *m1, Matrix *m2) {
|
|
TEST_ASSERT_EQUAL_INT(m1->rows, m2->rows);
|
|
TEST_ASSERT_EQUAL_INT(m1->cols, m2->cols);
|
|
for (int i = 0; i < m1->rows; i++) {
|
|
for (int j = 0; j < m1->cols; j++) {
|
|
TEST_ASSERT_EQUAL_DOUBLE(m1->data[i][j], m2->data[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void test_network_loadstore(void) {
|
|
int dimensions[] = {2, 3, 1};
|
|
Network *network = network_create(3, dimensions);
|
|
matrix_initialise(network->weights[0], (double[3][2]){{1, 2}, {3, 4}, {5, 6}});
|
|
matrix_initialise(network->weights[1], (double[1][3]){{7, 8, 9}});
|
|
matrix_initialise(network->biases[0], (double[3][1]){{1}, {2}, {3}});
|
|
network_store(network, "my_network");
|
|
Network *loaded_network = network_load("my_network");
|
|
TEST_ASSERT_NOT_NULL(loaded_network);
|
|
TEST_ASSERT_EQUAL_INT(3, loaded_network->layerCount);
|
|
TEST_ASSERT_EQUAL_INT(2, loaded_network->dimensions[0]);
|
|
TEST_ASSERT_EQUAL_INT(3, loaded_network->dimensions[1]);
|
|
TEST_ASSERT_EQUAL_INT(1, loaded_network->dimensions[2]);
|
|
TEST_ASSERT_NOT_NULL(loaded_network->weights);
|
|
TEST_ASSERT_NOT_NULL(loaded_network->biases);
|
|
TEST_ASSERT_NOT_NULL(loaded_network->outputs);
|
|
for (int i = 0; i < 2; i++) {
|
|
TEST_ASSERT_NOT_NULL(loaded_network->weights[i]);
|
|
check_matrix_equality(network->weights[i], loaded_network->weights[i]);
|
|
}
|
|
for (int i = 0; i < 2; i++) {
|
|
TEST_ASSERT_NOT_NULL(loaded_network->biases[i]);
|
|
check_matrix_equality(network->biases[i], loaded_network->biases[i]);
|
|
}
|
|
network_free(network);
|
|
network_free(loaded_network);
|
|
|
|
}
|
|
|
|
int main(void) {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_network_create);
|
|
RUN_TEST(test_network_predict);
|
|
RUN_TEST(test_network_loadstore);
|
|
return UNITY_END();
|
|
} |