Skip to content

Commit

Permalink
version 0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
PhoenixIra committed Aug 25, 2023
1 parent c10bf64 commit a54cbf7
Show file tree
Hide file tree
Showing 46 changed files with 4,224 additions and 0 deletions.
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,44 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# VS Code
*.code-workspace
.vscode

# LaTeX files
*.tex

# LaTeX intermediate files
*.dvi
*.xdv
*-converted-to.*

# LaTeX auxiliary files
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync
*.alg
*.loa
*.thm
*.dpth
*.md5
*.auxlock

# LaTeX builds
*.pdf
127 changes: 127 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Python Algorithm Task Generator

This python program generates tasks written in LaTeX (in englisch and german) for various algorithms. Most algorithms are based upon Cormen, Leiserson, Rivest, Stein. Introduction to Algorithms 4ed. 2022. MIT Press. Its aim is to provide students learning these algorithms a way to execute them on different inputs and to ease the work on creating such exercises for educators, as it is often required for undergraduate algorithm courses.

## Requirements
- [python 3.8+](https://www.python.org)
- [pyaml](https://pypi.org/project/pyaml/) (for reading localisation files)
- [pylatex](https://pypi.org/project/PyLaTeX/) (for generating LaTeX code)
- [latexmk](https://ctan.org/pkg/latexmk) (for compiling LaTeX code)

## How to Run
Download the latest release, extract the files and execute python on the folder, e.g.

python3 pyAlgoTask TASK_CATEGORY TASK [optional Arguments]

Please not that you need to give at least the task category, the task and a file location for the exercise or for the solutuion for the program to do anything.

Alternatively you can locally install the program using

pip install ./pyAlgoTask

and using

pyAlgoTask TASK_CATEGORY TASK [optional Arguments]

in the commandline.

## How to Use
We specify ever task in a category. We currently support the following categories and tasks:

- Sorting
- Bubblesort
- Bucketsort (on numbers between 0 and 1)
- Countingsort
- Heapsort
- Insertionsort
- Mergesort
- Quicksort with Lomutos partition scheme
- Quicksort with Hoares partition scheme
- Radixsort (on non-negative numbers)
- Selectionsort

- Hashing
- Closed Hashing using double hashing
- Closed Hashing using linear probing
- Closed Hashing using quadratic probing
- Open Hashing

with the hash functions:
- Divison method (modulo table size)
- Multiplication method (scaling to table size)
- Bit-shift method

All tasks currently support only LaTeX output. You need to provide a file to write the source code into using parameters `-e` for exercise and `-s` for solution. Additionally you may use `--pdf` and `--view` to generate a pdf and directly view the pdf in a viewer respectively.

Generally, for input the parameters `-i` are used for commandline input and `-f` for file input. The syntax of the input is explained in the help files for each task. If no input is given, a random input is generated with certain heuristical bounds.

Further customization is possible and explained in the help for each task.

## Project Structure
This project is structured in five parts, the [Main part](#main-part), the [Tasks](#tasks), the [Inpud modules](#input), the [Randomizer modules](#randomizer) and the [Output modules](#output). Additionally, we use unittesting with [pytest](https://pytest.org/).

### Main part
The main class `src/pyAlgoTask/__man__` deals with reading the parser and calling all other modules. This includes error handling, to call the exporter `src/pyAlgoTask/export` for file export and allowing all tasks to register themself using the module `src/pyAlgoTask/tasks/tasks.py` and their argument parsers. Most modules have the possibility to register parser options themself (using [argparse](https://docs.python.org/3/library/argparse.html)) and to parse the parameter themself.

### Tasks
The folder `src/pyAlgoTask/tasks` contain one folder for each category, containing one file per task classes. Tasks classes handle the algorithm to generate a task for and the various modules surrounding this task. Theses are especially [Input Modules](#Input), [Randomizer Modules](#Randomizer), the language pick module `src/pyAlgoTask/language.py` and various data structures or wrapper classes from `src/pyAlgoTask/structures.py`.

#### Algorithm Method
The algorithm is implemented as a generator `def algorithm(self): ... `, that yields intermediate steps are required by the task. Usually, the generator yields a tuple, where the first entry is the actual output and the second are highlighting information, if used. The generator is called by the [Output Module](#Output) when the exercise and solution code is generated.

### Input
This module has various classes for handling various input types, e.g. arrays for sorting or insert/delete operations for data structures. They are generally assumes to register arguments to [argparse](https://docs.python.org/3/library/argparse.html) and to read them from argparse.

### Randomizer
Generally, every Input module also has a Randomizer module to generate a certain random input for in case no input was given. This design follows the parser-randomizer dualism.

### Output
Output modules are used to generate LaTeX code for certain types of tasks. Since tasks are rather diverse, so are their respective output modules. Generally speaking, the exercise file contains first some text, usually consisting of a pretext, the input for the algorithm, followed by a posttext. Lastly space for entering the solution is given. The space is roughly oriented on the solution, but sometimes a bit more space is given (i.e. for open hashing we offer sufficient place to insert every item at one position)

### Testing
The module `tests/...` offer various testing classes using [pytest](https://pytest.org/) with [mock](https://docs.python.org/3/library/unittest.mock.html). We use one testing file per category, where we try to test all algorithms in the same class similarly or even the same to enforce uniformity.

### Documentation
Documentation is designed for pydoctor using the command

pydoctor --make-html --html-output=docs/api --docformat=restructuredtext src/pyalgotask

in the root directory

## How to Contribute
Please open an issue if you found bugs or have feature requests. The feature requests may be added to the TODO file in this repository.

If you would like to contribute code, please use the following tools:

* pylint
* black formatter
* pydoctor
* pytest

And open an pull request detailing your contribution.

## Credits
This tool is developed by:
* Ira Fesefedt

## License
The MIT License (MIT)

Copyright (c) 2023 Ira Fesefeldt

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51 changes: 51 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[project]
name = "pyalgotask"
version = "0.1.0"
description = "Generates tasks for executing algorithms to better understand their innerworkings, as often used in algorithm classes."
authors = [
{name = "Ira Fesefeldt", email="[email protected]"}
]
maintainers = [
{name = "Ira Fesefeldt", email="[email protected]"}
]
license = {file = "LICENSE.txt"}
readme = "README.md"
requires-python = ">=3.8"

keywords = ["algorithm", "education", "tasks"]

classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Private :: Do Not Upload",
"Environment :: Console",
"Natural Language :: English",
"Topic :: Education :: Computer Aided Instruction (CAI)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
]

# Requirements: This is done differently by poetry!
dependencies = [
"PyLaTeX",
"pyaml"
]

#[project.urls]
#homepage = ""
#documentation = ""
#repository = ""

[project.scripts]
pyAlgoTask = "pyalgotask.__main__:main"

[tool.pytask.ini_options]
paths = "src/pyalgotask"
pythonpath = "src"

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
13 changes: 13 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Content of setup.cfg

[metadata]
name = pyalgotask
version = 0.1.0

[options]
packages = find:
package_dir =
=src

[options.packages.find]
where = src
1 change: 1 addition & 0 deletions src/pyalgotask/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""A module to generate tasks for various algorithms and datastructures"""
110 changes: 110 additions & 0 deletions src/pyalgotask/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""Main module for pyAlgoTask handling calling other classes and the general work flow."""
import argparse
import sys
import logging

import pyalgotask.__meta as meta
import pyalgotask.__settings as settings
import pyalgotask.tasks.task_base as task_base

from pyalgotask.export import Exporter

# let every task register itself
import pyalgotask.tasks # pylint: disable=unused-import


logging.basicConfig(level=settings.LOGGING_LEVEL)

logger = logging.getLogger(__name__)


def main():
"""Main method of the algorithm and is called when executing the program on the folder."""

# create argument parser
logger.debug("Creating argument parser.")
parser = argparse.ArgumentParser(
prog="pyAlgoEx",
description="Generates exercises for your typical algorithms course.",
epilog=(
"Choose an algorithm for which an exercise is generated.\n"
"If you choose no input method, a random input will be generated.\n"
"If you choose no output file path, the generated files will not be written anywhere."
),
)
parser.add_argument(
"-v",
"--version",
action="version",
version=f"%(prog)s {meta.__version__}",
)

exporter = Exporter()
subparser = parser.add_subparsers(title="Task categories", dest="cat")
subparser.metavar = ""
cat_parsers = {}

for cat in task_base.category_iterator():
(help_string, description) = task_base.get_category_info(cat)
cat_parser = subparser.add_parser(
cat, help=help_string, description=description
)
cat_parsers[cat] = cat_parser
cat_subparser = cat_parser.add_subparsers(dest="cmd")
for this_task in task_base.task_iterator(cat):
task_parser = cat_subparser.add_parser(
this_task.cmd_info.cmd,
help=this_task.cmd_info.help,
description=this_task.cmd_info.description,
)
exporter.init_parser(task_parser)
this_task.init_argument_parser(task_parser)

# parse arguments
logger.debug("Argument parser working.")
try:
args = parser.parse_args()
except ValueError as exception:
parser.error(exception)

# send help if no arguments present
if len(sys.argv) == 1:
parser.print_help()
sys.exit()

if not args.cat:
parser.error("No category given!")

if not args.cmd:
cat_parsers[args.cat].print_help()
sys.exit()

# get requested task
this_task = task_base.get_task_by_cmd(args.cat, args.cmd)
logger.debug("Selected task: %s %s", args.cat, args.cmd)

# parse arguments for task
try:
exporter.parse(args)
this_task.parse(args)
except ValueError as exception:
parser.error(str(exception))
logger.debug("Arguments parsed by task %s.", this_task.cmd_info.cmd)

# write exercise to file
logger.debug("Writing exercise.")
try:
exporter.write_exercise(this_task)
except ValueError as exception:
parser.error(str(exception))

# write solution to file
logger.debug("Writing solution.")
try:
exporter.write_solution(this_task)
except ValueError as exception:
parser.error(str(exception))


if __name__ == "__main__":
main()
11 changes: 11 additions & 0 deletions src/pyalgotask/__meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Various metadatas of this software."""

__author__ = "Ira Fesefeldt"
__credits__ = ["Ira Fesefeldt"]
__copyright__ = "Copyright 2023"

__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Ira Fesefeldt"
__email__ = "[email protected]"
__status__ = "Pre-Alpha"
6 changes: 6 additions & 0 deletions src/pyalgotask/__settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""File for settings used by this program"""
import logging

LOGGING_LEVEL = logging.ERROR

LANGUAGE = "deDE"
5 changes: 5 additions & 0 deletions src/pyalgotask/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Various exceptions used in this software"""


class WrongParameterError(Exception):
"""If the parameter from cli did not matched the expected side conditions"""
Loading

0 comments on commit a54cbf7

Please sign in to comment.