Here is my attempt to generate a pseudocode for algorithmicx package.
Current features
- Functions (as
SetDelayed
)
Set
If
with 2 and 3 arguments
While
Do
(any number of variables of any type) New!
Return
Module
, With
, and Block
CompoundExpression
(;
)
- Test functions (
EvenQ
, etc., and Not@EvenQ
, etc.) New!
- Indentation
Code
ClearAll[pseudocode, pscd]
SetAttributes[{pseudocode, pscd, texstring}, HoldFirst];
indent[n_] := "\n" <> ConstantArray[" ", n];
pscd[SetDelayed[f_[x___], code_], n_: 0, m_: 0] :=
indent[n] <> "\\Function{" <> pscd@f <> "}{" <>
Riffle[pscd@Hold@x, ","] <> "}\n" <> pscd[code, n + m, m] <>
indent[n] <> "\\EndFunction\n";
(*SetDelayed as a function*)
pscd[pattern_, n_: 0, m_: 0] /; Head@Unevaluated@pattern === Pattern :=
pscd /@ pattern // First;
(*remove patterns from arguments of functions*)
pscd[(Module | With | Block)[{vars___}, code_], n_: 0, m_: 0] :=
Cases[Hold@vars, s_ /; Head@Unevaluated@s === Set :> pscd[s, n, m]] <>
pscd[code, n, m];
(*remove everything from Module,With,and Block except code and setting of variables*)
pscd[set_, n_: 0, m_: 0] /; Head@Unevaluated@set === Set :=
indent[n] <> "\\State " <>
Riffle[pscd@# &@ReleaseHold[Hold @@@ Hold@set], " $\\gets$ "] <> "\n";
(*Set*)
pscd[CompoundExpression[code___], n_: 0, m_: 0] :=
Riffle[pscd[Hold@code, n, m], "\n"] <> "\n"
(*...;...;*)
pscd[If[cond_, true_], n_: 0, m_: 0] :=
indent[n] <> "\\If{" <> pscd@cond <> "}\n" <> pscd[true, n + m, m] <>
indent[n] <> "\\EndIf\n";
(*if*)
pscd[If[cond_, true_, false_], n_: 0, m_: 0] :=
indent[n] <> "\\If{" <> pscd@cond <> "}\n" <> pscd[true, n + m, m] <>
indent[n] <> "\\Else\n" <> pscd[false, n + m, m] <> indent[n] <>
"\\EndIf\n";
(*if... else*)
pscd[While[cond_, code_], n_: 0, m_: 0] :=
indent[n] <> "\\While{" <> pscd@cond <> "}\n" <>
pscd[code, n + m, m] <> indent[n] <> "\\EndWhile\n";
(*while*)
pscd[Do[code_, args__, arg1_], n_: 0, m_: 0] :=
pscd[Do[Do[code, arg1], args], n, m];
(*nested do*)
pscd[Do[code_, {i2_}], n_: 0, m_: 0] :=
indent[n] <> "\\Do{" <> pscd@i2 <> "}\n" <> pscd[code, n + m, m] <>
indent[n] <> "\\EndDo\n";
pscd[Do[code_, {i_, i2_}], n_: 0, m_: 0] :=
pscd[Do[code, {i, 1, i2}], n, m];
pscd[Do[code_, {i_, i1_, i2_}], n_: 0, m_: 0] :=
indent[n] <> "\\For{" <> pscd@i <> " = " <> pscd@i1 <> " \\ldots " <>
pscd@i2 <> "}\n" <> pscd[code, n + m, m] <> indent[n] <>
"\\EndFor\n";
pscd[Do[code_, {i_, i1_, i2_, di_}], n_: 0, m_: 0] :=
indent[n] <> "\\For{" <> pscd@i <> " = " <> pscd@i1 <> ", " <>
texstring[i1 + di] <> " \\ldots " <> pscd@i2 <> "}\n" <>
pscd[code, n + m, m] <> indent[n] <> "\\EndFor\n";
pscd[Do[code_, {i_, l_List}], n_: 0, m_: 0] :=
indent[n] <> "\\For{" <> pscd@i <> " = " <>
Riffle[pscd /@ l, ", "] <> "}\n" <> pscd[code, n + m, m] <>
indent[n] <> "\\EndFor\n";
(*do*)
pscd[q_[x_], n_: 0, m_: 0] /; (Last@# == "Q" && LowerCaseQ@#[[-2]] &)@
Characters@ToString@Unevaluated@q :=
pscd@x <> " is " <> Riffle[StringCases[ToString@q,
A_?UpperCaseQ ~~ b__?LowerCaseQ :> ToLowerCase@A <> b], " "]
(* convert EvenQ[x] to "x is even" and so on *)
pscd[Not@q_[x_], n_: 0, m_: 0] /; (Last@# == "Q" && LowerCaseQ@#[[-2]] &)@
Characters@ToString@Unevaluated@q :=
pscd@x <> " is not " <> Riffle[StringCases[ToString@q,
A_?UpperCaseQ ~~ b__?LowerCaseQ :> ToLowerCase@A <> b], " "]
(* convert Not@EvenQ[x] to "x is not even" and so on *)
pscd[Return[x_], n_: 0, m_: 0] :=
indent[n] <> "\\State \\textbf{return} " <> pscd@x <> "\n";
(*return*)
pscd[h_Hold, n_: 0, m_: 0] :=
List @@ Function[{x}, pscd[x, n, m], HoldAll] /@ h
(*Automatically transform Hold[x,y,...] to {pscd[x],pscd[y],...}*)
pscd[code_, n_: 0, m_: 0] := texstring@HoldForm@code;
(*default*)
texstring[code_] := "$" <> code~ToString~TeXForm <> "$";
(*sometimes we need to convert without holding *)
Options[pseudocode] = {Indentation -> 2};
pseudocode[code_, OptionsPattern[]] :=
CellPrint@TextCell[StringReplace[
"\\begin{algorithmic}\n" <>
pscd[code, OptionValue@Indentation, OptionValue@Indentation] <>
"\\end{algorithmic}", "\n" .. :> "\n"], "Output"];
For indentation I use n
and m
variables. n
is the current indentation and m
is the step of the indentation.
Examples
Example 1
pseudocode[
max[a_, b_] := Module[{r},
If[a > b, r = a, r = b];
Return[r]]
]
Output:
\begin{algorithmic}
\Function{$\max$}{$a$,$b$}
\If{$a>b$}
\State $r$ $\gets$ $a$
\Else
\State $r$ $\gets$ $b$
\EndIf
\State \textbf{return} $r$
\EndFunction
\end{algorithmic}

Example 2
pseudocode[
gcd[a_, b_] := Module[{r = Mod[a, b], x = a, y = b},
While[r != 0,
x = y;
y = r;
r = Mod[x, y]
];
Return[y]
]
]
Output:
\begin{algorithmic}
\Function{$\gcd$}{$a$,$b$}
\State $r$ $\gets$ $(a \bmod b)$
\State $x$ $\gets$ $a$
\State $y$ $\gets$ $b$
\While{$r\neq 0$}
\State $x$ $\gets$ $y$
\State $y$ $\gets$ $r$
\State $r$ $\gets$ $(x \bmod y)$
\EndWhile
\State \textbf{return} $y$
\EndFunction
\end{algorithmic}

Example 3
Do[i = i + n + m + k + l, {n, 10}, {m, 5, 20}, {k, m, 30, 2},
{l, {1, 3, 5, 8}}, {40}] // pseudocode
Output:
\begin{algorithmic}
\For{$n$ = $1$ \ldots $10$}
\For{$m$ = $5$ \ldots $20$}
\For{$k$ = $m$, $m+2$ \ldots $30$}
\For{$l$ = $1$, $3$, $5$, $8$}
\Do{$40$}
\State $i$ $\gets$ $i+n+m+k+l$
\EndDo
\EndFor
\EndFor
\EndFor
\EndFor
\end{algorithmic}

Example 4
If[! HermitianMatrixQ[H], H = H + ConjugateTranspose[H]] // pseudocode
Output:
\begin{algorithmic}
\If{$H$ is not hermitian matrix}
\State $H$ $\gets$ $H+H^{\dagger}$
\EndIf
\end{algorithmic}

$\LaTeX$ example file:
\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{algpseudocode}
\algrenewcommand\textproc{}% Disable uppercase in functions
%necessary for "do ... times" constructions
\algblockdefx[DO]{Do}{EndDo}[1]{\textbf{do} #1 \textbf{times}}{\textbf{end do}}
\begin{document}
\begin{algorithmic}
...
\end{algorithmic}
\end{document}
Let me know if you find a bug!
SpokenString
orCompilePrint
could come in handy. $\endgroup$