generated from freudenreichan/info2Praktikum-NeuronalesNetz
- matrix.c: multiply summiert in MatrixType statt int (Nachkommastellen gingen verloren), clearMatrix gibt Speicher frei, Indexpruefung pro Zeile/Spalte, NULL-Pruefungen in add/multiply - imageInput.c: fseek-Spruenge entfernt, Dateikopf pruefen, Lesefehler behandeln, clearSeries implementiert - neuralNetworkTests.c: prepareNeuralNetworkFile implementiert - neuralNetwork.c: clearModel gibt das Layer-Array frei (Speicherleck) - Zusaetzliche Unittests fuer Matrix und Bildeinlesen - Testartefakte und Testprogramme in .gitignore, testFile.info2 entfernt Alle 33 Tests gruen, keine Warnungen, 87.37 % Genauigkeit (wie Referenz). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
169 lines
4.5 KiB
C
169 lines
4.5 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "matrix.h"
|
|
|
|
// TODO Matrix-Funktionen implementieren
|
|
|
|
Matrix createMatrix(unsigned int rows, unsigned int cols)
|
|
{
|
|
Matrix m;
|
|
|
|
if (rows == 0 || cols == 0)
|
|
//Ueberprüfen, ob ungültige Werte für Matrix vorhanden
|
|
{
|
|
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));
|
|
//Bei Fehlschalg gibt calloc entweder NULL oder Zeiger verschieden von NULL aus
|
|
|
|
if (m.buffer == NULL)
|
|
//Kein Speicher: leere Matrix zurueckgeben, damit Groesse und Puffer zusammenpassen
|
|
{
|
|
m.rows = 0;
|
|
m.cols = 0;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
void clearMatrix(Matrix *matrix)
|
|
{
|
|
if (matrix != NULL)
|
|
{
|
|
free(matrix->buffer);
|
|
//Speicher leeren
|
|
matrix->buffer = NULL;
|
|
matrix->rows = 0;
|
|
matrix->cols = 0;
|
|
}
|
|
}
|
|
|
|
static int isValidIndex(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
|
|
{
|
|
//Zeile und Spalte einzeln pruefen: sonst wuerde z.B. (0, cols) faelschlich auf (1, 0) zugreifen
|
|
return matrix.buffer != NULL && rowIdx < matrix.rows && colIdx < matrix.cols;
|
|
}
|
|
|
|
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
|
|
{
|
|
if(isValidIndex(matrix, rowIdx, colIdx))
|
|
{
|
|
matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
|
|
}
|
|
}
|
|
|
|
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
|
|
{
|
|
MatrixType value = UNDEFINED_MATRIX_VALUE;
|
|
if(isValidIndex(matrix, rowIdx, colIdx))
|
|
{
|
|
value = matrix.buffer[rowIdx * matrix.cols + colIdx];
|
|
}
|
|
return value;
|
|
}
|
|
|
|
Matrix add(const Matrix matrix1, const Matrix matrix2)
|
|
{
|
|
typedef enum {elemt_add, broadcast} Addiermodi;
|
|
Addiermodi modus;
|
|
|
|
Matrix m = {NULL, 0, 0};
|
|
|
|
if(matrix1.buffer == NULL || matrix2.buffer == NULL)
|
|
{
|
|
return m;
|
|
}
|
|
|
|
//Elementweise zuerst pruefen: zwei Spaltenvektoren gleicher Groesse sind ein normaler elementweiser Fall
|
|
if((matrix1.rows == matrix2.rows) && (matrix1.cols == matrix2.cols))
|
|
{
|
|
modus = elemt_add;
|
|
}
|
|
else if((matrix1.cols == 1 || matrix2.cols ==1) && (matrix1.rows == matrix2.rows))
|
|
{
|
|
modus = broadcast;
|
|
}
|
|
else
|
|
{
|
|
return m;
|
|
}
|
|
|
|
if(modus == elemt_add)
|
|
{
|
|
m = createMatrix(matrix1.rows, matrix1.cols);
|
|
if(m.buffer == NULL)
|
|
{
|
|
return m;
|
|
}
|
|
|
|
for(unsigned int i = 0; i< matrix1.rows; i++)
|
|
{
|
|
for(unsigned int j = 0; j < matrix1.cols ; j++)
|
|
{
|
|
m.buffer[i*matrix1.cols+j] = matrix1.buffer[i*matrix1.cols+j] + matrix2.buffer[i*matrix1.cols+j];
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
else if(modus == broadcast)
|
|
{
|
|
|
|
if(matrix1.cols == 1)
|
|
{
|
|
m = createMatrix(matrix2.rows, matrix2.cols);
|
|
for(unsigned int i = 0; i< m.rows; i++)
|
|
{
|
|
for(unsigned int j = 0; j < m.cols ; j++)
|
|
{
|
|
m.buffer[i*matrix2.cols+j] = matrix2.buffer[i*matrix2.cols+j] + matrix1.buffer[i*matrix1.cols];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m = createMatrix(matrix1.rows, matrix1.cols);
|
|
for(unsigned int i = 0; i< m.rows; i++)
|
|
{
|
|
for(unsigned int j = 0; j < m.cols ; j++)
|
|
{
|
|
m.buffer[i*matrix1.cols+j] = matrix1.buffer[i*matrix1.cols+j] + matrix2.buffer[i*matrix2.cols];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
|
|
{
|
|
if(matrix1.buffer == NULL || matrix2.buffer == NULL || matrix1.cols != matrix2.rows)
|
|
{
|
|
Matrix failure = {NULL, 0, 0};
|
|
return failure;
|
|
}
|
|
|
|
Matrix m = createMatrix(matrix1.rows, matrix2.cols);
|
|
|
|
//Reihenfolge i-k-j statt i-j-k: matrix2 und m werden zeilenweise am Stueck durchlaufen.
|
|
//m startet dank calloc mit 0, daher wird direkt aufaddiert.
|
|
for(unsigned int i = 0; i < m.rows; i++)
|
|
{
|
|
for(unsigned int k = 0; k < matrix1.cols; k++)
|
|
{
|
|
MatrixType factor = matrix1.buffer[i*matrix1.cols+k];
|
|
//MatrixType statt int, hat die zahlen gerundet.
|
|
for(unsigned int j = 0; j < m.cols ; j++)
|
|
{
|
|
m.buffer[i*m.cols+j] += factor * matrix2.buffer[k*matrix2.cols+j];
|
|
}
|
|
}
|
|
}
|
|
return m;
|
|
}
|