66
$\begingroup$

I'm writing a paper and all my code is in Mathematica. The snippets are mostly simple, and consist of loops, maps, variables, and conditionals. I'd like add it to my paper, however, not many academic journals accept verbatim code in a specific language, and I'm short on time, so here is my question:

Does anyone know of a package that translates Mathematica functions and code to pseudo-code?

Of course there is no universal syntax pseudo-code, but I'll accept anything that is adequately general (bonus points for robust exportability to $\LaTeX$). Here are some examples of this utility in other languages:

When writing papers I always do the translation by hand, but enough is enough, Mathematica should excel at a high-level translation problem like this and at least get the bulk of the work done for me! I use the pseudocode environment from the fancybox package to typeset pseudocode into $\LaTeX$.

Please note that I fully intend on trying to write an answer to this myself, so don't down vote for the lack of code just yet! :)

$\endgroup$
6
  • 4
    $\begingroup$ +1, but I always wanted a package able to do it the other way around and can interpret my "Now get all those solutions" pseudocode comments $\endgroup$ Oct 29, 2013 at 6:09
  • $\begingroup$ Me too! Alas that direction is much much harder :/ I have a friend who believes that smart and visual programming languages in the next 10 years will have this ability. $\endgroup$
    – M.R.
    Oct 29, 2013 at 6:21
  • $\begingroup$ Perhaps SpokenString or CompilePrint could come in handy. $\endgroup$ Oct 29, 2013 at 11:52
  • 3
    $\begingroup$ But now with all those upvotes you sure gotta deliver ;-) $\endgroup$
    – Yves Klett
    Oct 29, 2013 at 13:35
  • 7
    $\begingroup$ IMO this is problematic due to the ill-defined nature of "pseudocode", dependent as it is on the expectations of the audience. I actually dislike pseudocode descriptions in papers since normally they are written in an inappropriately procedural style and often contain various bugs due to the fact that they can't actually be executed to check for correctness. I would suggest translating to some widely used, free and open language such as Python and providing the code in the supplementary materials. Another good alternative to pseudocode is a flowchart. $\endgroup$ Oct 29, 2013 at 19:14

1 Answer 1

63
$\begingroup$

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}

enter image description here

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}

enter image description here

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}

enter image description here

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}

enter image description here

$\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!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.