Символьные математические вычисления в Clojure vs. F # - PullRequest
4 голосов
/ 04 октября 2010

Я наткнулся на следующий пример F # и нашел его интригующим:

http://www.codeproject.com/KB/net-languages/SymbolicCalcInFS.aspx

Есть ли у Clojure средства для работы с языком / библиотекой для выполнения чего-то подобного с легкостью?Можно использовать польскую запись формул, если это облегчает задачу.

Спасибо, и дайте мне знать, если есть вопросы.

Ответы [ 6 ]

6 голосов
/ 04 октября 2010

Lisp имеет долгую историю в символьных вычислениях. См. книгу с примерами AI , написанную Питером Норвигом. Lisp предоставляет множество отличных языковых возможностей для абстрагирования общих операций над символами. Иногда вы можете написать действительно сжатый код (более краткий / короткий, чем F #).

Статические языки, такие как F #, имеют строгие системы типов и удобное сопоставление с образцом для типов данных. Компилятор может найти ошибки, обнаруженные системой типов, например, отсутствие рассмотрения одного особого случая. Размышление о типах с вашими данными также может снизить вероятность ошибок во время выполнения. Вывод типа в F # также делает код F # очень лаконичным.

6 голосов
/ 04 октября 2010

Я не знаю много о Clojure, но вот, по крайней мере, некоторые указатели.

Ключевой особенностью, которая делает код F # приятным, является сопоставление с шаблоном на алгебраических типах данных . Алгебраический тип данных является, например, объявлением типа Expression (который используется для представления математических выражений), а сопоставление с образцом - это конструкция match, которая используется для проверки различных известных случаев при реализации упрощения или дифференцирования.

Я не думаю, что Clojure имеет какую-либо встроенную поддержку сопоставления с образцом, но его можно реализовать в виде библиотеки. Одна библиотека, которая выглядит довольно интересной, - это модуль соответствия patter (в Clojars). Вот пример, который использует его для реализации алгебраического оценщика (что довольно близко к статье F #).

Еще одна вещь, которая появляется в статье F #, это активные шаблоны (которые позволяют объявлять и повторно использовать шаблоны). Я не думаю, что для этого есть библиотека Clojure, но, учитывая гибкость языка, должна быть возможность реализовать их тоже (однако в статье F # они на самом деле не так необходимы)

4 голосов
/ 05 октября 2010

Символическое дифференцирование было одним из первых применений lisp!

Я сделал блог о простом символическом дифференциаторе. Он имеет дело только с + и *, но легко расширяется.

Это была часть серии, которую я написал, чтобы познакомить новичков с clojure на конференции в Лондоне, чтобы показать, как легко для clojure манипулировать собственным кодом.

Конечно, самое приятное то, что после дифференциации код может быть скомпилирован! Таким образом, вы можете создавать дифференцированные версии пользовательского ввода или макросы, которые производят функции и их производные и т. Д.

Оригинал здесь, а синтаксис выделен:

http://www.learningclojure.com/2010/02/clojure-dojo-4-symbolic-differentiation.html

Но я разместил здесь код, чтобы вы могли посмотреть:

;; The simplest possible symbolic differentiator

;; Functions to create and unpack additions like (+ 1 2)
(defn make-add [ a b ] (list '+ a b))
(defn addition? [x] (and (=(count x) 3) (= (first x) '+)))
(defn add1   [x] (second x))
(defn add2   [x] (second (rest x)))


;; Similar for multiplications (* 1 2)
(defn make-mul [ a b ] (list '* a b))
(defn multiplication? [x] (and (=(count x) 3) (= (first x) '*)))
(defn mul1   [x] (second x))
(defn mul2   [x] (second (rest x)))


;; Differentiation. 
(defn deriv [exp var]
  (cond (number? exp) 0                                                              ;; d/dx c -> 0
        (symbol? exp) (if (= exp var) 1 0)                                           ;; d/dx x -> 1, d/dx y -> 0

        (addition? exp) (make-add (deriv (add1 exp) var) (deriv (add2 exp) var))     ;; d/dx a+b -> d/dx a + d/dx b
        (multiplication? exp) (make-add (make-mul (deriv (mul1 exp) var) (mul2 exp)) ;; d/dx a*b -> d/dx a * b + a * d/dx b
                                        (make-mul (mul1 exp) (deriv (mul2 exp) var)))
        :else :error))


;;an example of use: create the function x -> x^3 + 2x^2 + 1 and its derivative 
(def poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1))

(defn poly->fnform [poly] (list 'fn '[x] poly))

(def polyfn  (eval (poly->fnform poly)))
(def dpolyfn (eval (poly->fnform (deriv poly 'x))))



;;tests

(use 'clojure.test)

(deftest deriv-test
  (testing "binary operators"
    (is (= (let [m '(* a b)] [(multiplication? m) (make-mul (mul1 m) (mul2 m))]) [true  '(* a b)]))
    (is (= (let [m '(* a b)] [(addition? m)       (make-add (add1 m) (add2 m))]) [false '(+ a b)])))
  (testing "derivative function"

    (is (= (deriv '0 'x)               '0))
    (is (= (deriv '1 'x)               '0))
    (is (= (deriv 'x 'x)               '1))
    (is (= (deriv 'y 'x)               '0))
    (is (= (deriv '(+ x x) 'x)         '(+ 1 1)))
    (is (= (deriv '(* x x) 'x)         '(+ (* 1 x) (* x 1))))
    (is (= (deriv '(* x x) 'y)         '(+ (* 0 x) (* x 0))))
    (is (= (deriv '(* x (* x x)) 'x)   '(+ (* 1 (* x x)) (* x (+ (* 1 x) (* x 1)))))))
  (testing "function creation: d/dx (x^3 + 2x^2 + 1) = 3x^2 + 4x "
    (let [poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1)]
      (is (= ((eval (poly->fnform poly)) 3) 46))
      (is (= ((eval (poly->fnform (deriv poly 'x))) 3)))))) 
2 голосов
/ 04 октября 2010

Я не пробовал, но Clojuratica выглядит очень интересно.

1 голос
/ 30 августа 2011

Что ж, теперь Clojure предлагает мощные библиотеки сопоставления с образцом:

  1. соответствие: https://github.com/dcolthorp/matchure
  2. совпадение: https://github.com/swannodette/match
0 голосов
/ 14 января 2017

Да, такая система, как вы описали, теперь существует на Clojure!Это не что иное, как система компаньонов Джерри Суссмана в его книге SICM (Структура и интерпретация классической механики) Мудрости.Для Clojure он был назван sicmutils и портирован Колином Смитом.

Я кратко описал это в другом месте - https://stackoverflow.com/a/41646455/4070712 - но вкратце да, он определенно делает четыре вещи, о которых упоминает статья F #, а именно:

  1. Дифференциация:
  2. Упрощение алгебраических выражений
  3. Форматирование
  4. Синтаксический анализвыражения

и многое, многое другое ...

1) Дифференцирование (поддерживается полная частичная дифференциация)

> (defn ff [x y] (* (expt x 3)(expt y 5)))
> ((D ff) 'x 'y) ==> (down (* 3 (expt x 2) (expt y 5)) (* 5 (expt x 3) (expt y 4))) 
> ;; i.e. vector of results wrt to both variables

Примечание.Поддерживаются два типа векторов: «вверх» и «вниз» для размещения ковариантных и контравариантных выражений

2) Упрощение выражений: О, да ...

> (def unity (+ (square sin) (square cos)))
> (unity 'x)   ==> 1 ;; yes we can deal with symbols

3) Форматирование: Выражения могут быть отображены в TeX для красивого отображения.Я не могу показать это легко здесь, но в настоящее время блокнот / рабочий стол в стиле Maple находится в стадии разработки, используя Clojure "Gorilla"

4) Разбор: Очевидно.Преобразование между выражениями и функциями является основной частью системы.

Посмотрите на https://github.com/littleredcomputer/sicmutils.вам даже не нужен Clojure для его запуска, вы можете использовать прилагаемый файл jar Java.

...