init
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
---
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
ColumnLimit: 120
|
||||
TabWidth: 4
|
||||
IndentWidth: 2
|
||||
...
|
||||
@@ -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]
|
||||
@@ -0,0 +1,3 @@
|
||||
task1
|
||||
task2
|
||||
task3
|
||||
@@ -0,0 +1,3 @@
|
||||
task1.main.c
|
||||
task2.c
|
||||
task3.main.c
|
||||
@@ -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
|
||||
@@ -0,0 +1,358 @@
|
||||
# custom
|
||||
|
||||
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
|
||||
@@ -0,0 +1,4 @@
|
||||
[submodule "modules"]
|
||||
path = modules
|
||||
url = https://sgit.iue.tuwien.ac.at/360050/modules
|
||||
branch = main
|
||||
@@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
# define project metadata
|
||||
|
||||
project(exercise10 LANGUAGES C
|
||||
DESCRIPTION "exercise10"
|
||||
HOMEPAGE_URL "https://sgit.iue.tuwien.ac.at/360050/exercise10")
|
||||
|
||||
# setting required language standards
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||
set(CMAKE_C_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)
|
||||
|
||||
# find math library and link to all targets
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
link_libraries(${MATH_LIBRARY})
|
||||
|
||||
# get/setup dependencies
|
||||
|
||||
include_directories(modules)
|
||||
|
||||
# include own targets
|
||||
|
||||
add_executable(task1 task1.main.c)
|
||||
target_link_libraries(task1 PRIVATE ${MATH_LIBRARY})
|
||||
add_test(NAME task1 COMMAND task1 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
set_property(TEST task1 PROPERTY PASS_REGULAR_EXPRESSION ".*10.*")
|
||||
|
||||
add_executable(task2 task2.c task2.test.c)
|
||||
target_link_libraries(task2 PRIVATE ${MATH_LIBRARY})
|
||||
add_test(NAME task2 COMMAND task2 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
add_executable(task3_main task2.c task3.main.c)
|
||||
|
||||
add_test(NAME task3_popt_fail COMMAND task3_main --left rrev4x4.csv --right matrix4x2.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_inpath_fail COMMAND task3_main --left hui.csv --right matrix4x2.csv --out result.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_dims_fail COMMAND task3_main --left matrix4x2.csv --right rrev4x4.csv --out result.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_outpath_fail COMMAND task3_main --left rrev4x4.csv --right matrix4x2.csv --out hui/result.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_csv_fail COMMAND task3_main --left rrev4x4.csv --right invalid.csv --out matrix4x2_rrow.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_rrow COMMAND task3_main --left rrev4x4.csv --right matrix4x2.csv --out matrix4x2_rrow.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
add_test(NAME task3_rcol COMMAND task3_main --left matrix4x2.csv --right rcol2x2.csv --out matrix4x2_rcols.csv WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
add_executable(task3_test task3.test.c)
|
||||
add_test(NAME task3_test COMMAND task3_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
set_tests_properties(task3_popt_fail task3_inpath_fail task3_dims_fail task3_outpath_fail task3_csv_fail PROPERTIES WILL_FAIL TRUE)
|
||||
set_tests_properties(task3_test PROPERTIES DEPENDS task3_rrow)
|
||||
set_tests_properties(task3_test PROPERTIES DEPENDS task3_rcol)
|
||||
|
||||
add_custom_target(task3)
|
||||
add_dependencies(task3 task3_test task3_main)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Hausübung 10 (3 Punkte)
|
||||
|
||||
**Ausgabe**: Donnerstag 6. Juni 2024, vormittags.
|
||||
|
||||
**Abgabe bis**: Montag 17. Juni 2024, Ende des Tages.
|
||||
|
||||
**Abgabe via**: git-Repository mit dem Namen **`exercise10`** 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:
|
||||
|
||||
- C: Kommandozeilen-Optionen
|
||||
- C: Speicherung multidimensionaler (hier zweidimensional) Felder in einem kontinuierlichen Speicherbereich (hier *row-major*-Ordnung)
|
||||
- C: Matrixoperationen basierend auf einer *row-major*-Ordnung
|
||||
|
||||
**Die genaue Beschreibung und Anforderungen finden Sie in [`main.ipynb`](main.ipynb) und im Quellcode.**
|
||||
@@ -0,0 +1 @@
|
||||
-Imodules
|
||||
@@ -0,0 +1,5 @@
|
||||
// matrix4x2.csv: a 4x2 matrix, not using '#' to indicate comments, non float data
|
||||
not-a-number;11;12
|
||||
not-a-number;21;22
|
||||
not-a-number;31;32
|
||||
not-a-number;41;42
|
||||
|
@@ -0,0 +1,203 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 1: Ein eigenes kleines C-Programm (*row-major layout*) (1 Punkt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Erstellen Sie in [`task1.main.c`](task1.main.c) ein lauffähiges Ein-Dateien-Programm das folgende Struktur aufweist:\n",
|
||||
"\n",
|
||||
"- Einbinden benötigter Header-Dateien aus der Standardbibliothek, z.B.:\n",
|
||||
"\t```c\n",
|
||||
"\t#include <limits.h> // INT_MAX\n",
|
||||
"\t#include <stdio.h> // printf\n",
|
||||
"\t...\n",
|
||||
"\t```\n",
|
||||
"- Definition/Implementierung einer eigenen Funktion, z.B.:\n",
|
||||
"\t```cpp\n",
|
||||
"\tsize_t func(...) {\n",
|
||||
"\t ...\n",
|
||||
"\t}\n",
|
||||
"\t``` \n",
|
||||
"- Definition/Implementierung einer `main`-Funktion, die Ihre selbst geschriebene Funktion verwendet, z.B.:\n",
|
||||
"\t```cpp\n",
|
||||
"\tint main(){\n",
|
||||
"\t ...\t\n",
|
||||
"\t int res = func(...);\n",
|
||||
"\t ...\t\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.c`](task1.main.c)\n",
|
||||
"- Ihre Implementierung erfolgt ebenfalls in [`task1.main.c`](task1.main.c)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 2: Funktionalität für zweidimensionale Felder mit kontinuierlichem Speicherlayout (hier: *row-major order*) (1 Punkt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"Gegeben ist eine Struktur `struct Matrix`, die eine *M x N*-Matrix mit kontinuierlichem Speicherlayout darstellt, ebenso gegeben sind drei yugehörige Funktionen:<>\n",
|
||||
"```c\n",
|
||||
"struct Matrix {\n",
|
||||
" double* data; ///< pointer to a dynamically allocated contiguous memory block of size m*n\n",
|
||||
" size_t m; ///< number of rows (first dimension)\n",
|
||||
" size_t n; ///< number of colmns (second dimension)\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"struct Matrix matrix_init(size_t m, size_t n, const double *data);\n",
|
||||
"void matrix_print(const struct Matrix* mat);\n",
|
||||
"void matrix_clear(struct Matrix* mat);\n",
|
||||
"```\n",
|
||||
"Sie implementieren weitere vier Funktionen, die die Funktionalität erweitern:\n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"// todo: implement\n",
|
||||
"struct Matrix matrix_zeros(size_t m, size_t n);\n",
|
||||
"struct Matrix matrix_identity(size_t n);\n",
|
||||
"void matrix_transpose(struct Matrix* mat);\n",
|
||||
"void matrix_mult(const struct Matrix* a, const struct Matrix* b, struct Matrix* c);\n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Die vorgegebenen Strukturen/Funktionen und eine genaue Beschreibung und Anforderungen finden Sie in [`task2.h`](task2.h)\n",
|
||||
"- Ihre Implementierung erfolgt in [`task2.c`](task2.c)\n",
|
||||
"- Die zugeordneten Tests finden Sie in [`task2.test.c`](task2.test.c) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 3: Kommandozeilen-Programm Matrix/Matrix-Multiplikation (1 Punkt)\n",
|
||||
"\n",
|
||||
"Sie implementieren ein Programm, das \n",
|
||||
"\n",
|
||||
"- zwei Matrizen aus zwei `.csv`-Dateien einließt, \n",
|
||||
"- das Produkt der Matrizen berechnet (Matrix/Matrix-Multiplikation), und\n",
|
||||
"- das Ergebnis wiederum als `.csv`-Datei speichert.\n",
|
||||
"\n",
|
||||
"Die Dateinamen werden mittels der Kommandozeile übergeben.\n",
|
||||
"\n",
|
||||
"Das Programm bricht in folgenden Sitationen ab:\n",
|
||||
"\n",
|
||||
"- unzureichende Argumente\n",
|
||||
"- invalide Dateipfade\n",
|
||||
"- Fehler beim Einlesen der Dateien\n",
|
||||
"- inkompatible Matrix-Dimensionen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Die vorgegebenen Deklaration und eine genaue Beschreibung und Anforderungen finden Sie in [`task3.main.c`](task3.main.c)\n",
|
||||
"- Ihre Implementierung erfolgt ebenfalls in [`task3.main.c`](task3.main.c)\n",
|
||||
"- Getestet wird Ihr Programm, indem es mit verschiedenen Parametern in der Kommandozeile aufgerufen wird (siehe auch [`CMakeLists.txt`](CMakeLists.txt) und im nächsten Abschnitt).\n",
|
||||
"- Nachfolgend werden die Ausgabedateien der letzten beiden Aufrufe mit den Tests in [`task3.test.c`](task3.test.c) überprüft."
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Kompilieren/Testen\n",
|
||||
"\n",
|
||||
"So testen Sie Ihre Implementierung (direkter Aufruf von `gcc`):\n",
|
||||
"\n",
|
||||
"```shell\n",
|
||||
"# prepare\n",
|
||||
"mkdir build\n",
|
||||
"# compile\n",
|
||||
"gcc -g -std=c11 task1.main.c -o build/task1 -lm\n",
|
||||
"gcc -g -Imodules -std=c11 task2.c task2.test.c -o build/task2 -lm\n",
|
||||
"gcc -g -Imodules -std=c11 task2.c task3.main.c -o build/task3_main -lm\n",
|
||||
"gcc -g -Imodules -std=c11 task3.test.c -o build/task3_test -lm\n",
|
||||
"\n",
|
||||
"# run tests\n",
|
||||
"./build/task1\n",
|
||||
"./build/task2\t\n",
|
||||
"./build/task3_main --left rrev4x4.csv --right matrix4x2.csv # expect runtime fail: invalid arguments\n",
|
||||
"./build/task3_main --left hui.csv --right matrix4x2.csv --out result.csv # expect runtime fail: invalid input filename\n",
|
||||
"./build/task3_main --left matrix4x2.csv --right rrev4x4.csv --out result.csv # expect runtime fail: invalid matrix dimensions\n",
|
||||
"./build/task3_main --left rrev4x4.csv --right matrix4x2.csv --out hui/result.csv # expect runtime fail: invalid output filename\n",
|
||||
"./build/task3_main --left rrev4x4.csv --right invalid.csv --out matrix4x2_rrow.csv # expect runtime fail: invalid line in invalid.csv\n",
|
||||
"./build/task3_main --left rrev4x4.csv --right matrix4x2.csv --out matrix4x2_rrow.csv # expected succeed and to generate matrix4x2_rrow.csv\n",
|
||||
"./build/task3_main --left matrix4x2.csv --right rcol2x2.csv --out matrix4x2_rcols.csv # expected succeed and to generate matrix4x2_rcols.csv\n",
|
||||
"./build/task3_test # tests the contents of the generated files matrix4x2_rrow.csv and matrix4x2_rcols.csv\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Alternativ (mittels CMake-Configuration):\n",
|
||||
"\n",
|
||||
"```shell\n",
|
||||
"# prepare\n",
|
||||
"cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug # Windows\n",
|
||||
"cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -D CMAKE_C_FLAGS=\"-fsanitize=address\" # Linux\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 --verbose\n",
|
||||
"ctest --test-dir build -C Debug -R task2 --verbose\n",
|
||||
"ctest --test-dir build -C Debug -R task3 --verbose\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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# matrix4x2.csv: a 4x2 matrix
|
||||
11;12
|
||||
21;22
|
||||
31;32
|
||||
41;42
|
||||
|
@@ -0,0 +1,4 @@
|
||||
1.200000000000000000e+001;1.100000000000000000e+001
|
||||
2.200000000000000000e+001;2.100000000000000000e+001
|
||||
3.200000000000000000e+001;3.100000000000000000e+001
|
||||
4.200000000000000000e+001;4.100000000000000000e+001
|
||||
|
@@ -0,0 +1,4 @@
|
||||
4.100000000000000000e+001;4.200000000000000000e+001
|
||||
3.100000000000000000e+001;3.200000000000000000e+001
|
||||
2.100000000000000000e+001;2.200000000000000000e+001
|
||||
1.100000000000000000e+001;1.200000000000000000e+001
|
||||
|
Submodule
+1
Submodule exercise10/modules added at 33515ac3ad
@@ -0,0 +1,3 @@
|
||||
# rcol2x2: reverses column order if right multiplied with any Mx2 matrix
|
||||
0; 1
|
||||
1; 0
|
||||
|
@@ -0,0 +1,5 @@
|
||||
# rrev4x4.csv: reverses row order if left multiplied to a 4xN matrix
|
||||
0; 0; 0; 1
|
||||
0; 0; 1; 0
|
||||
0; 1; 0; 0
|
||||
1; 0; 0; 0
|
||||
|
@@ -0,0 +1,67 @@
|
||||
/// @file
|
||||
/// @brief Task1: "single-file" executable C program
|
||||
|
||||
/// @todo Include C standard library headers, as needed
|
||||
|
||||
/// @todo Implement a function 'max_column_sum' according to the description below:
|
||||
/// The function receives a "m x n"-matrix holding signed integer values stored in a contiguous block of memory using
|
||||
/// row-major layout. Specifically it receives these arguments
|
||||
/// - number of rows m
|
||||
/// - number of columns n
|
||||
/// - pointer to a contiguous block of memory containing m*n signed integer values
|
||||
/// - row-major storage order is used, access of element (i,j) -> data[j + n*i]
|
||||
/// The function then calculates the maximum column sum, i.e. the maximum sum of values in one column of the matrix, and
|
||||
/// returns this value.
|
||||
|
||||
/// @todo Implement a 'main' function conducting the following tasks in this order:
|
||||
/// - construct three local variables containing the following values:
|
||||
/// - an integer value for the number of rows: 2
|
||||
/// - an integer value for the number of columns: 4
|
||||
/// - an array of integer values to be interpreted as a 2x4 matrix in row-major layout containing these values:
|
||||
/// {5, -2, -12, 4, 1, 3, -5, 6}
|
||||
/// - use your function to calculate the maximum column sum of the 2x4 matrix specified by your three local variables
|
||||
/// - print the result to the console
|
||||
|
||||
|
||||
/// @file
|
||||
/// @brief Task1: "single-file" executable C program
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/// Function to calculate the maximum column sum of a matrix
|
||||
int max_column_sum(int m, int n, int data[]) {
|
||||
int max_sum = data[0]; // Initialize with first element
|
||||
|
||||
// Loop through each column
|
||||
for (int j = 1; j < n; j++) {
|
||||
int current_sum = 0;
|
||||
// Loop through each row in the current column
|
||||
for (int i = 0; i < m; i++) {
|
||||
// Calculate sum of elements in current column
|
||||
current_sum += data[j + n * i];
|
||||
}
|
||||
// Update max_sum if current sum is greater
|
||||
if (current_sum > max_sum) {
|
||||
max_sum = current_sum;
|
||||
}
|
||||
}
|
||||
|
||||
return max_sum;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Define matrix dimensions
|
||||
int rows = 2;
|
||||
int cols = 4;
|
||||
|
||||
// Define matrix data in row-major order
|
||||
int data[] = {5, -2, -12, 4, 1, 3, -5, 6};
|
||||
|
||||
// Calculate maximum column sum
|
||||
int max_column_sum_value = max_column_sum(rows, cols, data);
|
||||
|
||||
// Print the result
|
||||
printf("Maximum column sum: %d\n", max_column_sum_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/// @file
|
||||
/// @brief Task2: function definitions
|
||||
|
||||
#include "task2.h" // struct Matrix, matrix_mult
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdio.h> // printf
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
/// @todo Include C standard library headers as needed
|
||||
|
||||
/// @note This implementation is provided as declared and specified in task2.h
|
||||
struct Matrix matrix_init(size_t m, size_t n, const double* data) {
|
||||
struct Matrix res = {.data = malloc(sizeof(double) * m * n), .m = m, .n = n};
|
||||
double* A = res.data;
|
||||
for (size_t i = 0; i != m * n; ++i)
|
||||
A[i] = data[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @note This implementation is provided as declared and specified in task2.h
|
||||
void matrix_print(const struct Matrix* mat) {
|
||||
size_t M = mat->m;
|
||||
size_t N = mat->n;
|
||||
const double* A = mat->data;
|
||||
|
||||
for (size_t m = 0; m != M; ++m) {
|
||||
for (size_t n = 0; n != N; ++n)
|
||||
printf("%lf ", A[n + N * m]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/// @note This implementation is provided as declared and specified in task2.h
|
||||
void matrix_clear(struct Matrix* mat) {
|
||||
free(mat->data);
|
||||
mat->m = 0;
|
||||
mat->n = 0;
|
||||
}
|
||||
|
||||
/// @brief Initializes an matrix with zeros
|
||||
/// @param m first dimension of the matrix
|
||||
/// @param n first dimension of the matrix
|
||||
struct Matrix matrix_zeros(size_t m, size_t n){
|
||||
double* data = malloc(sizeof(double) * m * n);
|
||||
for (size_t i = 0; i != m * n; ++i)
|
||||
data[i] = 0;
|
||||
return matrix_init(m, n, data);
|
||||
}
|
||||
|
||||
/// @brief Initializes a square identity matrix
|
||||
/// @param n dimension of the identity matrix
|
||||
struct Matrix matrix_identity(size_t n){
|
||||
double* data = malloc(sizeof(double) * n * n);
|
||||
for (size_t i = 0; i != n; ++i)
|
||||
for (size_t j = 0; j != n; ++j)
|
||||
data[j + n * i] = i == j ? 1 : 0;
|
||||
return matrix_init(n, n, data);
|
||||
|
||||
}
|
||||
|
||||
/// @brief Transposes a matrix
|
||||
/// @param mat Matrix to be transposed
|
||||
/// @note this function might swap/replace the block of memory owned by the matrix
|
||||
void matrix_transpose(struct Matrix* mat){
|
||||
size_t m = mat->m;
|
||||
size_t n = mat->n;
|
||||
double* data = malloc(sizeof(double) * m * n);
|
||||
for (size_t i = 0; i != m; ++i)
|
||||
for (size_t j = 0; j != n; ++j)
|
||||
data[i + m * j] = mat->data[j + n * i];
|
||||
free(mat->data);
|
||||
mat->data = data;
|
||||
mat->m = n;
|
||||
mat->n = m;
|
||||
|
||||
}
|
||||
|
||||
/// @brief Performs a matrix-matrix mutliplication: a*b = c
|
||||
/// @a first matrix (left factor)
|
||||
/// @b second matrix (right factor)
|
||||
/// @c Result of the multiplication is stored in this Matrix:
|
||||
/// - the dimensions of this matrix must be 'a.m x b.n' when calling this function
|
||||
/// - the values will be overwritten with the result of the multiplication
|
||||
void matrix_mult(const struct Matrix* a, const struct Matrix* b, struct Matrix* c){
|
||||
size_t m = a->m;
|
||||
size_t n = a->n;
|
||||
size_t p = b->n;
|
||||
double* data = malloc(sizeof(double) * m * p);
|
||||
for (size_t i = 0; i != m; ++i)
|
||||
for (size_t j = 0; j != p; ++j){
|
||||
double sum = 0;
|
||||
for (size_t k = 0; k != n; ++k)
|
||||
sum += a->data[k + n * i] * b->data[j + p * k];
|
||||
data[j + p * i] = sum;
|
||||
}
|
||||
free(c->data);
|
||||
c->data = data;
|
||||
c->m = m;
|
||||
c->n = p;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/// @file
|
||||
/// @brief Task2: Structure definitions and function declarations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
/// @brief Two-dimensional matrix with 'm' rows and 'n' columns.
|
||||
/// @note: the values ares stored in a contiguous block in memory in row-major layout
|
||||
/// @note: row-major storage order is used, access of element (i,j) -> data[j + n*i]
|
||||
struct Matrix {
|
||||
double* data; ///< pointer to a dynamically allocated contiguous memory block fitting m*n values
|
||||
size_t m; ///< number of rows (first dimension)
|
||||
size_t n; ///< number of columns (second dimension)
|
||||
};
|
||||
|
||||
/// @brief Initalize a matrix from the values in a buffer
|
||||
/// @param m first dimension of the matrix
|
||||
/// @param n second dimension of the matrix
|
||||
/// @param data contiguous memory holding the values to copy (in row-major format)
|
||||
struct Matrix matrix_init(size_t m, size_t n, const double* data);
|
||||
|
||||
/// @brief Prints a Matrix to the console
|
||||
/// @param mat Matrix to be printed
|
||||
void matrix_print(const struct Matrix* mat);
|
||||
|
||||
/// @brief Resets a matrix (deallocates memory and sets its size to 0 x 0)
|
||||
/// @param mat Matrix to be reset
|
||||
void matrix_clear(struct Matrix* mat);
|
||||
|
||||
/// @brief Initializes an matrix with zeros
|
||||
/// @param m first dimension of the matrix
|
||||
/// @param n first dimension of the matrix
|
||||
struct Matrix matrix_zeros(size_t m, size_t n);
|
||||
|
||||
/// @brief Initializes a square identity matrix
|
||||
/// @param n dimension of the identity matrix
|
||||
struct Matrix matrix_identity(size_t n);
|
||||
|
||||
/// @brief Transposes a matrix
|
||||
/// @param mat Matrix to be transposed
|
||||
/// @note this function might swap/replace the block of memory owned by the matrix
|
||||
void matrix_transpose(struct Matrix* mat);
|
||||
|
||||
/// @brief Performs a matrix-matrix mutliplication: a*b = c
|
||||
/// @a first matrix (left factor)
|
||||
/// @b second matrix (right factor)
|
||||
/// @c Result of the multiplication is stored in this Matrix:
|
||||
/// - the dimensions of this matrix must be 'a.m x b.n' when calling this function
|
||||
/// - the values will be overwritten with the result of the multiplication
|
||||
void matrix_mult(const struct Matrix* a, const struct Matrix* b, struct Matrix* c);
|
||||
@@ -0,0 +1,220 @@
|
||||
/// @file
|
||||
/// @brief Task2: tests
|
||||
|
||||
#include "task2.h" // struct Matrix, matrix_mult
|
||||
|
||||
#include "modules/iue-num/numerics.h" // iuenum_isclose
|
||||
|
||||
#include <assert.h> // assert
|
||||
#include <stdbool.h> // bool, true, false
|
||||
#include <stdio.h> // printf
|
||||
|
||||
// helper function
|
||||
bool isclose(const struct Matrix* a, const struct Matrix* b) {
|
||||
if (a->m != b->m)
|
||||
return false;
|
||||
if (a->n != b->n)
|
||||
return false;
|
||||
for (size_t i = 0; i != a->m; ++i)
|
||||
for (size_t j = 0; j != a->n; ++j)
|
||||
if (!iuenum_isclose(a->data[j + a->n * i], b->data[j + b->n * i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
{ // testing 'matrix_zeros' for 3x3
|
||||
struct Matrix mat = matrix_zeros(3, 3);
|
||||
double data[3][3] = {
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
};
|
||||
struct Matrix expected = matrix_init(3, 3, &data[0][0]);
|
||||
assert(isclose(&mat, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_zeros' for 4x3
|
||||
struct Matrix mat = matrix_zeros(4, 3);
|
||||
double data[4][3] = {
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
};
|
||||
struct Matrix expected = matrix_init(4, 3, &data[0][0]);
|
||||
assert(isclose(&mat, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_identity' for 3x3
|
||||
|
||||
double data_expected[3][3] = {
|
||||
{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
};
|
||||
struct Matrix expected = matrix_init(3, 3, &data_expected[0][0]);
|
||||
struct Matrix mat = matrix_identity(3);
|
||||
|
||||
// matrix_print(&mat);
|
||||
assert(isclose(&mat, &expected));
|
||||
// matrix_print(&expected);
|
||||
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_identity' for 4x4
|
||||
|
||||
double data_expected[4][4] = {
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
};
|
||||
struct Matrix expected = matrix_init(4, 4, &data_expected[0][0]);
|
||||
struct Matrix mat = matrix_identity(4);
|
||||
|
||||
// matrix_print(&mat);
|
||||
assert(isclose(&mat, &expected));
|
||||
// matrix_print(&expected);
|
||||
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_transpose' of a 3x3 identity
|
||||
|
||||
struct Matrix mat = matrix_identity(3);
|
||||
|
||||
double data_expected[3][3] = {
|
||||
{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
};
|
||||
struct Matrix expected = matrix_init(3, 3, &data_expected[0][0]);
|
||||
|
||||
// matrix_print(&mat);
|
||||
matrix_transpose(&mat);
|
||||
// matrix_print(&mat);
|
||||
// matrix_print(&expected);
|
||||
|
||||
assert(isclose(&mat, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_transpose' for 4x2
|
||||
|
||||
double data[4][2] = {
|
||||
{11, 12},
|
||||
{21, 22},
|
||||
{31, 32},
|
||||
{41, 42},
|
||||
};
|
||||
struct Matrix mat = matrix_init(4, 2, &data[0][0]);
|
||||
|
||||
double data_expected[2][4] = {
|
||||
{11, 21, 31, 41},
|
||||
{12, 22, 32, 42},
|
||||
};
|
||||
struct Matrix expected = matrix_init(2, 4, &data_expected[0][0]);
|
||||
|
||||
// matrix_print(&mat);
|
||||
matrix_transpose(&mat);
|
||||
// matrix_print(&mat);
|
||||
// matrix_print(&expected);
|
||||
|
||||
assert(isclose(&mat, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing 'matrix_mult' using a left multiplty with a row permuting matrix
|
||||
|
||||
double data[4][2] = {
|
||||
{11, 12},
|
||||
{21, 22},
|
||||
{31, 32},
|
||||
{41, 42},
|
||||
};
|
||||
struct Matrix mat = matrix_init(4, 2, &data[0][0]);
|
||||
|
||||
double data_permute[4][4] = {
|
||||
{0, 0, 0, 1},
|
||||
{0, 0, 1, 0},
|
||||
{0, 1, 0, 0},
|
||||
{1, 0, 0, 0},
|
||||
};
|
||||
struct Matrix permute = matrix_init(4, 4, &data_permute[0][0]);
|
||||
|
||||
double data_expected[4][2] = {
|
||||
{41, 42},
|
||||
{31, 32},
|
||||
{21, 22},
|
||||
{11, 12},
|
||||
};
|
||||
struct Matrix expected = matrix_init(4, 2, &data_expected[0][0]);
|
||||
|
||||
struct Matrix product = matrix_zeros(permute.m, mat.n);
|
||||
|
||||
// matrix_print(&permute);
|
||||
// matrix_print(&mat);
|
||||
matrix_mult(&permute, &mat, &product); // left multiply with permuation matrix
|
||||
// matrix_print(&product);
|
||||
|
||||
assert(isclose(&product, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
matrix_clear(&permute);
|
||||
matrix_clear(&product);
|
||||
}
|
||||
|
||||
|
||||
{ // testing 'matrix_mult' using a right multiplty with a column permuting matrix
|
||||
|
||||
double data[4][2] = {
|
||||
{11, 12},
|
||||
{21, 22},
|
||||
{31, 32},
|
||||
{41, 42},
|
||||
};
|
||||
struct Matrix mat = matrix_init(4, 2, &data[0][0]);
|
||||
|
||||
double data_permute[2][2] = {
|
||||
{0, 1},
|
||||
{1, 0},
|
||||
};
|
||||
struct Matrix permute = matrix_init(2, 2, &data_permute[0][0]);
|
||||
|
||||
double data_expected[4][2] = {
|
||||
{12, 11},
|
||||
{22, 21},
|
||||
{32, 31},
|
||||
{42, 41},
|
||||
};
|
||||
struct Matrix expected = matrix_init(4, 2, &data_expected[0][0]);
|
||||
|
||||
struct Matrix product = matrix_zeros(mat.m, permute.n);
|
||||
|
||||
// matrix_print(&permute);
|
||||
// matrix_print(&mat);
|
||||
matrix_mult(&mat, &permute, &product); // right multiply with permuation matrix
|
||||
// matrix_print(&product);
|
||||
|
||||
assert(isclose(&product, &expected));
|
||||
matrix_clear(&mat);
|
||||
matrix_clear(&expected);
|
||||
matrix_clear(&permute);
|
||||
matrix_clear(&product);
|
||||
}
|
||||
|
||||
printf("task2.test.c: all asserts passed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/// @file
|
||||
/// @brief Task3: program with command line options
|
||||
|
||||
/// @todo Include header from modules/iue-*, as needed
|
||||
/// e.g. #include "iue-po/cpo.h"
|
||||
/// e.g. #include "iue-io/ccsv.h"
|
||||
|
||||
/// @todo Include header of task2, if needed
|
||||
// #include "task2.h"
|
||||
|
||||
/// @todo Include C standard library headers, as needed
|
||||
/// e.g. #include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS
|
||||
|
||||
/// @todo Implement an executable program which the following top-level description:
|
||||
/// 1. reads two matrices 'L', and 'R' from two separate .csv-files
|
||||
/// 2. calculates the matrix product LR (i.e. a matrix-matrix multiplication)
|
||||
/// 3. stores the resulting matrix in a third .csv-file
|
||||
/// Detailed Requirements:
|
||||
/// 1. All .csv-files which are involved need to be compatible with
|
||||
/// the format supported by 'iueio_savetxt' and 'iueio_loadtxt' from the header 'iue-io/ccsv.h'
|
||||
/// using ';' as delimiter and '#' as comment
|
||||
/// 2. The program needs to support the following three mandatory command line arguments in arbitrary order:
|
||||
/// --left relative filepath to the 'L' matrix
|
||||
/// --right relative filepath to the 'R' matrix
|
||||
/// --out relative filepath for the produced result
|
||||
/// 3. The program prints an error message to stderr, terminates, and returns EXIT_FAILURE if
|
||||
/// a) If any of the mandatory arguments is missing
|
||||
/// b) If any of the provided filepaths is not valid
|
||||
/// c) If any of the provided files cannot be parsed successfully
|
||||
/// d) If the dimension of the provided matrices are not compatible
|
||||
/// 4. If the program finishes without any issue, it returns EXIT_SUCCESS
|
||||
///
|
||||
/// Implementation hints/valid assumtions for this exercise:
|
||||
/// - you do not need to support empty .csv-files
|
||||
/// - you can always assume that all rows in a .csv-file have the same length
|
||||
|
||||
/// @file
|
||||
/// @brief Task3: program with command line options
|
||||
|
||||
#include "modules/iue-io/ccsv.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#define DELIM ';'
|
||||
#define COMMENT '#'
|
||||
|
||||
// Function to multiply two matrices
|
||||
double** multiply_matrices(double** L, size_t L_rows, size_t L_cols, double** R, size_t R_rows, size_t R_cols, size_t* out_rows, size_t* out_cols) {
|
||||
if (L_cols != R_rows) {
|
||||
return NULL; // Incompatible dimensions
|
||||
}
|
||||
|
||||
*out_rows = L_rows;
|
||||
*out_cols = R_cols;
|
||||
|
||||
double** result = malloc(L_rows * sizeof(double*));
|
||||
for (size_t i = 0; i < L_rows; ++i) {
|
||||
result[i] = malloc(R_cols * sizeof(double));
|
||||
for (size_t j = 0; j < R_cols; ++j) {
|
||||
result[i][j] = 0.0;
|
||||
for (size_t k = 0; k < L_cols; ++k) {
|
||||
result[i][j] += L[i][k] * R[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
char* left_filepath = NULL;
|
||||
char* right_filepath = NULL;
|
||||
char* out_filepath = NULL;
|
||||
bool left_set = false;
|
||||
bool right_set = false;
|
||||
bool out_set = false;
|
||||
|
||||
// Parse command line arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--left") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "Missing argument for --left\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
left_filepath = argv[i + 1];
|
||||
left_set = true;
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "--right") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "Missing argument for --right\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
right_filepath = argv[i + 1];
|
||||
right_set = true;
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "--out") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "Missing argument for --out\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
out_filepath = argv[i + 1];
|
||||
out_set = true;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for missing mandatory arguments
|
||||
if (!left_set || !right_set || !out_set) {
|
||||
fprintf(stderr,
|
||||
"Missing mandatory arguments. Usage: %s --left <left_file.csv> --right <right_file.csv> --out "
|
||||
"<output_file.csv>\n",
|
||||
argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Load matrices from files
|
||||
struct Table left_table = {NULL, 0};
|
||||
struct Table right_table = {NULL, 0};
|
||||
if (iueio_loadtxt(left_filepath, &left_table, DELIM, COMMENT) != 0) {
|
||||
fprintf(stderr, "Error loading file %s\n", left_filepath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (iueio_loadtxt(right_filepath, &right_table, DELIM, COMMENT) != 0) {
|
||||
fprintf(stderr, "Error loading file %s\n", right_filepath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check if the matrices are compatible
|
||||
//if (left_table.n == 0 || right_table.n == 0 || left_table.rows[0].n != right_table.rows[0].n) {
|
||||
// fprintf(stderr, "Incompatible dimensions\n");
|
||||
// return EXIT_FAILURE;
|
||||
//}
|
||||
|
||||
// Convert tables to matrices
|
||||
size_t L_rows = left_table.n;
|
||||
size_t L_cols = left_table.rows[0].n;
|
||||
double** L = malloc(L_rows * sizeof(double*));
|
||||
for (size_t i = 0; i < L_rows; ++i) {
|
||||
L[i] = malloc(L_cols * sizeof(double));
|
||||
for (size_t j = 0; j < L_cols; ++j) {
|
||||
L[i][j] = left_table.rows[i].values[j];
|
||||
}
|
||||
}
|
||||
|
||||
size_t R_rows = right_table.n;
|
||||
size_t R_cols = right_table.rows[0].n;
|
||||
double** R = malloc(R_rows * sizeof(double*));
|
||||
for (size_t i = 0; i < R_rows; ++i) {
|
||||
R[i] = malloc(R_cols * sizeof(double));
|
||||
for (size_t j = 0; j < R_cols; ++j) {
|
||||
R[i][j] = right_table.rows[i].values[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply matrices
|
||||
size_t out_rows, out_cols;
|
||||
double** result = multiply_matrices(L, L_rows, L_cols, R, R_rows, R_cols, &out_rows, &out_cols);
|
||||
if (result == NULL) {
|
||||
fprintf(stderr, "Incompatible dimensions\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Convert result to table
|
||||
struct Table out_table = {NULL, 0};
|
||||
for (size_t i = 0; i < out_rows; ++i) {
|
||||
table_append_copy(&out_table, result[i], out_cols);
|
||||
}
|
||||
|
||||
// Save result to file
|
||||
if (iueio_savetxt(out_filepath, &out_table, DELIM, "", COMMENT) != 0) {
|
||||
fprintf(stderr, "Error saving file %s\n", out_filepath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Free memory
|
||||
for (size_t i = 0; i < L_rows; ++i) {
|
||||
free(L[i]);
|
||||
}
|
||||
free(L);
|
||||
for (size_t i = 0; i < R_rows; ++i) {
|
||||
free(R[i]);
|
||||
}
|
||||
free(R);
|
||||
for (size_t i = 0; i < out_rows; ++i) {
|
||||
free(result[i]);
|
||||
}
|
||||
free(result);
|
||||
table_clear(&left_table);
|
||||
table_clear(&right_table);
|
||||
table_clear(&out_table);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/// @file
|
||||
/// @brief Task3: tests of output files generated by other tests/commands using command line arguments for task3_main
|
||||
|
||||
#include "modules/iue-io/ccsv.h" // iueio_loadtxt
|
||||
#include "modules/iue-num/numerics.h" // iuenum_isclose
|
||||
|
||||
#include <assert.h> // assert
|
||||
#include <stdbool.h> // bool, true, false
|
||||
#include <stdio.h> // printf
|
||||
|
||||
bool isclose(const struct Table* a, const struct Table* b) {
|
||||
if (a->n != b->n)
|
||||
return false;
|
||||
|
||||
for (size_t r = 0; r != a->n; ++r) {
|
||||
if (a->rows[r].n != a->rows[r].n)
|
||||
return false;
|
||||
for (size_t c = 0; c != a->rows[r].n; ++c)
|
||||
if (!iuenum_isclose(a->rows[r].values[c], b->rows[r].values[c]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
{ // testing result of this command:
|
||||
// "./build/task3_main --left rrev4x4.csv --right matrix4x2.csv --out matrix4x2_rrow.csv"
|
||||
|
||||
double data_expected[4][2] = {
|
||||
{41, 42},
|
||||
{31, 32},
|
||||
{21, 22},
|
||||
{11, 12},
|
||||
};
|
||||
|
||||
struct Table expected = {NULL, 0};
|
||||
table_append_copy(&expected, data_expected[0], 2);
|
||||
table_append_copy(&expected, data_expected[1], 2);
|
||||
table_append_copy(&expected, data_expected[2], 2);
|
||||
table_append_copy(&expected, data_expected[3], 2);
|
||||
|
||||
const char filepath[] = "matrix4x2_rrow.csv";
|
||||
struct Table table = {NULL, 0};
|
||||
|
||||
if (iueio_loadtxt(filepath, &table, ';', '#') != 0) {
|
||||
fprintf(stderr, "error loading file %s\n", filepath);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
assert(isclose(&table, &expected));
|
||||
table_clear(&table);
|
||||
table_clear(&expected);
|
||||
}
|
||||
|
||||
{ // testing result of this command:
|
||||
// "./build/task3_main --left matrix4x2.csv --right rcol2x2.csv --out matrix4x2_rcols.csv"
|
||||
|
||||
double data_expected[4][2] = {
|
||||
{12, 11},
|
||||
{22, 21},
|
||||
{32, 31},
|
||||
{42, 41},
|
||||
};
|
||||
|
||||
struct Table expected = {NULL, 0};
|
||||
table_append_copy(&expected, data_expected[0], 2);
|
||||
table_append_copy(&expected, data_expected[1], 2);
|
||||
table_append_copy(&expected, data_expected[2], 2);
|
||||
table_append_copy(&expected, data_expected[3], 2);
|
||||
|
||||
const char filepath[] = "matrix4x2_rcols.csv";
|
||||
struct Table table = {NULL, 0};
|
||||
|
||||
if (iueio_loadtxt(filepath, &table, ';', '#') != 0) {
|
||||
fprintf(stderr, "error loading file %s\n", filepath);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
assert(isclose(&table, &expected));
|
||||
table_clear(&table);
|
||||
table_clear(&expected);
|
||||
}
|
||||
|
||||
printf("task3.test.c: all asserts passed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user