maxima in lisp
i ended up giving up on using maxima as a visualization/symbolic math computation library for lisp, it wasnt made with this usecase in mind i guess, and so its an utter nightmare to lisp with it
maxima is written in lisp and so it can be used as a modified/extended lisp runtime
how to
to start the lisp runtime use the command:rmaxima -r 'to_lisp();'(sly "rmaxima -r to_lisp();")
alternatively, we can clone maxima's source code to the subdirectory
local-projects of the quicklisp installation directory (usually quicklisp~ unless you've modified it), follow the instructions at https:sourceforge.netp/maxima/code/ci/master/tree/INSTALL.lispBROKEN to compile maxima and you'll be able to load it as a library:
(ql:quickload "maxima")maxima::, e.g.
(maxima::displa (maxima::$integrate #$2/(3*x^5)$ 'x))
2 x
----
5
3 x
----
5
3 x
unless you enter the library itself then you dont need the prefix:
(in-package :maxima)draw when maxima is loaded as a library, thats why using rmaxima is better
misc
to write an expression in infix syntax we do:(print #$10/13$)
((MAXIMA::RAT MAXIMA::SIMP) 10 13)
to display math using ascii art we use the function
displa (short for display)
(maxima::displa #$10/13$)
10
--
13
--
13
maxima expression to lisp expression
this function helps turn maxima expressions into their corresponding lisp expression(defun lisp-form (macsyma-string)
(maxima::macsyma-read-string (concatenate 'string macsyma-string "$")))example:
(print (lisp-form "diff(sin(x),x)"))
((MAXIMA::$DIFF) ((MAXIMA::%SIN) MAXIMA::$X) MAXIMA::$X)
some expressions will return symbols instead of functions so they cannot be run directly, e.g.
(print (lisp-form "sin(10d0)"))
((MAXIMA::%SIN) 10.0)
so to evaluate these expressions we can use
meval*:
(print (lisp-form "sin(10d0)"))
(print (maxima::meval* (lisp-form "sin(10d0)")))
(print (maxima::meval* '((maxima::%sin) 10.0)))
((MAXIMA::%SIN) 10.0)
-0.5440211108893698
-0.5440211108893698
although functions like
$sin do exist and can be used instead of symbols like %sin
taken from https://github.com/livelisp/livewlisp/blob/main/maxima-tutorial.txt
integration
the main function for integration is$integrate (or sinint)
(maxima::displa (maxima::$integrate #$2/(3*x^2)$ 'x))
2 x
----
2
3 x
----
2
3 x
(maxima::displa (maxima::$integrate '((maxima::%cos) x) 'x))
sin(x)
lists
i havent a better approach yet(maxima::displa (maxima::meval* `((maxima::mlist) 2 3 5)))
[2, 3, 5]
lisp list to maxima list:
(defun list->mlist (list)
(let ((mlist (maxima::meval* `((maxima::mlist)))))
(loop for expr in (reverse list)
do (setf
mlist
(maxima::meval* `((maxima::$append) ((maxima::mlist) ,expr) ,mlist))))
mlist))(print (list->mlist '(1 2 3)))
(maxima::displa (list->mlist '(1 2 3)))
((MAXIMA::MLIST MAXIMA::SIMP) 1 2 3)
[1, 2, 3]
plotting
we need to initialize some variables (like*maxima-tempdir*) to be able to plot, this can be done automatically using initialize-runtime-globals
(maxima::initialize-runtime-globals)gnuplot
(maxima::$plot2d
'((maxima::mlist)
maxima::$discrete
((maxima::mlist) 1 2 3) ((maxima::mlist) 1 2 3)))list->mlist (see above)
(maxima::$plot2d
`((maxima::mlist)
((maxima::mlist) maxima::$discrete
,(list->mlist '(1 2 3)) ,(list->mlist '(1 2 3)))
((maxima::mlist) maxima::$discrete
,(list->mlist '(1 2 3)) ,(list->mlist '(1 5 3)))))maxima, see the how to section):
(let ((scene1 '((MAXIMA::$GR2D)
((MAXIMA::MEQUAL) MAXIMA::$TITLE "first plot")
((MAXIMA::MEQUAL) MAXIMA::$NTICKS 300)
((MAXIMA::$PARAMETRIC)
((MAXIMA::MTIMES) 2 ((MAXIMA::%COS) MAXIMA::$T))
((MAXIMA::MTIMES) 5 ((MAXIMA::%SIN) MAXIMA::$T)) MAXIMA::$T 0
((MAXIMA::MTIMES) 2 MAXIMA::$%PI))))
(scene2 `((MAXIMA::$GR2D)
((MAXIMA::MEQUAL) MAXIMA::$TITLE "second plot")
((MAXIMA::MEQUAL) MAXIMA::$NTICKS 300)
((maxima::$points) ((mlist) 1 2 3) ((mlist) 1 2 3)))))
(maxima::meval* `((MAXIMA::$DRAW) ,scene1 ,scene2 ((MAXIMA::MEQUAL) MAXIMA::$COLUMNS 2))))(defun plot-points (x-values y-values)
(maxima::$plot2d
`((maxima::mlist)
maxima::$discrete
,(list->mlist x-values) ,(list->mlist y-values))))