This commit is contained in:
2025-04-09 10:22:44 +02:00
commit 96ff5392c8
330 changed files with 28300 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
---
BasedOnStyle: LLVM
---
Language: Cpp
DerivePointerAlignment: false
PointerAlignment: Left
ColumnLimit: 120
TabWidth: 4
IndentWidth: 2
...
+25
View File
@@ -0,0 +1,25 @@
# debug: clangd --check=modules/iue-io/ccsv.h
# debug: clangd --check=task1.hpp
# debug: clangd --check=task1.test.cpp
InlayHints:
Enabled: No
ParameterNames: Yes
DeducedTypes: No
---
CompileFlags:
Add:
# - --target=x86_64-w64-windows-gnu
# - --target=x86_64-pc-linux-gnu
- -Wall
- -Wno-unused-function
- -Wno-unused-variable
---
If:
PathMatch: [.*\.c, .*\.h]
CompileFlags:
Add: [-std=c11]
---
If:
PathMatch: [.*\.cpp, .*\.hpp]
CompileFlags:
Add: [-std=c++20]
+4
View File
@@ -0,0 +1,4 @@
task1
task2
task3_cpp
task3_py
+4
View File
@@ -0,0 +1,4 @@
task1.main.cpp
task2.cpp
task3.cpp
task3.py
+16
View File
@@ -0,0 +1,16 @@
## source: https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.h text
*.hpp text
*.c text
*.cpp text
*.py text
*.ipynb text
*.md text
*.txt text
*.csv text
+360
View File
@@ -0,0 +1,360 @@
# custom
*.csv
*.png
build
doc
.cache
.vscode
.idea
# https://github.com/github/gitignore/blob/main/CMake.gitignore
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
# ttps://github.com/github/gitignore/blob/main/C.gitignore
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# https://github.com/github/gitignore/blob/main/C%2B%2B.gitignore
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# source: https://github.com/github/gitignore/blob/main/Python.gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# jetbrain IDEs: https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# VSCODE source: https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
+4
View File
@@ -0,0 +1,4 @@
[submodule "modules"]
path = modules
url = https://sgit.iue.tuwien.ac.at/360050/modules
branch = main
+54
View File
@@ -0,0 +1,54 @@
cmake_minimum_required(VERSION 3.20)
# define project metadata
project(exercise3 LANGUAGES CXX
DESCRIPTION "exercise3"
HOMEPAGE_URL "https://sgit.iue.tuwien.ac.at/360050/exercise3")
# setting required language standards
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)
# misc settings
# avoid ctest dashboard targets
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
# generate a compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# make all symbols visible on windows (which is default on unix)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# options
option(BUILD_TESTING "enable testing with ctest" ON)
# testing
include(CTest)
# get/setup dependencies
include_directories(modules)
# include own targets
add_executable(task1 task1.main.cpp)
add_test(NAME task1 COMMAND task1 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
set_property(TEST task1 PROPERTY PASS_REGULAR_EXPRESSION "45")
add_executable(task2 task2.cpp task2.test.cpp)
add_test(NAME task2 COMMAND task2 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
add_executable(task3_cpp task2.cpp task3.cpp task3.test.cpp)
add_test(NAME task3_cpp COMMAND task3_cpp WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
find_package(Python3 COMPONENTS Interpreter REQUIRED)
add_test(NAME task3_py COMMAND ${Python3_EXECUTABLE} task3.test.py WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
set_tests_properties(task3_py PROPERTIES DEPENDS task3_cpp)
add_custom_target(task3)
add_dependencies(task3 task3_cpp)
+29
View File
@@ -0,0 +1,29 @@
# Hausübung 3 (3 Punkte)
**Ausgabe**: Donnerstag 21. März 2024, vormittags.
**Abgabe bis**: Montag 15. April 2024, Ende des Tages.
**Abgabe via**: git-Repository mit dem Namen **`exercise3`** auf unserem git-Server https://sgit.iue.tuwien.ac.at
Details zum Abgabeprozess via `git` finden Sie hier: https://sgit.iue.tuwien.ac.at/360050/git
# Aufgabenstellung
In dieser Hausübung werden folgende Themen erstmalig einfliessen:
- Vektoren von Vektoren, hier beschränkt auf folgende Typen:
```cpp
std::vector<std::vector<double>>
std::vector<std::vector<int>>
```
- Uebergabe von aufrufbaren Objekten, mittels `std::function` hier beschränkt auf folgenden Typ:
```cpp
std::function<double(double)>
```
- Numerische Integration und Differenzierung
- Einbinden und Nutzung einer [lokalen Bibilothek](https://sgit.iue.tuwien.ac.at/360050/modules/src/branch/main/iue-io/csv.hpp) zum Schreiben von `.csv`-Dateien sowie Plotten der geschrieben Daten mit Python/Matplotlib.
**Die genaue Beschreibung und Anforderungen finden Sie in [`main.ipynb`](main.ipynb) und im Quellcode.**
+1
View File
@@ -0,0 +1 @@
-Imodules
+248
View File
@@ -0,0 +1,248 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Aufgabe 1: Ein eigenes kleines C++-Programm (*vector of vectors*) (1 Punkt)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Erstellen Sie in [`task1.main.cpp`](task1.main.cpp) ein lauffähiges Ein-Dateien-Programm das folgende Struktur aufweist:\n",
"\n",
"- Einbinden benötigter Header-Dateien aus der Standardbibliothek, z.B.:\n",
"\t```cpp\n",
"\t#include <iostream> // std::cout, std::endl\n",
"\t#include <...>\n",
"\t```\n",
"- Definition/Implementierung einer eigenen Funktion, z.B.:\n",
"\t```cpp\n",
"\tint sum(...){\n",
"\t ...\n",
"\t}\n",
"\t``` \n",
"- Definition/Implementierung einer `main`-Funktion (Einstiegspunkt für jedes lauffähige Programm), die Ihre selbest geschriebene Funktion verwendet und die berechneten Ergebnisse in der Konsole ausgibt, z.B.:\n",
"\t```cpp\n",
"\tint main(){\n",
"\t ...\n",
"\t auto res = sum(...)\t\n",
"\t std::cout << res << std::endl;\n",
"\t return 0;\n",
"\t}\n",
"\t``` \n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"- Eine genaue Beschreibung und Anforderungen finden Sie in [`task1.main.cpp`](task1.main.cpp)\n",
"- Ihre Implementierung erfolgt ebenfalls in [`task1.main.cpp`](task1.main.cpp)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Aufgabe 2: Mathematische Funktionen abtasten, numerische Integration und Differenzierung (1 Punkt)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Sie implementieren Funktionen, die\n",
"\n",
"- ein Intervall $[a,b]$ mittels $N$ Stellen gleichabständig abstasten -> $\\mathbf{x} = \\left[ x_1, x_2, ... , x_N \\right]$,\n",
"- eine Funktion $f(x)$ für die diskreten Werte im Intervall evaluieren -> $\\mathbf{y} = \\left[ f(x_1), f(x_2), ... , f(x_N) \\right]$,\n",
"- anhand der diskreten Wertepaare ($\\mathbf{x}, \\mathbf{y}$) die Ableitung approximieren:\n",
"\t- Vorwärts-Differenz an der ersten Stelle: $f'(x_1) \\approx \\frac{y_2 - y_1}{x_2 - x_1}$,\n",
"\t- Rückwarts-Differenz an der letzten Stelle: $f'(x_N) \\approx \\frac{y_N - y_{N-1}}{x_N - x_{N-1}}$,\n",
"\t- Zentrale-Differenz für alle anderen Stellen $f'(x_i) \\approx \\frac{y_{i+1} - y_{i-1} }{x_{i+1} - x_{i-1}}$, und\n",
"- anhand der diskreten Wertepaare ($\\mathbf{x}, \\mathbf{y}$) die Stammfunktion approximieren:\n",
"\t- Integrationskonstante an der ersten Stelle: $F(x_1) = C$\n",
"\t- Trapezregel für alle anderen Stellen: $F(x_i) \\approx C + \\sum_{2}^{i} \\left[ 0.5 \\cdot \\left(y_{i}+y_{i-1}\\right) \\cdot \\left(x_i - x_{i-1}\\right) \\right]$."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Implementieren Sie die folgenden vier Funktionen:\n",
"\n",
"```cpp\n",
"using Vector = std::vector<double>;\n",
"using Callable = std::function<double(double)>;\n",
"\n",
"Vector range(double start, double end, unsigned int N);\n",
"Vector sample(Vector values, Callable func);\n",
"Vector numdiff(Vector x, Vector y);\n",
"Vector numint(Vector x, Vector y, double C);\n",
"```"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"- Die vorgegebenen Deklarationen und eine genaue Beschreibung und Anforderungen finden Sie in [`task2.hpp`](task2.hpp)\n",
"- Ihre Implementierung erfolgt in [`task2.cpp`](task2.cpp)\n",
"- Die zugeordneten Tests finden Sie in [`task2.test.cpp`](task2.test.cpp)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Aufgabe 3: Diskrete Funktionswerte abspeichern und plotten (1 Punkt)\n",
"\n",
"Sie implementieren eine Funktion in C++ die eine `.csv`-Datei mit diskreten Funktionswerten erzeugt:\n",
"- verwenden Sie Ihre in Aufgabe 2 entwickelten Funktionen zum Abtasten und numerisch Integrieren/Differenzieren\n",
"- verwenden Sie die bereitgestellte Funktion [`iue::io::savetxt`](https://sgit.iue.tuwien.ac.at/360050/modules/src/commit/7b31b845bf2d1297553a8565ba6ca2474305394a/iue-io/csv.hpp#L20) zum Schreiben der `.csv`-Datei\n",
"\n",
"Ebenso implementieren Sie eine Funktion in Python, um die Funktionswerten in der von Ihnen erzeugten `.csv`-Datei zu plotten:\n",
"- verwenden Sie [numpy.loadtxt](https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html) zum Lesen der `.csv`-Datei\n",
"- verwenden Sie [`Matplotlib`](https://matplotlib.org/stable/tutorials/pyplot.html) zum Plotten der eingelesenen Daten"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Implementieren Sie folgende Funktion (**C++**):\n",
"\n",
"```cpp\n",
"\n",
"using Filename = std::filesystem::path;\n",
"using Callable = std::function<double(double)>;\n",
"\n",
"void sample_to_csv(Filename filepath, \n",
" char del, \n",
" char comments, \n",
" Callable func, \n",
" double start, \n",
" double end, \n",
" unsigned int N);\n",
"```"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"- Die vorgegebenen Deklaration und eine genaue Beschreibung und Anforderungen finden Sie in [`task3.hpp`](task3.hpp)\n",
"- Ihre Implementierung erfolgt in [`task3.cpp`](task3.cpp)\n",
"- Die zugeordneten Tests finden Sie in [`task3.test.cpp`](task3.test.cpp)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Implementieren Sie zudem folgende Funktion (**Python**):\n",
"\n",
"```py\n",
"def plot_discrete_function(csvfile, delimiter, comments, pngfile):\n",
"\tpass # todo: implement\n",
"```"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"- Ihre Implementierung erfolgt in [`task3.py`](task3.py)\n",
"- Die zugeordneten Tests finden Sie in [`task3.test.py`](task3.test.py)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Die final erzeugten Plots könnten z.B. so aussehen:\n",
"\n",
"![images/task3_plot_sin.png](images/task3_plot_sin.png) \n",
"![images/test3_plot_cos.png](images/task3_plot_cos.png)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Kompilieren/Testen\n",
"\n",
"So testen Sie Ihre Implementierung (direkter Aufruf von `g++` und `python`):\n",
"\n",
"```shell\n",
"# prepare\n",
"mkdir build\n",
"# compile\n",
"g++ -g -std=c++20 task1.main.cpp -o build/task1.exe\n",
"g++ -g -std=c++20 task2.cpp task2.test.cpp -o build/task2.exe\n",
"g++ -g -Imodules -std=c++20 task2.cpp task3.cpp task3.test.cpp -o build/task3.exe\n",
"\n",
"# run tests\n",
"./build/task1.exe\n",
"./build/task2.exe\n",
"./build/task3.exe\n",
"python task3.test.py\n",
"```\n",
"\n",
"Alternativ (mittels CMake-Configuration):s\n",
"\n",
"```shell\n",
"# prepare\n",
"cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug\n",
"# compile\n",
"cmake --build build --config Debug --target task1\n",
"cmake --build build --config Debug --target task2\n",
"cmake --build build --config Debug --target task3\n",
"cmake --build build --config Debug # all\n",
"# run tests\n",
"ctest --test-dir build -C Debug -R task1 \n",
"ctest --test-dir build -C Debug -R task2 \n",
"ctest --test-dir build -C Debug -R task3 \n",
"ctest --test-dir build -C Debug # all\n",
"``` \n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.15"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+1
Submodule exercise3/modules added at b8ce24c87f
+38
View File
@@ -0,0 +1,38 @@
/// @file
/// @brief Task1: "single-file" excutable C++ program
#include <iostream>
#include <vector>
/// @brief Calculate the sum of all integer values in a std::vector<std::vector<int>>
/// @param data A vector of vectors containing the values to be summed
/// @return Sum of all values in data
double sum(const std::vector<std::vector<int>>& data) {
double sum = 0;
for (const auto& row : data) {
for (const auto& value : row) {
sum += value;
}
}
return sum;
}
/// @brief main function (entry point for executable) conducting the following tasks in this order
/// - create and prepare a local variable of type std::vector<std::vector<int>>
/// holding 9 int values in this arrangement:
/// 1, 2, 3
/// 4, 5, 6
/// 7, 8, 9
/// - call your function 'sum' and provide the prepared variable as argument to the call
/// - capture the result of your function call in a local variable and print it to the console
int main() {
std::vector<std::vector<int>> data = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
double result = sum(data);
std::cout << "Sum: " << result << std::endl;
return 0;
}
+71
View File
@@ -0,0 +1,71 @@
/// @file
/// @brief Task2: implementation
#include "task2.hpp"
/// @todo Include standard library headers as needed
#include <cassert> // assert
#include <functional> // std::function
#include <vector> // std::vector
#include <cmath> // std::abs
/// @brief Creates a sequence of equidistant values in a given interval (inclusive).
/// @param start Start of the interval
/// @param end End of the interval
/// @param N Number of values; assumption: N >= 2
/// @return Sequence of equidistant values in increasing order
std::vector<double> range(double start, double end, unsigned int N) {
assert(N >= 2);
std::vector<double> values(N);
double step = (end - start) / (N - 1);
for (unsigned int i = 0; i < N; ++i) {
values[i] = start + i * step;
}
return values;
}
/// @brief Evaluates a one-dimensional scalar function at the provided discrete locations
/// @param values Sequence of discrete locations
/// @param func Callable with a signature compatible with f(double) -> double
/// @return Sequence of function values
std::vector<double> sample(std::vector<double> values, std::function<double(double)> func) {
std::vector<double> results(values.size());
for (unsigned int i = 0; i < values.size(); ++i) {
results[i] = func(values[i]);
}
return results;
}
/// @brief Performs a numerical differentiation using a combined forward/center/backward difference scheme
/// @param x Discrete sequence of locations; assumption: two or more values, ascending, and equally spaced
/// @param y Discrete sequence of function values; assumption: same size as 'x'
/// @return Sequence of function values of the numerical derivative
std::vector<double> numdiff(std::vector<double> x, std::vector<double> y) {
assert(x.size() == y.size());
assert(x.size() >= 2);
std::vector<double> derivative(x.size());
double h = x[1] - x[0];
derivative[0] = (y[1] - y[0]) / h;
for (unsigned int i = 1; i < x.size() - 1; ++i) {
derivative[i] = (y[i + 1] - y[i - 1]) / (2 * h);
}
derivative[x.size() - 1] = (y[x.size() - 1] - y[x.size() - 2]) / h;
return derivative;
}
/// @brief Performs a numerical integration using the trapezoidal rule
/// @param x Discrete sequence of locations; assumption: two or more values, ascending, and equally spaced
/// @param y Discrete sequence of function values; assumption: same size as 'x'
/// @param C Constant of integration
/// @return Sequence of function values of the numerical antiderivative
std::vector<double> numint(std::vector<double> x, std::vector<double> y, double C) {
assert(x.size() == y.size());
assert(x.size() >= 2);
std::vector<double> integral(x.size());
double h = x[1] - x[0];
integral[0] = C;
for (unsigned int i = 1; i < x.size(); ++i) {
integral[i] = integral[i - 1] + (y[i - 1] + y[i]) * h / 2;
}
return integral;
}
+34
View File
@@ -0,0 +1,34 @@
/// @file
/// @brief Task2: function declarations
#pragma once
#include <functional> // std::function
#include <vector> // std::vector
/// @brief Creates a sequence of equidistant values in a given interval (inclusive).
/// @param start Start of the interval
/// @param end End of the interval
/// @param N Number of values; assumption: N >= 2
/// @return Sequence of equidistant values in increasing order
std::vector<double> range(double start, double end, unsigned int N);
/// @brief Evaluates a one-dimensional scalar function at the provided discrete locations
/// @param values Sequence of discrete locations
/// @param func Callable with a signature compatible with f(double) -> double
/// @return Sequence of function values
std::vector<double> sample(std::vector<double> values, std::function<double(double)> func);
/// @brief Performs a numerical differentiation using a combined forward/center/backward difference scheme
/// @param x Discrete sequence of locations; assumption: two or more values, ascending, and equally spaced
/// @param y Discrete sequence of function values; assumption: same size as 'x'
/// @return Sequence of function values of the numerical derivative
std::vector<double> numdiff(std::vector<double> x, std::vector<double> y);
/// @brief Performs a numerical integration using the trapezoidal rule
/// @param x Discrete sequence of locations; assumption: two or more values, ascending, and equally spaced
/// @param y Discrete sequence of function values; assumption: same size as 'x'
/// @param C Constant of integration
/// @return Sequence of function values of the numerical antiderivative
std::vector<double> numint(std::vector<double> x, std::vector<double> y, double C);
+97
View File
@@ -0,0 +1,97 @@
/// @file
/// @brief Task2: tests
#include "task2.hpp"
#include <cassert> // assert
#include <cmath> // std::abs|sin
#include <iostream> // std::cout|endl
#include <vector> // std::vector
namespace help {
/// @brief only to disambiguate the 'sin'-overloads from cmath
double sin(double value) { return std::sin(value); }
/// @brief only to disambiguate the 'cos'-overloads from cmath
double cos(double value) { return std::cos(value); }
} // namespace help
int main() {
{ // testing function 'range'
std::vector<double> x = range(0, 10, 11);
double dx = x[1] - x[0];
assert(std::abs(dx - 1.0) < 1e-7);
for (unsigned int i = 1; i != x.size(); ++i)
assert(std::abs(x[i] - x[i - 1] - dx) < 1e-7);
}
{ // testing functions 'range' and 'sample'
std::vector<double> x = range(2, 10, 6);
std::vector<double> f = sample(x, help::sin);
for (unsigned int i = 0; i != x.size(); ++i)
assert(std::abs(f[i] - help::sin(x[i])) < 1e-7);
}
{ // testing functions 'range' and 'sample'
std::vector<double> x = range(0, 5, 6);
std::vector<double> f = sample(x, help::cos);
for (unsigned int i = 0; i != x.size(); ++i)
assert(std::abs(f[i] - help::cos(x[i])) < 1e-7);
}
{ // testing function 'numdiff'
std::vector<double> x = {0, 1, 2, 3, 4};
std::vector<double> f = {0, 1, 1, 1, 0.5};
std::vector<double> df = numdiff(x, f);
assert(std::abs(df[0] - 1.0) < 1e-7);
assert(std::abs(df[1] - 0.5) < 1e-7);
assert(std::abs(df[2] - 0.0) < 1e-7);
assert(std::abs(df[3] + 0.25) < 1e-7);
assert(std::abs(df[4] + 0.5) < 1e-7);
}
{ // testing function 'numdiff'
double s = 2.0;
std::vector<double> x = {0*s, 1*s, 2*s, 3*s, 4*s};
std::vector<double> f = {0, 1, 1, 1, 0.5};
std::vector<double> df = numdiff(x, f);
assert(std::abs(df[0] - 1.00/s) < 1e-7);
assert(std::abs(df[1] - 0.50/s) < 1e-7);
assert(std::abs(df[2] - 0.00/s) < 1e-7);
assert(std::abs(df[3] + 0.25/s) < 1e-7);
assert(std::abs(df[4] + 0.50/s) < 1e-7);
}
{ // testing function 'numint'
std::vector<double> x = {0, 1, 2, 3, 4};
std::vector<double> f = {0, 1, 1, 1, 0};
std::vector<double> F = numint(x, f, 0.0);
assert(std::abs(F[0] - 0.0) < 1e-7);
assert(std::abs(F[1] - (F[0] + 0.5)) < 1e-7);
assert(std::abs(F[2] - (F[1] + 1.0)) < 1e-7);
assert(std::abs(F[3] - (F[2] + 1.0)) < 1e-7);
assert(std::abs(F[4] - (F[3] + 0.5)) < 1e-7);
}
{ // testing function 'numint'
double s = 2.0;
std::vector<double> x = {0*s, 1*s, 2*s, 3*s, 4*s, 5*s};
std::vector<double> f = {0, 1, 1, 1, 0, -1};
std::vector<double> F = numint(x, f, 10.0);
assert(std::abs(F[0] - 10.0) < 1e-7);
assert(std::abs(F[1] - (F[0] + 0.5*s)) < 1e-7);
assert(std::abs(F[2] - (F[1] + 1.0*s)) < 1e-7);
assert(std::abs(F[3] - (F[2] + 1.0*s)) < 1e-7);
assert(std::abs(F[4] - (F[3] + 0.5*s)) < 1e-7);
assert(std::abs(F[5] - (F[4] - 0.5*s)) < 1e-7);
}
std::cout << "task2.test.cpp: all asserts passed" << std::endl;
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
/// @file
/// @brief Task3: implementation
#include "task3.hpp" // sample_to_csv
#include "iue-io/csv.hpp" // iue::io::savetxt
#include "task2.hpp" // range|sample|numint|numdiff
/// @todo Include standard library headers as needed
#include <functional> // std::function
#include <vector> // std::vector
/// @brief This function
/// - samples a one-dimensional scalar function (f) in a provided interval and resolution,
// - approximates its derivative (df) and antiderivative (F) numerically, and
/// - produces a csv-file holding the discrete values in this form:
/// - csv-column layout: x, f, F, df
/// @param filepath
/// @param del Delimiter
/// @param comment Character designating a line as a comment
/// @param func Callable with a signature compatible with f(double) -> double
/// @param start Start of the interval
/// @param end End of the interval
/// @param N Number of values; assumption: N >= 2
void sample_to_csv(std::filesystem::path filepath, char del, char comments, std::function<double(double)> func,
double start, double end, unsigned int N) {
// Create a sequence of equidistant values in the interval [start, end]
std::vector<double> x = range(start, end, N);
// Sample the function 'func' at the locations 'x'
std::vector<double> f = sample(x, func);
// Approximate the derivative of 'f' at the locations 'x'
std::vector<double> df = numdiff(x, f);
// Approximate the antiderivative of 'f' at the locations 'x'
std::vector<double> F = numint(x, f, 0.0);
// Create a matrix holding the discrete values of 'x', 'f', 'F', and 'df'
std::vector<std::vector<double>> data(N, std::vector<double>(4));
for (unsigned int i = 0; i < N; ++i) {
data[i][0] = x[i];
data[i][1] = f[i];
data[i][2] = F[i];
data[i][3] = df[i];
}
// Save the matrix to a csv-file
iue::io::savetxt(filepath, data, del);
}
+22
View File
@@ -0,0 +1,22 @@
/// @file
/// @brief Task3: function declarations
#pragma once
#include <filesystem> // std::filesystem::path
#include <functional> // std::function
/// @brief This function
/// - samples a one-dimensional scalar function (f) in a provided interval and resolution,
// - approximates its derivative (df) and antiderivative (F) numerically, and
/// - produces a csv-file holding the discrete values in this form:
/// - csv-column layout: x, f, F, df
/// @param filepath
/// @param del Delimiter
/// @param comment Character designating a line as a comment
/// @param func Callable with a signature compatible with f(double) -> double
/// @param start Start of the interval
/// @param end End of the interval
/// @param N Number of values; assumption: N >= 2
void sample_to_csv(std::filesystem::path filepath, char del, char comments, std::function<double(double)> func,
double start, double end, unsigned int N);
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
""" Task3: implementation """
import numpy as np
import matplotlib.pyplot as plt
def plot_discrete_function(csvfile, delimiter, comments, pngfile):
"""
Reads a csv-file containing discretized value of a function (f), its derivative (df) and antiderivative (F)
and plots all three functions over the discrete value of the interval (x).
Expected csv-column layout:
x, f, F, df
Requirements for the plot:
- axis labels
- a legend for the plotted data records
Implementation hints:
- use numpy.loadtxt(...) for loading the data from the csvfile
- use Matplotlib for plotting
Parameters
----------
csvfile : string
Name of the csv-file containing the discrete function
delimiter: character
Charater used to delimit individual values in the rows
comments: character
Charater (when used as first character in a row) denoting comment lines
pngfile : string
Name of the file where the plot is saved
"""
# load data from csv file
data = np.loadtxt(csvfile, delimiter=delimiter, comments=comments)
x = data[:, 0]
f = data[:, 1]
F = data[:, 2]
df = data[:, 3]
# plot the data
plt.plot(x, f, label='f')
plt.plot(x, F, label='F')
plt.plot(x, df, label='df')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.savefig(pngfile)
plt.close('all')
+59
View File
@@ -0,0 +1,59 @@
/// @file
/// @brief Task3: tests
#include "task3.hpp"
#include "iue-io/csv.hpp"
#include <cassert> // assert
#include <cmath> // std::sin
#include <filesystem> // std::filesystem::remove
#include <iostream> // std::cout|endl
#include <numbers> // std::numbers::pi
int main() {
{
auto f = [](double x) { return cos(x); };
auto df = [](double x) { return -sin(x); };
auto F = [](double x) { return sin(x) - (sin(0)); };
std::filesystem::path filename = "test.task3.cos.csv";
std::filesystem::remove(filename);
sample_to_csv(filename, ';', '#', f, 0, 2 * std::numbers::pi, 18);
auto table = iue::io::loadtxt(filename, ';', '#');
assert(table.size() == 18);
for (unsigned int r = 0; r != table.size(); ++r) {
assert(table[r].size() == 4);
assert(std::abs(f(table[r][0]) - table[r][1]) < 0.2);
assert(std::abs(F(table[r][0]) - table[r][2]) < 0.2);
assert(std::abs(df(table[r][0]) - table[r][3]) < 0.2);
}
}
{
auto f = [](double x) { return sin(x); };
auto df = [](double x) { return cos(x); };
auto F = [](double x) { return -cos(x) - (-cos(0)); };
std::filesystem::path filename = "test.task3.sin.csv";
std::filesystem::remove(filename);
sample_to_csv(filename, ';', '#', f, 0, 2 * std::numbers::pi, 360);
auto table = iue::io::loadtxt(filename, ';', '#');
assert(table.size() == 360);
for (unsigned int r = 0; r != table.size(); ++r) {
assert(table[r].size() == 4);
assert(std::abs(f(table[r][0]) - table[r][1]) < 0.01);
assert(std::abs(F(table[r][0]) - table[r][2]) < 0.01);
assert(std::abs(df(table[r][0]) - table[r][3]) < 0.01);
}
}
std::cout << "task3.test.cpp: all asserts passed" << std::endl;
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
""" Task3: tests """
import os
import unittest
import matplotlib.pyplot as plt
import task3
class Test(unittest.TestCase):
def test_plot_sin(self):
figname = "test.task3.sin.png"
if os.path.isfile(figname):
os.remove(figname)
plt.close('all')
task3.plot_discrete_function("test.task3.sin.csv",";","#",figname)
plt.close('all')
self.assertTrue(os.path.isfile(figname))
def test_plot_cos(self):
figname = "test.task3.cos.png"
if os.path.isfile(figname):
os.remove(figname)
plt.close('all')
task3.plot_discrete_function("test.task3.cos.csv",";","#",figname)
plt.close('all')
self.assertTrue(os.path.isfile(figname))
if __name__ == "__main__":
unittest.main()