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();'
can also run this in emacs' slime/sly with (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:
  1. net
pmaximacodecimastertreeINSTALL.lispBROKEN to compile maxima and you'll be able to load it as a library:
  (ql:quickload "maxima")
but then you gotta prefix functions with maxima::, e.g.
  (maxima::displa (maxima::$integrate #$2/(3*x^5)$ 'x))
3 x
5
----
2 x

unless you enter the library itself then you dont need the prefix:
  (in-package :maxima)
loading maxima as a library works most of the time, but it causes some problems, for example we cant use 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$)
13
--
10

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)))
-0.5440211108893698
-0.5440211108893698
((MAXIMA::%SIN) 10.0)

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))
3 x
2
----
2 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))
example:
  (print (list->mlist '(1 2 3)))
(maxima::displa (list->mlist '(1 2 3)))
[1, 2, 3]
((MAXIMA::MLIST MAXIMA::SIMP) 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)
to plot a set of points (discrete plot) using gnuplot
  (maxima::$plot2d
'((maxima::mlist)
maxima::$discrete
((maxima::mlist) 1 2 3) ((maxima::mlist) 1 2 3)))
this can be (somewhat) simplified using our function 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)))))
we can draw multiple plots (this only works when running lisp using 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))))
we implement some abstraction over this to make it less explicit:
  (defun plot-points (x-values y-values)
(maxima::$plot2d
`((maxima::mlist)
maxima::$discrete
,(list->mlist x-values) ,(list->mlist y-values))))