forked from freudenreichan/info2Praktikum-NeuronalesNetz
170 lines
5.9 KiB
C
170 lines
5.9 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "matrix.h"
|
|
|
|
// TODO Matrix-Funktionen implementieren
|
|
|
|
Matrix createMatrix(unsigned int rows, unsigned int cols) // eine Matrix mit ner bestimmten Anzahl an Zeilen und Spalten erstellen und benötigten Speicher reservieren
|
|
{
|
|
// leere Matrix erstellen:
|
|
Matrix matrix = {0, 0, NULL};
|
|
|
|
if (rows == 0 || cols == 0) // Matrizen mit null Zeilen oder Spalten sind nicht erlaubt
|
|
{
|
|
return matrix;
|
|
}
|
|
|
|
// Speicher für alle Matrixelemente reservieren:
|
|
matrix.buffer = (MatrixType *)calloc(rows * cols, sizeof(MatrixType));
|
|
|
|
// prüfen, ob die Speicherreservierung erfolgreich war:
|
|
if (matrix.buffer != NULL)
|
|
{
|
|
matrix.rows = rows;
|
|
matrix.cols = cols;
|
|
}
|
|
|
|
return matrix;
|
|
}
|
|
|
|
void clearMatrix(Matrix *matrix) // den dynamisch reservierten Speicher einer Matrix freigeben und die Matrix zurücksetzen
|
|
{
|
|
if (matrix != NULL) // prüfen, ob ein gültiger Zeiger übergeben wurde
|
|
{
|
|
free(matrix->buffer); // reservierten Speicher freigeben
|
|
|
|
// Matrix auf Ausgangszustand zurücksetzen:(kann sonst zu Speicherlecks (Memory Leaks) führen, da dynamische Speicher weiterhin belegt bleibt)
|
|
matrix->buffer = NULL;
|
|
matrix->rows = 0;
|
|
matrix->cols = 0;
|
|
}
|
|
}
|
|
|
|
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx) // einen bestimmten Wert an einer bestimmten Position der Matrix speichern
|
|
{
|
|
// prüfen, ob die Matrix gültig ist und die Indizes innerhalb der Matrixgrenzen liegen:
|
|
if (matrix.buffer == NULL || rowIdx >= matrix.rows || colIdx >= matrix.cols)
|
|
{
|
|
return;
|
|
}
|
|
|
|
unsigned int index = rowIdx * matrix.cols + colIdx; // Position im eindimensionalen Speicher berechnen
|
|
|
|
matrix.buffer[index] = value; // Wert an der gewünschten Position speichern
|
|
}
|
|
|
|
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx) // einen Wert an einer bestimmten Position auslesen
|
|
{
|
|
// prüfen, ob die Matrix gültig ist und die Indizes innerhalb der Matrixgrenzen liegen:
|
|
if (matrix.buffer == NULL || rowIdx >= matrix.rows || colIdx >= matrix.cols)
|
|
{
|
|
return UNDEFINED_MATRIX_VALUE; // in matrix.h def.
|
|
}
|
|
|
|
unsigned int index = rowIdx * matrix.cols + colIdx; // eindimensionalen Index berechnen
|
|
|
|
return matrix.buffer[index]; // Wert an der gewünschten Position zurückgeben
|
|
}
|
|
|
|
Matrix add(const Matrix matrix1, const Matrix matrix2) // zwei Matrizen addieren
|
|
{
|
|
Matrix result = {0, 0, NULL}; // zunächst eine leere Ergebnismatrix erstellen
|
|
|
|
// ungültige Eingabematrizen überprüfen:
|
|
if (matrix1.buffer == NULL || matrix2.buffer == NULL || matrix1.rows == 0 || matrix1.cols == 0 || matrix2.rows == 0 || matrix2.cols == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// Fall 1: Beide Matrizen haben dieselben Dimensionen:
|
|
if (matrix1.rows == matrix2.rows &&
|
|
matrix1.cols == matrix2.cols)
|
|
{
|
|
result = createMatrix(matrix1.rows, matrix1.cols);
|
|
|
|
if (result.buffer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < matrix1.rows * matrix1.cols; i++) // alle Elemente paarweise addieren
|
|
{
|
|
result.buffer[i] = matrix1.buffer[i] + matrix2.buffer[i];
|
|
}
|
|
}
|
|
|
|
// Fall 2: Broadcasting mit einem Spaltenvektor:
|
|
else if (matrix1.rows == matrix2.rows && (matrix1.cols == 1 || matrix2.cols == 1))
|
|
{
|
|
// die Matrix mit mehr Spalten bestimmt die Ergebnisgröße:
|
|
const Matrix *matrix = &matrix1;
|
|
const Matrix *vector = &matrix2;
|
|
|
|
if (matrix1.cols == 1) // falls matrix1 der Spaltenvektor ist, werden die Rollen der beiden Eingabematrizen vertauscht (Broadcasting soll in beiden Reihenfolgen funktionieren)
|
|
{
|
|
matrix = &matrix2;
|
|
vector = &matrix1;
|
|
}
|
|
|
|
result = createMatrix(matrix->rows, matrix->cols);
|
|
|
|
if (result.buffer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
for (unsigned int row = 0; row < matrix->rows; row++) // jeden Matrixwert mit dem Vektorwert seiner Zeile addieren
|
|
{
|
|
for (unsigned int col = 0; col < matrix->cols; col++)
|
|
{
|
|
result.buffer[row * matrix->cols + col] =
|
|
matrix->buffer[row * matrix->cols + col]
|
|
+ vector->buffer[row];
|
|
}
|
|
}
|
|
}
|
|
|
|
return result; // wenn keine der beiden Varianten möglich ist, bleibt Ergebnismatrix leer
|
|
}
|
|
|
|
Matrix multiply(const Matrix matrix1, const Matrix matrix2) // zwei Matrizen multiplizieren
|
|
{
|
|
Matrix result = {0, 0, NULL}; // leere Ergebnismatrix
|
|
|
|
// prüfen, ob beide Eingabematrizen gültig sind:
|
|
if (matrix1.buffer == NULL || matrix2.buffer == NULL || matrix1.rows == 0 || matrix1.cols == 0 || matrix2.rows == 0 || matrix2.cols == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (matrix1.cols != matrix2.rows) // Spaltenanzahl der ersten Matrix muss der Zeilenanzahl der zweiten Matrix entsprechen
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result = createMatrix(matrix1.rows, matrix2.cols); // Ergebnis hat so viele Zeilen wie matrix1 und so viele Spalten wie matrix2
|
|
|
|
if (result.buffer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
for (unsigned int row = 0; row < matrix1.rows; row++) // Durchführung Matrixmultiplikation...
|
|
{
|
|
for (unsigned int col = 0; col < matrix2.cols; col++)
|
|
{
|
|
MatrixType sum = 0; // Summe für das aktuelle Ergebniselement
|
|
|
|
for (unsigned int k = 0; k < matrix1.cols; k++)
|
|
{
|
|
sum += matrix1.buffer[row * matrix1.cols + k] * matrix2.buffer[k * matrix2.cols + col];
|
|
// "row" durchläuft Zeilen d. ersten Matrix; "col" durchläuft Zeilen d. zweiten Matrix; "k" berechnet Summe d. Produkte
|
|
}
|
|
|
|
|
|
result.buffer[row * result.cols + col] = sum; // berechnetes Ergebnis speichern
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} |