! Copyright (C) 2009 Jason Merrill. ! See http://factorcode.org/license.txt for BSD license. USING: kernel fry accessors math math.functions locals assocs ; IN: automatic-differentiation TUPLE: dual ordinary-part epsilon-part ; C: dual M: number ordinary-part>> ; M: number epsilon-part>> drop 0 ; : unpack-dual ( dual -- ordinary-part epsilon-part ) [ ordinary-part>> ] [ epsilon-part>> ] bi ; : d+ ( x y -- x+y ) [ [ ordinary-part>> ] bi@ + ] [ [ epsilon-part>> ] bi@ + ] 2bi ; : dneg ( x -- -x ) unpack-dual [ neg ] bi@ ; : d- ( x y -- x-y ) dneg d+ ; : d* ( x y -- x*y ) [ [ ordinary-part>> ] bi@ * ] [ [ [ epsilon-part>> ] [ ordinary-part>> ] bi* * ] [ [ ordinary-part>> ] [ epsilon-part>> ] bi* * ] 2bi + ] 2bi ; ! Not written in terms of recip in order to avoid loss of precision. : d/ ( x y -- x/y ) [ [ ordinary-part>> ] bi@ / ] [ [ [ epsilon-part>> ] [ ordinary-part>> ] bi* / ] [ [ ordinary-part>> ] [ unpack-dual ] bi* swap sq / * ] 2bi - ] 2bi ; :: (d^) ( xo xe yo ye -- x^y ) xo yo ^ xo yo 1 - ^ yo * xe * ye 0 = [ ] [ xo yo ^ yo log * ye * + ] if ; : d^ ( x y -- x^y ) [ unpack-dual ] bi@ (d^) ; M: dual sin [ ordinary-part>> sin ] [ unpack-dual swap cos * ] bi ; M: dual cos [ ordinary-part>> cos ] [ unpack-dual swap sin neg * ] bi ; M: dual exp [ ordinary-part>> exp ] [ unpack-dual swap exp * ] bi ; M: dual log [ ordinary-part>> log ] [ unpack-dual swap / ] bi ; ! Replaces instances of math operators with their dual counterparts. This ! could be much smarter (work with nested quotations, inline word defs, etc.). ! If math operators could be overloaded like other generic words, there would ! be no need for this. : lift ( quot -- quot' ) H{ { + d+ } { - d- } { * d* } { / d/ } { ^ d^ } } substitute ; : [1diff] ( quot -- quot' ) lift '[ 1 @ epsilon-part>> ] ; inline : 1diff ( x quot -- y ) [1diff] call ; inline ! Plan for improvement: ! * Write a few unit tests. ! * Create a macro (?) define-derivative that takes a word and its derivative ! and specializes the word to operate on the dual class. ! * Similar to above for math-derivative. ! * Create a way to flatten definitions so that the math operators can be ! replaced with their dual counterparts.