diff --git a/.gitignore b/.gitignore index 080718f9..bff4fb3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +doc/_build +doc/generated +doc/source/reference/generated/ .DS_Store* MANIFEST dist/ @@ -12,3 +15,4 @@ build.log *~ setup.cfg _skbuild + diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 00000000..747ffb7b --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 00000000..544739b5 --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,12 @@ +sphinx>=7.2.6 +numpy +scipy +pandas +matplotlib +matplotlib_venn +sphinx_rtd_theme>=2.0.0 +numpydoc +ipykernel +nbsphinx +docutils +#docutils==0.16 # pin until sphinx_rtd_theme is compatible with 0.17 or later diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 00000000..3c1eb275 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,50 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +import os +import sys +sys.path.insert(0, os.path.abspath('../slycot')) + +master_doc = "index" +from datetime import date +project = 'Slycot' +copyright = f'{date.today().year}, Slycot Developers' +author = 'Slycot Developers' + +# Version information - read from the source code +import re + +# Get the version number for this commmit (including alpha/beta/rc tags) +release = re.sub('^v', '', os.popen('git describe').read().strip()) + +# The short X.Y.Z version +version = re.sub(r'(\d+\.\d+\.\d+(.post\d+)?)(.*)', r'\1', release) + +print("version %s, release %s" % (version, release)) + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.napoleon', + 'sphinx.ext.intersphinx', 'sphinx.ext.imgmath', + 'sphinx.ext.autosummary', 'nbsphinx', 'numpydoc', + 'sphinx.ext.doctest' +] +# scan documents for autosummary directives and generate stub pages for each. +autosummary_generate = True + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] diff --git a/doc/source/contributing/index.rst b/doc/source/contributing/index.rst new file mode 100644 index 00000000..e1ccbbf0 --- /dev/null +++ b/doc/source/contributing/index.rst @@ -0,0 +1,30 @@ +.. this page is referenced from the front page but it's unnecessary as a navigation section for now. + +:orphan: + +Contributing to Slycot +====================== + +Development process and tools +----------------------------- + +The development process is currently described on the `slycot github repo `_ and the `slycot github wiki `_. +You should be familiar with following topics: + +- `git `_ +- `github `_ +- `Sphinx `_ +- `reStructuredText `_ +- `numpydoc `_ +- `f2py `_ + +numpydoc +-------- + +Slycot uses numpydoc for the docstring style in order to provide support the Numpy docstring format in sphinx, +`see numpydoc example `_. + +F2PY +---- + +Slycot heavily relias on `F2PY `_, which is currently a part of `NumPy `_. \ No newline at end of file diff --git a/doc/source/explanation/index.rst b/doc/source/explanation/index.rst new file mode 100644 index 00000000..dec31068 --- /dev/null +++ b/doc/source/explanation/index.rst @@ -0,0 +1,12 @@ +.. this page is referenced from the front page but it's unnecessary as a navigation section for now. + +:orphan: + +Inspect +======= + +.. toctree:: + :maxdepth: 1 + + inspect_slycot + inspect_slicot_slycot diff --git a/doc/source/explanation/inspect_slicot_slycot.ipynb b/doc/source/explanation/inspect_slicot_slycot.ipynb new file mode 100644 index 00000000..9e895712 --- /dev/null +++ b/doc/source/explanation/inspect_slicot_slycot.ipynb @@ -0,0 +1,694 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect Slycot vs SLICOT" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook shows how to inspect the slycot module and the slicot libary.\n", + "The result gives us a insight which slicot routines are implemented slycot." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.5.5.dev75+g8cd8497'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import re\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib_venn import venn2\n", + "\n", + "import slycot\n", + "slycot.__version__" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper function" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def print_list_chunks(routines_list, n=8):\n", + " \"\"\"Print list in chunks of lists.\"\"\"\n", + " start = 0\n", + " end = len(routines_list)\n", + " step = n\n", + " for i in range(start, end, step):\n", + " x = i\n", + " print(routines_list[x:x+step])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def get_slycot_routines(sly):\n", + " all_attributes = dir(sly)\n", + " r = re.compile(\"[a-z][a-z][0-9][0-9a-z][a-z][a-z]\")\n", + " matched_attributes = list(filter(r.match, all_attributes)) # Read Note below\n", + " return matched_attributes" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inspect function" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 56 routines that are found in slycot.\n", + "------\n", + "['ab01nd', 'ab04md', 'ab05md', 'ab05nd', 'ab07nd', 'ab08nd', 'ab08nz', 'ab09ad']\n", + "['ab09ax', 'ab09bd', 'ab09md', 'ab09nd', 'ab13bd', 'ab13dd', 'ab13ed', 'ab13fd']\n", + "['ab13md', 'ag08bd', 'mb02ed', 'mb03rd', 'mb03vd', 'mb03vy', 'mb03wd', 'mb05md']\n", + "['mb05nd', 'mc01td', 'sb01bd', 'sb02md', 'sb02mt', 'sb02od', 'sb03md', 'sb03md57']\n", + "['sb03od', 'sb04md', 'sb04qd', 'sb10ad', 'sb10dd', 'sb10fd', 'sb10hd', 'sb10jd']\n", + "['sb10yd', 'sg02ad', 'sg03ad', 'sg03bd', 'tb01id', 'tb01pd', 'tb03ad', 'tb04ad']\n", + "['tb05ad', 'tc01od', 'tc04ad', 'td04ad', 'tf01md', 'tf01rd', 'tg01ad', 'tg01fd']\n", + "None\n", + "\n", + "\n", + "There are currently 607 routines that are found in slicot.\n", + "------\n", + "['mb01wd', 'tg01gd', 'ab13fd', 'sg03ay', 'mb01oe', 'mb02fd', 'tg01oa', 'dg01ny']\n", + "['sg03ax', 'fb01qd', 'ma02az', 'mc01md', 'md03by', 'tf01mx', 'ib01nd', 'mb02rz']\n", + "['mb04bp', 'tb01kd', 'ab09gd', 'ma02jz', 'ud01cd', 'ib01rd', 'nf01bx', 'mb02rd']\n", + "['ma02es', 'mb04iy', 'tg01id', 'mb01rd', 'mc01xd', 'mb04wr', 'sg03bs', 'mb03kc']\n", + "['ma02cd', 'tb04ad', 'md03bx', 'mb03vy', 'ab09cd', 'tf01nd', 'sb09md', 'sb03ot']\n", + "['mb04pu', 'mb04yd', 'mb02pd', 'mb04tu', 'mb02ud', 'ib01cd', 'mb04dp', 'tg01fz']\n", + "['sb04od', 'nf01ad', 'mb03qd', 'ab09bd', 'mb02jd', 'sb02mw', 'ma02ad', 'mb04dl']\n", + "['sb08ed', 'tb01uy', 'md03ba', 'ab05nd', 'mb03pd', 'sb02mx', 'sb04ow', 'ma02mz']\n", + "['mb02cy', 'ag08by', 'mb03bb', 'ab09cx', 'mb01kd', 'sb02sd', 'mb01xd', 'sb01md']\n", + "['mb02ny', 'sb02ox', 'sb10pd', 'ma01cd', 'tg01hd', 'mb02nd', 'sb02cx', 'sb04px']\n", + "['mb03qg', 'tg01hx', 'mb03ag', 'mc01py', 'mb03kb', 'mb04jd', 'tg01bd', 'tb03ay']\n", + "['ab13ed', 'sb03rd', 'ma02id', 'ma02md', 'sb03os', 'mb02cv', 'mb05oy', 'sb06nd']\n", + "['nf01bp', 'sb02od', 'mb03md', 'fb01vd', 'ma02iz', 'tb01ld', 'mb02sd', 'tb01nd']\n", + "['ud01md', 'mb02xd', 'mb02md', 'sg03br', 'mb04az', 'sb02ru', 'sb10qd', 'sg03bu']\n", + "['sb04qr', 'mb03lf', 'ma01ad', 'sb04rd', 'ma02gd', 'sb04ry', 'ab13ad', 'ab13md']\n", + "['nf01by', 'mb04nd', 'mb03yt', 'sg02cx', 'tg01hu', 'ab09kx', 'mb04hd', 'mb03gd']\n", + "['sb08cd', 'mb03od', 'sb04mr', 'mb02kd', 'ab09jx', 'ud01bd', 'fb01sd', 'mb03rd']\n", + "['ab07nd', 'mb03fd', 'sb03ou', 'mb03ya', 'mb01rh', 'sb08hd', 'ab08nw', 'ab07md']\n", + "['ab05qd', 'mb02qy', 'mb03id', 'ma02bd', 'ma02dd', 'mb04ed', 'sb03td', 'mb04tv']\n", + "['td04ad', 'tb01ud', 'tc01od', 'nf01bs', 'ma02oz', 'sg02nd', 'mb04ru', 'mc01rd']\n", + "['mb03bd', 'mb04tt', 'sb08ny', 'tg01ad', 'sb04qu', 'nf01bf', 'tg01qd', 'mc01td']\n", + "['mb04fp', 'mb03ud', 'mb3lzp', 'sb04nv', 'mb04qb', 'mb04wp', 'mc01sy', 'sb10dd']\n", + "['mb02sz', 'mb04kd', 'tb04bw', 'mb01ry', 'sb03mv', 'tb03ad', 'mb03gz', 'mb01ot']\n", + "['mb03be', 'tb01zd', 'ab04md', 'mb01os', 'sb03qx', 'mb04pb', 'nf01bu', 'mb04su']\n", + "['mc01od', 'sb16bd', 'mb02td', 'sg03ad', 'sb03qy', 'mb03xs', 'md03bb', 'mb04qc']\n", + "['mb03jd', 'sb01by', 'ab09nd', 'sb03md', 'mb04oy', 'mb05nd', 'ab08nx', 'mb01rb']\n", + "['dg01md', 'mb02wd', 'sb03ud', 'mb03py', 'mc01pd', 'ma02pz', 'ab09iy', 'ma02od']\n", + "['sb10td', 'tf01my', 'sb16cy', 'tg01oz', 'ab05pd', 'mb04cd', 'sb16ay', 'sb10hd']\n", + "['mb02gd', 'mc03md', 'mb03bc', 'sb04nx', 'mc01qd', 'ab01od', 'ab09jd', 'sb16ad']\n", + "['sg03bv', 'nf01bb', 'ab09dd', 'mb03lp', 'md03bf', 'mb03ah', 'mb3jzp', 'sb04mu']\n", + "['ab09kd', 'sb03ov', 'sb03pd', 'fd01ad', 'sb03sd', 'td05ad', 'mb02hd', 'mb02cd']\n", + "['mb03qx', 'sb04nd', 'mb04tb', 'sb04pd', 'tg01jy', 'tb04cd', 'tg01dd', 'ab09ed']\n", + "['mb03wx', 'tg01pd', 'tf01pd', 'sb08fd', 'ab13ax', 'nf01ba', 'sb08md', 'mb04dy']\n", + "['sb04my', 'ab09fd', 'mb04vd', 'mb01md', 'ib01oy', 'mb04ld', 'sb01bd', 'sb02mu']\n", + "['sg03bx', 'tg01ed', 'mb02qd', 'mb01ss', 'mb01rw', 'sb10ud', 'mb03cz', 'ag8byz']\n", + "['sb02ow', 'mb02dd', 'sb08nd', 'mb03my', 'mb03yd', 'tg01od', 'mc01sw', 'ma02bz']\n", + "['ib01ad', 'ab09hd', 'ud01mz', 'td03ad', 'sb03my', 'ib03bd', 'mb04dd', 'mb04xd']\n", + "['ma02hd', 'ab09ax', 'tg01hy', 'mc01sx', 'tb01ux', 'df01md', 'mb04vx', 'mb04wd']\n", + "['ab08md', 'tb01vd', 'nf01ay', 'md03bd', 'mb03rz', 'ab09ix', 'ab13dd', 'tb01iz']\n", + "['nf01bw', 'mb04qf', 'ab05sd', 'mb04db', 'mb03ai', 'sb08gd', 'mb02od', 'mb04ty']\n", + "['mb02uv', 'ib01px', 'tb01ty', 'sb03oy', 'sb03mu', 'tg01nd', 'ab09hx', 'ab09id']\n", + "['mb04id', 'mb03ed', 'mb04di', 'mb04tx', 'sb03od', 'mb04xy', 'mb03hz', 'tc04ad']\n", + "['mb01rx', 'sb02ov', 'mb03zd', 'mb03jp', 'mb02yd', 'mb04ox', 'bd01ad', 'mb04fd']\n", + "['ab05md', 'tb04bx', 'dg01od', 'sb10zd', 'mb01rt', 'sb02mr', 'ab01nd', 'mb04bz']\n", + "['ma01bz', 'ma02ed', 'mb03ld', 'tb01md', 'tb01xz', 'mb04qs', 'ab09md', 'sb10id']\n", + "['sb03sx', 'mb02cu', 'ab13bd', 'mb3oyz', 'mb02tz', 'tb01px', 'mb03iz', 'sg03bw']\n", + "['mb04dz', 'nf01bv', 'bd02ad', 'tf01md', 'mb03wd', 'mb4dbz', 'mb04tw', 'mb03vd']\n", + "['mb01oo', 'fb01rd', 'mb04rb', 'mb03ry', 'mb01xy', 'tb05ad', 'ib03ad', 'mb03xz']\n", + "['mb05md', 'mb02ed', 'sb03mw', 'sg03bd', 'mb01ru', 'mb01oc', 'bb02ad', 'ab09jw']\n", + "['mb03cd', 'mb04pa', 'sb10yd', 'mb02jx', 'tg01az', 'sg02ad', 'ma02hz', 'mb03dz']\n", + "['tg01md', 'sb08my', 'tb04ay', 'sb02nd', 'sb02mt', 'sb04rw', 'mb04wu', 'nf01be']\n", + "['de01pd', 'sb02mv', 'sb10ed', 'sb10zp', 'mb03lz', 'sb02oy', 'sb04md', 'mb03bg']\n", + "['mb03ad', 'mb01uw', 'sb10kd', 'ma02jd', 'ma02gz', 'tf01qd', 'mb03td', 'mb04gd']\n", + "['tb04bv', 'tg01ld', 'mb03ba', 'ue01md', 'mb3pyz', 'mb03xp', 'sb02ou', 'mb01nd']\n", + "['sg02cw', 'mb04yw', 'sb04mw', 'mb01uy', 'sg03by', 'ib01py', 'mb02uw', 'tg01ob']\n", + "['mb03jz', 'mb04ad', 'tg01fd', 'mb03sd', 'ab13id', 'ab08ny', 'mb03za', 'mb02uu']\n", + "['ab08nd', 'mc01wd', 'tg01ly', 'mb01uz', 'mb03xu', 'mb03nd', 'ag07bd', 'sg03bt']\n", + "['mb03xd', 'ma02nz', 'ab13dx', 'ab08nz', 'sb04ny', 'mb03ts', 'sb04qy', 'mb03rx']\n", + "['mb03af', 'ib01md', 'mb03ke', 'sb02pd', 'sb16cd', 'ab8nxz', 'mb04bd', 'tf01rd']\n", + "['mb01ux', 'mb03bz', 'sb03sy', 'mc03ny', 'sb10ld', 'ma02fd', 'td03ay', 'bb04ad']\n", + "['mb03ab', 'dk01md', 'ab05od', 'mc03nx', 'mb01td', 'tb01id', 'tg01cd', 'mb04ow']\n", + "['sb04nw', 'mb03ae', 'mb03rw', 'mb03qy', 'sb04py', 'nf01bq', 'mb03dd', 'tb01kx']\n", + "['mb01ud', 'ma01bd', 'mb03ny', 'ab08mz', 'sb02rd', 'sb04qd', 'tb01wx', 'ag08bz']\n", + "['tg01wd', 'tb04bd', 'sb02md', 'bb01ad', 'mc01sd', 'mc01vd', 'sb10ad', 'mb01vd']\n", + "['de01od', 'ib01pd', 'mb03bf', 'sb02ms', 'mb04py', 'mc03nd', 'tb01wd', 'mc01nd']\n", + "['dg01nd', 'ab09ad', 'mb02id', 'tb01yd', 'sb03mx', 'mb03vw', 'sg02cv', 'ab05rd']\n", + "['mb04ds', 'mb01od', 'mb4dpz', 'mb03oy', 'sb03qd', 'sb01bx', 'sb08dd', 'ib01od']\n", + "['sb10md', 'mb01ld', 'mb04iz', 'mb05od', 'tb01td', 'mb02vd', 'mb03fz', 'mb05my']\n", + "['mb01oh', 'mb04zd', 'sb03oz', 'tg01kz', 'mb02cx', 'tg01jd', 'mb01zd', 'mb01pd']\n", + "['sb01dd', 'mb03hd', 'sb02qd', 'mb03qw', 'tb01xd', 'ud01nd', 'sb10rd', 'ib01my']\n", + "['tf01od', 'ud01dd', 'tb01vy', 'ab09hy', 'sb04rx', 'ib01qd', 'mb04od', 'mb03qv']\n", + "['sg03bz', 'sb03or', 'mb03kd', 'ab13cd', 'tg01kd', 'mb03wa', 'mb04ts', 'mb03ka']\n", + "['mb4dlz', 'mb04qu', 'sb10fd', 'ma02pd', 'sb10jd', 'mb01qd', 'ab09jv', 'sb10vd']\n", + "['fb01td', 'ma02ez', 'tc05ad', 'sb10wd', 'md03ad', 'nf01bd', 'ma02cz', 'mb04ny']\n", + "['sb04rv', 'nf01br', 'tb01pd', 'ab01md', 'ib01bd', 'mb01yd', 'tg01nx', 'sb01fy']\n", + "['mb04md', 'sb10sd', 'mb04ud', 'mb01sd', 'ag08bd', 'ab09bx', 'bb03ad']\n", + "None\n" + ] + } + ], + "source": [ + "slycot_routines = get_slycot_routines(slycot)\n", + "\n", + "print(f\"There are currently {len(slycot_routines)} routines that are found in slycot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(slycot_routines))\n", + "print(\"\\n\")\n", + "\n", + "with open('slicot_routines.txt') as f:\n", + " lines = f.readlines()\n", + "\n", + "slicot_routines = [x.split(\"\\n\")[0] for x in lines]\n", + "\n", + "print(f\"There are currently {len(slicot_routines)} routines that are found in slicot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(slicot_routines))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Sets for the Venn-Diagramm" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 1 routines that are found in slycot and not in slicot.\n", + "------\n", + "['sb03md57']\n", + "None\n", + "\n", + "\n", + "There are currently 552 routines that are found in slicot and not in slycot.\n", + "------\n", + "['mb04bd', 'tb01kx', 'mb02hd', 'mb02cy', 'mb03hz', 'sb02oy', 'ib01md', 'mb03jp']\n", + "['mb01yd', 'sb02mx', 'sb04od', 'nf01ay', 'mc01rd', 'ma02mz', 'mb04yw', 'mb04su']\n", + "['mc01md', 'mb02rd', 'fb01vd', 'mb02cu', 'mb04qu', 'nf01bu', 'mb02sd', 'sb03qx']\n", + "['ab09kx', 'ma02jd', 'mb04ts', 'sb04nw', 'ab08mz', 'mb03ah', 'tg01dd', 'ud01dd']\n", + "['mc01xd', 'ib03ad', 'mb01od', 'tg01jd', 'sb10ld', 'mb03wa', 'nf01by', 'mb04pu']\n", + "['mb04xd', 'mb01oc', 'bb04ad', 'tb04bd', 'mb01zd', 'ab09cx', 'tf01od', 'ab09jw']\n", + "['mb03oy', 'mb01pd', 'sb04ry', 'tg01ob', 'sb04ny', 'ab13cd', 'tg01md', 'mb03ts']\n", + "['sb01bx', 'nf01bf', 'mb02vd', 'sb03ud', 'sb16cd', 'ag08by', 'mb3jzp', 'mb03jz']\n", + "['mb02rz', 'sb09md', 'bd01ad', 'mc01qd', 'md03by', 'nf01br', 'mb02uw', 'mb01ld']\n", + "['mb02qd', 'mb04fd', 'ib01qd', 'ma02id', 'tb01kd', 'mb3lzp', 'sb04mw', 'mb03ba']\n", + "['sb10ud', 'mb03ab', 'mc01sy', 'sb02pd', 'mb03ai', 'mc01wd', 'mc01vd', 'ab09jx']\n", + "['ma02pd', 'tb01md', 'mb03bb', 'mb02jx', 'sb03oz', 'sb04qy', 'sb02ow', 'sb16ay']\n", + "['ab13ad', 'mb04tb', 'ab13id', 'mb03bf', 'ma02bd', 'ab09bx', 'dg01ny', 'mb02uu']\n", + "['mb03bd', 'sb01by', 'mb02td', 'ab08nx', 'tf01my', 'tg01od', 'mb03qd', 'tb04bv']\n", + "['sb03sy', 'mb4dbz', 'mb04cd', 'tb01wd', 'mb05oy', 'sb03ou', 'mb01nd', 'ag07bd']\n", + "['tg01jy', 'tb01ty', 'sb03pd', 'mb04qs', 'ud01bd', 'mb02dd', 'mb03bg', 'mb02nd']\n", + "['sb04mr', 'sb04nd', 'tg01oa', 'mb02pd', 'sb02sd', 'ma01bz', 'ab08nw', 'mb04ru']\n", + "['ma02hd', 'tg01oz', 'mb03kd', 'ud01mz', 'nf01bx', 'tg01az', 'ma02jz', 'mb03gz']\n", + "['ma02pz', 'mb04gd', 'sb02rd', 'sb10sd', 'fb01qd', 'mb03xd', 'tg01hu', 'mb04wr']\n", + "['tb04bx', 'ma02md', 'mb04ud', 'mb01rw', 'tg01ld', 'ib01bd', 'md03ba', 'sb02ms']\n", + "['mb04ad', 'mc03nx', 'ud01md', 'ma02gd', 'tb01td', 'mb04od', 'sb03or', 'tb01iz']\n", + "['sb02ou', 'tf01qd', 'sg03bz', 'ma02es', 'sb03os', 'ab01od', 'mb04pa', 'ib01my']\n", + "['mb04ny', 'mb3oyz', 'mb04fp', 'mc01sd', 'ma01bd', 'nf01bp', 'tb03ay', 'mb01rb']\n", + "['fb01rd', 'ma02fd', 'ab09hy', 'ma02cd', 'tg01ly', 'fb01td', 'mb03qv', 'sb04py']\n", + "['ab05qd', 'sg03bs', 'ab01md', 'mb01uy', 'mb04wu', 'mb02ny', 'mb03cd', 'sb04rw']\n", + "['tg01kz', 'mb01xd', 'mc01pd', 'mb02cd', 'mb04rb', 'tb01vy', 'mb01rt', 'tb01uy']\n", + "['mc01od', 'mb03qw', 'sb02ru', 'nf01ad', 'tg01bd', 'mb01ux', 'mb02fd', 'mb04tw']\n", + "['sb10pd', 'nf01bb', 'tb01ux', 'sb02mw', 'sg03ay', 'mb03af', 'mb03nd', 'mb01wd']\n", + "['mc01sx', 'tb01ld', 'sb10wd', 'mb02md', 'tb01ud', 'ma02ez', 'tb01zd', 'sb08nd']\n", + "['sb16bd', 'sb08md', 'mb04dl', 'dk01md', 'mb03qx', 'tg01hy', 'sb03mv', 'mb04iz']\n", + "['sb02ox', 'tb01nd', 'mb04dz', 'mb04az', 'sb04qr', 'sb08my', 'mb03kb', 'mb03ae']\n", + "['ab09id', 'ma02hz', 'ab09jd', 'mb04yd', 'mb02jd', 'sb16ad', 'mb01md', 'dg01od']\n", + "['nf01ba', 'ab13ax', 'mb03ny', 'mb04kd', 'nf01bd', 'sb03qy', 'mb04tv', 'md03bd']\n", + "['sb04px', 'mb03ud', 'sb10vd', 'mb04qc', 'mb04qb', 'mb03rz', 'mb03sd', 'mb02ud']\n", + "['mb02qy', 'bb03ad', 'mb02kd', 'tg01wd', 'mc03ny', 'mb3pyz', 'mb03pd', 'mb05my']\n", + "['sb10md', 'fd01ad', 'tf01nd', 'mb03be', 'sb08ed', 'sb03qd', 'sb03td', 'mb01ot']\n", + "['sg03bx', 'mb03yd', 'ma02cz', 'ab08md', 'mb01rd', 'ab05pd', 'mb03gd', 'ab09gd']\n", + "['mb01xy', 'sb08hd', 'de01pd', 'mb03md', 'mb03za', 'mb05od', 'mb03ya', 'mb04bz']\n", + "['mb03ry', 'mb04zd', 'sb04my', 'mb03my', 'mb03xz', 'mb01uw', 'mb03ka', 'ma02ed']\n", + "['sb04mu', 'sg03bw', 'mb03dz', 'mb01vd', 'sb08fd', 'ib01od', 'ab05rd', 'tg01ed']\n", + "['mb4dpz', 'tg01cd', 'mb03py', 'tb01yd', 'mb01ss', 'mb04di', 'mb02yd', 'tb04ay']\n", + "['td03ad', 'mb03ke', 'mb01rh', 'ab13dx', 'ib01rd', 'mb04ld', 'mb02sz', 'mb03fd']\n", + "['ab8nxz', 'mb04qf', 'ma02nz', 'mc01py', 'sb04rx', 'mb03iz', 'td05ad', 'sb08ny']\n", + "['mb03ed', 'sb02mr', 'mb04vd', 'bd02ad', 'mb03qy', 'sb01md', 'sb03sd', 'tb04bw']\n", + "['sb10qd', 'de01od', 'mb04iy', 'sb04rv', 'ab09hd', 'sb03mw', 'sb10kd', 'ab05sd']\n", + "['ab09iy', 'ue01md', 'sg03bu', 'mb04ty', 'md03ad', 'tg01nd', 'mb03bc', 'sb03ov']\n", + "['mb04vx', 'mb03fz', 'tb01wx', 'mb02cx', 'ib01nd', 'mb02wd', 'sb03mu', 'sb02mv']\n", + "['tf01mx', 'mb04ow', 'mb04nd', 'sb01dd', 'sg02nd', 'mb01rx', 'ib01ad', 'ma02gz']\n", + "['sb10td', 'tc05ad', 'mb02tz', 'mb03ad', 'sb04nx', 'ma02dd', 'sg02cw', 'sg03bv']\n", + "['mb01oh', 'dg01md', 'mb04dy', 'mb01oe', 'sb04rd', 'mb04id', 'mb01kd', 'mb02cv']\n", + "['ma02iz', 'mb03yt', 'mb04dd', 'sb01fy', 'bb01ad', 'sb03rd', 'mc01nd', 'ma02az']\n", + "['mb03lp', 'mb04dp', 'ab09jv', 'mb03id', 'tg01hd', 'tg01gd', 'sb04pd', 'tf01pd']\n", + "['sb08dd', 'sb03sx', 'ab07md', 'sb10rd', 'mb04xy', 'sb04nv', 'nf01bs', 'md03bb']\n", + "['mb03ld', 'tg01fz', 'tg01qd', 'mb03kc', 'mc03md', 'tb01xd', 'mb04tx', 'sb10id']\n", + "['sb10zp', 'mb03xp', 'ib01py', 'mb03hd', 'mb03cz', 'mb04md', 'mb02xd', 'mb01ud']\n", + "['sg02cv', 'mb01qd', 'mb01sd', 'ma02oz', 'sb02nd', 'sb03mx', 'mb03jd', 'mb02od']\n", + "['sb02cx', 'sb02qd', 'bb02ad', 'ma02ad', 'mb4dlz', 'mb03lz', 'ib01pd', 'mb04bp']\n", + "['tb04cd', 'ib01cd', 'tb01vd', 'nf01bw', 'mb03od', 'mb04tu', 'mb03lf', 'mb03qg']\n", + "['sb08cd', 'ib03bd', 'sg03by', 'fb01sd', 'sg02cx', 'ag8byz', 'mb01os', 'ab08ny']\n", + "['mb02id', 'nf01be', 'mb04ox', 'tb01xz', 'sg03br', 'mb01td', 'md03bx', 'mb04tt']\n", + "['mb02uv', 'sg03ax', 'mb03td', 'sb03oy', 'ab09cd', 'ab09ed', 'ib01px', 'td03ay']\n", + "['sb06nd', 'sb02ov', 'sb02mu', 'tg01pd', 'sg03bt', 'ab09fd', 'sb04qu', 'mb03xs']\n", + "['mb02gd', 'mb04wd', 'ma02od', 'mb04db', 'ab05od', 'sb04ow', 'ag08bz', 'mb04py']\n", + "['sb16cy', 'mb03vw', 'mb04jd', 'mb03dd', 'sb10ed', 'mb03zd', 'ma01ad', 'mc01sw']\n", + "['sb08gd', 'mb03rw', 'ab09hx', 'mb04wp', 'ib01oy', 'mb04ed', 'tb01px', 'df01md']\n", + "['ab09ix', 'mb03xu', 'ab09kd', 'tg01kd', 'sb03my', 'mb04hd', 'mb01uz', 'ma02bz']\n", + "['mb03bz', 'sb03ot', 'mb04pb', 'mb04oy', 'md03bf', 'mb01oo', 'mc03nd', 'nf01bv']\n", + "['mb04ds', 'ud01nd', 'mb01ry', 'mb03rx', 'sb10zd', 'mb01ru', 'nf01bq', 'mb03wx']\n", + "['tg01nx', 'ud01cd', 'tg01id', 'tg01hx', 'ma01cd', 'ab09dd', 'mb03ag', 'dg01nd']\n", + "None\n", + "\n", + "\n" + ] + } + ], + "source": [ + "not_in_slicot = list(set(slycot_routines)- set(slicot_routines))\n", + "not_in_slicot\n", + "\n", + "print(f\"There are currently {len(not_in_slicot)} routines that are found in slycot and not in slicot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(not_in_slicot))\n", + "print(\"\\n\")\n", + "\n", + "not_in_slycot = list(set(slicot_routines) - set(slycot_routines))\n", + "not_in_slycot\n", + "\n", + "print(f\"There are currently {len(not_in_slycot)} routines that are found in slicot and not in slycot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(not_in_slycot))\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 608 routines that are found in slicot or in slycot. (union)\n", + "------\n", + "['mb04bd', 'tb01kx', 'mb02hd', 'mb02cy', 'mb03hz', 'sb02oy', 'ib01md', 'mb03jp']\n", + "['mb01yd', 'sb02mx', 'sb04od', 'nf01ay', 'mc01rd', 'ma02mz', 'mb04yw', 'mb04su']\n", + "['mc01md', 'mb02rd', 'fb01vd', 'mb02cu', 'mb04qu', 'nf01bu', 'mb02sd', 'sb03qx']\n", + "['ab09kx', 'ma02jd', 'mb04ts', 'sb04nw', 'ab08mz', 'mb03ah', 'tg01dd', 'ud01dd']\n", + "['mc01xd', 'ib03ad', 'ab13ed', 'mb01od', 'tg01jd', 'sb10ld', 'mb03wa', 'nf01by']\n", + "['mb04pu', 'tf01md', 'mb04xd', 'mb01oc', 'bb04ad', 'tb04bd', 'mb01zd', 'ab01nd']\n", + "['ab09cx', 'tf01od', 'ab09jw', 'mb03oy', 'mb01pd', 'sb04ry', 'tg01ob', 'sb04ny']\n", + "['ab13cd', 'tg01md', 'mb03ts', 'sb01bx', 'nf01bf', 'mb02vd', 'sb03ud', 'sb16cd']\n", + "['ag08by', 'mb3jzp', 'mb03jz', 'mb02rz', 'sb09md', 'bd01ad', 'mc01qd', 'md03by']\n", + "['nf01br', 'mb02uw', 'mb01ld', 'mb02qd', 'mb04fd', 'ib01qd', 'ma02id', 'tb01kd']\n", + "['mb3lzp', 'sb04mw', 'mb03ba', 'sb10ud', 'tf01rd', 'mb03ab', 'mc01sy', 'sb02pd']\n", + "['mb03ai', 'mc01wd', 'mc01vd', 'ab09jx', 'ma02pd', 'sb03md57', 'tb01md', 'mb03bb']\n", + "['mb02jx', 'sb03oz', 'sb04qy', 'sb02ow', 'sb16ay', 'ab13fd', 'ab13ad', 'mb04tb']\n", + "['ab13id', 'mb03bf', 'ma02bd', 'ab09bx', 'dg01ny', 'mb02uu', 'mb03bd', 'sb01by']\n", + "['mb02td', 'ab08nx', 'tf01my', 'tg01od', 'mb03qd', 'tb04bv', 'sb03sy', 'mb4dbz']\n", + "['mb04cd', 'tb01wd', 'mb05oy', 'sb03ou', 'mb01nd', 'ag07bd', 'tg01jy', 'tb01ty']\n", + "['sb03pd', 'mb04qs', 'ud01bd', 'mb02dd', 'sb03od', 'mb03bg', 'mb02nd', 'sb04mr']\n", + "['sb04nd', 'tg01oa', 'mb02pd', 'sb02sd', 'ma01bz', 'ab08nw', 'mb04ru', 'ma02hd']\n", + "['tg01oz', 'mb03kd', 'ud01mz', 'sb10ad', 'nf01bx', 'sb10dd', 'ab05md', 'mb02ed']\n", + "['tg01az', 'ma02jz', 'mb03gz', 'ma02pz', 'mb04gd', 'sb02rd', 'sb10sd', 'fb01qd']\n", + "['mb03xd', 'tg01hu', 'mb04wr', 'tb04bx', 'ma02md', 'mb04ud', 'mb01rw', 'sb10yd']\n", + "['tg01ld', 'ib01bd', 'tc04ad', 'ab09bd', 'md03ba', 'mb05md', 'sb02ms', 'mb04ad']\n", + "['mc03nx', 'ud01md', 'ma02gd', 'tb01td', 'mb04od', 'sb03or', 'tb01iz', 'sb02ou']\n", + "['tf01qd', 'sg03bz', 'ab08nd', 'ma02es', 'sb03os', 'ab01od', 'tg01fd', 'mb04pa']\n", + "['ib01my', 'mb04ny', 'mb3oyz', 'mb04fp', 'mc01sd', 'tb01id', 'ma01bd', 'nf01bp']\n", + "['tb03ay', 'mb01rb', 'fb01rd', 'ma02fd', 'ab09hy', 'ma02cd', 'tg01ly', 'fb01td']\n", + "['mb03qv', 'sb04py', 'ab05qd', 'ab13bd', 'sg03bs', 'ab01md', 'tb01pd', 'mb01uy']\n", + "['mb04wu', 'mb02ny', 'mb03cd', 'sb04rw', 'tg01kz', 'mb01xd', 'sb02od', 'mc01pd']\n", + "['mb02cd', 'mb04rb', 'tb01vy', 'mb01rt', 'tb01uy', 'mc01od', 'mb03qw', 'sb02ru']\n", + "['nf01ad', 'tg01bd', 'mb01ux', 'ab09ad', 'mb02fd', 'mb04tw', 'sb10pd', 'nf01bb']\n", + "['tb01ux', 'sb02mw', 'sg03ay', 'mb03af', 'mb03nd', 'mb01wd', 'mc01sx', 'tb01ld']\n", + "['sb10wd', 'mb02md', 'tb01ud', 'ma02ez', 'tb01zd', 'sb08nd', 'sb16bd', 'sb08md']\n", + "['mb04dl', 'dk01md', 'mb03qx', 'mb03wd', 'tg01hy', 'sb03mv', 'mb04iz', 'sb02ox']\n", + "['tb01nd', 'mb04dz', 'sb02mt', 'mb04az', 'ab13md', 'sb04qr', 'sb08my', 'mb03kb']\n", + "['mb03ae', 'sg03ad', 'ab09id', 'ma02hz', 'ab09jd', 'mb04yd', 'mb02jd', 'sb16ad']\n", + "['mb01md', 'dg01od', 'sb04md', 'nf01ba', 'ab13ax', 'mb03ny', 'mb04kd', 'nf01bd']\n", + "['sb10hd', 'sb03qy', 'mb04tv', 'md03bd', 'sb04px', 'tg01ad', 'mb03ud', 'sb10vd']\n", + "['mb04qc', 'mb04qb', 'mb03rz', 'mb03sd', 'mb02ud', 'mb02qy', 'bb03ad', 'mb02kd']\n", + "['tg01wd', 'mc03ny', 'mb3pyz', 'mb03pd', 'mb05my', 'ab13dd', 'sb10md', 'fd01ad']\n", + "['tf01nd', 'mb03be', 'mb03vy', 'sb08ed', 'sb03qd', 'sb03td', 'mb01ot', 'sg03bx']\n", + "['mb03yd', 'ma02cz', 'ab08md', 'mb01rd', 'ab05pd', 'mb03gd', 'ab09gd', 'mb01xy']\n", + "['sb08hd', 'de01pd', 'sb10jd', 'mb03md', 'mb03za', 'mb05od', 'ab09md', 'mb03ya']\n", + "['mb04bz', 'mb03ry', 'mb04zd', 'sb04my', 'mb03my', 'mb03xz', 'mb01uw', 'sb10fd']\n", + "['mb03ka', 'ma02ed', 'sb04mu', 'sg03bw', 'mb03dz', 'mb01vd', 'sb08fd', 'ib01od']\n", + "['ab05rd', 'tg01ed', 'mb4dpz', 'tg01cd', 'ab07nd', 'mb03py', 'tb01yd', 'ab09ax']\n", + "['mb01ss', 'mb04di', 'ab04md', 'mb02yd', 'tb04ay', 'td03ad', 'mb03ke', 'mb01rh']\n", + "['ab13dx', 'ib01rd', 'mb04ld', 'mb02sz', 'mb03fd', 'ab8nxz', 'mb04qf', 'ma02nz']\n", + "['mc01py', 'sb04rx', 'mb03iz', 'td05ad', 'sb08ny', 'ab08nz', 'tb05ad', 'mb03ed']\n", + "['sb02mr', 'mb04vd', 'bd02ad', 'mb03qy', 'sb01md', 'sb03sd', 'tb04bw', 'sb10qd']\n", + "['de01od', 'mb04iy', 'mb03rd', 'ag08bd', 'sb04rv', 'ab09hd', 'sb03mw', 'sb10kd']\n", + "['ab05sd', 'ab09iy', 'ue01md', 'sg03bu', 'mb04ty', 'md03ad', 'tg01nd', 'mb03bc']\n", + "['sb03ov', 'mb04vx', 'mb03fz', 'tb01wx', 'mb02cx', 'ib01nd', 'mb02wd', 'sb03mu']\n", + "['sb02mv', 'tf01mx', 'mb04ow', 'mb04nd', 'sb01dd', 'sb03md', 'sg02nd', 'sb04qd']\n", + "['mb03vd', 'mb01rx', 'ib01ad', 'ma02gz', 'ab05nd', 'sb10td', 'tc05ad', 'mb02tz']\n", + "['mb03ad', 'sb04nx', 'ma02dd', 'sg02cw', 'sg03bv', 'mb01oh', 'mc01td', 'dg01md']\n", + "['mb04dy', 'mb01oe', 'sb04rd', 'mb04id', 'mb01kd', 'mb02cv', 'ma02iz', 'mb03yt']\n", + "['mb04dd', 'sb01fy', 'bb01ad', 'sb03rd', 'mc01nd', 'ma02az', 'mb03lp', 'mb04dp']\n", + "['ab09jv', 'mb03id', 'tg01hd', 'tg01gd', 'sb04pd', 'tf01pd', 'sb08dd', 'sb03sx']\n", + "['ab07md', 'sb10rd', 'mb04xy', 'sg02ad', 'sb04nv', 'nf01bs', 'md03bb', 'mb03ld']\n", + "['tg01fz', 'tg01qd', 'mb03kc', 'mc03md', 'tb01xd', 'mb04tx', 'sb10id', 'sb10zp']\n", + "['mb03xp', 'ib01py', 'mb03hd', 'mb03cz', 'mb04md', 'mb02xd', 'mb01ud', 'sg03bd']\n", + "['sg02cv', 'mb01qd', 'mb01sd', 'ma02oz', 'sb02nd', 'sb03mx', 'mb03jd', 'mb02od']\n", + "['sb02cx', 'sb02qd', 'bb02ad', 'ma02ad', 'mb4dlz', 'mb03lz', 'ib01pd', 'sb01bd']\n", + "['mb04bp', 'tb04cd', 'ib01cd', 'tb01vd', 'nf01bw', 'mb03od', 'mb04tu', 'mb03lf']\n", + "['mb03qg', 'sb08cd', 'tb03ad', 'ib03bd', 'sg03by', 'fb01sd', 'sg02cx', 'ag8byz']\n", + "['mb01os', 'ab08ny', 'mb02id', 'nf01be', 'mb04ox', 'tb01xz', 'sg03br', 'mb01td']\n", + "['md03bx', 'mb04tt', 'mb02uv', 'sg03ax', 'mb03td', 'sb03oy', 'ab09cd', 'ab09ed']\n", + "['ib01px', 'td03ay', 'sb06nd', 'sb02ov', 'sb02mu', 'tg01pd', 'mb05nd', 'sg03bt']\n", + "['ab09fd', 'sb04qu', 'tc01od', 'mb03xs', 'mb02gd', 'mb04wd', 'ma02od', 'mb04db']\n", + "['ab05od', 'sb04ow', 'ag08bz', 'mb04py', 'sb16cy', 'mb03vw', 'mb04jd', 'mb03dd']\n", + "['sb10ed', 'sb02md', 'mb03zd', 'ma01ad', 'td04ad', 'mc01sw', 'sb08gd', 'mb03rw']\n", + "['ab09hx', 'mb04wp', 'ib01oy', 'mb04ed', 'tb01px', 'df01md', 'ab09ix', 'tb04ad']\n", + "['mb03xu', 'ab09kd', 'tg01kd', 'sb03my', 'mb04hd', 'mb01uz', 'ma02bz', 'mb03bz']\n", + "['sb03ot', 'mb04pb', 'mb04oy', 'md03bf', 'mb01oo', 'mc03nd', 'nf01bv', 'ab09nd']\n", + "['mb04ds', 'ud01nd', 'mb01ry', 'mb03rx', 'sb10zd', 'mb01ru', 'nf01bq', 'mb03wx']\n", + "['tg01nx', 'ud01cd', 'tg01id', 'tg01hx', 'ma01cd', 'ab09dd', 'mb03ag', 'dg01nd']\n", + "None\n", + "\n", + "\n", + "There are currently 55 routines that are found in slicot and slycot. (intersection)\n", + "------\n", + "['ab08nd', 'tb05ad', 'sb02mt', 'sb10ad', 'ab13md', 'tg01fd', 'mb02ed', 'ab05md']\n", + "['sb10dd', 'sg03ad', 'ab13ed', 'sb03md', 'tb01id', 'ab13dd', 'sb04qd', 'ab07nd']\n", + "['ab09ad', 'mb03vd', 'ab09ax', 'sb01bd', 'ab04md', 'mb03vy', 'mb05nd', 'tf01md']\n", + "['ab05nd', 'sb04md', 'ab09nd', 'tf01rd', 'tc01od', 'ab01nd', 'tb03ad', 'sb10hd']\n", + "['mb03rd', 'ag08bd', 'sg02ad', 'sb10yd', 'sb03od', 'sb10jd', 'tc04ad', 'ab13bd']\n", + "['sb02md', 'ab09md', 'ab09bd', 'mb05md', 'mc01td', 'td04ad', 'tg01ad', 'tb01pd']\n", + "['ab08nz', 'sb10fd', 'ab13fd', 'sb02od', 'mb03wd', 'sg03bd', 'tb04ad']\n", + "None\n" + ] + } + ], + "source": [ + "union = list(set(slicot_routines) | set(slycot_routines))\n", + "\n", + "print(f\"There are currently {len(union)} routines that are found in slicot or in slycot. (union)\")\n", + "print(\"------\")\n", + "print(print_list_chunks(union))\n", + "print(\"\\n\")\n", + "\n", + "intersection = list(set(slicot_routines) & set(slycot_routines))\n", + "intersection\n", + "\n", + "print(f\"There are currently {len(intersection)} routines that are found in slicot and slycot. (intersection)\")\n", + "print(\"------\")\n", + "print(print_list_chunks(intersection))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
chapter nameslycot routinesslicot routines
aAnalysis Routines1860
bBenchmark06
cAdaptive Control00
dData Analysis08
fFiltering06
iIdentification015
mMathematical routines8281
nNonlinear Systems016
sSynthesis Routines18131
tTransformation Routines1277
uUtility Routines07
total-56607
\n", + "
" + ], + "text/plain": [ + " chapter name slycot routines slicot routines\n", + "a Analysis Routines 18 60\n", + "b Benchmark 0 6\n", + "c Adaptive Control 0 0\n", + "d Data Analysis 0 8\n", + "f Filtering 0 6\n", + "i Identification 0 15\n", + "m Mathematical routines 8 281\n", + "n Nonlinear Systems 0 16\n", + "s Synthesis Routines 18 131\n", + "t Transformation Routines 12 77\n", + "u Utility Routines 0 7\n", + "total - 56 607" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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57xv3779pR7fWZq1a9dCoVBgxIgRJZYXJaS//PILOnbsqPaiKuDJY0HHjh2LS5cu4dy5c68dz+tgYktERERUiejo6CAyMhJRUVFQKpXw9PTEl19+WeYb4Z919epVODk5FXvW/LOuXLlS6pOIio5fuXLllWIoL0xsiYiIiCqZnj174tatW9i5cyd8fX0RExMDNze3Em/KepGXeY7Au/7MASa2RERERJWQvr4+OnbsiClTpuD48eMICgrCtGnTXrodZ2dn/P333y98q6izszMSEhJKLCs67uzs/NL9lycmtkREREQaoH79+nj06NFLn9e/f39kZWXhu+++K7G86Oaxjz76CAcPHiy2jrawsBALFy5E/fr1i62/fdt4iz4RERFRJXL//n307t0bwcHBaNy4MYyNjXH69GnMnz8f/v7+Ur3//e9/iI+PVzvX3t6+WHseHh6YMGGC9HKk7t27w8bGBteuXcOKFSvwwQcf4LPPPsPYsWOxY8cOdO3aFeHh4fDw8MCdO3cwZ84cJCQk4ODBg5DJZG/68p+LiS0RERHRs97ht4EpFAp4eHhg4cKFSEpKQl5eHmxtbTF06FB8+eWXUr0FCxZgwYIFaueuWbMGH3zwQbE2582bh/feew/ffvstVqxYgcLCQtSuXRu9evVCYGAggCdLH37//XfMmTMHX375pdoLGv744w80bNjwzV54GfDNY1Sl8M1jRERU5LlvHqO3jm8eIyIiIiL6/5jYEhEREZFGYGJLRERERBqBiS0RERERaQQmtkRERFSl8T76d0N5fB+Y2BIREVGVpKurCwDIzs6u4EgI+L/vQ9H35VXwObZERERUJWlra0OpVCItLQ0AYGhoWOEvGKiKhBDIzs5GWloalEoltLW1X7ktJrZERERUZVlZWQGAlNxSxVEqldL341UxsSUiIqIqSyaTwdraGpaWlsjLy6vocKosXV3d15qpLcLEloiIiKo8bW3tckmsqGIxsaUSxcTEoF27dnjw4AGUSmVFhwMACAoKQnp6OrZv3/76jYXVAuQvWEf1Dr8nnIiIiIrjUxHeQUFBQZDJZNJmbm4OX19fnD9/vqJDIyIiInpnMbF9R/n6+kKlUkGlUiE6Oho6Ojrw8/Or6LAqREFBAQoLCys6DCIiInrHMbF9R8nlclhZWcHKygpNmzbFxIkTcePGDdy9excAcOPGDfTp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QAA+++wzXLp0CStXrkRkZCRmz56tdn5oaCi6d++OCxcuIDg4uMQ+srOzsWDBAqxZswZHjhxBamoqQkJCpPJ58+Zh7dq1iIiIQGxsLDIzM8u0NCIsLAympqbSZmtr+4qjQERERO86JrZV0K5du6BQKKStd+/ez61vYWEBAFAqlbCyspL2p0+fjokTJyIwMBBOTk7o2LEjZs6ciZUrV6qd379/fwwaNAhOTk6ws7MrsY+8vDysWLEC7u7ucHNzw6hRoxAdHS2VL126FJMmTUL37t1Rr149LFu2rEw3nk2aNAkZGRnSduPGjReeQ0RERJUT19hWQe3atcPy5culfSMjI/Tr1++l2zl37hxiY2PVZmgLCgrw+PFjZGdnw9DQEADg7u7+wrYMDQ1Ru3Ztad/a2hppaWkAgIyMDNy5cwctWrSQyrW1tfHee++hsLDwue3K5XLI5fKXui4iIiKqnJjYVkFGRkaoU6fOa7eTlZWF6dOno0ePHsXK9PX11fp7EV1dXbV9mUwGIcRrx0hERERVBxNbKhNdXV0UFBSoHXNzc0NiYmK5JMnPY2pqiho1auDUqVNo06YNgCczw3/++SeaNm36ao1OugmYmJRfkERERFThmNhSmTg4OCA6Ohqenp6Qy+WoVq0apk6dCj8/P9jZ2aFXr17Q0tLCuXPncPHiRcyaNatc+//0008RFhaGOnXqoF69eli6dCkePHgAmewFL1kgIiKiKoM3j1GZhIeH48CBA7C1tUWzZs0AAD4+Pti1axf279+P5s2b4/3338fChQthb29f7v1/8cUX6NevHwICAtCyZUsoFAr4+PioLXkgIiKiqk0muJCRKqHCwkK4urqiT58+z31j2rMyMzNhamqKjIwMmHApAhERUaVQ1t/fXIpAlcL169exf/9+tG3bFjk5OVi2bBmSk5PRv3//ig6NiIiI3hFcikCVgpaWFiIjI9G8eXN4enriwoULOHjwIFxdXSs6NCIiInpHcMaWKgVbW1vExsZWdBhERET0DuOMLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJ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uXIlIiIi4OXlVe4xm5mZISAgAKGhoSgsLERERATee+89+Pn5oWXLlhBCYPfu3dJH+66urvjuu+/w7bffokmTJjh58iRCQkLU2hw6dChcXFzg7u4OCwsLxMbGvlJsPj4+2LVrF/bv34/mzZvj/fffx8KFC6XEValUYtWqVfD09ETjxo1x8OBB/PrrrzA3N3+9QSEiIqJKTybK+xVURO+wzMxMmJqaIiMjgzeSERERVRJl/f39RmdsiYiIiIjeFia2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGkGnogOoKlJSUuDo6IizZ8+iadOmiImJQbt27fDgwQMolUpERkZizJgxSE9Pr+hQy1VQUBDS09Oxffv2ig5FXVgtQC57cb3QjDcfCxEREZULzti+BC8vL4wZM6bY8cjISCiVSmk/KCgI3bp1U6tja2sLlUqFhg0blth23759ceXKFWk/NDQUTZs2fe2YY2JiIJPJpM3CwgKdO3fGhQsXXrvtp6WkpEAmkyE+Pl7t+OLFixEZGVmufRERERGVhIntW6KtrQ0rKyvo6JQ8SW5gYABLS8s31n9iYiJUKhX27duHnJwcdOnSBbm5uW+svyKmpqZqST8RERHRm8LEtpyFhoYiKioKO3bskGZJY2JiSp3RLPL0rG9kZCSmT5+Oc+fOSW1ERkYiODgYfn5+aufl5eXB0tISq1evfm5clpaWsLKygpubG8aMGYMbN27g8uXLUvmWLVvQoEEDyOVyODg4IDw8XO18mUxWbDlB0RIKAHB0dAQANGvWDDKZDF5eXgCKz157eXlh9OjRmDBhAszMzGBlZYXQ0FC1dtPT0zFkyBBYWFjAxMQE7du3x7lz56Tyc+fOoV27djA2NoaJiQnee+89nD59usTrzsnJQWZmptpGREREmolrbMtZSEgIEhISkJmZiYiICACAmZkZbt26VeY2+vbti4sXL2Lv3r04ePAggCczn87OzmjTpg1UKhWsra0BALt27UJ2djb69u1bprYzMjKwfv16AICenh4A4MyZM+jTpw9CQ0PRt29fHD9+HCNGjIC5uTmCgoLK1O7JkyfRokULHDx4EA0aNJDaLklUVBTGjRuHEydOIC4uDkFBQfD09ETHjh0BAL1794aBgQH27NkDU1NTrFy5Eh06dMCVK1dgZmaGAQMGoFmzZli+fDm0tbURHx8PXV3dEvsKCwvD9OnTy3QNREREVLkxsS1nCoUCBgYGyMnJgZWV1Su1YWBgAIVCAR0dHbU2WrVqBRcXF6xZswYTJkwAAERERKB3795QKBTPbbNWrVoAgEePHgEAPvzwQ9SrVw8A8M0336BDhw6YMmUKAMDZ2RmXLl3C119/XebE1sLCAgBgbm7+wutu3Lgxpk2bBgCoW7culi1bhujoaHTs2BHHjh3DyZMnkZaWBrlcDgBYsGABtm/fjs2bN+OTTz5Bamoqxo8fL8Vft27dUvuaNGkSxo0bJ+1nZmbC1ta2TNdERERElQuXIlQyQ4YMkWaC79y5gz179iA4OPiF5x09ehRnzpxBZGQknJ2dsWLFCqksISEBnp6eavU9PT1x9epVFBQUlO8F4Eli+zRra2ukpaUBeLLMICsrC+bm5lAoFNKWnJyMpKQkAMC4ceMwZMgQeHt7Y+7cudLxksjlcpiYmKhtREREpJk4Y/sSTExMkJFR/PFP6enpMDU1fSsxBAQEYOLEiYiLi8Px48fh6OiI1q1bv/A8R0dHKJVKuLi4IC0tDX379sWRI0fK3K9MJoMQQu1YXl7eS8cPoNiyAZlMhsLCQgBAVlYWrK2tERMTU+y8ojXIoaGh6N+/P3777Tfs2bMH06ZNw/r169G9e/dXioeIiIg0AxPbl+Di4oL9+/cXO/7nn3/C2dlZ2tfT03vtmc7S2jA3N0e3bt0QERGBuLg4DBo06KXbHjlyJMLCwrBt2zZ0794drq6uiI2NVasTGxsLZ2dnaGtrA3iy1EClUknlV69eRXZ2tlq8AF77ut3c3HD79m3o6OjAwcGh1HrOzs5wdnbG2LFj0a9fP0RERLxcYjvpJsDZWyIiIo3CpQgvYfjw4bhy5QpGjx6N8+fPIzExEd988w3WrVuHzz//XKrn4OAgld+7d++VZjYdHByQnJyM+Ph43Lt3Dzk5OVLZkCFDEBUVhYSEBAQGBr5024aGhhg6dCimTZsGIQQ+//xzREdHY+bMmbhy5QqioqKwbNkyhISESOe0b98ey5Ytw9mzZ3H69GkMGzZMbebV0tISBgYG2Lt3L+7cuVPizHZZeHt7o2XLlujWrRv279+PlJQUHD9+HJMnT8bp06fx77//YtSoUYiJicH169cRGxuLU6dOwdXV9ZX6IyIiIs3BxPYlODk54ciRI7h8+TK8vb3h4eGBjRs3YtOmTfD19ZXqDR06FC4uLnB3d4eFhUWx2dCy6NmzJ3x9fdGuXTtYWFhg3bp1Upm3tzesra3h4+MDGxubV7qWUaNGISEhAZs2bYKbmxs2btyI9evXo2HDhpg6dSpmzJihduNYeHg4bG1t0bp1a/Tv3x8hISEwNDSUynV0dLBkyRKsXLkSNjY28Pf3f6W4ZDIZdu/ejTZt2mDQoEFwdnbGRx99hOvXr6NGjRrQ1tbG/fv3ERAQAGdnZ/Tp0wedOnXikw+IiIgIMvHswkl652VlZaFmzZqIiIhAjx49KjqcSiUzMxOmpqbIyMjgjWRERESVRFl/f3ONbSVSWFiIe/fuITw8HEqlEh9++GFFh0RERET0zmBiW4mkpqbC0dERtWrVQmRkZKmv5yUiIiKqipgZVSIODg7FHrlFRERERE/w5jEiIiIi0ghMbImIiIhIIzCxJSIiIiKNwMSWiIiIiDQCE1siIiIi0ghMbImIiIhIIzCxJSIiIiKNwMSWiIiIiDQCE1siIiIi0gh88xhVKUVvbsvMzKzgSIiIiKisin5vv+gNrExsqUq5f/8+AMDW1raCIyEiIqKX9fDhQ5iampZazsSWqhQzMzMAQGpq6nN/MKhsMjMzYWtrixs3bsDExKSiw6n0OJ7li+NZvjie5Yvj+XKEEHj48CFsbGyeW4+JLVUpWlpPlpWbmpryP5JyZGJiwvEsRxzP8sXxLF8cz/LF8Sy7skxI8eYxIiIiItIITGyJiIiISCMwsaUqRS6XY9q0aZDL5RUdikbgeJYvjmf54niWL45n+eJ4vhky8aLnJhARERERVQKcsSUiIiIijcDEloiIiIg0AhNbIiIiItIITGyJiIiISCMwsSUiIiIijcDElqqMb7/9Fg4ODtDX14eHhwdOnjxZ0SFVCqGhoZDJZGpbvXr1pPLHjx9j5MiRMDc3h0KhQM+ePXHnzp0KjPjdcuTIEXTt2hU2NjaQyWTYvn27WrkQAlOnToW1tTUMDAzg7e2Nq1evqtX5559/MGDAAJiYmECpVGLw4MHIysp6i1fx7njReAYFBRX79+rr66tWh+P5f8LCwtC8eXMYGxvD0tIS3bp1Q2JiolqdsvyMp6amokuXLjA0NISlpSXGjx+P/Pz8t3kp74SyjKeXl1exf6PDhg1Tq8PxfHVMbKlK2LBhA8aNG4dp06bhzz//RJMmTeDj44O0tLSKDq1SaNCgAVQqlbQdO3ZMKhs7dix+/fVXbNq0CYcPH8atW7fQo0ePCoz23fLo0SM0adIE3377bYnl8+fPx5IlS7BixQqcOHECRkZG8PHxwePHj6U6AwYMwF9//YUDBw5g165dOHLkCD755JO3dQnvlBeNJwD4+vqq/Xtdt26dWjnH8/8cPnwYI0eOxB9//IEDBw4gLy8P//nPf/Do0SOpzot+xgsKCtClSxfk5ubi+PHjiIqKQmRkJKZOnVoRl1ShyjKeADB06FC1f6Pz58+Xyjier0kQVQEtWrQQI0eOlPYLCgqEjY2NCAsLq8CoKodp06aJJk2alFiWnp4udHV1xaZNm6RjCQkJAoCIi4t7SxFWHgDEtm3bpP3CwkJhZWUlvv76a+lYenq6kMvlYt26dUIIIS5duiQAiFOnTkl19uzZI2Qymfjf//731mJ/Fz07nkIIERgYKPz9/Us9h+P5fGlpaQKAOHz4sBCibD/ju3fvFlpaWuL27dtSneXLlwsTExORk5Pzdi/gHfPseAohRNu2bcVnn31W6jkcz9fDGVvSeLm5uThz5gy8vb2lY1paWvD29kZcXFwFRlZ5XL16FTY2NnBycsKAAQOQmpoKADhz5gzy8vLUxrZevXqws7Pj2JZBcnIybt++rTZ+pqam8PDwkMYvLi4OSqUS7u7uUh1vb29oaWnhxIkTbz3myiAmJgaWlpZwcXHB8OHDcf/+famM4/l8GRkZAAAzMzMAZfsZj4uLQ6NGjVCjRg2pjo+PDzIzM/HXX3+9xejfPc+OZ5G1a9eievXqaNiwISZNmoTs7GypjOP5enQqOgCiN+3evXsoKChQ+08CAGrUqIHLly9XUFSVh4eHByIjI+Hi4gKVSoXp06ejdevWuHjxIm7fvg09PT0olUq1c2rUqIHbt29XTMCVSNEYlfRvs6js9u3bsLS0VCvX0dGBmZkZx7gEvr6+6NGjBxwdHZGUlIQvv/wSnTp1QlxcHLS1tTmez1FYWIgxY8bA09MTDRs2BIAy/Yzfvn27xH/DRWVVVUnjCQD9+/eHvb09bGxscP78eXzxxRdITEzE1q1bAXA8XxcTWyJ6rk6dOklfN27cGB4eHrC3t8fGjRthYGBQgZERFffRRx9JXzdq1AiNGzdG7dq1ERMTgw4dOlRgZO++kSNH4uLFi2pr6OnVlTaeT6/nbtSoEaytrdGhQwckJSWhdu3abztMjcOlCKTxqlevDm1t7WJ38d65cwdWVlYVFFXlpVQq4ezsjGvXrsHKygq5ublIT09Xq8OxLZuiMXrev00rK6tiNznm5+fjn3/+4RiXgZOTE6pXr45r164B4HiWZtSoUdi1axcOHTqEWrVqScfL8jNuZWVV4r/horKqqLTxLImHhwcAqP0b5Xi+Oia2pPH09PTw3nvvITo6WjpWWFiI6OhotGzZsgIjq5yysrKQlJQEa2trvPfee9DV1VUb28TERKSmpnJsy8DR0RFWVlZq45eZmYkTJ05I49eyZUukp6fjzJkzUp3ff/8dhYWF0i9EKt3Nmzdx//59WFtbA+B4PksIgVGjRmHbtm34/fff4ejoqFZelp/xli1b4sKFC2p/MBw4cAAmJiaoX7/+27mQd8SLxrMk8fHxAKD2b5Tj+Roq+u41ordh/fr1Qi6Xi8jISHHp0iXxySefCKVSqXbXKZXs888/FzExMSI5OVnExsYKb29vUb16dZGWliaEEGLYsGHCzs5O/P777+L06dOiZcuWomXLlhUc9bvj4cOH4uzZs+Ls2bMCgPjmm2/E2bNnxfXr14UQQsydO1colUqxY8cOcf78eeHv7y8cHR3Fv//+K7Xh6+srmjVrJk6cOCGOHTsm6tatK/r161dRl1ShnjeeDx8+FCEhISIuLk4kJyeLgwcPCjc3N1G3bl3x+PFjqQ2O5/8ZPny4MDU1FTExMUKlUklbdna2VOdFP+P5+fmiYcOG4j//+Y+Ij48Xe/fuFRYWFmLSpEkVcUkV6kXjee3aNTFjxgxx+vRpkZycLHbs2CGcnJxEmzZtpDY4nq+HiS1VGUuXLhV2dnZCT09PtGjRQvzxxx8VHVKl0LdvX2FtbS309PREzZo1Rd++fcW1a9ek8n///VeMGDFCVKtWTRgaGoru3bsLlUpVgRG/Ww4dOiQAFNsCAwOFEE8e+TVlyhRRo0YNIZfLRYcOHURiYqJaG/fv3xf9+vUTCoVCmJiYiEGDBomHDx9WwNVUvOeNZ3Z2tvjPf/4jLCwshK6urrC3txdDhw4t9gcsx/P/lDSWAERERIRUpyw/4ykpKaJTp07CwMBAVK9eXXz++eciLy/vLV9NxXvReKampoo2bdoIMzMzIZfLRZ06dcT48eNFRkaGWjscz1cnE0KItzc/TERERET0ZnCNLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUZgYktEREREGoGJLRERERFpBCa2RERERKQRmNgSERERkUb4f53a5cM89RWyAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "slicot_full_names = {\n", + " \"a\": \"Analysis Routines\",\n", + " \"b\": \"Benchmark\",\n", + " \"c\": \"Adaptive Control\",\n", + " \"d\": \"Data Analysis\",\n", + " \"f\": \"Filtering\",\n", + " \"i\": \"Identification\",\n", + " \"m\": \"Mathematical routines\",\n", + " \"n\": \"Nonlinear Systems\",\n", + " \"s\": \"Synthesis Routines\",\n", + " \"t\": \"Transformation Routines\",\n", + " \"u\": \"Utility Routines\",\n", + "}\n", + "\n", + "def count_methods(list_routines, keys):\n", + " d = {key: 0 for key in keys}\n", + " for w in list_routines:\n", + " if w:\n", + " if w[0] in d:\n", + " d[w[0]] = d[w[0]] + 1\n", + " else:\n", + " d[w[0]] = 1\n", + " return d\n", + "\n", + "slicot_routines_dict = count_methods(slicot_routines, keys=slicot_full_names.keys())\n", + "slycot_routines_dict = count_methods(slycot_routines, keys=slicot_full_names.keys())\n", + "\n", + "df = pd.DataFrame(\n", + " {\n", + " \"chapter name\": slicot_full_names.values(),\n", + " \"slycot routines\": slycot_routines_dict.values(),\n", + " \"slicot routines\": slicot_routines_dict.values(),\n", + " },\n", + " index=slicot_routines_dict.keys()\n", + ")\n", + "csum = df.sum()\n", + "df.loc['total']= df.sum()\n", + "df.loc[df.index[-1], 'chapter name'] = '-'\n", + "display(df)\n", + "\n", + "names_sli = list(slicot_routines_dict.keys())\n", + "names_sli.reverse()\n", + "values_sli = list(slicot_routines_dict.values())\n", + "values_sli.reverse()\n", + "\n", + "names_sly = list(slycot_routines_dict.keys())\n", + "names_sly.reverse()\n", + "values_sly = list(slycot_routines_dict.values())\n", + "values_sly.reverse()\n", + "\n", + "height = 0.25\n", + "plt.barh(np.arange(len(slycot_routines_dict)), values_sly, height=height)\n", + "plt.barh(np.arange(len(slicot_routines_dict)) - height, values_sli, height=height)\n", + "plt.yticks(np.arange(len(slicot_routines_dict)) - height, [slicot_full_names[x] for x in names_sli])\n", + "plt.legend((\"Slycot\",\"SLICOT\"))\n", + "plt.title(\"Slycot vs SLICOT\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "venn2(subsets = (len(set(slycot_routines)),\n", + " len(set(slicot_routines)), \n", + " len(intersection)), set_labels = ('Slycot', 'SLICOT'))\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "slycot-dev", + "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.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/explanation/inspect_slycot.ipynb b/doc/source/explanation/inspect_slycot.ipynb new file mode 100644 index 00000000..d15bff71 --- /dev/null +++ b/doc/source/explanation/inspect_slycot.ipynb @@ -0,0 +1,344 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect Slycot" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook shows how to inspect the slycot module.\n", + "The result gives us a first insight which slicot procedures are implemented.\n", + "In addition we get some insight about the organization of the slycot module." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.5.5.dev75+g8cd8497\n" + ] + } + ], + "source": [ + "import re\n", + "import slycot\n", + "print(slycot.__version__)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper functions" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def print_list_chunks(routines_list, n=6):\n", + " \"\"\"Print list in chunks of lists.\"\"\"\n", + " start = 0\n", + " end = len(routines_list)\n", + " step = n\n", + " for i in range(start, end, step):\n", + " x = i\n", + " print(routines_list[x:x+step])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def get_slycot_routines(sly):\n", + " all_attributes = dir(sly)\n", + " r = re.compile(\"[a-z][a-z][0-9][0-9a-z][a-z][a-z]\")\n", + " matched_attributes = list(filter(r.match, all_attributes)) # Read Note below\n", + " return matched_attributes" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inspect Wrapper function" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Outer wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 56 routines that are found in slycot.\n", + "------\n", + "['ab01nd', 'ab04md', 'ab05md', 'ab05nd', 'ab07nd', 'ab08nd']\n", + "['ab08nz', 'ab09ad', 'ab09ax', 'ab09bd', 'ab09md', 'ab09nd']\n", + "['ab13bd', 'ab13dd', 'ab13ed', 'ab13fd', 'ab13md', 'ag08bd']\n", + "['mb02ed', 'mb03rd', 'mb03vd', 'mb03vy', 'mb03wd', 'mb05md']\n", + "['mb05nd', 'mc01td', 'sb01bd', 'sb02md', 'sb02mt', 'sb02od']\n", + "['sb03md', 'sb03md57', 'sb03od', 'sb04md', 'sb04qd', 'sb10ad']\n", + "['sb10dd', 'sb10fd', 'sb10hd', 'sb10jd', 'sb10yd', 'sg02ad']\n", + "['sg03ad', 'sg03bd', 'tb01id', 'tb01pd', 'tb03ad', 'tb04ad']\n", + "['tb05ad', 'tc01od', 'tc04ad', 'td04ad', 'tf01md', 'tf01rd']\n", + "['tg01ad', 'tg01fd']\n", + "None\n" + ] + } + ], + "source": [ + "slycot_wrapper = get_slycot_routines(slycot)\n", + "\n", + "print(f\"There are currently {len(slycot_wrapper)} routines that are found in slycot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(slycot_wrapper))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inner wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 74 routines that are found in slycot._wrapper.\n", + "------\n", + "['ab01nd', 'ab04md', 'ab05md', 'ab05nd', 'ab07nd', 'ab08nd']\n", + "['ab08nz', 'ab09ad', 'ab09ax', 'ab09bd', 'ab09md', 'ab09nd']\n", + "['ab13bd', 'ab13dd', 'ab13ed', 'ab13fd', 'ab13md', 'ag08bd']\n", + "['mb02ed', 'mb03rd', 'mb03vd', 'mb03vy', 'mb03wd', 'mb05md']\n", + "['mb05nd', 'mc01td', 'sb01bd', 'sb02md', 'sb02mt_c', 'sb02mt_cl']\n", + "['sb02mt_n', 'sb02mt_nl', 'sb02od_b', 'sb02od_c', 'sb02od_d', 'sb02od_n']\n", + "['sb03md', 'sb03od', 'sb04md', 'sb04qd', 'sb10ad', 'sb10dd']\n", + "['sb10fd', 'sb10hd', 'sb10jd', 'sb10yd', 'sg02ad_bb', 'sg02ad_bc']\n", + "['sg02ad_bd', 'sg02ad_bn', 'sg02ad_g', 'sg03ad', 'sg03bd', 'tb01id']\n", + "['tb01pd', 'tb03ad_l', 'tb03ad_r', 'tb04ad_c', 'tb04ad_r', 'tb05ad_ag']\n", + "['tb05ad_ng', 'tb05ad_nh', 'tc01od_l', 'tc01od_r', 'tc04ad_l', 'tc04ad_r']\n", + "['td04ad_c', 'td04ad_r', 'tf01md', 'tf01rd', 'tg01ad', 'tg01fd_ii']\n", + "['tg01fd_nn', 'tg01fd_uu']\n", + "None\n" + ] + } + ], + "source": [ + "slycot_f2py_wrapper = get_slycot_routines(slycot._wrapper)\n", + "\n", + "print(f\"There are currently {len(slycot_f2py_wrapper)} routines that are found in slycot._wrapper.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(slycot_f2py_wrapper))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Sets for the Venn-Diagramm" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from matplotlib_venn import venn2" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 11 routines that found in slycot not in slycot._wrapper.\n", + "------\n", + "['sb02od', 'sb02mt', 'sg02ad', 'tg01fd', 'td04ad', 'tb03ad']\n", + "['sb03md57', 'tc01od', 'tc04ad', 'tb04ad', 'tb05ad']\n", + "None\n", + "\n", + "\n", + "There are currently 29 routines that are found in slycot._wrapper not in slycot.\n", + "------\n", + "['sb02od_n', 'sg02ad_bd', 'sb02od_d', 'sg02ad_g', 'tb04ad_r', 'sg02ad_bn']\n", + "['tb05ad_ag', 'tc01od_l', 'sb02mt_c', 'sb02mt_cl', 'tb03ad_l', 'sb02od_c']\n", + "['tc04ad_r', 'sb02mt_n', 'tb05ad_nh', 'sb02od_b', 'tg01fd_uu', 'tg01fd_nn']\n", + "['tb03ad_r', 'tc01od_r', 'td04ad_r', 'tb04ad_c', 'sb02mt_nl', 'tc04ad_l']\n", + "['tg01fd_ii', 'sg02ad_bc', 'tb05ad_ng', 'td04ad_c', 'sg02ad_bb']\n", + "None\n", + "\n", + "\n" + ] + } + ], + "source": [ + "not_in_slycot_f2py_wrapper = list(set(slycot_wrapper) - set(slycot_f2py_wrapper))\n", + "not_in_slycot_f2py_wrapper\n", + "\n", + "print(f\"There are currently {len(not_in_slycot_f2py_wrapper)} routines that found in slycot not in slycot._wrapper.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(not_in_slycot_f2py_wrapper))\n", + "print(\"\\n\")\n", + "\n", + "not_in_slycot_wrapper = list(set(slycot_f2py_wrapper) - set(slycot_wrapper))\n", + "not_in_slycot_wrapper\n", + "\n", + "print(f\"There are currently {len(not_in_slycot_wrapper)} routines that are found in slycot._wrapper not in slycot.\")\n", + "print(\"------\")\n", + "print(print_list_chunks(not_in_slycot_wrapper))\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are currently 85 routines that are found in slycot or in slycot._wrapper. (union)\n", + "------\n", + "['ab04md', 'sg02ad_bd', 'mb02ed', 'tb04ad_r', 'sg02ad_g', 'sb04qd']\n", + "['sg02ad_bn', 'tf01md', 'td04ad', 'tb05ad_ag', 'tb01pd', 'tc04ad']\n", + "['tb01id', 'sb04md', 'sb02mt_cl', 'tc04ad_r', 'sb02od_b', 'tg01fd_uu']\n", + "['mb05md', 'tg01fd_nn', 'sb02mt', 'ab09ad', 'ab13md', 'mc01td']\n", + "['tg01fd', 'sg03ad', 'sb10hd', 'td04ad_r', 'ab09bd', 'sb01bd']\n", + "['tc04ad_l', 'tg01fd_ii', 'sb10fd', 'ab13bd', 'tb03ad', 'sg02ad_bc']\n", + "['ab09ax', 'ab09nd', 'sg02ad_bb', 'tb05ad', 'ab13fd', 'sb03md']\n", + "['sb02od_n', 'sb02od_d', 'ab08nd', 'tc01od_l', 'ab09md', 'sb02mt_c']\n", + "['sb10dd', 'tb03ad_l', 'ab08nz', 'sb02od_c', 'sg02ad', 'sb02mt_n']\n", + "['sg03bd', 'tb05ad_nh', 'sb03md57', 'tc01od', 'sb03od', 'mb03vd']\n", + "['sb10yd', 'tf01rd', 'sb02od', 'sb10ad', 'ab01nd', 'sb02md']\n", + "['tg01ad', 'tb03ad_r', 'sb10jd', 'mb05nd', 'mb03rd', 'mb03vy']\n", + "['tc01od_r', 'tb04ad_c', 'ab05nd', 'sb02mt_nl', 'mb03wd', 'ab13dd']\n", + "['ab07nd', 'ab05md', 'ag08bd', 'ab13ed', 'tb05ad_ng', 'tb04ad']\n", + "['td04ad_c']\n", + "None\n", + "\n", + "\n", + "There are currently 45 routines that are found in slycot and in slycot._wrapper. (intersection)\n", + "------\n", + "['ab04md', 'ab13fd', 'sb03md', 'mb02ed', 'ab08nd', 'sb04qd']\n", + "['tf01md', 'tb01pd', 'tb01id', 'ab09md', 'sb04md', 'sb10dd']\n", + "['ab08nz', 'sg03bd', 'sb03od', 'sb10yd', 'mb03vd', 'mb05md']\n", + "['tf01rd', 'sb10ad', 'ab09ad', 'ab01nd', 'ab13md', 'mc01td']\n", + "['sb02md', 'tg01ad', 'sg03ad', 'sb10jd', 'mb05nd', 'mb03rd']\n", + "['mb03vy', 'sb10hd', 'ab05nd', 'ab09bd', 'mb03wd', 'ab13dd']\n", + "['sb01bd', 'ab07nd', 'ab05md', 'sb10fd', 'ab13bd', 'ag08bd']\n", + "['ab13ed', 'ab09ax', 'ab09nd']\n", + "None\n", + "\n", + "\n" + ] + } + ], + "source": [ + "union = list(set(slycot_f2py_wrapper) | set(slycot_wrapper))\n", + "\n", + "print(f\"There are currently {len(union)} routines that are found in slycot or in slycot._wrapper. (union)\")\n", + "print(\"------\")\n", + "print(print_list_chunks(union))\n", + "print(\"\\n\")\n", + "\n", + "\n", + "intersection = list(set(slycot_f2py_wrapper) & set(slycot_wrapper))\n", + "intersection\n", + "\n", + "print(f\"There are currently {len(intersection)} routines that are found in slycot and in slycot._wrapper. (intersection)\")\n", + "print(\"------\")\n", + "print(print_list_chunks(intersection))\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "venn2(subsets = (len(set(slycot_wrapper)), \n", + " len(set(slycot_f2py_wrapper)), \n", + " len(intersection)), set_labels = ('slycot', 'slycot._wrapper'))\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "slycot-dev", + "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.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/explanation/slicot_routines.txt b/doc/source/explanation/slicot_routines.txt new file mode 100644 index 00000000..43bc7fe3 --- /dev/null +++ b/doc/source/explanation/slicot_routines.txt @@ -0,0 +1,607 @@ +mb01wd +tg01gd +ab13fd +sg03ay +mb01oe +mb02fd +tg01oa +dg01ny +sg03ax +fb01qd +ma02az +mc01md +md03by +tf01mx +ib01nd +mb02rz +mb04bp +tb01kd +ab09gd +ma02jz +ud01cd +ib01rd +nf01bx +mb02rd +ma02es +mb04iy +tg01id +mb01rd +mc01xd +mb04wr +sg03bs +mb03kc +ma02cd +tb04ad +md03bx +mb03vy +ab09cd +tf01nd +sb09md +sb03ot +mb04pu +mb04yd +mb02pd +mb04tu +mb02ud +ib01cd +mb04dp +tg01fz +sb04od +nf01ad +mb03qd +ab09bd +mb02jd +sb02mw +ma02ad +mb04dl +sb08ed +tb01uy +md03ba +ab05nd +mb03pd +sb02mx +sb04ow +ma02mz +mb02cy +ag08by +mb03bb +ab09cx +mb01kd +sb02sd +mb01xd +sb01md +mb02ny +sb02ox +sb10pd +ma01cd +tg01hd +mb02nd +sb02cx +sb04px +mb03qg +tg01hx +mb03ag +mc01py +mb03kb +mb04jd +tg01bd +tb03ay +ab13ed +sb03rd +ma02id +ma02md +sb03os +mb02cv +mb05oy +sb06nd +nf01bp +sb02od +mb03md +fb01vd +ma02iz +tb01ld +mb02sd +tb01nd +ud01md +mb02xd +mb02md +sg03br +mb04az +sb02ru +sb10qd +sg03bu +sb04qr +mb03lf +ma01ad +sb04rd +ma02gd +sb04ry +ab13ad +ab13md +nf01by +mb04nd +mb03yt +sg02cx +tg01hu +ab09kx +mb04hd +mb03gd +sb08cd +mb03od +sb04mr +mb02kd +ab09jx +ud01bd +fb01sd +mb03rd +ab07nd +mb03fd +sb03ou +mb03ya +mb01rh +sb08hd +ab08nw +ab07md +ab05qd +mb02qy +mb03id +ma02bd +ma02dd +mb04ed +sb03td +mb04tv +td04ad +tb01ud +tc01od +nf01bs +ma02oz +sg02nd +mb04ru +mc01rd +mb03bd +mb04tt +sb08ny +tg01ad +sb04qu +nf01bf +tg01qd +mc01td +mb04fp +mb03ud +mb3lzp +sb04nv +mb04qb +mb04wp +mc01sy +sb10dd +mb02sz +mb04kd +tb04bw +mb01ry +sb03mv +tb03ad +mb03gz +mb01ot +mb03be +tb01zd +ab04md +mb01os +sb03qx +mb04pb +nf01bu +mb04su +mc01od +sb16bd +mb02td +sg03ad +sb03qy +mb03xs +md03bb +mb04qc +mb03jd +sb01by +ab09nd +sb03md +mb04oy +mb05nd +ab08nx +mb01rb +dg01md +mb02wd +sb03ud +mb03py +mc01pd +ma02pz +ab09iy +ma02od +sb10td +tf01my +sb16cy +tg01oz +ab05pd +mb04cd +sb16ay +sb10hd +mb02gd +mc03md +mb03bc +sb04nx +mc01qd +ab01od +ab09jd +sb16ad +sg03bv +nf01bb +ab09dd +mb03lp +md03bf +mb03ah +mb3jzp +sb04mu +ab09kd +sb03ov +sb03pd +fd01ad +sb03sd +td05ad +mb02hd +mb02cd +mb03qx +sb04nd +mb04tb +sb04pd +tg01jy +tb04cd +tg01dd +ab09ed +mb03wx +tg01pd +tf01pd +sb08fd +ab13ax +nf01ba +sb08md +mb04dy +sb04my +ab09fd +mb04vd +mb01md +ib01oy +mb04ld +sb01bd +sb02mu +sg03bx +tg01ed +mb02qd +mb01ss +mb01rw +sb10ud +mb03cz +ag8byz +sb02ow +mb02dd +sb08nd +mb03my +mb03yd +tg01od +mc01sw +ma02bz +ib01ad +ab09hd +ud01mz +td03ad +sb03my +ib03bd +mb04dd +mb04xd +ma02hd +ab09ax +tg01hy +mc01sx +tb01ux +df01md +mb04vx +mb04wd +ab08md +tb01vd +nf01ay +md03bd +mb03rz +ab09ix +ab13dd +tb01iz +nf01bw +mb04qf +ab05sd +mb04db +mb03ai +sb08gd +mb02od +mb04ty +mb02uv +ib01px +tb01ty +sb03oy +sb03mu +tg01nd +ab09hx +ab09id +mb04id +mb03ed +mb04di +mb04tx +sb03od +mb04xy +mb03hz +tc04ad +mb01rx +sb02ov +mb03zd +mb03jp +mb02yd +mb04ox +bd01ad +mb04fd +ab05md +tb04bx +dg01od +sb10zd +mb01rt +sb02mr +ab01nd +mb04bz +ma01bz +ma02ed +mb03ld +tb01md +tb01xz +mb04qs +ab09md +sb10id +sb03sx +mb02cu +ab13bd +mb3oyz +mb02tz +tb01px +mb03iz +sg03bw +mb04dz +nf01bv +bd02ad +tf01md +mb03wd +mb4dbz +mb04tw +mb03vd +mb01oo +fb01rd +mb04rb +mb03ry +mb01xy +tb05ad +ib03ad +mb03xz +mb05md +mb02ed +sb03mw +sg03bd +mb01ru +mb01oc +bb02ad +ab09jw +mb03cd +mb04pa +sb10yd +mb02jx +tg01az +sg02ad +ma02hz +mb03dz +tg01md +sb08my +tb04ay +sb02nd +sb02mt +sb04rw +mb04wu +nf01be +de01pd +sb02mv +sb10ed +sb10zp +mb03lz +sb02oy +sb04md +mb03bg +mb03ad +mb01uw +sb10kd +ma02jd +ma02gz +tf01qd +mb03td +mb04gd +tb04bv +tg01ld +mb03ba +ue01md +mb3pyz +mb03xp +sb02ou +mb01nd +sg02cw +mb04yw +sb04mw +mb01uy +sg03by +ib01py +mb02uw +tg01ob +mb03jz +mb04ad +tg01fd +mb03sd +ab13id +ab08ny +mb03za +mb02uu +ab08nd +mc01wd +tg01ly +mb01uz +mb03xu +mb03nd +ag07bd +sg03bt +mb03xd +ma02nz +ab13dx +ab08nz +sb04ny +mb03ts +sb04qy +mb03rx +mb03af +ib01md +mb03ke +sb02pd +sb16cd +ab8nxz +mb04bd +tf01rd +mb01ux +mb03bz +sb03sy +mc03ny +sb10ld +ma02fd +td03ay +bb04ad +mb03ab +dk01md +ab05od +mc03nx +mb01td +tb01id +tg01cd +mb04ow +sb04nw +mb03ae +mb03rw +mb03qy +sb04py +nf01bq +mb03dd +tb01kx +mb01ud +ma01bd +mb03ny +ab08mz +sb02rd +sb04qd +tb01wx +ag08bz +tg01wd +tb04bd +sb02md +bb01ad +mc01sd +mc01vd +sb10ad +mb01vd +de01od +ib01pd +mb03bf +sb02ms +mb04py +mc03nd +tb01wd +mc01nd +dg01nd +ab09ad +mb02id +tb01yd +sb03mx +mb03vw +sg02cv +ab05rd +mb04ds +mb01od +mb4dpz +mb03oy +sb03qd +sb01bx +sb08dd +ib01od +sb10md +mb01ld +mb04iz +mb05od +tb01td +mb02vd +mb03fz +mb05my +mb01oh +mb04zd +sb03oz +tg01kz +mb02cx +tg01jd +mb01zd +mb01pd +sb01dd +mb03hd +sb02qd +mb03qw +tb01xd +ud01nd +sb10rd +ib01my +tf01od +ud01dd +tb01vy +ab09hy +sb04rx +ib01qd +mb04od +mb03qv +sg03bz +sb03or +mb03kd +ab13cd +tg01kd +mb03wa +mb04ts +mb03ka +mb4dlz +mb04qu +sb10fd +ma02pd +sb10jd +mb01qd +ab09jv +sb10vd +fb01td +ma02ez +tc05ad +sb10wd +md03ad +nf01bd +ma02cz +mb04ny +sb04rv +nf01br +tb01pd +ab01md +ib01bd +mb01yd +tg01nx +sb01fy +mb04md +sb10sd +mb04ud +mb01sd +ag08bd +ab09bx +bb03ad diff --git a/doc/source/guides/ab13dd_nb.ipynb b/doc/source/guides/ab13dd_nb.ipynb new file mode 100644 index 00000000..84af663b --- /dev/null +++ b/doc/source/guides/ab13dd_nb.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ab13dd Example\n", + "\n", + "Johannes Kaisinger, 26 July 2023" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy.linalg as linalg\n", + "import slycot" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([\n", + " [-1, 10],\n", + " [0, -1]\n", + "])\n", + "\n", + "B = np.array([\n", + " [0],\n", + " [1]])\n", + "\n", + "C = np.array([\n", + " [1, 0]])\n", + "D = np.zeros((1,1))\n", + "\n", + "n, m = B.shape\n", + "p, _ = C.shape" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Slycot H-infinity Norm" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.0\n" + ] + } + ], + "source": [ + "out = slycot.ab13dd('C', 'I', 'N', 'D', n, m, p, A, np.eye(n), B, C, D)\n", + "norm_sylcot, _ = out\n", + "print(norm_sylcot)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bisection algorithm H-infinity Norm" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def H_inf(A,B,C,D,gam_l,gam_h,emin):\n", + " \"\"\"naive implementation of bisection algorithm for H-infinity norm\n", + "\n", + " Args:\n", + " A (_type_): _description_\n", + " B (_type_): _description_\n", + " C (_type_): _description_\n", + " D (_type_): _description_\n", + " gam_l (_type_): _description_\n", + " gam_h (_type_): _description_\n", + " emin (_type_): _description_\n", + "\n", + " Returns:\n", + " _type_: _description_\n", + " \"\"\"\n", + " gam_last_stable = None\n", + " while (gam_h - gam_l) > emin:\n", + " gam = (gam_l+gam_h)/2\n", + " R = gam**2*np.eye(1)-D.T@D\n", + " R_inv = linalg.inv(R)\n", + " Mgam = np.vstack((\n", + " np.hstack((A+B@R_inv@D.T@C, B@R_inv@B.T)),\n", + " np.hstack((-C.T@(np.eye(1)+D@R_inv@D.T)@C, -(A+B@R_inv@D.T@C).T))))\n", + " d = linalg.eigvals(Mgam)\n", + " if np.any(np.imag(d)):\n", + " gam_l = gam\n", + " else:\n", + " gam_h = gam\n", + " gam_last_stable = gam\n", + " return gam_last_stable" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.000000000000638\n" + ] + } + ], + "source": [ + "norm_bi = H_inf(A,B,C,D,0.001,100,1e-10)\n", + "print(norm_bi)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compare" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.0\n", + "10.000000000000638\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# compare results\n", + "print(norm_sylcot)\n", + "print(norm_bi)\n", + "np.allclose(norm_sylcot,norm_bi)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "slycot-dev", + "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.10.6" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/guides/system_norms.rst b/doc/source/guides/system_norms.rst new file mode 100644 index 00000000..01126619 --- /dev/null +++ b/doc/source/guides/system_norms.rst @@ -0,0 +1,11 @@ +.. this page is referenced from the front page but it's unnecessary as a navigation section for now. + +:orphan: + +System norms +============ + +.. toctree:: + :maxdepth: 1 + + ab13dd_nb \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 00000000..47736c24 --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,63 @@ +.. Slycot documentation master file, created by + sphinx-quickstart on Thu Jan 18 21:43:47 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Slycot's documentation! +================================== + +Python wrapper for selected `SLICOT `_ routines, +notably including solvers for Riccati, Lyapunov, and Sylvester equations. + +Chapters +-------- + +The Slycot library is organised by chapters. Each chapter can be identified by a single letter. The following chapters are included: + +- ``A`` : Analysis Routines +- ``B`` : Benchmark +- ``C`` : Adaptive Control +- ``D`` : Data Analysis +- ``F`` : Filtering +- ``I`` : Identification +- ``M`` : Mathematical Routines +- ``N`` : Nonlinear Systems +- ``S`` : Synthesis Routines +- ``T`` : Transformation Routines +- ``U`` : Utility Routines + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: 🚀 Tutorials + + /tutorial/index + /tutorial/getting + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: 💡 Explanation + + /explanation/index + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: 🪄 How-to guides + + /guides/system_norms + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: 📚 Reference + + /reference/index + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Contributing + + /contributing/index diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst new file mode 100644 index 00000000..ee1de2dd --- /dev/null +++ b/doc/source/reference/index.rst @@ -0,0 +1,26 @@ +.. this page is referenced from the front page but it's unnecessary as a navigation section for now. + +:orphan: + +Reference +========= + +For most users only the :ref:`function-ref` is important. + +.. toctree:: + :maxdepth: 1 + + slycot_outer + +For advanced users and developer also the + +.. toctree:: + :maxdepth: 1 + + slycot_inner + +and the + +`SLICOT-Reference `_ + +can be important. \ No newline at end of file diff --git a/doc/source/reference/slycot_inner.rst b/doc/source/reference/slycot_inner.rst new file mode 100644 index 00000000..d9d54de8 --- /dev/null +++ b/doc/source/reference/slycot_inner.rst @@ -0,0 +1,112 @@ +.. _inner_function-ref: + +************************ +Inner function reference +************************ + +.. automodule:: slycot + :no-members: + :no-inherited-members: + :no-special-members: + +Analysis +======== + +.. autosummary:: + :toctree: generated/ + + _wrapper.ab01nd + _wrapper.ab04md + _wrapper.ab05md + _wrapper.ab05nd + _wrapper.ab07nd + _wrapper.ab08nd + _wrapper.ab08nz + _wrapper.ab09ad + _wrapper.ab09ax + _wrapper.ab09bd + _wrapper.ab09md + _wrapper.ab09nd + _wrapper.ab13bd + _wrapper.ab13dd + _wrapper.ab13ed + _wrapper.ab13fd + _wrapper.ab13md + _wrapper.ag08bd + +Mathematical routines +===================== + +.. autosummary:: + :toctree: generated/ + + _wrapper.mb02ed + _wrapper.mb03rd + _wrapper.mb03vd + _wrapper.mb03vy + _wrapper.mb03wd + _wrapper.mb05md + _wrapper.mb05nd + _wrapper.mc01td + +Synthesis +========= + +.. autosummary:: + :toctree: generated/ + + _wrapper.sb01bd + _wrapper.sb02md + _wrapper.sb02mt_c + _wrapper.sb02mt_cl + _wrapper.sb02mt_n + _wrapper.sb02mt_nl + _wrapper.sb02od_b + _wrapper.sb02od_c + _wrapper.sb02od_d + _wrapper.sb02od_n + _wrapper.sb03md + _wrapper.sb03od + _wrapper.sb04md + _wrapper.sb04qd + _wrapper.sb10ad + _wrapper.sb10dd + _wrapper.sb10fd + _wrapper.sb10hd + _wrapper.sb10jd + _wrapper.sb10yd + _wrapper.sg02ad_bb + _wrapper.sg02ad_bc + _wrapper.sg02ad_bd + _wrapper.sg02ad_bn + _wrapper.sg02ad_g + _wrapper.sg03ad + _wrapper.sg03bd + +Transformation Routines +======================= + +.. autosummary:: + :toctree: generated/ + + _wrapper.tb01id + _wrapper.tb01pd + _wrapper.tb03ad_l + _wrapper.tb03ad_r + _wrapper.tb04ad_c + _wrapper.tb04ad_r + _wrapper.tb05ad_ag + _wrapper.tb05ad_ng + _wrapper.tb05ad_nh + _wrapper.tc01od_l + _wrapper.tc01od_r + _wrapper.tc04ad_l + _wrapper.tc04ad_r + _wrapper.td04ad_c + _wrapper.td04ad_r + _wrapper.tf01md + _wrapper.tf01rd + _wrapper.tg01ad + _wrapper.tg01fd_ii + _wrapper.tg01fd_nn + _wrapper.tg01fd_uu \ No newline at end of file diff --git a/doc/source/reference/slycot_outer.rst b/doc/source/reference/slycot_outer.rst new file mode 100644 index 00000000..2fbd3b50 --- /dev/null +++ b/doc/source/reference/slycot_outer.rst @@ -0,0 +1,94 @@ +.. _function-ref: + +************************ +Outer function reference +************************ + +.. automodule:: slycot + :no-members: + :no-inherited-members: + :no-special-members: + +Analysis +======== + +.. autosummary:: + :toctree: generated/ + + ab01nd + ab04md + ab05md + ab05nd + ab07nd + ab08nd + ab08nz + ab09ad + ab09ax + ab09bd + ab09md + ab09nd + ab13bd + ab13dd + ab13ed + ab13fd + ab13md + ag08bd + +Mathematical routines +===================== + +.. autosummary:: + :toctree: generated/ + + mb02ed + mb03rd + mb03vd + mb03vy + mb03wd + mb05md + mb05nd + mc01td + +Synthesis +========= + +.. autosummary:: + :toctree: generated/ + + sb01bd + sb02md + sb02mt + sb02od + sb03md + sb03md57 + sb03od + sb04md + sb04qd + sb10ad + sb10dd + sb10fd + sb10hd + sb10jd + sb10yd + sg02ad + sg03ad + sg03bd + +Transformation Routines +======================= + +.. autosummary:: + :toctree: generated/ + + tb01id + tb01pd + tb03ad + tb04ad + tb05ad + tc01od + tc04ad + td04ad + tf01md + tf01rd + tg01ad + tg01fd \ No newline at end of file diff --git a/doc/source/tutorial/getting.rst b/doc/source/tutorial/getting.rst new file mode 100644 index 00000000..4beee7be --- /dev/null +++ b/doc/source/tutorial/getting.rst @@ -0,0 +1,7 @@ +Getting started +=============== + +There are two different ways to use the package. For the default interface +described in :ref:`function-ref`, simply import the slycot package as follows:: + + >>> import slycot \ No newline at end of file diff --git a/doc/source/tutorial/index.rst b/doc/source/tutorial/index.rst new file mode 100644 index 00000000..b0df32b6 --- /dev/null +++ b/doc/source/tutorial/index.rst @@ -0,0 +1,47 @@ +.. this page is referenced from the front page but it's unnecessary as a navigation section for now. + +:orphan: + +Installation +============ + +The `slycot` package can be installed using conda or pip. The +package requires `NumPy `_. + +For users with the Anaconda distribution of Python, the following +command can be used:: + + conda install -c conda-forge slycot + +This installs `slycot` from conda-forge, including the +`openblas` package. NumPy will also be installed if +they are not already present. + +.. note:: + Mixing packages from conda-forge and the default conda channel + can sometimes cause problems with dependencies, so it is usually best to + instally NumPy, SciPy, and Matplotlib from conda-forge as well. + +To install using pip:: + + pip install slycot + +.. note:: + If you install Slycot using pip you'll need a development + environment (e.g., Python development files, C and Fortran compilers). + Pip installation can be particularly complicated for Windows. + +Users can check to insure that slycot is installed +correctly by running the command:: + + python -c "import slycot" + +and verifying that no error message appears. More information on the +Slycot package can be obtained from the `Slycot project page +`_. + +Alternatively, to install from source, first `download the source +`_ and unpack it. +To install in your home directory, use:: + + pip install . \ No newline at end of file diff --git a/examples/ab13dd_example.py b/examples/ab13dd_example.py new file mode 100644 index 00000000..33855de5 --- /dev/null +++ b/examples/ab13dd_example.py @@ -0,0 +1,25 @@ +# Enrico Avventi 2010 + +import numpy as np +import slycot + +A = np.array([[ 0 , 1 , 0 , 0 , 0 , 0 ], + [ -0.5 , -0.0002 , 0 , 0 , 0 , 0 ], + [ 0 , 0 , 0 , 1 , 0 , 0 ], + [ 0 , 0 , -1 , -0.00002 , 0 , 0 ], + [ 0 , 0 , 0 , 0 , 0 , 1 ], + [ 0 , 0 , 0 , 0 , -2 , -0.000002 ]]) +B = np.array([[ 1 ], + [ 0 ], + [ 1 ], + [ 0 ], + [ 1 ], + [ 0 ]]) +C = np.array([[ 1 , 0 , 1 , 0 , 1 , 0 ]]) +D = np.array([[ 0 ]]) +out = slycot.ab13dd('C', 'I', 'N', 'D', 6, 1, 1, A, np.eye(6), B, C, D) +print('--- Example for ab13dd ---') +print('The L_infty norm of the system is') +print(out[0]) +print('The peak frequency is') +print(out[1]) \ No newline at end of file diff --git a/examples/ab13dd_nb.ipynb b/examples/ab13dd_nb.ipynb new file mode 100644 index 00000000..84af663b --- /dev/null +++ b/examples/ab13dd_nb.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ab13dd Example\n", + "\n", + "Johannes Kaisinger, 26 July 2023" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy.linalg as linalg\n", + "import slycot" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array([\n", + " [-1, 10],\n", + " [0, -1]\n", + "])\n", + "\n", + "B = np.array([\n", + " [0],\n", + " [1]])\n", + "\n", + "C = np.array([\n", + " [1, 0]])\n", + "D = np.zeros((1,1))\n", + "\n", + "n, m = B.shape\n", + "p, _ = C.shape" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Slycot H-infinity Norm" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.0\n" + ] + } + ], + "source": [ + "out = slycot.ab13dd('C', 'I', 'N', 'D', n, m, p, A, np.eye(n), B, C, D)\n", + "norm_sylcot, _ = out\n", + "print(norm_sylcot)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bisection algorithm H-infinity Norm" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def H_inf(A,B,C,D,gam_l,gam_h,emin):\n", + " \"\"\"naive implementation of bisection algorithm for H-infinity norm\n", + "\n", + " Args:\n", + " A (_type_): _description_\n", + " B (_type_): _description_\n", + " C (_type_): _description_\n", + " D (_type_): _description_\n", + " gam_l (_type_): _description_\n", + " gam_h (_type_): _description_\n", + " emin (_type_): _description_\n", + "\n", + " Returns:\n", + " _type_: _description_\n", + " \"\"\"\n", + " gam_last_stable = None\n", + " while (gam_h - gam_l) > emin:\n", + " gam = (gam_l+gam_h)/2\n", + " R = gam**2*np.eye(1)-D.T@D\n", + " R_inv = linalg.inv(R)\n", + " Mgam = np.vstack((\n", + " np.hstack((A+B@R_inv@D.T@C, B@R_inv@B.T)),\n", + " np.hstack((-C.T@(np.eye(1)+D@R_inv@D.T)@C, -(A+B@R_inv@D.T@C).T))))\n", + " d = linalg.eigvals(Mgam)\n", + " if np.any(np.imag(d)):\n", + " gam_l = gam\n", + " else:\n", + " gam_h = gam\n", + " gam_last_stable = gam\n", + " return gam_last_stable" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.000000000000638\n" + ] + } + ], + "source": [ + "norm_bi = H_inf(A,B,C,D,0.001,100,1e-10)\n", + "print(norm_bi)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compare" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10.0\n", + "10.000000000000638\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# compare results\n", + "print(norm_sylcot)\n", + "print(norm_bi)\n", + "np.allclose(norm_sylcot,norm_bi)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "slycot-dev", + "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.10.6" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}