Generates algorithmic environment
I have worked recently to investigate if we could generate the LaTeX algorithm environment from the function. Actually it can work like this:
I think this feature is really useful for almost arbitrary functions.
There are several caveats.
Specifically, IPython supports only MathJax, meaning that it accepts only a single expression. To output more complicated LaTeX document, we need to complie the source directly, and convert the generated file to an image that IPython accepts.
In the work above, I used pdflatex and pdf2image. They requires to install external libraries, e.g., texlive with the algorithmicx package (for pdflatex) and Poppler (for pdf2image).
An option to implement it for IPython is to use immediate newline in the single expression with appropriate manual spacing, but it requires some hacks. I think it would be better to apply external commands to generate the compiled image.
Can this, if implemented, be added to the ipynb example?
@luisArandas Yes, the poc works on Jupyter and/or Colab and we can add examples.
I guess composing everything into array would be another option to show the result on Jupyter. Maybe we can introduce multiple codegen (one for algorithmic, one for jupyter).
I'd agree with multiple code gen, targeting either Jupyter or algorithmic. I'd be interested in taking a look into algorithmic at some point.
I have some ideas about this.
- First, we can provide the
ExpressionCodegen, which convertsast.exprto LaTeX. I thinkast.expris the minimal fragment of AST that we can share the same behavior among different output styles. - Then, we provide several codegens, such as
FunctionCodegen,AlgorithmCodegen,IPythonAlgorithmCodegen, or something else, to process the whole syntax. They invokesExpressionCodegeninternally to obtain the underlying expressions, and organize all results along with the style that the codegen finally produces.
This design has also an advantage about programmatic use of this library. We can define a function latexify.compile_expression("...expr..."), which directly invokes ExpressionCodegen and returns the LaTeX. (also discussed in #108)
I would think that ExpressionCodegen(ast.NodeVisitor) would be the parent class to FunctionCodegen, AlgorithmCodegen, etc., since I think the visiting of nodes for expressions should be shared among them?
Would you happen to have the LaTeX code for the example MAX_IN_ARRAY function in the image above? Not super familiar with using Latex in this way, and it would be nice for an example to get a sense of what the end result would be here.
ExpressionCodegen(ast.NodeVisitor) would be the parent class to FunctionCodegen, AlgorithmCodegen, etc
We don't need inheritance (and shouldn't adopt inheritance here IMO) because there's basically no advantage over composition in this case. We could define ExpressionCodegen as just a kind of function.
For the first example, I tried to synthesize the following LaTeX environment: https://www.overleaf.com/learn/latex/Algorithms (note that there are many options/variants of this environment)
Maybe an required keyword argument to specify the argument to target?
I guess you meant some argument to specify the output style. Yes we need to have one for it (and maybe it'd be better to integrate the current function and expression behaviors into "style")
Maybe adding a sytle=StyleEnum field in the config, and instead of latexify.expression being a wrapper around latexify.function with use_signature=False. Instead it would be a wrapper with config.style = Style.EXPRESSION?
That way we could have things like
@latexify.function(style=Style.EXPRESSION)
def fact(n):
return 1 if n == 0 else n * fact(n - 1)
and we could have
Style(str, enum.Enum):
EXPRESSION = "expression"
FUNCTION = "function"
ALGPSEUDOCODE = "algpseudocode"
Yes. And we should have functions for every choice of style. As this is an essential config, users shouldn't write the style parameter every time.
An option to implement it for IPython is to use immediate newline in the single expression with appropriate manual spacing, but it requires some hacks. I think it would be better to apply external commands to generate the compiled image.
I think it might be nice to try to do this using said hacks so that we don't add unnecessary dependancies.
I don't think it would actually be that difficult. Do you mind if I try to accomplish this, or did you prefer to go the image approach?
I don't like the image approach actually, so going with two codegens is fine.
~~~~
Better to use \hspace{width} rather than whitespace characters, because indentation does not mean anything about the expression itself. (it also allows us to control the amount of the depth afterwards)
\mathrm{\textbf{foo}}
Better to use \mathbf{foo}.
See also my previous example.