Моя идея о том, чтобы символьный оценщик выполнял деривацию на динамическом множестве переменных - PullRequest
1 голос
/ 13 апреля 2011

Это будет немного ссылаться на мои два предыдущих вопроса ссылка 1 , ссылка 2 . Я работаю над символическим оценщиком, который станет частью моего проекта по моделированию электрических цепей. Как уже упоминалось ранее, я обратил свое внимание на лямбда-функции и автоматическую генерацию функций.

Задача проста. Давайте определим хеш-таблицу с некоторыми ключами и значениями.

(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*))

А вот и основная деривационная функция. Вывод выполняется процессом генерации лямбда-функции с некоторой рекурсией. Это всего лишь образец, поэтому он может выполнять вывод переменных, чисел и произведений двух входных данных.

 (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)))

Некоторые полезные определения условий

 (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)))

Поскольку некоторые переменные могут выйти из производного цикла, я определил специальную функцию для оценки.

 (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)))))) 

Введение некоторых переменных в базу данных

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

Проверка уравнения d (v1 * v2) / dv1

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

Правильно ли я делаю это? Может ли это быть сделано более четко LISP.

Ответы [ 2 ]

1 голос
/ 14 апреля 2011

Я предлагаю сделать так, чтобы функция diff выполняла больше обработки exp . Вместо одной большой лямбда-функции, возвращайте замыкание для каждой условной ветви, причем большая часть обработки, включаярекурсивные вызовы diff, выполняемые вне лямбда-функций.

Выполнение большей части обработки в diff может улучшить производительность во время выполнения по мере продвижения вперед, особенно если результат вызова diff используется повторно,Это также может помочь отладке, так как многие ошибки, включая ошибки в exp , будут обнаружены при вызове diff, а не позже при вызове diff-eval.

0 голосов
/ 02 июля 2011

Вы можете использовать существующее бесплатное программное обеспечение Computer Algebra System Maxima. Его сравнительно легко загрузить в изображение на Лиспе, и вы можете использовать его для гораздо более сложных задач, чем просто производные.

Скачать Maxima можно здесь: git clone git: //maxima.git.sourceforge.net/gitroot/maxima/maxima

Откройте новый файл lisp в Emacs / SLIME и запустите:

(require :asdf)
(setf asdf:*central-registry* (union '("/data/src/maxima/src/")
                     asdf:*central-registry*))
(require :maxima)

(in-package :maxima)
;; Documentation of how to convert between Lisp and Maxima:
;; http://maxima.sourceforge.net/docs/manual/en/maxima_3.html
;; this sets the Maxima variable foo to contain a list x, y:
(msetq $foo #$[x, y]$)

;; The lisp function displa displays a maxima expression:
(displa '((MLIST SIMP) $X $Y $Z))

;; and this stores the derivation of log(z) into foo:
(msetq $foo #$diff (log (z))$)
;; => ((MTIMES SIMP) ((MEXPT SIMP) $Z -1) ((%DEL SIMP) $Z))
...