nflow v0.2.0

топ 100 блогов love5an30.01.2011 Полностью переработал модель распространения данных в neural-flow 
Не без помощи nflow v0.2.0 [info]dmitry_vk  в lisp@c.j.r, надо сказать.

Библиотека стала больше походить на cells. Но, её интерфейс и dataflow-модель - намного проще и удобнее в использовании.

Теперь зависимости между нейронами вычисляются автоматически, динамически, и, кроме того, один нейрон может зависеть от нескольких других одновременно.

Что значит "автоматически"? Это значит, что, в отличие от предыдущей версии, теперь не нужно руками делать add-connection и remove-connection. Нейрон сам вычислит, с кем он связан и соответствующим образом распространяет поток данных.

Что значит "динамически"? Это значит, что связи между нейронами создаются и изменяются во время выполнения программы, на основе взаимодействия нейронов, а не на основе каких-либо статически заданных формул. Короче, как и у настоящих нейронов.
А связи между настоящими нейронами зависят от множества факторов - от расположения нейрона, от количества алкоголя в крови, да и даже от фазы луны.

Кстати, о фазе луны. Вот сразу  пример :)

(defparameter *input* (neuron ()
nil))

(defparameter *first* (neuron ()
(neuron-value *input*)
:first))

(defparameter *second* (neuron ()
(neuron-value *input*)
:second))

(defparameter *output* (neuron ()
(if (evenp (floor (get-universal-time) ;;количество секунд с 1 января 1900 года
(* 60 60 24 29.5 1/2))) ;;количество секунд в лунном полуцикле
(neuron-value *second*)
(neuron-value *first*))))

(defun query-lunar-phase ()
(update-neuron *input*)
(neuron-value *output*))

В первую половину лунного цикла нейрон *output* будет узнавать значение лунной фазы из нейрона *first*, а во вторую половину - из *second*. Ну, довольно очевидно, что на сегодняшний день он будет хранить значение :second :)

Макрос neuron это просто удобная форма записи (make-instance 'neuron ...)
Выглядит он так:

(defmacro neuron ((&optional (neuron-class 'neuron) (value-var (gensym)) &rest args)
&body body)
(check-type value-var symbol)
`(make-instance ',neuron-class
:function (lambda (,value-var) (declare (ignorable ,value-var)) ,@body)
,@args))
Таким образом, что каждый нейрон представляет собой функтор, являющийся звеном в некоторой цепочке вычислений.

Как видно, в функции query-lunar-phase мы не указываем явно, что нам нужно обновить именно нейрон *output*, который собственно и вычисляет фазу луны. Напротив, мы обновляем только нейрон *input*. И тем не менее, поток данных проходит весь путь от *input* к *output*.

Как это достигается? Очень просто - вызов функции neuron-value записывает нейрон, из которого мы эту функцию вызываем, в список зависимостей нейрона, к которому мы обращаемся.

(defun neuron-value (neuron)
(declare (type neuron neuron))
(when *current-neuron*
(pushnew *current-neuron* (slot-value neuron '%dependents) :test #'eq))
(slot-value neuron '%value))
Сама же функция-обработчик-данных нейрона, вызывается, среди прочего, при его создании.

Таким образом, связи между нейронами зависят исключительно от того, куда нейрон дотягивается "дендритами" во время выполнения программы. Для вышеописанного примера, на сегодняшнее число, связи будут выглядеть так:
нейроны
Прослеживается аналогия с монадами - нейрон, как и монада, это некое звено в цепочке вычислений. Отличие в том, что функция нейрона выполняет роли как bind, так и return; впрочем, я думаю позже ввести "синапсы"  - обобщенные функции, которые бы обрабатывали значение, полученное из нейрона, и значение, возвращаемое самим функтором. 

Важное отличие от традиционного FRP(functional reactive programming) состоит в том, что в моей библиотеке используется data-driven(push-based, eager) модель, в противоположность demand-driven(pull-based, lazy) моделям, которые обычно используются в FRP-фреймворках.

На практике это означает то, что поток данных инициируется каким-либо событием, например, изменением слота, хранящего текущее значение нейрона, или вызовом update-neuron, в противоположность традиционному FRP, где вычисления начинаются при попытке узнать значение слота.

Напоследок, еще один пример:

;;В объектах классов, являющихся экземплярами метакласса dataflow-class
;; все слоты являются нейронами
;; При этом, мы можем продолжать с ними работать как с обычными слотами.
(defclass textbox (dataflow-object)
((text :initform "" :accessor textbox-text))
(:metaclass dataflow-class))

(defclass checkbox (dataflow-object)
((checked :initform nil :accessor checkbox-checked))
(:metaclass dataflow-class))

(defun event-example ()
(let* ((textbox (make-instance 'textbox))
(checkbox (make-instance 'checkbox)))
;;bindf это обобщенная функция, устанавливающая нейрону или слоту(как здесь)
;; новую функцию-обработчик, или же устанавливающая слоту новый нейрон.
(bindf (lambda (old-value)
(declare (ignore old-value))
(if (checkbox-checked checkbox)
"Checked"
"Unchecked"))
textbox
:slot 'text)
;;просто некий нейрон, который будет нас оповещать об изменениях
;; слота text у textbox'а
(let ((observer (neuron ()
(format t "Text changed. New value: ~s"
(textbox-text textbox)))))
(declare (ignorable observer))
checkbox)))


;;При изменении слота checked, слот textbox'a также будет изменяться -
;; устанавливаться в "Checked" или "Unchecked" соответственно.
;; А при изменении самого слота text, этим, или
;; другим способом(например через (setf slot-value)),
;; об изменении нас будет оповещать нейрон observer

Оставить комментарий

Архив записей в блогах:
Иудеи живут по Торе, известной нам, христианам, как Ветхий Завет. Ветхий Завет — это архаика-архаика и жуткое живодёрство. Я пишу именно про иудеев, а не про евреев, поскольку, если что, то первые христиане — это тоже евреи, но христиан-евреев иудеи считают сектантами и ...
Это не я, это всё Гугл-переводчик со своим удивительным умением называть вещи не совсем своими именами, так, что хоть стой, хоть падай. Конечно, это никакие не торты. По крайней мере, в нашем обычном понимании этого слова. Тогда что? Печенье? ...
Богатое слово узнал. Более того, это не просто человек, но и пароход имя существительное - это ещё и специальность :)! Кажется, я теперь знаю, чем можно заменить неуклюжее и поднадоевшее "диванный эксперт". Как только кто-то устанет от ваших рассуждений или, упаси боже, обвинит в ...
Сегодня вечером (ну, то есть, технически, вчера) научно-исследовательский корабль "Колумб" Земного Директората обнаружил чайник Рассела . Если вы в Stellaris обнаружили аномалию на орбите звезды, и при её изучении открылся спецпроект Improbable Ceramics ("Невозможная керамика" в русской ...
Реализация мечты колонизатора Сесила Родса о всемирной англосаксонской империи в цифровую эпоху В качестве одного из своих главных ближайших дел избранный президентом США Джозеф Байден объявил проведение в 2021 году «глобального саммита в поддержку демократии против ...