%% algpseudocodex.sty %% Copyright 2017, 2020-2023 Christian Matt % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2008-05-04 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Christian Matt. % % This work consists of the files algpseudocodex.sty and algpseudocodex.tex. % Pseudocodex algorithmic style % Based on Szasz Janos' algpseudocode.sty \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{algpseudocodex}[2023-04-17 v1.1.2 pseudocode typesetting] \RequirePackage{kvoptions} \RequirePackage{algorithmicx} \RequirePackage{etoolbox} \RequirePackage{fifo-stack} \RequirePackage{varwidth} \RequirePackage{tabto} \RequirePackage{totcount} \RequirePackage{tikz} \usetikzlibrary{calc,fit,tikzmark} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Package options % \SetupKeyvalOptions{% family=algpx,% prefix=algpx@% } \DeclareBoolOption[true]{noEnd}% don't print end if etc. \DeclareBoolOption[true]{indLines}% show indent guide lines \DeclareBoolOption[true]{spaceRequire}% adds vertical space before \Require if not in first line \DeclareBoolOption[true]{italicComments}% italicise comments \DeclareBoolOption[true]{rightComments}% right justify comments \DeclareStringOption[gray]{commentColor}% color of comments \DeclareStringOption[$\triangleright$~]{beginComment}% print at beginning of comment \DeclareStringOption[]{endComment}% print at end of comment \DeclareStringOption[$\triangleright$~]{beginLComment}% print at beginning of long comment \DeclareStringOption[~$\triangleleft$]{endLComment}% print at end of long comment \ProcessLocalKeyvalOptions* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Styles % \tikzset{% algpxDefaultBox/.style={draw},% algpxIndentLine/.style={draw=gray,very thin}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Declarations % \algnewlanguage{pseudocodex} \alglanguage{pseudocodex} % \tikzmark is only available on next compilation; the following command immediately after using it \newcommand{\@tikzmarkNow}[2][]{\tikz[overlay,remember picture] \node[#1] (#2) {};} \long\def\@ifnodedefined#1#2#3{% \@ifundefined{pgf@sh@ns@#1}{#3}{#2}% } \newlength{\algpx@codeBoxInnerSep}% distance between box and its content \newlength{\algpx@codeBoxSep}% distance between nested boxes \newlength{\algpx@codeBoxOuterSep}% additional space before and after box % the following lengths related to indent lines are set when opening an algorithmic environment to reflect to current font size \newlength{\algpx@indShiftX}% indent line shifted right by that amount from beginning of line \newlength{\algpx@indStartShiftY}% start of indent line shifted up by that amount from beginning of line \newlength{\algpx@indEndShiftY}% end of indent line shifted up by that amount from beginning of line (only if noEnd=false, otherwise no shift) \newlength{\algpx@indXLineLength}% length of horizonal line drawn at end when noEnd=true \newlength{\algpx@minIndDist}% minimum distance between start and end of indent line to draw line \newlength{\algpx@oldPos} \newlength{\algpx@newPos} \newlength{\algpx@tmpLen}% length to be used for various things \newlength{\algpx@currentLineskiplimit}% used to restore lineskiplimit in varwidth \newlength{\algpx@currentLineskip}% used to restore lineskip in varwidth \newlength{\algpx@indStartY} \newlength{\algpx@indEndY} \newlength{\algpx@indStartX}% x coordinate of indent line \newlength{\algpx@extraShiftX}% current line is shifted by this amount right \newlength{\algpx@minTopPageHeight}% minimum for setting height of first line on page (used, e.g., to draw indent lines on page break) \newlength{\algpx@minBotPageDepth}% minimum for setting depth of last line on page (used, e.g., to draw indent lines on page break) \setlength{\algpx@codeBoxInnerSep}{2pt} \setlength{\algpx@codeBoxSep}{3pt} \setlength{\algpx@codeBoxOuterSep}{1pt} \settoheight{\algpx@minTopPageHeight}{\footnotesize9}% account for line numbers, which use \footnotesize \settodepth{\algpx@minBotPageDepth}{\footnotesize9}% account for line numbers, which use \footnotesize \newbool{algpx@firstLine} \newbool{algpx@setNorth}% whether codeBoxNorth should be set \newbool{algpx@executeEndVarwidth} \newbool{algpx@adjustHeight} \newbool{algpx@restorePrevdepth} \newbool{algpx@hasCheckedPageBreak}% whether checkPageBreak has been executed in current environment \newbool{algpx@indJustEnded}% true after end with noend \newbool{algpx@pageJustBroken}% \newcounter{algpx@codeBoxCount}% number of already created code boxes. Used to fill algpx@startNewCodeBoxQueue \newcounter{algpx@nestedCBoxCount} \newcounter{algpx@startedBoxesCount} \newcounter{algpx@endedBoxesCount} \newcounter{algpx@nestedBoxedStringCount} \newcounter{algpx@nestedBoxedStringMaxCount} \newcounter{algpx@indentCount} \newcounter{algpx@lastIndentEnded} \newcounter{algpx@pageCount}% counter of "pages" (columns in multi column format); incremented when page break is detected \newcounter{algpx@tmpCount}% temporary counter \FSCreate{algpx@startNewCodeBoxQueue}{0}% queue of code boxes to be created on next \State, \If etc. Only stores index of box (0 is value of top if empty; should not be relevant) \FSCreate{algpx@codeBoxStack}{0} \FSCreate{algpx@codeBoxStackTmp}{0} \FSCreate{algpx@indentStack}{0} \FSCreate{algpx@indentStackTmp}{0} \newsavebox{\algpx@boxedStringBox} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Macros for boxes around code % % Draw a box. First parameter is style, others are coordinates (north, west, east, south) \newcommand{\algpx@drawCodeBox}[5]{% \tikz[overlay,remember picture]{% \node[inner sep=\algpx@codeBoxInnerSep,#1,fit={(pic cs:#2) (pic cs:#3) (pic cs:#4) (pic cs:#5)}] {};% }% } % execute after \State, \If etc. \newcommand{\algpx@startCodeCommand}{% \algpx@startCodeCommandX{}{}% } % execute before printing end if etc. \newcommand{\algpx@startEndBlockCommand}{% % add space for indentation because of how ALG@nested is computed \algpx@startCodeCommandX[1]{}{\hspace*{\algorithmicindent}}% } % extended version of \algpx@startCodeCommand % first argument 1 if executed in \algpx@startEndBlockCommand % second argument is printed before content % third argument is used to reserve space after contents (for end symbol of long comments) \newcommand{\algpx@startCodeCommandX}[3][0]{% \setbool{algpx@indJustEnded}{false}% \setcounter{algpx@startedBoxesCount}{0}% \setcounter{algpx@endedBoxesCount}{0}% \setcounter{algpx@nestedBoxedStringMaxCount}{0}% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}% \algpx@drawCodeBox{algpx@codeBoxStyle-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}% \FSPop{algpx@startNewCodeBoxQueue}% \setbool{algpx@setNorth}{true}% \stepcounter{algpx@startedBoxesCount}% }% \algpx@setCodeBoxWest% % check for page break only if indent line is open because page breaks are only used for this \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}}}{% \algpx@checkPageBreak[#1]% }{}% \setbool{algpx@firstLine}{false}% \setbool{algpx@executeEndVarwidth}{true}% #2% % create box from here to end of line, leaving space for #3 \settowidth{\algpx@extraShiftX}{#2}% remember that line actually starts further right than last box \settowidth{\algpx@tmpLen}{#3}% \setlength{\algpx@currentLineskiplimit}{\lineskiplimit}% remember value of lineskiplimit \setlength{\algpx@currentLineskip}{\lineskip}% remember value of lineskip \begin{varwidth}[t]{\dimexpr \linewidth - \algpx@extraShiftX - \algpx@tmpLen - \algorithmicindent * \numexpr \value{ALG@nested} - 1 \relax \relax}% \setlength{\lineskiplimit}{\algpx@currentLineskiplimit}% restore lineskiplimit value \setlength{\lineskip}{\algpx@currentLineskip}% restore lineskip value } % executed before \State, \If etc., i.e., at end of previous line % first argument 1 if after \EndIf etc. and noend \newcommand{\algpx@endCodeCommand}[1][0]{% \ifbool{algpx@executeEndVarwidth}{% \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982 \end{varwidth}\setbox0=\lastbox\usebox0% \setbool{algpx@executeEndVarwidth}{false}% \setbool{algpx@adjustHeight}{true}% \setbool{algpx@restorePrevdepth}{true}% }{}% \ifbool{algpx@setNorth}{% % todo: north should not be set again if highest element in current line is BoxedString \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line \setbool{algpx@setNorth}{false}% }{}% \algpx@setCodeBoxEast% % remember position of ending line and possibly set north of page % not necessary if no indent lines are open or just ended (because EndIf with noEnd cannot break page) \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}} and not bool{algpx@indJustEnded}}{% \algpx@setLineEndPos% }{}% \ifbool{algpx@adjustHeight}{% % todo: if highest or deepest element in current line is BoxedString, \ht0 or \dp0 should be adjusted for different sep values \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{\the\ht0}{\value{algpx@endedBoxesCount}}{\the\dp0}% \setbool{algpx@adjustHeight}{false}% }{}% \ifboolexpr{bool{algpx@restorePrevdepth} and test{\ifstrequal{#1}{0}}}{% \par\prevdepth\algpx@pdtemp% \setbool{algpx@restorePrevdepth}{false}% }{}% } % Checks whether current line starts on new page (or column) by comparing y position with previous line. % If so, draws indent lines neither starting nor ending on this page. % Optional argument is 1 if executed on end block with noEnd=false. % % Note: We do not rely on \iftikzmarkonpage because, e.g., in double-column format, lines can be on the same page, % but we want to consider them to be on different pages. \newcommand{\algpx@checkPageBreak}[1][0]{% \ifbool{algpx@hasCheckedPageBreak}{% first line of code cannot be on new page % extract y positions of previous line \tikz[overlay,remember picture]{% \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@currentStartYPos}{center}}% \global\algpx@oldPos=\algpx@oldPos% }% % current pos is 0, so if last pos is less than that, we are on new page \ifdimcomp{\algpx@oldPos}{<}{0ex}{% % set south of previous page to y pos last saved in \algpx@setLineEndPos \tikz[overlay,remember picture]{% \tikzmark{algpx@pageSouth-\thealgpx@pageCount}{(algpx@currentEndYPos)}% }% \stepcounter{algpx@pageCount}% \setbool{algpx@pageJustBroken}{true}% % all currently open indent lines have started on earlier page. % Draw full line from top to bottom for all of those not ending on this page either \algpx@drawIndentLinesOnPageBreak[#1]% }{% \tikz[overlay,remember picture]{}% dummy to keep in sync \tikz[overlay,remember picture]{}% dummy to keep in sync (inside drawIndentLinesOnPageBreak) }% }{}% \@tikzmarkNow{algpx@currentStartYPos}% save y position of current line to compare next time \setbool{algpx@hasCheckedPageBreak}{true}% } % Remember current position as south of page and set north of current page if page was just broken. \newcommand{\algpx@setLineEndPos}{% % save y position of current line shifted down the depth of current line to later use for pageSouth coordinate in \algpx@checkPageBreak % shift down at least by \algpx@minBotPageDepth \ifdimcomp{\the\dp0}{<}{\algpx@minBotPageDepth}{% \@tikzmarkNow[yshift=-\algpx@minBotPageDepth]{algpx@currentEndYPos}% }{% \@tikzmarkNow[yshift=-\the\dp0]{algpx@currentEndYPos}% }% % right after pagebreak, set north of current page \ifbool{algpx@pageJustBroken}{% % shift to beginning of line and also shift up by height of current line, but last least \algpx@minTopPageHeight % also shift to left by \wd0 (width of last box, i.e., of line in varwidth) + \algpx@extraShiftX to get x position at beginning of line \tikz[overlay,remember picture]{% \ifdimcomp{\the\ht0}{<}{\algpx@minTopPageHeight}{% \coordinate (algpx@pageNorth) at (-\wd0 - \algpx@extraShiftX,\algpx@minTopPageHeight);% }{% \coordinate (algpx@pageNorth) at (-\wd0 - \algpx@extraShiftX,\the\ht0);% }% \tikzmark{algpx@pageNorth-\thealgpx@pageCount}{(algpx@pageNorth)}% }% \setbool{algpx@pageJustBroken}{false}% }{% \tikz[overlay,remember picture]{}% dummy to keep in sync }% } % set algpx@codeBoxNorthMax of current box and all ancestors; argument is amount to shift up from current baseline \newcommand{\algpx@setCodeBoxNorth}[1]{% \setcounter{algpx@nestedCBoxCount}{0}% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp \@ifnodedefined{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{% % get current position; shift according to nest-level to ensure nested boxes don't collide \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthHere}% % extract y-coordinate of previously stored north \tikz[overlay,remember picture]{% \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{center}}% \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxNorthHere}{center}}% \global\algpx@oldPos=\algpx@oldPos% \global\algpx@newPos=\algpx@newPos% }% \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{% % new y is greater than old one, so set it \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}% }{% \@tikzmarkNow{algpx@codeBoxNorthDummy}% set something to keep in sync }% }{% \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}% }% \FSPop{algpx@codeBoxStack}% \stepcounter{algpx@nestedCBoxCount}% }% % restore stack from tmp \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% \FSPop{algpx@codeBoxStackTmp}% }% } % set algpx@codeBoxSouthMax of current box and all ancestors; argument is amount to shift down from current baseline \newcommand{\algpx@setCodeBoxSouth}[1]{% \setcounter{algpx@nestedCBoxCount}{0}% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp \@ifnodedefined{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{% % get current position; shift according to nest-level to ensure nested boxes don't collide \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthHere}% % extract y-coordinate of previously stored south \tikz[overlay,remember picture]{% \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{center}}% \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxSouthHere}{center}}% \global\algpx@oldPos=\algpx@oldPos% \global\algpx@newPos=\algpx@newPos% }% \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{% % new y is less than old one, so set it \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}% }{% \@tikzmarkNow{algpx@codeBoxSouthDummy}% set something to keep in sync }% }{% \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}% }% \FSPop{algpx@codeBoxStack}% \stepcounter{algpx@nestedCBoxCount}% }% % restore stack from tmp \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% \FSPop{algpx@codeBoxStackTmp}% }% } % set algpx@codeBoxWestMax of current box and all ancestors; argument is amount to shift left from current position \newcommand{\algpx@setCodeBoxWest}[1][0pt]{% \setcounter{algpx@nestedCBoxCount}{0}% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp \@ifnodedefined{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{% % get current position; shift according to nest-level to ensure nested boxes don't collide \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestHere}% % extract x-coordinate of previously stored west \tikz[overlay,remember picture]{% \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{center}}% \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxWestHere}{center}}% \global\algpx@oldPos=\algpx@oldPos% \global\algpx@newPos=\algpx@newPos% }% \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{% % new x is smaller than old one, so set it \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}% }{% \@tikzmarkNow{algpx@codeBoxWestDummy}% set something to keep in sync }% }{% \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}% }% \FSPop{algpx@codeBoxStack}% \stepcounter{algpx@nestedCBoxCount}% }% % restore stack from tmp \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% \FSPop{algpx@codeBoxStackTmp}% }% } % set algpx@codeBoxEastMax of current box and all ancestors \newcommand{\algpx@setCodeBoxEast}{% \setcounter{algpx@nestedCBoxCount}{0}% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp \@ifnodedefined{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{% % get current position; shift according to nest-level to ensure nested boxes don't collide \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastHere}% % extract x-coordinate of previously stored east \tikz[overlay,remember picture]{% \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{center}}% \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxEastHere}{center}}% \global\algpx@oldPos=\algpx@oldPos% \global\algpx@newPos=\algpx@newPos% }% \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{% % new x is greater than old one, so set it \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}% }{% \@tikzmarkNow{algpx@codeBoxEastDummy}% set something to keep in sync }% }{% \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}% }% \FSPop{algpx@codeBoxStack}% \stepcounter{algpx@nestedCBoxCount}% }% % restore stack from tmp \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% \FSPop{algpx@codeBoxStackTmp}% }% } % Set coordinates of box on top of algpx@codeBoxStack to maximal reported values. % This ensures, e.g., that the right edge of the box is after the longest line inside. \newcommand{\algpx@setBoxesToStoredMax}{% \tikz[overlay,remember picture]{% \tikzmark{algpx@codeBoxNorth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack})}% \tikzmark{algpx@codeBoxSouth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack})}% \tikzmark{algpx@codeBoxWest-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack})}% \tikzmark{algpx@codeBoxEast-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack})}% }% } % add some space above and below box; more if several boxes are nested % first argument: number of boxes above % second argument: height of content % third argument: number of boxes below % fourth argument: depth of content \newcommand{\algpx@addBoxSpacing}[4]{% \ifnumcomp{0}{<}{#1}{% \rule{0pt}{\dimexpr #2 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#1 - 1))\relax}% }{}% \ifnumcomp{0}{<}{#3}{% \rule[\dimexpr -#4 - \algpx@codeBoxInnerSep - \algpx@codeBoxOuterSep - (\algpx@codeBoxSep * (#3 - 1))\relax]{0pt}{\dimexpr #4 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#3 - 1))\relax}% negative offset equal to height to draw line down from baseline }{}% } % Begin a new code box here. % Must be followed by \State, \If, \For etc. % (optional) argument is style of box \newcommand{\BeginBox}[1][algpxDefaultBox]{% \ignorespaces% \FSUnshift{algpx@startNewCodeBoxQueue}{\thealgpx@codeBoxCount}% add to queue; processed by \algpx@startCodeCommand %globally set tikz style (https://tex.stackexchange.com/a/47918) \begingroup% \globaldefs=1\relax% \pgfqkeys{/tikz}{algpx@codeBoxStyle-\thealgpx@codeBoxCount/.style={#1}}% \endgroup% \stepcounter{algpx@codeBoxCount}% \ignorespaces% } % End one open code box. Fails if no box open (i.e., if algpx@codeBoxStack is empty). \newcommand{\EndBox}{% \ignorespaces% \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{% \PackageError{algpseudocodex}{BeginBox must be followed by State, If, For, etc. Use BoxedString instead}{}% \FSClear{algpx@startNewCodeBoxQueue}% }{% \ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}{% \unskip% \ifbool{algpx@executeEndVarwidth}{% \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982 \end{varwidth}\setbox0=\lastbox\usebox0% \setbool{algpx@executeEndVarwidth}{false}% \setbool{algpx@adjustHeight}{true}% \setbool{algpx@restorePrevdepth}{true}% }{}% \ifbool{algpx@setNorth}{% \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line \setbool{algpx@setNorth}{false}% }{}% \algpx@setCodeBoxEast% \ifbool{algpx@indJustEnded}{% \algpx@setCodeBoxSouth{0pt}% set south here, don't shift after end with noEnd % add space after boxes. Otherwise done by endCodeCommand, but this is not executed after End with noEnd \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{0pt}{\numexpr \value{algpx@endedBoxesCount} + 1 \relax}{0pt}% }{% \algpx@setCodeBoxSouth{\the\dp0}% set south here shifted by depth of current line }% %adjust stored prevdepth for ended boxes \ifnumcomp{0}{<}{\value{algpx@endedBoxesCount}}{% \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxSep \relax}% }{% \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep \relax}% }% \algpx@setBoxesToStoredMax% \FSPop{algpx@codeBoxStack}% \stepcounter{algpx@endedBoxesCount}% }{% \PackageError{algpseudocodex}{No box to end}{}% }% }% \ignorespaces% } % Draw box within a single line of code. % (Optional) first argument is style of the box. % Second argument is the string to print inside the box. \newcommand{\BoxedString}[2][algpxDefaultBox]{% \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{% \setcounter{algpx@nestedBoxedStringMaxCount}{0}% reset max count for new boxes }{}% \stepcounter{algpx@nestedBoxedStringCount}% \ifnumcomp{\value{algpx@nestedBoxedStringMaxCount}}{<}{\value{algpx@nestedBoxedStringCount}}{% \setcounter{algpx@nestedBoxedStringMaxCount}{\value{algpx@nestedBoxedStringCount}}% }{}% \algpx@drawCodeBox{#1}{algpx@codeBoxNorth-\thealgpx@codeBoxCount}{algpx@codeBoxWest-\thealgpx@codeBoxCount}{algpx@codeBoxEast-\thealgpx@codeBoxCount}{algpx@codeBoxSouth-\thealgpx@codeBoxCount}% \FSPush{algpx@codeBoxStack}{\thealgpx@codeBoxCount}% \stepcounter{algpx@codeBoxCount}% \algpx@setCodeBoxWest% \ifmmode% % This works in equation but not in align / displaystyle etc. gets lost \savebox{\algpx@boxedStringBox}{$\m@th#2$}% \usebox{\algpx@boxedStringBox}% \else% \savebox{\algpx@boxedStringBox}{#2}% \usebox{\algpx@boxedStringBox}% \fi% \algpx@setCodeBoxEast% \algpx@setCodeBoxNorth{\the\ht\algpx@boxedStringBox}% \algpx@setCodeBoxSouth{\the\dp\algpx@boxedStringBox}% \algpx@setBoxesToStoredMax% \FSPop{algpx@codeBoxStack}% \addtocounter{algpx@nestedBoxedStringCount}{-1}% BoxedString ends here \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{% \algpx@addBoxSpacing{\value{algpx@nestedBoxedStringMaxCount}}{\the\ht\algpx@boxedStringBox}{\value{algpx@nestedBoxedStringMaxCount}}{\the\dp\algpx@boxedStringBox}% }{}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Macros for indentation lines % % start indented block \newcommand{\algpx@startIndent}{% \ifbool{algpx@indLines}{% % Define counter for the page on which this indent line ends. % The use of totcount ensures the last value is preserved during compilations and thus can be used before setting it. % expansion is needed because name contains variable, see % https://tex.stackexchange.com/questions/517559/why-cant-the-name-of-a-totcounter-be-defined-with-a-variable \expanded{\noexpand\newtotcounter{algpx@indentEndPage-\thealgpx@indentCount}}% % set start coordinate here and draw indent line % Note: Draw already here because endIndent could already be called on next page if end is at last line of page. \tikz[overlay,remember picture]{% \coordinate (startPos) at (\algpx@indShiftX,\algpx@indStartShiftY); \algpx@drawIndentLine{\thealgpx@indentCount}{startPos}% }% \FSPush{algpx@indentStack}{\thealgpx@indentCount}% \stepcounter{algpx@indentCount}% }{}% } % end of indented block % optional argument 1 means that only interrupted by else, 2 means ended with until \newcommand{\algpx@endIndent}[1][0]{% \ifbool{algpx@indLines}{% % remember on which page indent line ends (remembered through compiliations because we use totcount) \setcounter{algpx@indentEndPage-\FSTop{algpx@indentStack}}{\value{algpx@pageCount}}% \tikz[overlay,remember picture]{% \ifboolexpr{bool{algpx@indJustEnded} and test{\ifstrequal{#1}{0}}}{% % if another line has just ended, use same coordinates as for previous end % to this end, remember index of previous end to use \expanded{\noexpand\newtotcounter{algpx@indentEndCoordIndex-\FSTop{algpx@indentStack}}}% \setcounter{algpx@indentEndCoordIndex-\FSTop{algpx@indentStack}}{\thealgpx@lastIndentEnded}% }{% % if not just ended, use current position (0,0) as end \ifboolexpr{bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{% % Draw additional line to right if noend and line is not interrupted and move down by current line depth. % Note: we are now at the end of the line, so the x position is too far right. % We solve this in \algpx@drawIndentLine by going at most \algpx@indShiftX to the right. % Adjusting here would require access to the start position and thus an additional compilation. \coordinate (algpx@indentEndCoord) at (\algpx@indShiftX+\algpx@indXLineLength,-\the\dp0);% }{% % if using end or interrupted by else etc., use current position shifted by default values \coordinate (algpx@indentEndCoord) at (\algpx@indShiftX,\algpx@indEndShiftY);% }% % remember end position using \tikzmark so it can be accessed by \algpx@startIndent before \tikzmark{algpx@indentEnd-\FSTop{algpx@indentStack}}{(algpx@indentEndCoord)}% }% }% }{}% % set indJustEnded even if indLines are not drawn; also used for EndBox \ifboolexpr{not bool{algpx@indJustEnded} and bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{% \setbool{algpx@indJustEnded}{true}% \ifbool{algpx@indLines}{% \setcounter{algpx@lastIndentEnded}{\FSTop{algpx@indentStack}}% }{}% }{}% \ifbool{algpx@indLines}{% \FSPop{algpx@indentStack}% \ifstrequal{#1}{1}{% \algpx@startIndent% start new line if only interrupted }{}% }{}% } % Draw indent line with index #1 and start coordinate (#2). % To be called inside a TikZ picture. \newcommand{\algpx@drawIndentLine}[2]{% \ifnumcomp{\totvalue{algpx@indentEndPage-#1}}{>}{\value{algpx@pageCount}}{% % if indentation does not end on the same page, draw line to end of page with x position of start \coordinate (algpx@indentEndCoord) at (#2 |- {pic cs:algpx@pageSouth-\thealgpx@pageCount});% }{% % otherwise, indentation ends on same page \@ifundefined{c@algpx@indentEndCoordIndex-#1@totc}{% % if no indentEndCoordIndex is stored, just use stored end position \coordinate (algpx@indentEndCoord) at (pic cs:algpx@indentEnd-#1);% }{% % if indentEndCoordIndex is defined, another line has just ended and we use the same y coordinates as for previous end \coordinate (algpx@indentEndCoord) at (pic cs:algpx@indentEnd-\the\totvalue{algpx@indentEndCoordIndex-#1});% }% }{}% % Only draw if there is minimum distance between start and end \pgfextracty{\algpx@indStartY}{\pgfpointanchor{#2}{center}}% \pgfextracty{\algpx@indEndY}{\pgfpointanchor{algpx@indentEndCoord}{center}}% \ifdimcomp{\algpx@indStartY - \algpx@indEndY}{>}{\algpx@minIndDist}{% % draw in straight lines from start position (#2) to end coordinate, but with x position at most start + \algpx@indXLineLength since end position is set at end of line in \algpx@endIndent \draw[algpxIndentLine] let \p1=(#2), \p2=(algpx@indentEndCoord) in (#2) |- ({min(\x2, \x1 + \algpx@indXLineLength)}, \y2);% }{}% } % For all open indent lines not ending on current page, draw from top to bottom of page % Optional argument is 1 if executed on end block with noEnd=false. \newcommand{\algpx@drawIndentLinesOnPageBreak}[1][0]{% \tikz[overlay,remember picture]{% % iterate over all open indent lines \ifstrequal{#1}{0}{% \setcounter{algpx@tmpCount}{0}% tmp counter to count interations }{% % if ending block here, the last indentation has already ended and line won't be drawn % start counting at -1 to get correct indentation of later ending lines. \setcounter{algpx@tmpCount}{-1}% }% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}}}{% \FSPush{algpx@indentStackTmp}{\FSTop{algpx@indentStack}}% copy stack to tmp \stepcounter{algpx@tmpCount}% % draw line to bottom of page % set beginning of line to north of page (with x set to beginning of line, see \algpx@checkPageBreak) % shifted by the number indentations \coordinate (startPos) at ($(pic cs:algpx@pageNorth-\thealgpx@pageCount) - (\dimexpr \algorithmicindent * \value{algpx@tmpCount} - \algpx@indShiftX \relax, 0ex)$);% \algpx@drawIndentLine{\FSTop{algpx@indentStack}}{startPos}% % finally remove top element \FSPop{algpx@indentStack}% }% % restore stack from tmp \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStackTmp}}}}{% \FSPush{algpx@indentStack}{\FSTop{algpx@indentStackTmp}}% \FSPop{algpx@indentStackTmp}% }% }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Keywords % \algnewcommand\algorithmicend{\textbf{end}} \algnewcommand\algorithmicdo{\textbf{do}} \algnewcommand\algorithmicwhile{\textbf{while}} \algnewcommand\algorithmicfor{\textbf{for}} \algnewcommand\algorithmicforall{\textbf{for all}} \algnewcommand\algorithmicloop{\textbf{loop}} \algnewcommand\algorithmicrepeat{\textbf{repeat}} \algnewcommand\algorithmicuntil{\textbf{until}} \algnewcommand\algorithmicprocedure{\textbf{procedure}} \algnewcommand\algorithmicfunction{\textbf{function}} \algnewcommand\algorithmicif{\textbf{if}} \algnewcommand\algorithmicthen{\textbf{then}} \algnewcommand\algorithmicelse{\textbf{else}} \algnewcommand\algorithmicrequire{\textbf{Require:}} \algnewcommand\algorithmicensure{\textbf{Ensure:}} \algnewcommand\algorithmicreturn{\textbf{return}} \algnewcommand\algorithmicoutput{\textbf{output}} \algnewcommand\textproc{\textsc} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Loops, conditional statements, and functions % \algdef{SE}[WHILE]{While}{EndWhile}[1]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicwhile\ #1\ \algorithmicdo% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicwhile% } \algdef{SE}[FOR]{For}{EndFor}[1]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicfor\ #1\ \algorithmicdo% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicfor% } \algdef{S}[FOR]{ForAll}[1]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicforall\ #1\ \algorithmicdo% } \algdef{SE}[LOOP]{Loop}{EndLoop}{% \algpx@startCodeCommand\algpx@startIndent\algorithmicloop% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicloop% } \algdef{SE}[REPEAT]{Repeat}{Until}{% \algpx@startCodeCommand\algpx@startIndent\algorithmicrepeat% }[1]{% \algpx@startEndBlockCommand\algpx@endIndent[2]\algorithmicuntil\ #1% } \algdef{SE}[IF]{If}{EndIf}[1]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicif\ #1\ \algorithmicthen% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicif% } \algdef{C}[IF]{IF}{ElsIf}[1]{% \algpx@startCodeCommand\algpx@endIndent[1]\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen% } \algdef{Ce}[ELSE]{IF}{Else}{EndIf}{% \algpx@startCodeCommand\algpx@endIndent[1]\algorithmicelse% } \algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicprocedure\ \textproc{#1}\ifstrempty{#2}{}{(#2)}% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicprocedure% } \algdef{SE}[FUNCTION]{Function}{EndFunction}[2]{% \algpx@startCodeCommand\algpx@startIndent\algorithmicfunction\ \textproc{#1}\ifstrempty{#2}{}{(#2)}% }{% \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicfunction% } \ifbool{algpx@noEnd}{% \algtext*{EndWhile}% \algtext*{EndFor}% \algtext*{EndLoop}% \algtext*{EndIf}% \algtext*{EndProcedure}% \algtext*{EndFunction}% % % end indent line before end command \pretocmd{\EndWhile}{\algpx@endIndent}{}{}% \pretocmd{\EndFor}{\algpx@endIndent}{}{}% \pretocmd{\EndLoop}{\algpx@endIndent}{}{}% \pretocmd{\EndIf}{\algpx@endIndent}{}{}% \pretocmd{\EndProcedure}{\algpx@endIndent}{}{}% \pretocmd{\EndFunction}{\algpx@endIndent}{}{}% }{}% % execute \algpx@endCodeCommand before \State, \If etc. \pretocmd{\State}{\algpx@endCodeCommand}{}{} \pretocmd{\While}{\algpx@endCodeCommand}{}{} \pretocmd{\For}{\algpx@endCodeCommand}{}{} \pretocmd{\ForAll}{\algpx@endCodeCommand}{}{} \pretocmd{\Loop}{\algpx@endCodeCommand}{}{} \pretocmd{\Repeat}{\algpx@endCodeCommand}{}{} \pretocmd{\Until}{\algpx@endCodeCommand}{}{} \pretocmd{\If}{\algpx@endCodeCommand}{}{} \pretocmd{\ElsIf}{\algpx@endCodeCommand}{}{} \pretocmd{\Else}{\algpx@endCodeCommand}{}{} \pretocmd{\Procedure}{\algpx@endCodeCommand}{}{} \pretocmd{\Function}{\algpx@endCodeCommand}{}{} % for end commands that may not be printed, tell endCodeCommand whether we are using noEnd \ifbool{algpx@noEnd}{% \pretocmd{\EndWhile}{\algpx@endCodeCommand[1]}{}{}% \pretocmd{\EndFor}{\algpx@endCodeCommand[1]}{}{}% \pretocmd{\EndLoop}{\algpx@endCodeCommand[1]}{}{}% \pretocmd{\EndIf}{\algpx@endCodeCommand[1]}{}{}% \pretocmd{\EndProcedure}{\algpx@endCodeCommand[1]}{}{}% \pretocmd{\EndFunction}{\algpx@endCodeCommand[1]}{}{}% }{% \pretocmd{\EndWhile}{\algpx@endCodeCommand[0]}{}{}% \pretocmd{\EndFor}{\algpx@endCodeCommand[0]}{}{}% \pretocmd{\EndLoop}{\algpx@endCodeCommand[0]}{}{}% \pretocmd{\EndIf}{\algpx@endCodeCommand[0]}{}{}% \pretocmd{\EndProcedure}{\algpx@endCodeCommand[0]}{}{}% \pretocmd{\EndFunction}{\algpx@endCodeCommand[0]}{}{}% }% % execute \algpx@startCodeCommand after \State (this is done for loops etc. inside the definitions above) \apptocmd{\State}{\algpx@startCodeCommand}{}{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Other declarations % % dirty hack: execute drawing in argument of item and rest of \algpx@startCodeCommand outside % argument: text in item[.] \newcommand{\algpx@drawInItem}[1]{% \item[% \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}% \algpx@drawCodeBox{algpx@codeBoxStyle-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}% \FSPop{algpx@startNewCodeBoxQueue}% \stepcounter{algpx@startedBoxesCount}% }% #1% ]% \setbool{algpx@indJustEnded}{false}% \setcounter{algpx@startedBoxesCount}{0}% \setcounter{algpx@endedBoxesCount}{0}% \setcounter{algpx@nestedBoxedStringMaxCount}{0}% \settowidth{\algpx@tmpLen}{#1}% \algpx@setCodeBoxWest[\dimexpr \labelsep + \algpx@tmpLen \relax]% \setbool{algpx@firstLine}{false}% \setbool{algpx@executeEndVarwidth}{true}% \setlength{\algpx@currentLineskiplimit}{\lineskiplimit}% remember value of lineskiplimit \setlength{\algpx@currentLineskip}{\lineskip}% remember value of lineskip \begin{varwidth}[t]{\dimexpr \linewidth - \labelsep - \algpx@tmpLen + \leftmargin \relax}% \setlength{\lineskiplimit}{\algpx@currentLineskiplimit}% restore lineskiplimit value \setlength{\lineskip}{\algpx@currentLineskip}% restore lineskip value \settoheight{\algpx@tmpLen}{#1}% \rule{0pt}{\algpx@tmpLen}% } \algnewcommand\Require{% \algpx@endCodeCommand% \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}% \ifboolexpr{bool{algpx@spaceRequire} and not bool{algpx@firstLine}}{% \medskip% }{}% \algpx@drawInItem{\algorithmicrequire}% } \algnewcommand\Ensure{% \algpx@endCodeCommand% \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}% \algpx@drawInItem{\algorithmicensure}% } \algnewcommand\Return{\algorithmicreturn{} } \algnewcommand\Output{\algorithmicoutput{} } \algnewcommand\Call[2]{\textproc{#1}\ifstrempty{#2}{}{(#2)}} %% internal methods to format comment % format according to comment format \newcommand{\algpx@commentFormat}[1]{% \ifbool{algpx@italicComments}{% \textit{\textcolor{\algpx@commentColor}{#1}}% }{% \textcolor{\algpx@commentColor}{#1}% }% } % get string for inline comment including begin and end markers \newcommand{\algpx@commentString}[1]{% \algpx@commentFormat{\algpx@beginComment#1\algpx@endComment}% } % redefine \Comment \algrenewcomment[1]{% \ifbool{algpx@rightComments}{% \settowidth{\algpx@tmpLen}{\algpx@commentString{#1}}% set temp variable to width of comment \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here \ifdimcomp{\algpx@tmpLen}{<}{\dimexpr \linewidth - \TabPrevPos \relax}{% check whether comment fits on line \tabto{\dimexpr \linewidth - \algpx@tmpLen \relax}% move position to right justify text \algpx@commentString{#1}% print comment }{% \algpx@commentString{#1}% if it doesn't fit, just print normally, allowing line break }% }{% \algpx@commentString{#1}% just print normally if not right justified }% \ignorespaces% }% % Long comment starting on new line. % Can span several lines and in contrast to \Comment, never right justified. \algdef{SL}[LCOMMENT]{LComment}{0}[1]{% \algpx@startCodeCommandX{\algpx@commentFormat{\algpx@beginLComment}}{\algpx@commentFormat{\algpx@endLComment}}% \algpx@commentFormat{#1}% print actual comment \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here \setlength{\algpx@tmpLen}{\dimexpr \linewidth - \TabPrevPos \relax}% set to remaining space on line \makebox[0pt][l]{% start box here that takes no space (otherwise impacts spacing of text before) \rule{\algpx@tmpLen}{0pt}% draw invisible rule from beginning of line until end of comment text \algpx@commentFormat{\algpx@endLComment}% print end comment at the end \algpx@setCodeBoxEast% since this takes 0 space, we have to set east of code box here explicitly }% }% \pretocmd{\LComment}{\algpx@endCodeCommand}{}{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Execute at beginning and end of algorithmic environment % \AtBeginEnvironment{algorithmic}{% \setbool{algpx@firstLine}{true}% \setbool{algpx@setNorth}{false}% \setbool{algpx@executeEndVarwidth}{false}% \setbool{algpx@adjustHeight}{false}% \setbool{algpx@restorePrevdepth}{false}% \setbool{algpx@hasCheckedPageBreak}{false}% \setbool{algpx@pageJustBroken}{false}% \setcounter{algpx@startedBoxesCount}{0}% \setcounter{algpx@endedBoxesCount}{0}% % % Set lengths here to use correct font sizes \setlength{\algpx@indShiftX}{0.12em}% \setlength{\algpx@indStartShiftY}{-0.8ex}% \setlength{\algpx@indEndShiftY}{2.0ex}% \setlength{\algpx@indXLineLength}{0.5em}% \setlength{\algpx@minIndDist}{0.7ex}% } \AtEndEnvironment{algorithmic}{% \algpx@endCodeCommand% % Error checking \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}} or test {\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% \PackageError{algpseudocodex}{Some boxes have not ended}{}% }{}% }