From fba834a617d2d2905cfc84595de100f8a5368c0a Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 6 Jun 2026 21:45:45 +0200 Subject: sort out scripts into proper directories --- .ci/plot.sh | 46 ------------------ .github/workflows/ci.yml | 2 +- algorithms/scripts/plot.py | 119 +++++++++++++++++++++++++++++++++++++++++++++ algorithms/scripts/test.py | 93 +++++++++++++++++++++++++++++++++++ plot.bat | 46 ------------------ plot.py | 119 --------------------------------------------- plot.sh | 49 ------------------- scripts/plot.bat | 47 ++++++++++++++++++ scripts/plot.sh | 50 +++++++++++++++++++ scripts/plot_all.sh | 46 ++++++++++++++++++ test.py | 93 ----------------------------------- 11 files changed, 356 insertions(+), 354 deletions(-) delete mode 100755 .ci/plot.sh create mode 100755 algorithms/scripts/plot.py create mode 100755 algorithms/scripts/test.py delete mode 100644 plot.bat delete mode 100755 plot.py delete mode 100755 plot.sh create mode 100644 scripts/plot.bat create mode 100755 scripts/plot.sh create mode 100755 scripts/plot_all.sh delete mode 100755 test.py diff --git a/.ci/plot.sh b/.ci/plot.sh deleted file mode 100755 index fee1166..0000000 --- a/.ci/plot.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2019 Egor Tensin -# This file is part of the "Sorting algorithms" project. -# For details, see https://github.com/egor-tensin/sorting-algorithms. -# Distributed under the MIT License. - -set -o errexit -o nounset -o pipefail -shopt -s inherit_errexit lastpipe - -script_dir="$( dirname -- "${BASH_SOURCE[0]}" )" -script_dir="$( cd -- "$script_dir" && pwd )" -readonly script_dir - -declare -a algorithm_list=( - bubble_sort - bubble_sort_optimized - heapsort - insertion_sort - merge_sort - quicksort_first - quicksort_last - quicksort_middle - quicksort_random - quicksort_second - selection_sort -) - -fix_matplotlib() { - # Get rid of: - # tkinter.TclError: no display name and no $DISPLAY environment variable - mkdir -p -- ~/.config/matplotlib - echo 'backend: Agg' > ~/.config/matplotlib/matplotlibrc -} - -main() { - fix_matplotlib - - local algorithm - for algorithm in ${algorithm_list[@]+"${algorithm_list[@]}"}; do - echo "Plotting algorithm $algorithm..." - "$script_dir/../plot.sh" "$algorithm" - done -} - -main "$@" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 066e684..4f01a7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,4 +24,4 @@ jobs: - name: Install dependencies run: pip install -r requirements.txt - name: Run tests - run: ./.ci/plot.sh + run: ./scripts/plot_all.sh diff --git a/algorithms/scripts/plot.py b/algorithms/scripts/plot.py new file mode 100755 index 0000000..bb441e1 --- /dev/null +++ b/algorithms/scripts/plot.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2015 Egor Tensin +# This file is part of the "Sorting algorithms" project. +# For details, see https://github.com/egor-tensin/sorting-algorithms. +# Distributed under the MIT License. + +import argparse +import sys + +from ..input_kind import InputKind +from ..params import AlgorithmParameters +from .. import registry + + +_DEFAULT_ITERATIONS = 100 +_DEFAULT_INPUT_KIND = InputKind.AVERAGE +_DEFAULT_MIN_LENGTH = 0 +_DEFAULT_MAX_LENGTH = 200 + + +def plot_algorithm(algorithm, input_kind=_DEFAULT_INPUT_KIND, + min_len=_DEFAULT_MIN_LENGTH, + max_len=_DEFAULT_MAX_LENGTH, + iterations=_DEFAULT_ITERATIONS, + output_path=None): + + if isinstance(algorithm, str): + algorithm = registry.get(algorithm) + + params = AlgorithmParameters(algorithm, min_len, max_len, + input_kind=input_kind, + iterations=iterations) + params.plot_running_time(output_path) + + +def _parse_non_negative_integer(s): + try: + n = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + str(s)) + if n < 0: + raise argparse.ArgumentTypeError('must be a non-negative integer') + return n + + +def _parse_positive_integer(s): + try: + n = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a positive integer: ' + str(s)) + if n < 1: + raise argparse.ArgumentTypeError('must be a positive integer') + return n + + +def _parse_input_kind(s): + try: + return InputKind(s) + except ValueError: + raise argparse.ArgumentTypeError('invalid input kind: ' + str(s)) + + +def _format_algorithm(codename): + return '* {}: {}'.format(codename, registry.get(codename).display_name) + + +def _format_available_algorithms(): + descr = 'available algorithms (in the CODENAME: DISPLAY_NAME format):\n' + return descr + '\n'.join(map( + _format_algorithm, sorted(registry.get_codenames()))) + + +def _format_description(): + return _format_available_algorithms() + + +def _create_argument_parser(): + return argparse.ArgumentParser( + description=_format_description(), + formatter_class=argparse.RawDescriptionHelpFormatter) + + +def _parse_args(args=None): + if args is None: + args = sys.argv[1:] + parser = _create_argument_parser() + + parser.add_argument('algorithm', metavar='CODENAME', + choices=registry.get_codenames(), + help='algorithm codename') + parser.add_argument('--iterations', '-r', metavar='N', + type=_parse_positive_integer, + default=_DEFAULT_ITERATIONS, + help='set number of algorithm iterations') + parser.add_argument('--input', '-i', dest='input_kind', + choices=InputKind, + type=_parse_input_kind, default=_DEFAULT_INPUT_KIND, + help='specify input kind') + parser.add_argument('--min', '-a', metavar='N', dest='min_len', + type=_parse_non_negative_integer, + default=_DEFAULT_MIN_LENGTH, + help='set min input length') + parser.add_argument('--max', '-b', metavar='N', dest='max_len', + type=_parse_non_negative_integer, + default=_DEFAULT_MAX_LENGTH, + help='set max input length') + parser.add_argument('--output', '-o', metavar='PATH', dest='output_path', + help='set plot file path') + + return parser.parse_args(args) + + +def main(args=None): + plot_algorithm(**vars(_parse_args(args))) + + +if __name__ == '__main__': + main() diff --git a/algorithms/scripts/test.py b/algorithms/scripts/test.py new file mode 100755 index 0000000..ba7bf0a --- /dev/null +++ b/algorithms/scripts/test.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2016 Egor Tensin +# This file is part of the "Sorting algorithms" project. +# For details, see https://github.com/egor-tensin/sorting-algorithms. +# Distributed under the MIT License. + +from array import array +import argparse +import sys + +from ..input_kind import InputKind +import ..registry as registry + + +_DEFAULT_INPUT_KIND = InputKind.AVERAGE +_DEFAULT_LENGTH = 100 + + +def test(algorithm, input_kind=_DEFAULT_INPUT_KIND, length=_DEFAULT_LENGTH): + if isinstance(algorithm, str): + algorithm = registry.get(algorithm) + xs = algorithm.gen_input(length, input_kind) + output = algorithm.function(xs) + if isinstance(output, array): + output = output.tolist() + print(output) + + +def _parse_non_negative_integer(s): + try: + n = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + str(s)) + if n < 0: + raise argparse.ArgumentTypeError('must be a non-negative integer') + return n + + +def _parse_input_kind(s): + try: + return InputKind(s) + except ValueError: + raise argparse.ArgumentTypeError('invalid input kind: ' + str(s)) + + +def _format_algorithm(codename): + return '* {}: {}'.format(codename, registry.get(codename).display_name) + + +def _format_available_algorithms(): + descr = 'available algorithms (in the CODENAME: DISPLAY_NAME format):\n' + return descr + '\n'.join(map( + _format_algorithm, sorted(registry.get_codenames()))) + + +def _format_description(): + return _format_available_algorithms() + + +def _create_argument_parser(): + return argparse.ArgumentParser( + description=_format_description(), + formatter_class=argparse.RawDescriptionHelpFormatter) + + +def _parse_args(args=None): + if args is None: + args = sys.argv[1:] + parser = _create_argument_parser() + + parser.add_argument('algorithm', metavar='CODENAME', + choices=registry.get_codenames(), + help='algorithm codename') + parser.add_argument('--input', '-i', dest='input_kind', + choices=InputKind, + type=_parse_input_kind, + default=_DEFAULT_INPUT_KIND, + help='specify input kind') + parser.add_argument('--length', '-l', '-n', metavar='N', + type=_parse_non_negative_integer, + default=_DEFAULT_LENGTH, + help='set input length') + + return parser.parse_args(args) + + +def main(args=None): + test(**vars(_parse_args(args))) + + +if __name__ == '__main__': + main() diff --git a/plot.bat b/plot.bat deleted file mode 100644 index 3a2f22d..0000000 --- a/plot.bat +++ /dev/null @@ -1,46 +0,0 @@ -@rem Copyright (c) 2015 Egor Tensin -@rem This file is part of the "Sorting algorithms" project. -@rem For details, see https://github.com/egor-tensin/sorting-algorithms. -@rem Distributed under the MIT License. - -@setlocal enabledelayedexpansion -@echo off - -set default_iterations=100 -set default_min=0 -set default_max=200 - -if "%~1" == "" goto :exit_with_usage -set "algorithm=%~1" - -if "%~2" == "" ( - set "iterations=%default_iterations%" -) else ( - set "iterations=%~2" -) -if "%~3" == "" ( - set "min=%default_min%" -) else ( - set "min=%~3" -) -if "%~4" == "" ( - set "max=%default_max%" -) else ( - set "max=%~4" -) - -mkdir /p img - -for %%i in (best average worst) do ( - plot.py "%algorithm%" ^ - --input "%%i" ^ - --min "%min%" --max "%max%" ^ - --iterations "%iterations%" ^ - --output "img\%algorithm%_%iterations%_%%i_%min%_%max%.png" || exit /b !errorlevel! -) - -exit /b 0 - -:exit_with_usage: -echo Usage: %~nx0 ALGORITHM [ITERATIONS [MIN_VALUE [MAX_VALUE]]] -exit /b 1 diff --git a/plot.py b/plot.py deleted file mode 100755 index 5105e5f..0000000 --- a/plot.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015 Egor Tensin -# This file is part of the "Sorting algorithms" project. -# For details, see https://github.com/egor-tensin/sorting-algorithms. -# Distributed under the MIT License. - -import argparse -import sys - -from algorithms.input_kind import InputKind -from algorithms.params import AlgorithmParameters -import algorithms.registry as registry - - -_DEFAULT_ITERATIONS = 100 -_DEFAULT_INPUT_KIND = InputKind.AVERAGE -_DEFAULT_MIN_LENGTH = 0 -_DEFAULT_MAX_LENGTH = 200 - - -def plot_algorithm(algorithm, input_kind=_DEFAULT_INPUT_KIND, - min_len=_DEFAULT_MIN_LENGTH, - max_len=_DEFAULT_MAX_LENGTH, - iterations=_DEFAULT_ITERATIONS, - output_path=None): - - if isinstance(algorithm, str): - algorithm = registry.get(algorithm) - - params = AlgorithmParameters(algorithm, min_len, max_len, - input_kind=input_kind, - iterations=iterations) - params.plot_running_time(output_path) - - -def _parse_non_negative_integer(s): - try: - n = int(s) - except ValueError: - raise argparse.ArgumentTypeError('must be a non-negative integer: ' + str(s)) - if n < 0: - raise argparse.ArgumentTypeError('must be a non-negative integer') - return n - - -def _parse_positive_integer(s): - try: - n = int(s) - except ValueError: - raise argparse.ArgumentTypeError('must be a positive integer: ' + str(s)) - if n < 1: - raise argparse.ArgumentTypeError('must be a positive integer') - return n - - -def _parse_input_kind(s): - try: - return InputKind(s) - except ValueError: - raise argparse.ArgumentTypeError('invalid input kind: ' + str(s)) - - -def _format_algorithm(codename): - return '* {}: {}'.format(codename, registry.get(codename).display_name) - - -def _format_available_algorithms(): - descr = 'available algorithms (in the CODENAME: DISPLAY_NAME format):\n' - return descr + '\n'.join(map( - _format_algorithm, sorted(registry.get_codenames()))) - - -def _format_description(): - return _format_available_algorithms() - - -def _create_argument_parser(): - return argparse.ArgumentParser( - description=_format_description(), - formatter_class=argparse.RawDescriptionHelpFormatter) - - -def _parse_args(args=None): - if args is None: - args = sys.argv[1:] - parser = _create_argument_parser() - - parser.add_argument('algorithm', metavar='CODENAME', - choices=registry.get_codenames(), - help='algorithm codename') - parser.add_argument('--iterations', '-r', metavar='N', - type=_parse_positive_integer, - default=_DEFAULT_ITERATIONS, - help='set number of algorithm iterations') - parser.add_argument('--input', '-i', dest='input_kind', - choices=InputKind, - type=_parse_input_kind, default=_DEFAULT_INPUT_KIND, - help='specify input kind') - parser.add_argument('--min', '-a', metavar='N', dest='min_len', - type=_parse_non_negative_integer, - default=_DEFAULT_MIN_LENGTH, - help='set min input length') - parser.add_argument('--max', '-b', metavar='N', dest='max_len', - type=_parse_non_negative_integer, - default=_DEFAULT_MAX_LENGTH, - help='set max input length') - parser.add_argument('--output', '-o', metavar='PATH', dest='output_path', - help='set plot file path') - - return parser.parse_args(args) - - -def main(args=None): - plot_algorithm(**vars(_parse_args(args))) - - -if __name__ == '__main__': - main() diff --git a/plot.sh b/plot.sh deleted file mode 100755 index 60bad3a..0000000 --- a/plot.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2019 Egor Tensin -# This file is part of the "Sorting algorithms" project. -# For details, see https://github.com/egor-tensin/sorting-algorithms. -# Distributed under the MIT License. - -set -o errexit -o nounset -o pipefail -shopt -s inherit_errexit lastpipe - -script_dir="$( dirname -- "${BASH_SOURCE[0]}" )" -script_dir="$( cd -- "$script_dir" && pwd )" -readonly script_dir -script_name="$( basename -- "${BASH_SOURCE[0]}" )" -readonly script_name - -readonly default_iterations=100 -readonly default_min=0 -readonly default_max=200 - -main() { - if [ "$#" -lt 1 ] || [ "$#" -gt 4 ]; then - echo "usage: $script_name ALGORITHM [ITERATIONS [MIN_VALUE [MAX_VALUE]]]" >&2 - exit 1 - fi - - local algorithm="$1" - local iterations="$default_iterations" - [ "$#" -ge 2 ] && iterations="$2" - local min="$default_min" - [ "$#" -ge 3 ] && min="$3" - local max="$default_max" - [ "$#" -ge 4 ] && max="$4" - - mkdir -p -- "$script_dir/img" - - local input_kind - for input_kind in best average worst; do - local output_name="${algorithm}_${iterations}_${input_kind}_${min}_${max}.png" - python "$script_dir/plot.py" \ - "$algorithm" \ - --input "$input_kind" \ - --min "$min" --max "$max" \ - --iterations "$iterations" \ - --output "$script_dir/img/$output_name" - done -} - -main "$@" diff --git a/scripts/plot.bat b/scripts/plot.bat new file mode 100644 index 0000000..c76c43a --- /dev/null +++ b/scripts/plot.bat @@ -0,0 +1,47 @@ +@rem Copyright (c) 2015 Egor Tensin +@rem This file is part of the "Sorting algorithms" project. +@rem For details, see https://github.com/egor-tensin/sorting-algorithms. +@rem Distributed under the MIT License. + +@setlocal enabledelayedexpansion +@echo off + +set default_iterations=100 +set default_min=0 +set default_max=200 + +if "%~1" == "" goto :exit_with_usage +set "algorithm=%~1" + +if "%~2" == "" ( + set "iterations=%default_iterations%" +) else ( + set "iterations=%~2" +) +if "%~3" == "" ( + set "min=%default_min%" +) else ( + set "min=%~3" +) +if "%~4" == "" ( + set "max=%default_max%" +) else ( + set "max=%~4" +) + +cd .. +mkdir /p img + +for %%i in (best average worst) do ( + plot.py "%algorithm%" ^ + --input "%%i" ^ + --min "%min%" --max "%max%" ^ + --iterations "%iterations%" ^ + --output "img\%algorithm%_%iterations%_%%i_%min%_%max%.png" || exit /b !errorlevel! +) + +exit /b 0 + +:exit_with_usage: +echo Usage: %~nx0 ALGORITHM [ITERATIONS [MIN_VALUE [MAX_VALUE]]] +exit /b 1 diff --git a/scripts/plot.sh b/scripts/plot.sh new file mode 100755 index 0000000..d310dcd --- /dev/null +++ b/scripts/plot.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# Copyright (c) 2019 Egor Tensin +# This file is part of the "Sorting algorithms" project. +# For details, see https://github.com/egor-tensin/sorting-algorithms. +# Distributed under the MIT License. + +set -o errexit -o nounset -o pipefail +shopt -s inherit_errexit lastpipe + +script_dir="$( dirname -- "${BASH_SOURCE[0]}" )" +script_dir="$( cd -- "$script_dir" && pwd )" +readonly script_dir +script_name="$( basename -- "${BASH_SOURCE[0]}" )" +readonly script_name + +readonly default_iterations=100 +readonly default_min=0 +readonly default_max=200 + +main() { + if [ "$#" -lt 1 ] || [ "$#" -gt 4 ]; then + echo "usage: $script_name ALGORITHM [ITERATIONS [MIN_VALUE [MAX_VALUE]]]" >&2 + exit 1 + fi + + local algorithm="$1" + local iterations="$default_iterations" + [ "$#" -ge 2 ] && iterations="$2" + local min="$default_min" + [ "$#" -ge 3 ] && min="$3" + local max="$default_max" + [ "$#" -ge 4 ] && max="$4" + + cd -- "$script_dir/.." + mkdir -p -- img + + local input_kind + for input_kind in best average worst; do + local output_name="${algorithm}_${iterations}_${input_kind}_${min}_${max}.png" + python -m algorithms.scripts.plot \ + "$algorithm" \ + --input "$input_kind" \ + --min "$min" --max "$max" \ + --iterations "$iterations" \ + --output "img/$output_name" + done +} + +main "$@" diff --git a/scripts/plot_all.sh b/scripts/plot_all.sh new file mode 100755 index 0000000..1e56f40 --- /dev/null +++ b/scripts/plot_all.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Copyright (c) 2019 Egor Tensin +# This file is part of the "Sorting algorithms" project. +# For details, see https://github.com/egor-tensin/sorting-algorithms. +# Distributed under the MIT License. + +set -o errexit -o nounset -o pipefail +shopt -s inherit_errexit lastpipe + +script_dir="$( dirname -- "${BASH_SOURCE[0]}" )" +script_dir="$( cd -- "$script_dir" && pwd )" +readonly script_dir + +declare -a algorithm_list=( + bubble_sort + bubble_sort_optimized + heapsort + insertion_sort + merge_sort + quicksort_first + quicksort_last + quicksort_middle + quicksort_random + quicksort_second + selection_sort +) + +fix_matplotlib() { + # Get rid of: + # tkinter.TclError: no display name and no $DISPLAY environment variable + mkdir -p -- ~/.config/matplotlib + echo 'backend: Agg' > ~/.config/matplotlib/matplotlibrc +} + +main() { + fix_matplotlib + + local algorithm + for algorithm in ${algorithm_list[@]+"${algorithm_list[@]}"}; do + echo "Plotting algorithm $algorithm..." + "$script_dir/plot.sh" "$algorithm" + done +} + +main "$@" diff --git a/test.py b/test.py deleted file mode 100755 index b03bf88..0000000 --- a/test.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2016 Egor Tensin -# This file is part of the "Sorting algorithms" project. -# For details, see https://github.com/egor-tensin/sorting-algorithms. -# Distributed under the MIT License. - -from array import array -import argparse -import sys - -from algorithms.input_kind import InputKind -import algorithms.registry as registry - - -_DEFAULT_INPUT_KIND = InputKind.AVERAGE -_DEFAULT_LENGTH = 100 - - -def test(algorithm, input_kind=_DEFAULT_INPUT_KIND, length=_DEFAULT_LENGTH): - if isinstance(algorithm, str): - algorithm = registry.get(algorithm) - xs = algorithm.gen_input(length, input_kind) - output = algorithm.function(xs) - if isinstance(output, array): - output = output.tolist() - print(output) - - -def _parse_non_negative_integer(s): - try: - n = int(s) - except ValueError: - raise argparse.ArgumentTypeError('must be a non-negative integer: ' + str(s)) - if n < 0: - raise argparse.ArgumentTypeError('must be a non-negative integer') - return n - - -def _parse_input_kind(s): - try: - return InputKind(s) - except ValueError: - raise argparse.ArgumentTypeError('invalid input kind: ' + str(s)) - - -def _format_algorithm(codename): - return '* {}: {}'.format(codename, registry.get(codename).display_name) - - -def _format_available_algorithms(): - descr = 'available algorithms (in the CODENAME: DISPLAY_NAME format):\n' - return descr + '\n'.join(map( - _format_algorithm, sorted(registry.get_codenames()))) - - -def _format_description(): - return _format_available_algorithms() - - -def _create_argument_parser(): - return argparse.ArgumentParser( - description=_format_description(), - formatter_class=argparse.RawDescriptionHelpFormatter) - - -def _parse_args(args=None): - if args is None: - args = sys.argv[1:] - parser = _create_argument_parser() - - parser.add_argument('algorithm', metavar='CODENAME', - choices=registry.get_codenames(), - help='algorithm codename') - parser.add_argument('--input', '-i', dest='input_kind', - choices=InputKind, - type=_parse_input_kind, - default=_DEFAULT_INPUT_KIND, - help='specify input kind') - parser.add_argument('--length', '-l', '-n', metavar='N', - type=_parse_non_negative_integer, - default=_DEFAULT_LENGTH, - help='set input length') - - return parser.parse_args(args) - - -def main(args=None): - test(**vars(_parse_args(args))) - - -if __name__ == '__main__': - main() -- cgit v1.3