MMS-Loesung-2024-25/MMS24-25.c

499 lines
15 KiB
C

/* =========================STYLE-GUIDELINES===========================
* All comments use MD-Syntax;
* Formulas are written in KaTeX/TeX Syntax.
* We adhere by the `kernel.org` style-guidelines.
* See: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
* =============================AUTHORS================================
* Created by Frederik Beimgraben, Minh Dan Cam and Lea Hornberger in
* the winter term of 2024/25 at the faculty of computer science at
* Reutlingen University.
* After grading the full source code will be available at:
* https://git.beimgraben.net/MMS-2024-25/MMS-Loesung-2024-25.git
*/
#include "MMS24-25.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
#include "MMS24-25.h"
#include <stdio.h>
#include <stdarg.h>
// #region Error Handling and Debugging
void _error(char *fmt, ...) {
fprintf(stderr, "<\x1B[31;1m ERROR \x1B[0m: \x1B[34m'");
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "'\x1B[0m >\n");
#ifndef _TESTS_NONSTOP
exit(EXIT_FAILURE);
#endif
}
void _debug(char *fmt, ...) {
fprintf(stderr, "[\x1B[31;1m DEBUG \x1B[0m] \x1B[34m'");
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "'\x1B[0m\n");
}
void _warn(char *fmt, ...) {
fprintf(stderr, "[\x1B[33;1m WARN \x1B[0m] \x1B[34m'");
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "'\x1B[0m\n");
}
// #endregion
// #region Aufgabe 1
double interpolateLine(
double dX1,
double dY1,
double dX2,
double dY2,
double dXq
) {
if (dX2 == dX1)
_error("interpolateLine: dX1 and dX2 must differ!");
double y = dY1 *(
(dX2 - dXq) / (dX2 - dX1)
) + dY2 *(
(dXq - dX1) / (dX2 - dX1)
);
#ifdef _DEBUG_
// DEBUG: print the parameters and result
_debug("interpolateLine(%lf, %lf, %lf, %lf, %lf) -> %lf\n",
dX1,dY1,dX2,dY2,dXq,y);
#endif
return y;
}
void rescaleDoubleArray(
double *pdIn,
int iLen,
double dMin,
double dFactor,
double *pdOut
) {
/* Rescale an array of double values, so that the following rules apply:
* Given $ |pdIn| = |pdOut| = iLen $ it should be, that:
* $ min(pdIn) > dMin $, as well as
* \[ \forall i, j \in (0,\dots,iLen-1):
* (pdOut_i - pdOut_j) = (pdIn_i - pdIn_j) *dFactor \],
* which naturally results from:
* $ pdOut_i = pdIn_i *dFactor + dMin $
*/
for (int i = 0; i < iLen; i++) {
pdOut[i] = pdIn[i] *dFactor + dMin;
}
}
double *generateSineValues(
int iNumValues,
int iNumSamplesPerPeriod,
double dAmp
) {
/* Generate an array of `iNumValues` double value, so that the values
* represent the Y-coordinates of a sine curve of which one full period
* occupies `iNumSamplesPerPeriod` values.
*/
if (iNumSamplesPerPeriod == 0)
_error("*generateSineValues: iNumSamplesPerPeriod must be non-0!");
if (iNumSamplesPerPeriod < 0)
_warn("*generateSineValues: iNumSamplesPerPeriod is less than 0!");
if (iNumValues < 0)
_error("*generateSineValues: iNumValues must be equal to or greater than 0!");
if (iNumValues == 0)
_warn("*generateSineValues: iNumValues is 0!");
// Initialize the output array
double *sineArray = NULL;
sineArray = (double*) malloc(sizeof(double) *iNumValues);
if (sineArray == NULL)
_error("*generateSineValues: Failed to allocate memory for Sine Array\n");
for (int i=0; i<iNumValues;i++){
sineArray[i] = dAmp*sin(((2*M_PI)/iNumSamplesPerPeriod) *i);
}
return sineArray;
}
void writeDoubleArray(double *pdOut, int iLen, char *pcOutName) {
// Write a list of double values to a file
FILE *file = fopen(pcOutName, "w");
if (file == NULL)
_error("writeDoubleArray: Error while opening file '%s'.\n", pcOutName);
for (int i = 0; i < iLen; i++) {
fprintf(file, "%f\n", pdOut[i]);
}
fclose(file);
}
int readDoubleArray(char *pcInName, double **ppdIn) {
char *line = NULL;
size_t len = 0;
ssize_t read;
int i = 0;
*ppdIn = NULL;
FILE *file = fopen(pcInName, "r");
if (file == NULL)
_error("readDoubleArray: Error while opening file '%s'.\n", pcInName);
while ((read = getline(&line, &len, file)) != -1) {
if (*ppdIn == NULL) {
*ppdIn = (double*) malloc(sizeof(double));
} else {
*ppdIn = (double*) realloc(*ppdIn, sizeof(double) *(i+1));
}
if (*ppdIn == NULL)
_error("readDoubleArray: Failed to allocate or re-allocate memory for pdIn\n");
(*ppdIn)[i] = atof(line);
i++;
}
free(line);
fclose(file);
return i;
}
MMSignal *createSignal() {
MMSignal *signal = NULL;
signal = (MMSignal*) malloc(sizeof(MMSignal));
if (signal == NULL)
_error("createSignal: Failed to allocate memory for signal\n");
signal->pdValues = NULL;
signal->iNumValues = 0;
signal->dArea = 0;
signal->dMean = 0;
signal->dStdDev = 0;
signal->dMedian = 0;
signal->pexExtrema = NULL;
return signal;
}
MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
MMSignal *signal = createSignal();
// Initialize and copy the values (deep copy)
signal->pdValues = (double*) malloc(sizeof(double) *pmmsIn->iNumValues);
if (signal->pdValues == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < pmmsIn->iNumValues; i++) {
signal->pdValues[i] = pmmsIn->pdValues[i];
}
// Copy shallow items
signal->iNumValues = pmmsIn->iNumValues;
signal->dArea = pmmsIn->dArea;
signal->dMean = pmmsIn->dMean;
signal->dStdDev = pmmsIn->dStdDev;
signal->dMedian = pmmsIn->dMedian;
// Deep copy of Extrema
signal->pexExtrema = (Extrema*) malloc(sizeof(Extrema));
if (signal->pexExtrema == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema\n");
signal->pexExtrema->iGlobalMinPos = pmmsIn->pexExtrema->iGlobalMinPos;
signal->pexExtrema->iGlobalMaxPos = pmmsIn->pexExtrema->iGlobalMaxPos;
signal->pexExtrema->pexLocalMax = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (signal->pexExtrema->pexLocalMax == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMax\n");
signal->pexExtrema->pexLocalMax->iNumLocalExtrema = pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema;
signal->pexExtrema->pexLocalMax->piLocalExtremaPos = (int*) malloc(sizeof(int) *pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema);
if (signal->pexExtrema->pexLocalMax->piLocalExtremaPos == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMax->piLocalExtremaPos\n");
for (int i = 0; i < pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema; i++) {
signal->pexExtrema->pexLocalMax->piLocalExtremaPos[i] = pmmsIn->pexExtrema->pexLocalMax->piLocalExtremaPos[i];
}
signal->pexExtrema->pexLocalMin = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (signal->pexExtrema->pexLocalMin == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMin\n");
signal->pexExtrema->pexLocalMin->iNumLocalExtrema = pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema;
signal->pexExtrema->pexLocalMin->piLocalExtremaPos = (int*) malloc(sizeof(int) *pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema);
if (signal->pexExtrema->pexLocalMin->piLocalExtremaPos == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMin->piLocalExtremaPos\n");
for (int i = 0; i < pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema; i++) {
signal->pexExtrema->pexLocalMin->piLocalExtremaPos[i] = pmmsIn->pexExtrema->pexLocalMin->piLocalExtremaPos[i];
}
return signal;
}
MMSignal *createSignalWithDefault(int iArrayLen, double dDefaultValue) {
MMSignal *signal = createSignal();
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
if (signal->pdValues == NULL)
_error("createSignalWithDefault: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < iArrayLen; i++) {
signal->pdValues[i] = dDefaultValue;
}
signal->iNumValues = iArrayLen;
return signal;
}
MMSignal *createSignalFromDoubleArray(int iArrayLen, double *pdIn) {
MMSignal *signal = createSignal();
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
if (signal->pdValues == NULL)
_error("createSignalFromDoubleArray: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < iArrayLen; i++) {
signal->pdValues[i] = pdIn[i];
}
signal->iNumValues = iArrayLen;
return signal;
}
MMSignal *createSignalFromFile(char *pcInName) {
double *pdIn = NULL;
int iArrayLen = readDoubleArray(pcInName, &pdIn);
MMSignal *signal = createSignal();
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
if (signal->pdValues == NULL)
_error("createSignalFromFile: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < iArrayLen; i++) {
signal->pdValues[i] = pdIn[i];
}
signal->iNumValues = iArrayLen;
return signal;
}
void writeMMSignal(char *pcInName, MMSignal *pmmsIn) {
writeDoubleArray(
pmmsIn->pdValues,
pmmsIn->iNumValues,
pcInName
);
}
void deleteSignal(MMSignal *pmmsIn) {
free(pmmsIn->pdValues);
free(pmmsIn->pexExtrema->pexLocalMax->piLocalExtremaPos);
free(pmmsIn->pexExtrema->pexLocalMax);
free(pmmsIn->pexExtrema->pexLocalMin->piLocalExtremaPos);
free(pmmsIn->pexExtrema->pexLocalMin);
free(pmmsIn->pexExtrema);
free(pmmsIn);
}
// #endregion
// #region Aufgabe 2
double calculateArea(double *pdIn, int iLen) {
double area = 0;
// #FIXME: Which one should we use according to the task?
for (int i = 0; i < iLen-1; i++) {
area += (pdIn[i] + pdIn[i+1]) / 2;
}
return area;
}
double calculateMean(double *pdIn, int iLen) {
double mean = 0;
for (int i = 0; i < iLen; i++) {
mean += pdIn[i];
}
return mean / iLen;
}
double calculateStddev(double *pdIn, int iLen) {
double mean = calculateMean(pdIn, iLen);
double stdDev = 0;
for (int i = 0; i < iLen; i++) {
stdDev += pow(pdIn[i] - mean, 2);
}
return sqrt(stdDev / iLen);
}
Extrema *initExtrema(double *pdIn, int iLen) {
Extrema *extrema = (Extrema*) malloc(sizeof(Extrema));
if (extrema == NULL)
_error("initExtrema: Failed to allocate memory for extrema\n");
extrema->pexLocalMax = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (extrema->pexLocalMax == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMax\n");
extrema->pexLocalMin = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (extrema->pexLocalMin == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMin\n");
extrema->pexLocalMax->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
if (extrema->pexLocalMax->piLocalExtremaPos == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMax->piLocalExtremaPos\n");
extrema->pexLocalMin->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
if (extrema->pexLocalMin->piLocalExtremaPos == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMin->piLocalExtremaPos\n");
extrema->iGlobalMaxPos = 0;
extrema->iGlobalMinPos = 0;
return extrema;
}
void deleteExtrema(Extrema *pexIn) {
free(pexIn->pexLocalMax->piLocalExtremaPos);
free(pexIn->pexLocalMax);
free(pexIn->pexLocalMin->piLocalExtremaPos);
free(pexIn->pexLocalMin);
free(pexIn);
}
void initMMSignalFeatures(MMSignal *pmmsIn) {
pmmsIn->dArea = calculateArea(pmmsIn->pdValues, pmmsIn->iNumValues);
pmmsIn->dMean = calculateMean(pmmsIn->pdValues, pmmsIn->iNumValues);
pmmsIn->dStdDev = calculateStddev(pmmsIn->pdValues, pmmsIn->iNumValues);
pmmsIn->dMedian = calculateMedian(pmmsIn->pdValues, pmmsIn->iNumValues);
pmmsIn->pexExtrema = initExtrema(pmmsIn->pdValues, pmmsIn->iNumValues);
}
Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) {
Histogram *histogram = (Histogram*) malloc(sizeof(Histogram));
if (histogram == NULL)
_error("initHistogram: Failed to allocate memory for histogram\n");
histogram->dIntervalMin = pdIn[0];
histogram->dIntervalMax = pdIn[0];
for (int i = 0; i < iLen; i++) {
if (pdIn[i] < histogram->dIntervalMin)
histogram->dIntervalMin = pdIn[i];
if (pdIn[i] > histogram->dIntervalMax)
histogram->dIntervalMax = pdIn[i];
}
histogram->dBinWidth = (histogram->dIntervalMax - histogram->dIntervalMin) / iNumBins;
histogram->iNumBins = iNumBins;
histogram->pdBinValues = (double*) malloc(sizeof(double) *iNumBins);
if (histogram->pdBinValues == NULL)
_error("initHistogram: Failed to allocate memory for histogram->pdBinValues\n");
for (int i = 0; i < iNumBins; i++) {
histogram->pdBinValues[i] = 0;
}
return histogram;
}
void deleteHistogram(Histogram *phIn) {
free(phIn->pdBinValues);
free(phIn);
}
// #FIXME: Check if this checks out
double calculateEntropy(Histogram *phisIn) {
double entropy = 0;
for (int i = 0; i < phisIn->iNumBins; i++) {
if (phisIn->pdBinValues[i] != 0) {
entropy += phisIn->pdBinValues[i] * log2(phisIn->pdBinValues[i]);
}
}
return -entropy;
}
// #endregion
// #region Aufgabe 3
MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) {
MMSignal *signal = createSignal();
if (pmmsInA->iNumValues != pmmsInB->iNumValues)
_error("convoluteSignals: Signals must have the same length\n");
signal->pdValues = (double*) malloc(sizeof(double) *pmmsInA->iNumValues);
if (signal->pdValues == NULL)
_error("convoluteSignals: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < pmmsInA->iNumValues; i++) {
signal->pdValues[i] = pmmsInA->pdValues[i] * pmmsInB->pdValues[i];
}
signal->iNumValues = pmmsInA->iNumValues;
return signal;
}
// #FIXME: Check if this checks out
MMSignal *getPascalLine(int iLinenum) {
MMSignal *signal = createSignal();
signal->pdValues = (double*) malloc(sizeof(double) *iLinenum);
if (signal->pdValues == NULL)
_error("getPascalLine: Failed to allocate memory for signal->pdValues\n");
signal->pdValues[0] = 1;
signal->pdValues[iLinenum-1] = 1;
for (int i = 1; i < iLinenum-1; i++) {
signal->pdValues[i] = signal->pdValues[i-1] *(iLinenum-i) / i;
}
signal->iNumValues = iLinenum;
return signal;
}
// #endregion