Radul, A., Pearlmutter, B., and Siskind, J.M., `AD in Fortran, Part 1: Design,' submitted to 6th International Conference on Automatic Differentiation, Advances in Automatic Differentiation, Lecture Notes in Computational Science and Engineering, Springer:Berlin, 2012.which finds an equilibrium of a two-player game with continuous scalar strategies.
This page shows in detail how the Farfel
program from Listing 1 in the paper transforms to
Fortran77, using
Tapenade 3.6 and
adifor to perform the AD
transformations.
The intermediate result of each stage of the transformation is given by a link
to a complete Farfel program.
The final result is a runnable
Fortran77 program.
fprime
from
argmax
function argmax(f, x0, n) function fprime(x) fprime = deriv1(f, x) end argmax = root(fprime, x0, n) endinto
function argmax_fprime(x) argmax_fprime = deriv1(f, x) end function argmax(f, x0, n) argmax = root(argmax_fprime, x0, n) endby extracting the nested subprogram
fprime
to the top
level and renaming it argmax_fprime.function argmax_fprime(x, f) argmax_fprime = deriv1(f, x) endIntermediate state: html text
argmax = root(argmax_fprime, f, x0, n)Intermediate state: html text
function root_1(f, f1, x0, n) x = x0 do 1669 i = 1, n call deriv2(f, f1, x, y, yprime) 1669 x = x - y / yprime root_1 = x endand adjust the call site to use the correct version of
root
:argmax = root_1(argmax_fprime, f, x0, n)Intermediate state: html text
root
:subroutine deriv2_1(f, f1, x, y, yprime) external f adf(x) y = f(x, f1) end adf(yprime = tangent(y)) endand adjust the call site accordingly:
call deriv2_1(f, f1, x, y, yprime)Valid Farfel program: html text
function root_1(f1, x0, n) x = x0 do 1669 i = 1, n call deriv2_1(f1, x, y, yprime) 1669 x = x - y / yprime root_1 = x end subroutine deriv2_1(f1, x, y, yprime) adf(x) y = argmax_fprime(x, f1) end adf(yprime = tangent(y)) end argmax = root_1(f, x0, n)Valid Farfel program: html text
f
from eqlbrm.subroutine eqlbrm(biga, bigb, astar, bstar, n) external biga, bigb function f(astar) function g(a) function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) g = biga(a, bstar) end f = argmax(g, astar, n) - astar end astar = root(f, astar, n) endbecomes
function eqlbrm_f(astar) external biga, bigb function g(a) function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) g = biga(a, bstar) end eqlbrm_f = argmax(g, astar, n) - astar end subroutine eqlbrm(biga, bigb, astar, bstar, n) astar = root(eqlbrm_f, astar, n) endby extracting the nested subprogram f to the top level and renaming it to
eqlbrm_f
.function eqlbrm_f(astar, biga, bigb, bstar, n) function g(a) function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) g = biga(a, bstar) end eqlbrm_f = argmax(g, astar, n) - astar endIntermediate state: html text
astar = root(eqlbrm_f, biga, bigb, bstar, n, astar, n)Intermediate state: html text
f
:function root_2(f, biga, bigb, bstar, x0, n) x = x0 do 1669 i = 1, n call deriv2(f, x, y, yprime) 1669 x = x - y / yprime root_2 = x endand adjust the call site to call the specialization:
astar = root_2(f, biga, bigb, bstar, astar, n)Note that we eliminate the extra copy of n in both the subprogram definition and the call site.
subroutine deriv2_2(f, biga, bigb, bstar, n, x, y, yprime) external f adf(x) y = f(x, biga, bigb, bstar, n) end adf(yprime = tangent(y)) endand redirect its call site:
call deriv2_2(f, biga, bigb, bstar, n, x, y, yprime)Valid Farfel program: html text
astar = root_2(biga, bigb, bstar, astar, n) function root_2(biga, bigb, bstar, x0, n) x = x0 do 1669 i = 1, n call deriv2_2(biga, bigb, bstar, n, x, y, yprime) 1669 x = x - y / yprime root_2 = x end subroutine deriv2_2(biga, bigb, bstar, n, x, y, yprime) adf(x) y = eqlbrm_f(x, biga, bigb, bstar, n) end adf(yprime = tangent(y)) endValid Farfel program: html text
g
from eqlbrm_f:function eqlbrm_f(astar, biga, bigb, bstar, n) external biga, bigb function g(a) function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) g = biga(a, bstar) end eqlbrm_f = argmax(g, astar, n) - astar endbecomes
function eqlbrm_f_g(a) external biga, bigb function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) eqlbrm_f_g = biga(a, bstar) end function eqlbrm_f(astar, biga, bigb, bstar, n) eqlbrm_f = argmax(eqlbrm_f_g, astar, n) - astar endby extracting the nested subprogram g to the top level.
function eqlbrm_f_g(a, astar, biga, bigb, bstar, n) external biga, bigb function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) eqlbrm_f_g = biga(a, bstar) endIntermediate state: html text
eqlbrm_f = argmax(eqlbrm_f_g, astar, biga, bigb, bstar, n, astar, n) - astarIntermediate state: html text
eqlbrm_f_g
:
function argmax_1(f, astar, biga, bigb, bstar, x0, n) argmax_1 = root_1(f, astar, biga, bigb, bstar, n, x0, n) endand change the call site to call the specialization:
eqlbrm_f = argmax_1(eqlbrm_f_g, astar, biga, bigb, bstar, astar, n) - astarNote that we eliminate the extra copy of n in both the subprogram definition and the call site.
function root_1_1(f1, astar, biga, bigb, bstar, x0, n) x = x0 do 1669 i = 1, n call deriv2_1(f1, astar, biga, bigb, bstar, n, x, y, yprime) 1669 x = x - y / yprime root_1_1 = x endand adjust its call site:
argmax_1 = root_1_1(f, astar, biga, bigb, bstar, x0, n)Note that we eliminate the extra copy of n in both the subprogram definition and the call site.
subroutine deriv2_1_1(f1, astar, biga, bigb, bstar, n, x, y, yprime) adf(x) y = argmax_fprime(x, f1, astar, biga, bigb, bstar, n) end adf(yprime = tangent(y)) endand change the call site to call the specialization:
call deriv2_1_1(f1, astar, biga, bigb, bstar, n, x, y, yprime)Intermediate state: html text
function argmax_fprime_1(x, f, astar, biga, bigb, bstar, n) argmax_fprime_1 = deriv1(f, astar, biga, bigb, bstar, n, x) endand retarget its call site:
y = argmax_fprime_1(x, f1, astar, biga, bigb, bstar, n)Intermediate state: html text
function deriv1_1(f, astar, biga, bigb, bstar, n, x) external f adf(x) y = f(x, astar, biga, bigb, bstar, n) end adf(deriv1_1 = tangent(y)) endand retarget its call site:
argmax_fprime_1 = deriv1_1(f, astar, biga, bigb, bstar, n, x)Valid Farfel program: html text
eqlbrm_f = argmax_1(astar, biga, bigb, bstar, astar, n) - astar function root_1_1(astar, biga, bigb, bstar, x0, n) x = x0 do 1669 i = 1, n call deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) 1669 x = x - y / yprime root_1_1 = x end subroutine deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) adf(x) y = argmax_fprime_1(x, astar, biga, bigb, bstar, n) end adf(yprime = tangent(y)) end function argmax_fprime_1(x, astar, biga, bigb, bstar, n) argmax_fprime_1 = deriv1_1(astar, biga, bigb, bstar, n, x) end function argmax_1(astar, biga, bigb, bstar, x0, n) argmax_1 = root_1_1(astar, biga, bigb, bstar, x0, n) end function deriv1_1(astar, biga, bigb, bstar, n, x) adf(x) y = eqlbrm_f_g(x, astar, biga, bigb, bstar, n) end adf(deriv1_1 = tangent(y)) endValid Farfel program: html text
h
in eqlbrm_f_g:function eqlbrm_f_g(a, astar, biga, bigb, bstar, n) external biga, bigb function h(b) h = bigb(astar, b) end bstar = argmax(h, bstar, n) eqlbrm_f_g = biga(a, bstar) endbecomes
function eqlbrm_f_g_h(b) external bigb eqlbrm_f_g_h = bigb(astar, b) end function eqlbrm_f_g(a, astar, biga, bigb, bstar, n) external biga bstar = argmax(eqlbrm_f_g_h, bstar, n) eqlbrm_f_g = biga(a, bstar) endby extracting the nested subprogram h to the top level.
function eqlbrm_f_g_h(b, astar, bigb) external bigb eqlbrm_f_g_h = bigb(astar, b) endIntermediate state: html text
bstar = argmax(eqlbrm_f_g_h, astar, bigb, bstar, n)Intermediate state: html text
eqlbrm_f_g_h
:function argmax_2(f, astar, bigb, x0, n) argmax_2 = root_1(f, astar, bigb, x0, n) endand change its call site to refer to the specialization:
bstar = argmax_2(eqlbrm_f_g_h, astar, bigb, bstar, n)Intermediate state: html text
function root_1_2(f1, astar, bigb, x0, n) x = x0 do 1669 i = 1, n call deriv2_1(f1, astar, bigb, x, y, yprime) 1669 x = x - y / yprime root_1_2 = x endand change its call site:
argmax_2 = root_1_2(f, astar, bigb, x0, n)Intermediate state: html text
subroutine deriv2_1_2(f1, astar, bigb, x, y, yprime) adf(x) y = argmax_fprime(x, f1, astar, bigb) end adf(yprime = tangent(y)) endand adjust its call site:
call deriv2_1_2(f1, astar, bigb, x, y, yprime)Intermediate state: html text
function argmax_fprime_2(x, f, astar, bigb) argmax_fprime_2 = deriv1(f, astar, bigb, x) endand adjust its call site:
y = argmax_fprime_2(x, f1, astar, bigb)Intermediate state: html text
function deriv1_2(f, astar, bigb, x) external f adf(x) y = f(x, astar, bigb) end adf(deriv1_2 = tangent(y)) endand adjust its call site:
argmax_fprime_2 = deriv1_2(f, astar, bigb, x)Valid Farfel program: html text
bstar = argmax_2(astar, bigb, bstar, n) function root_1_2(astar, bigb, x0, n) x = x0 do 1669 i = 1, n call deriv2_1_2(astar, bigb, x, y, yprime) 1669 x = x - y / yprime root_1_2 = x end subroutine deriv2_1_2(astar, bigb, x, y, yprime) adf(x) y = argmax_fprime_2(x, astar, bigb) end adf(yprime = tangent(y)) end function argmax_fprime_2(x, astar, bigb) argmax_fprime_2 = deriv1_2(astar, bigb, x) end function deriv1_2(astar, bigb, x) adf(x) y = eqlbrm_f_g_h(x, astar, bigb) end adf(deriv1_2 = tangent(y)) end function argmax_2(astar, bigb, x0, n) argmax_2 = root_1_2(astar, bigb, x0, n) endValid Farfel program: html text
adf
blocks to be single subroutine calls.
We transformfunction deriv1_1(astar, biga, bigb, bstar, n, x) adf(x) y = eqlbrm_f_g(x, astar, biga, bigb, bstar, n) end adf(deriv1_1 = tangent(y)) endinto
function deriv1_1(astar, biga, bigb, bstar, n, x) subroutine adf1() y = eqlbrm_f_g(x, astar, biga, bigb, bstar, n) end adf(x) call adf1() end adf(deriv1_1 = tangent(y)) endand then closure-convert (by re-applying the above process) to get
subroutine deriv1_1_adf1(x, astar, biga, bigb, bstar, n, y) y = eqlbrm_f_g(x, astar, biga, bigb, bstar, n) end function deriv1_1(astar, biga, bigb, bstar, n, x) adf(x) call deriv1_1_adf1(x, astar, biga, bigb, bstar, n, y) end adf(deriv1_1 = tangent(y)) endValid Farfel program: html text
function deriv1_2(astar, bigb, x) adf(x) y = eqlbrm_f_g_h(x, astar, bigb) end adf(deriv1_2 = tangent(y)) endinto
subroutine deriv1_2_adf2(x, astar, bigb, y) y = eqlbrm_f_g_h(x, astar, bigb) end function deriv1_2(astar, bigb, x) adf(x) call deriv1_2_adf2(x, astar, bigb, y) end adf(deriv1_2 = tangent(y)) endValid Farfel program: html text
subroutine deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) adf(x) y = argmax_fprime_1(x, astar, biga, bigb, bstar, n) end adf(yprime = tangent(y)) endinto
subroutine deriv2_1_1_adf3(x, astar, biga, bigb, bstar, n, y) y = argmax_fprime_1(x, astar, biga, bigb, bstar, n) end subroutine deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) adf(x) call deriv2_1_1_adf3(x, astar, biga, bigb, bstar, n, y) end adf(yprime = tangent(y)) endValid Farfel program: html text
subroutine deriv2_1_2(astar, bigb, x, y, yprime) adf(x) y = argmax_fprime_2(x, astar, bigb) end adf(yprime = tangent(y)) endinto
subroutine deriv2_1_2_adf4(x, astar, bigb, y) y = argmax_fprime_2(x, astar, bigb) end subroutine deriv2_1_2(astar, bigb, x, y, yprime) adf(x) call deriv2_1_2_adf4(x, astar, bigb, y) end adf(yprime = tangent(y)) endValid Farfel program: html text
subroutine deriv2_2(biga, bigb, bstar, n, x, y, yprime) adf(x) y = f(x, biga, bigb, bstar, n) end adf(yprime = tangent(y)) endinto
subroutine deriv2_2_adf5(x, biga, bigb, bstar, n, y) y = f(x, biga, bigb, bstar, n) end subroutine deriv2_2(biga, bigb, bstar, n, x, y, yprime) adf(x) call deriv2_2_adf5(x, biga, bigb, bstar, n, y) end adf(yprime = tangent(y)) endValid Farfel program: html text
adf
blocks into
calls to subroutines that will be generated by AD. For
Tapenade, that
looks like the following:
function deriv1_1(astar, biga, bigb, bstar, n, x) adf(x) call deriv1_1_adf1(x, astar, biga, bigb, bstar, n, y) end adf(deriv1_1 = tangent(y)) endinto
function deriv1_1(astar, biga, bigb, bstar, n, x) x_g1 = 1.0 astar_g1 = 0.0 bstar_g1 = 0.0 call deriv1_1_adf1_g1(x, x_g1, astar, astar_g1, biga, bigb, bstar, +bstar_g1, n, y, deriv1_1) endIntermediate state: html text
function deriv1_2(astar, bigb, x) adf(x) call deriv1_2_adf2(x, astar, bigb, y) end adf(deriv1_2 = tangent(y)) endinto
function deriv1_2(astar, bigb, x) x_g2 = 1.0 astar_g2 = 0.0 call deriv1_2_adf2_g2(x, x_g2, astar, astar_g2, bigb, y, deriv1_2) endIntermediate state: html text
subroutine deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) adf(x) call deriv2_1_1_adf3(x, astar, biga, bigb, bstar, n, y) end adf(yprime = tangent(y)) endinto
subroutine deriv2_1_1(astar, biga, bigb, bstar, n, x, y, yprime) x_g3 = 1.0 astar_g3 = 0.0 bstar_g3 = 0.0 call deriv2_1_1_adf3_g3(x, x_g3, astar, astar_g3, biga, bigb, bstar, +bstar_g3, n, y, yprime) endIntermediate state: html text
subroutine deriv2_1_2(astar, bigb, x, y, yprime) adf(x) call deriv2_1_2_adf4(x, astar, bigb, y) end adf(yprime = tangent(y)) endinto
subroutine deriv2_1_2(astar, bigb, x, y, yprime) x_g4 = 1.0 astar_g4 = 0.0 call deriv2_1_2_adf4_g4(x, x_g4, astar, astar_g4, bigb, y, yprime) endIntermediate state: html text
subroutine deriv2_2(biga, bigb, bstar, n, x, y, yprime) adf(x) call deriv2_2_adf5(x, biga, bigb, bstar, n, y) end adf(yprime = tangent(y)) endinto
subroutine deriv2_2(biga, bigb, bstar, n, x, y, yprime) x_g5 = 1.0 bstar_g5 = 1.0 call deriv2_2_adf5_g5(x, x_g5, biga, bigb, bstar, bstar_g5, n, y, yprime) endIntermediate state: html text
gmbiga
and
gmbigb
from the call to eqlbrm in
the main program to everything it (indirectly) calls:
deriv1_1_adf1,
deriv1_1,
deriv1_2_adf2,
deriv1_2,
deriv2_1_1_adf3,
deriv2_1_1,
deriv2_1_2_adf4,
deriv2_1_2,
deriv2_2_adf5,
deriv2_2,
root_1_1,
root_1_2,
root_2,
argmax_fprime_1,
argmax_fprime_2,
argmax_1,
argmax_2,
eqlbrm_f_g_h,
eqlbrm_f_g,
eqlbrm_f, and
eqlbrm, thereby freeing all programs to be differentiated
from external declarations.tapenade -root deriv1_2_adf2 -d -o eqlbrm42 -diffvarname _g2 -difffuncname _g2 eqlbrm42.f tapenade -root deriv2_1_2_adf4 -d -o eqlbrm42 -diffvarname _g4 -difffuncname _g4 eqlbrm42{,_g2}.f tapenade -root deriv1_1_adf1 -d -o eqlbrm42 -diffvarname _g1 -difffuncname _g1 eqlbrm42{,_g2,_g4}.f tapenade -root deriv2_1_1_adf3 -d -o eqlbrm42 -diffvarname _g3 -difffuncname _g3 eqlbrm42{,_g2,_g4,_g1}.f tapenade -root deriv2_2_adf5 -d -o eqlbrm42 -diffvarname _g5 -difffuncname _g5 eqlbrm42{,_g2,_g4,_g1,_g3}.fNote that the AD transforms must be invoked in the reverse of the call graph order, so that appropriate derivatives are available to be further transformed.
This work was supported, in part, by Science Foundation Ireland grant 09/IN.1/I2637, National Science Foundation grant CCF-0438806, the Naval Research Laboratory under Contract Number N00173-10-1-G023, and the Army Research Laboratory accomplished under Cooperative Agreement Number W911NF-10-2-0060. Any views, opinions, findings, conclusions, or recommendations contained or expressed in this document or material are those of the author(s) and do not necessarily reflect or represent the views or official policies, either expressed or implied, of SFI, NSF, NRL, the Office of Naval Research, ARL, or the Irish or U.S. Governments. The U.S. Government is authorized to reproduce and distribute reprints for Government purposes, notwithstanding any copyright notation herein.