emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [TIP] Exporting Maxima results to LaTeX
@ 2023-02-07 21:40 Leo Butler
  2023-02-07 22:13 ` Thomas S. Dye
  2023-02-08 15:43 ` Max Nikulin
  0 siblings, 2 replies; 7+ messages in thread
From: Leo Butler @ 2023-02-07 21:40 UTC (permalink / raw)
  To: Org Mode Mailing List

[-- Attachment #1: Type: text/plain, Size: 118 bytes --]

Attached is a self-documented setup to do what the subject line says.
Comments/suggestions welcome.

Best,
Leo


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tip.org --]
[-- Type: text/x-org; name="maxima-tip.org", Size: 3910 bytes --]

#+TITLE: Tip for exporting Maxima results to LaTeX
#+AUTHOR: Leo Butler
#+OPTIONS: H:2 toc:nil num:nil tags:nil todo:nil
#+LATEX_CLASS: article
#+LATEX_HEADER: \usepackage{color}
#+LATEX_COMPILER: lualatex
#+STARTUP: beamer
#+PROPERTY: header-args:maxima :eval never-export :exports results :results raw drawer

* Goal
Generate @@latex:\LaTeX{}@@ code from Maxima code.

* Setup
** maxima-init.lisp
The command =org-babel-execute:maxima= in =lisp/ob-maxima.el= uses the Maxima command ~batchload~ to execute Maxima code. This is a very tight-lipped loader, so we over-write ~batchload~ with ~batch~. We also ~load~ an init file:

