Compare commits

..
8 Commits
Author SHA1 Message Date
reckertni101608 b802e24abd imageInputTests Kommentiert 2025-11-18 01:12:09 +01:00
Tubui 37d6d88ddf complete version 2025-11-17 20:33:15 +01:00
reckertni101608 a50550f3ea Hilfsfunktionen für ImageInput.c 2025-11-17 20:01:13 +01:00
reckertni101608 ad32be997b Kommentare für besseres Verständnis 2025-11-16 21:51:15 +01:00
reckertni101608 46601b3020 Test 2025-11-16 20:44:49 +01:00
reckertni101608 339c3e81b1 All Tests Passed 2025-11-16 20:43:25 +01:00
Tubui b7e44e9670 Second commit 2025-11-16 19:08:19 +01:00
Tubui c76b9bc927 First commit 2025-11-04 14:43:24 +01:00
41 changed files with 873 additions and 532 deletions

No files matched your search

+3 -60
View File
@@ -1,61 +1,4 @@
# ---> C
# Prerequisites
*.d
# Object files
mnist
runTests
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
Startcode/mnist
Startcode/runTests
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# IDE folders
.vscode/
.idea/
# macOS
.DS_Store
*.exe
Binary file not shown.
-22
View File
@@ -1,22 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei
// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
GrayScaleImageSeries *readImages(const char *path)
{
GrayScaleImageSeries *series = NULL;
return series;
}
// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt
void clearSeries(GrayScaleImageSeries *series)
{
}
-143
View File
@@ -1,143 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "imageInput.h"
static void prepareImageFile(const char *path, unsigned short int width, unsigned short int height, unsigned int short numberOfImages, unsigned char label)
{
FILE *file = fopen(path, "wb");
if(file != NULL)
{
const char *fileTag = "__info2_image_file_format__";
GrayScalePixelType *zeroBuffer = (GrayScalePixelType *)calloc(numberOfImages * width * height, sizeof(GrayScalePixelType));
if(zeroBuffer != NULL)
{
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&numberOfImages, sizeof(numberOfImages), 1, file);
fwrite(&width, sizeof(width), 1, file);
fwrite(&height, sizeof(height), 1, file);
for(int i = 0; i < numberOfImages; i++)
{
fwrite(zeroBuffer, sizeof(GrayScalePixelType), width * height, file);
fwrite(&label, sizeof(unsigned char), 1, file);
}
free(zeroBuffer);
}
fclose(file);
}
}
void test_readImagesReturnsCorrectNumberOfImages(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedNumberOfImages = 2;
const char *path = "testFile.info2";
prepareImageFile(path, 8, 8, expectedNumberOfImages, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_EQUAL_UINT16(expectedNumberOfImages, series->count);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectImageWidth(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedWidth = 10;
const char *path = "testFile.info2";
prepareImageFile(path, expectedWidth, 8, 2, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->images);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[0].width);
TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[1].width);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectImageHeight(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedHeight = 10;
const char *path = "testFile.info2";
prepareImageFile(path, 8, expectedHeight, 2, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->images);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[0].height);
TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[1].height);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectLabels(void)
{
const unsigned char expectedLabel = 15;
GrayScaleImageSeries *series = NULL;
const char *path = "testFile.info2";
prepareImageFile(path, 8, 8, 2, expectedLabel);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->labels);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
for (int i = 0; i < 2; i++) {
TEST_ASSERT_EQUAL_UINT8(expectedLabel, series->labels[i]);
}
clearSeries(series);
remove(path);
}
void test_readImagesReturnsNullOnNotExistingPath(void)
{
const char *path = "testFile.txt";
remove(path);
TEST_ASSERT_NULL(readImages(path));
}
void test_readImagesFailsOnWrongFileTag(void)
{
const char *path = "testFile.info2";
FILE *file = fopen(path, "w");
if(file != NULL)
{
fprintf(file, "some_tag ");
fclose(file);
TEST_ASSERT_NULL(readImages(path));
}
remove(path);
}
void setUp(void) {
// Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden
}
void tearDown(void) {
// Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden
}
int main()
{
UNITY_BEGIN();
printf("\n============================\nImage input tests\n============================\n");
RUN_TEST(test_readImagesReturnsCorrectNumberOfImages);
RUN_TEST(test_readImagesReturnsCorrectImageWidth);
RUN_TEST(test_readImagesReturnsCorrectImageHeight);
RUN_TEST(test_readImagesReturnsCorrectLabels);
RUN_TEST(test_readImagesReturnsNullOnNotExistingPath);
RUN_TEST(test_readImagesFailsOnWrongFileTag);
return UNITY_END();
}
-35
View File
@@ -1,35 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "matrix.h"
// TODO Matrix-Funktionen implementieren
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
}
void clearMatrix(Matrix *matrix)
{
}
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
}
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
}
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
}
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
}
-242
View File
@@ -1,242 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "unity.h"
#include "neuralNetwork.h"
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
{
// TODO
}
void test_loadModelReturnsCorrectNumberOfLayers(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
MatrixType buffer2[] = {1, 2, 3, 4, 5, 6};
Matrix weights1 = {.buffer=buffer1, .rows=3, .cols=2};
Matrix weights2 = {.buffer=buffer2, .rows=2, .cols=3};
MatrixType buffer3[] = {1, 2, 3};
MatrixType buffer4[] = {1, 2};
Matrix biases1 = {.buffer=buffer3, .rows=3, .cols=1};
Matrix biases2 = {.buffer=buffer4, .rows=2, .cols=1};
Layer layers[] = {{.weights=weights1, .biases=biases1}, {.weights=weights2, .biases=biases2}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=2};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_EQUAL_INT(expectedNet.numberOfLayers, netUnderTest.numberOfLayers);
clearModel(&netUnderTest);
}
void test_loadModelReturnsCorrectWeightDimensions(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
clearModel(&netUnderTest);
}
void test_loadModelReturnsCorrectBiasDimensions(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].biases.rows, netUnderTest.layers[0].biases.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].biases.cols, netUnderTest.layers[0].biases.cols);
clearModel(&netUnderTest);
}
void test_loadModelReturnsCorrectWeights(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
int n = netUnderTest.layers[0].weights.rows * netUnderTest.layers[0].weights.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(expectedNet.layers[0].weights.buffer, netUnderTest.layers[0].weights.buffer, n);
clearModel(&netUnderTest);
}
void test_loadModelReturnsCorrectBiases(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
int n = netUnderTest.layers[0].biases.rows * netUnderTest.layers[0].biases.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(expectedNet.layers[0].biases.buffer, netUnderTest.layers[0].biases.buffer, n);
clearModel(&netUnderTest);
}
void test_loadModelFailsOnWrongFileTag(void)
{
const char *path = "some_nn_test_file.info2";
NeuralNetwork netUnderTest;
FILE *file = fopen(path, "wb");
if(file != NULL)
{
const char *fileTag = "info2_neural_network_file_format";
fwrite(fileTag, sizeof(char), strlen(fileTag), file);
fclose(file);
}
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_NULL(netUnderTest.layers);
TEST_ASSERT_EQUAL_INT(0, netUnderTest.numberOfLayers);
}
void test_clearModelSetsMembersToNull(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_NOT_NULL(netUnderTest.layers);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
clearModel(&netUnderTest);
TEST_ASSERT_NULL(netUnderTest.layers);
TEST_ASSERT_EQUAL_INT(0, netUnderTest.numberOfLayers);
}
static void someActivation(Matrix *matrix)
{
for(int i = 0; i < matrix->rows * matrix->cols; i++)
{
matrix->buffer[i] = fabs(matrix->buffer[i]);
}
}
void test_predictReturnsCorrectLabels(void)
{
const unsigned char expectedLabels[] = {4, 2};
GrayScalePixelType imageBuffer1[] = {10, 30, 25, 17};
GrayScalePixelType imageBuffer2[] = {20, 40, 10, 128};
GrayScaleImage inputImages[] = {{.buffer=imageBuffer1, .width=2, .height=2}, {.buffer=imageBuffer2, .width=2, .height=2}};
MatrixType weightsBuffer1[] = {1, -2, 3, -4, 5, -6, 7, -8};
MatrixType weightsBuffer2[] = {-9, 10, 11, 12, 13, 14};
MatrixType weightsBuffer3[] = {-15, 16, 17, 18, -19, 20, 21, 22, 23, -24, 25, 26, 27, -28, -29};
Matrix weights1 = {.buffer=weightsBuffer1, .rows=2, .cols=4};
Matrix weights2 = {.buffer=weightsBuffer2, .rows=3, .cols=2};
Matrix weights3 = {.buffer=weightsBuffer3, .rows=5, .cols=3};
MatrixType biasBuffer1[] = {200, 0};
MatrixType biasBuffer2[] = {0, -100, 0};
MatrixType biasBuffer3[] = {0, -1000, 0, 2000, 0};
Matrix biases1 = {.buffer=biasBuffer1, .rows=2, .cols=1};
Matrix biases2 = {.buffer=biasBuffer2, .rows=3, .cols=1};
Matrix biases3 = {.buffer=biasBuffer3, .rows=5, .cols=1};
Layer layers[] = {{.weights=weights1, .biases=biases1, .activation=someActivation}, \
{.weights=weights2, .biases=biases2, .activation=someActivation}, \
{.weights=weights3, .biases=biases3, .activation=someActivation}};
NeuralNetwork netUnderTest = {.layers=layers, .numberOfLayers=3};
unsigned char *predictedLabels = predict(netUnderTest, inputImages, 2);
TEST_ASSERT_NOT_NULL(predictedLabels);
int n = (int)(sizeof(expectedLabels) / sizeof(expectedLabels[0]));
TEST_ASSERT_EQUAL_UINT8_ARRAY(expectedLabels, predictedLabels, n);
free(predictedLabels);
}
void setUp(void) {
// Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden
}
void tearDown(void) {
// Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden
}
int main()
{
UNITY_BEGIN();
printf("\n============================\nNeural network tests\n============================\n");
RUN_TEST(test_loadModelReturnsCorrectNumberOfLayers);
RUN_TEST(test_loadModelReturnsCorrectWeightDimensions);
RUN_TEST(test_loadModelReturnsCorrectBiasDimensions);
RUN_TEST(test_loadModelReturnsCorrectWeights);
RUN_TEST(test_loadModelReturnsCorrectBiases);
RUN_TEST(test_loadModelFailsOnWrongFileTag);
RUN_TEST(test_clearModelSetsMembersToNull);
RUN_TEST(test_predictReturnsCorrectLabels);
return UNITY_END();
}
+192
View File
@@ -0,0 +1,192 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
// =====================================================
// Hilfsfunktion 1
// Datei öffnen + Header prüfen + Metadaten lesen
// =====================================================
static FILE *openFileAndReadHeader(const char *path, unsigned short *count, unsigned short *width, unsigned short *height)
{
// Schritt 1: Datei öffnen
FILE *file = fopen(path, "rb");
if (!file) {
fprintf(stderr, "Error: Cannot open file '%s'\n", path);
return NULL;
}
// Schritt 2: Header-String prüfen
char buffer[BUFFER_SIZE] = {0};
size_t headerLen = strlen(FILE_HEADER_STRING);
if (fread(buffer, sizeof(char), headerLen, file) != headerLen) {
fprintf(stderr, "Error: Cannot read file header (file too small?)\n");
fclose(file);
return NULL;
}
if (strncmp(buffer, FILE_HEADER_STRING, headerLen) != 0) {
fprintf(stderr, "Error: Invalid file header. Expected '%s', got: %.24s\n",
FILE_HEADER_STRING, buffer);
fclose(file);
return NULL;
}
// Schritt 3: Metadaten lesen (Reihenfolge: count, width, height)
// WICHTIG: Diese Reihenfolge (Anzahl, Breite, Höhe) entspricht
// der Aufgabenstellung und dem in den Tests verwendeten Format.
if (fread(count, sizeof(unsigned short), 1, file) != 1) {
fprintf(stderr, "Error: Cannot read image count\n");
fclose(file);
return NULL;
}
if (fread(width, sizeof(unsigned short), 1, file) != 1) {
fprintf(stderr, "Error: Cannot read image width\n");
fclose(file);
return NULL;
}
if (fread(height, sizeof(unsigned short), 1, file) != 1) {
fprintf(stderr, "Error: Cannot read image height\n");
fclose(file);
return NULL;
}
// Input-Validierung: Prüfe auf ungültige Dimensionen
if (*count == 0) {
fprintf(stderr, "Error: Image count is 0\n");
fclose(file);
return NULL;
}
if (*width == 0) {
fprintf(stderr, "Error: Image width is 0\n");
fclose(file);
return NULL;
}
if (*height == 0) {
fprintf(stderr, "Error: Image height is 0\n");
fclose(file);
return NULL;
}
// Erfolg: offene Datei zurückgeben, Position ist nach Metadaten
return file;
}
// -----------------------------------------------------
// Hilfsfunktion 2: Speicher für die gesamte Serie anlegen
// -----------------------------------------------------
static GrayScaleImageSeries *allocateSeries(unsigned short count,
unsigned short width,
unsigned short height)
{
GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries));
if (!series) return NULL;
series->count = count;
series->images = calloc(count, sizeof(GrayScaleImage));
series->labels = calloc(count, sizeof(unsigned char));
if (!series->images || !series->labels)
{
clearSeries(series);
return NULL;
}
// Bilddimensionen in jedes Struktur-Element übernehmen
for (unsigned short i = 0; i < count; i++)
{
series->images[i].width = width;
series->images[i].height = height;
}
return series;
}
// -----------------------------------------------------
// Hilfsfunktion 3: EIN BILD + EIN LABEL lesen
// -----------------------------------------------------
static int readSingleImage(FILE *file, GrayScaleImage *img, unsigned char *label)
{
unsigned int pixelCount = img->width * img->height;
img->buffer = malloc(pixelCount * sizeof(GrayScalePixelType));
if (!img->buffer)
return 0;
if (fread(img->buffer, sizeof(GrayScalePixelType), pixelCount, file) != pixelCount)
return 0;
if (fread(label, sizeof(unsigned char), 1, file) != 1)
return 0;
return 1;
}
// =====================================================
// Hauptfunktion: Liest komplette Bilderserie
// =====================================================
GrayScaleImageSeries *readImages(const char *path)
{
unsigned short count = 0, width = 0, height = 0;
// Schritt 1-3: Datei öffnen + Header + Metadaten
FILE *file = openFileAndReadHeader(path, &count, &width, &height);
if (!file) {
// Fehler bereits geloggt von openFileAndReadHeader()
return NULL;
}
// Schritt 4: Bilderserie allokieren
GrayScaleImageSeries *series = allocateSeries(count, width, height);
if (!series) {
fprintf(stderr, "Error: Cannot allocate image series\n");
fclose(file);
return NULL;
}
// Schritt 5: Alle Bilder + Labels lesen
for (unsigned short i = 0; i < count; i++) {
if (!readSingleImage(file, &series->images[i], &series->labels[i])) {
fprintf(stderr, "Error: Cannot read image %u\n", i);
clearSeries(series);
fclose(file);
return NULL;
}
}
fclose(file);
return series;
}
// =====================================================
// Speicher-Freigabe
// =====================================================
void clearSeries(GrayScaleImageSeries *series)
{
if (!series)
return;
if (series->images)
{
for (unsigned int i = 0; i < series->count; i++)
{
free(series->images[i].buffer);
series->images[i].buffer = NULL;
}
free(series->images);
series->images = NULL;
}
if (series->labels)
{
free(series->labels);
series->labels = NULL;
}
free(series);
}
File renamed without changes.
+311
View File
@@ -0,0 +1,311 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "imageInput.h"
static void prepareImageFile(const char *path, unsigned short int width, unsigned short int height, unsigned int short numberOfImages, unsigned char label)
{
FILE *file = fopen(path, "wb");
if(file != NULL)
{
const char *fileTag = "__info2_image_file_format__";
GrayScalePixelType *zeroBuffer = (GrayScalePixelType *)calloc(numberOfImages * width * height, sizeof(GrayScalePixelType));
if(zeroBuffer != NULL)
{
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&numberOfImages, sizeof(numberOfImages), 1, file);
fwrite(&width, sizeof(width), 1, file);
fwrite(&height, sizeof(height), 1, file);
for(int i = 0; i < numberOfImages; i++)
{
fwrite(zeroBuffer, sizeof(GrayScalePixelType), width * height, file);
fwrite(&label, sizeof(unsigned char), 1, file);
}
free(zeroBuffer);
}
fclose(file);
}
}
void test_readImagesReturnsCorrectNumberOfImages(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedNumberOfImages = 2;
const char *path = "testFile.info2";
prepareImageFile(path, 8, 8, expectedNumberOfImages, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_EQUAL_UINT16(expectedNumberOfImages, series->count);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectImageWidth(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedWidth = 10;
const char *path = "testFile.info2";
// prepareImageFile(path, width, height, numberOfImages, label)
prepareImageFile(path, expectedWidth, 8, 2, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->images);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[0].width);
TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[1].width);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectImageHeight(void)
{
GrayScaleImageSeries *series = NULL;
const unsigned short expectedHeight = 10;
const char *path = "testFile.info2";
// prepareImageFile(path, width, height, numberOfImages, label)
prepareImageFile(path, 8, expectedHeight, 2, 1);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->images);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[0].height);
TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[1].height);
clearSeries(series);
remove(path);
}
void test_readImagesReturnsCorrectLabels(void)
{
const unsigned char expectedLabel = 15;
GrayScaleImageSeries *series = NULL;
const char *path = "testFile.info2";
prepareImageFile(path, 8, 8, 2, expectedLabel);
series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_NOT_NULL(series->labels);
TEST_ASSERT_EQUAL_UINT16(2, series->count);
for (int i = 0; i < 2; i++) {
TEST_ASSERT_EQUAL_UINT8(expectedLabel, series->labels[i]);
}
clearSeries(series);
remove(path);
}
void test_readImagesReturnsNullOnNotExistingPath(void)
{
const char *path = "testFile.txt";
remove(path);
TEST_ASSERT_NULL(readImages(path));
}
void test_readImagesFailsOnWrongFileTag(void)
{
const char *path = "testFile.info2";
FILE *file = fopen(path, "w");
if(file != NULL)
{
fprintf(file, "some_tag ");
fclose(file);
TEST_ASSERT_NULL(readImages(path));
}
remove(path);
}
// =====================================================
// Tests für Hilfsfunktion imageInput.c
// =====================================================
void test_openFileAndReadHeaderFailsOnZeroImageCount(void)
{
// Test: Datei mit count=0 sollte fehlschlagen
const char *path = "testZeroCount.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
const char *fileTag = "__info2_image_file_format__";
unsigned short zero_count = 0;
unsigned short width = 28;
unsigned short height = 28;
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&zero_count, sizeof(unsigned short), 1, file);
fwrite(&height, sizeof(unsigned short), 1, file);
fwrite(&width, sizeof(unsigned short), 1, file);
fclose(file);
}
// readImages sollte NULL zurückgeben bei count=0
TEST_ASSERT_NULL(readImages(path));
remove(path);
}
void test_openFileAndReadHeaderFailsOnZeroWidth(void)
{
// Test: Datei mit width=0 sollte fehlschlagen
const char *path = "testZeroWidth.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
const char *fileTag = "__info2_image_file_format__";
unsigned short count = 5;
unsigned short width = 0;
unsigned short height = 28;
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&count, sizeof(unsigned short), 1, file);
fwrite(&height, sizeof(unsigned short), 1, file);
fwrite(&width, sizeof(unsigned short), 1, file);
fclose(file);
}
TEST_ASSERT_NULL(readImages(path));
remove(path);
}
void test_openFileAndReadHeaderFailsOnZeroHeight(void)
{
// Test: Datei mit height=0 sollte fehlschlagen
const char *path = "testZeroHeight.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
const char *fileTag = "__info2_image_file_format__";
unsigned short count = 5;
unsigned short width = 28;
unsigned short height = 0;
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&count, sizeof(unsigned short), 1, file);
fwrite(&height, sizeof(unsigned short), 1, file);
fwrite(&width, sizeof(unsigned short), 1, file);
fclose(file);
}
TEST_ASSERT_NULL(readImages(path));
remove(path);
}
void test_openFileAndReadHeaderFailsOnTruncatedHeader(void)
{
// Test: Datei ist zu kurz für Header
const char *path = "testTruncated.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
// Nur 10 Bytes schreiben (Header ist 24 Bytes)
const char *fileTag = "__info2_im";
fwrite(fileTag, 1, 10, file);
fclose(file);
}
TEST_ASSERT_NULL(readImages(path));
remove(path);
}
void test_openFileAndReadHeaderFailsOnMissingCount(void)
{
// Test: Datei hat Header aber keine Meta Daten
const char *path = "testMissingCount.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
const char *fileTag = "__info2_image_file_format__";
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fclose(file);
}
TEST_ASSERT_NULL(readImages(path));
remove(path);
}
void test_openFileAndReadHeaderSucceedsWithValidData(void)
{
// Test: Valide Datei sollte erfolgreich sein
const char *path = "testValid.info2";
prepareImageFile(path, 28, 28, 5, 3);
GrayScaleImageSeries *series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_EQUAL_UINT16(5, series->count);
TEST_ASSERT_EQUAL_UINT16(28, series->images[0].width);
TEST_ASSERT_EQUAL_UINT16(28, series->images[0].height);
clearSeries(series);
remove(path);
}
void test_openFileAndReadHeaderCorrectMetadataOrder(void)
{
// Test: Metadaten werden in richtiger Reihenfolge gelesen
const char *path = "testMetadataOrder.info2";
FILE *file = fopen(path, "wb");
if (file != NULL) {
const char *fileTag = "__info2_image_file_format__";
unsigned short count = 10;
unsigned short width = 16; // Anzahl, Breite, Höhe
unsigned short height = 32;
unsigned char label = 5;
unsigned char pixel_data[16*32];
memset(pixel_data, 128, sizeof(pixel_data));
fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file);
fwrite(&count, sizeof(unsigned short), 1, file);
fwrite(&width, sizeof(unsigned short), 1, file);
fwrite(&height, sizeof(unsigned short), 1, file);
for (int i = 0; i < count; i++) {
fwrite(pixel_data, 1, 16*32, file);
fwrite(&label, 1, 1, file);
}
fclose(file);
}
GrayScaleImageSeries *series = readImages(path);
TEST_ASSERT_NOT_NULL(series);
TEST_ASSERT_EQUAL_UINT16(10, series->count);
TEST_ASSERT_EQUAL_UINT16(32, series->images[0].height); // height korrekt
TEST_ASSERT_EQUAL_UINT16(16, series->images[0].width); // width korrekt
clearSeries(series);
remove(path);
}
void setUp(void) {
// Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden
}
void tearDown(void) {
// Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden
}
int main()
{
UNITY_BEGIN();
printf("\n============================\nImage input tests\n============================\n");
// Ursprüngliche Tests
RUN_TEST(test_readImagesReturnsCorrectNumberOfImages);
RUN_TEST(test_readImagesReturnsCorrectImageWidth);
RUN_TEST(test_readImagesReturnsCorrectImageHeight);
RUN_TEST(test_readImagesReturnsCorrectLabels);
RUN_TEST(test_readImagesReturnsNullOnNotExistingPath);
RUN_TEST(test_readImagesFailsOnWrongFileTag);
// Neue Tests für kombinierte Funktion (Input-Validierung)
printf("\n--- Tests für Input-Validierung ---\n");
RUN_TEST(test_openFileAndReadHeaderFailsOnZeroImageCount);
RUN_TEST(test_openFileAndReadHeaderFailsOnZeroWidth);
RUN_TEST(test_openFileAndReadHeaderFailsOnZeroHeight);
RUN_TEST(test_openFileAndReadHeaderFailsOnTruncatedHeader);
RUN_TEST(test_openFileAndReadHeaderFailsOnMissingCount);
RUN_TEST(test_openFileAndReadHeaderSucceedsWithValidData);
RUN_TEST(test_openFileAndReadHeaderCorrectMetadataOrder);
return UNITY_END();
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+126
View File
@@ -0,0 +1,126 @@
#include "matrix.h"
#include <stdlib.h>
// Matrix erstellen
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
Matrix m;
if (rows == 0 || cols == 0) {
m.rows = 0;
m.cols = 0;
m.buffer = NULL;
return m;
}
m.rows = rows;
m.cols = cols;
m.buffer = (MatrixType*)calloc(rows * cols, sizeof(MatrixType));
if (!m.buffer) {
m.rows = 0;
m.cols = 0;
}
return m;
}
// Speicher freigeben
void clearMatrix(Matrix *matrix)
{
if (!matrix || !matrix->buffer) return;
free(matrix->buffer);
matrix->buffer = NULL;
matrix->rows = 0;
matrix->cols = 0;
}
// Wert setzen
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return;
matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
}
// Wert auslesen
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return UNDEFINED_MATRIX_VALUE;
return matrix.buffer[rowIdx * matrix.cols + colIdx];
}
// Addition (mit Broadcasting-Unterstützung für Bias)
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
Matrix result;
// Fall 1: Exakte Dimensionen (Element-weise Addition)
if (matrix1.rows == matrix2.rows && matrix1.cols == matrix2.cols) {
result = createMatrix(matrix1.rows, matrix1.cols);
for (unsigned int i = 0; i < matrix1.rows * matrix1.cols; i++)
result.buffer[i] = matrix1.buffer[i] + matrix2.buffer[i];
return result;
}
// Fall 2: matrix1 ist (zeilen x 1) Spaltenvektor, matrix2 ist (zeilen x spalten)
// Broadcasting: matrix1's Spalte wird zu jeder Spalte von matrix2 addiert
if (matrix1.rows == matrix2.rows && matrix1.cols == 1) {
result = createMatrix(matrix2.rows, matrix2.cols);
for (unsigned int col = 0; col < matrix2.cols; col++) {
for (unsigned int row = 0; row < matrix2.rows; row++) {
MatrixType val1 = matrix1.buffer[row * matrix1.cols + 0];
MatrixType val2 = matrix2.buffer[row * matrix2.cols + col];
result.buffer[row * result.cols + col] = val1 + val2;
}
}
return result;
}
// Fall 3: matrix2 ist (zeilen x 1) Spaltenvektor, matrix1 ist (zeilen x spalten)
// Broadcasting: matrix2's Spalte wird zu jeder Spalte von matrix1 addiert
if (matrix2.rows == matrix1.rows && matrix2.cols == 1) {
result = createMatrix(matrix1.rows, matrix1.cols);
for (unsigned int col = 0; col < matrix1.cols; col++) {
for (unsigned int row = 0; row < matrix1.rows; row++) {
MatrixType val1 = matrix1.buffer[row * matrix1.cols + col];
MatrixType val2 = matrix2.buffer[row * matrix2.cols + 0];
result.buffer[row * result.cols + col] = val1 + val2;
}
}
return result;
}
// Ungültige Dimensionen - leere Matrix zurückgeben
result.rows = 0;
result.cols = 0;
result.buffer = NULL;
return result;
}
// Multiplikation
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
Matrix result;
// Überprüfe ob Multiplikation möglich ist (Spalten matrix1 == Zeilen matrix2)
if (matrix1.cols != matrix2.rows) {
result.rows = 0;
result.cols = 0;
result.buffer = NULL;
return result;
}
result = createMatrix(matrix1.rows, matrix2.cols);
// Berechne alle Elemente des Ergebnisses
for (unsigned int i = 0; i < matrix1.rows; i++)
{
for (unsigned int j = 0; j < matrix2.cols; j++)
{
// Skalarprodukt: Reihe i von matrix1 × Spalte j von matrix2
MatrixType sum = 0;
for (unsigned int k = 0; k < matrix1.cols; k++)
sum += matrix1.buffer[i * matrix1.cols + k] * matrix2.buffer[k * matrix2.cols + j];
result.buffer[i * result.cols + j] = sum;
}
}
return result;
}
+7 -2
View File
@@ -5,9 +5,15 @@
typedef float MatrixType;
// TODO Matrixtyp definieren
// Struktur Matrix
typedef struct {
MatrixType *buffer; // pointer
unsigned int rows;
unsigned int cols;
} Matrix;
// Funktionen
Matrix createMatrix(unsigned int rows, unsigned int cols);
void clearMatrix(Matrix *matrix);
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx);
@@ -15,5 +21,4 @@ MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int co
Matrix add(const Matrix matrix1, const Matrix matrix2);
Matrix multiply(const Matrix matrix1, const Matrix matrix2);
#endif
+1 -28
View File
@@ -71,32 +71,6 @@ void test_addFailsOnDifferentInputDimensions(void)
TEST_ASSERT_EQUAL_UINT32(0, result.cols);
}
void test_addSupportsBroadcasting(void)
{
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
MatrixType buffer2[] = {7, 8};
Matrix matrix1 = {.rows=2, .cols=3, .buffer=buffer1};
Matrix matrix2 = {.rows=2, .cols=1, .buffer=buffer2};
Matrix result1 = add(matrix1, matrix2);
Matrix result2 = add(matrix2, matrix1);
float expectedResults[] = {8, 9, 10, 12, 13, 14};
TEST_ASSERT_EQUAL_UINT32(matrix1.rows, result1.rows);
TEST_ASSERT_EQUAL_UINT32(matrix1.cols, result1.cols);
TEST_ASSERT_EQUAL_UINT32(matrix1.rows, result2.rows);
TEST_ASSERT_EQUAL_UINT32(matrix1.cols, result2.cols);
TEST_ASSERT_EQUAL_INT(sizeof(expectedResults)/sizeof(expectedResults[0]), result1.rows * result1.cols);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, result1.buffer, result1.cols * result1.rows);
TEST_ASSERT_EQUAL_INT(sizeof(expectedResults)/sizeof(expectedResults[0]), result2.rows * result2.cols);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, result2.buffer, result2.cols * result2.rows);
free(result1.buffer);
free(result2.buffer);
}
void test_multiplyReturnsCorrectResults(void)
{
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
@@ -164,7 +138,7 @@ void test_setMatrixAtFailsOnIndicesOutOfRange(void)
Matrix matrixToTest = {.rows=2, .cols=3, .buffer=buffer};
setMatrixAt(-1, matrixToTest, 2, 3);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, sizeof(buffer)/sizeof(MatrixType));
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, matrixToTest.cols * matrixToTest.rows);
}
void setUp(void) {
@@ -185,7 +159,6 @@ int main()
RUN_TEST(test_clearMatrixSetsMembersToNull);
RUN_TEST(test_addReturnsCorrectResult);
RUN_TEST(test_addFailsOnDifferentInputDimensions);
RUN_TEST(test_addSupportsBroadcasting);
RUN_TEST(test_multiplyReturnsCorrectResults);
RUN_TEST(test_multiplyFailsOnWrongInputDimensions);
RUN_TEST(test_getMatrixAtReturnsCorrectResult);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -254,6 +254,8 @@ unsigned char *predict(const NeuralNetwork model, const GrayScaleImage images[],
return result;
}
void clearModel(NeuralNetwork *model)
{
if(model != NULL)
File renamed without changes.
+231
View File
@@ -0,0 +1,231 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity.h"
#include "neuralNetwork.h"
#define FILE_HEADER_STRING "__info2_neural_network_file_format__"
// --------------------------
// Hilfsfunktion zum Erstellen einer Test-Datei für das Netzwerk
// --------------------------
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
{
FILE *file = fopen(path, "wb");
if (!file) return;
// Dateikennzeichnung schreiben
const char *fileTag = "__info2_neural_network_file_format__";
fwrite(fileTag, sizeof(char), strlen(fileTag), file);
// Alle Layer des Netzwerks in die Datei schreiben
for (unsigned int i = 0; i < nn.numberOfLayers; i++)
{
unsigned int inputDim = nn.layers[i].weights.cols;
unsigned int outputDim = nn.layers[i].weights.rows;
// Dimensionen des Layers schreiben
fwrite(&inputDim, sizeof(unsigned int), 1, file);
fwrite(&outputDim, sizeof(unsigned int), 1, file);
// Gewichtsmatrix schreiben
fwrite(nn.layers[i].weights.buffer, sizeof(MatrixType),
nn.layers[i].weights.rows * nn.layers[i].weights.cols, file);
// Biasvektor schreiben
fwrite(nn.layers[i].biases.buffer, sizeof(MatrixType),
nn.layers[i].biases.rows * nn.layers[i].biases.cols, file);
}
// Markierung für das Datei-Ende (keine weiteren Layer)
unsigned int zero = 0;
fwrite(&zero, sizeof(unsigned int), 1, file);
fclose(file);
}
// --------------------------
// Test: Prüft, ob loadModel richtige Anzahl Layer lädt
// --------------------------
void test_loadModelReturnsCorrectNumberOfLayers(void)
{
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
prepareNeuralNetworkFile(path, nn);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(1, loaded.numberOfLayers);
clearModel(&loaded);
remove(path);
}
// --------------------------
// Test: Prüft Dimensionen der Gewichte
// --------------------------
void test_loadModelReturnsCorrectWeightDimensions(void)
{
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
prepareNeuralNetworkFile(path, nn);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(3, loaded.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(2, loaded.layers[0].weights.cols);
clearModel(&loaded);
remove(path);
}
// --------------------------
// Test: Prüft Dimensionen der Biases
// --------------------------
void test_loadModelReturnsCorrectBiasDimensions(void)
{
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
prepareNeuralNetworkFile(path, nn);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(3, loaded.layers[0].biases.rows);
TEST_ASSERT_EQUAL_INT(1, loaded.layers[0].biases.cols);
clearModel(&loaded);
remove(path);
}
// --------------------------
// Test: Prüft, dass Gewichte korrekt geladen werden
// --------------------------
void test_loadModelReturnsCorrectWeights(void)
{
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
prepareNeuralNetworkFile(path, nn);
NeuralNetwork loaded = loadModel(path);
int n = loaded.layers[0].weights.rows * loaded.layers[0].weights.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(wBuf, loaded.layers[0].weights.buffer, n);
clearModel(&loaded);
remove(path);
}
// --------------------------
// Test: Prüft, dass Bias korrekt geladen werden
// --------------------------
void test_loadModelReturnsCorrectBiases(void)
{
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
prepareNeuralNetworkFile(path, nn);
NeuralNetwork loaded = loadModel(path);
int n = loaded.layers[0].biases.rows * loaded.layers[0].biases.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(bBuf, loaded.layers[0].biases.buffer, n);
clearModel(&loaded);
remove(path);
}
// --------------------------
// Test: predict Funktion
// --------------------------
void test_predictReturnsCorrectLabels(void)
{
GrayScalePixelType img1[] = {10,20,30,40};
GrayScalePixelType img2[] = {5,15,25,35};
GrayScaleImage images[] = {
{.buffer=img1, .width=2, .height=2},
{.buffer=img2, .width=2, .height=2}
};
// Dummy Network für test: ReLU-ähnlich
MatrixType w1[] = {1,0,0,1,1,0,0,1};
MatrixType b1[] = {0,0};
Layer layers[] = {{.weights={w1,2,4}, .biases={b1,2,1}, .activation=NULL}};
NeuralNetwork nn = {layers,1};
unsigned char *labels = predict(nn, images, 2);
TEST_ASSERT_NOT_NULL(labels);
free(labels);
}
// --------------------------
// Test: clearModel setzt Pointer auf NULL
// --------------------------
void test_clearModelSetsMembersToNull(void)
{
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
clearModel(&nn);
TEST_ASSERT_NULL(nn.layers);
TEST_ASSERT_EQUAL_INT(0, nn.numberOfLayers);
}
// --------------------------
// Test: Fehlerhafte Datei (Header falsch)
// --------------------------
void test_loadModelFailsOnWrongFileTag(void)
{
const char *path = "wrong_nn_file.info2";
FILE *file = fopen(path, "wb");
if(file != NULL)
{
const char *wrongTag = "wrong_header_string";
fwrite(wrongTag, sizeof(char), strlen(wrongTag), file);
fclose(file);
}
NeuralNetwork nn = loadModel(path);
TEST_ASSERT_NULL(nn.layers);
TEST_ASSERT_EQUAL_INT(0, nn.numberOfLayers);
remove(path);
}
// --------------------------
// Unity Setup / Teardown
// --------------------------
void setUp(void) {}
void tearDown(void) {}
// --------------------------
// Hauptfunktion zum Ausführen der Tests
// --------------------------
int main(void)
{
UNITY_BEGIN();
printf("\n============================\nNeural network tests\n============================\n");
RUN_TEST(test_loadModelReturnsCorrectNumberOfLayers);
RUN_TEST(test_loadModelReturnsCorrectWeightDimensions);
RUN_TEST(test_loadModelReturnsCorrectBiasDimensions);
RUN_TEST(test_loadModelReturnsCorrectWeights);
RUN_TEST(test_loadModelReturnsCorrectBiases);
RUN_TEST(test_predictReturnsCorrectLabels);
RUN_TEST(test_clearModelSetsMembersToNull);
RUN_TEST(test_loadModelFailsOnWrongFileTag);
return UNITY_END();
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.