diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..cb8d469 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/ProgramData/mingw64/mingw64/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7583c69 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "c:/Users/Max-R/I2Pr/repoKachelto/I2-Pr_neuronalesNetz/info2Praktikum-NeuronalesNetz", + "program": "c:/Users/Max-R/I2Pr/repoKachelto/I2-Pr_neuronalesNetz/info2Praktikum-NeuronalesNetz/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bb879da --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false +} \ No newline at end of file diff --git a/NeuronalesNetz_Aufgabenstellung.pdf b/NeuronalesNetz_Aufgabenstellung.pdf index dcb354a..b4c6ce5 100644 Binary files a/NeuronalesNetz_Aufgabenstellung.pdf and b/NeuronalesNetz_Aufgabenstellung.pdf differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..135c0cb --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Projekt 2 für Informatik 2 Praktikum + \ No newline at end of file diff --git a/imageInput.c b/imageInput.c index bb30de1..d31a7da 100644 --- a/imageInput.c +++ b/imageInput.c @@ -7,16 +7,23 @@ #define FILE_HEADER_STRING "__info2_image_file_format__" // TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei +GrayScaleImage readImage() +{ + +} // TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen GrayScaleImageSeries *readImages(const char *path) { GrayScaleImageSeries *series = NULL; - + FILE *file = fopen("mnist_test.info2","rb"); + char headOfFile; + series = malloc(); return series; } // TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt void clearSeries(GrayScaleImageSeries *series) { + } \ No newline at end of file diff --git a/imageInputTests.c b/imageInputTests.c index c704271..03240ab 100644 --- a/imageInputTests.c +++ b/imageInputTests.c @@ -54,7 +54,7 @@ void test_readImagesReturnsCorrectImageWidth(void) GrayScaleImageSeries *series = NULL; const unsigned short expectedWidth = 10; const char *path = "testFile.info2"; - prepareImageFile(path, 8, expectedWidth, 2, 1); + prepareImageFile(path, expectedWidth, 8, 2, 1); series = readImages(path); TEST_ASSERT_NOT_NULL(series); TEST_ASSERT_NOT_NULL(series->images); @@ -70,7 +70,7 @@ void test_readImagesReturnsCorrectImageHeight(void) GrayScaleImageSeries *series = NULL; const unsigned short expectedHeight = 10; const char *path = "testFile.info2"; - prepareImageFile(path, expectedHeight, 8, 2, 1); + prepareImageFile(path, 8, expectedHeight, 2, 1); series = readImages(path); TEST_ASSERT_NOT_NULL(series); TEST_ASSERT_NOT_NULL(series->images); diff --git a/makefile b/makefile index f27b756..444bd21 100644 --- a/makefile +++ b/makefile @@ -63,4 +63,4 @@ ifeq ($(OS),Windows_NT) else rm -f *.o mnist runMatrixTests runNeuralNetworkTests runImageInputTests endif - + \ No newline at end of file diff --git a/matrix.c b/matrix.c index ad00628..2a4eb7b 100644 --- a/matrix.c +++ b/matrix.c @@ -1,35 +1,191 @@ +#include "matrix.h" #include #include -#include "matrix.h" - // TODO Matrix-Funktionen implementieren - -Matrix createMatrix(unsigned int rows, unsigned int cols) -{ - +/*typedef struct { + unsigned int rows; //Zeilen + unsigned int cols; //Spalten + MatrixType *buffer; //Zeiger auf Speicherbereich Reihen*Spalten +} Matrix;*/ +Matrix createMatrix(unsigned int rows, unsigned int cols) { + if (cols == 0 || rows == 0){ + Matrix errorMatrix = {0, 0, NULL}; + return errorMatrix; + } + MatrixType *buffer = + malloc(rows * cols * sizeof(MatrixType)); // Speicher reservieren, malloc + // liefert Zeiger auf Speicher + Matrix newMatrix = {rows, cols, buffer}; // neue Matrix nach struct + return newMatrix; } - -void clearMatrix(Matrix *matrix) -{ - +void clearMatrix(Matrix *matrix) { + matrix->buffer = UNDEFINED_MATRIX_VALUE; + matrix->rows = UNDEFINED_MATRIX_VALUE; + matrix->cols = UNDEFINED_MATRIX_VALUE; + free((*matrix).buffer); // Speicher freigeben } +void setMatrixAt(const MatrixType value, Matrix matrix, + const unsigned int rowIdx, // Kopie der Matrix wird übergeben + const unsigned int colIdx) { -void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx) -{ - + if (rowIdx >= matrix.rows || colIdx >= matrix.cols) { + // Speichergröße nicht überschreiten + return; + } + matrix.buffer[rowIdx * matrix.cols + colIdx] = value; + // rowIdx * matrix.cols -> Beginn der Zeile colIdx ->Spalte + // innerhalb der Zeile } +MatrixType getMatrixAt(const Matrix matrix, + unsigned int rowIdx, // Kopie der Matrix wird übergeben + unsigned int colIdx) { + if (rowIdx >= matrix.rows || + colIdx >= matrix.cols) { // Speichergröße nicht überschreiten + return 0; + } -MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx) -{ - + MatrixType value = matrix.buffer[rowIdx * matrix.cols + colIdx]; + + return value; } - -Matrix add(const Matrix matrix1, const Matrix matrix2) -{ - +Matrix broadcastingCols(const Matrix matrix, const unsigned int cols){ + Matrix copy1 = createMatrix(matrix.rows, cols); + for (int r= 0; r < matrix.rows; r++){ + MatrixType valueMatrix1 = getMatrixAt(matrix, r, 0); + for (int c=0; c < cols; c++){ + setMatrixAt(valueMatrix1, copy1,r,c); + } + } + return copy1; } +Matrix broadcastingRows(const Matrix matrix, const unsigned int rows){ + Matrix copy1 = createMatrix(rows, matrix.cols); + for (int c= 0; c < matrix.cols; c++){ + MatrixType valueMatrix1 = getMatrixAt(matrix, 0, c); + for (int r=0; r < rows; r++){ + setMatrixAt(valueMatrix1, copy1,r,c); + } + } + return copy1; -Matrix multiply(const Matrix matrix1, const Matrix matrix2) -{ - -} \ No newline at end of file +} +Matrix add(const Matrix matrix1, const Matrix matrix2) { + + // Ergebnismatrix + Matrix result; + const int cols1 = matrix1.cols; + const int rows1 = matrix1.rows; + const int cols2 = matrix2.cols; + const int rows2 = matrix2.rows; + + + const int rowsEqual = (matrix1.rows==matrix2.rows) ? 1: 0; + const int colsEqual = (matrix1.cols==matrix2.cols) ? 1: 0; + + // Broadcasting nur bei Vektor und Matrix, Fehlermeldung bei zwei unpassender + // Matrix + if (rowsEqual == 1 && colsEqual == 1){ + Matrix result = createMatrix(matrix1.rows, matrix1.cols); + for (int i = 0; i< rows1; i++) { + for (int j= 0; j< cols1; j++){ + int valueM1= getMatrixAt(matrix1, i, j); + int valueM2= getMatrixAt(matrix2, i, j); + int sum = valueM1 + valueM2; + setMatrixAt(sum, result, i, j); + } + } + return result; + } + else if (rowsEqual ==1 && (cols1 ==1 || cols2 ==1)){ + if (cols1==1){ //broadcasting von vektor 1 zu matrix 1, add + Matrix newMatrix = broadcastingCols(matrix1, cols2); + //add + Matrix result = createMatrix(newMatrix.rows, newMatrix.cols); + for (int i = 0; i< rows1; i++) { + for (int j= 0; j< cols2; j++){ + int valueM1= getMatrixAt(newMatrix, i, j); + int valueM2= getMatrixAt(matrix2, i, j); + int sum = valueM1 + valueM2; + setMatrixAt(sum, result, i, j); + } + } + return result; + } + else{ + Matrix newMatrix2 = broadcastingCols(matrix2, cols1); + //add + Matrix result = createMatrix(newMatrix2.rows, newMatrix2.cols); + for (int i = 0; i< rows1; i++) { + for (int j= 0; j< cols1; j++){ + int valueM1= getMatrixAt(matrix1, i, j); + int valueM2= getMatrixAt(newMatrix2, i, j); + int sum = valueM1 + valueM2; + setMatrixAt(sum, result, i, j); + } + } + return result; + } + } + + else if ((rows1 ==1 || rows2 ==1) && colsEqual == 1){ + if (rows1==1){ + Matrix newMatrix = broadcastingRows(matrix1, rows2); + //add + Matrix result = createMatrix(newMatrix.rows, newMatrix.cols); + for (int i = 0; i< rows2; i++) { + for (int j= 0; j< cols1; j++){ + int valueM1= getMatrixAt(newMatrix, i, j); + int valueM2= getMatrixAt(matrix2, i, j); + int sum = valueM1 + valueM2; + setMatrixAt(sum, result, i, j); + } + } + return result; + } + else{ + Matrix newMatrix2 = broadcastingRows(matrix2, rows1); + //add + Matrix result = createMatrix(newMatrix2.rows, newMatrix2.cols); + for (int i = 0; i< rows1; i++) { + for (int j= 0; j< cols1; j++){ + int valueM1= getMatrixAt(matrix1, i, j); + int valueM2= getMatrixAt(newMatrix2, i, j); + int sum = valueM1 + valueM2; + setMatrixAt(sum, result, i, j); + } + } + return result; + } + } + else { + // kein add möglich + Matrix errorMatrix = {0, 0, NULL}; + return errorMatrix; + } + return result; +} +Matrix multiply(const Matrix matrix1, const Matrix matrix2) { + //Spalten1 müssen gleich zeilen2 sein! dann multiplizieren + if (matrix1.cols == matrix2.rows){ + Matrix multMatrix = createMatrix(matrix1.rows,matrix2.cols); + //durch neue matrix iterieren + for (int r=0; r< matrix1.rows; r++){ + for (int c=0; c< matrix2.cols; c++){ + MatrixType sum = 0.0; + //skalarprodukte berechnen, k damit die ganze zeile mal die ganze spalte genommen wird quasi + for (int k=0; k< matrix1.cols; k++){ + //sum+= matrix1.buffer[r*matrix1.cols+k]*matrix2.buffer[k*matrix2.cols+c]; + sum += getMatrixAt(matrix1, r, k)*getMatrixAt(matrix2, k, c); + } + //Ergebnisse in neue matrix speichern + setMatrixAt(sum, multMatrix, r, c); + } + } + return multMatrix; + } + //sonst fehler, kein multiply möglich + else{ + Matrix errorMatrix = {0, 0, NULL}; + return errorMatrix; + } +} diff --git a/matrix.h b/matrix.h index cc640d1..ca871ae 100644 --- a/matrix.h +++ b/matrix.h @@ -6,14 +6,20 @@ typedef float MatrixType; // TODO Matrixtyp definieren +typedef struct { + unsigned int rows; + unsigned int cols; + MatrixType *buffer; +} Matrix; 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); +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); - #endif diff --git a/matrixTests.c b/matrixTests.c index 686db1e..6d56e7a 100644 --- a/matrixTests.c +++ b/matrixTests.c @@ -71,6 +71,32 @@ 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}; @@ -138,7 +164,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, matrixToTest.cols * matrixToTest.rows); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, sizeof(buffer)/sizeof(MatrixType)); } void setUp(void) { @@ -159,6 +185,7 @@ 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); diff --git a/neuralN_readFiles b/neuralN_readFiles new file mode 100644 index 0000000..4e29b1f --- /dev/null +++ b/neuralN_readFiles @@ -0,0 +1,29 @@ +Inhalte: Dynamische Speicherverwaltung, Strukturen, Dateien lesen. + +Ziel: Die Bilder aus mnist_test.info 2 auslesen + +Struktur für einlesen des Strings am Anfang der Datei: + int AnzahlBilder + int breiteBilder + int LaengeBilder + +Struktur für Bilder: + unsinged int array Breite * Höhe + unsigned int Klasse (Label 0 - 9) + + +Speicher für Bilder dynamisch allokieren + +GrayScaleImageSeries: + datei einlesen + header String aus der Datei lesen + mit header String den benötigten Speicher freigeben + in den Speicher die Datei einschreiben (mit Hilfsfunktion) + +Hilfsfunktion (saveFile) + gehe zum Anfang des Strings + speicher alles der Reihe nach ein + +clearSeries: + pointer der be malloc kommt nehemen + free()