Search code examples
lisplambdasymbolic-math

My idea of symbolic evaluator performing derivation on dynamic set of variables


This will slightly link to my two previous questions link 1, link 2. I'm working on some symbolic evaluator which will be part of my project for simulation of electrical circuits. As someone had mentioned before I have turned my attention to lambda function and automatic function generation.

Task is easy. Let's define hash-table with some keys and values.

(defparameter *my-hash* (make-hash-table :test #'equal))

(defun get-symbol-var (x)
  (gethash x *my-hash*))

(defun symbol-var (x)
  (gethash (rest x) *my-hash*))

And here is main derivation function. Derivation is performed by lambda function generation process with some recursion. It is just a sample so it can perform derivation of variables, numbers and product of two inputs.

 (defun diff (exp var)
   #'(lambda (x) (cond 
       ((numberp exp) 0)       
       ((variablep exp)
         (if (same-variablep exp var) 1 0))
       ((productp exp)
          (+ (* (funcall (diff (second exp) var) x) ( eval-exp (third exp)))  
          (* (funcall (diff (third exp ) var) x) ( eval-exp (second exp)))))))) 

(defun diff-eval (equation var)
  (funcall (diff equation var) (symbol-var var)))

Some useful condition definitions

 (defun productp (x)
   (eql (car x) '*))

 (defun variablep (x) 
   (eql (car x) 'symbol-var))

 (defun same-variablep (v1 v2)
   (and (variablep v1) (variablep v2) (equal v1 v2)))

Because some variables can get out of derivation loop I defined special function for evaluation.

 (defun eval-exp (exp) 
   (cond
     ((numberp exp) exp)       
     ((variablep exp) (get-symbol-var (rest exp)))
     ((sump exp) (+ (eval-var-symbol (third exp))
                    (eval-var-symbol (second exp))))
     ((productp exp) (* (eval-var-symbol (third exp))
                        (eval-var-symbol (second exp)))))) 

Introducing some variables to database

(setf (gethash '(v 1) *my-hash* ) 1)
(setf (gethash '(v 2) *my-hash* ) 23)
(setf (gethash '(v 3) *my-hash* ) 1)

Testing equation d(v1*v2)/dv1

(setf *equation* '(* (symbol-var v 2) (symbol-var v 1)))
(diff-eval *equation* '(symbol-var v 1))

Am I doing it in a right way? Could this be done more LISP clearly.


Solution

  • I suggest making the diff function do more processing of exp. Instead of one big lambda function, return a closure for each conditional branch, with much of the processing including the recursive calls to diff done outside the lambda functions.

    Doing more of the processing in diff may improve run-time performance as you move forward, particularly if the result of calling diff is reused. It can also benefit debugging, as many errors including those in exp will be caught when calling diff rather than later when invoking diff-eval.