diff --git a/.gitignore b/.gitignore index 864eb7b..28b1198 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,9 @@ eggs/ lib/ lib64/ parts/ +pantigny/ sdist/ +tmp/ var/ wheels/ *.egg-info/ diff --git a/InstallationSteps.png b/InstallationSteps.png new file mode 100644 index 0000000..1dbf4c6 Binary files /dev/null and b/InstallationSteps.png differ diff --git a/LuaLaTeX Sample.ipynb b/LuaLaTeX Sample.ipynb deleted file mode 100644 index ebb90d9..0000000 --- a/LuaLaTeX Sample.ipynb +++ /dev/null @@ -1,672 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The itikz extension is already loaded. To reload it, use:\n", - " %reload_ext itikz\n" - ] - } - ], - "source": [ - "%load_ext itikz" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "%reload_ext itikz" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\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", - "\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", - " \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", - " \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", - " \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", - "\n", - " \n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%itikz --tex-program=lualatex\n", - "\\documentclass{standalone}\n", - "\n", - "\\usepackage{tikz}\n", - "\n", - "\\usetikzlibrary{arrows.meta}\n", - "\\usetikzlibrary{calc}\n", - "\\usetikzlibrary{fit}\n", - "\\usetikzlibrary{graphs}\n", - "\\usetikzlibrary{matrix}\n", - "\\usetikzlibrary{positioning}\n", - "\n", - "\\usetikzlibrary{graphdrawing}\n", - "\\usegdlibrary{layered}\n", - "\n", - "\\begin{document}\n", - " \\begin{tikzpicture}[rounded corners,thick,\n", - " app/.style={draw=red,fill=red!20},\n", - " server/.style={draw=green,fill=green!20},\n", - " dbms/.style={draw=blue,fill=blue!20},\n", - " marble/.style={text=white,circle,font=\\footnotesize,fill=#1!75!black}]\n", - " \\graph [\n", - " layered layout,\n", - " level sep=0.75cm,sibling sep=0.5cm,\n", - " nodes={minimum height=1.5cm,minimum width=2.5cm,draw,align=center},\n", - " edges={arrows={-Stealth}}\n", - " ] {\n", - " RDBMS[dbms]\n", - " -> QB/Query\\\\Builder[dbms]\n", - " -> ORM/\"Object-\\\\Relational\\\\Mapping\"[dbms]\n", - " -> BL/Business\\\\Logic[app];\n", - " RDBMS -> ERD/\"Entity-\\\\Relationship\\\\Diagram\"[dbms];\n", - " { UI/UI Toolkit[app], BL, API/RESTful\\\\API[server] } -> SPA/\"Single-Page\\\\App\"[app];\n", - " BL -> Server/RESTful\\\\Server[server];\n", - " Validation[server] -> API;\n", - " { API, Auth/\"Authen-\\\\tication\"[server] } -> Server;\n", - "\n", - " { [nodes={gray,dashed,minimum height=0cm,minimum width=0cm},\n", - " edges={gray,dotted}]\n", - " TypeScript -> Vue;\n", - " Hapi -> Server;\n", - " Vue -> UI;\n", - " { Server, SPA } -> Testing;\n", - " Async -> { QB, ORM, BL, Auth, Validation };\n", - " };\n", - " };\n", - "\n", - " \\node[marble=blue] at (RDBMS.north east) {1};\n", - " \\node[marble=blue] at (ERD.north east) {2};\n", - " \\node[marble=blue] at (QB.north east) {3};\n", - " \\node[marble=blue] at (ORM.north east) {4};\n", - " \\node[marble=green] at (API.north east) {5};\n", - " \\node[marble=green] at (Server.south) {6};\n", - " \\node[marble=green] at (Validation.north east) {7};\n", - " \\node[marble=red] at (UI.north east) {8};\n", - " \\node[marble=red] at (SPA.south) {9};\n", - "\n", - " \\end{tikzpicture}\n", - "\\end{document}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/LuaLaTeX_Sample.ipynb b/LuaLaTeX_Sample.ipynb new file mode 100644 index 0000000..ab29293 --- /dev/null +++ b/LuaLaTeX_Sample.ipynb @@ -0,0 +1,663 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext itikz" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext itikz" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\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", + "\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", + " \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", + " \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", + " \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", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%itikz --tex-program=lualatex\n", + "\\documentclass{standalone}\n", + "\n", + "\\usepackage{tikz}\n", + "\n", + "\\usetikzlibrary{arrows.meta}\n", + "\\usetikzlibrary{calc}\n", + "\\usetikzlibrary{fit}\n", + "\\usetikzlibrary{graphs}\n", + "\\usetikzlibrary{matrix}\n", + "\\usetikzlibrary{positioning}\n", + "\n", + "\\usetikzlibrary{graphdrawing}\n", + "\\usegdlibrary{layered}\n", + "\n", + "\\begin{document}\n", + " \\begin{tikzpicture}[rounded corners,thick,\n", + " app/.style={draw=red,fill=red!20},\n", + " server/.style={draw=green,fill=green!20},\n", + " dbms/.style={draw=blue,fill=blue!20},\n", + " marble/.style={text=white,circle,font=\\footnotesize,fill=#1!75!black}]\n", + " \\graph [\n", + " layered layout,\n", + " level sep=0.75cm,sibling sep=0.5cm,\n", + " nodes={minimum height=1.5cm,minimum width=2.5cm,draw,align=center},\n", + " edges={arrows={-Stealth}}\n", + " ] {\n", + " RDBMS[dbms]\n", + " -> QB/Query\\\\Builder[dbms]\n", + " -> ORM/\"Object-\\\\Relational\\\\Mapping\"[dbms]\n", + " -> BL/Business\\\\Logic[app];\n", + " RDBMS -> ERD/\"Entity-\\\\Relationship\\\\Diagram\"[dbms];\n", + " { UI/UI Toolkit[app], BL, API/RESTful\\\\API[server] } -> SPA/\"Single-Page\\\\App\"[app];\n", + " BL -> Server/RESTful\\\\Server[server];\n", + " Validation[server] -> API;\n", + " { API, Auth/\"Authen-\\\\tication\"[server] } -> Server;\n", + "\n", + " { [nodes={gray,dashed,minimum height=0cm,minimum width=0cm},\n", + " edges={gray,dotted}]\n", + " TypeScript -> Vue;\n", + " Hapi -> Server;\n", + " Vue -> UI;\n", + " { Server, SPA } -> Testing;\n", + " Async -> { QB, ORM, BL, Auth, Validation };\n", + " };\n", + " };\n", + "\n", + " \\node[marble=blue] at (RDBMS.north east) {1};\n", + " \\node[marble=blue] at (ERD.north east) {2};\n", + " \\node[marble=blue] at (QB.north east) {3};\n", + " \\node[marble=blue] at (ORM.north east) {4};\n", + " \\node[marble=green] at (API.north east) {5};\n", + " \\node[marble=green] at (Server.south) {6};\n", + " \\node[marble=green] at (Validation.north east) {7};\n", + " \\node[marble=red] at (UI.north east) {8};\n", + " \\node[marble=red] at (SPA.south) {9};\n", + "\n", + " \\end{tikzpicture}\n", + "\\end{document}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Quickstart.ipynb b/Quickstart.ipynb index f5bcc7a..c5ea447 100644 --- a/Quickstart.ipynb +++ b/Quickstart.ipynb @@ -37,7 +37,8 @@ "See:\n", " \n", "- [Texlive](https://www.tug.org/texlive/)\n", - "- [pdf2svg](http://www.cityinthesky.co.uk/opensource/pdf2svg/)" + "- [pdf2svg](http://www.cityinthesky.co.uk/opensource/pdf2svg/)\n", + "- [Windows Instructions](InstallationSteps.png)" ] }, { @@ -89,7 +90,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -97,13 +98,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -139,7 +140,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -147,13 +148,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -201,10 +202,11 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "03f400523adb0f7d2fea15f4c4d6ad6e.svg 03f400523adb0f7d2fea15f4c4d6ad6e.tex\n" + "ls: cannot access '*.svg': No such file or directory\n", + "ls: cannot access '*.tex': No such file or directory\n" ] } ], @@ -227,7 +229,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -235,13 +237,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -276,13 +278,11 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "03f400523adb0f7d2fea15f4c4d6ad6e.svg\n", - "03f400523adb0f7d2fea15f4c4d6ad6e.tex\n", - "conway-04c3ec160176559dffa49ef2ac7746f2.svg\n", - "conway-04c3ec160176559dffa49ef2ac7746f2.tex\n" + "ls: cannot access '*.svg': No such file or directory\n", + "ls: cannot access '*.tex': No such file or directory\n" ] } ], @@ -314,7 +314,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -322,13 +322,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -363,7 +363,7 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ "ls: cannot access '*.svg': No such file or directory\n", @@ -389,7 +389,7 @@ "outputs": [], "source": [ "import os\n", - "os.environ['ITIKZ_TEMP_DIR'] = '1'" + "os.environ['ITIKZ_TEMP_DIR'] = 'C:/tmp'" ] }, { @@ -400,7 +400,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -408,13 +408,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -428,7 +428,7 @@ } ], "source": [ - "%%itikz --file-prefix conway-\n", + "%%itikz --file-prefix conway- --keep-file \"/tmp/itikz/foo\"\n", "\\documentclass[tikz]{standalone}\n", "\\begin{document}\n", "\\begin{tikzpicture}\n", @@ -448,7 +448,7 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ "ls: cannot access '*.svg': No such file or directory\n", @@ -499,37 +499,7 @@ "cell_type": "code", "execution_count": 15, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "%itikz --temp-dir --file-prefix conway- conway_str" ] @@ -538,7 +508,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Generally, string-generation is bad. One useful thing you can do without it is use an implicit `tikzpicture` environment. " + "Generally, string-generation is bad. One useful thing you can do is use a provided template `pic` environment." ] }, { @@ -549,7 +519,7 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", " \n", @@ -557,13 +527,13 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "" ], @@ -577,7 +547,7 @@ } ], "source": [ - "%%itikz --file-prefix implicit-demo- --implicit-pic \n", + "%%itikz --file-prefix implicit-demo- --template pic --keep-file tmp/implicit-demo\n", "\\draw[help lines] grid (5, 5);\n", "\\draw[fill=magenta!10] (1, 1) rectangle (2, 2);\n", "\\draw[fill=magenta!10] (2, 1) rectangle (3, 2);\n", @@ -599,22 +569,30 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "cat: implicit-demo-a6fdb3ecbc22048b7f090c20b5039b38.tex: No such file or directory\n" + "cat: 'implicit-demo-*.tex': No such file or directory\n" ] } ], "source": [ - "!cat implicit-demo-a6fdb3ecbc22048b7f090c20b5039b38.tex" + "!cat implicit-demo-*.tex" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "rm: cannot remove 'implicit-demo*': No such file or directory\n" + ] + } + ], "source": [ "!rm implicit-demo*" ] @@ -638,77 +616,77 @@ { "data": { "image/svg+xml": [ - "\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", - "\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", @@ -717,52 +695,52 @@ "\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", "" @@ -777,7 +755,7 @@ } ], "source": [ - "%%itikz --temp-dir --implicit-pic --tikz-libraries=quotes,angles --tex-packages=amsfonts --scale=2\n", + "%%itikz --temp-dir --template pic --tikz-libraries=quotes,angles --tex-packages=amsfonts --scale=2\n", "% Example from Paul Gaborit\n", "% http://www.texample.net/tikz/examples/angles-quotes/\n", "\\draw\n", @@ -786,7 +764,7 @@ " -- (2,2) coordinate (c) node[above right] {c}\n", " pic[\"$\\alpha$\", draw=orange, <->, angle eccentricity=1.2, angle radius=1cm]\n", " {angle=a--b--c};\n", - " \n", + "\n", "\\node[rotate=10] (r) at (2.5, 0.65) {Something about in $\\mathbb{R}^2$};" ] }, @@ -805,29 +783,29 @@ { "data": { "image/svg+xml": [ - "\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", @@ -850,47 +828,47 @@ "\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", "" @@ -905,7 +883,7 @@ } ], "source": [ - "%%itikz --temp-dir --implicit-standalone --tex-packages=smartdiagram,amsfonts\n", + "%%itikz --temp-dir --template standalone --tex-packages=smartdiagram,amsfonts\n", "\\smartdiagramset{uniform sequence color=true,\n", "sequence item border color=black,\n", "sequence item font size=\\footnotesize,\n", @@ -966,29 +944,29 @@ { "data": { "image/svg+xml": [ - "\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", @@ -997,55 +975,55 @@ "\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", + "\n", "\n", - "\n", + "\n", "\n", "" ], @@ -1067,11 +1045,11 @@ "\\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=2.8cm,\n", " semithick]\n", " \\tikzstyle{every state}=[fill=mymagenta,draw=none,text=white]\n", - " \n", + "\n", " {% for name, angle in nodes.items() -%}\n", " \\node[color=mymagenta] (v{{loop.index0}}) at ({{angle}}:1) {${{name}}$};\n", " {% endfor -%}\n", - " \n", + "\n", " {% for n1 in range(n) -%}\n", " {% for n2 in range(n) -%}\n", " {%if n1 < n2 -%}\n", @@ -1100,29 +1078,29 @@ { "data": { "image/svg+xml": [ - "\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", @@ -1131,55 +1109,55 @@ "\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", + "\n", "\n", - "\n", + "\n", "\n", "" ], @@ -1193,15 +1171,15 @@ } ], "source": [ - "%%itikz --as-jinja --temp-dir --tex-packages=tikz --tikz-libraries=arrows,automata --implicit-standalone\n", + "%%itikz --as-jinja --temp-dir --tex-packages=tikz --tikz-libraries=arrows,automata --template standalone\n", "\\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=2.8cm,\n", " semithick]\n", " \\tikzstyle{every state}=[fill=mymagenta,draw=none,text=white]\n", - " \n", + "\n", " {% for name, angle in nodes.items() -%}\n", " \\node[color=red] (v{{loop.index0}}) at ({{angle}}:1) {${{name}}$};\n", " {% endfor -%}\n", - " \n", + "\n", " {% for n1 in range(n) -%}\n", " {% for n2 in range(n) -%}\n", " {%if n1 < n2 -%}\n", @@ -1261,15 +1239,15 @@ } ], "source": [ - "%%itikz --as-jinja --print-jinja --temp-dir --as-jinja --tex-packages=tikz --tikz-libraries=arrows,automata --implicit-standalone\n", + "%%itikz --as-jinja --print-jinja --temp-dir --as-jinja --tex-packages=tikz --tikz-libraries=arrows,automata --template standalone\n", "\\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=2.8cm,\n", " semithick]\n", " \\tikzstyle{every state}=[fill=mymagenta,draw=none,text=white]\n", - " \n", + "\n", " {% for name, angle in nodes.items() -%}\n", " \\node[color=red] (v{{loop.index0}}) at ({{angle}}:1) {${{name}}$};\n", " {% endfor -%}\n", - " \n", + "\n", " {% for n1 in range(n) -%}\n", " {% for n2 in range(n) -%}\n", " {%if n1 < n2 -%}\n", @@ -1310,7 +1288,7 @@ "\\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=2.8cm,\n", " semithick]\n", " \\tikzstyle{every state}=[fill=mymagenta,draw=none,text=white]\n", - " \n", + "\n", "{% block content %}\n", "{% endblock %}\n", "\n", @@ -1343,29 +1321,29 @@ { "data": { "image/svg+xml": [ - "\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", @@ -1374,55 +1352,55 @@ "\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", + "\n", "\n", - "\n", + "\n", "\n", "" ], @@ -1443,7 +1421,7 @@ "{% for name, angle in nodes.items() %}\n", " \\node[color=mymagenta] (v{{loop.index0}}) at ({{angle}}:1) {${{name}}$};\n", "{% endfor -%}\n", - " \n", + "\n", "{% for n1 in range(n) %}\n", " {% for n2 in range(n) %}\n", " {%if n1 < n2 %}\n", @@ -1459,7 +1437,18 @@ "cell_type": "code", "execution_count": 28, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "rm: cannot remove '#': No such file or directory\n", + "rm: cannot remove 'ignore': No such file or directory\n", + "rm: cannot remove 'this,': No such file or directory\n", + "rm: cannot remove 'its just housekeeping': No such file or directory\n" + ] + } + ], "source": [ "!rm dag_demo.tex # ignore this, it's just housekeeping" ] @@ -1478,7 +1467,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHEAAABxCAYAAADifkzQAAAABmJLR0QA/wD/AP+gvaeTAAABuElEQVR4nO3czyoHUQBH8fOTP2FB2XoFOztPoORtLL2UJ1KWNnYKYSHFhMLi3k7nU7P/1rkzs5pZMadj4Ap4GD1kYQM4Aa4H7/hkffSAH+wBO6NHLNyOHvCVtdED8n9FFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQoosDM3+zPeMA2gSPgYPSQj1ajB3xjHzhjvn3nvO16GT0kf3fJW8CprhkfWfmlIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFFgHbgANkYPWdgFtoC70UMWToF74Hn0kI9WwA1wOHrIFx6Z73DdA9ujRyytAU+jR3xjxt+MTHUHvuudKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiCrwCz382MGOgB9wAAAAASUVORK5CYII=\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHEAAABxCAYAAADifkzQAAAABmJLR0QA/wD/AP+gvaeTAAABuElEQVR4nO3czyoHUQBH8fOTP2FB2XoFOztPoORtLL2UJ1KWNnYKYSHFhMLi3k7nU7P/1rkzs5pZMadj4Ap4GD1kYQM4Aa4H7/hkffSAH+wBO6NHLNyOHvCVtdED8n9FFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQoosDM3+zPeMA2gSPgYPSQj1ajB3xjHzhjvn3nvO16GT0kf3fJW8CprhkfWfmlIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFFgHbgANkYPWdgFtoC70UMWToF74Hn0kI9WwA1wOHrIFx6Z73DdA9ujRyytAU+jR3xjxt+MTHUHvuudKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiChRRoIgCRRQookARBYooUESBIgoUUaCIAkUUKKJAEQWKKFBEgSIKFFGgiAJFFCiiQBEFiihQRIEiCrwCz382MGOgB9wAAAAASUVORK5CYII=", "text/plain": [ "" ] @@ -1489,7 +1478,7 @@ } ], "source": [ - "%%itikz --implicit-pic --temp-dir --rasterize\n", + "%%itikz --template pic --temp-dir --rasterize\n", "\\draw[fill=black] (1, 1) rectangle (2, 2);\n", "\\draw[fill=black] (2, 1) rectangle (3, 2);\n", "\\draw[fill=black] (3, 1) rectangle (4, 2);\n", @@ -1506,28 +1495,11 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "l.6 \\end{tikzpicture}\n", - " \n", - "? \n", - "! Emergency stop.\n", - " \n", - " $\n", - "l.6 \\end{tikzpicture}\n", - " \n", - "! ==> Fatal error occurred, no output PDF file produced!\n", - "Transcript written on 26e1ca6384b15e1d929f6c01ce6ba32f.log.\n" - ] - } - ], + "outputs": [], "source": [ - "%%itikz --implicit-pic\n", + "%%itikz --template pic\n", "4$" ] }, @@ -1540,168 +1512,9 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018/Debian) (preloaded format=pdflatex)\n", - " restricted \\write18 enabled.\n", - "entering extended mode\n", - "(./26e1ca6384b15e1d929f6c01ce6ba32f.tex\n", - "LaTeX2e <2018-04-01> patch level 4\n", - "Babel <3.20> and hyphenation patterns for 84 language(s) loaded.\n", - "(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cls\n", - "Document Class: standalone 2018/03/26 v1.3a Class to compile TeX sub-files stan\n", - "dalone\n", - "(/usr/share/texlive/texmf-dist/tex/latex/tools/shellesc.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifluatex.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifpdf.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex))))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cfg)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls\n", - "Document Class: article 2014/09/29 v1.4h Standard LaTeX document class\n", - "(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-lists.t\n", - "ex)) (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def\n", - "(/usr/share/texlive/texmf-dist/tex/latex/ms/everyshi.sty))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def)))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.t\n", - "ex)) (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.de\n", - "f)))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.\n", - "tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.\n", - "tex)) (/usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code\n", - ".tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonomet\n", - "ric.code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.cod\n", - "e.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison\n", - ".code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.\n", - "tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code\n", - ".tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.\n", - "tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerari\n", - "thmetics.code.tex)))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.te\n", - "x)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.\n", - "code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code\n", - ".tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.te\n", - "x)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.c\n", - "ode.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformation\n", - "s.code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex\n", - ")\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.t\n", - "ex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing\n", - ".code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.te\n", - "x)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex\n", - ")\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex\n", - "\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.\n", - "tex))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.te\n", - "x)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.c\n", - "ode.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.\n", - "tex)))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex\n", - ") (/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex\n", - ")\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65\n", - ".sty)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18\n", - ".sty)) (/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex)))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex\n", - "\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers\n", - ".code.tex)\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex\n", - ")\n", - "(/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tik\n", - "zlibrarytopaths.code.tex))))\n", - "No file 26e1ca6384b15e1d929f6c01ce6ba32f.aux.\n", - "ABD: EveryShipout initializing macros\n", - "(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii\n", - "[Loading MPS to PDF converter (version 2006.09.02).]\n", - ") (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty)))\n", - "(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/etexcmds.sty)))\n", - "(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty)\n", - "(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg))\n", - "! Missing $ inserted.\n", - " \n", - " $\n", - "l.6 \\end{tikzpicture}\n", - " \n", - "? \n", - "! Emergency stop.\n", - " \n", - " $\n", - "l.6 \\end{tikzpicture}\n", - " \n", - "! ==> Fatal error occurred, no output PDF file produced!\n", - "Transcript written on 26e1ca6384b15e1d929f6c01ce6ba32f.log.\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "%%itikz --implicit-pic --full-error\n", "4$" @@ -1716,44 +1529,9 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "usage: %%itikz [--temp-dir] [--file-prefix FILE_PREFIX] [--implicit-pic]\n", - " [--implicit-standalone] [--scale SCALE]\n", - " [--tikz-libraries TIKZ_LIBRARIES] [--tex-packages TEX_PACKAGES]\n", - " [--as-jinja] [--print-jinja] [--rasterize] [--full-error] [-h]\n", - " [k]\n", - "\n", - "Tikz to tex to SVG\n", - "\n", - "positional arguments:\n", - " k the variable in IPython with the string source\n", - "\n", - "optional arguments:\n", - " --temp-dir emit artifacts to system temp dir\n", - " --file-prefix FILE_PREFIX\n", - " emit artifacts with a path prefix\n", - " --implicit-pic wrap source in implicit tikzpicture document\n", - " --implicit-standalone\n", - " wrap source in implicit document\n", - " --scale SCALE Set tikzpicture scale in --implicit-pic tmpl\n", - " --tikz-libraries TIKZ_LIBRARIES\n", - " Comma separated list of tikz libraries to use\n", - " --tex-packages TEX_PACKAGES\n", - " Comma separated list of tex packages to use\n", - " --as-jinja Interpret the source as a jinja2 template\n", - " --print-jinja Print interpolated jinja2 source then bail.\n", - " --rasterize Rasterize the svg with cairosvg\n", - " --full-error Emit the full error message\n", - " -h, --help show this help message\n" - ] - } - ], + "outputs": [], "source": [ "%itikz -h" ] @@ -1761,7 +1539,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1775,9 +1553,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.11.8" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/README.rst b/README.rst index 9e7d895..23c302d 100644 --- a/README.rst +++ b/README.rst @@ -11,15 +11,38 @@ itikz .. image:: https://img.shields.io/coveralls/github/jbn/itikz.svg :target: https://coveralls.io/github/jbn/itikz +Latex with Tikz to SVG conversion. Includes Cell magic for rendering in Jupyter -Cell magic for PGF/TikZ-to-SVG rendering in Jupyter +**This Fork of the original project has enhancements for the display of Linear Algebra Computations** * Free software: MIT license Basic Usage ----------- +The installation information below will install the version provided by the original author. +To use the upgraded version here, download it, and copy the itikz subdirectory into +a directory in your PYTHONPATH. -Install it: +* **Step by step instructions for Windows** are shown in + .. image:: InstallationInstructions.png + +Prerequisites: + +* a working TeX installation, e.g., https://tug.org/texlive/windows.html +* inkscape (ensure inkscape is on the path) +* pdf2svg (https://github.com/jalios/pdf2svg-windows enure the selected directory is on the path) + +Install itikz with `python -m pip install` + +To see the directories in your pythonpath, execute the following in python: + +.. code:: python + + import sys + for p in sys.path: + print( p ) + +To install the original version instead, run: .. code:: sh @@ -35,7 +58,7 @@ Use it: .. code:: tex - %%itikz --file-prefix implicit-demo- --implicit-pic + %%itikz --file-prefix implicit-demo- --template pic \draw[help lines] grid (5, 5); \draw[fill=magenta!10] (1, 1) rectangle (2, 2); \draw[fill=magenta!10] (2, 1) rectangle (3, 2); @@ -47,3 +70,17 @@ Getting Started Guide --------------------- `Getting Started Notebook `__ + +Youtube Video Introducing the nicematrix package +------------------------------------------------ + +``__ + +API +--- + +Python: + +..code:: build_commands, svg_from_tex, fetch_or_compile_svg + +Can be invoked from Julia using PyCall, tested in jupyter-lab and Pluto.jl diff --git a/develop_Itikz_NiceMatrix.ipynb b/develop_Itikz_NiceMatrix.ipynb new file mode 100644 index 0000000..cdec563 --- /dev/null +++ b/develop_Itikz_NiceMatrix.ipynb @@ -0,0 +1,20547 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = true;\n", + " const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = false;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n", + " require([\"katex\"], function(katex) {\n", + " window.katex = katex\n", + " on_load()\n", + " })\n", + " require([\"autoLoad\"], function(renderMathInElement) {\n", + " window.renderMathInElement = renderMathInElement\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 2;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.7.3.min.js\", \"https://cdn.holoviz.org/panel/1.7.5/dist/panel.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n require([\"katex\"], function(katex) {\n window.katex = katex\n on_load()\n })\n require([\"autoLoad\"], function(renderMathInElement) {\n window.renderMathInElement = renderMathInElement\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.7.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.7.3.min.js\", \"https://cdn.holoviz.org/panel/1.7.5/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "a81eb1a8-a973-4032-910b-01ea8491dadf" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = false;\n", + " const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = true;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n", + " require([\"katex\"], function(katex) {\n", + " window.katex = katex\n", + " on_load()\n", + " })\n", + " require([\"autoLoad\"], function(renderMathInElement) {\n", + " window.renderMathInElement = renderMathInElement\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 2;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = false;\n const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = true;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n require([\"katex\"], function(katex) {\n window.katex = katex\n on_load()\n })\n require([\"autoLoad\"], function(renderMathInElement) {\n window.renderMathInElement = renderMathInElement\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%load_ext itikz\n", + "import itikz\n", + "if False : from itikz import nicematrix_dev as nM\n", + "else: from itikz import nicematrix as nM\n", + "\n", + "import sympy as sym\n", + "\n", + "import jinja2\n", + "\n", + "import panel as pn ; pn.extension('katex')\n", + "import holoviews as hv; hv.extension('bokeh')\n", + "import numpy as np\n", + "import sympy as sym\n", + "\n", + "import os\n", + "import tempfile\n", + "from pathlib import Path\n", + "\n", + "from IPython.display import display\n", + "\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "np.random.seed(112244)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "C=sym.Matrix([[1, 1, 1], [1, 0, 1]])\n", + "def to_str(x, digits=3):\n", + " \"\"\"\n", + " Convert the input into a string representation.\n", + "\n", + " Parameters:\n", + " - `x`: The input value. Can be an integer, float, complex number, or a SymPy expression.\n", + "\n", + " Returns:\n", + " - A string representation of `x`.\n", + " \"\"\"\n", + "\n", + " # Check for integers\n", + " if isinstance(x, int):\n", + " return str(x)\n", + " elif isinstance(x, float):\n", + " return str(round(x, digits))\n", + " elif isinstance(x, complex):\n", + " real_part = round(x.real, digits)\n", + " imag_part = round(x.imag, digits)\n", + " if imag_part == 0:\n", + " return str(real_part)\n", + " elif real_part == 0:\n", + " return f\"{imag_part}i\"\n", + " elif imag_part > 0:\n", + " return f\"{real_part} + {imag_part}i\"\n", + " else:\n", + " return f\"{real_part} - {abs(imag_part)}i\"\n", + " elif isinstance(x, sym.Expr):\n", + " return str(x.evalf(digits))\n", + " elif isinstance(x, (bool,)):\n", + " return str(int(x)) # Since bool is a subclass of int in Python\n", + " else:\n", + " return str(x)\n", + "\n", + "nM.show_svd_table(C,formater=nM.to_str)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# Gaussian Elimination Type Algorithms" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def gen_matrix(m,n, low=1,high=9):\n", + " return np.random.randint( low=low,high=high, size=(m,n))\n", + "\n", + "def gen_cx_matrix(m,n, low=1,high=9):\n", + " return np.random.randint( low=low,high=high, size=(m,n))+\\\n", + " 1j*np.random.randint( low=low,high=high, size=(m,n))\n", + "\n", + "\n", + "A0 = None; A1 = gen_matrix(2,3); A2=gen_matrix(3,2); A3=gen_matrix(2,1)\n", + "B0 = gen_matrix(2,2); B1 = B0 @ A1; B2= B1 @ A2; B3=B2 @ A3\n", + "#C0 = gen_matrix(1,2); C1 = C0 @ B1; C2= C1 @ B2\n", + "\n", + "# - (2,3) (3,2) => COLS: 2 3 2\n", + "# (2,2) (2,3) (2,2) => ROWS: 3 2\n", + "\n", + "layers=[ [A0, A1, A2, A3],\n", + " [B0, B1, B2, B3],\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A0 = None; A1 = gen_matrix(2,3); A2=gen_matrix(2,2)\n", + "layers=[ [A0, A1], [A2, A1]]\n", + "h,m = nM.ge( layers, Nrhs=[0],\n", + " formater = sym.latex,\n", + " pivot_list=[ [(0,1), [(0,1)] ] ],\n", + " bg_for_entries = [[1,0, [(0,0)], 'yellow!15', 1], ],\n", + " ref_path_list = [ [1,0, [(0,0) ],'vv','cyan'],\n", + " ],\n", + " comment_list = [\" pivot in (1,1)\",],\n", + " variable_summary = [True,True,False],\n", + " array_names = ['E', ['A', 'b']],\n", + " tmp_dir=\"tmp\", keep_file=\"tmp/m3\"\n", + ")\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "rm: cannot remove 'tmp/*': No such file or directory\n" + ] + } + ], + "source": [ + "!ls tmp\n", + "!rm tmp/*" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "## MatrixGridLayout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#%load itikz/nicematrix.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| | | | |\n", + "| --- | --- | --- | --- |\n", + "| | | y y | |\n", + "| | x x x | y y |z |\n", + "| | x x x | y y |z |\n", + "| a a | * * * | * * |# |\n", + "| a a | * * * | * * |# |" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def testMatrixGridLayout():\n", + " A0 = None; A1 = gen_matrix(4,5);\n", + " B0 = gen_matrix(4,4); A2 = B0 @ A1;\n", + " B1 = gen_matrix(4,4); A3 = B1 @ A2;\n", + "\n", + " layers = [[ A0, A1], [B0, A2], [B1, A3]]\n", + " mm = nM.MatrixGridLayout(layers, extra_cols=[1,3,2], extra_rows=[0,0,0,2])\n", + " mm.describe()\n", + " print()\n", + " #print( 'no partition:', MatrixGridLayout.matrix_array_format( 5 ))\n", + " #print( 'partition: ', MatrixGridLayout.matrix_array_format( 5, vpartitions=[1,3,4] ))\n", + " #print()\n", + " print('Top Left : Bottom Right Corners')\n", + " for i in range(mm.nGridRows):\n", + " for j in range(mm.nGridCols):\n", + " tl,br,_ = mm._top_left_bottom_right(i,j)\n", + " print( f\" {tl}:{br}\", end='')\n", + " print()\n", + " # ====================================================================\n", + " # Process the Matrix Grid for Display\n", + " # ====================================================================\n", + " mm.array_format_string_list( partitions={ 1:[2], 2:[1], 3:[1]}, spacer_string=r'@{\\hspace{5mm}}' )\n", + " mm.array_of_tex_entries()\n", + " mm.nm_submatrix_locs()\n", + "\n", + " if True:\n", + " red = nM.make_decorator( text_color='red' )\n", + " boxbf = nM.make_decorator( boxed=True, bf=True, text_color='red')\n", + " bg = nM.make_decorator( text_bg=\"red!15\")\n", + "\n", + " mm.decorate_tex_entries( 0,3, red, entries=None )\n", + " mm.decorate_tex_entries( 1,2, boxbf, entries= [(1,0),(0,1)])\n", + " mm.decorate_tex_entries( 1,1, bg, entries=[(0,0),(1,1)] )\n", + "\n", + " #mm.decorate_tex_entries( 1,2, lambda a: '\\\\boxed{{ {a} }}'.format(a=a), entries= [(1,0),(0,1)])\n", + "\n", + " mm.tex_repr( blockseps = r'[3mm]') # r'\\noalign{\\vskip2mm} ')\n", + "\n", + " # ====================================================================\n", + "\n", + " print(\"% -------------------------------------\")\n", + " print(f\"format: {mm.format}\");\n", + " print(\"% -------------------------------------\")\n", + " print(\"LaTeX representation of the matrix\")\n", + " for l in mm.tex_list:\n", + " print(l)\n", + " print(\"% -------------------------------------\")\n", + " print(\"Submatrices:\", mm.locs )\n", + " print(\"% -------------------------------------\")\n", + "\n", + " return mm" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "## Example mX: Single Matrix, Extra Rows" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mX = nM.MatrixGridLayout([[None, gen_matrix(2,6)],[gen_matrix(2,2), gen_matrix(2,6)]], extra_cols=1, extra_rows=[1,1,0])\n", + "# extra_cols: add another column at the end\n", + "# extra_rows: add a row above, a row in the middle, no row at the end\n", + "mX.array_format_string_list( partitions={ 1:[2,1]}, spacer_string=r'@{\\hspace{5mm}}', last_col_format=r'l@{\\hspace{2.5cm}}' )\n", + "mX.array_of_tex_entries()\n", + "\n", + "# add some info in each of the extra rows\n", + "mX.add_row_above(0,1,['x_1','x_2','x_3'], formater = lambda a: '\\\\color{{magenta}}{{\\\\mathbf{{ {a} }}}}'.format(a=a))\n", + "mX.add_row_below(0,1,['x_1','x_2','x_3'], formater = lambda a: '\\\\color{{blue}}{{\\\\mathbf{{ {a} }}}}'.format(a=a))\n", + "\n", + "# add some info in each of the extra columns\n", + "mX.add_col_right(0,1,['b_1','b_2'], formater = lambda a: '\\\\color{{blue}}{{\\\\mathbf{{ {a} }}}}'.format(a=a))\n", + "\n", + "mX.nm_submatrix_locs()\n", + "\n", + "mX.tex_repr( blockseps = r'[2mm]')\n", + "mX_code = mX.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " mX_code, prefix='mX_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=4, keep_file=\"tmp/mX\" )\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "## Example m1" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1 = nM.MatrixGridLayout(gen_matrix(2,6), extra_cols=1, extra_rows=2)\n", + "m1.array_format_string_list( partitions={ 1:[3]}, spacer_string=r'@{\\hspace{5mm}}' )\n", + "m1.array_of_tex_entries()\n", + "m1.decorate_tex_entries( 0,1, lambda a: '\\\\color{{red}}{{ \\\\boxed{{{a}}} }}'.format(a=a), entries=[(0,0)] )\n", + "\n", + "blue = nM.make_decorator(text_color='blue', bf=True)\n", + "red = nM.make_decorator(text_color='red', bf=True)\n", + "\n", + "typ = [red(r'\\Uparrow'),red(r'\\Uparrow'),red(r'\\Uparrow'),blue(r'\\uparrow'),blue(r'\\uparrow'),blue(r'\\uparrow')]\n", + "var = [red('x_1'), red('x_2'), red('x_3'), blue('x_4'), blue('x_5'), blue('x_6')]\n", + "\n", + "m1.add_row_below(0,1,typ, formater=lambda a: a )\n", + "m1.add_row_below(0,1,var, offset=1, formater=lambda a: a )\n", + "\n", + "m1.nm_text( ['this here matrix is ...'])\n", + "m1.nm_submatrix_locs()\n", + "m1.tex_repr( blockseps = r'\\noalign{\\vskip2mm} ')\n", + "\n", + "m1_code = m1.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m1_code, prefix='m1_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=4, keep_file=\"tmp/m1\" )\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "## Example m2" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Layout 3 x 2 grid:\n", + ". insert extra_cols: [1, 3, 2]\n", + ". col_start = [ 1 8 15]\n", + ". row_start = [ 0 4 8 14]\n", + "\n", + "Consistent Matrix Sizes in the grid\n", + " (4, 4) (4, 5)\n", + " (4, 4) (4, 5)\n", + " (4, 4) (4, 5)\n", + "Actual TopLeft:BottomRight Indices\n", + " (np.int64(4), np.int64(5)):(np.int64(3), np.int64(4)) (np.int64(0), np.int64(8)):(np.int64(3), np.int64(12))\n", + " (np.int64(4), np.int64(1)):(np.int64(7), np.int64(4)) (np.int64(4), np.int64(8)):(np.int64(7), np.int64(12))\n", + " (np.int64(8), np.int64(1)):(np.int64(11), np.int64(4)) (np.int64(8), np.int64(8)):(np.int64(11), np.int64(12))\n", + "\n", + "Top Left : Bottom Right Corners\n", + " (np.int64(4), np.int64(5)):(np.int64(3), np.int64(4)) (np.int64(0), np.int64(8)):(np.int64(3), np.int64(12))\n", + " (np.int64(4), np.int64(1)):(np.int64(7), np.int64(4)) (np.int64(4), np.int64(8)):(np.int64(7), np.int64(12))\n", + " (np.int64(8), np.int64(1)):(np.int64(11), np.int64(4)) (np.int64(8), np.int64(8)):(np.int64(11), np.int64(12))\n", + "% -------------------------------------\n", + "format: r@{\\hspace{5mm}}rrrr@{\\hspace{5mm}}rrr@{\\hspace{5mm}}rrIrrr@{\\hspace{5mm}}rl@{\\hspace{2cm}}\n", + "% -------------------------------------\n", + "LaTeX representation of the matrix\n", + " & & & & & & & & 8 & 2 & 8 & 7 & 5 & & \\\\\n", + " & & & & & & & & 2 & 2 & 7 & 2 & 8 & & \\\\\n", + " & & & & & & & & 6 & 4 & 6 & 7 & 6 & & \\\\\n", + " & & & & & & & & 5 & 7 & 1 & 5 & 6 & & \\\\[3mm]\n", + " & 2 & 3 & 8 & 7 & & & & \\Block[draw=black,fill=red!15]{}{105} & 91 & 92 & 111 & 124 & & \\\\\n", + " & 2 & 7 & 2 & 5 & & & & 67 & \\Block[draw=black,fill=red!15]{}{61} & 82 & 67 & 108 & & \\\\\n", + " & 7 & 7 & 6 & 7 & & & & 141 & 101 & 148 & 140 & 169 & & \\\\\n", + " & 1 & 3 & 6 & 3 & & & & 65 & 53 & 68 & 70 & 83 & & \\\\[3mm]\n", + " & 5 & 7 & 5 & 5 & & & & 2024 & 1652 & 2114 & 2074 & 2636 & & \\\\\n", + " & 3 & 3 & 8 & 2 & & & & 1774 & 1370 & 1842 & 1794 & 2214 & & \\\\\n", + " & 6 & 5 & 8 & 1 & & & & 2158 & 1712 & 2214 & 2191 & 2719 & & \\\\\n", + " & 6 & 3 & 8 & 2 & & & & 2089 & 1643 & 2118 & 2127 & 2586 & & \\\\[3mm]\n", + " & & & & & & & & & & & & & & \\\\\n", + " & & & & & & & & & & & & & & \n", + "% -------------------------------------\n", + "Submatrices: [['name=A0x1', '{1-9}{4-13}'], ['name=A1x0', '{5-2}{8-5}'], ['name=A1x1', '{5-9}{8-13}'], ['name=A2x0', '{9-2}{12-5}'], ['name=A2x1', '{9-9}{12-13}']]\n", + "% -------------------------------------\n" + ] + } + ], + "source": [ + "m2=testMatrixGridLayout()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m2_latex_doc = m2.nm_latexdoc(template = nM.GE_TEMPLATE )\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m2_latex_doc, prefix='tst_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=\"tmp/m2\" )\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## Example m3" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "k = sym.Symbol('k'); h = sym.Symbol('h')\n", + "Ab = sym.Matrix([[1,2,4,1],[2,k,8,h],[3,7,3,1]]); matrices = [[None, Ab]]; pivots = []; txt=[]\n", + "# we could use row ops, but we want a computational layout (and hence the E matrices!):\n", + "# A=A.elementary_row_op('n->n+km', k=-3, row1=2,row2=0 );A\n", + "# A=A.elementary_row_op('n<->m',row1=1,row2=2);A\n", + "\n", + "E1=sym.eye(3);E1[1:,0]=[-2,-3]; A1=E1*Ab; matrices.append([E1,A1]); pivots.append((1,1));txt.append('Pivot at (1,1)')\n", + "E2=sym.eye(3);E2=E2.elementary_row_op('n<->m',row1=1,row2=2); A2=E2*A1; matrices.append([E2,A2]); pivots.append(None); txt.append('Rows 2 <-> 3')\n", + "E3=sym.eye(3);E3[2,1]=4-k; A3=E3*A2; matrices.append([E3,A3]); pivots.append((2,2));txt.append('Pivot at (2,2)')\n", + "pivots.append((3,3)); txt.append('In Row Echelon Form')\n", + "\n", + "if False:\n", + " mat_rep, submatrix_locs, pivot_locs, path_corners, txt_with_locs,mat_format = \\\n", + " nM.ge_layout( matrices, Nrhs=1, pivots=pivots, txt=txt, decorate=True,\\\n", + " formater=lambda x: sym.latex(x))\n", + "\n", + " mat_options = r\"\"\"[ code-before =\n", + " {\n", + " % ----------------------------------------------------------------------- Row-echelon form Path\n", + " \\tikz \\draw[red] \"\"\" + \" -- \".join( path_corners )+ \" ; } ]\"\n", + "\n", + " h =\\\n", + " itikz.fetch_or_compile_svg( jinja2.Template( nM.GE_TEMPLATE ).render( preamble=nM.preamble, extension=nM.extension,\n", + " mat_rep=mat_rep, mat_format=mat_format, mat_options=mat_options,\n", + " submatrix_locs=submatrix_locs, pivot_locs=pivot_locs, txt_with_locs=txt_with_locs),\n", + " prefix='sol_rhs_', working_dir='/tmp/itikz', debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), nexec=4, keep_file=\"/tmp/foo\" )\n", + " display(h)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# note the top annotation is not properly displayed. TODO: add mode space above when cropping the SVG\n", + "h,m = nM.ge( matrices, Nrhs=[1],\n", + " formater = sym.latex,\n", + " pivot_list=[ [(0,1), [(0,0)] ],\n", + " [(1,1), [(0,0)]], # ,(1,1)\n", + " [(2,1), [(0,0),(1,1)]],\n", + " [(3,1), [(0,0),(1,1)]] # ,(2,2)\n", + " ],\n", + " bg_for_entries = [[0,1, [(0,0)], 'yellow!15', 1],\n", + " [1,1, [(0,0) ], 'yellow!15', 1],\n", + " [1,1, [ (1,1) ], 'gray!15', 1],\n", + " [2,1, [(0,0),(1,1) ], 'yellow!15', 1],\n", + " [3,1, [(0,0),(1,1),(2,2)], 'yellow!15', 1],\n", + " [3,1, [(2,2)], 'gray!15', 1],\n", + " ],\n", + " ref_path_list = [ [0,1, [(0,0) ],'vv','cyan'],\n", + " [1,1, [(0,0),(1,1) ],'hv','cyan'],\n", + " [2,1, [(0,0),(1,1) ],'vh','cyan'],\n", + " [3,1, [(0,0),(1,1),(2,2)],'hh']\n", + " ],\n", + " comment_list = [\"pivot in (1,1)\",\n", + " r\"possible pivot in (2,2) \\\\ \\qquad provided $k \\ne 4$\",\n", + " r\"pivot in (2,2)\\\\ \\qquad after row exchange\",\n", + " r\"possible pivot in (3,3) \\\\ \\qquad provided $k \\ne 4$\"],\n", + " variable_summary = [True,True,True],\n", + " array_names = ['E', ['A', 'b']],\n", + " tmp_dir=\"tmp\", keep_file=\"tmp/m3\"\n", + ")\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# There is also a problem with the leftmost path in a single matrix\n", + "# TODO track down if it is itikz or nicematrix code\n", + "foo= [matrices[0]]\n", + "h,mm = nM.ge( foo, Nrhs=[1],\n", + " formater = sym.latex,\n", + " pivot_list=[ [(0,1), [(0,0)] ]\n", + " ],\n", + " bg_for_entries = [[ [0,1, [(0,0)], 'yellow!15', 1], [0,1, [(1,1)], 'black!15', 1]],\n", + " ],\n", + " ref_path_list = [ [0,1, [(0,0) ],'vv','cyan'],\n", + " ],\n", + " comment_list = [\"pivot in (1,1)\",],\n", + " variable_summary = [True,True,False],\n", + " array_names = ['E', ['A', 'b']],\n", + " tmp_dir=\"tmp\", keep_file=\"tmp/m3\"\n", + ")\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\tikz \\draw[blue,line width=0.6mm] let \\p1 = (A0x1.north west), \\p2 = (A0x1.south east), \\p3 = (4-|4), \\p4 = (4-|4) in (\\x1,\\y1) -- (\\x4,\\y2);\n", + "\\tikz \\draw[blue,line width=0.6mm] let \\p1 = (A1x1.north west), \\p2 = (A1x1.south east), \\p3 = (5-|4), \\p4 = (7-|5) in (\\x1,\\y3) -- ($ (5-|5) + (0.1,0) $) -- ($ (\\x4,\\y2) + (0.1,0) $);\n", + "\\tikz \\draw[cyan,line width=0.6mm] let \\p1 = (A2x1.north west), \\p2 = (A2x1.south east), \\p3 = (8-|4), \\p4 = (9-|5) in (\\x1,\\y1) -- (\\x1,\\y3) -- ($ (8-|5) + (0.1,0) $) -- ($ (9-|5) + (0.1,0) $) -- (\\x2,\\y4);\n", + "\\tikz \\draw[blue,line width=0.6mm] let \\p1 = (A3x1.north west), \\p2 = (A3x1.south east), \\p3 = (11-|4), \\p4 = (13-|6) in (\\x1,\\y3) -- ($ (11-|5) + (0.1,0) $) -- ($ (12-|5) + (0.1,0) $) -- ($ (12-|6) + (0.1,0) $) -- ($ (\\x4,\\y2) + (0.1,0) $) -- (\\x2,\\y2);\n" + ] + } + ], + "source": [ + "# We can use m to add additional decorations before converting to an SVG\n", + "m.rowechelon_paths=[]\n", + "m.submatrix_name = 'A'\n", + "\n", + "def nm_add_rowechelon_path( self, gM,gN, pivots, case='hh', color='red' ):\n", + " tl,_,shape = self._top_left_bottom_right( gM, gN )\n", + "\n", + " # --------------------------------------------- # add the end point\n", + " if (case=='vh') or (case=='hh'): # last dir: ->\n", + " pivots.append( (pivots[-1][0]+1,shape[1])) # we end in current row+1, last col\n", + " else: # last dir: |\n", + " pivots.append( (shape[0],pivots[-1][1])) # we end in current col, last row\n", + "\n", + " # --------------------------------------------- # obtain the corner positions\n", + " if (case == 'vh') or (case == 'vv'): # first motion is vertical: go down 1 row\n", + " cur = pivots[0] # since we move vertically, start at cur north east\n", + " else: # first move is horizontal\n", + " cur = (pivots[0][0]+1, pivots[0][1]) # since we move horizontally, start at cur south east\n", + "\n", + " ll = [ cur ]\n", + " for nxt in pivots[1:]:\n", + " if nxt[1] != cur[1]: # next entry is in a different column: first go down to its row\n", + " ll.append( (nxt[0],cur[1]) )\n", + " ll.append( nxt ) # now move horizontally to this entry\n", + " cur = nxt\n", + "\n", + " # --------------------------------------------- # generate the tikz command\n", + " if (case=='vh') or (case=='hh'): # last dir: ->\n", + " i,j = ll[-2]\n", + " pos = f'let \\\\p1 = ({self.submatrix_name}{gM}x{gN}.south east), \\\\p2 = ({i+tl[0]+1}-|{j+tl[1]+1}) in '\n", + " end = r' -- (\\x2,\\y1) -- (\\x1,\\y1);'\n", + " ndx = -2\n", + " else: # last dir: |\n", + " i,j = ll[-1]\n", + " pos = f'let \\\\p1 = ({self.submatrix_name}{gM}x{gN}.south west), \\\\p2 = ({i+tl[0]+1}-|{j+tl[1]+1}) in '\n", + " end = r' -- (\\x2,\\y1);'\n", + " ndx = -1\n", + "\n", + " cmd = '\\\\tikz \\\\draw['+color+'] ' + pos + ' -- '.join( [f'({i+tl[0]+1}-|{j+tl[1]+1})' for (i,j) in ll[:ndx]]) + end\n", + " self.rowechelon_paths.append( cmd )\n", + "\n", + "m.nm_add_rowechelon_path( 0,1, [(0,0) ],'vv','blue,line width=0.6mm')\n", + "m.nm_add_rowechelon_path( 1,1, [(0,0),(1,1) ],'hv','blue,line width=0.6mm')\n", + "m.nm_add_rowechelon_path( 2,1, [(0,0),(1,1) ],'vh','cyan,line width=0.6mm')\n", + "m.nm_add_rowechelon_path( 3,1, [(0,0),(1,1),(2,2)],'hh','blue,line width=0.6mm')\n", + "\n", + "for tikz in m.rowechelon_paths: print(tikz)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m_code = m.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m_code, prefix='ge_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file='tmp/tst' )\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# Fancy QR Example" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = sym.Matrix([[ 1, 1, -1],\n", + " [ 1, -2, 1],\n", + " [-1, -1, 2],\n", + " [ 1, 1, -1]])\n", + "W = sym.Matrix([[ 1, 1, 1],\n", + " [ 1, -3, 0],\n", + " [-1, -1, 2],\n", + " [ 1, 1, 1]])\n", + "\n", + "WtW = W.T @ W\n", + "WtA = W.T @ A\n", + "S = WtW**(-1)\n", + "for i in range(S.shape[0]):\n", + " S[i,i]=sym.sqrt(S[i,i])\n", + "\n", + "Qt = S*W.T\n", + "R = S*WtA\n", + "\n", + "matrices = [ [ None, None, A, W ],\n", + " [ None, W.T, WtA, WtW ],\n", + " [ S, Qt, R, None ] ]\n", + "\n", + "def nM_qr(matrices, formater=repr , array_names=True, scale=0.5, tmp_dir=None, keep_file=None):\n", + " mZ = nM.MatrixGridLayout( matrices, extra_rows = [1,0,0,0])\n", + "\n", + " mZ.array_format_string_list()\n", + " mZ.array_of_tex_entries(formater=formater)\n", + "\n", + " brown = nM.make_decorator(text_color='brown', bf=True )\n", + " def qr_dec_known_zeros( WtA, WtW ):\n", + " l_WtA = [(1,2), [(i,j) for i in range(WtA.shape[0]) for j in range(WtA.shape[0]) if i > j ]]\n", + " l_WtW = [(1,3), [(i,j) for i in range(WtW.shape[0]) for j in range(WtW.shape[0]) if i != j ]]\n", + " return [l_WtA, l_WtW]\n", + "\n", + " for spec in qr_dec_known_zeros(WtA, WtW):\n", + " #[ [(1,2), [(1,0),(2,0),(2,1)]], [(1,3), [(1,0),(2,0),(2,1), (0,1),(0,2),(1,2)]] ]:\n", + " mZ.decorate_tex_entries( *spec[0], brown, entries=spec[1] )\n", + "\n", + " red = nM.make_decorator(text_color='red', bf=True)\n", + " red_rgt = nM.make_decorator(text_color='red', bf=True, move_right=True)\n", + " mZ.add_row_above(0,2, [red(f'v_{i+1}') for i in range(3)] + [red(f'w_{i+1}') for i in range(3)], formater= lambda a: a )\n", + " mZ.add_col_left( 1,1, [red_rgt(f'w^t_{i+1}') for i in range(3)], formater= lambda a: a )\n", + "\n", + " if array_names:\n", + " dec = nM.make_decorator(bf=True, delim='$')\n", + " mZ.nm_submatrix_locs( 'QR', color='blue', name_specs=[\n", + " [(0,2), 'al', dec('A')],\n", + " [(0,3), 'ar', dec('W')],\n", + " # ----------------------\n", + " [(1,1), 'al', dec('W^t')],\n", + " [(1,2), 'al', dec('W^t A')],\n", + " [(1,3), 'ar', dec('W^t W')],\n", + " # ----------------------\n", + " [(2,0), 'al', dec(r'S = \\left( W^t W \\right)^{-\\tfrac{1}{2}}')],\n", + " [(2,1), 'br', dec(r'Q^t = S W^t')],\n", + " [(2,2), 'br', dec('R = S W^t A')]\n", + " ] )\n", + " else:\n", + " mZ.nm_submatrix_locs()\n", + "\n", + " mZ.tex_repr( blockseps = r'\\noalign{\\vskip3mm} ')\n", + "\n", + " mZ.preamble = nM.preamble + r\" \\NiceMatrixOptions{cell-space-limits = 2pt}\"\n", + " mZ_code = mZ.nm_latexdoc( fig_scale=scale )\n", + "\n", + " h = itikz.fetch_or_compile_svg(\n", + " mZ_code, prefix='qr_', working_dir=tmp_dir, debug=False, scale=0.8,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=keep_file )\n", + " return h, mZ\n", + "\n", + "#h,mz = nM.qr( matrices, formater=lambda x: '{0:.8f}'.format(float(x)), array_names=True, fig_scale=0.7, tmp_dir=\"/tmp\", keep_file='/tmp/qr')\n", + "h,mz = nM.qr( matrices, formater=sym.latex, array_names=True, tmp_dir=\"/tmp\", keep_file='/tmp/qr_fancy')\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# Matrix Stacks" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = np.array( [[-1,2,2],[2,0,-3]])\n", + "B = np.array( [[3,1],[0,-1],[2,2]])\n", + "C = np.array( [[2,2,1,-1],[-2,-1,0,-1]])\n", + "AB = A @ B\n", + "ABC = AB @ C\n", + "\n", + "matrices=[[None, B, C],[A, AB, ABC]]\n", + "m_lr = nM.MatrixGridLayout(matrices, extra_cols=1, extra_rows=2)\n", + "m_lr.array_format_string_list( spacer_string=r'@{\\hspace{5mm}}', last_col_format=r'l@{\\hspace{2.0cm}}',\n", + " partitions={2:[1,3]},\n", + " )\n", + "m_lr.array_of_tex_entries()\n", + "\n", + "dec = nM.make_decorator(bf=True, delim='$')\n", + "m_lr.nm_submatrix_locs( 'PROD', color='blue', name_specs=[\n", + " [(0,1), 'ar', dec('B')],\n", + " [(0,2), 'ar', dec('C')],\n", + " # ----------------------\n", + " [(1,0), 'al', dec('A')],\n", + " [(1,1), 'al', dec('A B')],\n", + " [(1,2), 'ar', dec('A B C')],\n", + " ],\n", + " line_specs = [\n", + " [(0,1), [1,2], None],\n", + " [(1,0), None, [1,2]]\n", + " ]\n", + " )\n", + "\n", + "def foo(m):\n", + " m.preamble = r'\\tikzset{highlight/.style = { fit = #1 , fill=red!15, inner sep = 2pt } } %' +\\\n", + " '\\n' #+\\\n", + " #r'\\tikzset{erase/.style = { fit = #1 , fill=Olive!90!Fuchsia, inner sep = 2pt } }'\n", + " m.codebefore.append( f'\\\\tikz \\\\node [highlight = (2-5)] {{ }} ;')\n", + " for k in ['(4-1) (4-3)','(5-3)', '(1-5) (3-5)']:\n", + " m.codebefore.append( f'\\\\tikz \\\\node [highlight = {k}] {{ }} ;')\n", + " #for k in ['(2-9) (3-9)','(4-9) (5-9)', '(4-4) (5-4)']:\n", + " # m.rowechelon_paths.append( f'\\\\node [erase = {k}] {{ }} ;')\n", + "\n", + " #dark = nM.make_decorator(text_color='Brown4', bg_color='Green4!60')\n", + "# m.codebefore.append(r'''\\cellcolor{red!15}{1-6,2-9,2-12,3-11} ''')\n", + "# m.codebefore.append(r'''\\columncolor{blue!15}{3} ''')\n", + "# m.decorate_tex_entries( 0,1, dark, entries=[(0,1),(1,1),(2,1)])\n", + "# m.decorate_tex_entries( 1,0, dark, entries=[(0,0),(0,1),(0,2)])\n", + "#m_lr.apply(foo)\n", + "#foo(m_lr)\n", + "#m_lr.nm_background( ['(4-1) (4-3)','(5-3)', '(1-5) (3-5)'], color='blue!30' )\n", + "#m_lr.nm_background( ['(2-6) (3-9)'], style_name='redbg', color='red!15' )\n", + "#m_lr.nm_background( ['(2-9) (3-9)','(4-9) (5-9)', '(4-4) (5-4)'], style_name='erase', color='black!30' )\n", + "\n", + "#m_lr.nm_background( 0,1, [(0,0),[(0,1),(2,1)]], color='blue!30', style_name='style_blue')\n", + "#m_lr.nm_background( 0,2, [[(0,0), (0,3)]], color='red!15', style_name='style_red')\n", + "#m_lr.nm_background( 1,0, [[(0,0), (0,2)]], color='black!30',style_name='erase')\n", + "#m_lr.nm_background( 1,1, [[(0,0), (0,1)]], color='black!30',style_name='erase')\n", + "#m_lr.nm_background( 1,2, [[(0,0), (0,3)]], color='black!30',style_name='erase')\n", + "\n", + "m_lr.tex_repr() # blockseps = r'\\noalign{\\vskip2mm} ')\n", + "\n", + "m_lr_code = m_lr.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m_lr_code, prefix='abc_',\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1,debug=False, working_dir=\"tmp\", keep_file=\"tmp/abc_lr_pb\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "entry: (1, 0)\n", + "entry: [(0, 0), (1, 3)]\n", + "entry: [(0, 0), (1, 0)]\n", + "entry: (1, 1)\n", + "['(4-1)', '(5-1)', '(5-2)']\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def _mk_entries( self, gM, gN, *args ):\n", + " tl,_,_ = self._top_left_bottom_right( gM, gN )\n", + "\n", + " def mk(entry):\n", + " print('entry:', entry)\n", + " if not isinstance( entry, list):\n", + " return [f'({tl[0]+entry[0]+1}-{tl[1]+entry[1]+1})']\n", + " i1,j1 = entry[0]\n", + " i2,j2 = entry[-1]\n", + "\n", + " return [f'({tl[0]+i+1}-{tl[1]+j+1})' for i in range(i1,i2+1) for j in range(j1,j2+1)]\n", + "\n", + " l = [mk(entry) for entry in args]\n", + " return [loc for sublist in l for loc in sublist]\n", + "\n", + "def nm_background( self, gM, gN, entries, style_name='highlight', color='red!15' ):\n", + " if style_name not in self.stylenames:\n", + " self.stylenames.append( style_name )\n", + " self.preamble = self.preamble + r'\\tikzset{' + style_name + f'/.style = {{ fit = #1 , fill={color}, inner sep = 2pt }} }} %' + '\\n'\n", + " for entry in entries:\n", + " for k in _mk_entries(self, gM,gN, entry):\n", + " self.codebefore.append( f'\\\\tikz \\\\node [{style_name} = {k}] {{ }} ;')\n", + "\n", + "def foo(*args):\n", + " for arg in args:\n", + " print(arg)\n", + "#foo([(0,0), (1,1)])\n", + "m_lr.stylenames=[]\n", + "nm_background( m_lr, 1,0, [ (1,0), [(0,0), (1,3)]] )\n", + "print( _mk_entries( m_lr, 1,0, [(0,0), (1,0)], (1,1)) )\n", + "#_mk_entries( m_lr, 1,0, (1,1), (1,2), [(2,1),(3,2)])\n", + "\n", + "m_lr_code = m_lr.nm_latexdoc()\n", + "\n", + "if True:\n", + " h = itikz.fetch_or_compile_svg(\n", + " m_lr_code, prefix='m_lr_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=\"tmp/m_lr\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = np.array( [[1,2,2],[2,0,3]])\n", + "B = np.array( [[3,1],[0,1],[2,2]])\n", + "C = np.array( [[2,2,1,1],[-2,-1,0,1]])\n", + "AB = A @ B\n", + "ABC = AB @ C\n", + "\n", + "matrices=[[None,C],[B, B@C], [A,ABC]]\n", + "m_td = nM.MatrixGridLayout(matrices, extra_cols=1, extra_rows=2)\n", + "m_td.array_format_string_list( spacer_string=r'@{\\hspace{5mm}}',\n", + " last_col_format=r'l@{\\hspace{2cm}}' )\n", + "m_td.array_of_tex_entries()\n", + "\n", + "#m_td.add_horizontal_partition( 0,1,0, (0,3))\n", + "#m_td.add_horizontal_partition( 1,1,1, (0,3))\n", + "\n", + "dec = nM.make_decorator(bf=True, delim='$')\n", + "m_td.nm_submatrix_locs( 'PROD', color='blue', name_specs=[\n", + " [(0,1), 'al', dec('C')],\n", + " # ----------------------\n", + " [(1,0), 'al', dec('B')],\n", + " [(1,1), 'al', dec('B C')],\n", + " [(2,0), 'al', dec('A')],\n", + " [(2,1), 'ar', dec('A B C')],\n", + " ] ,\n", + " line_specs = [\n", + " [(0,1), 1, None],\n", + " [(1,0), None, 1], [(1,1), 2,[1,2,3]],\n", + " [(2,0), None, 2], [(2,1),None,[1,2,3]]\n", + " ]\n", + " )\n", + "m_td.tex_repr(blockseps = r'[2mm]') # blockseps = r'\\noalign{\\vskip2mm} ')\n", + "#m_td.add_horizontal_partitions( [[0,2,0,[0,4]] ])\n", + "\n", + "m_td_code = m_td.nm_latexdoc()\n", + "\n", + "if True:\n", + " h = itikz.fetch_or_compile_svg(\n", + " m_td_code, prefix='m_td_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=\"tmp/abc_td\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'tex_program': ['latexmk', '-quiet', '-silent', '-xelatex'],\n", + " 'svg_converter': [['dvisvgm', '--font-format=woff2', '--exact'], '.xdv'],\n", + " 'svg_crop': ['inkscape',\n", + " '--batch-process',\n", + " '--export-plain-svg',\n", + " '-D',\n", + " '--export-margin=1',\n", + " '-o']}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "itikz.build_commands_dict(use_xetex=True,use_dvi=True,crop=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "# Eigenproblem Tables" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": "true", + "tags": [] + }, + "source": [ + "## Use itikz directly" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\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", + " \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", + "\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", + " \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", + "\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", + "\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", + " \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", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%itikz --template standalone --tex-packages=booktabs,mathtools,nicematrix,xcolor --use-xetex --keep-file ./tmp/ep --temp-dir\n", + "% --debug\n", + "\\begin{tabular}{@{}lccc@{}} \\toprule\n", + "$\\color{blue}{\\sigma}$ & $\\sqrt{3}$ & & $\\sqrt{2}$ \\\\ \\cmidrule{2-2} \\cmidrule{4-4}\n", + "$\\color{blue}{\\lambda}$ & $3$ & & $2$ \\\\ \\cmidrule{2-2} \\cmidrule{4-4}\n", + "$\\color{blue}{\\left( m_a \\right)}$ & $(2)$ & & $(1)$ \\\\ \\cmidrule{2-2} \\cmidrule{4-4} \\addlinespace[1mm]\n", + "% ------------------------------------------------------------- eigenvectors\n", + "{\\parbox{2cm}{\\textcolor{blue}{basis for $\\color{blue}{E_\\lambda}$}}} & $\\begin{pNiceArray}{r} 1 \\\\2\\\\3 \\end{pNiceArray},\n", + " \\begin{pNiceArray}{r} 0 \\\\ -3 \\\\ 2 \\end{pNiceArray}$\n", + " & & $\\begin{pNiceArray}{r} -1 \\\\2\\\\3 \\end{pNiceArray}$ \\\\ \\cmidrule{2-2} \\cmidrule{4-4} \\addlinespace[2mm]\n", + "% ------------------------------------------------------------- orthonormal eigenvectors\n", + "{\\parbox{2cm}{\\textcolor{blue}{orthonormal basis for $E_\\lambda$}}} & $\\frac{1}{\\sqrt{14}}\\begin{pNiceArray}{r} 1 \\\\2\\\\3 \\end{pNiceArray},\n", + " \\frac{1}{\\sqrt{13}}\\begin{pNiceArray}{r} 0 \\\\ -3 \\\\ 2 \\end{pNiceArray}$\n", + " & & $\\frac{1}{\\sqrt{14}}\\begin{pNiceArray}{r} -1 \\\\2\\\\3 \\end{pNiceArray}$ \\\\ \\addlinespace[1mm]\n", + " \\addlinespace[2mm] \\midrule \\addlinespace[2mm]\n", + "% ------------------------------------------------------------- lambda\n", + "$\\color{blue}{\\Sigma_r =}$ & \\multicolumn{3}{c}{\n", + " $\\begin{pNiceArray}{c@{\\hspace{8mm}}c@{\\hspace{8mm}}c}\n", + " \\;\\; \\sqrt{3} & 0 & 0 \\;\\; \\\\\n", + " \\;\\; 0 & \\sqrt{3} & 0 \\;\\; \\\\\n", + " \\;\\; 0 & 0 & \\sqrt{2} \\;\\; \\\\ \\end{pNiceArray}$} \\\\ \\addlinespace[2mm]\n", + "% ------------------------------------------------------------- Q\n", + "$\\color{blue}{V_r = }$ & \\multicolumn{3}{c}{ $ \\begin{pNiceArray}{rrr}\n", + " \\frac{1}{\\sqrt{14}} & 0 & -\\frac{1}{\\sqrt{14}} \\\\[2mm]\n", + " \\frac{2}{\\sqrt{14}} & -\\frac{3}{\\sqrt{13}} & \\frac{2}{\\sqrt{14}} \\\\[2mm]\n", + " \\frac{3}{\\sqrt{14}} & \\frac{2}{\\sqrt{13}} & \\frac{3}{\\sqrt{14}} \\\\[2mm]\n", + " \\end{pNiceArray} $} \\\\ \\addlinespace[2mm] \\bottomrule\n", + "\\end{tabular}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## Use nM" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# SVD example\n", + "eig = {\n", + " 'lambda': [3, 2, 1],\n", + " 'ma': [2, 1, 1],\n", + " 'sigma': [sym.sqrt(3), sym.sqrt(2), 1],\n", + " 'evecs': [[sym.Matrix([4, 2, 1,0]), sym.Matrix([3, -1, 1,0])],\n", + " [sym.Matrix([2, 1, 2,1])],\n", + " [sym.Matrix([1, 1, 0,0])]],\n", + " 'qvecs': [[sym.Matrix([4, 2, 1,0])/sym.sqrt(21), sym.Matrix([3, -1, 1,0])/sym.sqrt(11)],\n", + " [sym.Matrix([2, 1, 2,1])/sym.sqrt(10)],\n", + " [sym.Matrix([1, 1, 0,0])/sym.sqrt(2)]],\n", + " 'uvecs': [[sym.Matrix([4, 2, 1,0])/sym.sqrt(21), sym.Matrix([3, -1, 1,0])/sym.sqrt(11)],\n", + " [sym.Matrix([2, 1, 2,1])/sym.sqrt(10)],\n", + " [sym.Matrix([1, 1, 0,0])/sym.sqrt(2)]]\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "E = nM.EigenProblemTable( eig, formater=sym.latex )\n", + "if True:\n", + " dec = nM.make_decorator(text_color='Purple')\n", + " #print(E.eig['sigma'])\n", + " E.decorate_values(E.eig['sigma'],dec,0)\n", + " E.decorate_matrix(E.eig['evecs'][0][0], dec)\n", + " E.decorate_matrix(E.eig['evecs'][0][1], dec, row=0)\n", + " E.decorate_matrix(E.eig['qvecs'][0][0], dec)\n", + " E.decorate_matrix(E.eig['qvecs'][0][1], dec)\n", + "\n", + " E.decorate_matrix(E.eig['uvecs'][0][0], dec)\n", + " E.decorate_matrix(E.eig['uvecs'][0][1], dec)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ep_code = E.nm_latex_doc(case='SVD', formater=str, mmS=0, mmLambda=7, fig_scale=0.8) #, color='Indigo')\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " ep_code, prefix='ep_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=\"tmp/ep\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "S = sym.Matrix([[1,0,0],[2,1,0],[1,-2,1]])\n", + "Q = S.QRdecomposition()[0]\n", + "A = 15 * Q @ sym.Matrix([[2,0,0],[0,2,0],[0,0,-2]]) @ Q.transpose()/2\n", + "\n", + "nM.show_eig_tbl(A,Ascale=15)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}-10 & 10 & 5\\\\10 & 11 & -2\\\\5 & -2 & 14\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[-10, 10, 5],\n", + "[ 10, 11, -2],\n", + "[ 5, -2, 14]])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nM.show_eig_tbl(A/15)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def svd_tbl(A):\n", + " A = sym.Matrix(A)\n", + " eig = {\n", + " 'sigma': [],\n", + " 'lambda': [],\n", + " 'ma': [],\n", + " 'evecs': [],\n", + " 'qvecs': [],\n", + " 'uvecs': []\n", + " }\n", + " def mySVD(A):\n", + " def q_gram_schmidt( v_list ):\n", + " W = []\n", + " for j in range( len( v_list )):\n", + " w_j = v_list[j]\n", + " for k in range( j-1 ):\n", + " w_j = w_j - W[k].dot( v_list[j]) * W[k]\n", + " W.append(1/w_j.norm() * w_j)\n", + " return W\n", + "\n", + " def sort_eig_vec(sym_eig_vec):\n", + " sort_eig_vecs = sorted(sym_eig_vec, key=lambda x: x[0], reverse=True)\n", + "\n", + " for i in sort_eig_vecs:\n", + " sigma = sym.sqrt(i[0])\n", + " eig['sigma'].append(sigma)\n", + "\n", + " eig['lambda'].append( i[0] )\n", + " eig['ma'].append( i[1] )\n", + " eig['evecs'].append( i[2] )\n", + " vvecs = q_gram_schmidt( i[2] )\n", + " eig['qvecs'].append( vvecs )\n", + "\n", + " if not sigma.is_zero:\n", + " eig['uvecs'].append( [ 1/sigma * A * v for v in vvecs] )\n", + "\n", + " sort_eig_vec((A.T @ A).eigenvects())\n", + " ns = A.T.nullspace()\n", + " if len(ns) > 0:\n", + " ns_on_basis = q_gram_schmidt( ns )\n", + " eig['uvecs'].append( ns_on_basis )\n", + "\n", + " mySVD(A)\n", + " return nM.EigenProblemTable( eig, formater=sym.latex, sz=A.shape )\n", + "\n", + "def show_svd_table(A, mmS=10, mmLambda=8, fig_scale=0.8, color='blue' ):\n", + " E = svd_tbl(A)\n", + " display( E.eig)\n", + " svd_code = E.nm_latex_doc( formater=str, case='SVD', mmS=mmS, mmLambda=mmLambda, fig_scale=fig_scale, color=color)\n", + "\n", + " h = itikz.fetch_or_compile_svg(\n", + " svd_code, prefix='svd_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=1, keep_file=\"tmp/svd\" )\n", + " return h\n", + "\n", + "S = sym.Matrix([[1,0,0],[2,1,0],[1,-2,1]])\n", + "Q = S.QRdecomposition()[0]\n", + "A = 15 * Q @ sym.Matrix([[2,0,0],[0,2,0],[0,0,-2]]) @ Q.transpose()/2\n", + "nM.show_svd_table(A, tmp_dir='./tmp', keep_file=\"./tmp/foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "B = np.asmatrix([[1,1,0],[1,1,0],[0,0,0]])\n", + "nM.show_svd_table(B, tmp_dir='./tmp', keep_file=\"./tmp/foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'sigma': ['2', '0'],\n", + " 'lambda': ['4', '0'],\n", + " 'ma': [1, 2],\n", + " 'evecs': [[array(['1', '1', '0'], dtype=object)],\n", + " [array(['-1', '1', '0'], dtype=object),\n", + " array(['0', '0', '1'], dtype=object)]],\n", + " 'qvecs': [[array(['\\\\frac{\\\\sqrt{2}}{2}', '\\\\frac{\\\\sqrt{2}}{2}', '0'], dtype=object)],\n", + " [array(['- \\\\frac{\\\\sqrt{2}}{2}', '\\\\frac{\\\\sqrt{2}}{2}', '0'],\n", + " dtype=object),\n", + " array(['0', '0', '1'], dtype=object)]],\n", + " 'uvecs': [[array(['\\\\frac{\\\\sqrt{2}}{2}', '\\\\frac{\\\\sqrt{2}}{2}', '0'], dtype=object)],\n", + " [array(['- \\\\frac{\\\\sqrt{2}}{2}', '\\\\frac{\\\\sqrt{2}}{2}', '0'],\n", + " dtype=object),\n", + " array(['0', '0', '1'], dtype=object)]]}" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#show_svd_table(B)\n", + "svd_tbl(B).eig" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'tex_program': ['latexmk', '-quiet', '-silent', '-xelatex'],\n", + " 'svg_converter': [['pdf2svg'], '.pdf'],\n", + " 'svg_crop': ['inkscape',\n", + " '--batch-process',\n", + " '--export-plain-svg',\n", + " '-D',\n", + " '--export-margin=1',\n", + " '-o']}" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "matrix([[1, 1, 0, 0],\n", + " [1, 1, 0, 0],\n", + " [0, 0, 0, 0]])" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "B = np.asmatrix([[1,1,0],[1,1,0],[0,0,0], [0,0,0]]).T\n", + "E = svd_tbl(B)\n", + "display(B)\n", + "\n", + "nM.show_svd_table(B)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nM.show_svd_table(B.T, mmLambda=15,mmS=12)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# NEW Nicematrix.sty" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1 = nM.MatrixGridLayout(gen_matrix(3,6), extra_cols=1, extra_rows=2)\n", + "m1.array_format_string_list( partitions={ 1:[3]}, spacer_string=r'@{\\hspace{5mm}}' )\n", + "m1.array_of_tex_entries()\n", + "m1.decorate_tex_entries( 0,1, lambda a: '\\\\color{{red}}{{ \\\\boxed{{{a}}} }}'.format(a=a), entries=[(0,0)] )\n", + "\n", + "blue = nM.make_decorator(text_color='blue', bf=True)\n", + "red = nM.make_decorator(text_color='red', bf=True)\n", + "\n", + "typ = [red(r'\\Uparrow'),red(r'\\Uparrow'),red(r'\\Uparrow'),blue(r'\\uparrow'),blue(r'\\uparrow'),blue(r'\\uparrow')]\n", + "var = [red('x_1'), red('x_2'), red('x_3'), blue('x_4'), blue('x_5'), blue('x_6')]\n", + "\n", + "m1.add_row_below(0,1,typ, formater=lambda a: a )\n", + "m1.add_row_below(0,1,var, offset=1, formater=lambda a: a )\n", + "\n", + "m1.nm_text( ['this here matrix is ...'])\n", + "m1.nm_submatrix_locs()\n", + "m1.tex_repr( blockseps = r'\\noalign{\\vskip2mm} ')\n", + "\n", + "m1_code = m1.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m1_code, prefix='m1_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=4, keep_file=\"tmp/m1\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def nm_background(self, gM,gN, loc_list, color='red!15', pt=0):\n", + " '''add background color to a list of entries (has been integrated)'''\n", + " tl,_,_ = self._top_left_bottom_right( gM, gN )\n", + " for entry in loc_list:\n", + " print(entry)\n", + "\n", + " cmd_1 = f'\\\\tikz \\\\node [fill={color}, inner sep = {pt}pt, fit = '\n", + " if not isinstance( entry, list):\n", + " cmd_2 = f'({tl[0]+entry[0]+1}-{tl[1]+entry[1]+1}-medium)'\n", + " else:\n", + " cmd_2 = f'({tl[0]+entry[0][0]+1}-{tl[1]+entry[0][1]+1}-medium) ({tl[0]+entry[1][0]+1}-{tl[1]+entry[1][1]+1}-medium)'\n", + " cmd_3 = ' ] {} ;'\n", + " print( '. ', cmd_1 + cmd_2 + cmd_3 )\n", + " self.codebefore.append( cmd_1 + cmd_2 + cmd_3 )\n", + "\n", + "bd = nM.make_decorator( box_color='blue' )\n", + "m1.decorate_tex_entries( 0,1, bd, entries=[(0,1),(1,2)] )\n", + "\n", + "m1.codebefore=[]\n", + "m1.nm_background( 0,1, [(0,3), [(1,3),(1,4)]], pt=3, color='blue!15')\n", + "m1.nm_background( 0,1, [(2,3), [(2,4),(2,5)]], pt=3, color='green!15')\n", + "m1.nm_background( 0,1, [(0,0), [(1,1),(1,2)]], pt=0)\n", + "\n", + "m1.nm_add_rowechelon_path( 0,1, [(0,0), (1,1), (2,3) ],case='vv',color='blue,line width=0.6mm', adj=0)\n", + "\n", + "print()\n", + "\n", + "m1_code = m1.nm_latexdoc()\n", + "\n", + "h = itikz.fetch_or_compile_svg(\n", + " m1_code, prefix='m1_', working_dir=\"tmp\", debug=False,\n", + " **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True),\n", + " nexec=4, keep_file=\"tmp/m1\" )\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\documentclass[notitlepage]{article}\n", + "\\pagestyle{empty}\n", + "\\usepackage[margin=0cm,paperwidth=90in]{geometry}\n", + "\n", + "\\usepackage{mathtools}\n", + "\\usepackage{xltxtra}\n", + "\\usepackage{pdflscape}\n", + "\\usepackage{graphicx}\n", + "\\usepackage[table,svgnames]{xcolor}\n", + "\\usepackage{nicematrix,tikz}\n", + "\\usetikzlibrary{calc,fit,decorations.markings}\n", + "\n", + "\\newcommand*{\\colorboxed}{}\n", + "\\def\\colorboxed#1#{%\n", + " \\colorboxedAux{#1}%\n", + "}\n", + "\\newcommand*{\\colorboxedAux}[3]{%\n", + " % #1: optional argument for color model\n", + " % #2: color specification\n", + " % #3: formula\n", + " \\begingroup\n", + " \\colorlet{cb@saved}{.}%\n", + " \\color#1{#2}%\n", + " \\boxed{%\n", + " \\color{cb@saved}%\n", + " #3%\n", + " }%\n", + " \\endgroup\n", + "}\n", + "\n", + "% ---------------------------------------------------------------------------- extension\n", + "%\n", + "\n", + "\\begin{document}\\begin{minipage}{\\textwidth}\n", + "\\begin{landscape}\n", + "\n", + "% ---------------------------------------------------------------------------- preamble\n", + "\n", + " \\NiceMatrixOptions{cell-space-limits = 1pt}\n", + "%\n", + "% ============================================================================ NiceArray\n", + "$\\begin{NiceArray}[vlines-in-sub-matrix = I]{@{\\hspace{5mm}}@{\\hspace{5mm}}rrrIrrr@{\\hspace{5mm}}l@{\\hspace{2cm}}}[create-extra-nodes,create-medium-nodes]%\n", + "\\CodeBefore [create-cell-nodes]\n", + " \\tikz \\node [fill=blue!15, inner sep = 3pt, fit = (1-4-medium) ] {} ;\n", + " \\tikz \\node [fill=blue!15, inner sep = 3pt, fit = (2-4-medium) (2-5-medium) ] {} ;\n", + " \\tikz \\node [fill=green!15, inner sep = 3pt, fit = (3-4-medium) ] {} ;\n", + " \\tikz \\node [fill=green!15, inner sep = 3pt, fit = (3-5-medium) (3-6-medium) ] {} ;\n", + " \\tikz \\node [fill=red!15, inner sep = 0pt, fit = (1-1-medium) ] {} ;\n", + " \\tikz \\node [fill=red!15, inner sep = 0pt, fit = (2-2-medium) (2-3-medium) ] {} ;\n", + " %\n", + "\\Body\n", + "\\color{red}{ \\boxed{5} } & 7 & 1 & 1 & 3 & 3 & \\\\\n", + "1 & 3 & 6 & 3 & 4 & 1 & \\\\\n", + "1 & 2 & 7 & 4 & 7 & 4 & \\\\\\noalign{\\vskip2mm} \n", + "\\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\\\\n", + "\\color{red}{\\mathbf{x_1}} & \\color{red}{\\mathbf{x_2}} & \\color{red}{\\mathbf{x_3}} & \\color{blue}{\\mathbf{x_4}} & \\color{blue}{\\mathbf{x_5}} & \\color{blue}{\\mathbf{x_6}} & \n", + "\\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ]\n", + "% --------------------------------------------------------------------------- submatrix delimiters\n", + " \\SubMatrix({1-1}{3-6})[name=A0x1]\n", + " % --------------------------------------------------------------------------- pivot outlines\n", + "\\begin{tikzpicture}\n", + " \\begin{scope}[every node/.style = draw]\n", + " \\end{scope}\n", + "%\n", + "% --------------------------------------------------------------------------- explanatory text\n", + " \\node [right,align=left,color=violet] at (1-6.east) {\\qquad this here matrix is ... } ;\n", + " %\n", + "% --------------------------------------------------------------------------- row echelon form path\n", + " \\tikz \\draw[blue,line width=0.6mm] let \\p1 = (A0x1.north west), \\p2 = (A0x1.south east), \\p3 = (2-|1), \\p4 = (4-|4) in (\\x1,\\y1) -- (\\x1,\\y3) -- (2-|2) -- (3-|2) -- (3-|4) -- (\\x4,\\y2);\n", + " \\end{tikzpicture}\n", + "\\end{NiceArray}$\n", + "\n", + "\\end{landscape}\n", + "\\end{minipage}\\end{document}\\documentclass[notitlepage]{article}\n", + "\\pagestyle{empty}\n", + "\\usepackage[margin=0cm,paperwidth=90in]{geometry}\n", + "\n", + "\\usepackage{mathtools}\n", + "\\usepackage{xltxtra}\n", + "\\usepackage{pdflscape}\n", + "\\usepackage{graphicx}\n", + "\\usepackage[table,svgnames]{xcolor}\n", + "\\usepackage{nicematrix,tikz}\n", + "\\usetikzlibrary{calc,fit,decorations.markings}\n", + "\n", + "\\newcommand*{\\colorboxed}{}\n", + "\\def\\colorboxed#1#{%\n", + " \\colorboxedAux{#1}%\n", + "}\n", + "\\newcommand*{\\colorboxedAux}[3]{%\n", + " % #1: optional argument for color model\n", + " % #2: color specification\n", + " % #3: formula\n", + " \\begingroup\n", + " \\colorlet{cb@saved}{.}%\n", + " \\color#1{#2}%\n", + " \\boxed{%\n", + " \\color{cb@saved}%\n", + " #3%\n", + " }%\n", + " \\endgroup\n", + "}\n", + "\n", + "% ---------------------------------------------------------------------------- extension\n", + "%\n", + "\n", + "\\begin{document}\\begin{minipage}{\\textwidth}\n", + "\\begin{landscape}\n", + "\n", + "% ---------------------------------------------------------------------------- preamble\n", + "\n", + " \\NiceMatrixOptions{cell-space-limits = 1pt}\n", + "%\n", + "% ============================================================================ NiceArray\n", + "$\\begin{NiceArray}[vlines-in-sub-matrix = I]{@{\\hspace{5mm}}@{\\hspace{5mm}}rrrIrrr@{\\hspace{5mm}}l@{\\hspace{2cm}}}[create-extra-nodes,create-medium-nodes]%\n", + "\\color{red}{ \\boxed{2} } & 7 & 3 & 6 & 1 & 2 & \\\\\n", + "6 & 8 & 1 & 7 & 1 & 1 & \\\\\\noalign{\\vskip2mm} \n", + "\\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\\\\n", + "\\color{red}{\\mathbf{x_1}} & \\color{red}{\\mathbf{x_2}} & \\color{red}{\\mathbf{x_3}} & \\color{blue}{\\mathbf{x_4}} & \\color{blue}{\\mathbf{x_5}} & \\color{blue}{\\mathbf{x_6}} & \n", + "\\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ]\n", + "% --------------------------------------------------------------------------- submatrix delimiters\n", + " \\SubMatrix({1-1}{2-6})[name=A0x1]\n", + " % --------------------------------------------------------------------------- pivot outlines\n", + "\\begin{tikzpicture}\n", + " \\begin{scope}[every node/.style = draw]\n", + " \\end{scope}\n", + "%\n", + "% --------------------------------------------------------------------------- explanatory text\n", + " \\node [right,align=left,color=violet] at (1-6.east) {\\qquad this here matrix is ... } ;\n", + " %\n", + "% --------------------------------------------------------------------------- row echelon form path\n", + " \\end{tikzpicture}\n", + "\\end{NiceArray}$\n", + "\n", + "\\end{landscape}\n", + "\\end{minipage}\\end{document}\\documentclass[notitlepage]{article}\n", + "\\pagestyle{empty}\n", + "\\usepackage[margin=0cm,paperwidth=90in]{geometry}\n", + "\n", + "\\usepackage{mathtools}\n", + "\\usepackage{xltxtra}\n", + "\\usepackage{pdflscape}\n", + "\\usepackage{graphicx}\n", + "\\usepackage[table,svgnames]{xcolor}\n", + "\\usepackage{nicematrix,tikz}\n", + "\\usetikzlibrary{calc,fit,decorations.markings}\n", + "\n", + "\\newcommand*{\\colorboxed}{}\n", + "\\def\\colorboxed#1#{%\n", + " \\colorboxedAux{#1}%\n", + "}\n", + "\\newcommand*{\\colorboxedAux}[3]{%\n", + " % #1: optional argument for color model\n", + " % #2: color specification\n", + " % #3: formula\n", + " \\begingroup\n", + " \\colorlet{cb@saved}{.}%\n", + " \\color#1{#2}%\n", + " \\boxed{%\n", + " \\color{cb@saved}%\n", + " #3%\n", + " }%\n", + " \\endgroup\n", + "}\n", + "\n", + "% ---------------------------------------------------------------------------- extension\n", + "%\n", + "\n", + "\\begin{document}\\begin{minipage}{\\textwidth}\n", + "\\begin{landscape}\n", + "\n", + "% ---------------------------------------------------------------------------- preamble\n", + "\n", + " \\NiceMatrixOptions{cell-space-limits = 1pt}\n", + "%\n", + "% ============================================================================ NiceArray\n", + "$\\begin{NiceArray}[vlines-in-sub-matrix = I]{@{\\hspace{5mm}}@{\\hspace{5mm}}rrrIrrr@{\\hspace{5mm}}l@{\\hspace{2cm}}}[create-extra-nodes,create-medium-nodes]%\n", + "\\CodeBefore [create-cell-nodes]\n", + " \\tikz \\node [fill=blue!15, inner sep = 3pt, fit = (1-4-medium) ] {} ;\n", + " \\tikz \\node [fill=blue!15, inner sep = 3pt, fit = (2-4-medium) (2-5-medium) ] {} ;\n", + " \\tikz \\node [fill=green!15, inner sep = 3pt, fit = (3-4-medium) ] {} ;\n", + " \\tikz \\node [fill=green!15, inner sep = 3pt, fit = (3-5-medium) (3-6-medium) ] {} ;\n", + " \\tikz \\node [fill=red!15, inner sep = 0pt, fit = (1-1-medium) ] {} ;\n", + " \\tikz \\node [fill=red!15, inner sep = 0pt, fit = (2-2-medium) (2-3-medium) ] {} ;\n", + " %\n", + "\\Body\n", + "\\color{red}{ \\boxed{5} } & 7 & 1 & 1 & 3 & 3 & \\\\\n", + "1 & 3 & 6 & 3 & 4 & 1 & \\\\\n", + "1 & 2 & 7 & 4 & 7 & 4 & \\\\\\noalign{\\vskip2mm} \n", + "\\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\\\\n", + "\\color{red}{\\mathbf{x_1}} & \\color{red}{\\mathbf{x_2}} & \\color{red}{\\mathbf{x_3}} & \\color{blue}{\\mathbf{x_4}} & \\color{blue}{\\mathbf{x_5}} & \\color{blue}{\\mathbf{x_6}} & \n", + "\\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ]\n", + "% --------------------------------------------------------------------------- submatrix delimiters\n", + " \\SubMatrix({1-1}{3-6})[name=A0x1]\n", + " % --------------------------------------------------------------------------- pivot outlines\n", + "\\begin{tikzpicture}\n", + " \\begin{scope}[every node/.style = draw]\n", + " \\end{scope}\n", + "%\n", + "% --------------------------------------------------------------------------- explanatory text\n", + " \\node [right,align=left,color=violet] at (1-6.east) {\\qquad this here matrix is ... } ;\n", + " %\n", + "% --------------------------------------------------------------------------- row echelon form path\n", + " \\tikz \\draw[blue,line width=0.6mm] let \\p1 = (A0x1.north west), \\p2 = (A0x1.south east), \\p3 = (2-|1), \\p4 = (4-|4) in (\\x1,\\y1) -- (\\x1,\\y3) -- (2-|2) -- (3-|2) -- (3-|4) -- (\\x4,\\y2);\n", + " \\end{tikzpicture}\n", + "\\end{NiceArray}$\n", + "\n", + "\\end{landscape}\n", + "\\end{minipage}\\end{document}\\documentclass[notitlepage]{article}\n", + "\\pagestyle{empty}\n", + "\\usepackage[margin=0cm,paperwidth=90in]{geometry}\n", + "\n", + "\\usepackage{mathtools}\n", + "\\usepackage{xltxtra}\n", + "\\usepackage{pdflscape}\n", + "\\usepackage{graphicx}\n", + "\\usepackage[table,svgnames]{xcolor}\n", + "\\usepackage{nicematrix,tikz}\n", + "\\usetikzlibrary{calc,fit,decorations.markings}\n", + "\n", + "\\newcommand*{\\colorboxed}{}\n", + "\\def\\colorboxed#1#{%\n", + " \\colorboxedAux{#1}%\n", + "}\n", + "\\newcommand*{\\colorboxedAux}[3]{%\n", + " % #1: optional argument for color model\n", + " % #2: color specification\n", + " % #3: formula\n", + " \\begingroup\n", + " \\colorlet{cb@saved}{.}%\n", + " \\color#1{#2}%\n", + " \\boxed{%\n", + " \\color{cb@saved}%\n", + " #3%\n", + " }%\n", + " \\endgroup\n", + "}\n", + "\n", + "% ---------------------------------------------------------------------------- extension\n", + "%\n", + "\n", + "\\begin{document}\\begin{minipage}{\\textwidth}\n", + "\\begin{landscape}\n", + "\n", + "% ---------------------------------------------------------------------------- preamble\n", + "\n", + " \\NiceMatrixOptions{cell-space-limits = 1pt}\n", + "%\n", + "% ============================================================================ NiceArray\n", + "$\\begin{NiceArray}[vlines-in-sub-matrix = I]{@{\\hspace{5mm}}@{\\hspace{5mm}}rrrIrrr@{\\hspace{5mm}}l@{\\hspace{2cm}}}[create-extra-nodes,create-medium-nodes]%\n", + "\\color{red}{ \\boxed{5} } & 7 & 1 & 1 & 3 & 3 & \\\\\n", + "1 & 3 & 6 & 3 & 4 & 1 & \\\\\n", + "1 & 2 & 7 & 4 & 7 & 4 & \\\\\\noalign{\\vskip2mm} \n", + "\\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{red}{\\mathbf{\\Uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\color{blue}{\\mathbf{\\uparrow}} & \\\\\n", + "\\color{red}{\\mathbf{x_1}} & \\color{red}{\\mathbf{x_2}} & \\color{red}{\\mathbf{x_3}} & \\color{blue}{\\mathbf{x_4}} & \\color{blue}{\\mathbf{x_5}} & \\color{blue}{\\mathbf{x_6}} & \n", + "\\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ]\n", + "% --------------------------------------------------------------------------- submatrix delimiters\n", + " \\SubMatrix({1-1}{3-6})[name=A0x1]\n", + " % --------------------------------------------------------------------------- pivot outlines\n", + "\\begin{tikzpicture}\n", + " \\begin{scope}[every node/.style = draw]\n", + " \\end{scope}\n", + "%\n", + "% --------------------------------------------------------------------------- explanatory text\n", + " \\node [right,align=left,color=violet] at (1-6.east) {\\qquad this here matrix is ... } ;\n", + " %\n", + "% --------------------------------------------------------------------------- row echelon form path\n", + " \\end{tikzpicture}\n", + "\\end{NiceArray}$\n", + "\n", + "\\end{landscape}\n", + "\\end{minipage}\\end{document}\n" + ] + } + ], + "source": [ + "!cat tmp/m1*.tex" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## Back Substitution Layout" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}1 & 2 & 4 & 1\\\\0 & 1 & -9 & -2\\\\0 & - 2 k & 9 k - 36 & h + 2 k - 10\\end{matrix}\\right]$" + ], + "text/plain": [ + "Matrix([\n", + "[1, 2, 4, 1],\n", + "[0, 1, -9, -2],\n", + "[0, -2*k, 9*k - 36, h + 2*k - 10]])" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "k = sym.Symbol('k'); h = sym.Symbol('h')\n", + "Ab = sym.Matrix([[1,2,4,1],[2,-k,8,h],[3,7,3,1]]); matrices = [[None, Ab]]; pivots = []; txt=[]\n", + "# we could use row ops, but we want a computational layout (and hence the E matrices!):\n", + "# A=A.elementary_row_op('n->n+km', k=-3, row1=2,row2=0 );A\n", + "# A=A.elementary_row_op('n<->m',row1=1,row2=2);A\n", + "\n", + "E1=sym.eye(3);E1[1:,0]=[-2,-3]; A1=E1*Ab; matrices.append([E1,A1]); pivots.append((1,1));txt.append('Pivot at (1,1)')\n", + "E2=sym.eye(3);E2=E2.elementary_row_op('n<->m',row1=1,row2=2); A2=E2*A1; matrices.append([E2,A2]); pivots.append(None); txt.append('Rows 2 <-> 3')\n", + "E3=sym.eye(3);E3[2,1]=4-k; A3=E3*A2; matrices.append([E3,A3]); pivots.append((2,2));txt.append('Pivot at (2,2)')\n", + "pivots.append((3,3)); txt.append('In Row Echelon Form')\n", + "#Ab,A3,pivots\n", + "display(A3)\n", + "foo = nM.BacksubstitutionCascade.from_ref_Ab( A3, var_name=\"z\" )\n", + "foo.show( show_system=True, show_cascade=True, show_solution=True, keep_file=\"tmp/foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "matrix([[ 0, 2, 1, -1, 0],\n", + " [ 0, 0, 0, -1, 0],\n", + " [ 0, 0, 0, 0, 0],\n", + " [ 0, 0, 0, 0, 0],\n", + " [ 0, 0, 0, 0, 0]])" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "matrix([[3],\n", + " [1],\n", + " [0],\n", + " [0],\n", + " [0]])" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ref_A = np.matrix([[0,2,1,-1,0],[0,0,0,-1,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]])\n", + "ref_rhs = np.matrix([[3,1,0,0,0]]).T\n", + "display(ref_A), display(ref_rhs)\n", + "print(); print()\n", + "\n", + "foo = nM.BacksubstitutionCascade( ref_A, ref_rhs )\n", + "foo.show( A=foo.ref_A, b = foo.ref_rhs, show_system=True, show_cascade=True, show_solution=True,\n", + " fig_scale=None, keep_file=\"tmp/foo\" )\n", + "#print(foo.nm_latex_doc( show_cascade=True, show_solution=True, fig_scale=0.8))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = np.matrix( [ [ 1, 3, 0, 1, 0, 0],\n", + " [ 0, 1, 2, -1, 1, 3],\n", + " [ 0, 0, 3, 0, 2, 2],\n", + " [ 0, 0, 0, 1, 0, 1],\n", + " [ 0, 0, 0, 0, 0, 1],\n", + " [ 0, 0, 0, 0, 0, 1],\n", + " ])\n", + "rhs= A @ np.matrix([[ 2, 1, -1, 3, 0, 2]]).T\n", + "\n", + "foo = nM.BacksubstitutionCascade( A, rhs, var_name=r\"s\" )\n", + "foo.show( A=foo.ref_A, b = foo.ref_rhs, show_system=True, show_cascade=True, show_solution=True,\n", + " fig_scale=None, keep_file=\"tmp/foo\" )" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%itikz --temp-dir --file-prefix test_ --template article --tex-packages=amssymb,cascade,systeme,nicematrix,tikz,relsize --crop --tikz-libraries=decorations.pathreplacing\n", + "\n", + "\\systeme{2r + s -t +0 x_2 = 3, r=2, -2s +2t= 5, s=2, t=7}\n", + "\\vspace{1cm}\n", + "\n", + "% ==================================================================================== Decorate matrix\n", + " % ------------------------------------------------------------------------------------ Solve\n", + " {\\ShortCascade%\n", + " {\\ShortCascade%\n", + " {\\ShortCascade%\n", + " {$\\boxed{ x_3 = \\alpha_1, x_5 = \\alpha_2 }$}%\n", + " {$x_4 = 2 + 2 x_5$}%\n", + " {$\\;\\Rightarrow\\; \\boxed{x_4 = 2 + 2 \\alpha_2}$}%\n", + " }%\n", + " {$x_2 = 1 +x_3-x_4$}%\n", + " {$\\;\\Rightarrow\\; \\boxed{x_2 = -1+\\alpha_1-2\\alpha_2}$}%\n", + " }%\n", + " {$x_1 = 4 - x_2 - x_3 - 2 x_4 -2 x_5$}%\n", + " {$\\;\\Rightarrow \\; \\boxed{x_1 = 1-\\alpha_1+2\\alpha_2}.$}\n", + " }%\n", + " %& % --------------------------------------------------------------------------------- Standard Form\n", + " \\vspace{1cm}\n", + "\n", + " {$\\; \\therefore\\; \\left( \\begin{array}{r} x_1 \\\\ x_2 \\\\ x_3 \\\\ x_4 \\\\ x_5 \\end{array} \\right)\n", + " = \\left( \\begin{array}{r} 1 \\\\ -1 \\\\ 0 \\\\ 2 \\\\ 0 \\end{array} \\right)\n", + " + \\alpha_1 \\left( \\begin{array}{r} -1 \\\\ 1 \\\\ 1 \\\\ 0 \\\\ 0 \\end{array} \\right)\n", + " + \\alpha_2 \\left( \\begin{array}{r} 2 \\\\ -2 \\\\ 0 \\\\ 2 \\\\ 1 \\end{array} \\right)\n", + " $\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "!ls tmp" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "!rm tmp/*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# DBG" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "A = np.array( [ [1, 1, -1], [0, 1, -1], [-2, 0, 0], [2 , 4, 5]])\n", + "b = np.array([[1,1,1,1]]).T\n", + "A0 = np.concatenate( [A, b], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A1 = A.T @ A0\n", + "E1 = np.array([[1, 0, 0],[ -1, 1, 0],[ -1, 0, 1]]); A2 = E1@A1\n", + "E2 = np.array([[1, 0, 0],[ 0, 1, 0],[ 0,-1, 1]]); A3 = E2@A2\n", + "matrices =[ [ None, A0 ],\n", + " [ A.T, A1],\n", + " [ E1, A2],\n", + " [ E2, A3],\n", + " ]\n", + "h,m=nM.ge( matrices, Nrhs=1)\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = false;\n", + " const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = true;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n", + " require([\"katex\"], function(katex) {\n", + " window.katex = katex\n", + " on_load()\n", + " })\n", + " require([\"autoLoad\"], function(renderMathInElement) {\n", + " window.renderMathInElement = renderMathInElement\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 2;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = false;\n const py_version = '3.7.3'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = true;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min', 'autoLoad': 'https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min'}, 'shim': {}});\n require([\"katex\"], function(katex) {\n window.katex = katex\n on_load()\n })\n require([\"autoLoad\"], function(renderMathInElement) {\n window.renderMathInElement = renderMathInElement\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.katex !== undefined) && (!(window.katex instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.renderMathInElement !== undefined) && (!(window.renderMathInElement instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.7.5/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js\", \"https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/contrib/auto-render.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css?v=1.7.5\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "c93ae119-9bc7-45ab-8603-48cc538f3b4f" + } + }, + "output_type": "display_data" + }, + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "SVG(SVG)" + ] + }, + "execution_count": 52, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "0043310f-64a6-4dda-9318-e72a1232162a" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "import panel as pn\n", + "pn.extension()\n", + "pn.pane.SVG(h)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + " \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", + " \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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/itikz/__init__.py b/itikz/__init__.py index 1e37630..48e0d37 100644 --- a/itikz/__init__.py +++ b/itikz/__init__.py @@ -1,19 +1,28 @@ import argparse +import re import os import shlex import sys import tempfile from hashlib import md5 from shutil import fnmatch +from shutil import copy as shutil_copy from string import Template from subprocess import check_output, CalledProcessError +from subprocess import run as run_subprocess from IPython.display import SVG, Image from IPython.core.magic import Magics, magics_class, line_cell_magic +from pathlib import Path +import tempfile + +import logging +logger = logging.getLogger() +logger.setLevel( logging.DEBUG ) __author__ = """John Bjorn Nelson""" __email__ = 'jbn@abreka.com' -__version__ = '0.1.5' +__version__ = '0.1.7' IMPLICIT_PIC_TMPL = Template(r"""\documentclass[tikz]{standalone} @@ -31,6 +40,13 @@ $src \end{document}""") +IMPLICIT_ARTICLE = Template(r"""\documentclass{article} +\pagenumbering{gobble} +$extras +\begin{document} +$src +\end{document}""") + JINJA2_ENABLED = True try: @@ -54,6 +70,10 @@ def parse_args(line): parser.add_argument('k', type=str, nargs='?', help='the variable in IPython with the string source') + parser.add_argument('--keep-file', dest='keep_file', + default=None, + help='directory to keep tex and svg file') + parser.add_argument('--temp-dir', dest='temp_dir', action='store_true', default=False, help='emit artifacts to system temp dir') @@ -61,17 +81,17 @@ def parse_args(line): parser.add_argument('--file-prefix', dest='file_prefix', default='', help='emit artifacts with a path prefix') - parser.add_argument('--implicit-pic', dest='implicit_pic', - action='store_true', default=False, - help='wrap source in implicit tikzpicture document') + parser.add_argument('--template', dest='implicit_template', + default=None, + help='wrap source in implicit document: pic, standalone or article') - parser.add_argument('--implicit-standalone', dest='implicit_standalone', - action='store_true', default=False, - help='wrap source in implicit document') + parser.add_argument('--nexec', dest='nexec', + default=1, + help='set number of engine executions in --nexec') parser.add_argument('--scale', dest='scale', default='1', - help='Set tikzpicture scale in --implicit-pic tmpl') + help='Set tikzpicture scale in --template pic') parser.add_argument('--tikz-libraries', dest='tikz_libraries', default='', @@ -85,6 +105,17 @@ def parse_args(line): default='pdflatex', help='Name of alternate LaTeX program (e.g., lualatex)') + parser.add_argument('--use-xetex', dest='use_xetex', action='store_true', + default=False, + help='use xetex rather than pdflatex') + + parser.add_argument('--use-dvi', dest='use_dvi', action='store_true', + default=False, + help='use dvi or xdv for conversion to svg') + parser.add_argument('--crop', dest='crop', action='store_true', + default=False, + help='use inkscape to crop the svg') + parser.add_argument('--as-jinja', dest='as_jinja', action='store_true', default=False, help="Interpret the source as a jinja2 template") @@ -97,6 +128,9 @@ def parse_args(line): action='store_true', default=False, help="Rasterize the svg with cairosvg") + parser.add_argument('--debug', dest='debug', + action='store_true', default=False, + help="turn on debug mode") parser.add_argument('--full-error', dest='full_err', action='store_true', default=False, help="Emit the full error message") @@ -108,35 +142,195 @@ def parse_args(line): return parser, parser.parse_args(shlex.split(line)) - -def get_cwd(args): - if args.temp_dir or os.environ.get('ITIKZ_TEMP_DIR'): - cwd = os.path.join(tempfile.gettempdir(), 'itikz') - os.makedirs(cwd, exist_ok=True) - return cwd # Override as cwd +# ========================================================================== +def get_wd(s, root=None, add_itikz=True ): + '''build the working directory''' + if isinstance(root, bool): + root = None + if root is None: + tmp = os.environ.get( 'ITIKZ_TEMP_DIR' ) + if not tmp: + import platform + root = Path("/tmp" if platform.system() == "Darwin" else tempfile.gettempdir()) + else: + root = Path(tmp) + if isinstance(s, bool): + s = None + + if s is None: + if add_itikz: + root = root / 'itikz' + root.mkdir(parents=True, exist_ok=True) + return root + + s = Path(s) + l = len( s.parts ) + sa = Path(s).absolute() + + if sa.is_dir(): + d = sa / 'itikz' if add_itikz else sa + elif l > 1 and s.parent.is_dir(): + d = sa / 'itikz' if add_itikz else sa else: - return None # No override. - + d = root / s + d = d / 'itikz' if add_itikz else d + + d.mkdir(parents=True, exist_ok=True) + return d + +def get_wf(s, root, sfx='.tex'): + '''construct the full path name of a file with suffix s''' + s = Path(s) + p = s.parts + if len(p) > 1: + r = get_wd(s.parent, root, add_itikz=False) + return r / (s.name + sfx ) + if s.is_absolute(): + return root / s.parent / (s.name + sfx) + return root / ( "/".join( s.parts ) + sfx ) + +def build_commands_dict( tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], use_xetex=False, use_dvi=False, crop=False, nexec=1): + tex_program,svg_converter,svg_crop = build_commands( tex_program, svg_converter, use_xetex, use_dvi, crop, nexec) + return { "tex_program":tex_program,"svg_converter":svg_converter,"svg_crop":svg_crop } + +def build_commands( tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], use_xetex=False, use_dvi=False, crop=False, nexec=1): + ''' +build_commands( tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], use_xetex=False, use_dvi=False, crop=False, nexec=1): + ''' + if isinstance( tex_program, (list,)) is False: + tex_program = [tex_program] + + if tex_program[0] == "pdflatex": + if use_xetex is True: + if use_dvi is True: + if nexec > 1: + #print("EXA case 1") + ###_tex_program = ["xelatex", "--no-pdf", "--etex" ] + _tex_program = ["xelatex", "--no-pdf" ] + _svg_converter = [["dvisvgm", "--font-format=woff2", "--exact"], ".xdv"] + else: + #print("EXA case 2") + #_tex_program = ["latexmk", "--quiet", "--silent", "--xelatex", "--etex" ] + _tex_program = ["latexmk", "-quiet", "-silent", "-xelatex" ] + _svg_converter = [["dvisvgm", "--font-format=woff2", "--exact"], ".xdv"] + else: + if nexec > 1: + #print("EXA case 3") + #_tex_program = ["xelatex", "--etex" ] + _tex_program = ["xelatex" ] + _svg_converter = [["pdf2svg"], ".pdf"] + else: + #print("EXA case 4") + #_tex_program = ["latexmk", "--quiet", "--silent", "--xelatex", "--etex" ] + _tex_program = ["latexmk", "-quiet", "-silent", "-xelatex" ] + _svg_converter = [["pdf2svg"], ".pdf"] + else: + if use_dvi is True: + #print("EXA case 5") + #_tex_program = ["latexmk", "--quiet", "--silent", "--etex", "-dvi" ] + _tex_program = ["latexmk", "-quiet", "-silent", "-dvi" ] + _svg_converter = [["dvisvgm", "--font-format=woff2", "--exact"], ".dvi"] + else: + #print("EXA case 6") + #_tex_program = ["latexmk", "--quiet", "--silent", "--etex", "-pdf" ] + _tex_program = ["latexmk", "-quiet", "-silent", "-pdf" ] + _svg_converter = [["pdf2svg"], ".pdf"] + else: + #print("EXA case 7") + _tex_program = tex_program + _svg_converter = svg_converter + if crop: + _svg_crop = (["inkscape", "--batch-process", "--export-plain-svg", "-D", "--export-margin=1", "-o"]) + else: + _svg_crop = None + + return _tex_program, _svg_converter,_svg_crop + +def fetch_or_compile_svg(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' +fetch_or_compile_svg(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' + svg = svg_from_tex(src, prefix, working_dir, full_err, debug, tex_program, svg_converter, svg_crop, nexec, keep_file) + if svg is not None: + return SVG(svg) + return None + +def svg_file_from_tex(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' +svg_file_from_tex(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' + ##EXA working_dir = get_working_dir(working_dir) + working_dir = get_wd(working_dir, root=None, add_itikz=working_dir is None) -def fetch_or_compile_svg(src, prefix='', working_dir=None, full_err=False, tex_program='pdflatex'): src_hash = md5(src.encode()).hexdigest() - output_path = prefix + src_hash - if working_dir is not None: - output_path = os.path.join(working_dir, output_path) - svg_path = output_path + ".svg" - - if not os.path.exists(svg_path): - tex_path = output_path + ".tex" - pdf_path = output_path + ".pdf" - tex_filename = os.path.basename(tex_path) - - with open(tex_path, "w") as fp: - fp.write(src) + output_prefix = prefix +src_hash + + tex_file = working_dir / (output_prefix + '.tex') + pdf_file = working_dir / (output_prefix + '.pdf') + svg_file = working_dir / (output_prefix + '.svg') + + if debug or not svg_file.exists(): + if debug: + print(">>>> tex file: ", tex_file) + print(">>>> tex code:\n", src) + with open(tex_file, "w") as fp: + #print( "EXA ***writing to ", tex_file, "\nsrc: ", src) + try: + fp.write(src) + except: + print("failed to write tex source", file=sys.stderr) + cleanup_artifacts(working_dir, src_hash) + return + #print("EXA file exists: ", tex_file.exists(), tex_file ) try: - check_output([tex_program, tex_filename], cwd=working_dir) - check_output(["pdf2svg", pdf_path, svg_path], cwd=working_dir) + tex_program.append( str(tex_file) ) + if debug: + print(">>>> tex_PROGRAM: ", ' '.join(tex_program), working_dir) + for _ in range(nexec-1): + run_subprocess(tex_program, cwd=working_dir) + check_output(tex_program, cwd=working_dir) + + svg_program = svg_converter[0] + [str(pdf_file), str(svg_file)] + if debug: + print(">>>> svg_PROGRAM: ", ' '.join(svg_program)) + check_output(svg_program, cwd=working_dir) + + if svg_crop is not None: + crop_program = svg_crop + [str(svg_file), str(svg_file)] + if debug: + print(">>>> svg_crop_PROGRAM: ", ' '.join(crop_program)) + check_output( crop_program, cwd=working_dir) + + # Could also convert SVG to PNG here + # inkscape -z -e test.png -w 1024 -h 1024 test.svg + + if keep_file is not None: + tex_keep_file = get_wf(keep_file, Path.cwd(), sfx=".tex") + svg_keep_file = get_wf(keep_file, Path.cwd(), sfx=".svg") + + try: + if debug: + print(">>>> Save Files: ", ' '.join(["cp", str(tex_file), str(tex_keep_file)])) + print(" ", ' '.join(["cp", str(svg_file), str(svg_keep_file)])) + shutil_copy( tex_file, tex_keep_file ) + shutil_copy( svg_file, svg_keep_file ) + except: + print( "Could not copy files") + except CalledProcessError as e: + if keep_file is not None: + tex_keep_file = get_wf(keep_file, Path.cwd(), sfx=".tex") + svg_keep_file = get_wf(keep_file, Path.cwd(), sfx=".svg") + try: + if debug: + print(">>>> Save Files: ", ' '.join(["cp", str(tex_file), str(tex_keep_file)])) + print(" ", ' '.join(["cp", str(svg_file), str(svg_keep_file)])) + shutil_copy( tex_file, tex_keep_file ) + shutil_copy( svg_file, svg_keep_file ) + except: + print( "Could not copy files") + cleanup_artifacts(working_dir, src_hash) err_msg = e.output.decode() @@ -146,27 +340,37 @@ def fetch_or_compile_svg(src, prefix='', working_dir=None, full_err=False, tex_p print(err_msg, file=sys.stderr) return - cleanup_artifacts(working_dir, src_hash, svg_path, tex_path) + cleanup_artifacts(working_dir, src_hash, svg_file, tex_file) - with open(svg_path, "r") as fp: - return SVG(fp.read()) + return tex_file,svg_file +def html_img_from_tex(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): -def cleanup_artifacts(working_dir, src_hash, *retaining): - glob = "*{}*".format(src_hash) + _,svg_file = svg_file_from_tex(src, prefix, working_dir, full_err, debug, tex_program, svg_converter, svg_crop, nexec, keep_file) + return f'' + +def svg_from_tex(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' +svg_from_tex(src, prefix='', working_dir=None, full_err=False, debug=False, tex_program=["pdflatex"], svg_converter=[["pdf2svg"],".pdf"], svg_crop=None, nexec=1, keep_file=None): + ''' + + tex_file,svg_file = svg_file_from_tex(src, prefix, working_dir, full_err, debug, tex_program, svg_converter, svg_crop, nexec, keep_file) - for file_name in fnmatch.filter(os.listdir(working_dir), glob): - file_path = os.path.join(working_dir or '', file_name) - if file_path not in retaining: - os.unlink(file_path) + with open(svg_file, "r") as fp: + return fp.read() +def cleanup_artifacts(working_dir, src_hash, *retaining): + files = working_dir.glob(f'**/*{src_hash}*') + for f in files: + if f not in retaining: + f.unlink() def load_and_interpolate_jinja2(src, ns): # The FileSystemLoader should operate in the current working directory. # By assumption, extended jinja templates aren't temporary files -- # the user wrote them by hand. They are part of code you would want in # your repository! - fs_loader = jinja2.FileSystemLoader(os.getcwd()) + fs_loader = jinja2.FileSystemLoader(Path.cwd()) tmpl_env = jinja2.Environment(loader=fs_loader) # The final template -- the one that may extend a custom template -- @@ -199,9 +403,6 @@ def itikz(self, line, cell=None): src = ipython_ns[args.k] - if args.implicit_pic and args.implicit_standalone: - print("Can't use --implicit-standalone and --implicit-pic", - file=sys.stderr) return None # Jinja processing comes BEFORE implicit pic or standalone processing! @@ -218,14 +419,30 @@ def itikz(self, line, cell=None): print(src) return - if args.implicit_pic: - src = IMPLICIT_PIC_TMPL.substitute(build_template_args(src, args)) - elif args.implicit_standalone: - tmpl_args = build_template_args(src, args) - src = IMPLICIT_STANDALONE.substitute(tmpl_args) + if args.implicit_template is not None: + if args.implicit_template == "pic": + src = IMPLICIT_PIC_TMPL.substitute(build_template_args(src, args)) + elif args.implicit_template == "standalone": + tmpl_args = build_template_args(src, args) + src = IMPLICIT_STANDALONE.substitute(tmpl_args) + elif args.implicit_template == "article": + tmpl_args = build_template_args(src, args) + src = IMPLICIT_ARTICLE.substitute(tmpl_args) + else: + print( "no implicit template '", args.implicit_template, "'" ) + print( " known templates are one of: 'pic, standalone, article', else use jinja" ) + return + + if args.debug: + print(">>>> program args: ", args.tex_program, args.use_dvi, args.use_xetex) + + nexec = int(args.nexec) + tex_program,svg_converter,svg_crop = build_commands( args.tex_program, [["pdf2svg"],".pdf"], args.use_xetex, args.use_dvi, args.crop, nexec) - svg = fetch_or_compile_svg(src, args.file_prefix, get_cwd(args), - args.full_err, args.tex_program) + #print("EXA **** working dir<<<<", get_cwd(args), ">>>>") + working_dir = None if args.temp_dir == False else args.temp_dir + svg = fetch_or_compile_svg(src, args.file_prefix, working_dir, + args.full_err, args.debug, tex_program, svg_converter, svg_crop, nexec, args.keep_file) if svg is None: return None @@ -246,8 +463,14 @@ def itikz(self, line, cell=None): def build_template_args(src, args): extras = [] + pattern = re.compile( r'(\[[^]]*])(.*)' ) if args.tex_packages: - extras.append(r"\usepackage{" + args.tex_packages + "}") + for package in args.tex_packages.split(','): + match = pattern.match( package ) + if match: + extras.append( r"\usepackage" + match.group(1) + "{" + match.group(2)+ "}" ) + else: + extras.append(r"\usepackage{" + package + "}") if args.tikz_libraries: extras.append(r"\usetikzlibrary{" + args.tikz_libraries + "}") diff --git a/itikz/nicematrix.py b/itikz/nicematrix.py new file mode 100644 index 0000000..c50fbed --- /dev/null +++ b/itikz/nicematrix.py @@ -0,0 +1,1814 @@ +import numpy as np +import sympy as sym +import jinja2 +import itikz +from IPython.core.display import SVG +from IPython.core.display import HTML + +# ================================================================================================================================ +from collections.abc import Sequence +from collections.abc import Iterable + +# ================================================================================================================================ +# helper functions to convert PythonCall structures +# ================================================================================================================================ +def _is_julia_obj(x): + mod = type(x).__module__ + return mod.startswith("juliacall") or mod.startswith("PythonCall") + +def _jl_to_py(x): + """ + Convert PythonCall Julia containers to pure Python containers, + preserving the nested structure, but ensuring that Julia MATRICES + become 2-D numpy arrays. + """ + if x is None: + return None + + # If it's a Julia object coming from PythonCall/Juliacall… + if _is_julia_obj(x): + sh = getattr(x, "shape", None) + + # Julia matrix => force 2-D numpy array + if sh is not None and hasattr(sh, "__len__") and len(sh) == 2: + return np.array(x, dtype=object) + + # Julia vector / nested container => recurse into Python list + try: + return [_jl_to_py(e) for e in x] + except TypeError: + # scalar Julia value + return x + + # Pure Python containers => recurse + if isinstance(x, list): + return [_jl_to_py(e) for e in x] + if isinstance(x, tuple): + return tuple(_jl_to_py(e) for e in x) + + # numpy arrays and scalars => leave as-is + return x + +# ================================================================================================================================ +extension = r''' ''' +# ----------------------------------------------------------------- +preamble = r''' ''' +# ================================================================= +BACKSUBST_TEMPLATE = r'''\documentclass[notitlepage,table,svgnames]{article} +\pagestyle{empty} +\usepackage[margin=0cm,paperwidth=90in]{geometry} +\usepackage{mathtools} +\usepackage{amssymb} +\usepackage{cascade} +\usepackage{systeme} +\usepackage{nicematrix} + +\begin{document}\begin{minipage}{\textwidth} +{%% if fig_scale %%} +\scalebox{ {{fig_scale}} }{% +{%% endif %%} +% ---------------------------------------------------------------------------------------- +{{preamble}}% +%==================================================================== +{%% if show_system %%} +{{system_txt}} +{%% endif %%} +%==================================================================== +{%% if show_cascade %%} +{%% if show_system %%} +\vspace{1cm} + +{%% endif %%} +{%% for line in cascade_txt -%%} +{{line}} +{%% endfor -%%} +{%% endif %%} +%==================================================================== +{%% if show_solution %%} +{%% if show_system or show_cascade %%} +\vspace{1cm} + +{%% endif %%} +{{solution_txt}} +{%% endif %%} +%==================================================================== +{%% if fig_scale %%} +} +{%% endif %%} +\end{minipage}\end{document} +''' +# ================================================================= +EIGPROBLEM_TEMPLATE = r'''\documentclass[notitlepage,table,svgnames]{article} +\pagestyle{empty} +\usepackage{booktabs} +\usepackage{mathtools} +\usepackage{nicematrix} +\usepackage{xcolor} + +\begin{document}\begin{minipage}{\textwidth} +{%% if fig_scale %%} +{{fig_scale}} +{%% endif %%} +% ---------------------------------------------------------------------------------------- +{{preamble}}% +%========================================================================================= +\begin{tabular}{{table_format}} \toprule +{%% if sigmas %%}% sigma ----------------------------------------------------------------- +$\color{{color}}{\sigma}$ & {{sigmas}} {{rule_format}} +{%% endif %%}% lambda -------------------------------------------------------------------- +$\color{{color}}{\lambda}$ & {{lambdas}} {{rule_format}} +$\color{{color}}{m_a}$ & {{algebraic_multiplicities}} {{rule_format}} \addlinespace[1mm] +% eigenvectors -------------------------------------------------------------------------- +{\parbox{2cm}{\textcolor{{color}}{basis for $\color{{color}}{E_\lambda}$}}} & +{{eigenbasis}} {%% if orthonormal_basis %%} +% orthonormal eigenvectors -------------------------------------------------------------- + {{rule_format}} \addlinespace[2mm] +{\parbox{2cm}{\textcolor{{color}}{orthonormal basis for $E_\lambda$}}} & +{{orthonormal_basis}} +{%% endif -%%} + \addlinespace[2mm] \midrule \addlinespace[2mm] +% ------------------------------------------------------------- lambda +$\color{{color}}{ {{matrix_names[0]}} =}$ & {{lambda_matrix}} \\ \addlinespace[2mm] +% ------------------------------------------------------------- E or Q +{%% if evecs_matrix %%}% +$\color{{color}}{ {{matrix_names[1]}} = }$ & {{evecs_matrix}} \\ \addlinespace[2mm] %\bottomrule +{%% endif -%%} +% ------------------------------------------------------------- U +{%% if left_singular_matrix %%}% +$\color{{color}}{ {{matrix_names[2]}} = }$ & {{left_singular_matrix}} \\ \addlinespace[2mm] \bottomrule +{%% endif -%%} +\end{tabular} +{%% if fig_scale %%} +} +{%% endif %%} +\end{minipage}\end{document} +''' +# ================================================================= +GE_TEMPLATE = r'''\documentclass[notitlepage]{article} +\pagestyle{empty} +\usepackage[margin=0cm,paperwidth=90in]{geometry} + +\usepackage{mathtools} +\usepackage{xltxtra} +\usepackage{pdflscape} +\usepackage{graphicx} +\usepackage[table,svgnames]{xcolor} +\usepackage{nicematrix,tikz} +\usetikzlibrary{calc,fit,decorations.markings} + +\newcommand*{\colorboxed}{} +\def\colorboxed#1#{% + \colorboxedAux{#1}% +} +\newcommand*{\colorboxedAux}[3]{% + % #1: optional argument for color model + % #2: color specification + % #3: formula + \begingroup + \colorlet{cb@saved}{.}% + \color#1{#2}% + \boxed{% + \color{cb@saved}% + #3% + }% + \endgroup +} + +% ---------------------------------------------------------------------------- extension +{{extension}} +\begin{document}\begin{minipage}{\textwidth} +\begin{landscape} +{%% if fig_scale %%} +{{fig_scale}} +{%% endif %%} +% ---------------------------------------------------------------------------- preamble +{{preamble}}% +% ============================================================================ NiceArray +$\begin{NiceArray}[vlines-in-sub-matrix = I]{{mat_format}}{{mat_options}}% +{%% if codebefore != [] -%%} +\CodeBefore [create-cell-nodes] + {%% for entry in codebefore: -%%} + {{entry}} + {%% endfor -%%}% +\Body +{%% endif -%%} +{{mat_rep}} +\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ] +% --------------------------------------------------------------------------- submatrix delimiters + {%% for loc in submatrix_locs: -%%} + \SubMatrix({{loc[1]}})[{{loc[0]}}] + {%% endfor -%%} + {%% for txt in submatrix_names: -%%} + {{txt}} + {%% endfor -%%} +% --------------------------------------------------------------------------- pivot outlines +\begin{tikzpicture} + \begin{scope}[every node/.style = draw] + {%% for loc in pivot_locs: -%%} + \node [draw,{{loc[1]}},fit = {{loc[0]}}] {} ; + {%% endfor -%%} + \end{scope} +% +% --------------------------------------------------------------------------- explanatory text + {%% for loc,txt,c in txt_with_locs: -%%} + \node [right,align=left,color={{c}}] at {{loc}} {\qquad {{txt}} } ; + {%% endfor -%%} +% +% --------------------------------------------------------------------------- row echelon form path + {%% for t in rowechelon_paths %%} {{t}} + {%% endfor -%%} +\end{tikzpicture} +\end{NiceArray}$ +{%% if fig_scale %%} +} +{%% endif %%} +\end{landscape} +\end{minipage}\end{document} +''' +# ================================================================================================================================ +def convert_tuple_array_to_rationals(A): + '''overcome the limitations of the PyCall interface: convert integer tuples to rationals''' + A = _jl_to_py(A) + return sym.Matrix( [[sym.Rational(num, denom) for num, denom in row] for row in A] ) + +def convert_tuple_list_to_rationals(A): + '''overcome the limitations of the PyCall interface: convert integer tuples to rationals''' + A = _jl_to_py(A) + return sym.Matrix( [sym.Rational(num, denom) for num, denom in A] ) + +def convert_to_sympy_matrix(A): + if A is None: return None + A = _jl_to_py(A) + if isinstance( A, list): + if isinstance( A[0], list): + if isinstance(A[0][0], tuple ): # list of list of tuples + A = convert_tuple_array_to_rationals(A) + else: # list of list of values + A = sym.Matrix(A) + else: # just a list + if isinstance(A[0], tuple ): # list of tuples + A = convert_tuple_list_to_rationals(A) + else: + A = sym.Matrix(A) + else: # not a list; should be matrix + A = sym.Matrix(A) + return A +# ================================================================================================================================ +def to_str(x, digits=3): + """ + Convert the input into a string representation. + + Parameters: + - `x`: The input value. Can be an integer, float, complex number, or a SymPy expression. + + Returns: + - A string representation of `x`. + """ + + # Check for integers + if isinstance(x, int): + return str(x) + + # Check for floats + elif isinstance(x, float): + return str(round(x, digits)) + + # Check for complex numbers + elif isinstance(x, complex): + real_part = round(x.real, digits) + imag_part = round(x.imag, digits) + + # Handle purely real or purely imaginary numbers + if imag_part == 0: + return str(real_part) + elif real_part == 0: + return f"{imag_part}i" + elif imag_part > 0: + return f"{real_part} + {imag_part}i" + else: + return f"{real_part} - {abs(imag_part)}i" + + # Check for SymPy expressions + elif isinstance(x, sym.Expr): + return str(x.evalf(digits)) + + # For any other type that is a number + elif isinstance(x, (bool,)): + return str(int(x)) # Since bool is a subclass of int in Python + + else: + return str(x) + +# ================================================================================================================================ +# Index Computations and formating associated with Matrices laid out on a grid. +# ================================================================================================================================ +class MatrixGridLayout: + ''' Basic Computations of the Matrix Grid Layout and the resulting Tex Representation + Indexing is zero-based. + + The matrices are first written into an array, with an associated format string: + array_format_string_list() + array_of_tex_entries() + decorate_tex_entries() + Each array row is converted to a string + tex_repr + The display is further enhanced by adding + nm_add_option + nm_submatrix_locs + ''' + + def __init__(self, matrices, extra_cols=None, extra_rows = None ): + '''save the matrices, determine the matrix grid dimensions and the number of rows in the first row of the grid + Note that the number of cols in the first grid row and/or the number of rows in the first grid col can be ragged + ''' + # Fix up matrices + if not isinstance( matrices, list): # allow using this class for a single matrix [[None, A]] + matrices = [[ None, matrices ]] + + self.matrices = [] + cnt_layers = 0 + for (i,layer) in enumerate(matrices): # ensure the matrices are not passed as lists + cnt_layers += 1 + l = [] + for (j,mat) in enumerate(layer): + if isinstance( mat, list ): + l.append( np.array(mat) ) + else: + l.append( mat ) + self.matrices.append(l) + + self.nGridRows = cnt_layers # len(self.matrices) + self.nGridCols = max(len(row) for row in self.matrices) + + + self._set_shapes() + self.array_names = [] + + self.mat_row_height = [ max(map( lambda s: s[0], self.array_shape[i, :])) for i in range(self.nGridRows)] + self.mat_col_width = [ max(map( lambda s: s[1], self.array_shape[:, j])) for j in range(self.nGridCols)] + + self.adjust_positions( extra_cols, extra_rows ) + self.txt_with_locs = [] + self.rowechelon_paths = [] + self.codebefore = [] + self.preamble = '\n' + r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n' + self.extension = '%\n' + + def adjust_positions( self, extra_cols=None, extra_rows=None ): + '''insert extra rows and cols between matrices''' + self.extra_cols = MatrixGridLayout._set_extra( extra_cols, self.nGridCols ) + self.extra_rows = MatrixGridLayout._set_extra( extra_rows, self.nGridRows ) + + self.cs_extra_cols = np.cumsum( self.extra_cols ) + self.cs_extra_rows = np.cumsum( self.extra_rows ) + + self.cs_mat_row_height = np.cumsum( np.hstack([[0], self.mat_row_height])) + self.cs_mat_col_width = np.cumsum( np.hstack([[0], self.mat_col_width ])) + + self.tex_shape = (self.cs_mat_row_height[-1]+self.cs_extra_rows[-1], + self.cs_mat_col_width [-1]+self.cs_extra_cols[-1]) + + def _set_shapes(self): + '''compute the shapes of the arrays in the grid, obtain the maximal number of rows/cols''' + self.array_shape = np.empty((self.nGridRows, self.nGridCols), tuple) + for i in range(self.nGridRows): + row = self.matrices[i] + row_len = len(row) + for j in range(self.nGridCols): + if j < row_len and row[j] is not None: + # Check if it's actually a matrix/array with .shape attribute + try: + self.array_shape[i, j] = row[j].shape + except (AttributeError, TypeError): + # Not a matrix (could be wrapped symbol from PythonCall) + self.array_shape[i, j] = (0, 0) + else: + self.array_shape[i, j] = (0, 0) + + if self.nGridRows > 1: + self.n_Col_0 = [s[1] for s in self.array_shape[1:, 0]] + else: + self.n_Col_0 = [] + + if self.nGridCols > 1: + self.m_Row_0 = [s[0] for s in self.array_shape[0, 1:]] + else: + self.m_Row_0 = [] + + @staticmethod + def _set_extra( extra, n ): + if isinstance(extra, int): + extra = np.hstack([ np.repeat( 0, n), [extra] ]) + elif extra is None: + extra = np.repeat( 0, n+1 ) + else: + assert( len(extra) == (n+1)) + return extra + + def describe(self): + #self.grid_shape = [len(self.mat_row_height), len(self.mat_col_width)] + # = [self.nGridRows, self.nCOLMats] + + print( f"Layout {self.nGridRows} x {self.nGridCols} grid:") + + print( f". insert extra_cols: {self.extra_cols}") + print( f". col_start = {self.cs_mat_col_width + self.cs_extra_cols}") + print( f". row_start = {self.cs_mat_row_height + self.cs_extra_rows}") + print() + + print( "Consistent Matrix Sizes in the grid") + for i in self.mat_row_height: + for j in self.mat_col_width: + print( f' {(i,j)}', end='') + print() + + print("Actual TopLeft:BottomRight Indices") + for i in range(self.nGridRows): + for j in range(self.nGridCols): + tl,br,_ = self._top_left_bottom_right(i,j) + print( f' {tl}:{br}', end='') + print() + + def element_indices( self, i,j, gM, gN ): + '''return the actual indices of element (i,j) in the matrix at grid position (gM,gN)''' + last_row = self.cs_mat_row_height[gM+1] + self.cs_extra_rows[gM] + last_col = self.cs_mat_col_width [gN+1] + self.cs_extra_cols[gN] + + A_shape = self.array_shape[gM][gN] + return (last_row - (A_shape[0] -i), + last_col - (A_shape[1] - j) + ) + + def _top_left_bottom_right( self, gM, gN ): + ''' given the grid position obtain the actual indices of the top left corner for the matrix''' + A_shape = self.array_shape[gM,gN] + + row_offset = self.cs_extra_rows[gM]+self.cs_mat_row_height[gM]+self.mat_row_height[gM]-A_shape[0] + col_offset = self.cs_extra_cols[gN]+self.cs_mat_col_width [gN]+self.mat_col_width [gN]-A_shape[1] + return (row_offset, col_offset), \ + (row_offset+A_shape[0]-1, col_offset+A_shape[1]-1), \ + A_shape + + #def tex_repr( self, blockseps = r' \noalign{\vskip2mm} '): + def tex_repr( self, blockseps = r'[2mm]'): + '''Create a list of strings from the array of TeX strings, one for each line in the grid ready to print in the LaTeX document''' + self.tex_list =[' & '.join( self.a_tex[k,:]) for k in range(self.a_tex.shape[0])] + for i in range( len(self.tex_list) -1): + self.tex_list[i] += r' \\' + + for i in (self.cs_mat_row_height[1:-1] + self.cs_extra_rows[1:-1] - self.extra_rows[1:-1]): + self.tex_list[i-1] += blockseps + + if self.extra_rows[-1] != 0: # if there are final extra rows, we need another sep + self.tex_list[ self.tex_shape[0] - self.extra_rows[-1] - 1] += blockseps + + def array_of_tex_entries(self, formater=str): + '''Create a matrix of TeX strings from the grid entries''' + + a_tex = np.full( self.tex_shape,"", dtype=object) + + for i in range(self.nGridRows): + for j in range(self.nGridCols): + tl,br,shape = self._top_left_bottom_right(i,j) + A = self.matrices[i][j] + for ia in range( shape[0]): + for ja in range(shape[1]): + a_tex[ tl[0]+ia, tl[1]+ja ] = formater( A[ia,ja]) + self.a_tex = a_tex + + def decorate_tex_entries( self, gM, gN, decorate, entries=None): + '''apply decorate to the list of i,j TeX entries to grid matrix at (gM,gN)''' + try: # avoid writing code for A == None case + tl,br,shape = self._top_left_bottom_right(gM,gN) + + if entries is None: + for i in range(shape[0]): + for j in range(shape[1]): + self.a_tex[tl[0]+i, tl[1]+j] = decorate(self.a_tex[tl[0]+i, tl[1]+j]) + else: + for (i,j) in entries: + self.a_tex[tl[0]+i, tl[1]+j] = decorate(self.a_tex[tl[0]+i, tl[1]+j]) + except: + pass + + @staticmethod + def matrix_array_format( N, p_str='I', vpartitions=None): + '''format string for a matrix with N columns''' + if vpartitions is None: + return N*"r" + #return f"*{N}r" + s = "" + cur = 0 + for p in vpartitions: + s_r = (p-cur)*"r" + s += f"{s_r}{p_str}" + #s += f"*{p-cur}r{p_str}" + cur = p + if cur < N: + s += (N-cur)*"r" + #s += f"*{N-cur}r" + return s + + #def array_format_string_list( self, partitions={}, spacer_string=r'@{\qquad\ }', p_str='I', last_col_format = "l@{\qquad\;\;}") : + def array_format_string_list( self, partitions={}, spacer_string=r'@{\hspace{9mm}}', + p_str='I', last_col_format=r'l@{\hspace{2cm}}' ): + '''Construct the format string. Partitions is a dict { gridcolumn: list of partitions}''' + + for i in range(self.nGridCols): # make sure we have a partion entry for each column of matrices + if i not in partitions: + partitions[i]=None + + # format for initial extra cols + l = self.extra_cols[0] + fmt = l*'r' + + last = self.nGridCols - 1 + for i in range(self.nGridCols): + # we now iterate over (matrix, extra) pairs + # ----------- matrix ----------------------- + N = self.mat_col_width[i] + fmt += spacer_string + MatrixGridLayout.matrix_array_format( N, p_str=p_str, vpartitions=partitions[i] ) + + # ------------ spacer ---------------------- + l = self.extra_cols[i+1] + if l > 0: + if i == last: + if l > 1: + fmt += spacer_string + (l-1)*'r'+last_col_format + else: + fmt += spacer_string + last_col_format + else: + fmt += spacer_string + l*'r' + + self.format = fmt + + def tl_shape_below( self, gM, gN ): + '''obtain tl and shape of free space below grid matrix at (gM, gN)''' + tl,br,_ = self._top_left_bottom_right( gM, gN ) + free_tl = (br[0]+1, tl[1]) + shape = (self.tex_shape[0]-free_tl[0], self.tex_shape[1] - tl[1]) + return free_tl, shape + + def tl_shape_above( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,br,_ = self._top_left_bottom_right( gM, gN ) + free_tl = (tl[0]-self.extra_rows[gM], tl[1]) + shape = (self.extra_rows[gM], self.tex_shape[1]-free_tl[1]) + return free_tl, shape + + def tl_shape_left( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,_,_ = self._top_left_bottom_right( gM, gN ) + return (tl[0],tl[1]-self.extra_cols[gN]), \ + (self.tex_shape[0]-tl[0],self.extra_cols[gN]) + + def tl_shape_right( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,_,shape = self._top_left_bottom_right( gM, gN ) + return (tl[0],tl[1]+shape[1]), \ + (self.tex_shape[0]-tl[0],self.extra_cols[gN+1]) + + def add_row_above( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_above( gM, gN ) + for (j,v) in enumerate(m): + self.a_tex[tl[0]+offset, tl[1]+j] = formater( v ) + + def add_row_below( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_below( gM, gN ) + for (j,v) in enumerate(m): + self.a_tex[tl[0]+offset, tl[1]+j] = formater( v ) + + def add_col_right( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_right( gM, gN ) + for (i,v) in enumerate(m): + self.a_tex[tl[0]+i, tl[1]+offset] = formater( v ) + + def add_col_left( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_left( gM, gN ) + for (i,v) in enumerate(m): + self.a_tex[tl[0]+i, tl[1]+offset-1] = formater( v ) + + def nm_submatrix_locs(self, name='A', color='blue', name_specs=None, line_specs=None ): + '''nicematrix style location descriptors of the submatrices''' + # name_specs = [ spec*]; spec = [ (gM, gN), position, text ] + # line_specs = [ spec*]; spec = [ (gM, gN), h_lines, vlines ] + self.submatrix_name = name + smat_args = np.full( (self.nGridRows,self.nGridCols),"", dtype=object) + if line_specs is not None: + for pos,h_lines,v_lines in line_specs: + if h_lines is not None: + if isinstance( h_lines, int): + smat_args[pos] = f',hlines={h_lines}' + else: + smat_args[pos] = ',hlines={'+ ','.join([str(s) for s in h_lines]) + '}' + if v_lines is not None: + if isinstance( v_lines, int): + smat_args[pos] += f',vlines={v_lines}' + else: + smat_args[pos] += ',vlines={'+ ','.join([str(s) for s in v_lines]) + '}' + + locs = [] + for i in range(self.nGridRows): + for j in range(self.nGridCols): + if self.array_shape[i,j][0] != 0: + tl,br,_ = self._top_left_bottom_right(i,j) + smat_arg = f"name={name}{i}x{j}"+smat_args[i,j] + locs.append( [ smat_arg, f"{{{tl[0]+1}-{tl[1]+1}}}{{{br[0]+1}-{br[1]+1}}}"] ) + + self.locs = locs + + if name_specs is not None: + array_names = [] + ar=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north east) + (0.02,0.02) $) -- +(0.6cm,0.3cm) node[COLOR, above right=-3pt]{TXT};".replace('COLOR',color) + al=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north west) + (-0.02,0.02) $) -- +(-0.6cm,0.3cm) node[COLOR, above left=-3pt] {TXT};".replace('COLOR',color) + a =r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north) + (0,0) $) -- +(0cm,0.6cm) node[COLOR, above=1pt] {TXT};".replace('COLOR',color) + + bl=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south west) + (-0.02,-0.02) $) -- +(-0.6cm,-0.3cm) node[COLOR, below left=-3pt]{TXT};".replace('COLOR',color) + br=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south east) + (0.02,-0.02) $) -- +(0.6cm,-0.3cm) node[COLOR, below right=-3pt]{TXT};".replace('COLOR',color) + b =r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south) + (0,0) $) -- +(0cm,-0.6cm) node[COLOR, below=1pt] {TXT};".replace('COLOR',color) + + for (gM,gN),pos,txt in name_specs: + nm = f"{name}{gM}x{gN}" + t = None + if pos == 'a': t = a.replace('NAME',nm).replace('TXT',txt) + elif pos == 'al': t = al.replace('NAME',nm).replace('TXT',txt) + elif pos == 'ar': t = ar.replace('NAME',nm).replace('TXT',txt) + elif pos == 'b': t = b.replace('NAME',nm).replace('TXT',txt) + elif pos == 'bl': t = bl.replace('NAME',nm).replace('TXT',txt) + elif pos == 'br': t = br.replace('NAME',nm).replace('TXT',txt) + if t is not None: + array_names.append( t ) + + self.array_names = array_names + + def nm_background(self, gM,gN, loc_list, color='red!15', pt=0): + '''add background color to a list of entries''' + tl,_,_ = self._top_left_bottom_right( gM, gN ) + for entry in loc_list: + cmd_1 = f'\\tikz \\node [fill={color}, inner sep = {pt}pt, fit = ' + if not isinstance( entry, list): + cmd_2 = f'({tl[0]+entry[0]+1}-{tl[1]+entry[1]+1}-medium)' + else: + cmd_2 = f'({tl[0]+entry[0][0]+1}-{tl[1]+entry[0][1]+1}-medium) ({tl[0]+entry[1][0]+1}-{tl[1]+entry[1][1]+1}-medium)' + cmd_3 = ' ] {} ;' + self.codebefore.append( cmd_1 + cmd_2 + cmd_3 ) + + + def nm_text(self, txt_list, color='violet'): + '''add text add each layer (requires a right-most extra col)''' + assert( self.extra_cols[-1] != 0 ) + + # find the indices of the first row in the last col (+1 for nicematrix indexing) + txt_with_locs = [] + for (g,txt) in enumerate(txt_list): + A_shape = self.array_shape[g][self.nGridCols-1] + + first_row = self.cs_mat_row_height[g] + self.cs_extra_rows[g] + (self.mat_row_height[g] - A_shape[0])+1 + txt_with_locs.append(( f'({first_row}-{self.tex_shape[1]-1}.east)', txt, color) ) + self.txt_with_locs = txt_with_locs + + def nm_add_rowechelon_path( self, gM,gN, pivots, case='hh', color='violet,line width=0.4mm', adj=0.1 ): + tl,_,shape = self._top_left_bottom_right( gM, gN ) + + def coords(i,j): + if i >= shape[0]: + if gN == 0 and j == 0: # HACK alert: first col in leftmost matrix! + x = r'\x1' + else: + x = r'\x2' if j >= shape[1] else r'\x4' + #x = r'\x2' if j >= shape[1] else r'\x1' + y = r'\y2' + p = f'({x},{y})' + elif j >= shape[1]: + x = r'\x2' if i >= shape[0] else r'\x2' + y = r'\y4' + p = f'({x},{y})' + elif j == 0: + x = r'\x1' + y = r'\y1' if i == 0 else r'\y3' + p = f'({x},{y})' + else: + x = f'{i+1+tl[0]}' + y = f'{j+1+tl[1]}' + p = f'({x}-|{y})' + + if j != 0 and j < shape[1] and adj != 0: + p = f'($ {p} + ({adj:2},0) $)' + + return p + + cur = pivots[0] + ll = [cur] if (case == 'vv') or (case == 'vh') else [] + for nxt in pivots[1:]: # at top right + if cur[0] != nxt[0]: # down 1 + cur = (cur[0]+1, cur[1]) + ll.append( cur ) + if nxt[1] != cur[1]: # over + cur = (cur[0], nxt[1]) + ll.append( cur ) + if cur != nxt: + ll.append(nxt) # down to top right + cur = nxt + + if len(ll) == 0 and case == 'hv': + ll = [ (pivots[0][0]+1,pivots[0][0] ), (shape[0], pivots[0][1] )] + + if (case == 'hh') or (case == 'vh'): + if cur[0] != shape[0]: # down 1 + cur = (cur[0]+1, cur[1]) + ll.append( cur ) + ll.append( (cur[0], shape[1])) # over to right + else: + ll.append( (shape[0], cur[1])) # down to bottom + + corners = f'let \\p1 = ({self.submatrix_name}{gM}x{gN}.north west), \\p2 = ({self.submatrix_name}{gM}x{gN}.south east), ' + + if (case == 'vv') or (case == 'vh'): + p3 = f'\\p3 = ({ll[1][0]+tl[0]+1}-|{ll[1][1]+tl[1]+1}), ' + else: + p3 = f'\\p3 = ({ll[0][0]+tl[0]+1}-|{ll[0][1]+tl[1]+1}), ' + + if (case=='vh') or (case=='hh'): # last dir: -> + i,j = ll[-2] + p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + else: # last dir: | + i,j = ll[-1] + #if len(pivots) == 1 and cur[0] == 0 and gN == 0: # was this my previous "FIX"??? + # p4 = f'\\p4 = ({self.submatrix_name}{gM}x{gN}.south west) in ' + #else: + # p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + + cmd = '\\tikz \\draw['+color+'] ' + corners + p3 + p4 + ' -- '.join( [coords(*p) for p in ll] ) + ';' + self.rowechelon_paths.append( cmd ) + + def apply( self, func, *args, **kwargs ): + func( self, *args, **kwargs ) + + def nm_latexdoc( self, template = GE_TEMPLATE, fig_scale=None ): + if fig_scale is not None: + fig_scale = r'\scalebox{'+str(fig_scale)+'}{%' + return jinja2.Template( template, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = self.preamble, + fig_scale = fig_scale, + extension = self.extension, + mat_rep = '\n'.join( self.tex_list ), + mat_format = '{'+self.format+'}', + mat_options = '[create-extra-nodes,create-medium-nodes]', + submatrix_locs = self.locs, + submatrix_names = self.array_names, + pivot_locs = [], + txt_with_locs = self.txt_with_locs, + rowechelon_paths= self.rowechelon_paths, + codebefore = self.codebefore, + ) +# ----------------------------------------------------------------------------------------------------- +def make_decorator( text_color='black', bg_color=None, text_bg=None, boxed=None, box_color=None, bf=None, move_right=False, delim=None ): + '''decorate terms: + text_color : apply text color, default = 'black' + text_bg : apply background color, default = None + boxed : put a box around the entry, default = False (None) + box_color: put a colored box around the entry, default = False (None) + bf : make the entry boldface, default = False (None) + move_right : apply \\mathrlap, default = False (None) + delim : put delimiter around text, default = None, e.g., surround with in '$' + ''' + box_decorator = "\\boxed<{a}>" + coloredbox_decorator = "\\colorboxed<{color}><{a}>" + color_decorator = "\\Block[draw={text_color},fill={bg_color}]<><{a}>" + txt_color_decorator = "\\color<{color}><{a}>" + bg_color_decorator = "\\colorbox<{color}><{a}>" + bf_decorator = "\\mathbf<{a}>" + rlap_decorator = "\\mathrlap<{a}>" + delim_decorator = "<{delim}{a}{delim}>" + + x = '{a}' + if bf is not None: + x = bf_decorator.format(a=x) + if boxed is not None: + x = box_decorator.format( a=x ) + if box_color is not None: + x = coloredbox_decorator.format( a=x, color=box_color ) + if bg_color is not None: + x = bg_color_decorator.format(a=x, color=bg_color) + if text_bg is not None: + x = color_decorator.format(a=x, text_color= text_color, bg_color=text_bg) + elif text_color != 'black': + x = txt_color_decorator.format( color=text_color, a=x) + + if move_right: + x = rlap_decorator.format(a=x) + if delim is not None: + x = delim_decorator.format( delim=delim, a=x ) + + x = x.replace('<','{{').replace('>','}}') + + return lambda a: x.format(a=a) + +# ================================================================================================================================ +def str_rep_from_mat( A, formater=str): + '''str_rep_from_mat( A, formater=str) + convert matrix A to a string using formater + ''' + A = _jl_to_py(A) + + M,N=A.shape + return np.array( [[formater(A[i,j]) for j in range(N)] for i in range(M)] ) + +def str_rep_from_mats( A, b, formater=str ): + '''str_rep_from_mats( A, b, formater=str) + convert matrix A and vector b to a string using formater, return the augmented matrix + ''' + A = _jl_to_py(A) + b = _jl_to_py(b) + sA = str_rep_from_mat(A, formater) + sb = np.array(b).reshape(-1,1) + return np.hstack( [sA, sb] ) +# ================================================================================================================================ +def mk_ge_names(n, lhs='E', rhs=['A','b'], start_index=1 ): + '''utility to generate array names for ge''' + names = np.full( shape=(n,2),fill_value='', dtype=object) + + def pe(i): + if start_index is None: + return ' '.join([f' {lhs}' for k in range(i,0,-1)]) + else: + return ' '.join([f' {lhs}_{k+start_index-1}' for k in range(i,0,-1)]) + def pa(e_prod,i): + if i > 0 and rhs[-1] == 'I': + rhs[-1] = '' + return r' \mid '.join( [e_prod+' '+k for k in rhs ]) + + for i in range(n): + if start_index is None: + names[i,0] = f'{lhs}' + else: + names[i,0] = f'{lhs}_{start_index+i-1}' + + e_prod = pe(i) + names[i,1] = pa(e_prod,i) + + if len(rhs) > 1: + for i in range(n): + names[i,1] = r'\left( '+ names[i,1] + r' \right)' + + for i in range(n): + for j in range(2): + names[i,j] = r'\mathbf{ ' + names[i,j] + ' }' + + terms = [ [(0,1),'ar', '$' + names[0,1] + '$']] + for i in range(1,n): + terms.append( [(i,0), 'al', '$' + names[i,0] + '$']) + terms.append( [(i,1), 'ar', '$' + names[i,1] + '$']) + return terms +# -------------------------------------------------------------------------------------------------------------------------------- +def _ge( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0], [E1, A1], [E2, A2], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] where pt is the inner separation, e.g. 0 + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I']] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + extra_cols = None if comment_list is None else 1 + extra_rows = None if variable_summary is None else 2 + + m = MatrixGridLayout(matrices, extra_rows=extra_rows, extra_cols = extra_cols ) + + # compute the format spec for the arrays and set up the entries (defaults to a single partition line) + if isinstance( Nrhs, np.ndarray ): # julia passes arrays rather than lists :-() + Nrhs = list(Nrhs.flatten()) + + if not isinstance( Nrhs, list): + partitions = {} if Nrhs == 0 else { 1: [m.mat_col_width[-1]-Nrhs]} + else: + nrhs = Nrhs.copy() # partitions just specifies each col + cuts = [m.mat_col_width[-1] - sum(nrhs)] # cut after the main matrix + for cut in nrhs[0:-1]: # we don't need a cut at the end of the matrix + cuts.append( cuts[-1]+cut ) # cut location is cut cols from previous cut + partitions = { 1: cuts} + + m.array_format_string_list( partitions=partitions ) + m.array_of_tex_entries(formater=formater) # could overwride the entry to TeX string conversion here + + if pivot_list is not None: + red_box = make_decorator( text_color=pivot_text_color, boxed=True, bf=True ) + for spec in pivot_list: + m.decorate_tex_entries( *spec[0], red_box, entries=spec[1] ) + + if func is not None: + m.apply( func ) + + if comment_list is not None: + m.nm_text( comment_list ) + + if variable_summary is not None: + blue = make_decorator(text_color=variable_colors[1], bf=True) + red = make_decorator(text_color=variable_colors[0], bf=True) + typ = [] + var = [] + for (i,basic) in enumerate(variable_summary): + if basic is True: + typ.append(red(r'\Uparrow')) + var.append(red( f'x_{i+1}')) + elif basic is False: + typ.append(blue(r'\uparrow')) + var.append(blue( f'x_{i+1}')) + else: + typ.append(blue('')) + var.append(blue('')) + m.add_row_below(m.nGridRows-1,1,typ, formater=lambda a: a ) + m.add_row_below(m.nGridRows-1,1,var, offset=1, formater=lambda a: a ) + + if array_names is not None: + name_specs = mk_ge_names( m.nGridRows, *array_names, start_index ) + else: + name_specs = None + + m.nm_submatrix_locs('A',color='blue',name_specs=name_specs) # this defines the submatrices (the matrix delimiters) + m.tex_repr() # converts the array of TeX entries into strings with separators and spacers + + if bg_for_entries is not None: + for spec in bg_for_entries: + if all(isinstance(elem, list) for elem in spec): + for s in spec: + m.nm_background( *s ) + else: + m.nm_background( *spec ) + + if ref_path_list is not None: + for spec in ref_path_list: + m.nm_add_rowechelon_path( *spec ) + + m_code = m.nm_latexdoc(template = GE_TEMPLATE, fig_scale=fig_scale ) + + tex_file,svg_file = itikz.svg_file_from_tex( + m_code, prefix='ge_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + + + return m,tex_file,svg_file +# ----------------------------------------------------------------------------------------------- +def ge( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0, ... ], [E1, A1, ... ], [E2, A2, ... ], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I']] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + + # Normalize all incoming structured arguments + matrices = _jl_to_py(matrices) + bg_for_entries = _jl_to_py(bg_for_entries) + pivot_list = _jl_to_py(pivot_list) + ref_path_list = _jl_to_py(ref_path_list) + array_names = _jl_to_py(array_names) + variable_colors = _jl_to_py(variable_colors) + + m, tex_file, svg_file = _ge( matrices, Nrhs=Nrhs, formater=formater, + pivot_list=pivot_list, bg_for_entries=bg_for_entries, + variable_colors=variable_colors,pivot_text_color=pivot_text_color, + ref_path_list=ref_path_list, comment_list=comment_list, + variable_summary=variable_summary, array_names=array_names, + start_index=start_index, func=func, fig_scale=fig_scale, + tmp_dir=tmp_dir, keep_file=keep_file) + + with open(svg_file, "r") as fp: + svg = fp.read() + if svg is not None: + return SVG(svg), m + + return None, m +# ----------------------------------------------------------------------------------------------- +def _to_svg_str( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0], [E1, A1], [E2, A2], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] where pt is the inner separation, e.g. 0 + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I'] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + + m, tex_file, svg_file = _ge( matrices, Nrhs=Nrhs, formater=formater, + pivot_list=pivot_list, bg_for_entries=bg_for_entries, + variable_colors=variable_colors,pivot_text_color=pivot_text_color, + ref_path_list=ref_path_list, comment_list=comment_list, + variable_summary=variable_summary, array_names=array_names, + start_index=start_index, func=func, fig_scale=fig_scale, + tmp_dir=tmp_dir, keep_file=keep_file) + + with open(svg_file, "r") as fp: + svg = fp.read() + + return svg +# ================================================================================================================================ +def _q_gram_schmidt( v_list ): + w = [] + for j in range( len( v_list )): + w_j = v_list[j] + for k in range( j ): + w_j = w_j - w[k].dot( v_list[j]) * w[k] + w.append(1/w_j.norm() * w_j) + return w + +def compute_qr_matrices( A, W ): + ''' given the matrix A and the corresponding matrix W with orthogonal columns, + compute the list of list of sympy matrices in a QR layout + ''' + A = _jl_to_py(A) + W = _jl_to_py(W) + A = sym.Matrix(A) + W = sym.Matrix(W) + WtW = W.T @ W + WtA = W.T @ A + S = sym.Matrix.diag( list( map(lambda x: 1/sym.sqrt(x), sym.Matrix.diagonal( WtW)))) + + Qt = S*W.T + R = S*WtA + + matrices = [ [ None, None, A, W ], + [ None, W.T, WtA, WtW ], + [ S, Qt, R, None ] ] + return matrices + +def _qr(matrices, formater=str, array_names=True, fig_scale=None, tmp_dir="tmp", keep_file=None): + m = MatrixGridLayout( matrices, extra_rows = [1,0,0,0]) + m.preamble = preamble + '\n' + r" \NiceMatrixOptions{cell-space-limits = 2pt}"+'\n' + + N = matrices[0][2].shape[1] + + m.array_format_string_list() + m.array_of_tex_entries(formater=formater) + + brown = make_decorator(text_color='brown', bf=True ) + def qr_dec_known_zeros( WtA, WtW ): + l_WtA = [(1,2), [(i,j) for i in range(WtA.shape[0]) for j in range(WtA.shape[0]) if i > j ]] + l_WtW = [(1,3), [(i,j) for i in range(WtW.shape[0]) for j in range(WtW.shape[0]) if i != j ]] + return [l_WtA, l_WtW] + + for spec in qr_dec_known_zeros( matrices[1][2], matrices[1][3]): + #[ [(1,2), [(1,0),(2,0),(2,1)]], [(1,3), [(1,0),(2,0),(2,1), (0,1),(0,2),(1,2)]] ]: + m.decorate_tex_entries( *spec[0], brown, entries=spec[1] ) + + red = make_decorator(text_color='red', bf=True) + red_rgt = make_decorator(text_color='red', bf=True, move_right=True) + m.add_row_above(0,2, [red(f'v_{i+1}') for i in range(N)] + [red(f'w_{i+1}') for i in range(N)], formater= lambda a: a ) + m.add_col_left( 1,1, [red_rgt(f'w^t_{i+1}') for i in range(N)], formater= lambda a: a ) + + if array_names: + dec = make_decorator(bf=True, delim='$') + m.nm_submatrix_locs( 'QR', color='blue', name_specs=[ + [(0,2), 'al', dec('A')], + [(0,3), 'ar', dec('W')], + # ---------------------- + [(1,1), 'al', dec('W^t')], + [(1,2), 'al', dec('W^t A')], + [(1,3), 'ar', dec('W^t W')], + # ---------------------- + [(2,0), 'al', dec(r'S = \left( W^t W \right)^{-\tfrac{1}{2}}')], + [(2,1), 'br', dec(r'Q^t = S W^t')], + [(2,2), 'br', dec('R = S W^t A')] + ]) + else: + m.nm_submatrix_locs() + + m.tex_repr( blockseps = r'\noalign{\vskip3mm} ') + + m_code = m.nm_latexdoc( fig_scale=fig_scale ) + + + tex_file,svg_file = itikz.svg_file_from_tex( + m_code, prefix='qr_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + + return m,tex_file,svg_file +# ----------------------------------------------------------------------------------------------- +def qr(matrices, formater=str, array_names=True, fig_scale=None, tmp_dir="tmp", keep_file=None): + m,tex_file,svg_file = _qr(matrices, formater=formater, array_names=array_names, fig_scale=fig_scale, tmp_dir=tmp_dir, keep_file=keep_file) + matrices = _jl_to_py(matrices) + + with open(svg_file, "r") as fp: + svg = fp.read() + if svg is not None: + return SVG(svg), m + + return None, m + +def gram_schmidt_qr( A_, W_, formater=sym.latex, fig_scale=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + W = _jl_to_py(W) + + A = sym.Matrix( A_ ) + W = sym.Matrix( W_ ) + + WtW = W.T @ W + WtA = W.T @ A + S = WtW**(-1) + for i in range(S.shape[0]): + S[i,i]=sym.sqrt(S[i,i]) + + Qt = S*W.T + R = S*WtA + + matrices = [ [ None, None, A, W ], + [ None, W.T, WtA, WtW ], + [ S, Qt, R, None ] ] + h,m = qr( matrices, formater=formater, array_names=True, fig_scale=fig_scale, tmp_dir=tmp_dir ) + return h,m + +# ================================================================================================== +# BACKSUBSTITUTION +# ================================================================================================== +class BacksubstitutionCascade: + def __init__(self, ref_A, ref_rhs = None, var_name='x' ): + self.ref_syseq( ref_A, ref_rhs=ref_rhs, var_name=var_name) + + @classmethod + def from_ref_Ab(cls, ref_Ab, var_name='x'): + """create `cls` from augmented row echelon form matrix Ab (b is a column vector)""" + + if isinstance( ref_Ab, list ): + ref_A = [row[0:-1] for row in ref_Ab] + ref_rhs = [row[-1] for row in ref_Ab] + else: + ref_A = ref_Ab[:,0:-1] + ref_rhs = ref_Ab[:,-1] + return cls( ref_A, ref_rhs, var_name ) + + def ref_syseq(self, ref_A, ref_rhs = None, var_name='x' ): + self.var_name = var_name + self.ref_A = convert_to_sympy_matrix( ref_A ) + self.ref_rhs = convert_to_sympy_matrix( ref_rhs ) + + if ref_rhs is None: + self.rref_A, self.pivot_cols = self.ref_A.rref() + self.rref_rhs = None + else: + Ab = self.ref_A.row_join( self.ref_rhs ) + rref_Ab, pivot_cols_Ab = Ab.rref() + self.rref_A = rref_Ab[:,0:-1] + self.rref_rhs = rref_Ab[:,-1] + if pivot_cols_Ab[-1] == self.rref_A.shape[1]: + self.pivot_cols = pivot_cols_Ab[:-1] + else: + self.pivot_cols = pivot_cols_Ab + + #return cls( ref_Ab[:,0:-1], ref_Ab[:,-1] ) + + self.free_cols = [ i for i in range(self.ref_A.shape[1]) if i not in self.pivot_cols] + self.rank = len( self.pivot_cols) + + def set_ref_rhs( self, rhs ): + self.ref_rhs = None if rhs is None else sym.Matrix( rhs ) + + def ref_Ab( self, Ab ): + Ab = sym.Matrix( Ab ) + self.ref_syseq( Ab[:,0:-1], Ab[:,-1], var_name=self.var_name ) + + @staticmethod + def _bs_equation( ref_A, pivot_row, pivot_col, rhs=None, name="x" ): + """given a row, generate the right hand terms from A_ref for the back substitution algorithm""" + t = sym.Integer(0) if rhs is None else rhs[pivot_row] + for j in range(pivot_col+1, ref_A.shape[1]): + t = t - ref_A[pivot_row,j]*sym.Symbol(f"{name}_{j+1}") + + if t.is_zero: return f" 0 " + + factor = sym.Integer(1)/ref_A[pivot_row,pivot_col] + + if factor == 1: return(sym.latex(t)) + elif factor == -1: return f"- \\left( {sym.latex(t)} \\right)" + else: return f"{sym.latex(factor)} \\left( {sym.latex(t)} \\right)" + + def _gen_back_subst_eqs( self ): + """generate the equations for the back substitution algorithm""" + + alpha = r'\alpha' + var_name = self.var_name + bs = [] + if len(self.free_cols) > 0: + bs.append( ',\\;'.join([f"{self.var_name}_{i+1} = {alpha}_{i+1}" for i in self.free_cols] )) + start = self.rank-1 + else: + bs.append( f"{self.var_name}_{self.rank} = {BacksubstitutionCascade._bs_equation(self.ref_A,self.rank-1,self.pivot_cols[-1], self.ref_rhs, name=alpha )}") + start = self.rank-2 + + for i in range(start,-1, -1): + bs.append( [ + f"{self.var_name}_{self.pivot_cols[i]+1} = {BacksubstitutionCascade._bs_equation(self.ref_A, i,self.pivot_cols[i], self.ref_rhs, name=var_name )}", + f"{self.var_name}_{self.pivot_cols[i]+1} = {BacksubstitutionCascade._bs_equation(self.rref_A,i,self.pivot_cols[i], self.rref_rhs, name=alpha )}" + ]) + return bs + + def particular_solution(self): + p = sym.Matrix.zeros( self.rref_A.shape[1], 1) + ps = self.ref_A[0:self.rank,self.pivot_cols]**-1 * self.ref_rhs[0:self.rank,0] + for i,c in enumerate(self.pivot_cols): + p[c,0] = ps[i,0] + return p + + def homogeneous_solution(self): + if len(self.free_cols) == 0: + return sym.Matrix.zeros( self.rref_A.shape[1], 1) + + hs = sym.Matrix.zeros( self.rref_A.shape[1], len(self.free_cols)) + + for (i,col) in enumerate(self.free_cols): + hs[col,i] = 1 + for (i,col) in enumerate(self.pivot_cols): + hs[col, :] = -self.rref_A[i,self.free_cols] + return hs + + def _gen_solution_eqs( self ): + """generate the solution equations""" + #lft = r" \left( \begin{array}{r} " + #rgt = r" \end{array} \right)" + lft = r'\begin{pNiceArray}{r}' + rgt = r'\end{pNiceArray}' + + x = lft + r" \\ ".join( [f" {self.var_name}_{i+1}" for i in range(self.ref_A.shape[1]) ] ) + rgt + + if self.ref_rhs is None: + p = "" + plus = "" + else: + ps = self.particular_solution() + p = lft + r" \\ ".join( [ sym.latex(ps[i,0]) for i in range(self.ref_A.shape[1]) ] ) + rgt + plus = " + " if len(self.free_cols) > 0 else "" + + if len(self.free_cols) > 0: + hs = self.homogeneous_solution() + h_txt = [] + for j,jv in enumerate( self.free_cols ): + h = f"\\alpha_{jv+1} " + lft + r" \\ ".join( [ sym.latex(hs[i,j]) for i in range(self.ref_A.shape[1]) ] ) + rgt + h_txt.append( h ) + + h_txt = " + ".join(h_txt) + else: + h_txt="" + + return "$ " + x + " = " + p + plus + h_txt + " $" + + def _forward_adapter(self): + """ + Build an equivalent back-sub problem via the reversal permutation. + Ly=b --> (R A R^T) y = R b, which is upper-triangular if A was lower-triangular. + Returns a *temporary* BacksubstitutionCascade you can render with existing methods. + """ + + n = self.ref_A.shape[1] + R = self._reversal_matrix(n) + U = R * self.ref_A * R.T + bp = None if self.ref_rhs is None else R * self.ref_rhs + return BacksubstitutionCascade(U, bp, var_name=self.var_name) + + @staticmethod + def _reversal_matrix(n): + R = sym.zeros(n) + for i in range(n): + R[i, n-1-i] = 1 + return R + + @staticmethod + def gen_system_eqs( A, b, var_name ): + """generate the system equations""" + var = set() + def mk( j, v ): + var.add(f"{var_name}_{j}") + try: + if v > 0: + if v == 1: s = [" + ", f"{var_name}_{j}" ] + else: s = [" + ", sym.latex( v ), f"{var_name}_{j}" ] + elif v < 0: + if v == -1: s = [" - ", f"{var_name}_{j}" ] + else: s = [" - ", sym.latex(-v ), f"{var_name}_{j}" ] + else: + s = [""] + except: + vs = sym.latex(v) + if vs.find("+") < 0 or vs.find("-") < 0: + s = [ " + ", "( ", vs.replace("+",r"\+").replace("-",r"\-"), " ) ", f"{var_name}_{j}" ] + else: + s = [ " + ", sym.latex(v), f"{var_name}_{j}" ] + + return s + + A = convert_to_sympy_matrix( A ) + b = convert_to_sympy_matrix( b ) + + eqs = [] + for i in range( A.shape[0] ): + terms = [] + for j in range( A.shape[1] ): + if not A[i,j].is_zero: + terms.extend( mk( j+1, A[i,j] )) + + if len(terms) == 0: terms = [" 0 "] + if terms[0] == " + ": + terms = terms[1:] + eqs.append( "".join( terms ) + " = " + sym.latex( b[i,0] ) ) + return r"\sysdelim.\}\systeme[" + "".join(sorted(var)) + "]{ " + ",".join( eqs ) + "}" + + @staticmethod + def _mk_cascade( bs ): + def mk_args( bs ): + mbs = [ f" {{$\\boxed{{ {bs[0]} }}$}}%" ] + for term in bs[1:]: + mbs.append( [f" {{${term[0]}$}}%", f" {{$\\;\\Rightarrow\\; \\boxed{{ {term[1]} }}$}}%"]) + return mbs + + mbs = mk_args(bs) + num_c = len(mbs)-1 + lines = num_c*[ r"{\ShortCascade%"] + lines.append( mbs[0] ) + for i in range(num_c): + lines.extend( mbs[i+1] ) + lines.append( r"}%") + + return lines + + def nm_latex_doc( self, A=None, b=None, show_system=False, show_cascade=True, show_solution=False, fig_scale=None ): + if show_system: + if A is None or b is None: + system_txt = BacksubstitutionCascade.gen_system_eqs( self.ref_A, self.ref_rhs, self.var_name ) + else: + system_txt = BacksubstitutionCascade.gen_system_eqs( A, b, self.var_name ) + else: + system_txt = None + + if show_cascade: + bsA = self._gen_back_subst_eqs() + cascade_txt = BacksubstitutionCascade._mk_cascade(bsA) # why at times is this a tuple with a list entry????? FIX + else: + cascade_txt = None + + if show_solution: + solution_txt = self._gen_solution_eqs() + else: + solution_txt = None + + return jinja2.Template( BACKSUBST_TEMPLATE, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n', + show_system = show_system, system_txt = system_txt, + show_cascade = show_cascade, cascade_txt = cascade_txt[0] if type(cascade_txt) is tuple else cascade_txt, + show_solution = show_solution,solution_txt = solution_txt, + fig_scale = fig_scale + ) + + def nm_latex_doc_forward(self, A=None, b=None, show_system=False, show_cascade=True, + show_solution=False, fig_scale=None): + """ + Forward-substitution view. Keeps the full feature set of nm_latex_doc, + but runs it on the reversed system. + """ + tmp = self._forward_adapter() + code = tmp.nm_latex_doc(A=A, b=b, show_system=show_system, show_cascade=show_cascade, + show_solution=show_solution, fig_scale=fig_scale) + + n = self.ref_A.shape[1] + # do longest index first to avoid overlap during replacement + for k in range(n, 0, -1): + code = code.replace(f"{self.var_name}_{{{k}}}", f"{self.var_name}_{{{n+1-k}}}") + code = code.replace(rf"\alpha_{{{k}}}", rf"\alpha_{{{n+1-k}}}") + + return code + + def show(self, A=None, b=None, show_system=False, show_cascade=True, + show_solution=False, fig_scale=None, keep_file=None, tmp_dir="tmp", + forward=False): + if forward: + code = self.nm_latex_doc_forward(A=A, b=b, show_system=show_system, + show_cascade=show_cascade, show_solution=show_solution, + fig_scale=fig_scale) + else: + code = self.nm_latex_doc(A=A, b=b, show_system=show_system, + show_cascade=show_cascade, show_solution=show_solution, + fig_scale=fig_scale) + + h = itikz.fetch_or_compile_svg( + code, prefix='backsubst_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h + +# ================================================================================================== +# EigenProblem Tables +# ================================================================================================== +class EigenProblemTable: + ''' Basic Computations of the EigenDecomposition tables and the resulting Tex Representation + Indexing is zero-based. + ''' + + def __init__(self, eig, formater=None, eig_digits=None, sigma_digits=None, vec_digits=None, sz=None ): + ''' + eig: dictionary with entries + 'lambda' : distinct eigenvalues + 'sigma' : distinct singular values + 'ma' : corresponding algebraic multiplicites + 'evecs' : list of mg vectors for each eigenvalue + 'qvecs' : list of mg orthonormal vectors for each eigenvalue + 'uvecs' : list of mg orthonormal vectors for each singular value + 'sz' : size (M,N) of the matrix needed for the SVD table + ''' + + self.N = sum(eig['ma']) + self.sz = (self.N,self.N) if sz is None else sz + + self.ncols = 2*len(eig['lambda'])-1 + self.color = "blue" + + self.eig = eig + self._round( eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits ) + + if formater is not None: + self.eig['lambda'] = list( map( formater, eig['lambda']) ) + + if 'sigma' in eig.keys(): + self.eig['sigma'] = list( map( formater, eig['sigma']) ) + + self.eig['ma'] = eig['ma'] + + if 'evecs' in eig.keys(): + self.eig['evecs'] = self._mk_vectors('evecs', formater=formater ) + if 'qvecs' in eig.keys(): + self.eig['qvecs'] = self._mk_vectors('qvecs', formater=formater ) + if 'uvecs' in eig.keys(): + self.eig['uvecs'] = self._mk_vectors('uvecs', formater=formater ) + + + self.tbl_fmt = self._mk_table_format() + self.rule_fmt = self._mk_rule_format() + + def _round( self, eig_digits=None, sigma_digits=None, vec_digits=None ): + if eig_digits is not None and 'lambda' in self.eig.keys(): + f = lambda x: round(x) if eig_digits==0 else round(x,eig_digits) + self.eig['lambda'] = list( map( f, self.eig['lambda'] )) + if sigma_digits is not None and 'sigma' in self.eig.keys(): + f = lambda x: round(x) if sigma_digits==0 else round(x,sigma_digits) + self.eig['sigma'] = list( map( f, self.eig['sigma'] )) + if vec_digits is not None: + f = lambda x: round(x) if vec_digits==0 else round(x,vec_digits) + if 'evecs' in self.eig.keys(): + self.eig['evecs'] = self._mk_vectors('evecs', f) + if 'qvecs' in self.eig.keys(): + self.eig['qvecs'] = self._mk_vectors('qvecs', f) + if 'uvecs' in self.eig.keys(): + self.eig['uvecs'] = self._mk_vectors('uvecs', f) + + + def _mk_table_format( self ): + fmt = '{@{}l' + self.ncols*'c' + '@{}}' + return fmt + + def _mk_rule_format( self ): + fmt = '' + for i in range(1, len(self.eig['lambda'])+1): + fmt += ' \\cmidrule{' + f'{2*i}-{2*i}' + '}' + return fmt + + def _mk_values( self, key='lambda', formater=str ): + l = list( map( formater, self.eig[key]) ) + if key == 'sigma' and self.eig[key][-1] == '0': + l[-1] = formater(' ') + l = list( map( lambda x: '$'+x+'$', l) ) + + ll=[l[0]] + for i in l[1:]: + ll.append('') + ll.append( i) + return ll + + def mk_values( self, key, formater=str ): + line = self._mk_values(key=key, formater=formater) + return " & ".join( line ) + r' \\' # + self.rule_fmt + + def _mk_vectors(self, key, formater=str ): + groups = [] + for vecs in self.eig[key]: + l_lambda = [] + for vec in vecs: + l_lambda.append( np.array( [ formater(v) for v in vec], dtype=object )) + groups.append( l_lambda ) + return groups + + def mk_vectors(self, key, formater=str, add_height=0 ): + groups = [] + nl = r' \\ ' if add_height == 0 else r' \\'+ f'[{add_height}mm] ' + for vecs in self.eig[key]: + l_lambda = [] + for vec in vecs: + l = [ formater(v) for v in vec] + l_lambda.append( r'$\begin{pNiceArray}{r}' + nl.join(l) + r' \end{pNiceArray}$') + groups.append( ', '.join(l_lambda )) + return " & & ".join( groups ) + + def _mk_diag_matrix( self, key='lambda', mm=8, formater=str ): + space = '@{\\hspace{' + str(mm) + 'mm}}' + pre = r'\multicolumn{' + f'{len(self.eig["ma"])}' + '}{c}{\n'+\ + r'$\begin{pNiceArray}{' + space.join( self.N*['c'] ) + '}' + post = r'\end{pNiceArray}$}' + + Lambda = np.full( self.sz, formater(0), dtype=object) + lambdas = [] + for i,v in enumerate( self.eig['ma'] ): + l = self.eig[key][i] + lambdas += v*[l] + + for i,v in enumerate(lambdas): + try: + Lambda[i,i] = formater(v) + except: + break + + return pre,Lambda,post + + def _mk_evecs_matrix( self, key='evecs', formater=str, mm=0 ): + sz = self.sz[0] if key == 'uvecs' else self.sz[1] + space = '@{\\hspace{' + str(mm) + 'mm}}' if mm > 0 else '' + pre = r'\multicolumn{' + f'{len(self.eig["ma"])}' + '}{c}{\n'+\ + r'$\begin{pNiceArray}{' + space.join( sz*['r'] ) + '}' + post = r'\end{pNiceArray}$}' + + S = np.empty( (sz,sz), dtype=object) + j = 0 + for vecs in self.eig[key]: + for vec in vecs: + for i,v in enumerate(vec): + S[i,j] = formater(v) + j += 1 + return pre,S,post + + def _fmt_matrix( self, pre, m, post, add_height=0 ): + nl = r' \\ ' if add_height == 0 else r' \\'+ f'[{add_height}mm] ' + + mat = [] + for i in range( m.shape[0]): + mat.append( ' & '.join( m[i,: ])) + mat = pre + nl.join( mat ) + r' \\ ' + post + return mat + + def mk_diag_matrix( self, key, formater=str, mm=8, extra_space='', add_height=0 ): + pre, m, post = self._mk_diag_matrix(key=key, formater=formater, mm=mm ) + for i in range(m.shape[0]): + m[i,0] = extra_space+m[i,0] + m[i,self.N-1] = m[i,self.N-1]+extra_space + return self._fmt_matrix( pre, m, post, add_height=add_height ) + + def mk_evecs_matrix( self, key, formater=str, mm=8,extra_space='', add_height=0 ): + pre, m, post = self._mk_evecs_matrix(key=key, formater=formater, mm=mm ) + sz = self.sz[0] if key == 'uvecs' else self.sz[1] + if m.shape[1] == sz: + for i in range(m.shape[0]): + m[i,0] = extra_space+m[i,0] + m[i,m.shape[1]-1]=m[i,m.shape[1]-1]+extra_space + + return self._fmt_matrix( pre, m, post, add_height ) + else: + return m + + def decorate_values(self, l, decorate, i=None ): + if i is not None: + l[i] = decorate( l[i] ) + else: + for i in range(0,len(l)): + l[i] = decorate(l[i]) + + def decorate_matrix(self, m, decorate, row=None, col=None ): + m = m.reshape( m.shape[0],-1 ) + rows = range( m.shape[0] ) if row is None else [ row ] + cols = range( m.shape[1] ) if col is None else [ col ] + for i in rows: + for j in cols: + m[i,j]=decorate( m[i,j]) + + def nm_latex_doc( self, formater=sym.latex, case="S", color='blue', + mmLambda=8, mmS=4, spaceLambda=r' \;\; ', spaceS=r' \;\; ', + fig_scale = None + ): + tbl_fmt = self._mk_table_format() + + # ------------------------------------------------------ values + def no_zeros(x): + if type(x) is str: + return '' if x=='0' else formater(x) + try: + return '' if x.is_zero else formater(x) + except: + return formater(x) + sigmas = self.mk_values('sigma', formater=no_zeros ) if case == 'SVD' else None + lambdas = self.mk_values('lambda', formater=formater) + mas = self.mk_values('ma', formater=formater) + + # ------------------------------------------------------ vectors + evecs = self.mk_vectors('evecs', formater=formater) + r' \\' + + qvecs = None + uvecs = None + + if case == 'Q': + qvecs = self.mk_vectors('qvecs', formater=formater, add_height=1) + r' \\' + elif case == 'SVD': + qvecs = self.mk_vectors('qvecs', formater=formater, add_height=1) + r' \\' + try: + uvecs = self.mk_vectors('uvecs', formater=formater, add_height=1) + r' \\' + except: + uvecs = None + + # ------------------------------------------------------ matrices + left_singular_matrix = None + + if case == 'SVD': + lambda_matrix = self.mk_diag_matrix( 'sigma', formater=formater, mm=mmLambda) + else: + try: + lambda_matrix = self.mk_diag_matrix( 'lambda', formater=formater, mm=mmLambda) + except: + lambda_matrix = None + + if case == 'S': + try: + evecs_matrix = self.mk_evecs_matrix( 'evecs', formater=formater, mm=mmS ) + except: + evecs_matrix = None + else: + evecs_matrix = self.mk_evecs_matrix( 'qvecs', formater=formater, mm=mmS ) + if case == 'SVD': + try: + left_singular_matrix = self.mk_evecs_matrix( 'uvecs', formater=formater, mm=mmS ) + except: + left_singular_matrix = None + + if case == 'S': matrix_names=[r'\Lambda', 'S'] + elif case == 'Q': matrix_names=[r'\Lambda', 'Q'] + else: matrix_names=[r'\Sigma', 'V', 'U'] + + # ------------------------------------------------------ figure scaling + if fig_scale is not None: + fig_scale = r'\scalebox{'+str(fig_scale)+'}{%' + + return jinja2.Template( EIGPROBLEM_TEMPLATE, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n', + fig_scale = fig_scale, + matrix_names = matrix_names, + table_format = tbl_fmt, color = '{'+color+'}', + rule_format = self.rule_fmt, + sigmas = sigmas, + lambdas = lambdas, + algebraic_multiplicities = mas, + eigenbasis = evecs, + orthonormal_basis = qvecs, + left_singular_matrix = left_singular_matrix, + lambda_matrix = lambda_matrix, + evecs_matrix = evecs_matrix + ) +# -------------------------------------------------------------------------------------------------- +def eig_tbl(A, normal=False, eig_digits=None,vec_digits=None): + A = _jl_to_py(A) + A = sym.Matrix(A) + eig = { + 'lambda': [], + 'ma': [], + 'evecs': [], + } + if normal: + eig['qvecs'] = [] + + res = A.eigenvects() + for e,m,vecs in res: + eig['lambda'].insert(0,e) + eig['ma'].insert(0,m) + eig['evecs'].insert(0,vecs) + if normal: + vvecs = _q_gram_schmidt( vecs ) + eig['qvecs'].insert(0, vvecs ) + + return EigenProblemTable( eig,eig_digits=eig_digits, vec_digits=vec_digits ) + +def show_eig_tbl(A, Ascale=None, normal=False, eig_digits=None, vec_digits=None, formater=sym.latex, mmS=10, mmLambda=8, fig_scale=1.0, color='blue', keep_file=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + E = eig_tbl(A, normal=normal, eig_digits=eig_digits,vec_digits=vec_digits) + if Ascale is not None: + E.eig[ 'lambda' ] = [ e/Ascale for e in E.eig[ 'lambda' ]] + + c = 'Q' if normal else 'S' + + svd_code = E.nm_latex_doc( formater=formater, case=c, mmS=mmS, mmLambda=mmLambda, fig_scale=fig_scale, color=color) + + h = itikz.fetch_or_compile_svg( + svd_code, prefix='svd_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h +# -------------------------------------------------------------------------------------------------- +def svd_tbl(A, Ascale=None, eig_digits=None, sigma_digits=None, vec_digits=None): + A = _jl_to_py(A) + A = sym.Matrix(A) + eig = { + 'sigma': [], + 'lambda': [], + 'ma': [], + 'evecs': [], + 'qvecs': [], + 'uvecs': [] + } + def mySVD(A): + A = sym.Matrix(A) + + def sort_eig_vec(sym_eig_vec): + sort_eig_vecs = sorted(sym_eig_vec, key=lambda x: x[0], reverse=True) + + for i in sort_eig_vecs: + e = i[0] if Ascale is None else i[0] / (Ascale*Ascale) + sigma = sym.sqrt(e) + eig['sigma'].append(sigma) + + eig['lambda'].append( e ) + eig['ma'].append( i[1] ) + eig['evecs'].append( i[2] ) + vvecs = _q_gram_schmidt( i[2] ) + eig['qvecs'].append( vvecs ) + + if not sigma.is_zero: + s_inv = 1/sigma if Ascale is None else 1/(sigma*Ascale) + eig['uvecs'].append( [ s_inv * A * v for v in vvecs] ) + + sort_eig_vec((A.transpose() * A).eigenvects()) + ns = A.transpose().nullspace() + if len(ns) > 0: + ns_on_basis = _q_gram_schmidt( ns ) + eig['uvecs'].append( ns_on_basis ) + + mySVD(A) + return EigenProblemTable( eig, sz=A.shape, eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits ) + +def show_svd_table(A, Ascale=None, eig_digits=None, sigma_digits=None, vec_digits=None, + formater=sym.latex, mmS=10, mmLambda=8, fig_scale=1.0, color='blue', keep_file=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + E = svd_tbl(A, Ascale=Ascale, eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits) + svd_code = E.nm_latex_doc( formater=formater, case='SVD', mmS=mmS, mmLambda=mmLambda, fig_scale=fig_scale, color=color) + + h = itikz.fetch_or_compile_svg( + svd_code, prefix='svd_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h +# ================================================================================================== +def html_string(txt,sz=20,color="darkred",justify="left",height="15"): + return HTML(f"""
+ + ${txt} +
""") +# -------------------------------------------------------------------------------------------------- +def html_strings(txt1,txt2,sz1=20,sz2=20,color="darkred",justify="left",height="15"): + return HTML("""
+${txt1}
+${txt2}
+
""") + + +#def foo(x): +# print( "foo input: ", x) +# if x is None: +# print( "None == ", None) +# if x is not None: +# print( "not None != ", None) diff --git a/itikz/nicematrix_dev.py b/itikz/nicematrix_dev.py new file mode 100644 index 0000000..c50fbed --- /dev/null +++ b/itikz/nicematrix_dev.py @@ -0,0 +1,1814 @@ +import numpy as np +import sympy as sym +import jinja2 +import itikz +from IPython.core.display import SVG +from IPython.core.display import HTML + +# ================================================================================================================================ +from collections.abc import Sequence +from collections.abc import Iterable + +# ================================================================================================================================ +# helper functions to convert PythonCall structures +# ================================================================================================================================ +def _is_julia_obj(x): + mod = type(x).__module__ + return mod.startswith("juliacall") or mod.startswith("PythonCall") + +def _jl_to_py(x): + """ + Convert PythonCall Julia containers to pure Python containers, + preserving the nested structure, but ensuring that Julia MATRICES + become 2-D numpy arrays. + """ + if x is None: + return None + + # If it's a Julia object coming from PythonCall/Juliacall… + if _is_julia_obj(x): + sh = getattr(x, "shape", None) + + # Julia matrix => force 2-D numpy array + if sh is not None and hasattr(sh, "__len__") and len(sh) == 2: + return np.array(x, dtype=object) + + # Julia vector / nested container => recurse into Python list + try: + return [_jl_to_py(e) for e in x] + except TypeError: + # scalar Julia value + return x + + # Pure Python containers => recurse + if isinstance(x, list): + return [_jl_to_py(e) for e in x] + if isinstance(x, tuple): + return tuple(_jl_to_py(e) for e in x) + + # numpy arrays and scalars => leave as-is + return x + +# ================================================================================================================================ +extension = r''' ''' +# ----------------------------------------------------------------- +preamble = r''' ''' +# ================================================================= +BACKSUBST_TEMPLATE = r'''\documentclass[notitlepage,table,svgnames]{article} +\pagestyle{empty} +\usepackage[margin=0cm,paperwidth=90in]{geometry} +\usepackage{mathtools} +\usepackage{amssymb} +\usepackage{cascade} +\usepackage{systeme} +\usepackage{nicematrix} + +\begin{document}\begin{minipage}{\textwidth} +{%% if fig_scale %%} +\scalebox{ {{fig_scale}} }{% +{%% endif %%} +% ---------------------------------------------------------------------------------------- +{{preamble}}% +%==================================================================== +{%% if show_system %%} +{{system_txt}} +{%% endif %%} +%==================================================================== +{%% if show_cascade %%} +{%% if show_system %%} +\vspace{1cm} + +{%% endif %%} +{%% for line in cascade_txt -%%} +{{line}} +{%% endfor -%%} +{%% endif %%} +%==================================================================== +{%% if show_solution %%} +{%% if show_system or show_cascade %%} +\vspace{1cm} + +{%% endif %%} +{{solution_txt}} +{%% endif %%} +%==================================================================== +{%% if fig_scale %%} +} +{%% endif %%} +\end{minipage}\end{document} +''' +# ================================================================= +EIGPROBLEM_TEMPLATE = r'''\documentclass[notitlepage,table,svgnames]{article} +\pagestyle{empty} +\usepackage{booktabs} +\usepackage{mathtools} +\usepackage{nicematrix} +\usepackage{xcolor} + +\begin{document}\begin{minipage}{\textwidth} +{%% if fig_scale %%} +{{fig_scale}} +{%% endif %%} +% ---------------------------------------------------------------------------------------- +{{preamble}}% +%========================================================================================= +\begin{tabular}{{table_format}} \toprule +{%% if sigmas %%}% sigma ----------------------------------------------------------------- +$\color{{color}}{\sigma}$ & {{sigmas}} {{rule_format}} +{%% endif %%}% lambda -------------------------------------------------------------------- +$\color{{color}}{\lambda}$ & {{lambdas}} {{rule_format}} +$\color{{color}}{m_a}$ & {{algebraic_multiplicities}} {{rule_format}} \addlinespace[1mm] +% eigenvectors -------------------------------------------------------------------------- +{\parbox{2cm}{\textcolor{{color}}{basis for $\color{{color}}{E_\lambda}$}}} & +{{eigenbasis}} {%% if orthonormal_basis %%} +% orthonormal eigenvectors -------------------------------------------------------------- + {{rule_format}} \addlinespace[2mm] +{\parbox{2cm}{\textcolor{{color}}{orthonormal basis for $E_\lambda$}}} & +{{orthonormal_basis}} +{%% endif -%%} + \addlinespace[2mm] \midrule \addlinespace[2mm] +% ------------------------------------------------------------- lambda +$\color{{color}}{ {{matrix_names[0]}} =}$ & {{lambda_matrix}} \\ \addlinespace[2mm] +% ------------------------------------------------------------- E or Q +{%% if evecs_matrix %%}% +$\color{{color}}{ {{matrix_names[1]}} = }$ & {{evecs_matrix}} \\ \addlinespace[2mm] %\bottomrule +{%% endif -%%} +% ------------------------------------------------------------- U +{%% if left_singular_matrix %%}% +$\color{{color}}{ {{matrix_names[2]}} = }$ & {{left_singular_matrix}} \\ \addlinespace[2mm] \bottomrule +{%% endif -%%} +\end{tabular} +{%% if fig_scale %%} +} +{%% endif %%} +\end{minipage}\end{document} +''' +# ================================================================= +GE_TEMPLATE = r'''\documentclass[notitlepage]{article} +\pagestyle{empty} +\usepackage[margin=0cm,paperwidth=90in]{geometry} + +\usepackage{mathtools} +\usepackage{xltxtra} +\usepackage{pdflscape} +\usepackage{graphicx} +\usepackage[table,svgnames]{xcolor} +\usepackage{nicematrix,tikz} +\usetikzlibrary{calc,fit,decorations.markings} + +\newcommand*{\colorboxed}{} +\def\colorboxed#1#{% + \colorboxedAux{#1}% +} +\newcommand*{\colorboxedAux}[3]{% + % #1: optional argument for color model + % #2: color specification + % #3: formula + \begingroup + \colorlet{cb@saved}{.}% + \color#1{#2}% + \boxed{% + \color{cb@saved}% + #3% + }% + \endgroup +} + +% ---------------------------------------------------------------------------- extension +{{extension}} +\begin{document}\begin{minipage}{\textwidth} +\begin{landscape} +{%% if fig_scale %%} +{{fig_scale}} +{%% endif %%} +% ---------------------------------------------------------------------------- preamble +{{preamble}}% +% ============================================================================ NiceArray +$\begin{NiceArray}[vlines-in-sub-matrix = I]{{mat_format}}{{mat_options}}% +{%% if codebefore != [] -%%} +\CodeBefore [create-cell-nodes] + {%% for entry in codebefore: -%%} + {{entry}} + {%% endfor -%%}% +\Body +{%% endif -%%} +{{mat_rep}} +\CodeAfter %[ sub-matrix / extra-height=2mm, sub-matrix / xshift=2mm ] +% --------------------------------------------------------------------------- submatrix delimiters + {%% for loc in submatrix_locs: -%%} + \SubMatrix({{loc[1]}})[{{loc[0]}}] + {%% endfor -%%} + {%% for txt in submatrix_names: -%%} + {{txt}} + {%% endfor -%%} +% --------------------------------------------------------------------------- pivot outlines +\begin{tikzpicture} + \begin{scope}[every node/.style = draw] + {%% for loc in pivot_locs: -%%} + \node [draw,{{loc[1]}},fit = {{loc[0]}}] {} ; + {%% endfor -%%} + \end{scope} +% +% --------------------------------------------------------------------------- explanatory text + {%% for loc,txt,c in txt_with_locs: -%%} + \node [right,align=left,color={{c}}] at {{loc}} {\qquad {{txt}} } ; + {%% endfor -%%} +% +% --------------------------------------------------------------------------- row echelon form path + {%% for t in rowechelon_paths %%} {{t}} + {%% endfor -%%} +\end{tikzpicture} +\end{NiceArray}$ +{%% if fig_scale %%} +} +{%% endif %%} +\end{landscape} +\end{minipage}\end{document} +''' +# ================================================================================================================================ +def convert_tuple_array_to_rationals(A): + '''overcome the limitations of the PyCall interface: convert integer tuples to rationals''' + A = _jl_to_py(A) + return sym.Matrix( [[sym.Rational(num, denom) for num, denom in row] for row in A] ) + +def convert_tuple_list_to_rationals(A): + '''overcome the limitations of the PyCall interface: convert integer tuples to rationals''' + A = _jl_to_py(A) + return sym.Matrix( [sym.Rational(num, denom) for num, denom in A] ) + +def convert_to_sympy_matrix(A): + if A is None: return None + A = _jl_to_py(A) + if isinstance( A, list): + if isinstance( A[0], list): + if isinstance(A[0][0], tuple ): # list of list of tuples + A = convert_tuple_array_to_rationals(A) + else: # list of list of values + A = sym.Matrix(A) + else: # just a list + if isinstance(A[0], tuple ): # list of tuples + A = convert_tuple_list_to_rationals(A) + else: + A = sym.Matrix(A) + else: # not a list; should be matrix + A = sym.Matrix(A) + return A +# ================================================================================================================================ +def to_str(x, digits=3): + """ + Convert the input into a string representation. + + Parameters: + - `x`: The input value. Can be an integer, float, complex number, or a SymPy expression. + + Returns: + - A string representation of `x`. + """ + + # Check for integers + if isinstance(x, int): + return str(x) + + # Check for floats + elif isinstance(x, float): + return str(round(x, digits)) + + # Check for complex numbers + elif isinstance(x, complex): + real_part = round(x.real, digits) + imag_part = round(x.imag, digits) + + # Handle purely real or purely imaginary numbers + if imag_part == 0: + return str(real_part) + elif real_part == 0: + return f"{imag_part}i" + elif imag_part > 0: + return f"{real_part} + {imag_part}i" + else: + return f"{real_part} - {abs(imag_part)}i" + + # Check for SymPy expressions + elif isinstance(x, sym.Expr): + return str(x.evalf(digits)) + + # For any other type that is a number + elif isinstance(x, (bool,)): + return str(int(x)) # Since bool is a subclass of int in Python + + else: + return str(x) + +# ================================================================================================================================ +# Index Computations and formating associated with Matrices laid out on a grid. +# ================================================================================================================================ +class MatrixGridLayout: + ''' Basic Computations of the Matrix Grid Layout and the resulting Tex Representation + Indexing is zero-based. + + The matrices are first written into an array, with an associated format string: + array_format_string_list() + array_of_tex_entries() + decorate_tex_entries() + Each array row is converted to a string + tex_repr + The display is further enhanced by adding + nm_add_option + nm_submatrix_locs + ''' + + def __init__(self, matrices, extra_cols=None, extra_rows = None ): + '''save the matrices, determine the matrix grid dimensions and the number of rows in the first row of the grid + Note that the number of cols in the first grid row and/or the number of rows in the first grid col can be ragged + ''' + # Fix up matrices + if not isinstance( matrices, list): # allow using this class for a single matrix [[None, A]] + matrices = [[ None, matrices ]] + + self.matrices = [] + cnt_layers = 0 + for (i,layer) in enumerate(matrices): # ensure the matrices are not passed as lists + cnt_layers += 1 + l = [] + for (j,mat) in enumerate(layer): + if isinstance( mat, list ): + l.append( np.array(mat) ) + else: + l.append( mat ) + self.matrices.append(l) + + self.nGridRows = cnt_layers # len(self.matrices) + self.nGridCols = max(len(row) for row in self.matrices) + + + self._set_shapes() + self.array_names = [] + + self.mat_row_height = [ max(map( lambda s: s[0], self.array_shape[i, :])) for i in range(self.nGridRows)] + self.mat_col_width = [ max(map( lambda s: s[1], self.array_shape[:, j])) for j in range(self.nGridCols)] + + self.adjust_positions( extra_cols, extra_rows ) + self.txt_with_locs = [] + self.rowechelon_paths = [] + self.codebefore = [] + self.preamble = '\n' + r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n' + self.extension = '%\n' + + def adjust_positions( self, extra_cols=None, extra_rows=None ): + '''insert extra rows and cols between matrices''' + self.extra_cols = MatrixGridLayout._set_extra( extra_cols, self.nGridCols ) + self.extra_rows = MatrixGridLayout._set_extra( extra_rows, self.nGridRows ) + + self.cs_extra_cols = np.cumsum( self.extra_cols ) + self.cs_extra_rows = np.cumsum( self.extra_rows ) + + self.cs_mat_row_height = np.cumsum( np.hstack([[0], self.mat_row_height])) + self.cs_mat_col_width = np.cumsum( np.hstack([[0], self.mat_col_width ])) + + self.tex_shape = (self.cs_mat_row_height[-1]+self.cs_extra_rows[-1], + self.cs_mat_col_width [-1]+self.cs_extra_cols[-1]) + + def _set_shapes(self): + '''compute the shapes of the arrays in the grid, obtain the maximal number of rows/cols''' + self.array_shape = np.empty((self.nGridRows, self.nGridCols), tuple) + for i in range(self.nGridRows): + row = self.matrices[i] + row_len = len(row) + for j in range(self.nGridCols): + if j < row_len and row[j] is not None: + # Check if it's actually a matrix/array with .shape attribute + try: + self.array_shape[i, j] = row[j].shape + except (AttributeError, TypeError): + # Not a matrix (could be wrapped symbol from PythonCall) + self.array_shape[i, j] = (0, 0) + else: + self.array_shape[i, j] = (0, 0) + + if self.nGridRows > 1: + self.n_Col_0 = [s[1] for s in self.array_shape[1:, 0]] + else: + self.n_Col_0 = [] + + if self.nGridCols > 1: + self.m_Row_0 = [s[0] for s in self.array_shape[0, 1:]] + else: + self.m_Row_0 = [] + + @staticmethod + def _set_extra( extra, n ): + if isinstance(extra, int): + extra = np.hstack([ np.repeat( 0, n), [extra] ]) + elif extra is None: + extra = np.repeat( 0, n+1 ) + else: + assert( len(extra) == (n+1)) + return extra + + def describe(self): + #self.grid_shape = [len(self.mat_row_height), len(self.mat_col_width)] + # = [self.nGridRows, self.nCOLMats] + + print( f"Layout {self.nGridRows} x {self.nGridCols} grid:") + + print( f". insert extra_cols: {self.extra_cols}") + print( f". col_start = {self.cs_mat_col_width + self.cs_extra_cols}") + print( f". row_start = {self.cs_mat_row_height + self.cs_extra_rows}") + print() + + print( "Consistent Matrix Sizes in the grid") + for i in self.mat_row_height: + for j in self.mat_col_width: + print( f' {(i,j)}', end='') + print() + + print("Actual TopLeft:BottomRight Indices") + for i in range(self.nGridRows): + for j in range(self.nGridCols): + tl,br,_ = self._top_left_bottom_right(i,j) + print( f' {tl}:{br}', end='') + print() + + def element_indices( self, i,j, gM, gN ): + '''return the actual indices of element (i,j) in the matrix at grid position (gM,gN)''' + last_row = self.cs_mat_row_height[gM+1] + self.cs_extra_rows[gM] + last_col = self.cs_mat_col_width [gN+1] + self.cs_extra_cols[gN] + + A_shape = self.array_shape[gM][gN] + return (last_row - (A_shape[0] -i), + last_col - (A_shape[1] - j) + ) + + def _top_left_bottom_right( self, gM, gN ): + ''' given the grid position obtain the actual indices of the top left corner for the matrix''' + A_shape = self.array_shape[gM,gN] + + row_offset = self.cs_extra_rows[gM]+self.cs_mat_row_height[gM]+self.mat_row_height[gM]-A_shape[0] + col_offset = self.cs_extra_cols[gN]+self.cs_mat_col_width [gN]+self.mat_col_width [gN]-A_shape[1] + return (row_offset, col_offset), \ + (row_offset+A_shape[0]-1, col_offset+A_shape[1]-1), \ + A_shape + + #def tex_repr( self, blockseps = r' \noalign{\vskip2mm} '): + def tex_repr( self, blockseps = r'[2mm]'): + '''Create a list of strings from the array of TeX strings, one for each line in the grid ready to print in the LaTeX document''' + self.tex_list =[' & '.join( self.a_tex[k,:]) for k in range(self.a_tex.shape[0])] + for i in range( len(self.tex_list) -1): + self.tex_list[i] += r' \\' + + for i in (self.cs_mat_row_height[1:-1] + self.cs_extra_rows[1:-1] - self.extra_rows[1:-1]): + self.tex_list[i-1] += blockseps + + if self.extra_rows[-1] != 0: # if there are final extra rows, we need another sep + self.tex_list[ self.tex_shape[0] - self.extra_rows[-1] - 1] += blockseps + + def array_of_tex_entries(self, formater=str): + '''Create a matrix of TeX strings from the grid entries''' + + a_tex = np.full( self.tex_shape,"", dtype=object) + + for i in range(self.nGridRows): + for j in range(self.nGridCols): + tl,br,shape = self._top_left_bottom_right(i,j) + A = self.matrices[i][j] + for ia in range( shape[0]): + for ja in range(shape[1]): + a_tex[ tl[0]+ia, tl[1]+ja ] = formater( A[ia,ja]) + self.a_tex = a_tex + + def decorate_tex_entries( self, gM, gN, decorate, entries=None): + '''apply decorate to the list of i,j TeX entries to grid matrix at (gM,gN)''' + try: # avoid writing code for A == None case + tl,br,shape = self._top_left_bottom_right(gM,gN) + + if entries is None: + for i in range(shape[0]): + for j in range(shape[1]): + self.a_tex[tl[0]+i, tl[1]+j] = decorate(self.a_tex[tl[0]+i, tl[1]+j]) + else: + for (i,j) in entries: + self.a_tex[tl[0]+i, tl[1]+j] = decorate(self.a_tex[tl[0]+i, tl[1]+j]) + except: + pass + + @staticmethod + def matrix_array_format( N, p_str='I', vpartitions=None): + '''format string for a matrix with N columns''' + if vpartitions is None: + return N*"r" + #return f"*{N}r" + s = "" + cur = 0 + for p in vpartitions: + s_r = (p-cur)*"r" + s += f"{s_r}{p_str}" + #s += f"*{p-cur}r{p_str}" + cur = p + if cur < N: + s += (N-cur)*"r" + #s += f"*{N-cur}r" + return s + + #def array_format_string_list( self, partitions={}, spacer_string=r'@{\qquad\ }', p_str='I', last_col_format = "l@{\qquad\;\;}") : + def array_format_string_list( self, partitions={}, spacer_string=r'@{\hspace{9mm}}', + p_str='I', last_col_format=r'l@{\hspace{2cm}}' ): + '''Construct the format string. Partitions is a dict { gridcolumn: list of partitions}''' + + for i in range(self.nGridCols): # make sure we have a partion entry for each column of matrices + if i not in partitions: + partitions[i]=None + + # format for initial extra cols + l = self.extra_cols[0] + fmt = l*'r' + + last = self.nGridCols - 1 + for i in range(self.nGridCols): + # we now iterate over (matrix, extra) pairs + # ----------- matrix ----------------------- + N = self.mat_col_width[i] + fmt += spacer_string + MatrixGridLayout.matrix_array_format( N, p_str=p_str, vpartitions=partitions[i] ) + + # ------------ spacer ---------------------- + l = self.extra_cols[i+1] + if l > 0: + if i == last: + if l > 1: + fmt += spacer_string + (l-1)*'r'+last_col_format + else: + fmt += spacer_string + last_col_format + else: + fmt += spacer_string + l*'r' + + self.format = fmt + + def tl_shape_below( self, gM, gN ): + '''obtain tl and shape of free space below grid matrix at (gM, gN)''' + tl,br,_ = self._top_left_bottom_right( gM, gN ) + free_tl = (br[0]+1, tl[1]) + shape = (self.tex_shape[0]-free_tl[0], self.tex_shape[1] - tl[1]) + return free_tl, shape + + def tl_shape_above( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,br,_ = self._top_left_bottom_right( gM, gN ) + free_tl = (tl[0]-self.extra_rows[gM], tl[1]) + shape = (self.extra_rows[gM], self.tex_shape[1]-free_tl[1]) + return free_tl, shape + + def tl_shape_left( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,_,_ = self._top_left_bottom_right( gM, gN ) + return (tl[0],tl[1]-self.extra_cols[gN]), \ + (self.tex_shape[0]-tl[0],self.extra_cols[gN]) + + def tl_shape_right( self, gM, gN ): + '''obtain tl and shape of free space above grid matrix at (gM, gN)''' + tl,_,shape = self._top_left_bottom_right( gM, gN ) + return (tl[0],tl[1]+shape[1]), \ + (self.tex_shape[0]-tl[0],self.extra_cols[gN+1]) + + def add_row_above( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_above( gM, gN ) + for (j,v) in enumerate(m): + self.a_tex[tl[0]+offset, tl[1]+j] = formater( v ) + + def add_row_below( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_below( gM, gN ) + for (j,v) in enumerate(m): + self.a_tex[tl[0]+offset, tl[1]+j] = formater( v ) + + def add_col_right( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_right( gM, gN ) + for (i,v) in enumerate(m): + self.a_tex[tl[0]+i, tl[1]+offset] = formater( v ) + + def add_col_left( self, gM, gN, m, formater=str, offset=0 ): + '''add tex entries to the tex array''' + tl,shape = self.tl_shape_left( gM, gN ) + for (i,v) in enumerate(m): + self.a_tex[tl[0]+i, tl[1]+offset-1] = formater( v ) + + def nm_submatrix_locs(self, name='A', color='blue', name_specs=None, line_specs=None ): + '''nicematrix style location descriptors of the submatrices''' + # name_specs = [ spec*]; spec = [ (gM, gN), position, text ] + # line_specs = [ spec*]; spec = [ (gM, gN), h_lines, vlines ] + self.submatrix_name = name + smat_args = np.full( (self.nGridRows,self.nGridCols),"", dtype=object) + if line_specs is not None: + for pos,h_lines,v_lines in line_specs: + if h_lines is not None: + if isinstance( h_lines, int): + smat_args[pos] = f',hlines={h_lines}' + else: + smat_args[pos] = ',hlines={'+ ','.join([str(s) for s in h_lines]) + '}' + if v_lines is not None: + if isinstance( v_lines, int): + smat_args[pos] += f',vlines={v_lines}' + else: + smat_args[pos] += ',vlines={'+ ','.join([str(s) for s in v_lines]) + '}' + + locs = [] + for i in range(self.nGridRows): + for j in range(self.nGridCols): + if self.array_shape[i,j][0] != 0: + tl,br,_ = self._top_left_bottom_right(i,j) + smat_arg = f"name={name}{i}x{j}"+smat_args[i,j] + locs.append( [ smat_arg, f"{{{tl[0]+1}-{tl[1]+1}}}{{{br[0]+1}-{br[1]+1}}}"] ) + + self.locs = locs + + if name_specs is not None: + array_names = [] + ar=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north east) + (0.02,0.02) $) -- +(0.6cm,0.3cm) node[COLOR, above right=-3pt]{TXT};".replace('COLOR',color) + al=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north west) + (-0.02,0.02) $) -- +(-0.6cm,0.3cm) node[COLOR, above left=-3pt] {TXT};".replace('COLOR',color) + a =r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.north) + (0,0) $) -- +(0cm,0.6cm) node[COLOR, above=1pt] {TXT};".replace('COLOR',color) + + bl=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south west) + (-0.02,-0.02) $) -- +(-0.6cm,-0.3cm) node[COLOR, below left=-3pt]{TXT};".replace('COLOR',color) + br=r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south east) + (0.02,-0.02) $) -- +(0.6cm,-0.3cm) node[COLOR, below right=-3pt]{TXT};".replace('COLOR',color) + b =r"\tikz \draw[<-,>=stealth,COLOR,thick] ($ (NAME.south) + (0,0) $) -- +(0cm,-0.6cm) node[COLOR, below=1pt] {TXT};".replace('COLOR',color) + + for (gM,gN),pos,txt in name_specs: + nm = f"{name}{gM}x{gN}" + t = None + if pos == 'a': t = a.replace('NAME',nm).replace('TXT',txt) + elif pos == 'al': t = al.replace('NAME',nm).replace('TXT',txt) + elif pos == 'ar': t = ar.replace('NAME',nm).replace('TXT',txt) + elif pos == 'b': t = b.replace('NAME',nm).replace('TXT',txt) + elif pos == 'bl': t = bl.replace('NAME',nm).replace('TXT',txt) + elif pos == 'br': t = br.replace('NAME',nm).replace('TXT',txt) + if t is not None: + array_names.append( t ) + + self.array_names = array_names + + def nm_background(self, gM,gN, loc_list, color='red!15', pt=0): + '''add background color to a list of entries''' + tl,_,_ = self._top_left_bottom_right( gM, gN ) + for entry in loc_list: + cmd_1 = f'\\tikz \\node [fill={color}, inner sep = {pt}pt, fit = ' + if not isinstance( entry, list): + cmd_2 = f'({tl[0]+entry[0]+1}-{tl[1]+entry[1]+1}-medium)' + else: + cmd_2 = f'({tl[0]+entry[0][0]+1}-{tl[1]+entry[0][1]+1}-medium) ({tl[0]+entry[1][0]+1}-{tl[1]+entry[1][1]+1}-medium)' + cmd_3 = ' ] {} ;' + self.codebefore.append( cmd_1 + cmd_2 + cmd_3 ) + + + def nm_text(self, txt_list, color='violet'): + '''add text add each layer (requires a right-most extra col)''' + assert( self.extra_cols[-1] != 0 ) + + # find the indices of the first row in the last col (+1 for nicematrix indexing) + txt_with_locs = [] + for (g,txt) in enumerate(txt_list): + A_shape = self.array_shape[g][self.nGridCols-1] + + first_row = self.cs_mat_row_height[g] + self.cs_extra_rows[g] + (self.mat_row_height[g] - A_shape[0])+1 + txt_with_locs.append(( f'({first_row}-{self.tex_shape[1]-1}.east)', txt, color) ) + self.txt_with_locs = txt_with_locs + + def nm_add_rowechelon_path( self, gM,gN, pivots, case='hh', color='violet,line width=0.4mm', adj=0.1 ): + tl,_,shape = self._top_left_bottom_right( gM, gN ) + + def coords(i,j): + if i >= shape[0]: + if gN == 0 and j == 0: # HACK alert: first col in leftmost matrix! + x = r'\x1' + else: + x = r'\x2' if j >= shape[1] else r'\x4' + #x = r'\x2' if j >= shape[1] else r'\x1' + y = r'\y2' + p = f'({x},{y})' + elif j >= shape[1]: + x = r'\x2' if i >= shape[0] else r'\x2' + y = r'\y4' + p = f'({x},{y})' + elif j == 0: + x = r'\x1' + y = r'\y1' if i == 0 else r'\y3' + p = f'({x},{y})' + else: + x = f'{i+1+tl[0]}' + y = f'{j+1+tl[1]}' + p = f'({x}-|{y})' + + if j != 0 and j < shape[1] and adj != 0: + p = f'($ {p} + ({adj:2},0) $)' + + return p + + cur = pivots[0] + ll = [cur] if (case == 'vv') or (case == 'vh') else [] + for nxt in pivots[1:]: # at top right + if cur[0] != nxt[0]: # down 1 + cur = (cur[0]+1, cur[1]) + ll.append( cur ) + if nxt[1] != cur[1]: # over + cur = (cur[0], nxt[1]) + ll.append( cur ) + if cur != nxt: + ll.append(nxt) # down to top right + cur = nxt + + if len(ll) == 0 and case == 'hv': + ll = [ (pivots[0][0]+1,pivots[0][0] ), (shape[0], pivots[0][1] )] + + if (case == 'hh') or (case == 'vh'): + if cur[0] != shape[0]: # down 1 + cur = (cur[0]+1, cur[1]) + ll.append( cur ) + ll.append( (cur[0], shape[1])) # over to right + else: + ll.append( (shape[0], cur[1])) # down to bottom + + corners = f'let \\p1 = ({self.submatrix_name}{gM}x{gN}.north west), \\p2 = ({self.submatrix_name}{gM}x{gN}.south east), ' + + if (case == 'vv') or (case == 'vh'): + p3 = f'\\p3 = ({ll[1][0]+tl[0]+1}-|{ll[1][1]+tl[1]+1}), ' + else: + p3 = f'\\p3 = ({ll[0][0]+tl[0]+1}-|{ll[0][1]+tl[1]+1}), ' + + if (case=='vh') or (case=='hh'): # last dir: -> + i,j = ll[-2] + p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + else: # last dir: | + i,j = ll[-1] + #if len(pivots) == 1 and cur[0] == 0 and gN == 0: # was this my previous "FIX"??? + # p4 = f'\\p4 = ({self.submatrix_name}{gM}x{gN}.south west) in ' + #else: + # p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + p4 = f'\\p4 = ({i+tl[0]+1}-|{j+tl[1]+1}) in ' + + cmd = '\\tikz \\draw['+color+'] ' + corners + p3 + p4 + ' -- '.join( [coords(*p) for p in ll] ) + ';' + self.rowechelon_paths.append( cmd ) + + def apply( self, func, *args, **kwargs ): + func( self, *args, **kwargs ) + + def nm_latexdoc( self, template = GE_TEMPLATE, fig_scale=None ): + if fig_scale is not None: + fig_scale = r'\scalebox{'+str(fig_scale)+'}{%' + return jinja2.Template( template, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = self.preamble, + fig_scale = fig_scale, + extension = self.extension, + mat_rep = '\n'.join( self.tex_list ), + mat_format = '{'+self.format+'}', + mat_options = '[create-extra-nodes,create-medium-nodes]', + submatrix_locs = self.locs, + submatrix_names = self.array_names, + pivot_locs = [], + txt_with_locs = self.txt_with_locs, + rowechelon_paths= self.rowechelon_paths, + codebefore = self.codebefore, + ) +# ----------------------------------------------------------------------------------------------------- +def make_decorator( text_color='black', bg_color=None, text_bg=None, boxed=None, box_color=None, bf=None, move_right=False, delim=None ): + '''decorate terms: + text_color : apply text color, default = 'black' + text_bg : apply background color, default = None + boxed : put a box around the entry, default = False (None) + box_color: put a colored box around the entry, default = False (None) + bf : make the entry boldface, default = False (None) + move_right : apply \\mathrlap, default = False (None) + delim : put delimiter around text, default = None, e.g., surround with in '$' + ''' + box_decorator = "\\boxed<{a}>" + coloredbox_decorator = "\\colorboxed<{color}><{a}>" + color_decorator = "\\Block[draw={text_color},fill={bg_color}]<><{a}>" + txt_color_decorator = "\\color<{color}><{a}>" + bg_color_decorator = "\\colorbox<{color}><{a}>" + bf_decorator = "\\mathbf<{a}>" + rlap_decorator = "\\mathrlap<{a}>" + delim_decorator = "<{delim}{a}{delim}>" + + x = '{a}' + if bf is not None: + x = bf_decorator.format(a=x) + if boxed is not None: + x = box_decorator.format( a=x ) + if box_color is not None: + x = coloredbox_decorator.format( a=x, color=box_color ) + if bg_color is not None: + x = bg_color_decorator.format(a=x, color=bg_color) + if text_bg is not None: + x = color_decorator.format(a=x, text_color= text_color, bg_color=text_bg) + elif text_color != 'black': + x = txt_color_decorator.format( color=text_color, a=x) + + if move_right: + x = rlap_decorator.format(a=x) + if delim is not None: + x = delim_decorator.format( delim=delim, a=x ) + + x = x.replace('<','{{').replace('>','}}') + + return lambda a: x.format(a=a) + +# ================================================================================================================================ +def str_rep_from_mat( A, formater=str): + '''str_rep_from_mat( A, formater=str) + convert matrix A to a string using formater + ''' + A = _jl_to_py(A) + + M,N=A.shape + return np.array( [[formater(A[i,j]) for j in range(N)] for i in range(M)] ) + +def str_rep_from_mats( A, b, formater=str ): + '''str_rep_from_mats( A, b, formater=str) + convert matrix A and vector b to a string using formater, return the augmented matrix + ''' + A = _jl_to_py(A) + b = _jl_to_py(b) + sA = str_rep_from_mat(A, formater) + sb = np.array(b).reshape(-1,1) + return np.hstack( [sA, sb] ) +# ================================================================================================================================ +def mk_ge_names(n, lhs='E', rhs=['A','b'], start_index=1 ): + '''utility to generate array names for ge''' + names = np.full( shape=(n,2),fill_value='', dtype=object) + + def pe(i): + if start_index is None: + return ' '.join([f' {lhs}' for k in range(i,0,-1)]) + else: + return ' '.join([f' {lhs}_{k+start_index-1}' for k in range(i,0,-1)]) + def pa(e_prod,i): + if i > 0 and rhs[-1] == 'I': + rhs[-1] = '' + return r' \mid '.join( [e_prod+' '+k for k in rhs ]) + + for i in range(n): + if start_index is None: + names[i,0] = f'{lhs}' + else: + names[i,0] = f'{lhs}_{start_index+i-1}' + + e_prod = pe(i) + names[i,1] = pa(e_prod,i) + + if len(rhs) > 1: + for i in range(n): + names[i,1] = r'\left( '+ names[i,1] + r' \right)' + + for i in range(n): + for j in range(2): + names[i,j] = r'\mathbf{ ' + names[i,j] + ' }' + + terms = [ [(0,1),'ar', '$' + names[0,1] + '$']] + for i in range(1,n): + terms.append( [(i,0), 'al', '$' + names[i,0] + '$']) + terms.append( [(i,1), 'ar', '$' + names[i,1] + '$']) + return terms +# -------------------------------------------------------------------------------------------------------------------------------- +def _ge( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0], [E1, A1], [E2, A2], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] where pt is the inner separation, e.g. 0 + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I']] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + extra_cols = None if comment_list is None else 1 + extra_rows = None if variable_summary is None else 2 + + m = MatrixGridLayout(matrices, extra_rows=extra_rows, extra_cols = extra_cols ) + + # compute the format spec for the arrays and set up the entries (defaults to a single partition line) + if isinstance( Nrhs, np.ndarray ): # julia passes arrays rather than lists :-() + Nrhs = list(Nrhs.flatten()) + + if not isinstance( Nrhs, list): + partitions = {} if Nrhs == 0 else { 1: [m.mat_col_width[-1]-Nrhs]} + else: + nrhs = Nrhs.copy() # partitions just specifies each col + cuts = [m.mat_col_width[-1] - sum(nrhs)] # cut after the main matrix + for cut in nrhs[0:-1]: # we don't need a cut at the end of the matrix + cuts.append( cuts[-1]+cut ) # cut location is cut cols from previous cut + partitions = { 1: cuts} + + m.array_format_string_list( partitions=partitions ) + m.array_of_tex_entries(formater=formater) # could overwride the entry to TeX string conversion here + + if pivot_list is not None: + red_box = make_decorator( text_color=pivot_text_color, boxed=True, bf=True ) + for spec in pivot_list: + m.decorate_tex_entries( *spec[0], red_box, entries=spec[1] ) + + if func is not None: + m.apply( func ) + + if comment_list is not None: + m.nm_text( comment_list ) + + if variable_summary is not None: + blue = make_decorator(text_color=variable_colors[1], bf=True) + red = make_decorator(text_color=variable_colors[0], bf=True) + typ = [] + var = [] + for (i,basic) in enumerate(variable_summary): + if basic is True: + typ.append(red(r'\Uparrow')) + var.append(red( f'x_{i+1}')) + elif basic is False: + typ.append(blue(r'\uparrow')) + var.append(blue( f'x_{i+1}')) + else: + typ.append(blue('')) + var.append(blue('')) + m.add_row_below(m.nGridRows-1,1,typ, formater=lambda a: a ) + m.add_row_below(m.nGridRows-1,1,var, offset=1, formater=lambda a: a ) + + if array_names is not None: + name_specs = mk_ge_names( m.nGridRows, *array_names, start_index ) + else: + name_specs = None + + m.nm_submatrix_locs('A',color='blue',name_specs=name_specs) # this defines the submatrices (the matrix delimiters) + m.tex_repr() # converts the array of TeX entries into strings with separators and spacers + + if bg_for_entries is not None: + for spec in bg_for_entries: + if all(isinstance(elem, list) for elem in spec): + for s in spec: + m.nm_background( *s ) + else: + m.nm_background( *spec ) + + if ref_path_list is not None: + for spec in ref_path_list: + m.nm_add_rowechelon_path( *spec ) + + m_code = m.nm_latexdoc(template = GE_TEMPLATE, fig_scale=fig_scale ) + + tex_file,svg_file = itikz.svg_file_from_tex( + m_code, prefix='ge_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + + + return m,tex_file,svg_file +# ----------------------------------------------------------------------------------------------- +def ge( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0, ... ], [E1, A1, ... ], [E2, A2, ... ], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I']] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + + # Normalize all incoming structured arguments + matrices = _jl_to_py(matrices) + bg_for_entries = _jl_to_py(bg_for_entries) + pivot_list = _jl_to_py(pivot_list) + ref_path_list = _jl_to_py(ref_path_list) + array_names = _jl_to_py(array_names) + variable_colors = _jl_to_py(variable_colors) + + m, tex_file, svg_file = _ge( matrices, Nrhs=Nrhs, formater=formater, + pivot_list=pivot_list, bg_for_entries=bg_for_entries, + variable_colors=variable_colors,pivot_text_color=pivot_text_color, + ref_path_list=ref_path_list, comment_list=comment_list, + variable_summary=variable_summary, array_names=array_names, + start_index=start_index, func=func, fig_scale=fig_scale, + tmp_dir=tmp_dir, keep_file=keep_file) + + with open(svg_file, "r") as fp: + svg = fp.read() + if svg is not None: + return SVG(svg), m + + return None, m +# ----------------------------------------------------------------------------------------------- +def _to_svg_str( matrices, Nrhs=0, formater=str, pivot_list=None, bg_for_entries=None, + variable_colors=['red','blue'], pivot_text_color='red', + ref_path_list=None, comment_list=None, variable_summary=None, array_names=None, + start_index=1, func=None, fig_scale=None, tmp_dir="tmp", keep_file=None ): + '''basic GE layout (development version): + matrices: [ [None, A0], [E1, A1], [E2, A2], ... ] + Nrhs: number of right hand side columns determines the placement of a partition line, if any + can also be a list of widths to be partioned... + pivot_list: [ pivot_spec, pivot_spec, ... ] where pivot_spec = [grid_pos, [pivot_pos, pivot_pos, ...]] + bg_for_entries: [ bg_spec, ...] where bg_spec = [gM,gN, [ entries ], color, pt ] where pt is the inner separation, e.g. 0 + variable_colors: [ basic_var_color, free_var_color] + ref_path_list: [ path_spec, path_spec, ... ] where path_spec = [grid_pos, [pivot_pos], directions ] where directions='vv','vh','hv' or 'hh' + comment_list: [ txt, txt, ... ] must have a txt entry for each layer. Multiline comments are separated by \\ + variable_summary: [ basic, ... ] a list of true/false values specifying whether a column has a pivot or not + array_names: list of names for the two columns: [ 'E', ['A','b','I'] + start_index: first subscript for the elementary operation matrices (can be None) + func: a function to be applied to the MatrixGridLayout object prior to generating the latex document + ''' + + m, tex_file, svg_file = _ge( matrices, Nrhs=Nrhs, formater=formater, + pivot_list=pivot_list, bg_for_entries=bg_for_entries, + variable_colors=variable_colors,pivot_text_color=pivot_text_color, + ref_path_list=ref_path_list, comment_list=comment_list, + variable_summary=variable_summary, array_names=array_names, + start_index=start_index, func=func, fig_scale=fig_scale, + tmp_dir=tmp_dir, keep_file=keep_file) + + with open(svg_file, "r") as fp: + svg = fp.read() + + return svg +# ================================================================================================================================ +def _q_gram_schmidt( v_list ): + w = [] + for j in range( len( v_list )): + w_j = v_list[j] + for k in range( j ): + w_j = w_j - w[k].dot( v_list[j]) * w[k] + w.append(1/w_j.norm() * w_j) + return w + +def compute_qr_matrices( A, W ): + ''' given the matrix A and the corresponding matrix W with orthogonal columns, + compute the list of list of sympy matrices in a QR layout + ''' + A = _jl_to_py(A) + W = _jl_to_py(W) + A = sym.Matrix(A) + W = sym.Matrix(W) + WtW = W.T @ W + WtA = W.T @ A + S = sym.Matrix.diag( list( map(lambda x: 1/sym.sqrt(x), sym.Matrix.diagonal( WtW)))) + + Qt = S*W.T + R = S*WtA + + matrices = [ [ None, None, A, W ], + [ None, W.T, WtA, WtW ], + [ S, Qt, R, None ] ] + return matrices + +def _qr(matrices, formater=str, array_names=True, fig_scale=None, tmp_dir="tmp", keep_file=None): + m = MatrixGridLayout( matrices, extra_rows = [1,0,0,0]) + m.preamble = preamble + '\n' + r" \NiceMatrixOptions{cell-space-limits = 2pt}"+'\n' + + N = matrices[0][2].shape[1] + + m.array_format_string_list() + m.array_of_tex_entries(formater=formater) + + brown = make_decorator(text_color='brown', bf=True ) + def qr_dec_known_zeros( WtA, WtW ): + l_WtA = [(1,2), [(i,j) for i in range(WtA.shape[0]) for j in range(WtA.shape[0]) if i > j ]] + l_WtW = [(1,3), [(i,j) for i in range(WtW.shape[0]) for j in range(WtW.shape[0]) if i != j ]] + return [l_WtA, l_WtW] + + for spec in qr_dec_known_zeros( matrices[1][2], matrices[1][3]): + #[ [(1,2), [(1,0),(2,0),(2,1)]], [(1,3), [(1,0),(2,0),(2,1), (0,1),(0,2),(1,2)]] ]: + m.decorate_tex_entries( *spec[0], brown, entries=spec[1] ) + + red = make_decorator(text_color='red', bf=True) + red_rgt = make_decorator(text_color='red', bf=True, move_right=True) + m.add_row_above(0,2, [red(f'v_{i+1}') for i in range(N)] + [red(f'w_{i+1}') for i in range(N)], formater= lambda a: a ) + m.add_col_left( 1,1, [red_rgt(f'w^t_{i+1}') for i in range(N)], formater= lambda a: a ) + + if array_names: + dec = make_decorator(bf=True, delim='$') + m.nm_submatrix_locs( 'QR', color='blue', name_specs=[ + [(0,2), 'al', dec('A')], + [(0,3), 'ar', dec('W')], + # ---------------------- + [(1,1), 'al', dec('W^t')], + [(1,2), 'al', dec('W^t A')], + [(1,3), 'ar', dec('W^t W')], + # ---------------------- + [(2,0), 'al', dec(r'S = \left( W^t W \right)^{-\tfrac{1}{2}}')], + [(2,1), 'br', dec(r'Q^t = S W^t')], + [(2,2), 'br', dec('R = S W^t A')] + ]) + else: + m.nm_submatrix_locs() + + m.tex_repr( blockseps = r'\noalign{\vskip3mm} ') + + m_code = m.nm_latexdoc( fig_scale=fig_scale ) + + + tex_file,svg_file = itikz.svg_file_from_tex( + m_code, prefix='qr_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + + return m,tex_file,svg_file +# ----------------------------------------------------------------------------------------------- +def qr(matrices, formater=str, array_names=True, fig_scale=None, tmp_dir="tmp", keep_file=None): + m,tex_file,svg_file = _qr(matrices, formater=formater, array_names=array_names, fig_scale=fig_scale, tmp_dir=tmp_dir, keep_file=keep_file) + matrices = _jl_to_py(matrices) + + with open(svg_file, "r") as fp: + svg = fp.read() + if svg is not None: + return SVG(svg), m + + return None, m + +def gram_schmidt_qr( A_, W_, formater=sym.latex, fig_scale=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + W = _jl_to_py(W) + + A = sym.Matrix( A_ ) + W = sym.Matrix( W_ ) + + WtW = W.T @ W + WtA = W.T @ A + S = WtW**(-1) + for i in range(S.shape[0]): + S[i,i]=sym.sqrt(S[i,i]) + + Qt = S*W.T + R = S*WtA + + matrices = [ [ None, None, A, W ], + [ None, W.T, WtA, WtW ], + [ S, Qt, R, None ] ] + h,m = qr( matrices, formater=formater, array_names=True, fig_scale=fig_scale, tmp_dir=tmp_dir ) + return h,m + +# ================================================================================================== +# BACKSUBSTITUTION +# ================================================================================================== +class BacksubstitutionCascade: + def __init__(self, ref_A, ref_rhs = None, var_name='x' ): + self.ref_syseq( ref_A, ref_rhs=ref_rhs, var_name=var_name) + + @classmethod + def from_ref_Ab(cls, ref_Ab, var_name='x'): + """create `cls` from augmented row echelon form matrix Ab (b is a column vector)""" + + if isinstance( ref_Ab, list ): + ref_A = [row[0:-1] for row in ref_Ab] + ref_rhs = [row[-1] for row in ref_Ab] + else: + ref_A = ref_Ab[:,0:-1] + ref_rhs = ref_Ab[:,-1] + return cls( ref_A, ref_rhs, var_name ) + + def ref_syseq(self, ref_A, ref_rhs = None, var_name='x' ): + self.var_name = var_name + self.ref_A = convert_to_sympy_matrix( ref_A ) + self.ref_rhs = convert_to_sympy_matrix( ref_rhs ) + + if ref_rhs is None: + self.rref_A, self.pivot_cols = self.ref_A.rref() + self.rref_rhs = None + else: + Ab = self.ref_A.row_join( self.ref_rhs ) + rref_Ab, pivot_cols_Ab = Ab.rref() + self.rref_A = rref_Ab[:,0:-1] + self.rref_rhs = rref_Ab[:,-1] + if pivot_cols_Ab[-1] == self.rref_A.shape[1]: + self.pivot_cols = pivot_cols_Ab[:-1] + else: + self.pivot_cols = pivot_cols_Ab + + #return cls( ref_Ab[:,0:-1], ref_Ab[:,-1] ) + + self.free_cols = [ i for i in range(self.ref_A.shape[1]) if i not in self.pivot_cols] + self.rank = len( self.pivot_cols) + + def set_ref_rhs( self, rhs ): + self.ref_rhs = None if rhs is None else sym.Matrix( rhs ) + + def ref_Ab( self, Ab ): + Ab = sym.Matrix( Ab ) + self.ref_syseq( Ab[:,0:-1], Ab[:,-1], var_name=self.var_name ) + + @staticmethod + def _bs_equation( ref_A, pivot_row, pivot_col, rhs=None, name="x" ): + """given a row, generate the right hand terms from A_ref for the back substitution algorithm""" + t = sym.Integer(0) if rhs is None else rhs[pivot_row] + for j in range(pivot_col+1, ref_A.shape[1]): + t = t - ref_A[pivot_row,j]*sym.Symbol(f"{name}_{j+1}") + + if t.is_zero: return f" 0 " + + factor = sym.Integer(1)/ref_A[pivot_row,pivot_col] + + if factor == 1: return(sym.latex(t)) + elif factor == -1: return f"- \\left( {sym.latex(t)} \\right)" + else: return f"{sym.latex(factor)} \\left( {sym.latex(t)} \\right)" + + def _gen_back_subst_eqs( self ): + """generate the equations for the back substitution algorithm""" + + alpha = r'\alpha' + var_name = self.var_name + bs = [] + if len(self.free_cols) > 0: + bs.append( ',\\;'.join([f"{self.var_name}_{i+1} = {alpha}_{i+1}" for i in self.free_cols] )) + start = self.rank-1 + else: + bs.append( f"{self.var_name}_{self.rank} = {BacksubstitutionCascade._bs_equation(self.ref_A,self.rank-1,self.pivot_cols[-1], self.ref_rhs, name=alpha )}") + start = self.rank-2 + + for i in range(start,-1, -1): + bs.append( [ + f"{self.var_name}_{self.pivot_cols[i]+1} = {BacksubstitutionCascade._bs_equation(self.ref_A, i,self.pivot_cols[i], self.ref_rhs, name=var_name )}", + f"{self.var_name}_{self.pivot_cols[i]+1} = {BacksubstitutionCascade._bs_equation(self.rref_A,i,self.pivot_cols[i], self.rref_rhs, name=alpha )}" + ]) + return bs + + def particular_solution(self): + p = sym.Matrix.zeros( self.rref_A.shape[1], 1) + ps = self.ref_A[0:self.rank,self.pivot_cols]**-1 * self.ref_rhs[0:self.rank,0] + for i,c in enumerate(self.pivot_cols): + p[c,0] = ps[i,0] + return p + + def homogeneous_solution(self): + if len(self.free_cols) == 0: + return sym.Matrix.zeros( self.rref_A.shape[1], 1) + + hs = sym.Matrix.zeros( self.rref_A.shape[1], len(self.free_cols)) + + for (i,col) in enumerate(self.free_cols): + hs[col,i] = 1 + for (i,col) in enumerate(self.pivot_cols): + hs[col, :] = -self.rref_A[i,self.free_cols] + return hs + + def _gen_solution_eqs( self ): + """generate the solution equations""" + #lft = r" \left( \begin{array}{r} " + #rgt = r" \end{array} \right)" + lft = r'\begin{pNiceArray}{r}' + rgt = r'\end{pNiceArray}' + + x = lft + r" \\ ".join( [f" {self.var_name}_{i+1}" for i in range(self.ref_A.shape[1]) ] ) + rgt + + if self.ref_rhs is None: + p = "" + plus = "" + else: + ps = self.particular_solution() + p = lft + r" \\ ".join( [ sym.latex(ps[i,0]) for i in range(self.ref_A.shape[1]) ] ) + rgt + plus = " + " if len(self.free_cols) > 0 else "" + + if len(self.free_cols) > 0: + hs = self.homogeneous_solution() + h_txt = [] + for j,jv in enumerate( self.free_cols ): + h = f"\\alpha_{jv+1} " + lft + r" \\ ".join( [ sym.latex(hs[i,j]) for i in range(self.ref_A.shape[1]) ] ) + rgt + h_txt.append( h ) + + h_txt = " + ".join(h_txt) + else: + h_txt="" + + return "$ " + x + " = " + p + plus + h_txt + " $" + + def _forward_adapter(self): + """ + Build an equivalent back-sub problem via the reversal permutation. + Ly=b --> (R A R^T) y = R b, which is upper-triangular if A was lower-triangular. + Returns a *temporary* BacksubstitutionCascade you can render with existing methods. + """ + + n = self.ref_A.shape[1] + R = self._reversal_matrix(n) + U = R * self.ref_A * R.T + bp = None if self.ref_rhs is None else R * self.ref_rhs + return BacksubstitutionCascade(U, bp, var_name=self.var_name) + + @staticmethod + def _reversal_matrix(n): + R = sym.zeros(n) + for i in range(n): + R[i, n-1-i] = 1 + return R + + @staticmethod + def gen_system_eqs( A, b, var_name ): + """generate the system equations""" + var = set() + def mk( j, v ): + var.add(f"{var_name}_{j}") + try: + if v > 0: + if v == 1: s = [" + ", f"{var_name}_{j}" ] + else: s = [" + ", sym.latex( v ), f"{var_name}_{j}" ] + elif v < 0: + if v == -1: s = [" - ", f"{var_name}_{j}" ] + else: s = [" - ", sym.latex(-v ), f"{var_name}_{j}" ] + else: + s = [""] + except: + vs = sym.latex(v) + if vs.find("+") < 0 or vs.find("-") < 0: + s = [ " + ", "( ", vs.replace("+",r"\+").replace("-",r"\-"), " ) ", f"{var_name}_{j}" ] + else: + s = [ " + ", sym.latex(v), f"{var_name}_{j}" ] + + return s + + A = convert_to_sympy_matrix( A ) + b = convert_to_sympy_matrix( b ) + + eqs = [] + for i in range( A.shape[0] ): + terms = [] + for j in range( A.shape[1] ): + if not A[i,j].is_zero: + terms.extend( mk( j+1, A[i,j] )) + + if len(terms) == 0: terms = [" 0 "] + if terms[0] == " + ": + terms = terms[1:] + eqs.append( "".join( terms ) + " = " + sym.latex( b[i,0] ) ) + return r"\sysdelim.\}\systeme[" + "".join(sorted(var)) + "]{ " + ",".join( eqs ) + "}" + + @staticmethod + def _mk_cascade( bs ): + def mk_args( bs ): + mbs = [ f" {{$\\boxed{{ {bs[0]} }}$}}%" ] + for term in bs[1:]: + mbs.append( [f" {{${term[0]}$}}%", f" {{$\\;\\Rightarrow\\; \\boxed{{ {term[1]} }}$}}%"]) + return mbs + + mbs = mk_args(bs) + num_c = len(mbs)-1 + lines = num_c*[ r"{\ShortCascade%"] + lines.append( mbs[0] ) + for i in range(num_c): + lines.extend( mbs[i+1] ) + lines.append( r"}%") + + return lines + + def nm_latex_doc( self, A=None, b=None, show_system=False, show_cascade=True, show_solution=False, fig_scale=None ): + if show_system: + if A is None or b is None: + system_txt = BacksubstitutionCascade.gen_system_eqs( self.ref_A, self.ref_rhs, self.var_name ) + else: + system_txt = BacksubstitutionCascade.gen_system_eqs( A, b, self.var_name ) + else: + system_txt = None + + if show_cascade: + bsA = self._gen_back_subst_eqs() + cascade_txt = BacksubstitutionCascade._mk_cascade(bsA) # why at times is this a tuple with a list entry????? FIX + else: + cascade_txt = None + + if show_solution: + solution_txt = self._gen_solution_eqs() + else: + solution_txt = None + + return jinja2.Template( BACKSUBST_TEMPLATE, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n', + show_system = show_system, system_txt = system_txt, + show_cascade = show_cascade, cascade_txt = cascade_txt[0] if type(cascade_txt) is tuple else cascade_txt, + show_solution = show_solution,solution_txt = solution_txt, + fig_scale = fig_scale + ) + + def nm_latex_doc_forward(self, A=None, b=None, show_system=False, show_cascade=True, + show_solution=False, fig_scale=None): + """ + Forward-substitution view. Keeps the full feature set of nm_latex_doc, + but runs it on the reversed system. + """ + tmp = self._forward_adapter() + code = tmp.nm_latex_doc(A=A, b=b, show_system=show_system, show_cascade=show_cascade, + show_solution=show_solution, fig_scale=fig_scale) + + n = self.ref_A.shape[1] + # do longest index first to avoid overlap during replacement + for k in range(n, 0, -1): + code = code.replace(f"{self.var_name}_{{{k}}}", f"{self.var_name}_{{{n+1-k}}}") + code = code.replace(rf"\alpha_{{{k}}}", rf"\alpha_{{{n+1-k}}}") + + return code + + def show(self, A=None, b=None, show_system=False, show_cascade=True, + show_solution=False, fig_scale=None, keep_file=None, tmp_dir="tmp", + forward=False): + if forward: + code = self.nm_latex_doc_forward(A=A, b=b, show_system=show_system, + show_cascade=show_cascade, show_solution=show_solution, + fig_scale=fig_scale) + else: + code = self.nm_latex_doc(A=A, b=b, show_system=show_system, + show_cascade=show_cascade, show_solution=show_solution, + fig_scale=fig_scale) + + h = itikz.fetch_or_compile_svg( + code, prefix='backsubst_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h + +# ================================================================================================== +# EigenProblem Tables +# ================================================================================================== +class EigenProblemTable: + ''' Basic Computations of the EigenDecomposition tables and the resulting Tex Representation + Indexing is zero-based. + ''' + + def __init__(self, eig, formater=None, eig_digits=None, sigma_digits=None, vec_digits=None, sz=None ): + ''' + eig: dictionary with entries + 'lambda' : distinct eigenvalues + 'sigma' : distinct singular values + 'ma' : corresponding algebraic multiplicites + 'evecs' : list of mg vectors for each eigenvalue + 'qvecs' : list of mg orthonormal vectors for each eigenvalue + 'uvecs' : list of mg orthonormal vectors for each singular value + 'sz' : size (M,N) of the matrix needed for the SVD table + ''' + + self.N = sum(eig['ma']) + self.sz = (self.N,self.N) if sz is None else sz + + self.ncols = 2*len(eig['lambda'])-1 + self.color = "blue" + + self.eig = eig + self._round( eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits ) + + if formater is not None: + self.eig['lambda'] = list( map( formater, eig['lambda']) ) + + if 'sigma' in eig.keys(): + self.eig['sigma'] = list( map( formater, eig['sigma']) ) + + self.eig['ma'] = eig['ma'] + + if 'evecs' in eig.keys(): + self.eig['evecs'] = self._mk_vectors('evecs', formater=formater ) + if 'qvecs' in eig.keys(): + self.eig['qvecs'] = self._mk_vectors('qvecs', formater=formater ) + if 'uvecs' in eig.keys(): + self.eig['uvecs'] = self._mk_vectors('uvecs', formater=formater ) + + + self.tbl_fmt = self._mk_table_format() + self.rule_fmt = self._mk_rule_format() + + def _round( self, eig_digits=None, sigma_digits=None, vec_digits=None ): + if eig_digits is not None and 'lambda' in self.eig.keys(): + f = lambda x: round(x) if eig_digits==0 else round(x,eig_digits) + self.eig['lambda'] = list( map( f, self.eig['lambda'] )) + if sigma_digits is not None and 'sigma' in self.eig.keys(): + f = lambda x: round(x) if sigma_digits==0 else round(x,sigma_digits) + self.eig['sigma'] = list( map( f, self.eig['sigma'] )) + if vec_digits is not None: + f = lambda x: round(x) if vec_digits==0 else round(x,vec_digits) + if 'evecs' in self.eig.keys(): + self.eig['evecs'] = self._mk_vectors('evecs', f) + if 'qvecs' in self.eig.keys(): + self.eig['qvecs'] = self._mk_vectors('qvecs', f) + if 'uvecs' in self.eig.keys(): + self.eig['uvecs'] = self._mk_vectors('uvecs', f) + + + def _mk_table_format( self ): + fmt = '{@{}l' + self.ncols*'c' + '@{}}' + return fmt + + def _mk_rule_format( self ): + fmt = '' + for i in range(1, len(self.eig['lambda'])+1): + fmt += ' \\cmidrule{' + f'{2*i}-{2*i}' + '}' + return fmt + + def _mk_values( self, key='lambda', formater=str ): + l = list( map( formater, self.eig[key]) ) + if key == 'sigma' and self.eig[key][-1] == '0': + l[-1] = formater(' ') + l = list( map( lambda x: '$'+x+'$', l) ) + + ll=[l[0]] + for i in l[1:]: + ll.append('') + ll.append( i) + return ll + + def mk_values( self, key, formater=str ): + line = self._mk_values(key=key, formater=formater) + return " & ".join( line ) + r' \\' # + self.rule_fmt + + def _mk_vectors(self, key, formater=str ): + groups = [] + for vecs in self.eig[key]: + l_lambda = [] + for vec in vecs: + l_lambda.append( np.array( [ formater(v) for v in vec], dtype=object )) + groups.append( l_lambda ) + return groups + + def mk_vectors(self, key, formater=str, add_height=0 ): + groups = [] + nl = r' \\ ' if add_height == 0 else r' \\'+ f'[{add_height}mm] ' + for vecs in self.eig[key]: + l_lambda = [] + for vec in vecs: + l = [ formater(v) for v in vec] + l_lambda.append( r'$\begin{pNiceArray}{r}' + nl.join(l) + r' \end{pNiceArray}$') + groups.append( ', '.join(l_lambda )) + return " & & ".join( groups ) + + def _mk_diag_matrix( self, key='lambda', mm=8, formater=str ): + space = '@{\\hspace{' + str(mm) + 'mm}}' + pre = r'\multicolumn{' + f'{len(self.eig["ma"])}' + '}{c}{\n'+\ + r'$\begin{pNiceArray}{' + space.join( self.N*['c'] ) + '}' + post = r'\end{pNiceArray}$}' + + Lambda = np.full( self.sz, formater(0), dtype=object) + lambdas = [] + for i,v in enumerate( self.eig['ma'] ): + l = self.eig[key][i] + lambdas += v*[l] + + for i,v in enumerate(lambdas): + try: + Lambda[i,i] = formater(v) + except: + break + + return pre,Lambda,post + + def _mk_evecs_matrix( self, key='evecs', formater=str, mm=0 ): + sz = self.sz[0] if key == 'uvecs' else self.sz[1] + space = '@{\\hspace{' + str(mm) + 'mm}}' if mm > 0 else '' + pre = r'\multicolumn{' + f'{len(self.eig["ma"])}' + '}{c}{\n'+\ + r'$\begin{pNiceArray}{' + space.join( sz*['r'] ) + '}' + post = r'\end{pNiceArray}$}' + + S = np.empty( (sz,sz), dtype=object) + j = 0 + for vecs in self.eig[key]: + for vec in vecs: + for i,v in enumerate(vec): + S[i,j] = formater(v) + j += 1 + return pre,S,post + + def _fmt_matrix( self, pre, m, post, add_height=0 ): + nl = r' \\ ' if add_height == 0 else r' \\'+ f'[{add_height}mm] ' + + mat = [] + for i in range( m.shape[0]): + mat.append( ' & '.join( m[i,: ])) + mat = pre + nl.join( mat ) + r' \\ ' + post + return mat + + def mk_diag_matrix( self, key, formater=str, mm=8, extra_space='', add_height=0 ): + pre, m, post = self._mk_diag_matrix(key=key, formater=formater, mm=mm ) + for i in range(m.shape[0]): + m[i,0] = extra_space+m[i,0] + m[i,self.N-1] = m[i,self.N-1]+extra_space + return self._fmt_matrix( pre, m, post, add_height=add_height ) + + def mk_evecs_matrix( self, key, formater=str, mm=8,extra_space='', add_height=0 ): + pre, m, post = self._mk_evecs_matrix(key=key, formater=formater, mm=mm ) + sz = self.sz[0] if key == 'uvecs' else self.sz[1] + if m.shape[1] == sz: + for i in range(m.shape[0]): + m[i,0] = extra_space+m[i,0] + m[i,m.shape[1]-1]=m[i,m.shape[1]-1]+extra_space + + return self._fmt_matrix( pre, m, post, add_height ) + else: + return m + + def decorate_values(self, l, decorate, i=None ): + if i is not None: + l[i] = decorate( l[i] ) + else: + for i in range(0,len(l)): + l[i] = decorate(l[i]) + + def decorate_matrix(self, m, decorate, row=None, col=None ): + m = m.reshape( m.shape[0],-1 ) + rows = range( m.shape[0] ) if row is None else [ row ] + cols = range( m.shape[1] ) if col is None else [ col ] + for i in rows: + for j in cols: + m[i,j]=decorate( m[i,j]) + + def nm_latex_doc( self, formater=sym.latex, case="S", color='blue', + mmLambda=8, mmS=4, spaceLambda=r' \;\; ', spaceS=r' \;\; ', + fig_scale = None + ): + tbl_fmt = self._mk_table_format() + + # ------------------------------------------------------ values + def no_zeros(x): + if type(x) is str: + return '' if x=='0' else formater(x) + try: + return '' if x.is_zero else formater(x) + except: + return formater(x) + sigmas = self.mk_values('sigma', formater=no_zeros ) if case == 'SVD' else None + lambdas = self.mk_values('lambda', formater=formater) + mas = self.mk_values('ma', formater=formater) + + # ------------------------------------------------------ vectors + evecs = self.mk_vectors('evecs', formater=formater) + r' \\' + + qvecs = None + uvecs = None + + if case == 'Q': + qvecs = self.mk_vectors('qvecs', formater=formater, add_height=1) + r' \\' + elif case == 'SVD': + qvecs = self.mk_vectors('qvecs', formater=formater, add_height=1) + r' \\' + try: + uvecs = self.mk_vectors('uvecs', formater=formater, add_height=1) + r' \\' + except: + uvecs = None + + # ------------------------------------------------------ matrices + left_singular_matrix = None + + if case == 'SVD': + lambda_matrix = self.mk_diag_matrix( 'sigma', formater=formater, mm=mmLambda) + else: + try: + lambda_matrix = self.mk_diag_matrix( 'lambda', formater=formater, mm=mmLambda) + except: + lambda_matrix = None + + if case == 'S': + try: + evecs_matrix = self.mk_evecs_matrix( 'evecs', formater=formater, mm=mmS ) + except: + evecs_matrix = None + else: + evecs_matrix = self.mk_evecs_matrix( 'qvecs', formater=formater, mm=mmS ) + if case == 'SVD': + try: + left_singular_matrix = self.mk_evecs_matrix( 'uvecs', formater=formater, mm=mmS ) + except: + left_singular_matrix = None + + if case == 'S': matrix_names=[r'\Lambda', 'S'] + elif case == 'Q': matrix_names=[r'\Lambda', 'Q'] + else: matrix_names=[r'\Sigma', 'V', 'U'] + + # ------------------------------------------------------ figure scaling + if fig_scale is not None: + fig_scale = r'\scalebox{'+str(fig_scale)+'}{%' + + return jinja2.Template( EIGPROBLEM_TEMPLATE, block_start_string='{%%', block_end_string='%%}', + comment_start_string='{##', comment_end_string='##}' ).render( \ + preamble = r" \NiceMatrixOptions{cell-space-limits = 1pt}"+'\n', + fig_scale = fig_scale, + matrix_names = matrix_names, + table_format = tbl_fmt, color = '{'+color+'}', + rule_format = self.rule_fmt, + sigmas = sigmas, + lambdas = lambdas, + algebraic_multiplicities = mas, + eigenbasis = evecs, + orthonormal_basis = qvecs, + left_singular_matrix = left_singular_matrix, + lambda_matrix = lambda_matrix, + evecs_matrix = evecs_matrix + ) +# -------------------------------------------------------------------------------------------------- +def eig_tbl(A, normal=False, eig_digits=None,vec_digits=None): + A = _jl_to_py(A) + A = sym.Matrix(A) + eig = { + 'lambda': [], + 'ma': [], + 'evecs': [], + } + if normal: + eig['qvecs'] = [] + + res = A.eigenvects() + for e,m,vecs in res: + eig['lambda'].insert(0,e) + eig['ma'].insert(0,m) + eig['evecs'].insert(0,vecs) + if normal: + vvecs = _q_gram_schmidt( vecs ) + eig['qvecs'].insert(0, vvecs ) + + return EigenProblemTable( eig,eig_digits=eig_digits, vec_digits=vec_digits ) + +def show_eig_tbl(A, Ascale=None, normal=False, eig_digits=None, vec_digits=None, formater=sym.latex, mmS=10, mmLambda=8, fig_scale=1.0, color='blue', keep_file=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + E = eig_tbl(A, normal=normal, eig_digits=eig_digits,vec_digits=vec_digits) + if Ascale is not None: + E.eig[ 'lambda' ] = [ e/Ascale for e in E.eig[ 'lambda' ]] + + c = 'Q' if normal else 'S' + + svd_code = E.nm_latex_doc( formater=formater, case=c, mmS=mmS, mmLambda=mmLambda, fig_scale=fig_scale, color=color) + + h = itikz.fetch_or_compile_svg( + svd_code, prefix='svd_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h +# -------------------------------------------------------------------------------------------------- +def svd_tbl(A, Ascale=None, eig_digits=None, sigma_digits=None, vec_digits=None): + A = _jl_to_py(A) + A = sym.Matrix(A) + eig = { + 'sigma': [], + 'lambda': [], + 'ma': [], + 'evecs': [], + 'qvecs': [], + 'uvecs': [] + } + def mySVD(A): + A = sym.Matrix(A) + + def sort_eig_vec(sym_eig_vec): + sort_eig_vecs = sorted(sym_eig_vec, key=lambda x: x[0], reverse=True) + + for i in sort_eig_vecs: + e = i[0] if Ascale is None else i[0] / (Ascale*Ascale) + sigma = sym.sqrt(e) + eig['sigma'].append(sigma) + + eig['lambda'].append( e ) + eig['ma'].append( i[1] ) + eig['evecs'].append( i[2] ) + vvecs = _q_gram_schmidt( i[2] ) + eig['qvecs'].append( vvecs ) + + if not sigma.is_zero: + s_inv = 1/sigma if Ascale is None else 1/(sigma*Ascale) + eig['uvecs'].append( [ s_inv * A * v for v in vvecs] ) + + sort_eig_vec((A.transpose() * A).eigenvects()) + ns = A.transpose().nullspace() + if len(ns) > 0: + ns_on_basis = _q_gram_schmidt( ns ) + eig['uvecs'].append( ns_on_basis ) + + mySVD(A) + return EigenProblemTable( eig, sz=A.shape, eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits ) + +def show_svd_table(A, Ascale=None, eig_digits=None, sigma_digits=None, vec_digits=None, + formater=sym.latex, mmS=10, mmLambda=8, fig_scale=1.0, color='blue', keep_file=None, tmp_dir="tmp" ): + A = _jl_to_py(A) + E = svd_tbl(A, Ascale=Ascale, eig_digits=eig_digits, sigma_digits=sigma_digits, vec_digits=vec_digits) + svd_code = E.nm_latex_doc( formater=formater, case='SVD', mmS=mmS, mmLambda=mmLambda, fig_scale=fig_scale, color=color) + + h = itikz.fetch_or_compile_svg( + svd_code, prefix='svd_', working_dir=tmp_dir, debug=False, + **itikz.build_commands_dict(use_xetex=True,use_dvi=False,crop=True), + nexec=1, keep_file=keep_file ) + return h +# ================================================================================================== +def html_string(txt,sz=20,color="darkred",justify="left",height="15"): + return HTML(f"""
+ + ${txt} +
""") +# -------------------------------------------------------------------------------------------------- +def html_strings(txt1,txt2,sz1=20,sz2=20,color="darkred",justify="left",height="15"): + return HTML("""
+${txt1}
+${txt2}
+
""") + + +#def foo(x): +# print( "foo input: ", x) +# if x is None: +# print( "None == ", None) +# if x is not None: +# print( "not None != ", None) diff --git a/itikz/tikz.py b/itikz/tikz.py new file mode 100644 index 0000000..a440bb7 --- /dev/null +++ b/itikz/tikz.py @@ -0,0 +1,62 @@ +import re +import jinja2 + +la_colors=r"""% ======================================================= colors +\definecolor{la_white}{RGB}{233,235,223} %#E9EBDF +\definecolor{la_dark}{RGB}{59,54,81} %#3B3651 +\definecolor{la_gray}{RGB}{96,112,139} %#60708B +\definecolor{la_tan}{RGB}{152,159,122} %#989F7A +""" + +template = r"""\documentclass[tikz{% for a in class_args %},{{a}}{% endfor %}]{standalone} +\pagestyle{empty} +{% for p in tex_packages %} +{{p}} +{% endfor %} +{% for p in tikz_libraries %} +\usetikzlibrary{{p}} +{% endfor %} +{{extension}} + +\begin{document} +{{preamble}} +\begin{tikzpicture}{% for p in tikz_args %}{{p}}{% endfor %} + {{tikz_code}} +\end{tikzpicture} +\end{document} +""" + +pattern = re.compile( r'(\[[^]]*])(.*)' ) + +def tikz_source( code, + class_args=None, tex_packages=None, tikz_libraries=None, extension="% no_extension", + preamble="% preamble", tikz_args=None): + def split(arg): + if arg is None: + return [] + l = [] + for a in arg.split(","): + match = pattern.match( a ) + if match: + l.append( r"\usepackage" + match.group(1) + "{" + match.group(2)+ "}" ) + else: + l.append(r"\usepackage{" + a + "}") + return l + + + class_args = [] if class_args is None else [class_args] + tex_packages = split(tex_packages) + tikz_libraries = [] if tikz_libraries is None else ["{"+tikz_libraries+"}"] + tikz_args = [] if tikz_args is None else ["["+tikz_args+"]"] + + src=jinja2.Template( template )\ + .render( class_args=class_args, + tex_packages=tex_packages, + tikz_libraries=tikz_libraries, + extension=extension, + preamble=preamble, + tikz_args=tikz_args, + tikz_code=code + ) + + return src diff --git a/patch.latexmk b/patch.latexmk new file mode 100644 index 0000000..c6318e5 --- /dev/null +++ b/patch.latexmk @@ -0,0 +1,20 @@ +--- /usr/bin/latexmk 2024-02-01 23:08:52.000000000 +0000 ++++ latexmk 2024-10-13 01:27:51.188858223 +0000 +@@ -2320,7 +2320,7 @@ + } + + if ( $diagnostics || $rc_report ) { +- show_array( "Rc files read:", @rc_files_read ); ++ show_array( "Rc files read:", @rc_files_read ) unless $silent; + } + + if ( $bad_options > 0 ) { +@@ -9475,7 +9475,7 @@ + + $pass{$rule}++; + +- warn_running( "Run number $pass{$rule} of rule '$rule'" ); ++ warn_running( "Run number $pass{$rule} of rule '$rule'" ) unless silent; + $return = &rdb_run1; + + if ($$Pchanged) { diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..730be16 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,36 @@ +# ── pyproject.toml ─────────────────────────────────────────────────────── +[build-system] +requires = [ + "setuptools>=71", # must be ≥71 to support PEP 660 editable builds + "wheel" + ] + build-backend = "setuptools.build_meta" + +# Project metadata – all keys appear **once** only. +[project] +name = "itikz" +version = "0.1.7" +description = "Cell magic for PGF/TikZ-to-SVG rendering in Jupyter" +readme = "README.rst" +requires-python = ">=3.9" +license = {text = "MIT"} # SPDX‑compatible expression (single definition) +authors = [{name = "John Bjorn Nelson", email = "jbn@abreka.com"}] +keywords = ["itikz", "jupyter", "tikz", "svg"] +classifiers = [ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only" + ] + +# Optional runtime dependencies (empty list if none) +dependencies = [] + +# Optional development/test dependencies – also appear only once. +[project.optional-dependencies] +dev = [ + "pytest", + "pytest-runner" + ] +# ──────────────────────────────────────────────────────────────────────── diff --git a/setup.cfg b/setup.cfg index 9b4abfb..c9eb0ef 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.1.5 +current_version = 0.1.7 commit = True tag = True @@ -17,10 +17,5 @@ universal = 1 [flake8] exclude = docs -[aliases] -# Define setup.py command aliases here -test = pytest - -[tool:pytest] -collect_ignore = ['setup.py'] - +[metadata] +license = MIT # ← SPDX‑compatible license expression diff --git a/setup.py b/setup.py index bf96d26..d9b4eb6 100644 --- a/setup.py +++ b/setup.py @@ -1,55 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +"""Thin shim for setuptools. -"""The setup script.""" +All package metadata is now stored in setup.cfg and pyproject.toml. +""" -from setuptools import setup, find_packages +from setuptools import setup -with open('README.rst') as readme_file: - readme = readme_file.read() - -with open('HISTORY.rst') as history_file: - history = history_file.read() - -requirements = [] - -setup_requirements = ['pytest-runner', ] - -test_requirements = ['pytest', ] - -setup( - author="John Bjorn Nelson", - author_email='jbn@abreka.com', - classifiers=[ - 'Development Status :: 2 - Pre-Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - "Programming Language :: Python :: 2", - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - ], - description="Cell magic for PGF/TikZ-to-SVG rendering in Jupyter", - entry_points={ - 'console_scripts': [ - 'itikz=itikz.cli:main', - ], - }, - install_requires=requirements, - license="MIT license", - long_description=readme + '\n\n' + history, - include_package_data=True, - keywords='itikz', - name='itikz', - packages=find_packages(include=['itikz']), - setup_requires=setup_requirements, - test_suite='tests', - tests_require=test_requirements, - url='https://github.com/jbn/itikz', - version='0.1.5', - zip_safe=False, -) +setup() diff --git a/silent.latexmk b/silent.latexmk new file mode 100755 index 0000000..f531a01 --- /dev/null +++ b/silent.latexmk @@ -0,0 +1,10284 @@ +#!/usr/bin/perl -w + +use warnings; + +## Copyright John Collins 1998-2021 +## (username jcc8 at node psu.edu) +## (and thanks to David Coppit (username david at node coppit.org) +## for suggestions) +## Copyright Evan McLean +## (modifications up to version 2) +## Copyright 1992 by David J. Musliner and The University of Michigan. +## (original version) +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +## +## +## +## Modification log from 14 Apr 2021 onwards in detail +## +## 20 Nov 2021 John Collins Add /etc to list of locations for system rc files +## 4 Nov 2021 John Collins Improve diagnostics when there's a mismatch of +## destination file of rule between .fdb_latexmk +## file and expectation. +## 2 Nov 2021 John Collins Sort generated-file section by filename; it's +## already done in file data secton. +## Only write fdb_latexmk file if nothing has been +## done. (Addition of $runs_total variable.) +## V. 4.76. +## 23 Sep 2021 John Collins Option -time: times for all rules reported now +## 18 Sep 2021 John Collins For biber: parse blg file for config file use +## V. 4.75. +## 27 Aug 2021 John Collins Modified "missing file" message (when parsing +# log file). +## 29 May 2021 John Collins When emulating aux_dir, put .synctex.gz .synctex +## files in out_dir (as done by MiKTeX, and needed +## for their use). +## Turn emulate aux_dir off by default, to match older +## behavior. (BACKWARDS INCOMPATIBLE with 4.73 and +## 4.74.) +## Add end-of-all-runs warning if emulate aux_dir needed +## to be turned on, when it was initially off. +## Add .synctex to list of extensions to clear by default. +## 20 May 2021 John Collins Turn back on default to report rc files read. +## Add options -rc-report, -rc-report-, +## -dir_report, -dir_report-. +## 16 May 2021 John Collins Deal with some variable used only once warnings +## Remove by default informational messages on rc +## files read, and aux_dir and out_dir setting. +## 5-6 May 2021 John Collins Correct normalization of aux and out dirs. +## Version 4.74 +## 3 May 2021 John Collins Minor corrections. Submit to CTAN. +## 30 Apr 2021 John Collins Revert the change of 14-15 Apr, by removing the +## of cwd(). That gave sometimes obnoxiously slow +## parsing of big log files, because of the slowness +## of large number of calls to cwd() caused by calls +## to sub normalize_filename. I think I am mistaken +## that cwd() could possibly give a different result +## than getcwd(), whose cached result is used by +## my goodcwd(). That idea was my motivation on 14 Apr. +## 22 Apr 2021 John Collins Clean up aux and out_dir code. +## 21 Apr 2021 John Collins Clean up some comments +## Add in emulation of -aux-directory. On by +## default. +## 20 Apr 2021 John Collins Add -dALLOWPSTRANSPARENCY option to ps2pdf and +## dvi2pdf. That avoids problems with recent +## ghostscript versions when, e.g., pstricks is used. +## 16 Apr 2021 John Collins Better normalization of aux_dir and out_dir, so +## that TEXMFOUTPUT, and the source and dest names for bibtex +## and makeindex allow them to work always when the aux_dir +## is **not** below cwd, at least under TeX Live. With MiKTeX +## bibtex works even without special precautions for aux_dir +## not below cwd. But makeindex doesn't work in this case, +## even if TEXMFOUTPUT is set correctly. +## 14-15 Apr 2021 John Collins In normalize_filename, try both good_cwd() and +## cwd() for removing directory component. +## That improves clean up. At least it could. +## V. 4.73. +## +## +## 1998-2021, John Collins: Many improvements and fixes. +## See CHANGE-log.txt for full list, and CHANGES for summaries +## +## Modified by Evan McLean (no longer available for support) +## Original script (RCS version 2.3) called "go" written by David J. Musliner +## +##----------------------------------------------------------------------- + +## Explicit exit codes: +## 10 = bad command line arguments +## 11 = file specified on command line not found +## or other file not found +## 12 = failure in some part of making files +## 13 = error in initialization file +## 20 = probable bug +## or retcode from called program. + +$my_name = 'latexmk'; +$My_name = 'Latexmk'; +$version_num = '4.76'; +$version_details = "$My_name, John Collins, 20 November 2021"; + +use Config; +use File::Basename; +use File::Copy; +use File::Spec; + +# If possible, use better glob, which does not use space as item separator. +# It's either File::Glob::bsd_glob or File::Glob::glob +# The first does not exist in old versions of Perl, while the second +# is deprecated in more recent versions and will be removed +$have_bsd_glob = 0; +use File::Glob; +if ( eval{ File::Glob->import('bsd_glob'); 1; } ) { + # Success in importing bsd_glob + $have_bsd_glob = 1; +} +elsif ( eval{ File::Glob->import('glob'); 1; } ) { + warn "$My_name: I could not import File::Glob:bsd_glob, probably because your\n", + " Perl is too old. I have arranged to use the deprecated File::Glob:glob\n", + " instead.\n", + " WARNING: It may malfunction on clean up operation on filenames containing\n", + " spaces.\n"; + $have_bsd_glob = 0; +} +else { + die "Could not import 'File::Glob:bsd_glob' or 'File::Glob:glob'\n"; +} +# How I use the result of loading glob routines: +sub my_glob { + if ($have_bsd_glob) { return bsd_glob( $_[0] ); } + else { return glob( $_[0] ); } +} + +use File::Path 2.08 qw( make_path ); +use FileHandle; +use File::Find; +use List::Util qw( max ); +use Cwd; +use Cwd "abs_path"; +use Cwd "chdir"; # Ensure $ENV{PWD} tracks cwd. +use Digest::MD5; + +#use strict; + +# The following variables are assigned once and then used in symbolic +# references, so we need to avoid warnings 'name used only once': +use vars qw( $dvi_update_command $ps_update_command $pdf_update_command $out_dir_requested ); + +# Translation of signal names to numbers and vv: +%signo = (); +@signame = (); +if ( defined $Config{sig_name} ) { + $i = 0; + foreach $name (split('\s+', $Config{sig_name})) { + $signo{$name} = $i; + $signame[$i] = $name; + $i++; + } +} +else { + warn "Something wrong with the perl configuration: No signals?\n"; +} + + +# Line length in log file that indicates wrapping. +# This number EXCLUDES line-end characters, and is one-based. +# It is the parameter max_print_line in the TeX program. (tex.web) +$log_wrap = 79; + +######################################################################### +## Default parsing and file-handling settings + +## Array of reg-exps for patterns in log-file for file-not-found +## Each item is the string in a regexp, without the enclosing slashes. +## First parenthesized part is the filename. +## Note the need to quote slashes and single right quotes to make them +## appear in the regexp. +## Add items by push, e.g., +## push @file_not_found, '^No data file found `([^\\\']*)\\\''; +## will give match to line starting "No data file found `filename'" +@file_not_found = ( + '^No file\\s*(.*)\\.$', + '^\\! LaTeX Error: File `([^\\\']*)\\\' not found\\.', + '^\\! I can\\\'t find file `([^\\\']*)\\\'\\.', + '.*?:\\d*: LaTeX Error: File `([^\\\']*)\\\' not found\\.', + '^LaTeX Warning: File `([^\\\']*)\\\' not found', + '^Package .* [fF]ile `([^\\\']*)\\\' not found', + '^Package .* No file `([^\\\']*)\\\'', + 'Error: pdflatex \(file ([^\)]*)\): cannot find image file', + ': File (.*) not found:\s*$', + '! Unable to load picture or PDF file \\\'([^\\\']+)\\\'.', +); + +# Characters that we won't allow in the name of a TeX file. +# Notes: Some are disallowed by TeX itself. +# '\' results in TeX macro expansion +# '$' results in possible variable substitution by kpsewhich called from tex. +# '"' gets special treatment. +# See subroutine test_fix_texnames and its call for their use. +$illegal_in_texname = "\x00\t\f\n\r\$%\\~\x7F"; + +# Whether to normalize aux_dir and out_dir where possible. +# This is important when these directories aren't subdirectories of the cwd, +# and TeXLive's makeindex and/or bibtex are used. +$normalize_names = 2; # Strongest kind. + +## Hash mapping file extension (w/o period, e.g., 'eps') to a single regexp, +# whose matching by a line in a file with that extension indicates that the +# line is to be ignored in the calculation of the hash number (md5 checksum) +# for the file. Typically used for ignoring datestamps in testing whether +# a file has changed. +# Add items e.g., by +# $hash_calc_ignore_pattern{'eps'} = '^%%CreationDate: '; +# This makes the hash calculation for an eps file ignore lines starting with +# '%%CreationDate: ' +# ?? Note that a file will be considered changed if +# (a) its size changes +# or (b) its hash changes +# So it is useful to ignore lines in the hash calculation only if they +# are of a fixed size (as with a date/time stamp). +%hash_calc_ignore_pattern =(); + +# Specification of templates for extra rules. +# See subroutine rdb_initialize_rules for examples of rule templates, and +# how they get used to construct rules. +# (Documentation obviously needs to be improved!) +%extra_rule_spec = (); + + +# Hooks for customized extra processing on aux files. The following +# variable is an array of references to functions. Each function is +# invoked in turn when a line of an aux file is processed (if none +# of the built-in actions have been done). On entry to the function, +# the following variables are set: +# $_ = current line of aux file +# $rule = name of rule during the invocation of which, the aux file +# was supposed to have been generated. +@aux_hooks = (); +# Hooks for customized processing on lists of source and missing files. +# The following variable is an array of references to functions. Each +# function is invoked in turn after a run of latex (or pdflatex etc) and +# latexmk has analyzed the .log and .fls files for dependency information. +# On entry to each called function, the following variables are set: +# $rule = name of *latex rule +# %dependents: maps source files and possible source files to a status. +# See begining of sub parse_log for possible values. +@latex_file_hooks = (); + +######################################################################### +## Default document processing programs, and related settings, +## These are mostly the same on all systems. +## Most of these variables represents the external command needed to +## perform a certain action. Some represent switches. + + +## Which TeX distribution is being used +## E.g., "MiKTeX 2.9", "TeX Live 2018" +## "" means not determined. Obtain from first line of .log file. +$tex_distribution = ''; + +&std_tex_cmds; + +# Possible code to execute by *latex before inputting source file. +# Not used by default. +$pre_tex_code = ''; + +## Default switches: +$latex_default_switches = ''; +$pdflatex_default_switches = ''; +$lualatex_default_switches = ''; + # Note that xelatex is used to give xdv file, not pdf file, hence + # we need the -no-pdf option. +$xelatex_default_switches = '-no-pdf'; + +## Switch(es) to make them silent: +$latex_silent_switch = '-interaction=batchmode'; +$pdflatex_silent_switch = '-interaction=batchmode'; +$lualatex_silent_switch = '-interaction=batchmode'; +$xelatex_silent_switch = '-interaction=batchmode'; + +# Whether to emulate -aux-directory, so we can use it on system(s) (TeXLive) +# that don't support it: +$emulate_aux = 0; +# Whether emulate_aux had to be switched on during a run: +$emulate_aux_switched = 0; + +%input_extensions = (); +# %input_extensions maps primary_rule_name to pointer to hash of file extensions +# used for extensionless files specified in the source file by constructs +# like \input{file} \includegraphics{file} +set_input_ext( 'latex', 'tex', 'eps' ); +set_input_ext( 'pdflatex', 'tex', 'jpg', 'pdf', 'png' ); +$input_extensions{lualatex} = $input_extensions{pdflatex}; +$input_extensions{xelatex} = $input_extensions{pdflatex}; +# Save these values as standards to be used when switching output, +# i.e., when actual primary rule differs from standard. +%standard_input_extensions = %input_extensions; + +%allowed_output_ext = ( ".dvi" => 1, ".xdv" => 1, ".pdf" => 1 ); +# Extensions of files preserved when clean up is by -c rather than -C: +%small_cleanup_preserved_exts = (); +foreach ( 'dvi', 'dviF', 'ps', 'psF', 'pdf', 'synctex', 'synctex.gz', 'xdv' ) { + $small_cleanup_preserved_exts{$_} = 1; +} + + +# Information about options to latex and pdflatex that latexmk will simply +# pass through to *latex +# Option without arg. maps to itself. +# Option with arg. maps the option part to the full specification +# e.g., -kpathsea-debug => -kpathsea-debug=NUMBER +%allowed_latex_options = (); +%allowed_latex_options_with_arg = (); +foreach ( + ##### + # TeXLive options + "-draftmode switch on draft mode (generates no output PDF)", + "-enc enable encTeX extensions such as \\mubyte", + "-etex enable e-TeX extensions", + "-file-line-error enable file:line:error style messages", + "-no-file-line-error disable file:line:error style messages", + "-fmt=FMTNAME use FMTNAME instead of program name or a %& line", + "-halt-on-error stop processing at the first error", + "-interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n". + " scrollmode/errorstopmode)", + "-ipc send DVI output to a socket as well as the usual\n". + " output file", + "-ipc-start as -ipc, and also start the server at the other end", + "-kpathsea-debug=NUMBER set path searching debugging flags according to\n". + " the bits of NUMBER", + "-mktex=FMT enable mktexFMT generation (FMT=tex/tfm/pk)", + "-no-mktex=FMT disable mktexFMT generation (FMT=tex/tfm/pk)", + "-mltex enable MLTeX extensions such as \charsubdef", + "-output-comment=STRING use STRING for DVI file comment instead of date\n". + " (no effect for PDF)", + "-parse-first-line enable parsing of first line of input file", + "-no-parse-first-line disable parsing of first line of input file", + "-progname=STRING set program (and fmt) name to STRING", + "-shell-escape enable \\write18{SHELL COMMAND}", + "-no-shell-escape disable \\write18{SHELL COMMAND}", + "-shell-restricted enable restricted \\write18", + "-src-specials insert source specials into the DVI file", + "-src-specials=WHERE insert source specials in certain places of\n". + " the DVI file. WHERE is a comma-separated value\n". + " list: cr display hbox math par parend vbox", + "-synctex=NUMBER generate SyncTeX data for previewers if nonzero", + "-translate-file=TCXNAME use the TCX file TCXNAME", + "-8bit make all characters printable by default", + + ##### + # MikTeX options not in TeXLive + "-alias=app pretend to be app", + "-buf-size=n maximum number of characters simultaneously present\n". + " in current lines", + "-c-style-errors C-style error messages", + "-disable-installer disable automatic installation of missing packages", + "-disable-pipes disable input (output) from (to) child processes", + "-disable-write18 disable the \\write18{command} construct", + "-dont-parse-first-line disable checking whether the first line of the main\n". + " input file starts with %&", + "-enable-enctex enable encTeX extensions such as \\mubyte", + "-enable-installer enable automatic installation of missing packages", + "-enable-mltex enable MLTeX extensions such as \charsubdef", + "-enable-pipes enable input (output) from (to) child processes", + "-enable-write18 fully enable the \\write18{command} construct", + "-error-line=n set the width of context lines on terminal error\n". + " messages", + "-extra-mem-bot=n set the extra size (in memory words) for large data\n". + " structures", + "-extra-mem-top=n set the extra size (in memory words) for chars,\n". + " tokens, et al", + "-font-max=n set the maximum internal font number", + "-font-mem-size=n set the size, in TeX memory words, of the font memory", + "-half-error-line=n set the width of first lines of contexts in terminal\n". + " error messages", + "-hash-extra=n set the extra space for the hash table of control\n". + " sequences", + "-job-time=file set the time-stamp of all output files equal to\n". + " file's time-stamp", + "-main-memory=n change the total size (in memory words) of the main\n". + " memory array", + "-max-in-open=n set the maximum number of input files and error\n". + " insertions that can be going on simultaneously", + "-max-print-line=n set the width of longest text lines output", + "-max-strings=n set the maximum number of strings", + "-nest-size=n set the maximum number of semantic levels\n". + " simultaneously active", + "-no-c-style-errors standard error messages", + "-param-size=n set the the maximum number of simultaneous macro\n". + " parameters", + "-pool-size=n set the maximum number of characters in strings", + "-record-package-usages=file record all package usages and write them into\n". + " file", + "-restrict-write18 partially enable the \\write18{command} construct", + "-save-size=n set the the amount of space for saving values\n". + " outside of current group", + "-stack-size=n set the maximum number of simultaneous input sources", + "-string-vacancies=n set the minimum number of characters that should be\n". + " available for the user's control sequences and font\n". + " names", + "-tcx=name process the TCX table name", + "-time-statistics show processing time statistics", + "-trace enable trace messages", + "-trace=tracestreams enable trace messages. The tracestreams argument is\n". + " a comma-separated list of trace stream names", + "-trie-size=n set the amount of space for hyphenation patterns", + "-undump=name use name as the name of the format to be used,\n". + " instead of the name by which the program was\n". + " called or a %& line.", + + ##### + # Options passed to *latex that have special processing by latexmk, + # so they are commented out here. + #-jobname=STRING set the job name to STRING + #-aux-directory=dir Set the directory dir to which auxiliary files are written + #-output-directory=DIR use existing DIR as the directory to write files in + # "-output-format=FORMAT use FORMAT for job output; FORMAT is `dvi\" or `pdf\"", + #-quiet + #-recorder enable filename recorder + # + # Options with different processing by latexmk than *latex + #-help + #-version + # + # Options NOT used by latexmk + #-includedirectory=dir prefix dir to the search path + #-initialize become the INI variant of the compiler + #-ini be pdfinitex, for dumping formats; this is implicitly + # true if the program name is `pdfinitex' +) { + if ( /^([^\s=]+)=/ ) { + $allowed_latex_options_with_arg{$1} = $_; + } + elsif ( /^([^\s=]+)\s/ ) { + $allowed_latex_options{$1} = $_; + } + else { + $allowed_latex_options{$_} = $_; + } +} + +# Arrays of options that will be added to latex and pdflatex. +# These need to be stored until after the command line parsing is finished, +# in case the values of $latex and/or $pdflatex change after an option +# is added. +@extra_latex_options = (); +@extra_pdflatex_options = (); +@extra_lualatex_options = (); +@extra_xelatex_options = (); + + +## Command to invoke biber & bibtex +$biber = 'biber %O %S'; +$bibtex = 'bibtex %O %S'; +# Switch(es) to make biber & bibtex silent: +$biber_silent_switch = '--onlylog'; +$bibtex_silent_switch = '-terse'; +$bibtex_use = 1; # Whether to actually run bibtex to update bbl files. + # This variable is also used in deciding whether to + # delete bbl files in clean up operations. + # 0: Never run bibtex. + # Do NOT delete bbl files on clean up. + # 1: Run bibtex only if the bibfiles exists + # according to kpsewhich, and the bbl files + # appear to be out-of-date. + # Do NOT delete bbl files on clean up. + # 1.5: Run bibtex only if the bibfiles exists + # according to kpsewhich, and the bbl files + # appear to be out-of-date. + # Only delete bbl files on clean up if bibfiles exist. + # 2: Run bibtex when the bbl files are out-of-date + # Delete bbl files on clean up. + # + # In any event bibtex is only run if the log file + # indicates that the document uses bbl files. +$bibtex_fudge = 1; # Whether or not to cd to aux dir when running bibtex. + # If the cd is not done, and bibtex is passed a + # filename with a path component, then it can easily + # happen that (a) bibtex refuses to write bbl and blg + # files to the aux directory, for security reasons, + # and/or (b) bibtex in pre-2019 versions fails to find + # some input file(s). But in some other cases, the cd + # method fails. + +## Command to invoke makeindex +$makeindex = 'makeindex %O -o %D %S'; +# Switch(es) to make makeinex silent: +$makeindex_silent_switch = '-q'; +$makeindex_fudge = 1; # Whether or not to cd to aux dir when running makeindex. + # Set to 1 to avoid security-related prohibition on + # makeindex writing to aux_dir when it is not specified + # as a subdirectory of cwd. + +## Command to convert dvi file to pdf file directly. +# Use option -dALLOWPSTRANSPARENCY so that it works with documents +# using pstricks etc: +$dvipdf = 'dvipdf -dALLOWPSTRANSPARENCY %O %S %D'; +# N.B. Standard dvipdf runs dvips and gs with their silent switch, so for +# standard dvipdf $dvipdf_silent_switch is unneeded, but innocuous. +# But dvipdfmx can be used instead, and it has a silent switch (-q). +# So implementing $dvipdf_silent_switch is useful. +$dvipdf_silent_switch = '-q'; + +## Command to convert dvi file to ps file: +$dvips = 'dvips %O -o %D %S'; +## Command to convert dvi file to ps file in landscape format: +$dvips_landscape = 'dvips -tlandscape %O -o %D %S'; +# Switch(es) to get dvips to make ps file suitable for conversion to good pdf: +# (If this is not used, ps file and hence pdf file contains bitmap fonts +# (type 3), which look horrible under acroread. An appropriate switch +# ensures type 1 fonts are generated. You can put this switch in the +# dvips command if you prefer.) +$dvips_pdf_switch = '-P pdf'; +# Switch(es) to make dvips silent: +$dvips_silent_switch = '-q'; + +## Command to convert ps file to pdf file. +# Use option -dALLOWPSTRANSPARENCY so that it works with documents +# using pstricks etc: +$ps2pdf = 'ps2pdf -dALLOWPSTRANSPARENCY %O %S %D'; + +## Command to convert xdv file to pdf file +$xdvipdfmx = 'xdvipdfmx -E -o %D %O %S'; +$xdvipdfmx_silent_switch = '-q'; + + +## Command to search for tex-related files +$kpsewhich = 'kpsewhich %S'; + +## Command to run make: +$make = 'make'; + +##Printing: +$print_type = 'auto'; # When printing, print the postscript file. + # Possible values: 'dvi', 'ps', 'pdf', 'auto', 'none' + # 'auto' ==> set print type according to the printable + # file(s) being made: priority 'ps', 'pdf', 'dvi' + +# Viewers. These are system dependent, so default to none: +$pdf_previewer = $ps_previewer = $ps_previewer_landscape = $dvi_previewer = $dvi_previewer_landscape = "NONE"; + +$dvi_update_signal = undef; +$ps_update_signal = undef; +$pdf_update_signal = undef; + +$dvi_update_command = undef; +$ps_update_command = undef; +$pdf_update_command = undef; + +$allow_subdir_creation = 1; + +$new_viewer_always = 0; # If 1, always open a new viewer in pvc mode. + # If 0, only open a new viewer if no previous + # viewer for the same file is detected. + +# Commands for use in pvc mode for compiling, success, warnings, and failure; +# they default to empty, i.e., not to use: +$compiling_cmd = $success_cmd = $warning_cmd = $failure_cmd = ""; + +# Commands for printing are highly system dependent, so default to NONE: +$lpr = 'NONE $lpr variable is not configured to allow printing of ps files'; +$lpr_dvi = 'NONE $lpr_dvi variable is not configured to allow printing of dvi files'; +$lpr_pdf = 'NONE $lpr_pdf variable is not configured to allow printing of pdf files'; + + +# The $pscmd below holds a **system-dependent** command to list running +# processes. It is used to find the process ID of the viewer looking at +# the current output file. The output of the command must include the +# process number and the command line of the processes, since the +# relevant process is identified by the name of file to be viewed. +# Its use is not essential. +$pscmd = 'NONE $pscmd variable is not configured to detect running processes'; +$pid_position = -1; # offset of PID in output of pscmd. + # Negative means I cannot use ps + + +$quote_filenames = 1; # Quote filenames in external commands + +$del_dir = ''; # Directory into which cleaned up files are to be put. + # If $del_dir is '', just delete the files + +@rc_system_files = (); + +######################################################################### + +################################################################ +## Special variables for system-dependent fudges, etc. +$log_file_binary = 0; # Whether to treat log file as binary + # Normally not, since the log file SHOULD be pure text. + # But Miktex 2.7 sometimes puts binary characters + # in it. (Typically in construct \OML ... after + # overfull box with mathmode.) + # Sometimes there is ctrl/Z, which is not only non-text, + # but is end-of-file marker for MS-Win in text mode. + +$MSWin_fudge_break = 1; # Give special treatment to ctrl/C and ctrl/break + # in -pvc mode under MSWin + # Under MSWin32 (at least with perl 5.8 and WinXP) + # when latexmk is running another program, and the + # user gives ctrl/C or ctrl/break, to stop the + # daughter program, not only does it reach + # the daughter, but also latexmk/perl, so + # latexmk is stopped also. In -pvc mode, + # this is not normally desired. So when the + # $MSWin_fudge_break variable is set, + # latexmk arranges to ignore ctrl/C and + # ctrl/break during processing of files; + # only the daughter programs receive them. + # This fudge is not applied in other + # situations, since then having latexmk also + # stopping because of the ctrl/C or + # ctrl/break signal is desirable. + # The fudge is not needed under UNIX (at least + # with Perl 5.005 on Solaris 8). Only the + # daughter programs receive the signal. In + # fact the inverse would be useful: In + # normal processing, as opposed to -pvc, if + # force mode (-f) is set, a ctrl/C is + # received by a daughter program does not + # also stop latexmk. Under tcsh, we get + # back to a command prompt, while latexmk + # keeps running in the background! + +## Substitute backslashes in file and directory names for +## MSWin command line +$MSWin_back_slash = 1; + +## Separator of elements in search_path. Default is unix value +$search_path_separator = ':'; + + +# Directory for temporary files. Default to current directory. +$tmpdir = "."; + + +# When the aux_dir is on a network share (or the like), its system +# time may differ from the system time on which latexmk is running. +# This complicates the tests of whether particular files have been +# made in a current run of a program or are left over from a previous +# run. One test, which is needed under some situations, is that a +# file was made on a previous run when the files modification time is +# less than the system time when the program is started. (See +# subroutine test_gen_file; this is only needed in a couple of +# situations.) The comparison between file and system times must be +# corrected if there is an offset between system times on the computer +# running latexmk and the computer hosting the file system containing +# aux_dir. The offset is measured in subroutine get_filetime_offset +# by writing a temporary file; the test only needs to be done once. +# +# The following variables are used. Since the system-independent +# values of system and file time are only accurate to a second (or 2 +# seconds for FAT file systems), the offset is also accurate only to a +# second or two. So thresholds are needed below which differences +# are insignificant. +# +# Note that the making or not making of a file is controlled by the +# state of the document being compiled and by latexmk's configuration. +# So a file that is left over from a previous run and not overwritten +# on the current run will have a file time at least many seconds less +# than the current time, corresponding to the time scale for a human +# run-edit-run cycle. +# +$filetime_offset_measured = 0; # Measurement not yet done. +$filetime_offset = 0; # Filetime relative to system time. +$filetime_causality_threshold = 5; # Threshold for detection of left-over file. + # Should be non-negative always, and should + # be bigger than 2 secs if a remote + # filesystem or network share is used. +$filetime_offset_report_threshold = 30; # Threshold beyond which filetime offsets + # are reported; large offsets indicate + # incorrect system time on at least one system. + + +################################################################ + + +# System-dependent overrides: +# Currently, the cases I have tests for are: MSWin32, cygwin, linux and +# darwin, msys, with the main complications being for MSWin32 and cygwin. +# Further special treatment may also be useful for MSYS (for which $^O reports +# "msys"). This is another *nix-emulation/system for MSWindows. At +# present it is treated as unix-like, but the environment variables +# are those of Windows. (The test for USERNAME as well as USER was +# to make latexmk work under MSYS's perl.) +# +if ( $^O eq "MSWin32" ) { +# Pure MSWindows configuration + ## Configuration parameters: + + ## Use first existing case for $tmpdir: + $tmpdir = $ENV{TMPDIR} || $ENV{TEMP} || '.'; + $log_file_binary = 1; # Protect against ctrl/Z in log file from + # Miktex 2.7. + + ## List of possibilities for the system-wide initialization file. + ## The first one found (if any) is used. + @rc_system_files = ( "C:/latexmk/LatexMk", "C:/latexmk/latexmkrc" ); + + $search_path_separator = ';'; # Separator of elements in search_path + + # For a pdf-file, "start x.pdf" starts the pdf viewer associated with + # pdf files, so no program name is needed: + $pdf_previewer = 'start %O %S'; + $ps_previewer = 'start %O %S'; + $ps_previewer_landscape = $ps_previewer; + $dvi_previewer = 'start %O %S'; + $dvi_previewer_landscape = "$dvi_previewer"; + # Viewer update methods: + # 0 => auto update: viewer watches file (e.g., gv) + # 1 => manual update: user must do something: e.g., click on window. + # (e.g., ghostview, MSWIN previewers, acroread under UNIX) + # 2 => send signal. Number of signal in $dvi_update_signal, + # $ps_update_signal, $pdf_update_signal + # 3 => viewer can't update, because it locks the file and the file + # cannot be updated. (acroread under MSWIN) + # 4 => run a command to force the update. The commands are + # specified by the variables $dvi_update_command, + # $ps_update_command, $pdf_update_command + $dvi_update_method = 1; + $ps_update_method = 1; + $pdf_update_method = 3; # acroread locks the pdf file +} +elsif ( $^O eq "cygwin" ) { + # The problem is a mixed MSWin32 and UNIX environment. + # Perl decides the OS is cygwin in two situations: + # 1. When latexmk is run from a cygwin shell under a cygwin + # environment. Perl behaves in a UNIX way. This is OK, since + # the user is presumably expecting UNIXy behavior. + # 2. When CYGWIN exectuables are in the path, but latexmk is run + # from a native NT shell. Presumably the user is expecting NT + # behavior. But perl behaves more UNIXy. This causes some + # clashes. + # The issues to handle are: + # 1. Perl sees both MSWin32 and cygwin filenames. This is + # normally only an advantage. + # 2. Perl uses a UNIX shell in the system command + # This is a nasty problem: under native NT, there is a + # start command that knows about NT file associations, so that + # we can do, e.g., (under native NT) system("start file.pdf"); + # But this won't work when perl has decided the OS is cygwin, + # even if it is invoked from a native NT command line. An + # NT command processor must be used to deal with this. + # 3. External executables can be native NT (which only know + # NT-style file names) or cygwin executables (which normally + # know both cygwin UNIX-style file names and NT file names, + # but not always; some do not know about drive names, for + # example). + # Cygwin executables for tex and latex may only know cygwin + # filenames. + # 4. The BIBINPUTS environment variables may be + # UNIX-style or MSWin-style depending on whether native NT or + # cygwin executables are used. They are therefore parsed + # differently. Here is the clash: + # a. If a user is running under an NT shell, is using a + # native NT installation of tex (e.g., fptex or miktex), + # but has the cygwin executables in the path, then perl + # detects the OS as cygwin, but the user needs NT + # behavior from latexmk. + # b. If a user is running under an UNIX shell in a cygwin + # environment, and is using the cygwin installation of + # tex, then perl detects the OS as cygwin, and the user + # needs UNIX behavior from latexmk. + # Latexmk has no way of detecting the difference. The two + # situations may even arise for the same user on the same + # computer simply by changing the order of directories in the + # path environment variable + + + ## Configuration parameters: We'll assume native NT executables. + ## The user should override if they are not. + + # This may fail: perl converts MSWin temp directory name to cygwin + # format. Names containing this string cannot be handled by native + # NT executables. + $tmpdir = $ENV{TMPDIR} || $ENV{TEMP} || '.'; + + ## List of possibilities for the system-wide initialization file. + ## The first one found (if any) is used. + ## We could stay with MSWin files here, since cygwin perl understands them + ## @rc_system_files = ( 'C:/latexmk/LatexMk', 'C:/latexmk/latexmkrc' ); + ## But they are deprecated in v. 1.7. So use the UNIX version, prefixed + ## with a cygwin equivalent of the MSWin location + ## In addition, we need to add the same set of possible locations as with + ## unix, so that the user use a unix-style setup. + @rc_system_files = (); + foreach ( 'LatexMk', 'latexmkrc' ) { + push @rc_system_files, + ( "/cygdrive/c/latexmk/$_", + "/etc/$_", + "/opt/local/share/latexmk/$_", + "/usr/local/share/latexmk/$_", + "/usr/local/lib/latexmk/$_" ); + } + $search_path_separator = ';'; # Separator of elements in search_path + # This is tricky. The search_path_separator depends on the kind + # of executable: native NT v. cygwin. + # So the user will have to override this. + + # We will assume that files can be viewed by native NT programs. + # Then we must fix the start command/directive, so that the + # NT-native start command of a cmd.exe is used. + # For a pdf-file, "start x.pdf" starts the pdf viewer associated with + # pdf files, so no program name is needed: + $start_NT = "cmd /c start \"\""; + $pdf_previewer = "$start_NT %O %S"; + $ps_previewer = "$start_NT %O %S"; + $ps_previewer_landscape = $ps_previewer; + $dvi_previewer = "$start_NT %O %S"; + $dvi_previewer_landscape = $dvi_previewer; + # Viewer update methods: + # 0 => auto update: viewer watches file (e.g., gv) + # 1 => manual update: user must do something: e.g., click on window. + # (e.g., ghostview, MSWIN previewers, acroread under UNIX) + # 2 => send signal. Number of signal in $dvi_update_signal, + # $ps_update_signal, $pdf_update_signal + # 3 => viewer can't update, because it locks the file and the file + # cannot be updated. (acroread under MSWIN) + $dvi_update_method = 1; + $ps_update_method = 1; + $pdf_update_method = 3; # acroread locks the pdf file +} +elsif ( $^O eq "msys" ) { + $search_path_separator = ';'; # Separator of elements in search_path + # I think MS-Win value is OK, since + # msys is running under MS-Win + $pdf_previewer = q[sh -c 'start %S']; + $ps_previewer = q[sh -c 'start %S']; + $dvi_previewer = q[sh -c 'start %S']; + $ps_previewer_landscape = $ps_previewer; + $dvi_previewer_landscape = "$dvi_previewer"; +} +else { + # Assume anything else is UNIX or clone + # Do special cases (e.g., linux, darwin (i.e., OS-X)) inside this block. + + ## Use first existing case for $tmpdir: + $tmpdir = $ENV{TMPDIR} || '/tmp'; + + ## List of possibilities for the system-wide initialization file. + ## The first one found (if any) is used. + @rc_system_files = (); + foreach ( 'LatexMk', 'latexmkrc' ) { + push @rc_system_files, + ( "/etc/$_", + "/opt/local/share/latexmk/$_", + "/usr/local/share/latexmk/$_", + "/usr/local/lib/latexmk/$_" ); + } + $search_path_separator = ':'; # Separator of elements in search_path + + $dvi_update_signal = $signo{USR1} + if ( defined $signo{USR1} ); # Suitable for xdvi + $ps_update_signal = $signo{HUP} + if ( defined $signo{HUP} ); # Suitable for gv + $pdf_update_signal = $signo{HUP} + if ( defined $signo{HUP} ); # Suitable for gv + ## default document processing programs. + # Viewer update methods: + # 0 => auto update: viewer watches file (e.g., gv) + # 1 => manual update: user must do something: e.g., click on window. + # (e.g., ghostview, MSWIN previewers, acroread under UNIX) + # 2 => send signal. Number of signal in $dvi_update_signal, + # $ps_update_signal, $pdf_update_signal + # 3 => viewer can't update, because it locks the file and the file + # cannot be updated. (acroread under MSWIN) + # 4 => Run command to update. Command in $dvi_update_command, + # $ps_update_command, $pdf_update_command. + $dvi_previewer = 'start see %O %S'; + $dvi_previewer_landscape = 'start see %O %S'; + if ( defined $dvi_update_signal ) { + $dvi_update_method = 2; # xdvi responds to signal to update + } else { + $dvi_update_method = 1; + } + # lets hope dvi viewer updates automatically + $dvi_update_method = 0; +# if ( defined $ps_update_signal ) { +# $ps_update_method = 2; # gv responds to signal to update +# $ps_previewer = 'start gv -nowatch'; +# $ps_previewer_landscape = 'start gv -swap -nowatch'; +# } else { +# $ps_update_method = 0; # gv -watch watches the ps file +# $ps_previewer = 'start gv -watch'; +# $ps_previewer_landscape = 'start gv -swap -watch'; +# } + # Turn off the fancy options for gv. Regular gv likes -watch etc + # GNU gv likes --watch etc. User must configure + $ps_update_method = 0; # gv -watch watches the ps file + $ps_previewer = 'start see %O %S'; + $ps_previewer_landscape = 'start see %O %S'; + $pdf_previewer = 'start see %O %S'; + $pdf_update_method = 0; # let us hope that the selected viewer does automatic updates + $lpr = 'lpr %O %S'; # Assume lpr command prints postscript files correctly + $lpr_dvi = + 'NONE $lpr_dvi variable is not configured to allow printing of dvi files'; + $lpr_pdf = + 'NONE $lpr_pdf variable is not configured to allow printing of pdf files'; + # The $pscmd below holds a command to list running processes. It + # is used to find the process ID of the viewer looking at the + # current output file. The output of the command must include the + # process number and the command line of the processes, since the + # relevant process is identified by the name of file to be viewed. + # Uses: + # 1. In preview_continuous mode, to save running a previewer + # when one is already running on the relevant file. + # 2. With xdvi in preview_continuous mode, xdvi must be + # signalled to make it read a new dvi file. + # + # The following works on Solaris, LINUX, HP-UX, IRIX + # Use -f to get full listing, including command line arguments. + # Use -u $ENV{USER} to get all processes started by current user (not just + # those associated with current terminal), but none of other users' + # processes. + # However, the USER environment variable may not exist. Windows uses + # USERNAME instead. (And this propagates to a situation of + # unix-emulation software running under Windows.) + if ( exists $ENV{USER} ) { + $pscmd = "ps -f -u $ENV{USER}"; + } + elsif ( exists $ENV{USERNAME} ) { + $pscmd = "ps -f -u $ENV{USERNAME}"; + } + else { + $pscmd = "ps -f"; + } + $pid_position = 1; # offset of PID in output of pscmd; first item is 0. + if ( $^O eq "linux" ) { + # Ps on Redhat (at least v. 7.2) appears to truncate its output + # at 80 cols, so that a long command string is truncated. + # Fix this with the --width option. This option works under + # other versions of linux even if not necessary (at least + # for SUSE 7.2). + # However the option is not available under other UNIX-type + # systems, e.g., Solaris 8. + # But (19 Aug 2010), the truncation doesn't happen on RHEL4 and 5, + # unless the output is written to a terminal. So the --width + # option is now unnecessary + # $pscmd = "ps --width 200 -f -u $ENV{USER}"; + } + elsif ( $^O eq "darwin" ) { + # OS-X on Macintosh + # open starts command associated with a file. + # For pdf, this is set by default to OS-X's preview, which is suitable. + # Manual update is simply by clicking on window etc, which is OK. + # For ps, this is set also to preview. This works, but since it + # converts the file to pdf and views the pdf file, it doesn't + # see updates, and a refresh cannot be done. This is far from + # optimal. + # For a full installation of MacTeX, which is probably the most common + # on OS-X, an association is created between dvi files and TeXShop. + # This also converts the file to pdf, so again while it works, it + # does not deal with changed dvi files, as far as I can see. + $pdf_previewer = 'open %S'; + $pdf_update_method = 1; # manual + $dvi_previewer = $dvi_previewer_landscape = 'NONE'; + $ps_previewer = $ps_previewer_landscape = 'NONE'; + # Others + $lpr_pdf = 'lpr %O %S'; + $pscmd = "ps -ww -u $ENV{USER}"; + } +} + +## default parameters +$auto_rc_use = 1; # Whether to read rc files automatically +$max_repeat = 5; # Maximum times I repeat latex. Normally + # 3 would be sufficient: 1st run generates aux file, + # 2nd run picks up aux file, and maybe toc, lof which + # contain out-of-date information, e.g., wrong page + # references in toc, lof and index, and unresolved + # references in the middle of lines. But the + # formatting is more-or-less correct. On the 3rd + # run, the page refs etc in toc, lof, etc are about + # correct, but some slight formatting changes may + # occur, which mess up page numbers in the toc and lof, + # Hence a 4th run is conceivably necessary. + # At least one document class (JHEP.cls) works + # in such a way that a 4th run is needed. + # We allow an extra run for safety for a + # maximum of 5. Needing further runs is + # usually an indication of a problem; further + # runs may not resolve the problem, and + # instead could cause an infinite loop. +$clean_ext = ""; # space separated extensions of files that are + # to be deleted when doing cleanup, beyond + # standard set +$clean_full_ext = ""; # space separated extensions of files that are + # to be deleted when doing cleanup_full, beyond + # standard set and those in $clean_ext +@cus_dep_list = (); # Custom dependency list +@default_files = ( '*.tex' ); # Array of LaTeX files to process when + # no files are specified on the command line. + # Wildcards allowed + # Best used for project specific files. +@default_excluded_files = ( ); + # Array of LaTeX files to exclude when using + # @default_files, i.e., when no files are specified + # on the command line. + # Wildcards allowed + # Best used for project specific files. +$texfile_search = ""; # Specification for extra files to search for + # when no files are specified on the command line + # and the @default_files variable is empty. + # Space separated, and wildcards allowed. + # These files are IN ADDITION to *.tex in current + # directory. + # This variable is obsolete, and only in here for + # backward compatibility. + +$fdb_ext = 'fdb_latexmk'; # Extension for the file for latexmk's + # file-database + # Make it long to avoid possible collisions. +$fdb_ver = 3; # Version number for kind of fdb_file. + +$jobname = ''; # Jobname: as with current tex, etc indicates + # basename of generated files. Defined so + # that --jobname=STRING on latexmk's command + # line has same effect as with current tex, + # etc, with the exception listed below. (If + # $jobname is non-empty, then the + # --jobname=... option is used on tex.) + # Extension: $jobname is allowed to contain + # placeholder(s) (currently only %A), + # which allows construction of jobnames + # dependent on name of main TeX file; this is + # useful when a jobname is used and latexmk is + # invoked on multiple files. +$out_dir = ''; # Directory for output files. + # Cf. --output-directory of current *latex + # Blank means default, i.e., cwd. +$aux_dir = ''; # Directory for aux files (log, aux, etc). + # Cf. --aux-directory of current *latex in MiKTeX. + # Blank means default, i.e., same as $out_dir. + # Note that these values get modified when + # processing a .tex file. + +## default flag settings. +$recorder = 1; # Whether to use recorder option on latex/pdflatex +$silent = 0; # Whether fo silence latex's messages (and others) +$warnings_as_errors = 0;# Treat warnings as errors and exit with non-zero exit code +$silence_logfile_warnings = 0; # Do list warnings in log file +$rc_report = 1; # Whether to report on rc files read +$aux_out_dir_report = 0; # Whether to report on aux_dir & out_dir after + # initialization and normalization + +$kpsewhich_show = 0; # Show calls to and results from kpsewhich +$landscape_mode = 0; # default to portrait mode +$analyze_input_log_always = 1; # Always analyze .log for input files in the + # <...> and (...) constructions. Otherwise, only + # do the analysis when fls file doesn't exist or is + # out of date. + # Under normal circumstances, the data in the fls file + # is reliable, and the test of the log file gets lots + # of false positives; usually $analyze_input_log_always + # is best set to zero. But the test of the log file + # is needed at least in the following situation: + # When a user needs to persuade latexmk that a certain + # file is a source file, and latexmk doesn't otherwise + # find it. User code causes line with (...) to be + # written to log file. One important case is for + # lualatex, which doesn't always generate lines in the + # .fls file for input lua files. (The situation with + # lualatex is HIGHLY version dependent, e.g., between + # 2016 and 2017.) + # To keep backward compatibility with older versions + # of latexmk, the default is to set + # $analyze_input_log_always to 1. + +# The following two arrays contain lists of extensions (without +# period) for files that are read in during a *LaTeX run but that +# are generated automatically from the previous run, as opposed to +# being user generated files (directly or indirectly from a custom +# dependency). These files get two kinds of special treatment: +# 1. In clean up, where depending on the kind of clean up, some +# or all of these generated files are deleted. +# (Note that special treatment is given to aux files.) +# 2. In analyzing the results of a run of *LaTeX, to +# determine if another run is needed. With an error free run, +# a rerun should be provoked by a change in any source file, +# whether a user file or a generated file. But with a run +# that ends in an error, only a change in a user file during +# the run (which might correct the error) should provoke a +# rerun, but a change in a generated file should not. +# These arrays can be user-configured. + +@generated_exts = ( 'aux', 'bcf', 'fls', 'idx', 'ind', 'lof', 'lot', + 'out', 'toc' ); + # N.B. 'out' is generated by hyperref package + +# Which kinds of file do I have requests to make? +# If no requests at all are made, then I will make dvi file +# If particular requests are made then other files may also have to be +# made. E.g., ps file requires a dvi file +$dvi_mode = 0; # No dvi file requested +$postscript_mode = 0; # No postscript file requested +$pdf_mode = 0; # No pdf file requested to be made by pdflatex + # Possible values: + # 0 don't create pdf file + # 1 to create pdf file by pdflatex + # 2 to create pdf file by ps2pdf + # 3 to create pdf file by dvipdf + # 4 to create pdf file by lualatex + # 5 to create pdf file by xelatex + xdvipdfmx +$view = 'default'; # Default preview is of highest of dvi, ps, pdf +$sleep_time = 2; # time to sleep b/w checks for file changes in -pvc mode +$banner = 0; # Non-zero if we have a banner to insert +$banner_scale = 220; # Original default scale +$banner_intensity = 0.95; # Darkness of the banner message +$banner_message = 'DRAFT'; # Original default message +$do_cd = 0; # Do not do cd to directory of source file. + # Thus behave like latex. +$dependents_list = 0; # Whether to display list(s) of dependencies +$dependents_phony = 0; # Whether list(s) of dependencies includes phony targets + # (as with 'gcc -MP'). +$deps_file = '-'; # File for dependency list output. Default stdout. +$rules_list = 0; # Whether to display list(s) of dependencies +@dir_stack = (); # Stack of pushed directories, each of form of + # pointer to array [ cwd, good_cwd ], where + # good_cwd differs from cwd by being converted + # to native MSWin path when cygwin is used. +$cleanup_mode = 0; # No cleanup of nonessential LaTex-related files. + # $cleanup_mode = 0: no cleanup + # $cleanup_mode = 1: full cleanup + # $cleanup_mode = 2: cleanup except for dvi, + # dviF, pdf, ps, psF & xdv +$cleanup_fdb = 0; # No removal of file for latexmk's file-database +$cleanup_only = 0; # When doing cleanup, do not go on to making files +$cleanup_includes_generated = 0; + # Determines whether cleanup deletes files generated by + # *latex (found from \openout lines in log file). + # It's more than that. BUG +$cleanup_includes_cusdep_generated = 0; + # Determines whether cleanup deletes files generated by + # custom dependencies +$diagnostics = 0; +$dvi_filter = ''; # DVI filter command +$ps_filter = ''; # Postscript filter command + +$force_mode = 0; # =1 to force processing past errors +$go_mode = 0; # =1 to force processing regardless of time-stamps + # =2 full clean-up first +$preview_mode = 0; +$preview_continuous_mode = 0; +$printout_mode = 0; # Don't print the file + +## Control pvc inactivity timeout: +$pvc_timeout = 0; +$pvc_timeout_mins = 30; + +$show_time = 0; +@timings = (); +$processing_time1 = processing_time(); + +$use_make_for_missing_files = 0; # Whether to use make to try to make missing files. + +# Do we make view file in temporary then move to final destination? +# (To avoid premature updating by viewer). +$always_view_file_via_temporary = 0; # Set to 1 if viewed file is always + # made through a temporary. +$pvc_view_file_via_temporary = 1; # Set to 1 if only in -pvc mode is viewed + # file made through a temporary. + +# State variables initialized here: + +$updated = 0; # Flags when something has been remade + # Used to allow convenient user message in -pvc mode +$waiting = 0; # Flags whether we are in loop waiting for an event + # Used to avoid unnecessary repeated o/p in wait loop + +# The following are used for some results of parsing log file +# Global variables, so results can be reported in main program. +$reference_changed = 0; +$mult_defined = 0; +$bad_reference = 0; +$bad_character = 0; +$bad_citation = 0; +@primary_warning_summary = (); + +# Cache of expensive-to-compute state variables, e.g., cwd in form +# fixed to deal with cygwin issues. +%cache = (); +&cache_good_cwd; + +# Set search paths for includes. +# Set them early so that they can be overridden +$BIBINPUTS = $ENV{'BIBINPUTS'}; +if (!$BIBINPUTS) { $BIBINPUTS = '.'; } + +# Convert search paths to arrays: +# If any of the paths end in '//' then recursively search the +# directory. After these operations, @BIBINPUTS should +# have all the directories that need to be searched + +@BIBINPUTS = find_dirs1( $BIBINPUTS ); + + +###################################################################### +###################################################################### +# +# ??? UPDATE THE FOLLOWING!! +# +# We will need to determine whether source files for runs of various +# programs are out of date. In a normal situation, this is done by +# asking whether the times of the source files are later than the +# destination files. But this won't work for us, since a common +# situation is that a file is written on one run of latex, for +# example, and read back in on the next run (e.g., an .aux file). +# Some situations of this kind are standard in latex generally; others +# occur with particular macro packages or with particular +# postprocessors. +# +# The correct criterion for whether a source is out-of-date is +# therefore NOT that its modification time is later than the +# destination file, but whether the contents of the source file have +# changed since the last successful run. This also handles the case +# that the user undoes some changes to a source file by replacing the +# source file by reverting to an earlier version, which may well have +# an older time stamp. Since a direct comparison of old and new files +# would involve storage and access of a large number of backup files, +# we instead use the md5 signature of the files. (Previous versions +# of latexmk used the backup file method, but restricted to the case +# of .aux and .idx files, sufficient for most, but not all, +# situations.) +# +# We will have a database of (time, size, md5) for the relevant +# files. If the time and size of a file haven't changed, then the file +# is assumed not to have changed; this saves us from having to +# determine its md5 signature, which would involve reading the whole +# file, which is naturally time-consuming, especially if network file +# access to a server is needed, and many files are involved, when most +# of them don't change. It is of course possible to change a file +# without changing its size, but then to adjust its timestamp +# to what it was previously; this requires a certain amount of +# perversity. We can safely assume that if the user edits a file or +# changes its contents, then the file's timestamp changes. The +# interesting case is that the timestamp does change, because the file +# has actually been written to, but that the contents do not change; +# it is for this that we use the md5 signature. However, since +# computing the md5 signature involves reading the whole file, which +# may be large, we should avoid computing it more than necessary. +# +# So we get the following structure: +# +# 1. For each relevant run (latex, pdflatex, each instance of a +# custom dependency) we have a database of the state of the +# source files that were last used by the run. +# 2. On an initial startup, the database for a primary tex file +# is read that was created by a previous run of latex or +# pdflatex, if this exists. +# 3. If the file doesn't exist, then the criterion for +# out-of-dateness for an initial run is that it goes by file +# timestamps, as in previous versions of latexmk, with due +# (dis)regard to those files that are known to be generated by +# latex and re-read on the next run. +# 4. Immediately before a run, the database is updated to +# represent the current conditions of the run's source files. +# 5. After the run, it is determined whether any of the source +# files have changed. This covers both files written by the +# run, which are therefore in a dependency loop, and files that +# the user may have updated during the run. (The last often +# happens when latex takes a long time, for a big document, +# and the user makes edits before latex has finished. This is +# particularly prevalent when latexmk is used with +# preview-continuous mode.) +# 6. In the case of latex or pdflatex, the custom dependencies +# must also be checked and redone if out-of-date. +# 7. If any source files have changed, the run is redone, +# starting at step 1. +# 8. There is naturally a limit on the number of reruns, to avoid +# infinite loops from bugs and from pathological or unforeseen +# conditions. +# 9. After the run is done, the run's file database is updated. +# (By hypothesis, the sizes and md5s are correct, if the run +# is successful.) +# 10. To allow reuse of data from previous runs, the file database +# is written to a file after every complete set of passes +# through latex or pdflatex. (Note that there is separate +# information for latex and pdflatex; the necessary +# information won't coincide: Out-of-dateness for the files +# for each program concerns the properties of the files when +# the other program was run, and the set of source files could +# be different, e.g., for graphics files.) +# +# We therefore maintain the following data structures.: +# +# a. For each run (latex, pdflatex, each custom dependency) a +# database is maintained. This is a hash from filenames to a +# reference to an array: [time, size, md5]. The semantics of +# the database is that it represents the state of the source +# files used in the run. During a run it represents the state +# immediately before the run; after a run, with all reruns, it +# represents the state of the files used, modified by having +# the latest timestamps for generated files. +# b. There is a global database for all files, which represents +# the current state. This saves having to recompute the md5 +# signatures of a changed file used in more than one run +# (e.g., latex and pdflatex). +# c. Each of latex and pdflatex has a list of the relevant custom +# dependencies. +# +# In all the following a fdb-hash is a hash of the form: +# filename -> [time, size, md5] +# If a file is found to disappear, its entry is removed from the hash. +# In returns from fdb access routines, a size entry of -1 indicates a +# non-existent file. + + +# List of known rules. Rule types: primary, +# external (calls program), internal (calls routine), cusdep. + +%possible_primaries = ( 'latex' => 'primary', 'pdflatex' => 'primary', + 'lualatex' => 'primary', 'xelatex' => 'primary' ); + +# Hashes, whose keys give names of particular kinds of rule, and targets. +# We use hashes for ease of lookup. +%possible_one_time = ( 'view' => 1, 'print' => 1, 'update_view' => 1, ); +%target_files = (); # Hash for target files. + # The keys are the filenames and the value is + # currently irrelevant. +%target_rules = (); # Hash for target rules beyond those corresponding to files. + # The keys are the rule names and the value is + # currently irrelevant. +# The target **files** can only be set inside the FILE loop. +$current_primary = 'latex'; # Rule to compile .tex file. + # Subject to document-dependent override if .tex document + # uses metcommands andobeying them is enabled. +$pdf_method = ''; # How to make pdf file. '' if not requested, + # else 'ps2pdf', 'dvipdf', 'pdflatex', 'lualatex' or 'xelatex' + # Subject to document-dependent override if .tex document + #uses \pdfoutput or c. +%requested_filetypes = (); # Hash of requested file types (dvi, dviF, etc) +%one_time = (); # Hash for requested one-time-only rules, currently + # possible values 'print' and 'view'. + +%actives = (); # Hash of active rules + +$allow_switch = 1; # Allow switch of rule structure to accommodate + # changed output file name of primary. Even if + # this flag is set on, the switch may be + # prohibited by other issues. + +%rule_db = (); # Database of all rules: + # Hash: rulename -> [array of rule data] + # Rule data: + # 0: [ cmd_type, ext_cmd, int_cmd, test_kind, + # source, dest, base, + # out_of_date, out_of_date_user, + # time_of_last_run, time_of_last_file_check, + # changed + # last_result, last_message, + # default_extra_generated, + # ] + # where + # cmd_type is 'primary', 'external', or 'cusdep' + # ext_cmd is string for associated external command + # with substitutions (%D for destination, %S + # for source, %B for base of current rule, + # %R for base of primary tex file, %T for + # texfile name, %O for options, + # %V=$aux_dir, %W=$out_dir, + # %Y for $aux_dir1, and %Z for $out_dir1 + # int_cmd specifies any internal command to be + # used to implement the application of the + # rule. If this is present, it overrides + # **direct** execution of the external command, and + # it is the responsibility of the perl subroutine + # specified in intcmd to execute the specified + # external command if this is appropriate. + # This variable intcmd is a reference to an array, + # $$intcmd[0] = internal routine + # $$intcmd[1...] = its arguments (if any) + # test_kind specifies method of determining + # whether a file is out-of-date: + # 0 for never + # 1 for usual: whether there is a source + # file change + # 2 for dest earlier than source + # 3 for method 2 at first run, 1 thereafter + # (used when don't have file data from + # previous run). + # source = name of primary source file, if any + # dest = name of primary destination file, + # if any + # base = base name, if any, of files for + # this rule + # out_of_date = 1 if it has been detected that + # this rule needs to be run + # (typically because a source + # file has changed). + # Other values may be used for special cases. + # 0 otherwise + # out_of_date_user is like out_of_date, except + # that the detection of out-of-dateness + # has been made from a change of a + # putative user file, i.e., one that is + # not a generated file (e.g., aux). This + # kind of out-of-dateness should provoke a + # rerun whether or not there was an error + # during a run of *LaTeX. Normally, + # if there is an error, one should wait + # for the user to correct the error. But + # it is possible the error condition is + # already corrected during the run, e.g., + # by the user changing a source file in + # response to an error message. + # time_of_last_run = time that this rule was + # last applied. (In standard units + # from perl, to be directly compared + # with file modification times.) + # time_of_last_file_check = last time that a check + # was made for changes in source files. + # changed flags whether special changes have been made + # that require file-existence status to be ignored + # last_result is + # -1 if no run has been made, + # 0 if the last run was successful + # 1 if last run was successful, but + # failed to create an output file + # 2 if last run failed + # 200 if last run gave a warning that is + # important enough to be reported with + # the error summary. The warning + # message is stored in last_message. + # last_message is error message for last run + # default_extra_generated is a reference to an array + # of specifications of extra generated files (beyond + # the main dest file. Standard place holders are used. + # 1: {Hash sourcefile -> [source-file data] } + # Source-file data array: + # 0: time + # 1: size + # 2: md5 + # 3: name of rule to make this file + # 4: whether the file is of the kind made by epstopdf.sty + # during a primary run. It will have been read during + # the run, so that even though the file changes during + # a primary run, there is no need to trigger another + # run because of this. + # Size and md5 correspond to the values at the last run. + # But time may be updated to correspond to the time + # for the file, if the file is otherwise unchanged. + # This saves excessive md5 calculations, which would + # otherwise be done everytime the file is checked, + # in the following situation: + # When the file has been rewritten after a run + # has started (commonly aux, bbl files etc), + # but the actual file contents haven't + # changed. Then because the filetime has + # changed, on every file-change check latexmk + # would normally redo the md5 calculation to + # test for actual changes. Once one such + # check is done, and the contents are + # unchanged, later checks are superfluous, and + # can be avoided by changing the file's time + # in the source-file list. + # 2: {Hash generated_file -> 1 } + # This lists all generated files; the values + # are currently unused, only the keys + # 3: {Hash source_rule -> last_pass } + # This lists rules that are to be considered source + # rules for the current rule, separately from the + # from_rules of the source files. It maps the name + # of each of these rules to the pass number of the + # current rule when it was last run. The current rule + # is out-of-date if the last_pass for a source rule + # is less than the pass number for the rule. + # The purpose of this is when the source file list + # is expected to be inaccurate, because the source + # files are hard to determine. Typical needs are + # for rules applied to dvi and xdv files, when + # graphics files are involved. Their names are coded + # inside the dvi/xdv file, but not the contents. + # It would need parsing of the contents of the file + # to determine the actual source files. + # An implication of using a source_rule is that this + # rule passes files to the current rule and that the + # current rule can be considered out-of-date whenever + # the source_rule has been run. Effectively these + # files are unconditionallyconsidered changed when + # the source_rule runs. + +%fdb_current = (); # Hash of information for all files used. + # It maps filename to a reference to an array + # (time, size, md5_checksum). +@nofile = (0,-1,0); # What we use for initializing a new entry in fdb + # or flagging non-existent file. + +# The following provide information about the structure of the network of rules +# and files. They are set by the routine rdb_set_rule_net +%from_rules = (); # Used to optimize test for whether a file is generated. + # This maps files to rules that generate them. (Files + # anywhere in %$PHdest.) +%from_rules_main = (); # Used to optimize test for whether a file is generated. + # This maps files to rules that generate them as the + # MAIN output. (I.e., file $$Pdest only.) +# Classification of rules, for determining order of application +%current_primaries = (); # Keys are primary rules (latex, etc) that are currently in use. +@pre_primary = (); # Array of rules that are thought of as pre-primary +@post_primary = (); # Array of rules that are thought of as post-primary +@unusual_one_time = (); # Array of rules that are special cases of one-time rules. + # Currently not used. + + +# User's home directory +$HOME = ''; +if (exists $ENV{'HOME'} ) { + $HOME = $ENV{'HOME'}; +} +elsif (exists $ENV{'USERPROFILE'} ) { + $HOME = $ENV{'USERPROFILE'}; +} +# XDG configuration home +$XDG_CONFIG_HOME = ''; +if (exists $ENV{'XDG_CONFIG_HOME'} ) { + $XDG_CONFIG_HOME = $ENV{'XDG_CONFIG_HOME'}; +} +elsif ($HOME ne '') { + if ( -d "$HOME/.config") { + $XDG_CONFIG_HOME = "$HOME/.config"; + } +} + + +#================================================== + +# Which rc files did I read? +@rc_files_read = (); + +# Options that are to be obeyed before rc files are read: +foreach $_ ( @ARGV ) +{ + if (/^-{1,2}norc$/ ) { + $auto_rc_use = 0; + } +} + +#================================================== +## Read rc files with this subroutine + +sub read_first_rc_file_in_list { + foreach my $rc_file ( @_ ) { + #print "===Testing for rc file \"$rc_file\" ...\n"; + if ( -d $rc_file ) { + warn "$My_name: I have found a DIRECTORY named \"$rc_file\".\n", + " Have you perhaps misunderstood latexmk's documentation?\n", + " This name is normally used for a latexmk configuration (rc) file,\n", + " and in that case it should be a regular text file, not a directory.\n"; + } + elsif ( -e $rc_file ) { + process_rc_file( $rc_file ); + return; + } + } +} + +# Note that each rc file may unset $auto_rc_use to +# prevent lower-level rc files from being read. +# So test on $auto_rc_use in each case. +if ( $auto_rc_use ) { + # System rc file: + if (exists $ENV{LATEXMKRCSYS} ) { + unshift @rc_system_files, $ENV{LATEXMKRCSYS}; + if ( !-e $ENV{LATEXMKRCSYS} ) { + warn "$My_name: you've specified a system rc file `$ENV{LATEXMKRCSYS}`\n", + " in environment variable LATEXMKRCSYS, but the file doesn't exist.\n", + " I won't read any system rc file.\n"; + } + else { + process_rc_file( $ENV{LATEXMKRCSYS} ); + } + } + else { + read_first_rc_file_in_list( @rc_system_files ); + } +} +if ( $auto_rc_use && ($HOME ne "" ) ) { + # User rc file: + @user_rc = (); + if ( $XDG_CONFIG_HOME ) { + push @user_rc, "$XDG_CONFIG_HOME/latexmk/latexmkrc"; + } + # N.B. $HOME equals "" if latexmk couldn't determine a home directory. + # In that case, we shouldn't look for an rc file there. + if ( $HOME ) { + push @user_rc, "$HOME/.latexmkrc"; + } + read_first_rc_file_in_list( @user_rc ); +} +if ( $auto_rc_use ) { + # Rc file in current directory: + read_first_rc_file_in_list( ".latexmkrc", "latexmkrc" ); +} + +## Process command line args. +@command_line_file_list = (); +$bad_options = 0; + +while ($_ = $ARGV[0]) +{ + # Make -- and - equivalent at beginning of option, + # but save original for possible use in *latex command line + $original = $_; + s/^--/-/; + shift; + if ( /^-aux-directory=(.*)$/ || /^-auxdir=(.*)$/ ) { + $aux_dir = $1; + } + elsif (/^-bib(tex|)fudge$/) { $bibtex_fudge = 1; } + elsif (/^-bib(tex|)fudge-$/) { $bibtex_fudge = 0; } + elsif (/^-bibtex$/) { $bibtex_use = 2; } + elsif (/^-bibtex-$/) { $bibtex_use = 0; } + elsif (/^-nobibtex$/) { $bibtex_use = 0; } + elsif (/^-bibtex-cond$/) { $bibtex_use = 1; } + elsif (/^-bibtex-cond1$/) { $bibtex_use = 1.5; } + elsif (/^-c$/) { $cleanup_mode = 2; $cleanup_fdb = 1; $cleanup_only = 1; } + elsif (/^-C$/ || /^-CA$/ ) { $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 1; } + elsif (/^-CF$/) { $cleanup_fdb = 1; } + elsif (/^-cd$/) { $do_cd = 1; } + elsif (/^-cd-$/) { $do_cd = 0; } + elsif (/^-commands$/) { &print_commands; exit; } + elsif (/^-d$/) { $banner = 1; } + elsif (/^-dependents$/ || /^-deps$/ || /^-M$/ ) { $dependents_list = 1; } + elsif (/^-nodependents$/ || /^-dependents-$/ || /^-deps-$/) { $dependents_list = 0; } + elsif (/^-deps-out=(.*)$/) { + $deps_file = $1; + $dependents_list = 1; + } + elsif (/^-diagnostics/) { $diagnostics = 1; } + elsif (/^-dir-report$/) { $aux_out_dir_report = 1; } + elsif (/^-dir-report-$/) { $aux_out_dir_report = 0; } + elsif (/^-dvi$/) { $dvi_mode = 1; } + elsif (/^-dvi-$/) { $dvi_mode = 0; } + elsif (/^-emulate-aux-dir$/) { $emulate_aux = 1; } + elsif (/^-emulate-aux-dir-$/) { $emulate_aux = 0; } + elsif (/^-f$/) { $force_mode = 1; } + elsif (/^-f-$/) { $force_mode = 0; } + elsif (/^-g$/) { $go_mode = 1; } + elsif (/^-g-$/) { $go_mode = 0; } + elsif (/^-gg$/) { + $go_mode = 2; $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 0; + } + elsif ( /^-h$/ || /^-help$/ ) { &print_help; exit;} + elsif (/^-jobname=(.*)$/) { + $jobname = $1; + } + elsif (/^-l$/) { $landscape_mode = 1; } + elsif (/^-l-$/) { $landscape_mode = 0; } + elsif ( /^-latex$/ ) { + $pdf_mode = 0; + $postscript_mode = 0; + $dvi_mode = 1; + } + elsif (/^-latex=(.*)$/) { + $latex = $1; + } + elsif (/^-latexoption=(.*)$/) { + push @extra_latex_options, $1; + push @extra_pdflatex_options, $1; + push @extra_lualatex_options, $1; + push @extra_xelatex_options, $1; + } + elsif ( /^-logfilewarninglist$/ || /^-logfilewarnings$/ ) + { $silence_logfile_warnings = 0; } + elsif ( /^-logfilewarninglist-$/ || /^-logfilewarnings-$/ ) + { $silence_logfile_warnings = 1; } + elsif ( /^-lualatex$/ || /^-pdflualatex$/ ) { + $pdf_mode = 4; + $dvi_mode = $postscript_mode = 0; + } +# See below for -lualatex=... +# See above for -M + elsif (/^-MF$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No file name specified after -MF switch"); + } + $deps_file = $ARGV[0]; + shift; + } + elsif ( /^-MP$/ ) { $dependents_phony = 1; } + elsif (/^-(make|)indexfudge$/) { $makeindex_fudge = 1; } + elsif (/^-(make|)indexfudge-$/) { $makeindex_fudge = 0; } + elsif ( /-MSWinBackSlash$/ ) { $MSWin_back_slash = 1; } + elsif ( /-MSWinBackSlash-$/ ) { $MSWin_back_slash = 0; } + elsif (/^-new-viewer$/) { + $new_viewer_always = 1; + } + elsif (/^-new-viewer-$/) { + $new_viewer_always = 0; + } + elsif (/^-norc$/ ) { + $auto_rc_use = 0; + # N.B. This has already been obeyed. + } + elsif (/^-nobib(tex|)fudge$/) { $bibtex_fudge = 0; } + elsif (/^-noemulate-aux-dir$/) { $emulate_aux = 0; } + elsif (/^-no(make|)indexfudge$/) { $makeindex_fudge = 0; } + elsif ( /^-output-directory=(.*)$/ ||/^-outdir=(.*)$/ ) { + $out_dir = $1; + } + elsif ( /^-output-format=(.*)$/ ) { + my $format = $1; + if ($format eq 'dvi' ) { + $dvi_mode = 1; + $pdf_mode = $postscript_mode = 0; + } + elsif ($format eq 'pdf' ) { + $pdf_mode = 1; + $dvi_mode = $postscript_mode = 0; + } + else { + warn "$My_name: unknown format in option '$_'\n"; + $bad_options++; + } + } + elsif (/^-p$/) { $printout_mode = 1; + $preview_continuous_mode = 0; # to avoid conflicts + $preview_mode = 0; + } + elsif (/^-p-$/) { $printout_mode = 0; } + elsif (/^-pdf$/) { $pdf_mode = 1; } + elsif (/^-pdf-$/) { $pdf_mode = 0; } + elsif (/^-pdfdvi$/){ $pdf_mode = 3; } + elsif (/^-pdflua$/){ $pdf_mode = 4; } + elsif (/^-pdfps$/) { $pdf_mode = 2; } + elsif (/^-pdfxe$/) { $pdf_mode = 5; } + elsif (/^-pdflatex$/) { + $pdflatex = "pdflatex %O %S"; + $pdf_mode = 1; + $dvi_mode = $postscript_mode = 0; + } + elsif (/^-pdflatex=(.*)$/) { + $pdflatex = $1; + } + elsif ( /^-pdflualatex=(.*)$/ || /^-lualatex=(.*)$/ ) { + $lualatex = $1; + } + elsif ( /^-pdfxelatex=(.*)$/ || /^-xelatex=(.*)$/ ) { + $xelatex = $1; + } + elsif (/^-pretex=(.*)$/) { + $pre_tex_code = $1; + } + elsif (/^-print=(.*)$/) { + $value = $1; + if ( $value =~ /^dvi$|^ps$|^pdf$|^auto$/ ) { + $print_type = $value; + $printout_mode = 1; + } + else { + &exit_help("$My_name: unknown print type '$value' in option '$_'"); + } + } + elsif (/^-ps$/) { $postscript_mode = 1; } + elsif (/^-ps-$/) { $postscript_mode = 0; } + elsif (/^-pv$/) { $preview_mode = 1; + $preview_continuous_mode = 0; # to avoid conflicts + $printout_mode = 0; + } + elsif (/^-pv-$/) { $preview_mode = 0; } + elsif (/^-pvc$/) { $preview_continuous_mode = 1; + $force_mode = 0; # So that errors do not cause loops + $preview_mode = 0; # to avoid conflicts + $printout_mode = 0; + } + elsif (/^-pvc-$/) { $preview_continuous_mode = 0; } + elsif (/^-pvctimeout$/) { $pvc_timeout = 1; } + elsif (/^-pvctimeout-$/) { $pvc_timeout = 0; } + elsif (/^-pvctimeoutmins=(.*)$/) { $pvc_timeout_mins = $1; } + elsif (/^-rc-report$/) { $rc_report = 1; } + elsif (/^-rc-report-$/) { $rc_report = 0; } + elsif (/^-recorder$/ ){ $recorder = 1; } + elsif (/^-recorder-$/ ){ $recorder = 0; } + elsif (/^-rules$/ ) { $rules_list = 1; } + elsif (/^-norules$/ || /^-rules-$/ ) { $rules_list = 0; } + elsif (/^-showextraoptions$/) { + print "List of extra latex and pdflatex options recognized by $my_name.\n", + "These are passed as is to *latex. They may not be recognized by\n", + "particular versions of *latex. This list is a combination of those\n", + "for TeXLive and MikTeX.\n", + "\n", + "Note that in addition to the options in this list, there are several\n", + "options known to the *latex programs that are also recognized by\n", + "latexmk and trigger special behavior by latexmk. Since these options\n", + "appear in the main list given by running 'latexmk --help', they do not\n", + "appear in the following list\n", + "NOTE ALSO: Not all of these options are supported by all versions of *latex.\n", + "\n"; + foreach $option ( sort( keys %allowed_latex_options, keys %allowed_latex_options_with_arg ) ) { + if (exists $allowed_latex_options{$option} ) { print " $allowed_latex_options{$option}\n"; } + if (exists $allowed_latex_options_with_arg{$option} ) { print " $allowed_latex_options_with_arg{$option}\n"; } + } + exit; + } + elsif (/^-silent$/ || /^-quiet$/ ){ $silent = 1; } + elsif (/^-stdtexcmds$/) { &std_tex_cmds; } + elsif (/^-time$/) { $show_time = 1;} + elsif (/^-time-$/) { $show_time = 0;} + elsif (/^-use-make$/) { $use_make_for_missing_files = 1; } + elsif (/^-use-make-$/) { $use_make_for_missing_files = 0; } + elsif (/^-usepretex$/) { &alt_tex_cmds; } + elsif (/^-usepretex=(.*)$/) { + &alt_tex_cmds; + $pre_tex_code = $1; + } + elsif (/^-v$/ || /^-version$/) { + print "\n$version_details. Version $version_num\n"; + exit; + } + elsif (/^-verbose$/) { $silent = 0; } + elsif (/^-view=default$/) { $view = "default";} + elsif (/^-view=dvi$/) { $view = "dvi";} + elsif (/^-view=none$/) { $view = "none";} + elsif (/^-view=ps$/) { $view = "ps";} + elsif (/^-view=pdf$/) { $view = "pdf"; } + elsif (/^-Werror$/){ $warnings_as_errors = 1; } + elsif ( /^-xelatex$/ || /^-pdfxelatex$/ ) { + $pdf_mode = 5; + $dvi_mode = $postscript_mode = 0; + } +# See above for -xelatex=... + elsif (/^-e$/) { + if ( $#ARGV < 0 ) { + &exit_help( "No code to execute specified after -e switch"); + } + execute_code_string( $ARGV[0] ); + shift; + } + elsif (/^-r$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No RC file specified after -r switch"); + } + if ( -e $ARGV[0] ) { + process_rc_file( $ARGV[0] ); + } + else { + die "$My_name: RC file [$ARGV[0]] does not exist\n"; + } + shift; + } + elsif (/^-bm$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No message specified after -bm switch"); + } + $banner = 1; $banner_message = $ARGV[0]; + shift; + } + elsif (/^-bi$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No intensity specified after -bi switch"); + } + $banner_intensity = $ARGV[0]; + shift; + } + elsif (/^-bs$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No scale specified after -bs switch"); + } + $banner_scale = $ARGV[0]; + shift; + } + elsif (/^-dF$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No dvi filter specified after -dF switch"); + } + $dvi_filter = $ARGV[0]; + shift; + } + elsif (/^-pF$/) { + if ( $ARGV[0] eq '' ) { + &exit_help( "No ps filter specified after -pF switch"); + } + $ps_filter = $ARGV[0]; + shift; + } + elsif ( ( exists( $allowed_latex_options{$_} ) ) + || ( /^(-.+)=/ && exists( $allowed_latex_options_with_arg{$1} ) ) + ) + { + push @extra_latex_options, $original; + push @extra_pdflatex_options, $original; + push @extra_lualatex_options, $original; + push @extra_xelatex_options, $original; + } + elsif (/^-/) { + warn "$My_name: $_ unknown option\n"; + $bad_options++; + } + else { + push @command_line_file_list, $_ ; + } +} + +if ( $diagnostics || $rc_report ) { + show_array( "Rc files read:", @rc_files_read ) unless $silent; +} + +if ( $bad_options > 0 ) { + &exit_help( "Bad options specified" ); +} + +warn "$My_name: This is $version_details, version: $version_num.\n", + unless $silent; + +if ($out_dir eq '' ){ + # Default to cwd + $out_dir = '.'; +} +if ( $aux_dir eq '' ){ + # Default to out_dir + # ?? This is different than MiKTeX + $aux_dir = $out_dir; +} +# Save original values for use in diagnositics. +# We may change $aux_dir and $out_dir after a detection +# of results of misconfiguration. +$aux_dir_requested = $aux_dir; +$out_dir_requested = $out_dir; + + +# The following reports results of diagnostics on location of .log file +# after the first run of a latex engine, when actually used aux_dir +# may not be the expected one, due to a configuration error. +# Values: -1 uninitialized (before first run) +# 0 log file not found; +# 1 log file in aux_dir; +# 2 log file **not** in aux_dir but in out_dir; +# 3 log file **not** in aux_dir or out_dir, but in cwd. +$where_log = -1; + +if ($bibtex_use > 1) { + push @generated_exts, 'bbl'; +} + +# For backward compatibility, convert $texfile_search to @default_files +# Since $texfile_search is initialized to "", a nonzero value indicates +# that an initialization file has set it. +if ( $texfile_search ne "" ) { + @default_files = split /\s+/, "*.tex $texfile_search"; +} + +#Glob the filenames command line if the script was not invoked under a +# UNIX-like environment. +# Cases: (1) MS/MSwin native Glob +# (OS detected as MSWin32) +# (2) MS/MSwin cygwin Glob [because we do not know whether +# the cmd interpreter is UNIXy (and does glob) or is +# native MS-Win (and does not glob).] +# (OS detected as cygwin) +# (3) UNIX Don't glob (cmd interpreter does it) +# (Currently, I assume this is everything else) +if ( ($^O eq "MSWin32") || ($^O eq "cygwin") ) { + # Preserve ordering of files + @file_list = glob_list1(@command_line_file_list); +#print "A1:File list:\n"; +#for ($i = 0; $i <= $#file_list; $i++ ) { print "$i: '$file_list[$i]'\n"; } +} +else { + @file_list = @command_line_file_list; +} +@file_list = uniq1( @file_list ); + + +# Check we haven't selected mutually exclusive modes. +# Note that -c overrides all other options, but doesn't cause +# an error if they are selected. +if (($printout_mode && ( $preview_mode || $preview_continuous_mode )) + || ( $preview_mode && $preview_continuous_mode )) +{ + # Each of the options -p, -pv, -pvc turns the other off. + # So the only reason to arrive here is an incorrect inititalization + # file, or a bug. + &exit_help( "Conflicting options (print, preview, preview_continuous) selected"); +} + +if ( @command_line_file_list ) { + # At least one file specified on command line (before possible globbing). + if ( !@file_list ) { + &exit_help( "Wildcards in file names didn't match any files"); + } +} +else { + # No files specified on command line, try and find some + # Evaluate in order specified. The user may have some special + # for wanting processing in a particular order, especially + # if there are no wild cards. + # Preserve ordering of files + my @file_list1 = uniq1( glob_list1(@default_files) ); + my @excluded_file_list = uniq1( glob_list1(@default_excluded_files) ); + # Make hash of excluded files, for easy checking: + my %excl = (); + foreach my $file (@excluded_file_list) { + $excl{$file} = ''; + } + foreach my $file (@file_list1) { + push( @file_list, $file) unless ( exists $excl{$file} ); + } + if ( !@file_list ) { + &exit_help( "No file name specified, and I couldn't find any"); + } +} + +$num_files = $#file_list + 1; +$num_specified = $#command_line_file_list + 1; + +#print "Command line file list:\n"; +#for ($i = 0; $i <= $#command_line_file_list; $i++ ) { print "$i: '$command_line_file_list[$i]'\n"; } +#print "File list:\n"; +#for ($i = 0; $i <= $#file_list; $i++ ) { print "$i: '$file_list[$i]'\n"; } + + +# If selected a preview-continuous mode, make sure exactly one filename was specified +if ($preview_continuous_mode && ($num_files != 1) ) { + if ($num_specified > 1) { + &exit_help( + "Need to specify exactly one filename for ". + "preview-continuous mode\n". + " but $num_specified were specified" + ); + } + elsif ($num_specified == 1) { + &exit_help( + "Need to specify exactly one filename for ". + "preview-continuous mode\n". + " but wildcarding produced $num_files files" + ); + } + else { + &exit_help( + "Need to specify exactly one filename for ". + "preview-continuous mode.\n". + " Since none were specified on the command line, I looked for \n". + " files in '@default_files'.\n". + " But I found $num_files files, not 1." + ); + } +} + +# If selected jobname, can only apply that to one file: +if ( ($jobname ne '') && ($jobname !~ /%A/) && ($num_files > 1) ) { + &exit_help( + "Need to specify at most one filename if ". + "jobname specified without a %A, \n". + " but $num_files were found (after defaults and wildcarding)." + ); +} +if ( $jobname =~ /%[^A]/ ) { + &exit_help( + "Jobname '$jobname' contains placeholder other than %A." + ); +} + +# Normalize the commands, to have place-holders for source, dest etc: +&fix_cmds; + +# Add common options +add_option( $latex_default_switches, \$latex ); +add_option( $pdflatex_default_switches, \$pdflatex ); +add_option( $lualatex_default_switches, \$lualatex ); +add_option( $xelatex_default_switches, \$xelatex ); + +foreach (@extra_latex_options) { add_option( $_, \$latex ); } +foreach (@extra_pdflatex_options) { add_option( $_, \$pdflatex ); } +foreach (@extra_lualatex_options) { add_option( $_, \$lualatex ); } +foreach (@extra_xelatex_options) { add_option( $_, \$xelatex ); } + + +# If landscape mode, change dvips processor, and the previewers: +if ( $landscape_mode ) +{ + $dvips = $dvips_landscape; + $dvi_previewer = $dvi_previewer_landscape; + $ps_previewer = $ps_previewer_landscape; +} + +if ( $silent ) { + add_option( "$latex_silent_switch", \$latex ); + add_option( "$pdflatex_silent_switch", \$pdflatex ); + add_option( "$lualatex_silent_switch", \$lualatex ); + add_option( "$xelatex_silent_switch", \$xelatex ); + add_option( "$biber_silent_switch", \$biber ); + add_option( "$bibtex_silent_switch", \$bibtex ); + add_option( "$makeindex_silent_switch", \$makeindex ); + add_option( "$dvipdf_silent_switch", \$dvipdf ); + add_option( "$dvips_silent_switch", \$dvips ); + add_option( "$xdvipdfmx_silent_switch", \$xdvipdfmx ); +} + +if ( $recorder ) { + add_option( "-recorder", \$latex, \$pdflatex, \$lualatex, \$xelatex ); +} + +# If the output and/or aux directories are specified, fix the *latex +# commands to use them. +# N.B. We'll ensure that the directories actually exist only after a +# possible cd to the document directory, since the directories can be +# relative to the document. + +if ( $jobname ne '' ) { + # Since $jobname may include placeholder(s), put %R placeholder + # in option, and let %R be substituted by actual jobname at runtime. + add_option( "--jobname=%R", \$latex, \$lualatex, \$pdflatex, \$xelatex ); +} + +# Which kind of file do we preview? +if ( $view eq "default" ) { + # If default viewer requested, use "highest" of dvi, ps and pdf + # that was requested by user. + # No explicit request means view dvi. + $view = "dvi"; + if ( $postscript_mode ) { $view = "ps"; } + if ( $pdf_mode ) { $view = "pdf"; } +} + +# Make sure we make the kind of file we want to view: +if ($view eq 'dvi') { $dvi_mode = 1; } +if ($view eq 'ps') { $postscript_mode = 1; } +if ( ($view eq 'pdf') && ($pdf_mode == 0) ) { + $pdf_mode = 1; +} + +# Make sure that we make something if all requests are turned off +if ( ! ( $dvi_mode || $pdf_mode || $postscript_mode || $printout_mode) ) { + print "No specific requests made, so default to dvi by latex\n"; + $dvi_mode = 1; +} + +# Determine requests. +if ( $banner ) { $postscript_mode = 1; } +if ( $dvi_mode ) { + $current_primary = 'latex'; + $requested_filetypes{'dvi'} = 1; + if ( length($dvi_filter) != 0 ) { $requested_filetypes{'dviF'} = 1; } +} +if ( $postscript_mode ) { + $current_primary = 'latex'; + $requested_filetypes{'ps'} = 1; + if ( length($ps_filter) != 0 ) { $requested_filetypes{'psF'} = 1; } +} + +if ($pdf_mode > 5) { + warn "$My_name: Non-allowed value of \$pdf_mode = $pdf_mode,", + " replaced by 1.\n"; + $pdf_mode = 1; +} +if ( ($dvi_mode || $postscript_mode) && $pdf_mode ) { + my %disallowed = (); + foreach (1,4,5) { $disallowed{$_} = 1; } + if ($disallowed{$pdf_mode}) { + warn "$My_name: \$pdf_mode = $pdf_mode is incompatible with dvi and postscript modes\n", + " which are required by other requests.\n"; + if ($postscript_mode) {$pdf_mode = 2;} + else { $pdf_mode = 3; } + warn " I replaced it by $pdf_mode.\n"; + } +} +if ( $pdf_mode == 0 ) { + $pdf_method = ''; +} +elsif ( $pdf_mode == 1 ) { + $requested_filetypes{'pdf'} = 1; + $pdf_method = 'pdflatex'; +} +elsif ( $pdf_mode == 2 ) { + $requested_filetypes{'pdf'} = 1; + $pdf_method = 'ps2pdf'; +} +elsif ( $pdf_mode == 3 ) { + $requested_filetypes{'pdf'} = 1; + $pdf_method = 'dvipdf'; +} +elsif ( $pdf_mode == 4 ) { + $requested_filetypes{'pdf'} = 1; + $pdf_method = 'lualatex'; +} +elsif ( $pdf_mode == 5 ) { + $requested_filetypes{'pdf'} = 1; + $pdf_method = 'xelatex'; +} + +if ($print_type eq 'auto') { + if ( $postscript_mode ) { $print_type = 'ps'; } + elsif ( $pdf_mode ) { $print_type = 'pdf'; } + elsif ( $dvi_mode ) { $print_type = 'dvi'; } + else { $print_type = 'none'; } +} +if ( $printout_mode ) { + $one_time{'print'} = 1; + if ($print_type eq 'none'){ + warn "$My_name: You have requested printout, but \$print_type is set to 'none'\n"; + } +} +if ( $preview_continuous_mode || $preview_mode ) { $one_time{'view'} = 1; } + +$can_switch = $allow_switch; +if ( $dvi_mode || $postscript_mode + || ( $printout_mode && ($print_type eq 'ps') || ($print_type eq 'dvi') ) + || ( ($preview_mode || $preview_continuous_mode) && ( ($view eq 'ps') || ($view eq 'dvi') ) ) + ) { + # Automatic switching (e.g., pdf<->dvi o/p) requires pdf files to be + # the only destinations. So if ps or dvi files needed, we cannot + # allow switching. (There will then be an error condition if a TeX + # engine fails to produce the correct type of output file.) + if ($diagnostics) { + warn "$My_name: Disallowing switch of output file as incompatible\n", + " with file requests.\n"; + } + $can_switch = 0; +} + + +if ( $pdf_mode == 2 ) { + # We generate pdf from ps. Make sure we have the correct kind of ps. + add_option( "$dvips_pdf_switch", \$dvips ); +} + +# Restrict variables to allowed values: + +if ($filetime_causality_threshold < 0) { + warn "$My_name: Correcting negative value of \$filetime_causality_threshold to zero.\n"; + $filetime_causality_threshold = 0; +} + +# Note sleep has granularity of 1 second. +# Sleep periods 0 < $sleep_time < 1 give zero delay, +# which is probably not what the user intended. +# Sleep periods less than zero give infinite delay +if ( $sleep_time < 0 ) { + warn "$My_name: Correcting negative sleep_time to 1 sec.\n"; + $sleep_time = 1; +} +elsif ( ($sleep_time < 1) && ( $sleep_time != 0 ) ) { + warn "$My_name: Correcting nonzero sleep_time of less than 1 sec to 1 sec.\n"; + $sleep_time = 1; +} +elsif ( $sleep_time == 0 ) { + warn "$My_name: sleep_time was configured to zero.\n", + " Do you really want to do this? It will give 100% CPU usage.\n"; +} + +# Make convenient forms for lookup. +# Extensions always have period. + +# Convert @generated_exts to a hash for ease of look up and deletion +# Keep extension without period! +%generated_exts_all = (); +foreach (@generated_exts ) { + $generated_exts_all{$_} = 1; +} + +$quell_uptodate_msgs = $silent; + # Whether to quell informational messages when files are uptodate + # Will turn off in -pvc mode + +$failure_count = 0; +@failed_primaries = (); + +if ($deps_file eq '' ) { + # Standardize name used for stdout + $deps_file = '-'; +} + +# Since deps_file is global (common to all processed files), we must +# delete it here when doing a clean up, and not in the FILE loop, where +# per-file processing (including clean-up) is done +if ( ($cleanup_mode > 0) && $dependents_list && ( $deps_file ne '-' ) ) { + unlink_or_move( $deps_file ); +} + +# In non-pvc mode, the dependency list is global to all processed TeX files, +# so we open a single file here, and add items to it after processing +# each file. But in -pvc mode, the dependency list should be written +# after round of processing the single TeX file (as if each round were +# a separate run of latexmk). +# If we are cleaning up ($cleanup_mode != 0) AND NOT continuing to +# make files (--gg option and $go_mode == 2), deps_file should not be +# created. +# I will use definedness of $deps_handle as flag for global deps file having +# been opened and therefore being available to be written to after +# compiling a file. +$deps_handle = undef; +if ( $dependents_list + && ! $preview_continuous_mode + && ( ($cleanup_mode == 0) || ($go_mode == 2) ) + ) { + $deps_handle = new FileHandle "> $deps_file"; + if (! $deps_handle ) { + die "Cannot open '$deps_file' for output of dependency information\n"; + } +} + +# Remove leading and trailing space in the following space-separated lists, +# and collapse multiple spaces to one, +# to avoid getting incorrect blank items when they are split. +foreach ($clean_ext, $clean_full_ext) { s/^\s+//; s/\s+$//; s/\s+/ /g; } + +# Deal with illegal and problematic characters in filename: +test_fix_texnames( @file_list ); + +$quote = $quote_filenames ? '"' : ''; + +FILE: +foreach $filename ( @file_list ) +{ + # Global variables for making of current file: + $updated = 0; + $failure = 0; # Set nonzero to indicate failure at some point of + # a make. Use value as exit code if I exit. + $failure_msg = ''; # Indicate reason for failure + + if ( $do_cd ) { + ($filename, $path) = fileparse( $filename ); + warn "$My_name: Changing directory to '$path'\n" + if !$silent; + pushd( dirname_no_tail( $path ) ); + } + else { + $path = ''; + } + + local $aux_dir = $aux_dir; + local $out_dir = $out_dir; + local $latex = $latex; + local $lualatex = $lualatex; + local $pdflatex = $pdflatex; + local $xelatex = $xelatex; + + &normalize_aux_out_ETC; + # Set -output-directory and -aux-directory options for *latex + &set_aux_out_options; + + &set_names; + + # For use under error conditions: + @default_includes = ($texfile_name, $aux_main); + # N.B. Do **not** apply local %rule_db here. It might appear appropriate, + # but %rule_db is needed in the continue block, which is not in the + # scope of a local declaration here. + &rdb_initialize_rules; + $view_file = ''; + rdb_one_rule( 'view', sub{ $view_file = $$Psource; } ); + + if ( $cleanup_mode > 0 ) { + my %other_generated = (); + my @index_bibtex_generated = (); + my @aux_files = (); + my @missing_bib_files = (); + my $bibs_all_exist = 0; + my %final_output_files = (); + foreach (keys %small_cleanup_preserved_exts) { + $final_output_files{"$out_dir1$root_filename.$_"} = 1; + } + $have_fdb = 0; + if ( -e $fdb_name ) { + print "$My_name: Examining fdb file '$fdb_name' for rules ...\n" + if $diagnostics; + $have_fdb = ( 0 == rdb_read( $fdb_name ) ); + } + if ( $have_fdb ) { + rdb_for_actives( + sub { # Find generated files at rule level + my ($base, $path, $ext) = fileparseA( $$Psource ); + $base = $path.$base; + if ( $rule =~ /^makeindex/ ) { + push @index_bibtex_generated, $$Psource, $$Pdest, "$base.ilg"; + } + elsif ( $rule =~ /^(bibtex|biber)/ ) { + push @index_bibtex_generated, $$Pdest, "$base.blg"; + push @aux_files, $$Psource; + if ( $bibtex_use == 1.5) { + foreach ( keys %$PHsource ) { + if ( ( /\.bib$/ ) && (! -e $_) ) { + push @missing_bib_files, $_; + } + } + } + } + elsif ( exists $other_generated{$$Psource} ) { +# print "=========== CHECKING: source file of rule '$rule', '$$Psource'\n", +# " is a generated file.\n"; + ## OLD with apparent bug: + #$other_generated{$$Pdest}; + } + foreach my $key (keys %$PHdest) { + $other_generated{$key} = 1; + } + }, + sub { # Find generated files at source file level + if ( $file =~ /\.aux$/ ) { push @aux_files, $file; } + } + ); + if ($#missing_bib_files == -1) { $bibs_all_exist = 1; } + } + elsif ( -e $log_name ) { + # No fdb file, but log file exists, so do inferior job by parse_log + print "$My_name: Examining log file '$log_name' for generated files...\n" + if $diagnostics; + # Variables set by parse_log. Can I remove them? + local %generated_log = (); + local %dependents = (); # Maps files to status. Not used here. + local @bbl_files = (); # Not used here. + local %idx_files = (); # Maps idx_file to (ind_file, base). Not used here. + local %conversions = (); # *latex-performed conversions. Not used here. + # Maps output file created and read by *latex + # to source file of conversion. + local $primary_out = ''; # Actual output file (dvi or pdf). Not used here. + local $fls_file_analyzed = 0; + &parse_log; + %other_generated = %generated_log; + } + else { + print "$My_name: No fdb or log file, so clean up default set of files ...\n" + if $diagnostics; + } + + if ( ($go_mode == 2) && !$silent ) { + warn "$My_name: Removing all generated files\n" unless $silent; + } + my $keep_bbl = 1; + if ( ($bibtex_use > 1.6) + || + ( ($bibtex_use == 1.5) && ($bibs_all_exist) ) + ) { + $keep_bbl = 0; + } + if ($keep_bbl) { + delete $generated_exts_all{'bbl'}; + } + # Convert two arrays to hashes: + my %index_bibtex_generated = (); + my %aux_files = (); + my %aux_files_to_save = (); + foreach (@index_bibtex_generated) { + $index_bibtex_generated{$_} = 1 + unless ( /\.bbl$/ && ($keep_bbl) ); + delete( $other_generated{$_} ); + } + foreach (@aux_files) { + if (exists $other_generated{$_} ) { + $aux_files{$_} = 1; + } + else { + $aux_files_to_save{$_} = 1; + } + } + + foreach (keys %final_output_files) { delete $other_generated{$_}; } + + if ($diagnostics) { + show_array( "For deletion, the following were determined from fdb file or log file:\n" + ." Generated (from makeindex and bibtex):", + keys %index_bibtex_generated ); + show_array( " Aux files:", keys %aux_files ); + show_array( " Other generated files:\n" + ." (only deleted if \$cleanup_includes_generated is set): ", + keys %other_generated ); + show_array( " Yet other generated files are specified by patterns:\n". + " Explicit pattern with %R or root-filename.extension:", + keys %generated_exts_all ); + show_array( " Aux files to SAVE and not delete:", keys %aux_files_to_save ); + } + + my @clean_args = ( 'blg', 'ilg', 'log', 'aux.bak', 'idx.bak', + split('\s+',$clean_ext), keys %generated_exts_all ); + cleanup1( $aux_dir1, @clean_args ); + if ( $out_dir1 ne $aux_dir1 ) { cleanup1( $out_dir1, @clean_args ); } + if ( $cleanup_mode == 1 ) { + my @clean_args = ( keys %small_cleanup_preserved_exts, split('\s+', $clean_full_ext) ); + cleanup1( $aux_dir1, @clean_args ); + if ( $out_dir1 ne $aux_dir1 ) { cleanup1( $out_dir1, @clean_args ); } + } + unlink_or_move( 'texput.log', "texput.aux", "missfont.log", + keys %index_bibtex_generated, + keys %aux_files ); + if ($cleanup_includes_generated) { + unlink_or_move( keys %other_generated ); + } + if ( $cleanup_includes_cusdep_generated) { + &cleanup_cusdep_generated; + } + } + if ($cleanup_fdb) { + unlink_or_move( $fdb_name ); + # If the fdb file exists, it will have been read, and therefore changed + # rule database. But deleting the fdb file implies we also want + # a virgin rule database, so we must reset it: + &rdb_initialize_rules; + } + if ($cleanup_only) { next FILE; } + + if ( $diagnostics ) { + print "$My_name: Rules after start up for '$texfile_name'\n"; + rdb_show(); + } + + $have_fdb = 0; + if (! -e $aux_main ) { + # No aux file => set up trivial aux file + # and corresponding fdb_file. Arrange them to provoke one run + # as minimum, but no more if actual aux file is trivial. + # (Useful on big files without cross references.) + # If aux file doesn't exist, then any fdb file is surely + # wrong. + # Previously, I had condition for this as being both aux and + # fdb files failing to exist. But it's not obvious what to + # do if aux exists and fdb doesn't. So I won't do anything. + &set_trivial_aux_fdb; + } + + if ( -e $fdb_name ) { + $rdb_errors = rdb_read( $fdb_name ); + $have_fdb = ($rdb_errors == 0); + } + if (!$have_fdb) { + # We didn't get a valid set of data on files used in + # previous run. So use filetime criterion for make + # instead of change from previous run, until we have + # done our own make. + rdb_recurse( [keys %possible_primaries], + sub{ if ( $$Ptest_kind == 1 ) { $$Ptest_kind = 3;} } + ); + if ( -e $log_name ) { + rdb_for_some( [keys %current_primaries], \&rdb_set_latex_deps ); + } + } + # At this point, we assume that the file database was correctly + # initialized from fdb_latexmk database (corresponding to the state at + # the end of the previous run of latexmk, if the fdb_latexmk file exists. + # PERHAPS if fdb_latexmk doesn't exist we ought to assume there was + # a previous run that completed, if the appropriate output files exist, + # so a new run of *latex etc isn't needed; then we should set the file + # data from the on-disk state. + if ($go_mode) { + # Force everything to be remade. + rdb_recurse( [ &rdb_target_array], sub{$$Pout_of_date=1;} ); + } + + + if ( $diagnostics ) { + print "$My_name: Rules after initialization\n"; + rdb_show(); + } + + #************************************************************ + + if ( $preview_continuous_mode ) { + &make_preview_continuous; + next FILE; + } + + +## Handling of failures: +## Variable $failure is set to indicate a failure, with information +## put in $failure_msg. +## These variables should be set to 0 and '' at any point at which it +## should be assumed that no failures have occurred. +## When after a routine is called it is found that $failure is set, then +## processing should normally be aborted, e.g., by return. +## Then there is a cascade of returns back to the outermost level whose +## responsibility is to handle the error. +## Exception: An outer level routine may reset $failure and $failure_msg +## after initial processing, when the error condition may get +## ameliorated later. + #Initialize failure flags now. + $failure = 0; + $failure_msg = ''; + if ($compiling_cmd) { Run_subst( $compiling_cmd ); } + $failure = &rdb_make; + if ( ( $failure <= 0 ) || $force_mode ) { + rdb_for_some( [keys %one_time], \&rdb_run1 ); + } + if ($#primary_warning_summary > -1) { + # N.B. $mult_defined, $bad_reference, $bad_character, $bad_citation also available here. + if ($warnings_as_errors) { + $failure = 1; + $failure_msg = "Warning(s) from latex (or c.) for '$filename'; treated as error"; + } + } + + if ($failure > 0) { + if ($failure_cmd) { Run_subst( $failure_cmd ); } + next FILE; + } else { + if ($success_cmd) { Run_subst( $success_cmd ); } + } +} # end FILE +continue { + if ($deps_handle) { deps_list($deps_handle); } + # If requested, print the list of rules. But don't do this in -pvc + # mode, since the rules list has already been printed. + if ($rules_list && ! $preview_continuous_mode) { rdb_list(); } + # Handle any errors + $error_message_count = rdb_show_rule_errors(); + if ( ($error_message_count == 0) || ($failure > 0) ) { + if ( $failure_msg ) { + #Remove trailing space + $failure_msg =~ s/\s*$//; + warn "----------------------\n"; + warn "This message may duplicate earlier message.\n"; + warn "$My_name: Failure in processing file '$filename':\n", + " $failure_msg\n"; + warn "----------------------\n"; + $failure = 1; + } + } + if ( ($failure > 0) || ($error_message_count > 0) ) { + $failure_count ++; + push @failed_primaries, $filename; + } + &ifcd_popd; +} +close($deps_handle) if ( $deps_handle ); + +if ($show_time) { show_timing();} + +sub show_timing { + my $processing_time = processing_time() - $processing_time1; + print @timings, "Accumulated processing time = $processing_time\n"; + print "Number of rules run = ", 1+$#timings, "\n"; + @timings = (); + $processing_time1 = processing_time(); +} + +# If we get here without going through the continue section: +if ( $do_cd && ($#dir_stack > -1) ) { + # Just in case we did an abnormal exit from the loop + warn "$My_name: Potential bug: dir_stack not yet unwound, undoing all directory changes now\n"; + &finish_dir_stack; +} + +if ($failure_count > 0) { + if ( $#file_list > 0 ) { + # Error occured, but multiple files were processed, so + # user may not have seen all the error messages + warn "\n------------\n"; + show_array( + "$My_name: Some operations failed, for the following tex file(s)", + @failed_primaries); + } + if ( !$force_mode ) { + warn "$My_name: Use the -f option to force complete processing,\n", + " unless error was exceeding maximum runs, or warnings treated as errors.\n"; + } + exit 12; +} + +if ( $where_log == 2 ) { + warn "$My_name: You requested aux_dir '$aux_dir_requested',\n", + " but '$out_dir' was used for the .log file etc, and I couldn't\n", + " correct the problem, even by setting emulation of aux_dir on.\n", + " There is a strong suspicion of a bug in $my_name or a configuration error.\n"; +} +if ( $emulate_aux_switched ) { + warn "$My_name: I had to switch -aux-directory on after it was initially off,\n", + " because your *latex program appeared not to support it. You probably\n", + " should either use the option -emulate-aux-dir, or in a latexmkrc file\n", + " set \$emulate_aux = 1;\n"; +} + +# end MAIN PROGRAM +############################################################# +############################################################# + +sub set_tex_cmds { + # Usage, e.g., set_tex_cmds( '%O %S' ) + my $args = $_[0]; + foreach my $cmd ('latex', 'lualatex', 'pdflatex', 'xelatex' ) { + ${$cmd} = "$cmd $args"; + } + # N.B. See setting of $latex_default_switches, ..., + # $xelatex_default_switches, etc, for any special options needed. +} + +sub std_tex_cmds { set_tex_cmds( '%O %S' ); } + +sub alt_tex_cmds { set_tex_cmds( '%O %P' ); } + +#======================== + +sub test_fix_texnames { + my $illegal_char = 0; + my $unbalanced_quote = 0; + my $balanced_quote = 0; + foreach (@_) { + if ( ($^O eq "MSWin32") || ($^O eq "msys") ) { + # On MS-Win, change directory separator '\' to '/', as needed + # by the TeX engines, for which '\' introduces a macro name. + # Remember that '/' is a valid directory separator in MS-Win. + s[\\][/]g; + } + if ($do_cd) { + my ($filename, $path) = fileparse( $_ ); + if ($filename =~ /[\Q$illegal_in_texname\E]/ ) { + $illegal_char++; + warn "$My_name: Filename '$filename' contains character not allowed for TeX file.\n"; + } + if ($filename =~ /^&/) { + $illegal_char++; + warn "$My_name: Filename '$filename' contains initial '&', which is\n", + " not allowed for TeX file.\n"; + } + } + else { + if ( /[\Q$illegal_in_texname\E]/ ) { + $illegal_char++; + warn "$My_name: Filename '$_' contains character not allowed for TeX file.\n"; + } + if (/^&/ ) { + $illegal_char++; + warn "$My_name: Filename '$_' contains initial '&', which is not allowed\n", + " for TeX file.\n"; + } + } + my $count_q = ($_ =~ tr/\"//); + if ( ($count_q % 2) != 0 ) { + warn "$My_name: Filename '$_' contains unbalanced quotes, not allowed.\n"; + $unbalanced_quote++; + } + elsif ( $count_q > 0 ) { + warn "$My_name: Removed (balanced quotes) from filename '$_',\n"; + s/\"//g; + warn " and obtained '$_'.\n"; + $balanced_quote++; + } + } + if ($illegal_char || $unbalanced_quote) { + die "$My_name: Stopping because of bad filename(s).\n"; + } +} + +############################################################# + +sub ensure_path { + # Usage: ensure_path( $var, values ...) + # $ENV{$var} is an environment variable (e.g. $ENV{TEXINPUTS}. + # Ensure the values are in it, prepending them if not, and + # creating the environment variable if it doesn't already exist. + my $var = shift; + my %cmpts = (); + if ( exists $ENV{$var} ) { + foreach ( split $search_path_separator, $ENV{$var} ) { + if ($_ ne '') { $cmpts{$_} = 1; } + } + } + foreach (@_) { + next if ( ($_ eq '') || (exists $cmpts{$_}) ); + if (exists $ENV{$var}) { + $ENV{$var} = $_ . $search_path_separator . $ENV{$var}; + } + else { + $ENV{$var} = $_ . $search_path_separator; + } + if ($diagnostics) { + print "Set environment variable $var='$ENV{$var}'\n"; + } + } +} #END ensure_path + +############################################################# + +sub normalize_aux_out_ETC { + # 1. Normalize $out_dir and $aux_dir, so that if they have a non-trivial last + # component, any trailing '/' is removed. + # 2. They should be non-empty. + # 3. Set $out_dir1 and $aux_dir1 to have a directory separator character + # '/' added if needed to give forms suitable for direct concatenation with + # a filename. These are needed for substitutions like %Y%R. + # Nasty cases of dir_name: "/" on all systems, "A:", "A:/" etc on MS-Win + # 4. Set some TeX-related environment variables. + # 5. Ensure the aux and out directories exist + + # Ensure the output/auxiliary directories exist, if need be + my $ret1 = 0; + my $ret2 = 0; + eval { + if ( $out_dir ) { + $ret1 = make_path_mod( $out_dir, 'output' ); + } + if ( $aux_dir && ($aux_dir ne $out_dir) ) { + $ret2 = make_path_mod( $aux_dir, 'auxiliary' ); + } + }; + if ($ret1 || $ret2 || $@ ) { + if ($@) { print "Error message:\n $@"; } + die "$My_name: Since there was trouble making the output (and aux) dirs, I'll stop\n" + } + + if ($normalize_names) { + foreach ( $aux_dir, $out_dir ) { $_ = normalize_filename_abs($_); } + } + $aux_dir1 = $aux_dir; + $out_dir1 = $out_dir; + foreach ( $aux_dir1, $out_dir1 ) { + if ($_ eq '.') {$_ = '';} + if ( ($_ ne '') && ! m([\\/\:]$) ) { + # Add a trailing '/' if necessary to give a string that can be + # correctly concatenated with a filename: + $_ .= '/'; + } + } + if ($aux_dir) { + # Ensure $aux_dir is in BIBINPUTS and TEXINPUTS search paths. + # TEXINPUTS is used by dvips for files generated by mpost. + # For BIBINPUTS, + # at least one widely package (revtex4-1) generates a bib file + # (which is used in revtex4-1 for putting footnotes in the reference + # list), and bibtex must be run to use it. But latexmk needs to + # determine the existence of the bib file by use of kpsewhich, otherwise + # there is an error. So cope with this situation (and any analogous + # cases by adding the aux_dir to the relevant path search environment + # variables. BIBINPUTS seems to be the only one currently affected. + # Convert $aux_dir to absolute path to make the search path invariant + # under change of directory. + foreach ( 'BIBINPUTS', 'TEXINPUTS' ) { + ensure_path( $_, $aux_dir ); + } + # Set TEXMFOUTPUT so that when the aux_dir is not a subdirectory + # of the cwd (or below), bibtex and makeindex can write to it. + # Otherwise, security precautions in these programs will prevent + # them from writing there, on TeXLive. MiKTeX is different: see + # below. + # The security issues concern **document-controlled** writing of + # files, when bibtex or makeindex is invoked directly by a + # document. In contrast, here $aux_dir is set by latexmk, not by + # the document. (See the main texmf.cnf file in a TeXLive + # distribution for some information on security issues.) + # + # PROPERTIES: + # 1. In TeXLive, the use of TEXMFOUTPUT works if + # (a) the directory given is an an absolute path, + # AND (b) the path contains no .. pieces + # AND (c) the directory component of the filename(s) on the command + # line for makeindex and bibtex is exactly the same string as + # for the directory named in TEXMFOUTPUT. + # 2. In MiKTeX, bibtex has none of the security restrictions; but + # makeindex has, and the use of TEXMFOUTPUT has no effect. + # So the following is only needed for TeXLive. + $ENV{TEXMFOUTPUT} = $aux_dir; + } + + if ($diagnostics || $aux_out_dir_report ) { + warn "$My_name: Cwd: '", good_cwd(), "'\n"; + warn "$My_name: Normalized aux dir and out dir: '$aux_dir', '$out_dir'\n"; + warn "$My_name: and combining forms: '$aux_dir1', '$out_dir1'\n"; + } + +} #END normalize_aux_out_ETC + +############################################################# + +sub set_aux_out_options { + # Set -output-directory and -aux-directory options for *latex. Use + # placeholders for substitutions so that correct value is put in at + # runtime. + # N.B. At this point, $aux_dir and $out_dir should be non-empty, unlike the + # case after the reading of latexmkrc files, where empty string means + # use default. Let's be certain, however: + if ($out_dir eq '') { $out_dir = '.'; $out_dir1 = ''; } + if ($aux_dir eq '') { $aux_dir = $out_dir; $aux_dir1 = $out_dir1; } + + if ($emulate_aux) { + if ( $aux_dir ne '.' ) { + # N.B. Set **output** directory to **aux_dir**, rather than + # out_dir. If aux and out dirs are are different, then we'll move + # the relevant files (.pdf, .ps, .dvi, .xdv, .fls to the output + # directory after running *latex. + add_option( "-output-directory=%V", + \$latex, \$pdflatex, \$lualatex, \$xelatex ); + } + } + else { + if ( $out_dir && ($out_dir ne '.') ) { + add_option( "-output-directory=%W", + \$latex, \$pdflatex, \$lualatex, \$xelatex ); + } + if ( $aux_dir ne $out_dir ) { + # N.B. If $aux_dir and $out_dir are the same, then the + # -output-directory option is sufficient, especially because + # the -aux-directory exists only in MiKTeX, not in TeXLive. + add_option( "-aux-directory=%V", + \$latex, \$pdflatex, \$lualatex, \$xelatex ); + } + } +} #END set_aux_out_options + +############################################################# + +sub fix_cmds { + # If commands do not have placeholders for %S etc, put them in + foreach ($latex, $lualatex, $pdflatex, $xelatex, $lpr, $lpr_dvi, $lpr_pdf, + $pdf_previewer, $ps_previewer, $ps_previewer_landscape, + $dvi_previewer, $dvi_previewer_landscape, + $kpsewhich + ) { + # Source only + if ( $_ && ! /%/ ) { $_ .= " %O %S"; } + } + foreach ($pdf_previewer, $ps_previewer, $ps_previewer_landscape, + $dvi_previewer, $dvi_previewer_landscape, + ) { + # Run previewers detached + if ( $_ && ! /^(nostart|NONE|internal) / ) { + $_ = "start $_"; + } + } + foreach ($biber, $bibtex) { + # Base only + if ( $_ && ! /%/ ) { $_ .= " %O %B"; } + } + foreach ($dvipdf, $ps2pdf) { + # Source and dest without flag for destination + if ( $_ && ! /%/ ) { $_ .= " %O %S %D"; } + } + foreach ($dvips, $makeindex) { + # Source and dest with -o dest before source + if ( $_ && ! /%/ ) { $_ .= " %O -o %D %S"; } + } + foreach ($dvi_filter, $ps_filter) { + # Source and dest, but as filters + if ( $_ && ! /%/ ) { $_ .= " %O <%S >%D"; } + } +} #END fix_cmds + +############################################################# + +sub add_option { + # Call add_option( $opt, \$cmd ... ) + # Add option to one or more commands + my $option = shift; + while (@_) { + if ( ${$_[0]} !~ /%/ ) { &fix_cmds; } + ${$_[0]} =~ s/%O/$option %O/; + shift; + } +} #END add_option + +############################################################# + +sub rdb_initialize_rules { + # Initialize rule database. + # (The rule database may get overridden/extended after the fdb_latexmk + # file is read, and after running commands to adjust to dependencies + # determined from document. + %rule_db = (); + %target_rules = (); + %target_files = (); + + local %rule_list = (); + &rdb_set_rule_templates; + + my %rule_template = %rule_list; + while ( my ($key, $value) = each %extra_rule_spec ) { + $rule_template{$key} = $value; + } + foreach my $rule ( keys %rule_template ) { + my ( $cmd_type, $ext_cmd, $int_cmd, $source, $dest, $base, $test_kind, $PA_extra_gen ) = @{$rule_template{$rule}}; + if ( ! $PA_extra_gen ) { $PA_extra_gen = []; } + my $needs_making = 0; + # Substitute in the filename variables, since we will use + # those for determining filenames. But delay expanding $cmd + # until run time, in case of changes. + foreach ($base, $source, $dest, @$PA_extra_gen ) { + s/%R/$root_filename/g; + s/%Y/$aux_dir1/; + s/%Z/$out_dir1/; + } + foreach ($source, $dest ) { + s/%B/$base/; + s/%T/$texfile_name/; + } + rdb_create_rule( $rule, $cmd_type, $ext_cmd, $int_cmd, $test_kind, + $source, $dest, $base, + $needs_making, undef, undef, 1, $PA_extra_gen ); + } # End rule iteration + + # Ensure we only have one way to make pdf file, and that it is appropriate. Remove other incompatibilities + if ($pdf_mode == 1) { rdb_deactivate( 'dvipdf', 'ps2pdf', 'latex', 'lualatex', 'xdvipdfmx', 'xelatex' ); } + elsif ($pdf_mode == 2) { rdb_deactivate( 'dvipdf', 'pdflatex', 'lualatex', 'xdvipdfmx', 'xelatex' ); } + elsif ($pdf_mode == 3) { rdb_deactivate( 'pdflatex', 'ps2pdf', 'lualatex', 'xdvipdfmx', 'xelatex' ); } + elsif ($pdf_mode == 4) { rdb_deactivate( 'pdflatex', 'ps2pdf', 'dvipdf', 'xdvipdfmx', 'xelatex' ); } + elsif ($pdf_mode == 5) { rdb_deactivate( 'pdflatex', 'ps2pdf', 'dvipdf', 'lualatex' ); } + else { rdb_deactivate( 'dvipdf', 'pdflatex', 'ps2pdf', 'lualatex', 'xdvipdfmx', 'xelatex' ); } + + if ($dvi_mode == 1) { + rdb_activate( 'latex' ); + $target_files{$dvi_final} = 1; + } + if ($postscript_mode == 1) { + rdb_activate( 'latex' ); + $target_files{$ps_final} = 1; + } + if ($pdf_mode) { $target_files{$pdf_final} = 1; } + &rdb_set_rule_net; +} # END rdb_initialize_rules + +#************************************************************ + +sub rdb_set_rule_templates { +# Set up specifications for standard rules, adjusted to current conditions +# Substitutions: %S = source, %D = dest, %B = this rule's base +# %T = texfile, %R = root = base for latex. +# %Y for $aux_dir1, %Z for $out_dir1 + + + my $print_file = ''; + my $print_cmd = 'NONE'; + if ( $print_type eq 'dvi' ) { + $print_file = $dvi_final; + $print_cmd = $lpr_dvi; + } + elsif ( $print_type eq 'pdf' ) { + $print_file = $pdf_final; + $print_cmd = $lpr_pdf; + } + elsif ( $print_type eq 'ps' ) { + $print_file = $ps_final; + $print_cmd = $lpr; + } + elsif ( $print_type eq 'none' ) { + $print_cmd = 'NONE echo NO PRINTING CONFIGURED'; + } + + my $view_file = ''; + my $viewer = ''; + my $viewer_update_method = 0; + my $viewer_update_signal = undef; + my $viewer_update_command = undef; + + if ( ($view eq 'dvi') || ($view eq 'pdf') || ($view eq 'ps') ) { + $view_file = ${$view.'_final'}; + $viewer = ${$view.'_previewer'}; + $viewer_update_method = ${$view.'_update_method'}; + $viewer_update_signal = ${$view.'_update_signal'}; + if (defined ${$view.'_update_command'}) { + $viewer_update_command = ${$view.'_update_command'}; + } + } + # Specification of internal command for viewer update: + my $PA_update = ['do_update_view', $viewer_update_method, $viewer_update_signal, 0, 1]; + +# For test_kind: Use file contents for latex and friends, but file time for the others. +# This is because, especially for dvi file, the contents of the file may contain +# a pointer to a file to be included, not the contents of the file! + %rule_list = ( + 'latex' => [ 'primary', "$latex", '', "%T", $dvi_name, "%R", 1, [$log_name] ], + 'pdflatex' => [ 'primary', "$pdflatex", '', "%T", $pdf_name, "%R", 1, [$log_name] ], + 'lualatex' => [ 'primary', "$lualatex", '', "%T", $pdf_name, "%R", 1, [$log_name] ], + 'xelatex' => [ 'primary', "$xelatex", '', "%T", $xdv_name, "%R", 1, [$log_name] ], + 'dvipdf' => [ 'external', "$dvipdf", 'do_viewfile', $dvi_final, $pdf_name, "%Z%R", 2 ], + 'xdvipdfmx' => [ 'external', "$xdvipdfmx", 'do_viewfile', $xdv_final, $pdf_name, "%Z%R", 2 ], + 'dvips' => [ 'external', "$dvips", 'do_viewfile', $dvi_final, $ps_name, "%Z%R", 2 ], + 'dvifilter' => [ 'external', $dvi_filter, 'do_viewfile', $dvi_name, $dviF_name, "%Z%R", 2 ], + 'ps2pdf' => [ 'external', "$ps2pdf", 'do_viewfile', $ps_final, $pdf_name, "%Z%R", 2 ], + 'psfilter' => [ 'external', $ps_filter, 'do_viewfile', $ps_name, $psF_name, "%Z%R", 2 ], + 'print' => [ 'external', "$print_cmd", 'if_source', $print_file, "", "", 2 ], + 'update_view' => [ 'external', $viewer_update_command, $PA_update, + $view_file, "", "", 2 ], + 'view' => [ 'external', "$viewer", 'if_source', $view_file, "", "", 2 ], + ); +} # END rdb_set_rule_templates + +#************************************************************ + +sub rdb_set_rule_net { + # Set network of rules, including links + &rdb_make_links; + &rdb_classify_rules; +} + +#************************************************************ + +sub rdb_make_links { +# ?? Problem if there are multiple rules for getting a file. Notably pdf. +# Which one to choose? +# ?? Problem: what if a rule is inactive, +# e.g., bibtex because biber is in use, +# or xelatex when pdflatex is in use +# or bibtex when $bibtex_use is 0. +# What if both latex and pdflatex are being used? +# That has been allowed. But .aux file (also +# .log file) are made by both. + +# Other case: package (like bibtopic) creates bbl or other file when +# it doesn't exist. Later a rule is created by latexmk to make that +# file. Then the rule's main destination file should have priority +# over non-main generated files from other rules. + local %from_rules_old = %from_rules; + &rdb_cache_generated; + + rdb_for_actives( + 0, + sub{ + if ( exists $from_rules_main{$file} ) { + $$Pfrom_rule = $from_rules_main{$file}; + } + elsif ( exists $from_rules{$file} ) { + $$Pfrom_rule = $from_rules{$file}; + } + if ( $$Pfrom_rule && (! rdb_rule_exists( $$Pfrom_rule ) ) ) { + $$Pfrom_rule = ''; + } + } + ); + rdb_for_actives( \&rdb_set_source_rules ); +# print "=========In rdb_make_links: rules\n"; &rdb_show; +} # END rdb_make_links + +#************************************************************ + +sub rdb_set_source_rules { + # This applies to rules whose source file is a dvi or xdv file + # Uses rule context + my ($base, $path, $ext) = fileparseA( $$Psource ); + if ( ($ext eq '.dvi') || ($ext eq '.dviF') || ($ext eq '.xdv') ) { + my $old_rule = $from_rules_old{$$Psource}; + my $new_rule = $from_rules{$$Psource}; + if ( defined $old_rule + && defined $new_rule + && ($old_rule eq $new_rule) + && defined $$PHsource_rules{$new_rule} + ) + { # Nothing to do: source rule is correct. + } + else { + if ( defined $old_rule ) { delete $$PHsource_rules{$old_rule}; } + if ( defined $new_rule ) { $$PHsource_rules{$new_rule} = 0; } + } + } +} + +#************************************************************ + +sub rdb_cache_generated { + # Update %from_rules + %from_rules = (); + %from_rules_main = (); + rdb_for_actives( \&one_from_main_rule_cache ); + rdb_for_actives( \&one_from_rule_cache ); +} # END rdb_cache_generated + +#------------ + +sub one_from_main_rule_cache { + # Rule context assumed. + # Set from_rules_main items for one rule + if (! $$Pdest) { return; } +# Error message trigger: if ( $$Pdest =~ /pdf$/) { $from_rules_main{$$Pdest} = 'pdflatexA'; } + if ( exists $from_rules_main{$$Pdest} ) { + my $old_rule = $from_rules_main{$$Pdest}; + if ( $old_rule eq $rule ) { + # OK + } + else { + warn "$My_name: Possible bug:\n", + " In linking rules I already set from_rules_main{$$Pdest} to '$old_rule'\n", + " But now I want to set it to '$rule'\n"; +# traceback( "================================\nFrom one_from_main_rule_cache" ); + } + } + $from_rules_main{$$Pdest} = $rule; +} # END one_from_main_rule_cache + +#------------ + +sub one_from_rule_cache { + # Rule context assumed. + # Set from_rules items for one rule + foreach ( @$PA_extra_gen, keys %$PHdest ) { + # Error message trigger: if ( $_ =~ /aux$/) { $from_rules{$_} = 'pdflatexA'; } + if ( exists $from_rules{$_} ) { + my $old_rule = $from_rules{$_}; + if ( $old_rule eq $rule ) { + # OK + } + elsif ( exists $from_rules_main{$_} && ( $from_rules_main{$_} ne $rule ) ) { + warn "$My_name: Possible bug:\n", + " In linking rules, I already set from_rules_main{$_}\n". + " to '$from_rules_main{$_}'\n", + " But now I also have a different rule '$rule' that also made the file.\n"; + } + elsif ( exists($possible_primaries{$old_rule}) && exists($possible_primaries{$rule}) ) { + # This could be problematic. But we'll let it go, + # because it is a common case for .aux and .log files + # (etc), and these cases do not appear to mess up + # anything (by experience). + # Once we allow an active flag for rules and only + # examine active rules, the only case of this that + # will appear (in the absence of other problems) will + # be where two primary rules are active, notably a + # latex rule to make dvi and a pdflatex (or other + # rule) to make pdf. + } + else { + warn "$My_name: Possible bug:\n", + " In linking rules I already set from_rules{$_} to '$old_rule'\n", + " But now I want to set it to '$rule'\n"; +# traceback( "================================\nFrom one_from__rule_cache" ); + } + } + $from_rules{$_} = $rule; + } +} #END from_rule_cache + +#************************************************************ + +sub set_trivial_aux_fdb { + # 1. Write aux file as would be written if the tex file had no cross + # cross references, etc. i.e., a minimal .aux file, as would be + # written by latex with a simple document. + # That saves a run of latex on such simple documents. + # Before about 2020, latex only wrote one line, containing '\relax ' + # in the aux file. After that a reference to the last page was + # added. So now I write what is written for a one page document. + # 2. Write a corresponding fdb file + # 3. Provoke a run of *latex (actually of all primaries). + + local *aux_file; + open( aux_file, '>', $aux_main ) + or die "Cannot write file '$aux_main'\n"; + print aux_file "\\relax \n"; + # The following is added by recent versions of latex for a + # one page document + print aux_file "\\gdef \\\@abspage\@last{1}\n"; + close(aux_file); + + foreach my $rule (keys %possible_primaries ) { + rdb_ensure_file( $rule, $texfile_name ); + rdb_ensure_file( $rule, $aux_main ); + rdb_one_rule( $rule, + sub{ $$Pout_of_date = 1; } + ); + } + &rdb_write( $fdb_name ); +} #END set_trivial_aux_fdb + +#************************************************************ +#### Particular actions +#************************************************************ +#************************************************************ + +sub do_cusdep { + # Unconditional application of custom-dependency + # except that rule is not applied if the source file source + # does not exist, and an error is returned if the dest is not made. + # + # Assumes rule context for the custom-dependency, and that my first + # argument is the name of the subroutine to apply + my $func_name = $_[0]; + my $return = 0; + if ( !-e $$Psource ) { + # Source does not exist. Users of this rule will need to turn + # it off when custom dependencies are reset + if ( !$silent ) { + warn "$My_name: In trying to apply custom-dependency rule\n", + " to make '$$Pdest' from '$$Psource'\n", + " the source file has disappeared since the last run\n"; + } + # Treat as successful + } + elsif ( !$func_name ) { + warn "$My_name: Possible misconfiguration or bug:\n", + " In trying to apply custom-dependency rule\n", + " to make '$$Pdest' from '$$Psource'\n", + " the function name is blank.\n"; + } + elsif ( ! defined &$func_name ) { + warn "$My_name: Misconfiguration or bug,", + " in trying to apply custom-dependency rule\n", + " to make '$$Pdest' from '$$Psource'\n", + " function name '$func_name' does not exists.\n"; + } + else { + my $cusdep_ret = &$func_name( $$Pbase ); + if ( defined $cusdep_ret && ($cusdep_ret != 0) ) { + $return = $cusdep_ret; + if ($return) { + warn "Rule '$rule', function '$func_name'\n", + " failed with return code = $return\n"; + } + } + elsif ( !-e $$Pdest ) { + # Destination non-existent, but routine failed to give an error + warn "$My_name: In running custom-dependency rule\n", + " to make '$$Pdest' from '$$Psource'\n", + " function '$func_name' did not make the destination.\n"; + $return = -1; + } + } + return $return; +} # END do_cusdep + +#************************************************************ + +sub do_viewfile { + # Unconditionally make file for viewing, going through temporary file if + # Assumes rule context + + my $return = 0; + my ($base, $path, $ext) = fileparseA( $$Pdest ); + if ( &view_file_via_temporary ) { + if ( $$Pext_cmd =~ /%D/ ) { + my $tmpfile = tempfile1( "${root_filename}_tmp", $ext ); + warn "$My_name: Making '$$Pdest' via temporary '$tmpfile'...\n"; + $return = &Run_subst( undef, undef, undef, undef, $tmpfile ); + move( $tmpfile, $$Pdest ); + } + else { + warn "$My_name is configured to make '$$Pdest' via a temporary file\n", + " but the command template '$$Pext_cmd' does not have a slot\n", + " to set the destination file, so I won't use a temporary file\n"; + $return = &Run_subst(); + } + } + else { + $return = &Run_subst(); + } + return $return; +} #END do_viewfile + +#************************************************************ + +sub do_update_view { + # Update viewer + # Assumes rule context + # Arguments: (method, signal, viewer_process) + + my $return = 0; + + # Although the process is passed as an argument, we'll need to update it. + # So (FUDGE??) bypass the standard interface for the process. + # We might as well do this for all the arguments. + my $viewer_update_method = ${$PAint_cmd}[1]; + my $viewer_update_signal = ${$PAint_cmd}[2]; + my $Pviewer_process = \${$PAint_cmd}[3]; + my $Pneed_to_get_viewer_process = \${$PAint_cmd}[4]; + + if ($viewer_update_method == 2) { + if ($$Pneed_to_get_viewer_process) { + $$Pviewer_process = &find_process_id( $$Psource ); + if ($$Pviewer_process != 0) { + $$Pneed_to_get_viewer_process = 0; + } + } + if ($$Pviewer_process == 0) { + print "$My_name: need to signal viewer for file '$$Psource', but didn't get \n", + " process ID for some reason, e.g., no viewer, bad configuration, bug\n" + if $diagnostics ; + } + elsif ( defined $viewer_update_signal) { + print "$My_name: signalling viewer, process ID $$Pviewer_process ", + "with signal $viewer_update_signal\n" + if $diagnostics ; + kill $viewer_update_signal, $$Pviewer_process; + } + else { + warn "$My_name: viewer is supposed to be sent a signal\n", + " but no signal is defined. Misconfiguration or bug?\n"; + $return = 1; + } + } + elsif ($viewer_update_method == 4) { + if (defined $$Pext_cmd) { + $return = &Run_subst(); + } + else { + warn "$My_name: viewer is supposed to be updated by running a command,\n", + " but no command is defined. Misconfiguration or bug?\n"; + } + } + return $return; +} #END do_update_view + +#************************************************************ + +sub if_source { + # Unconditionally apply rule if source file exists. + # Assumes rule context + if ( -e $$Psource ) { + return &Run_subst(); + } + else { + warn "Needed source file '$$Psource' does not exist.\n"; + return -1; + } +} #END if_source + +#************************************************************ +#### Subroutines +#************************************************************ +#************************************************************ + +sub find_basename { + # Finds the basename of the root file + # Arguments: + # 1 - Filename to breakdown + # 2 - Where to place base file + # 3 - Where to place tex file + # Returns non-zero if tex file does not exist + + my $fail = 0; + local ( $given_name, $base_name, $ext, $path, $tex_name, $source_name ); + $given_name = $_[0]; + $source_name = ''; + $tex_name = $given_name; # Default name if I don't find the tex file + ($base_name, $path, $ext) = fileparseB( $given_name ); + + # Treatment of extensions (in TeXLive 2019), with omission of path search: + # Exists: always means exists as a file, i.e., not as a directory. + # A. Finding of tex file: + # 1. If extension is .tex and given_name.tex exists, use it. + # 2. Else if given_name.tex exists, use it. + # 3. Else if givne_name exists, use it. + # B. The base filename is obtained by deleting the path + # component and the extension. + # C. The names of generated files (log, aux) are obtained by appending + # .log, .aux, etc to the basename. Note that these are all in the + # CURRENT directory (or the output or aux directory, as appropriate). + # The drive/path part of the originally given filename is ignored. + + # Here we'll do: + # 1. Find the tex file by the above method, if possible. + # 2. If not, find a custom dependency with a source file that exists to + # make the tex file so that after the tex file is made, the above + # rules find the tex file. + # 3. If that also fails, use kpsewhich on given_name to find the tex + # file + # 4. If that also fails, report non-existent tex file. + + + if ( ($ext eq '.tex') && (-f $given_name) ) { + $tex_name = "$given_name"; + } + elsif ( -f "$given_name.tex" ) { + $tex_name = "$given_name.tex"; + $base_name .= $ext; + } + elsif ( -f $given_name ) { + $tex_name = $given_name; + } + elsif ( ($ext eq '.tex') && find_cus_dep( $given_name, $source_name ) ) { + $tex_name = $given_name; + } + elsif ( find_cus_dep( "$given_name.tex", \$source_name ) ) { + $tex_name = "$given_name.tex"; + $base_name .= $ext; + } + elsif ( ($ext =~ /^\..+/) && find_cus_dep( $given_name, $source_name ) ) { + $tex_name = $given_name; + } + else { + my @kpse_result = kpsewhich( $given_name ); + if ($#kpse_result < 0) { + $fail = 1; + } + else { + $tex_name = $kpse_result[0]; + ($base_name) = fileparseB( $tex_name ); + } + } + + $_[1] = $base_name; + $_[2] = $tex_name; + + if ($diagnostics) { + print "Given='$given_name', tex='$tex_name', base='$base_name', ext= $ext, source='$source_name'\n"; + } + return $fail; + +} #END find_basename + +#************************************************************ + +sub make_preview_continuous { + local @changed = (); + local %changed_rules = (); + local @changed_user = (); + local @disappeared = (); + local @no_dest = (); # Non-existent destination files + local @rules_never_run = (); + local @rules_to_apply = (); + + local $failure = 0; + local %rules_applied = (); + local $updated = 0; + + print "======= Need to update make_preview_continuous for target files\n"; + + $quell_uptodate_msgs = 1; + + if ( ($view eq 'dvi') || ($view eq 'pdf') || ($view eq 'ps') ) { + warn "Viewing $view\n"; + } + elsif ( $view eq 'none' ) { + warn "Not using a previewer\n"; + $view_file = ''; + } + else { + warn "$My_name: BUG: Invalid preview method '$view'\n"; + exit 20; + } + + my $viewer_running = 0; # No viewer known to be running yet + # Get information from update_view rule + local $viewer_update_method = 0; + # Pointers so we can update the following: + local $Pviewer_process = undef; + local $Pneed_to_get_viewer_process = undef; + rdb_one_rule( 'update_view', + sub{ $viewer_update_method = $$PAint_cmd[1]; + $Pviewer_process = \$$PAint_cmd[3]; + $Pneed_to_get_viewer_process = \$$PAint_cmd[4]; + } + ); + # Note that we don't get the previewer process number from the program + # that starts it; that might only be a script to get things set up and the + # actual previewer could be (and sometimes IS) another process. + + if ( ($view_file ne '') && (-e $view_file) && !$new_viewer_always ) { + # Is a viewer already running? + # (We'll save starting up another viewer.) + $$Pviewer_process = &find_process_id( $view_file ); + if ( $$Pviewer_process ) { + warn "$My_name: Previewer is already running\n" + if !$silent; + $viewer_running = 1; + $$Pneed_to_get_viewer_process = 0; + } + } + + # Loop forever, rebuilding .dvi and .ps as necessary. + # Set $first_time to flag first run (to save unnecessary diagnostics) + my $last_action_time = time(); + my $timed_out = 0; +CHANGE: + for (my $first_time = 1; 1; $first_time = 0 ) { + + my %rules_to_watch = array_to_hash( &rdb_accessible ); + + $updated = 0; + $failure = 0; + $failure_msg = ''; + if ( $MSWin_fudge_break && ($^O eq "MSWin32") ) { + # Fudge under MSWin32 ONLY, to stop perl/latexmk from + # catching ctrl/C and ctrl/break, and let it only reach + # downstream programs. See comments at first definition of + # $MSWin_fudge_break. + $SIG{BREAK} = $SIG{INT} = 'IGNORE'; + } + if ($compiling_cmd) { + Run_subst( $compiling_cmd ); + } + $failure = &rdb_make; + + if ( $MSWin_fudge_break && ($^O eq "MSWin32") ) { + $SIG{BREAK} = $SIG{INT} = 'DEFAULT'; + } + # Start viewer if needed. + if ( ($failure > 0) && (! $force_mode) ) { + # No viewer yet + } + elsif ( ($view_file ne '') && (-e $view_file) && $updated && $viewer_running ) { + # A viewer is running. Explicitly get it to update screen if we have to do it: + rdb_one_rule( 'update_view', \&rdb_run1 ); + } + elsif ( ($view_file ne '') && (-e $view_file) && !$viewer_running ) { + # Start the viewer + if ( !$silent ) { + if ($new_viewer_always) { + warn "$My_name: starting previewer for '$view_file'\n", + "------------\n"; + } + else { + warn "$My_name: I have not found a previewer that ", + "is already running. \n", + " So I will start it for '$view_file'\n", + "------------\n"; + } + } + local $retcode = 0; + rdb_one_rule( 'view', sub { $retcode = &rdb_run1;} ); + if ( $retcode != 0 ) { + if ($force_mode) { + warn "$My_name: I could not run previewer\n"; + } + else { + &exit_msg1( "I could not run previewer", $retcode); + } + } + else { + $viewer_running = 1; + $$Pneed_to_get_viewer_process = 1; + } # end analyze result of trying to run viewer + } # end start viewer + if ( $failure > 0 ) { + if ( !$failure_msg ) { + $failure_msg = 'Failure to make the files correctly'; + } + &rdb_set_rule_net; + %rules_to_watch = array_to_hash( &rdb_accessible ); + + # There will be files changed during the run that are irrelevant. + # We need to wait for the user to change the files. + + # So set the GENERATED files from *latex as up-to-date: + rdb_for_some( [keys %current_primaries], \&rdb_update_gen_files ); + + # And don't watch for changes for post_primary rules (ps and pdf + # from dvi, etc haven't been run after an error in *latex, so + # are out-of-date by filetime criterion, but they should not be run + # until after another *latex run: + foreach (@post_primary) { delete $rules_to_watch{$_}; } + + $failure_msg =~ s/\s*$//; #Remove trailing space + warn "$My_name: $failure_msg\n", + " ==> You will need to change a source file before I do another run <==\n"; + if ($failure_cmd) { + Run_subst( $failure_cmd ); + } + } + else { + if ( ($#primary_warning_summary > -1) && $warning_cmd ) { + Run_subst( $warning_cmd ); + } + elsif ( ($#primary_warning_summary > -1) && $warnings_as_errors && $failure_cmd ) { + Run_subst( $failure_cmd ); + } + elsif ($success_cmd) { + Run_subst( $success_cmd ); + } + } + rdb_show_rule_errors(); + if ($rules_list) { rdb_list(); } + if ($show_time && ! $first_time) { show_timing(); } + if ( $dependents_list && ($updated || $failure) ) { + my $deps_handle = new FileHandle "> $deps_file"; + if ( defined $deps_handle ) { + deps_list($deps_handle); + close($deps_handle); + } + else { + warn "Cannot open '$deps_file' for output of dependency information\n"; + } + } + + # Now wait for a file to change... + &rdb_cache_generated; + # During waiting for file changes, handle ctrl/C and ctrl/break here, + # rather than letting system handle them by terminating script (and + # code in the following command line to work: any script that calls + # it). This allows, for example, the command cleanup in the following + # command line to work: + # latexmk -pvc foo; cleanup; + &catch_break; + $have_break = 0; + $last_action_time = time(); + $waiting = 1; + print "\n=== Watching for updated files. Use ctrl/C to stop ...\n"; + WAIT: while (1) { + sleep( $sleep_time ); + if ($have_break) { last WAIT; } + if ( rdb_user_changes(keys %rules_to_watch) ) { + if (!$silent) { + warn "$My_name: Need to remake files.\n"; + &rdb_diagnose_changes( ' ' ); + } + last WAIT; + } + # Don't count waiting time in processing: + $processing_time1 = processing_time(); + # Does this do this job???? + local $new_files = 0; + rdb_for_some( [keys %current_primaries], sub{ $new_files += &rdb_find_new_files } ); + if ($new_files > 0) { + warn "$My_name: New file(s) found.\n"; + last WAIT; + } + if ($have_break) { last WAIT; } + if ($pvc_timeout && ( time() > $last_action_time+60*$pvc_timeout_mins ) ) { + $timed_out = 1; + last WAIT; + } + } # end WAIT: + &default_break; + if ($have_break) { + print "$My_name: User typed ctrl/C or ctrl/break. I'll finish.\n"; + return; + } + if ($timed_out) { + print "$My_name: More than $pvc_timeout_mins mins of inactivity. I'll finish.\n"; + return; + } + $waiting = 0; if ($diagnostics) { warn "NOT WAITING\n"; } + } #end infinite_loop CHANGE: +} #END sub make_preview_continuous + +#************************************************************ + +sub process_rc_file { + # Usage process_rc_file( filename ) + # NEW VERSION + # Run rc_file whose name is given in first argument + # Exit with code 0 on success + # Exit with code 1 if file cannot be read or does not exist. + # Stop if there is a syntax error or other problem. + # PREVIOUSLY: + # Exit with code 2 if is a syntax error or other problem. + my $rc_file = $_[0]; + my $ret_code = 0; + push @rc_files_read, $rc_file; + + # I could use the do command of perl, but the preceeding -r test + # to get good diagnostics gets the wrong result under cygwin + # (e.g., on /cygdrive/c/latexmk/LatexMk) + my $RCH = new FileHandle; + if ( !-e $rc_file ) { + warn "$My_name: The rc-file '$rc_file' does not exist\n"; + return 1; + } + elsif ( -d $rc_file ) { + warn "$My_name: The supposed rc-file '$rc_file' is a directory; but it\n", + " should be a normal text file\n"; + return 1; + } + elsif ( open $RCH, "<$rc_file" ) { + my $code = ''; + { local $/; $code = <$RCH>;} + close $RCH; + eval $code; + } + else { + warn "$My_name: I cannot read the rc-file '$rc_file'\n"; + return 1; + } + # PREVIOUS VERSION +# if ( ! -r $rc_file ) { +# warn "$My_name: I cannot read the rc-file '$rc_file'\n", +# " or at least that's what Perl (for $^O) reports\n"; +# return 1; +# } +# do( $rc_file ); + if ( $@ ) { + # Indent each line of possibly multiline message: + my $message = prefix( $@, " " ); + warn "$My_name: Initialization file '$rc_file' gave an error:\n", + "$message\n"; + die "$My_name: Stopping because of problem with rc file\n"; + # Use the following if want non-fatal error. + return 2; + } + return 0; +} #END process_rc_file + +#************************************************************ + +sub execute_code_string { + # Usage execute_code_string( string_of_code ) + # Run the perl code contained in first argument + # Halt if there is a syntax error or other problem. + # ???Should I leave the exiting to the caller (perhaps as an option)? + # But I can always catch it with an eval if necessary. + # That confuses ctrl/C and ctrl/break handling. + my $code = $_[0]; + warn "$My_name: Executing initialization code specified by -e:\n", + " '$code'...\n" + if $diagnostics; + eval $code; + # The return value from the eval is not useful, since it is the value of + # the last expression evaluated, which could be anything. + # The correct test of errors is on the value of $@. + + if ( $@ ) { + # Indent each line of possibly multiline message: + my $message = prefix( $@, " " ); + die "$My_name: ", + "Stopping because executing following code from command line\n", + " $code\n", + "gave an error:\n", + "$message\n"; + } +} #END execute_code_string + +#************************************************************ + +sub cleanup1 { + # Usage: cleanup1( directory, exts_without_period, ... ) + # + # The directory and the root file name are fixed names, so I must escape + # any glob metacharacters in them: + my $dir = fix_pattern( shift ); + my $root_fixed = fix_pattern( $root_filename ); + foreach (@_) { + my $name = /%R/ ? $_ : "%R.$_"; + $name =~ s/%R/${root_fixed}/; + $name = $dir.$name; + unlink_or_move( my_glob( "$name" ) ); + } +} #END cleanup1 + +#************************************************************ + +sub cleanup_cusdep_generated { + # Remove files generated by custom dependencies + rdb_for_actives( \&cleanup_one_cusdep_generated ); +} #END cleanup_cusdep_generated + +#************************************************************ + +sub cleanup_one_cusdep_generated { + # Remove destination file generated by one custom dependency + # Assume rule context, but not that the rule is a custom dependency. + # Only delete destination file if source file exists (so destination + # file can be recreated) + if ( $$Pcmd_type ne 'cusdep' ) { + # NOT cusdep + return; + } + if ( ! -e $$Psource ) { + warn "$My_name: For custom dependency '$rule',\n", + " I won't delete destination file '$$Pdest'\n", + " and any other generated files,\n", + " because the source file '$$Psource' doesn't exist,\n", + " so the destination file may not be able to be recreated\n"; + return; + } + unlink_or_move( $$Pdest, keys %$PHdest ); +} #END cleanup_one_cusdep_generated + +#************************************************************ +#************************************************************ +#************************************************************ + +# Error handling routines, warning routines, help + +#************************************************************ + +sub die_trace { + # Call: die_trace( message ); + &traceback; # argument(s) passed unchanged + die "\n"; +} #END die_trace + +#************************************************************ + +sub traceback { + # Call: traceback() + # or traceback( message ) + # NOT &traceback!!! + my $msg = shift; + if ($msg) { warn "$msg\n"; } + warn "Traceback:\n"; + my $i=0; # Start with immediate caller + while ( my ($pack, $file, $line, $func) = caller($i++) ) { + if ($func eq 'die_trace') { next; } + warn " $func called from line $line\n"; + } +} #END traceback + +#************************************************************ + +sub exit_msg1 +{ + # exit_msg1( error_message, retcode ) + # 1. display error message + # 2. exit with retcode + warn "\n------------\n"; + warn "$My_name: $_[0].\n"; + warn "-- Use the -f option to force complete processing.\n"; + + my $retcode = $_[1]; + if ($retcode >= 256) { + # Retcode is the kind returned by system from an external command + # which is 256 * command's_retcode + $retcode /= 256; + } + exit $retcode; +} #END exit_msg1 + +#************************************************************ + +sub warn_running { + # Message about running program: + if ( $silent ) { + warn "$My_name: @_\n"; + } + else { + warn "------------\n@_\n------------\n"; + } +} #END warn_running + +#************************************************************ + +sub exit_help +# Exit giving diagnostic from arguments and how to get help. +{ + warn "\n$My_name: @_\n", + "Use\n", + " $my_name -help\nto get usage information\n"; + exit 10; +} #END exit_help + + +#************************************************************ + +sub print_help +{ + print + "$My_name $version_num: Automatic LaTeX document generation routine\n\n", + "Usage: $my_name [latexmk_options] [filename ...]\n\n", + " Latexmk_options:\n", + " -aux-directory=dir or -auxdir=dir \n", + " - set name of directory for auxiliary files (aux, log)\n", + " - Currently this only works with MiKTeX\n", + " -bibtex - use bibtex when needed (default)\n", + " -bibtex- - never use bibtex\n", + " -bibtex-cond - use bibtex when needed, but only if the bib file exists\n", + " -bibtex-cond1 - use bibtex when needed, but only if the bib file exists;\n", + " on cleanup delete bbl file only if bib file exists\n", + " -bibfudge or -bibtexfudge - change directory to output directory when running bibtex\n", + " -bibfudge- or -bibtexfudge- - don't change directory when running bibtex\n", + " -bm - Print message across the page when converting to postscript\n", + " -bi - Set contrast or intensity of banner\n", + " -bs - Set scale for banner\n", + " -commands - list commands used by $my_name for processing files\n", + " -c - clean up (remove) all nonessential files, except\n", + " dvi, ps and pdf files.\n", + " This and the other clean-ups are instead of a regular make.\n", + " -C - clean up (remove) all nonessential files\n", + " including aux, dep, dvi, postscript and pdf files\n", + " and file of database of file information\n", + " -CA - clean up (remove) all nonessential files.\n", + " Equivalent to -C option.\n", + " -CF - Remove file of database of file information before doing \n", + " other actions\n", + " -cd - Change to directory of source file when processing it\n", + " -cd- - Do NOT change to directory of source file when processing it\n", + " -dependents or -deps - Show list of dependent files after processing\n", + " -dependents- or -deps- - Do not show list of dependent files\n", + " -deps-out=file - Set name of output file for dependency list,\n", + " and turn on showing of dependency list\n", + " -dF - Filter to apply to dvi file\n", + " -dir-report - Before processing a tex file, report aux and out dir settings\n", + " -dir-report- - Before processing a tex file, do not report aux and out dir settings\n", + " -dvi - generate dvi\n", + " -dvi- - turn off required dvi\n", + " -e - Execute specified Perl code (as part of latexmk start-up\n", + " code)\n", + " -emulate-aux-dir - emulate -aux-directory option for *latex\n", + " -emulate-aux-dir- - use -aux-directory option with *latex\n", + " -f - force continued processing past errors\n", + " -f- - turn off forced continuing processing past errors\n", + " -gg - Super go mode: clean out generated files (-CA), and then\n", + " process files regardless of file timestamps\n", + " -g - process at least one run of all rules\n", + " -g- - Turn off -g and -gg\n", + " -h - print help\n", + " -help - print help\n", + " -indexfudge or -makeindexfudge - change directory to output directory when running makeindex\n", + " -indexfudge- or -makeindexfudge- - don't change directory when running makeindex\n", + " -jobname=STRING - set basename of output file(s) to STRING.\n", + " (Like --jobname=STRING on command line for many current\n", + " implementations of latex/pdflatex.)\n", + " -l - force landscape mode\n", + " -l- - turn off -l\n", + " -latex= - set program used for latex.\n", + " (replace '' by the program name)\n", + " -latexoption=