#+begin_example
,#+begin_src maxima :tangle maxima-init.lisp :exports none
  (defun $batchload (file) (mfuncall '$batch file))
  ($load "./maxima-init.mac")
,#+end_src
#+end_example

On tangling, this produces the ~common-lisp~ output file ~maxima-init.lisp~. It will be pre-loaded into Maxima.

#+begin_src maxima :tangle maxima-init.lisp :exports none
  (defun $batchload (file) (mfuncall '$batch file))
  ($load "./maxima-init.mac")
#+end_src

** maxima-init.mac
Next, we need to create an init file for Maxima that will provide an output printer that produces @@latex:\LaTeX{}@@ output. One option would be to use the ~imaxima~ printer. Here is another option that uses the ~alt-display~ package.
The code replaces the default printer with ~org_tex_display~. It also sets the ~epilog~ prompt, so that the final ~#+begin_example~ is terminated.

#+begin_example
,#+begin_src maxima :tangle maxima-init.mac :exports none
  load("alt-display.mac") $
  set_prompt('epilog,printf(false,"~%#+end_example")) $
  define_alt_display(org_tex_display(x),
    block([], printf(true,"#+end_example~%#+begin_export latex~%"),
      printf(true,"\\textcolor{blue}{(\\~a~d)} ",outchar,linenum-1), tex(second(x)), printf(true,"~&#+end_export~%#+begin_example~%(input) "))) $
  set_alt_display(2,org_tex_display) $
  display2d:true $
  printf(true,"#+begin_example~%(input) ") $
  linenum : 0 $
,#+end_src
#+end_example

#+begin_src maxima :tangle maxima-init.mac :exports none
  load("alt-display.mac") $
  set_prompt('epilog,printf(false,"~%#+end_example")) $
  define_alt_display(org_tex_display(x),
    block([], printf(true,"#+end_example~%#+begin_export latex~%"),
      printf(true,"\\textcolor{blue}{(\\~a~d)} ",outchar,linenum-1), tex(second(x)), printf(true,"~&#+end_export~%#+begin_example~%(input) "))) $
  set_alt_display(2,org_tex_display) $
  display2d:true $
  printf(true,"#+begin_example~%(input) ") $
  linenum : 0 $
#+end_src

* An example
Here is an example that computes the derivative of a composite function.

#+name: chain-rule
#+begin_src maxima :exports results :results raw drawer :cmdline -p ./maxima-init.lisp
  (gradef(f(u,v),f_1(u,v),f_2(u,v)), 'done);
  diff(f(x^2-y^2,x*y),x);
  diff(f(x^2-y^2,x*y),y);
#+end_src

#+RESULTS: chain-rule
:results:
#+begin_example
(input) 
read and interpret /tmp/babel-hhTrJS/maxima-0m0DnH.max
(gradef(f(u,v),f_1(u,v),f_2(u,v)),'done)
#+end_example
#+begin_export latex
\textcolor{blue}{(\%o1)} $$\mathbf{done}$$
#+end_export
#+begin_example
(input) 
diff(f(x^2-y^2,x*y),x)
#+end_example
#+begin_export latex
\textcolor{blue}{(\%o2)} $$y\,f_{2}\left(x^2-y^2 , x\,y\right)+2\,x\,f_{1}\left(x^2-y^2 , x\,y
 \right)$$
#+end_export
#+begin_example
(input) 
diff(f(x^2-y^2,x*y),y)
#+end_example
#+begin_export latex
\textcolor{blue}{(\%o3)} $$x\,f_{2}\left(x^2-y^2 , x\,y\right)-2\,y\,f_{1}\left(x^2-y^2 , x\,y
 \right)$$
#+end_export
#+begin_example
(input) 
gnuplot_close()
#+end_example
:end:

** Two annoyances
The initial line =read and interpret...= and that final, dangling
input line with ~gnuplot_close()~ are nuisances. They can be easily
suppressed, but that requires patching ~ob-maxima.el~. That's another
story.

[-- Attachment #3: maxima-tip.pdf --]
[-- Type: application/pdf, Size: 34392 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-07 21:40 [TIP] Exporting Maxima results to LaTeX Leo Butler
@ 2023-02-07 22:13 ` Thomas S. Dye
  2023-02-08 15:43 ` Max Nikulin
  1 sibling, 0 replies; 7+ messages in thread
From: Thomas S. Dye @ 2023-02-07 22:13 UTC (permalink / raw)
  To: Leo Butler; +Cc: emacs-orgmode

Aloha Leo,

Leo Butler <Leo.Butler@umanitoba.ca> writes:

> Attached is a self-documented setup to do what the subject line 
> says.
> Comments/suggestions welcome.
>
> Best,
> Leo
>

Please consider adding this to 
https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-maxima.org, 
which also has some notes on how to export Maxima to LaTeX.

All the best,
Tom

-- 
Thomas S. Dye
https://tsdye.online/tsdye


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-07 21:40 [TIP] Exporting Maxima results to LaTeX Leo Butler
  2023-02-07 22:13 ` Thomas S. Dye
@ 2023-02-08 15:43 ` Max Nikulin
  2023-02-08 16:11   ` Fraga, Eric
  2023-02-08 20:40   ` Leo Butler
  1 sibling, 2 replies; 7+ messages in thread
From: Max Nikulin @ 2023-02-08 15:43 UTC (permalink / raw)
  To: emacs-orgmode



On 08/02/2023 04:40, Leo Butler wrote:
> Generate @@latex:\LaTeX{}@@ code from Maxima code.

You can write just LaTeX, ox-latex recognizes such pattern. The bonus is 
the it will be literally exported to HTML.

> #+begin_example
> ,#+begin_src maxima :tangle maxima-init.lisp :exports none
>    (defun $batchload (file) (mfuncall '$batch file))
>    ($load "./maxima-init.mac")
> ,#+end_src
> #+end_example
> 
> On tangling, this produces the ~common-lisp~ output file ~maxima-init.lisp~. It will be pre-loaded into Maxima.
> 
> #+begin_src maxima :tangle maxima-init.lisp :exports none
>    (defun $batchload (file) (mfuncall '$batch file))
>    ($load "./maxima-init.mac")
> #+end_src

I am curious if it is possible to avoid duplication by e.g. using noweb.

> #+begin_src maxima :tangle maxima-init.mac :exports none

At first glance :prologue header argument might be an alternative, but 
likely I have missed something obvious.




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-08 15:43 ` Max Nikulin
@ 2023-02-08 16:11   ` Fraga, Eric
  2023-02-08 20:40   ` Leo Butler
  1 sibling, 0 replies; 7+ messages in thread
From: Fraga, Eric @ 2023-02-08 16:11 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode@gnu.org

On Wednesday,  8 Feb 2023 at 22:43, Max Nikulin wrote:
> At first glance :prologue header argument might be an alternative, but
> likely I have missed something obvious.

Indeed.  I use, for instance, the following

#+PROPERTY: header-args:maxima :prologue "fpprintprec: 2; linel: 50;"

for my teaching slides to ensure that Maxima output fits on my slides
(and only print relevant digits in the answers).

There's also an epilogue which I use to automatically format the
solution of my Maxima codes (all my examples have a particular form):

#+PROPERTY: header-args:maxima :epilogue "for j: 1 thru length(solution) do (print(\"\"), print(\"Solution\", j), print(\"\"), for i: 1 thru length(solution[j]) do grind(solution[j][i]))$"

All my Maxima blocks define a "solution" variable.

-- 
: Eric S Fraga, with org release_9.6-201-gb58fba in Emacs 30.0.50

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-08 15:43 ` Max Nikulin
  2023-02-08 16:11   ` Fraga, Eric
@ 2023-02-08 20:40   ` Leo Butler
  2023-02-11 11:39     ` Max Nikulin
  1 sibling, 1 reply; 7+ messages in thread
From: Leo Butler @ 2023-02-08 20:40 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode@gnu.org

On Wed, Feb 08 2023, Max Nikulin <manikulin@gmail.com> wrote:

> On 08/02/2023 04:40, Leo Butler wrote:
>> Generate @@latex:\LaTeX{}@@ code from Maxima code.
>
> You can write just LaTeX, ox-latex recognizes such pattern. The bonus
> is the it will be literally exported to HTML.

Thanks.

>
>> #+begin_example
>> ,#+begin_src maxima :tangle maxima-init.lisp :exports none
>>    (defun $batchload (file) (mfuncall '$batch file))
>>    ($load "./maxima-init.mac")
>> ,#+end_src
>> #+end_example
>> On tangling, this produces the ~common-lisp~ output file
>> ~maxima-init.lisp~. It will be pre-loaded into Maxima.
>> #+begin_src maxima :tangle maxima-init.lisp :exports none
>>    (defun $batchload (file) (mfuncall '$batch file))
>>    ($load "./maxima-init.mac")
>> #+end_src
>
> I am curious if it is possible to avoid duplication by e.g. using noweb.

I am not sure what you think is being duplicated. Do you mean the
duplication of the example and src blocks? I am not aware of how to
remove that duplication--all the examples I have found in the worg
source do what I have done above.

>
>> #+begin_src maxima :tangle maxima-init.mac :exports none
>
> At first glance :prologue header argument might be an alternative, but
> likely I have missed something obvious.

The prologue header is put into a temporary source file, along with the
body and epilogue and it is read by Maxima's `batchload' command. So
using a prologue is too late, because I need to overwrite `batchload' by
its more verbose companion `batch'. That is why `maxima-init.lisp' is
pre-loaded.

Leo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-08 20:40   ` Leo Butler
@ 2023-02-11 11:39     ` Max Nikulin
  2023-02-14 15:13       ` Leo Butler
  0 siblings, 1 reply; 7+ messages in thread
From: Max Nikulin @ 2023-02-11 11:39 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: Leo Butler

On 09/02/2023 03:40, Leo Butler wrote:
> On Wed, Feb 08 2023, Max Nikulin wrote:
>> I am curious if it is possible to avoid duplication by e.g. using noweb.
> 
> ... I am not aware of how to
> remove that duplication--all the examples I have found in the worg
> source do what I have done above.

I have tried

---- >8 ----
#+begin_src elisp :exports results :results silent
   (require 'ob-org)
#+end_src

#+begin_src org :exports both :results drawer replace
   ,#+begin_src elisp :exports results
     '((1 2 3) (4 5 6))
   ,#+end_src
#+end_src
---- 8< ----

It is exported to LaTeX as

---- >8 ----
\begin{verbatim}
#+begin_src elisp :exports results
   '((1 2 3) (4 5 6))
#+end_src
\end{verbatim}

\begin{center}
\begin{tabular}{rrr}
1 & 2 & 3\\[0pt]
4 & 5 & 6\\[0pt]
\end{tabular}
\end{center}
---- 8< ----

For debugging of the inner src block it is necessary to swap escaping 
with the outer #+begin_src. I have not figured out how to add some text 
in between of the exported source code example and its result.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TIP] Exporting Maxima results to LaTeX
  2023-02-11 11:39     ` Max Nikulin
@ 2023-02-14 15:13       ` Leo Butler
  0 siblings, 0 replies; 7+ messages in thread
From: Leo Butler @ 2023-02-14 15:13 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1020 bytes --]

On Sat, Feb 11 2023, Max Nikulin <manikulin@gmail.com> wrote:

> On 09/02/2023 03:40, Leo Butler wrote:
>> On Wed, Feb 08 2023, Max Nikulin wrote:
>>> I am curious if it is possible to avoid duplication by e.g. using noweb.
>> 
>> ... I am not aware of how to
>> remove that duplication--all the examples I have found in the worg
>> source do what I have done above.
>
> I have tried

<snip>

Recursive evaluation of code blocks! Of course! THANK YOU!

>
> For debugging of the inner src block it is necessary to swap escaping 
> with the outer #+begin_src.

Yes, it should be possible to recursive edit in indirect buffers. I
don't see how to do that.

> I have not figured out how to add some text in between of the exported
> source code example and its result.

See the attached. You need to name a code block and manually insert the
#+RESULT: stanza where you want the result put.

Thanks to Max and Eric for their comments. I have incorporated the
comments in the attached.

Leo


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: maxima-tip.org --]
[-- Type: text/x-org; name="maxima-tip.org", Size: 7145 bytes --]

#+TITLE: Tip for exporting Maxima results to LaTeX
#+AUTHOR: Leo Butler
#+OPTIONS: H:3 toc:t num:t tags:nil todo:nil
#+LATEX_CLASS: article
#+LATEX_HEADER: \usepackage{color} \usepackage[margin=2cm]{geometry}
#+LATEX_COMPILER: lualatex
#+PROPERTY: header-args:maxima :eval export :exports results :results raw drawer

* Goal
Generate LaTeX code from Maxima code.

* Setup
** maxima-init.lisp
The command =org-babel-execute:maxima= in =lisp/ob-maxima.el= uses the Maxima command ~batchload~ to execute Maxima code. This is a very tight-lipped loader, so we over-write ~batchload~ with ~batch~. We also ~load~ an init file:

#+name: maxima-init.lisp.org
#+begin_src org :exports code :results replace
,#+name: maxima-init.lisp
,#+begin_src maxima :tangle maxima-init.lisp :exports none
  (defun $batchload (file) (mfuncall '$batch file))
  ($load "./maxima-init.mac")
,#+end_src
#+end_src

On tangling, this produces the ~common-lisp~ output file ~maxima-init.lisp~. It will be pre-loaded into Maxima.

#+RESULTS: maxima-init.lisp.org
#+name: maxima-init.lisp
#+begin_src maxima :tangle maxima-init.lisp :exports none
  (defun $batchload (file) (mfuncall '$batch file))
  ($load "./maxima-init.mac")
#+end_src

** maxima-init.mac
Next, we need to create an init file for Maxima that will provide an output printer that produces @@latex:\LaTeX{}@@ output. One option would be to use the ~imaxima~ printer. Here is another option that uses the ~alt-display~ package.
The code replaces the default printer with ~org_tex_display~. It also sets the ~epilog~ prompt, so that the final ~#+begin_example~ is terminated.

#+name: maxima-init.mac.org
#+begin_src org :exports code :results replace
  ,#+name: maxima-init.mac
  ,#+begin_src maxima :tangle maxima-init.mac :exports none :eval none
  load("alt-display.mac") $
  set_prompt('epilog,printf(false,"~%#+end_example")) $
  define_alt_display(org_tex_display(x),
    block([], 
      printf(true,"#+end_example~%#+begin_export latex~%"),
      printf(true,"\\textcolor{blue}{(\\~a~d)} ",outchar,linenum-1),
      tex(second(x)),
      printf(true,"~&#+end_export~%#+begin_example~%(input) "))) $
  set_alt_display(2,org_tex_display) $
  display2d:true $
  printf(true,"#+begin_example~%(input) ") $
  linenum : 0 $
  ,#+end_src
#+end_src

#+RESULTS: maxima-init.mac.org
#+name: maxima-init.mac
#+begin_src maxima :tangle maxima-init.mac :exports none :eval none
load("alt-display.mac") $
set_prompt('epilog,printf(false,"~%#+end_example")) $
define_alt_display(org_tex_display(x),
  block([], 
    printf(true,"#+end_example~%#+begin_export latex~%"),
    printf(true,"\\textcolor{blue}{(\\~a~d)} ",outchar,linenum-1),
    tex(second(x)),
    printf(true,"~&#+end_export~%#+begin_example~%(input) "))) $
set_alt_display(2,org_tex_display) $
display2d:true $
printf(true,"#+begin_example~%(input) ") $
linenum : 0 $
#+end_src

* An example
Here is an example that computes the partial derivatives of a composite function.

** Org code

#+name: chain-rule.org
#+begin_src org :exports both :results replace
,#+name: chain-rule
,#+begin_src maxima :exports both :cmdline -p ./maxima-init.lisp
  (gradef(f(u,v),f_1(u,v),f_2(u,v)), 'done);
  diff(f(x^2-y^2,x*y),x);
  diff(f(x^2-y^2,x*y),y);
,#+end_src
#+end_src

** Maxima code

#+RESULTS: chain-rule.org

The first line defines the partial derivatives of \(f(u,v)\) with repect to \(u\) and \(v\). The second and third lines compute the partial derivatives of the composite \(f(x²-y²,xy)\).

** Result of evaluation; LaTeX output
The ~batch~ printer echos each input line; it prints the output of
each command line that ends in a semi-colon (=;=). The result of a
line ending in a dollar sign (=$=) is not printed. The
~org_tex_display~ printer wraps each echoed input line in an ~example~
block and prints the output as it would appear in an =imaxima=
session.

#+RESULTS: chain-rule

** Two annoyances
The initial line =read and interpret...= and that final, dangling
input line with ~gnuplot_close()~ are nuisances. They can be easily
suppressed, but that requires patching ~ob-maxima.el~. That's another
story.

* Epilogue
After sending my initial draft to the =Org= mailing list, I received some feedback.
** Eric Fraga's suggestion
:PROPERTIES:
:header-args:maxima: 
:END:

On the mailing list, Eric Fraga suggested adding the prologue/epilogue:

#+begin_example
#+PROPERTY: header-args:maxima :prologue "fpprintprec: 2; linel: 50;"
#+PROPERTY: header-args:maxima :epilogue "for j: 1 thru length(solution) do (\
            print(\"\"), print(\"Solution\", j), \
            print(\"\"), for i: 1 thru length(solution[j]) do grind(solution[j][i]))$"
#+end_example

\normalsize
Let's redo the example above with those settings and incorporating Eric's design that the results need to be collected in the ~solution~ list:

#+name: fraga-example.org
#+begin_src org :exports both :results replace :noweb yes
  ,#+name: chain-rule-redo
  ,#+header: :prologue "fpprintprec: 2; linel: 50;"
  ,#+header: :epilogue "for j: 1 thru length(solution) do (print(\"\"), print(\"Solution\", j), print(\"\"), for i: 1 thru length(solution[j]) do grind(solution[j][i]));"
  ,#+begin_src maxima :exports results :results table
  (gradef(f(u,v),f_1(u,v),f_2(u,v)), 'done);
  fx:diff(f(x^2-y^2,x*y),x);
  fy:diff(f(x^2-y^2,x*y),y);
  solution:[fx,fy];
  ,#+end_src
#+end_src

#+RESULTS: fraga-example.org

Here is the result:

#+RESULTS: chain-rule-redo

** Max Nikulin's idea

Max Nikulin remarked that the ~org~ code in this file contains redundancy. He suggested trying:

#+name: elisp-in-org-in-org
#+begin_src org :exports both :results replace
,#+begin_src elisp :exports results :results silent
  (require 'ob-org)
,#+end_src

,#+name: elisp-in-org
,#+begin_src org :exports both :results replace
  ,,#+name: elisp-block
  ,,#+begin_src elisp :exports results
    '((1 2 3) (4 5 6))
  ,,#+end_src
,#+end_src
#+end_src

The block named ~elisp-in-org~ is exported to:

#+RESULTS: elisp-in-org-in-org

The ~elisp~ code block exports to a named block of =elisp= code.

#+RESULTS: elisp-in-org

That exports to:

#+RESULTS: elisp-block

*** A bug // Feature request
=Org= does a good job of recursively evaluating code blocks, as can be seen by the examples here (Thanks, Max!). But, two things are not done quite correctly:
1. When editing ~org~ code blocks in an indirect buffer, it should be possible to recursively edit a code block. That does not appear to work at the moment.
2. Noweb expansion does not work correctly in combination with recursive evaluation of code blocks. In the ~org~ block named =fraga-example.org=, a noweb reference =<<chain-rule>>= to the Maxima code block =chain-rule= is not expanded correctly (it leaves a blank line).

* How to reproduce the pdf
1. In this =org= file, do ~C-c C-v t~ to tangle the two code blocks.
2. Then, do ~C-c C-e l p~ to export to pdf. Each time you are prompted about evaluating a code block, answer ~y~ or ~yes~.


[-- Attachment #3: maxima-tip.pdf --]
[-- Type: application/pdf, Size: 53439 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-02-14 15:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-07 21:40 [TIP] Exporting Maxima results to LaTeX Leo Butler
2023-02-07 22:13 ` Thomas S. Dye
2023-02-08 15:43 ` Max Nikulin
2023-02-08 16:11   ` Fraga, Eric
2023-02-08 20:40   ` Leo Butler
2023-02-11 11:39     ` Max Nikulin
2023-02-14 15:13       ` Leo Butler

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).