A Simple Differentiable Programming Language

  • 2019-11-11 19:14:15
  • Martin Abadi, Gordon D. Plotkin
  • 12

Abstract

Automatic differentiation plays a prominent role in scientific computing andin modern machine learning, often in the context of powerful programmingsystems. The relation of the various embodiments of automatic differentiationto the mathematical notion of derivative is not always entirelyclear---discrepancies can arise, sometimes inadvertently. In order to studyautomatic differentiation in such programming contexts, we define a small butexpressive programming language that includes a construct for reverse-modedifferentiation. We give operational and denotational semantics for thislanguage. The operational semantics employs popular implementation techniques,while the denotational semantics employs notions of differentiation familiarfrom real analysis. We establish that these semantics coincide.

 

Quick Read (beta)

A Simple Differentiable Programming Language

Martín Abadi Google ResearchUnited States [email protected]  and  Gordon D. Plotkin Google ResearchUnited States [email protected]
Abstract.

Automatic differentiation plays a prominent role in scientific computing and in modern machine learning, often in the context of powerful programming systems. The relation of the various embodiments of automatic differentiation to the mathematical notion of derivative is not always entirely clear—discrepancies can arise, sometimes inadvertently. In order to study automatic differentiation in such programming contexts, we define a small but expressive programming language that includes a construct for reverse-mode differentiation. We give operational and denotational semantics for this language. The operational semantics employs popular implementation techniques, while the denotational semantics employs notions of differentiation familiar from real analysis. We establish that these semantics coincide.

automatic differentiation, differentiable programming.
copyright: rightsretainedprice: doi: 10.1145/3371106journalyear: 2020journal: PACMPLjournalvolume: 4journalnumber: POPLpublicationmonth: 1ccs: Theory of computation Denotational semanticsccs: Theory of computation Operational semanticsccs: Software and its engineering Domain specific languagesccs: Computing methodologies Machine learning

1

1. Introduction

Automatic differentiation is a set of techniques for calculating the derivatives of functions described by computer programs (e.g., (Pearlmutter and Siskind, 2008; Hascoët and Pascual, 2013; Baydin et al., 2018; Griewank, 2000)). These techniques are not required to produce symbolic representations for derivatives as in classic symbolic differentiation; on the other hand, neither do they employ finite-difference approximation methods common in numerical differentiation. Instead, they rely on the chain rule from calculus to obtain the desired derivatives from those of the programs’s basic operations. Thus, automatic differentiation is at the intersection of calculus and programming. However, the programs of interest are more than chains of operations: they may include control-flow constructs, data structures, and computational effects (e.g., side-effects or exceptions). Calculus does not provide an immediate justification for the treatment of such programming-language features.

In the present work we help bridge the gap between rules for automatic differentiation in expressive programming languages and their mathematical justification in terms of denotational semantics. Specifically, we consider automatic differentiation from a programming-language perspective by defining and studying a small but powerful language. The language is a functional first-order language, with only rudimentary data structures, but with conditionals and recursively defined functions (from which loops can be constructed). Additionally, it contains a construct for reverse-mode differentiation, explained in detail below. Our language is thus inspired by modern systems for machine learning, which include standard programming constructs and support reverse-mode differentiation. Reverse-mode differentiation permits the computation of gradients, forward-mode derivatives, and more. Indeed as our differentiation construct is a language primitive, differentiations can be nested within differentiations, allowing the computation of higher-order derivatives.

In the setting of a language such as ours, we can consider some common approaches to implementing differentiation:

  • One approach relies on code transformation, whether on source code or intermediate representations. For example, for the derivative of a conditional expression 𝚒𝚏B𝚝𝚑𝚎𝚗M1𝚎𝚕𝚜𝚎M2, it would output 𝚒𝚏B𝚝𝚑𝚎𝚗N1𝚎𝚕𝚜𝚎N2, where N1 and N2 are the derivatives of M1 and M2 respectively. This approach is employed, for instance, in Theano (Bergstra et al., 2010), Tensorflow 1.0 (Abadi et al., 2016a; Yu et al., 2018), and Tangent (van Merrienboer et al., 2018).

  • Another approach relies on tracing, typically eliminating control structures to produce a simpler form of code, which we call an execution trace, that can more easily be differentiated. For example, to produce the derivative of 𝚒𝚏B𝚝𝚑𝚎𝚗M1𝚎𝚕𝚜𝚎M2, tracing would evaluate the conditional and produce a trace of the branch taken. Execution traces correspond to graphs of basic operations, and can be taken to be sequences of elementary assignments or else functional programs in A-normal form. Their derivatives can be calculated by applying the chain rule to those basic operations, perhaps via a code transformation (but now of a much simpler kind). Tracing may also record some intermediate values in an evaluation trace, to reduce, or eliminate, the need for recomputation.11 1 Terminology in the automatic differentiation literature varies. Here we follow (Griewank, 2000) for evaluation traces. Our execution traces are, perhaps in somewhat different manifestations, variously termed Wengert lists or tapes or evaluation traces (Baydin et al., 2018; Pearlmutter and Siskind, 2008). They can also be seen as combinations of the operation and index traces of (Griewank, 2000).

    This approach thereby conveniently avoids the problem of defining code transformations for conditionals and many other language constructs. It can also be implemented efficiently, sometimes in part with JIT compilation. For these reasons, trace-based differentiation is of growing importance. It is employed, for instance, in Autograd (Maclaurin et al., 2015), TensorFlow Eager Mode (Shankar and Dobson, 2017), Chainer (Tokui, 2018), PyTorch (PyTorch, 2018), and JAX (Frostig et al., 2018).

We therefore focus on trace-based differentiation in this paper, and give an operational semantics for our language using the trace-based approach. To do so, we define a sublanguage of execution trace terms (called simply trace terms below). These terms have no conditionals, function definitions or calls, or reverse-mode differentiations. They do have local definitions, corresponding to fanout in the graphs, but are not necessarily in A-normal form. Tracing is modeled by a new kind of evaluation, called symbolic evaluation. This uses an environment for the free variables of a term to remove conditionals and function calls. Function derivatives at a given value are evaluated in three stages: first, the function is traced at that value; next, the resulting trace term is symbolically differentiated (largely just using the chain rule), resulting in another such trace term; and, finally, that term is evaluated.

We do not account for some of the optimizations used in practice. Doing so would have been a more complicated enterprise, possibly with more arbitrary choices tied to implementation details, and we wished to get a more straightforward formalization working first.

From a mathematical perspective, both approaches to implementing differentiation pose correctness problems. In particular, functions defined using conditionals need not be continuous, let alone differentiable. Consider, for example, the following definition

f(x:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚒𝚏(x<0)𝚝𝚑𝚎𝚗 0𝚎𝚕𝚜𝚎x

of the popular ReLU function (Goodfellow et al., 2016). This function is not differentiable at 0. Further, changing the function body to 𝚒𝚏(x<0)𝚝𝚑𝚎𝚗 0𝚎𝚕𝚜𝚎 1 yields a non-continuous function. What is more, both approaches can produce wrong answers even for differentiable functions! Consider, for example, the following definition of the identity function on the reals:

g(x:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚒𝚏(x=0)𝚝𝚑𝚎𝚗 0𝚎𝚕𝚜𝚎x

The derivative of this function at x=0 is 1. However, differentiation “by branches” (whether by code transformation or tracing) would produce the wrong answer, 0.

In order to capture the mathematical perspective, in addition to its operational semantics we give our language a denotational semantics. This semantics is based on classical notions of differentiation from real analysis (see, for example, (Trench, 2003)). That theory concerns multivariate functions on the reals defined on open domains, i.e., partial such functions with open domains of definition. In our semantics, we make use of those that are smooth (that is, those that can be partially differentiated any number of times). A particularly pleasing aspect of this mathematical development is how well domain theory (needed to account for recursion) interacts with differentiation.

Partiality is necessary, as for any language with general recursion, but it also gives us useful flexibility in connection with differentiation. For example, let <˙ be the approximation to < which is equal to it except on the diagonal (i.e., where both arguments are equal) where it is undefined. Then

f˙(x:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚒𝚏(x<˙0)𝚝𝚑𝚎𝚗 0𝚎𝚕𝚜𝚎x

defines an approximation to ReLU which is undefined at 0. The approximation to < is (unlike <) continuous (i.e., the pre-images of 𝚝𝚛𝚞𝚎 and 𝚏𝚊𝚕𝚜𝚎 are open sets), and the approximation to ReLU is differentiable wherever it is defined. Therefore, we design the semantics of our language so that it forbids functions such as f but allows related approximations such as f˙. An interesting question is how satisfactory an idealization this is of programming practice (which in any case works with approximate reals). We return to this point in the final section.

Proceeding in this way, we obtain adequacy theorems (i.e., operational soundness and completeness theorems) connecting the operational semantics of our language with a denotational semantics based on the classical theory of differentiation of partially defined multivariate real functions. Our theorems apply not only to conditional expressions but to the full language.

In sum, the main contributions of this paper are: (1) a first-order language with conditionals, recursive function definitions, and a reverse-mode differentiation construct; (2) an operational semantics that models one form of trace-based differentiation; (3) a denotational semantics based on standard mathematical notions from real analysis and domain theory; and (4) theorems that show that the two semantics coincide, i.e., the derivatives computed by the operational semantics are indeed the correct derivatives in a mathematical sense. Beyond the specifics of these results, this paper aims to give some evidence of the relevance of ideas and techniques from the programming-languages literature for programming systems that include automatic differentiation, such as current systems for machine learning.

Additional context

While traditionally associated with scientific computing, automatic differentiation is now a central component of many modern machine learning systems, and those for deep learning in particular (Goodfellow et al., 2016). These systems often employ automatic differentiation to compute the gradients of “loss functions” with respect to parameters, such as neural network weights. Loss functions measure the error resulting from particular values for the parameters. For example, when a machine-learning model is trained with a dataset consisting of pairs (x0,y0),,(xn-1,yn-1), aiming to learn a function that maps the xi’s to the yi’s, the loss function may be the distance between the yi’s and the values the model predicts when presented with the xi’s. By applying gradient descent to adjust the parameters, this error can be reduced, until convergence or (more commonly) until the error is tolerable enough. This simple approach has proven remarkably effective: it is at the core of many recent successes of machine learning in a variety of domains.

Whereas gradients are for functions of type 𝚛𝚎𝚊𝚕n𝚛𝚎𝚊𝚕, for n0, treating the more general functions of type 𝚛𝚎𝚊𝚕n𝚛𝚎𝚊𝚕m, for n,m0, works better with function composition, and with the composite structures such as tensors of reals used in deep learning. The literature contains two basic “modes” for differentiating such functions. Forward-mode extends the computation of the function, step by step, with the computation of derivatives; it can be seen as evaluating the function on dual numbers of the form v+v˙ε where ε is nilpotent. In contrast, reverse-mode propagates derivatives backwards from each output, typically after the computation of the function. Reverse-mode differentiation is often preferred because of its superior efficiency for functions of type 𝚛𝚎𝚊𝚕n𝚛𝚎𝚊𝚕m with m<<n. In particular, systems for machine learning, which often deal with loss functions for which m=1, generally rely on reverse-mode differentiation. We refer the reader to the useful recent survey (Baydin et al., 2018) for additional background on these two modes of differentiation; it also discusses the use of higher-order differentiation.

Applications to machine learning are our main motivation. Accordingly, our language is loosely inspired by systems for machine learning, and the implementation strategies that we consider are ones of current interest there. We also de-emphasize some concerns (e.g., numerical stability) that, at present, seem to play a larger role in scientific computing than in machine learning. As noted in (Baydin et al., 2016), the machine learning community has developed a mindset and a body of techniques distinct from those traditional in automatic differentiation.

The literature on scientific computing has addressed the correctness problem for conditionals (Beck and Fischer, 1994; Fischer, 2001), although not in the context of a formally defined programming language. In (Mayero, 2002) a formal proof of correctness was given in Coq (Bertot and Castéran, 2013) for an algorithm for the automatic differentiation of straight-line sequences of Fortran assignments. Closer to machine learning, (Selsam et al., 2017) consider a stochastic graphical formalism where the nodes are random variables, and use the Lean theorem prover (de Moura et al., 2015) to establish the correctness of stochastic backpropagation. However, overall, the literature does not seem to contain semantics and theorems for a language of the kind we consider here.

Our work is also related to important papers by by Ehrhard, Regnier, et al., and by Di Gianantonio and Edalat. Ehrhard and Regnier introduce the differential λ-calculus (see (Ehrhard and Regnier, 2003)); this is a simply-typed higher-order λ-calculus with a forward-mode differentiation construct which can be applied to functions of any type. As described in (Blute et al., 2010), the differential λ-calculus can be modeled using the category of convenient vector spaces and smooth functions between them (see (Kriegl and Michor, 1997)). They do not give an operational semantics but they do give rules for symbolic differentiation and it should not be too difficult to use them to give an operational semantics. However their language with its convenient vector space semantics only supports total functions. It therefore cannot be extended to include recursive function definitions or conditionals (even with total predicates, as continuous functions from n to the booleans are constant). Di Gianantonio and Edalat (Di Gianantonio and Edalat, 2013) prove adequacy theorems for their language, as do we, but their work differs from ours in several respects. In particular, their language has first-order forward-mode but no reverse-mode differentiation: our language effectively supports both, and at all orders. On the other hand, their language allows recursively-defined higher-order functions and accommodates functions, such as the ReLU function, which are differentiable in only a weaker sense. As far as we know, no other work on differentiable programming languages (e.g., (Pearlmutter and Siskind, 2008; Elliott, 2018; Wang et al., 2018; Shaikhha et al., 2018; Manzyuk, 2012)) gives operational and denotational semantics and proves adequacy theorems. Further afield, there is a good deal of work in the categorical literature on categories equipped with differential structure, for example (Blute et al., 2009; Bucciarelli et al., 2010).

Outline

Section 2 defines our language. Section 3 gives it an operational semantics with rules for symbolically evaluating general terms to trace terms, and for symbolically differentiating these terms. Sections 4 and 5 cover the needed mathematical material and the denotational semantics. Sections 6 establishes the correspondence between operational and denotational semantics. Section 7 concludes with discussion and some suggestions for future work.

2. A simple language

The types S,T,U, of our language are given by the grammar:

T::=𝚛𝚎𝚊𝚕𝚞𝚗𝚒𝚝T×U

We will make use of iterated products T0××Tn-1, defined to be 𝚞𝚗𝚒𝚝 when n=0, T0 when n=1, and, recursively, (T0××Tn-1)×Tn, when n>1; we write 𝚛𝚎𝚊𝚕n for the n-fold iterated product of 𝚛𝚎𝚊𝚕. Note that this type system includes the types of tensors (multidimensional arrays) of a given shape: the type of tensors of shape (d0,,dn-1) is the iterated product 𝚛𝚎𝚊𝚕d0××𝚛𝚎𝚊𝚕dn-1. The terms L,M,N,P, and boolean terms B of the language are built from operation symbols opOp and predicate symbols predPred. An example operation symbol could be 𝐷𝑃𝑟𝑜𝑑n for dot product of vectors of dimension n (for n); an example predicate symbol could be <˙.

The terms are given by the following grammar, where x and f range over disjoint countably infinite sets of ordinary and function variables, respectively (so we have disjoint alphabets of ordinary and function variables):

M::=xr(r)M+Nop(M)𝚕𝚎𝚝x:T=M𝚒𝚗NM,NT,U𝚏𝚜𝚝T,U(M)𝚜𝚗𝚍T,U(M)𝚒𝚏B𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎N𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗Nf(M)M.𝚛𝚍L(x:T.N)B::=pred(M)𝚝𝚛𝚞𝚎𝚏𝚊𝚕𝚜𝚎

These constructs are all fairly standard, except for 𝚛𝚍, which is for reverse-mode differentiation, and which we explain below. We treat addition separately from the operations to underline the fact that the commutative monoid it forms, together with zero, is basic for differentiation. For example, the rules for symbolic differentiation given below make essential use of this structure, but do not need more any more of the available vector space structure.

Note the type subscripts on pairing and projection terms. Below, we rely on these subscripts for symbolic differentiation. In practice they could, if needed, be added when type-checking.

The sets FV(M) and FFV(M) of free ordinary variables and free function variables of a term M are understood as usual (and similarly for boolean terms). As is also usual, we do not distinguish α-equivalent terms (or boolean terms).

The useful abbreviation

𝚕𝚎𝚝x0:T0,,xn-1:Tn-1=M𝚒𝚗N

provides an elimination construct for iterated products. When n=0 this is

𝚕𝚎𝚝x:𝚞𝚗𝚒𝚝=M𝚒𝚗N

where xFV(N); when n=1 it is the above let construct; otherwise, it is defined recursively by:

𝚕𝚎𝚝x0:T0,,xn:Tn=M𝚒𝚗N=𝚕𝚎𝚝z:(T0××Tn)=M𝚒𝚗𝚕𝚎𝚝x0:T0,,xn-1:Tn-1=𝚏𝚜𝚝T0××Tn-1,Tn(z)𝚒𝚗𝚕𝚎𝚝xn:Tn=𝚜𝚗𝚍T0××Tn-1,Tn(z)𝚒𝚗N

(where z is chosen not free in N).

We have zero and addition only at type 𝚛𝚎𝚊𝚕. At other types we proceed inductively:

0𝚛𝚎𝚊𝚕=0  0𝚞𝚗𝚒𝚝=  0T×U=0T,0U

and:

M+𝚞𝚗𝚒𝚝N=𝚕𝚎𝚝x:𝚞𝚗𝚒𝚝=M𝚒𝚗𝚕𝚎𝚝y:𝚞𝚗𝚒𝚝=N𝚒𝚗M+T×UN=𝚕𝚎𝚝x1:T,x2:U=M𝚒𝚗𝚕𝚎𝚝y1:T,y2:U=N𝚒𝚗x1+Ty1,x2+Uy2

Skating over the difference between terms and their denotations, M.𝚛𝚍L(x:T.N) is the reverse-mode derivative at L:T, evaluated at M:U, of the function f, where f(x:T):U=N. Reverse-mode differentiation includes gradients as a special case. When T=𝚛𝚎𝚊𝚕n and U=𝚛𝚎𝚊𝚕, the gradient of f at L is given by:

𝚐𝚛𝚊𝚍L(x:𝚛𝚎𝚊𝚕n.N)= 1.𝚛𝚍L(x:𝚛𝚎𝚊𝚕n.N)

For definitions of gradients, Jacobians, and derivatives see Section 4.1 below, particularly equations (1), (2), (3), and (4). More generally, for an introduction to real analysis including vector-valued functions of several variables and their differentials and Jacobians, see, for example, (Trench, 2003).

As in (Christianson, 2012), and as validated by equation (6) below, forward-mode differentiation can be defined using nested reverse-mode differentiation. We can set:

M.𝚏𝚍U,L(x:T.N)=M.𝚛𝚍0U(y:U.y.𝚛𝚍L(x:T.N))

So our language effectively also has forward-mode differentiation.

Function definitions can be recursive. Indeed a function can even be defined in terms of its own derivative: in a recursive function definition 𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗N, the language allows occurrences of f within the term N in a sub-term M.𝚛𝚍L(y:T.N) of M. This generality may be useful—examples (Maclaurin, 2017, p22) have arisen in the context of Autograd (Maclaurin et al., 2015). Pleasantly, both our operational and denotational semantics accommodate it without special complications. When we define a function without recursion, we may abbreviate 𝚕𝚎𝚝𝚛𝚎𝚌 to 𝚕𝚎𝚝.

Turning to typing, operation and predicate symbols have assumed arities, written op:TU and pred:T; we write OpT,U for the set of operation symbols of arity TU. As examples, we would have 𝐷𝑃𝑟𝑜𝑑n:𝚛𝚎𝚊𝚕n×𝚛𝚎𝚊𝚕n𝚛𝚎𝚊𝚕 and <˙:𝚛𝚎𝚊𝚕2. Figure 1 gives typing rules for sequents of the forms

ΦΓM:T  ΦΓB

where (type) environments Γ have the form

x0:T0,,xn-1:Tn-1

(xi all different) and where function (type) environments Φ have the form

f0:T0U0,,fn-1:Tn-1Un-1

(fi all different). We adopt the usual overwriting notations Γ[Γ] and Φ[Φ] for type environments.

ΦΓx:T(x:TΓ)  ΦΓr:𝚛𝚎𝚊𝚕(r)ΦΓM:𝚛𝚎𝚊𝚕ΦΓN:𝚛𝚎𝚊𝚕ΦΓM+N:𝚛𝚎𝚊𝚕ΦΓM:TΦΓop(M):U  (op:TU)ΦΓM:T  ΦΓ[x:T]N:UΦΓ𝚕𝚎𝚝x:T=M𝚒𝚗N:UΦΓ:𝚞𝚗𝚒𝚝  ΦΓM:T  ΦΓN:UΦΓM,NT,U:T×UΦΓM:T×UΦΓ𝚏𝚜𝚝T,U(M):T  ΦΓM:T×UΦΓ𝚜𝚗𝚍T,U(M):UΦΓB  ΦΓM:T  ΦΓN:TΦΓ𝚒𝚏B𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎N:TΦ[f:TU]Γ[x:T]M:U  Φ[f:TU]ΓN:SΦΓ𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗N:S(FV(M){x})ΦΓM:TΦΓf(M):U(f:TUΦ)ΦΓ[x:T]N:U  ΦΓL:T  ΦΓM:UΦΓM.𝚛𝚍L(x:T.N):TΦΓ𝚝𝚛𝚞𝚎ΦΓ𝚏𝚊𝚕𝚜𝚎ΦΓM:TΦΓpred(M)(pred:T)
Figure 1. Typing rules

The typing rule for function definitions forbids any global variable occurrences (i.e., free variables in function definitions). This restriction involves no loss in expressiveness: as in lambda lifting, one can just add any global variables to a function’s parameters, and then apply the function to the global variables wherever it is called. The restriction enabled us to prove part (2) of Theorem 6.2 (below), but we conjecture it is not needed.

Our various abbreviations have natural admissible typing rules:

ΦΓM:T0×,×Tn-1  ΦΓ[x0:T0,,xn-1:Tn-1]N:UΦΓ𝚕𝚎𝚝x0:T0,,xn-1:Tn-1=M𝚒𝚗N:U
ΦΓN:𝚛𝚎𝚊𝚕n  ΦΓ[x:𝚛𝚎𝚊𝚕n]M:𝚛𝚎𝚊𝚕ΦΓ𝚐𝚛𝚊𝚍N(x:𝚛𝚎𝚊𝚕n.M):𝚛𝚎𝚊𝚕n
ΦΓ[x:T]N:U  ΦΓL:T  ΦΓM:TΦΓM.𝚏𝚍U,L(x:T.N):U
ΦΓ0T:T  ΦΓM:T  ΦΓN:TΦΓM+TN:T

We may write ΓM:T (or M:T) instead of ΦΓM:T if M has no free ordinary (or function) variables (and similarly for boolean terms). Typing is unique: for any Γ, Φ, and M there is at most one type T such that ΦΓM:T holds.

As an example, we use our language to program a miniature version of an algorithm for training a machine learning model by gradient descent, loosely based on (Goodfellow et al., 2016, Algorithm 8.1). In such training, one often starts with an untrained model, which is a function from inputs (for example, images) and parameter values to output “predictions” (for example, image labels). Relying on a dataset of input/output pairs, one then picks values of the parameters by gradient descent, as indicated in the Introduction. In our miniature version, we treat inputs, parameter values, and outputs as reals, and we assume that the training data consists of only one fixed input/output pair (a,b). We also assume that we have real constants w0 (for the initial value for gradient descent), 𝑟𝑎𝑡𝑒 (for the learning rate, which is fixed) and 𝑚𝑎𝑥𝐿𝑜𝑠𝑠 (for the desired maximum loss on the dataset), and the infix predicate symbol <˙. We can then define the trained model from the untrained model and a loss function as follows:

𝚕𝚎𝚝𝑚𝑦𝑇𝑟𝑎𝑖𝑛𝑒𝑑𝑀𝑜𝑑𝑒𝑙(x:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚕𝚎𝚝𝑐𝑢𝑟𝑟𝑒𝑛𝑡𝐿𝑜𝑠𝑠(w:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝑚𝑦𝐿𝑜𝑠𝑠(b,𝑚𝑦𝑈𝑛𝑡𝑟𝑎𝑖𝑛𝑒𝑑𝑀𝑜𝑑𝑒𝑙(a,w))𝚒𝚗𝚕𝚎𝚝𝑔𝑟𝑎𝑑𝐿𝑜𝑠𝑠(w:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚐𝚛𝚊𝚍w(w:𝚛𝚎𝚊𝚕.𝑐𝑢𝑟𝑟𝑒𝑛𝑡𝐿𝑜𝑠𝑠(w))𝚒𝚗𝚕𝚎𝚝𝚛𝚎𝚌𝑑𝑒𝑠𝑐𝑒𝑛𝑑(w:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕=𝚒𝚏𝑐𝑢𝑟𝑟𝑒𝑛𝑡𝐿𝑜𝑠𝑠(w)<˙c𝚝𝚑𝚎𝚗w𝚎𝚕𝚜𝚎𝑑𝑒𝑠𝑐𝑒𝑛𝑑(w-𝑟𝑎𝑡𝑒*𝑔𝑟𝑎𝑑𝐿𝑜𝑠𝑠(w))𝚒𝚗𝑚𝑦𝑈𝑛𝑡𝑟𝑎𝑖𝑛𝑒𝑑𝑀𝑜𝑑𝑒𝑙(x,𝑑𝑒𝑠𝑐𝑒𝑛𝑑(w0))𝚒𝚗

The example above is typical of what can be expressed in our language, and many variants of machine learning techniques that rely on gradient descent (e.g., of the kind presented in  (Goodfellow et al., 2016), and commonly used in systems like TensorFlow) are in scope as well. For instance, there is no difficulty in expressing optimization with momentum, or differentially private stochastic gradient descent (e.g., (Song et al., 2013; Abadi et al., 2016b)). Probabilistic choice may be treated via random number generators, as is done in practice. Architectures that rely on convolutions or RNN cells can be expressed, even conveniently, with a suitable choice of primitives.

3. Operational semantics

We give a big-step operational semantics, specified with Felleisen and Friedman’s method (Felleisen and Friedman, 1987) using evaluation contexts and redexes. Other styles of operational semantics accommodating differentiation are surely also possible.

Terms and boolean terms are (ordinarily) evaluated to closed values and (necessarily) closed boolean values. The most original aspect of our operational semantics concerns the evaluation of differential terms; this is based on the trace-based approach outlined in the Introduction, and uses a second mode of evaluation: symbolic evaluation.

The core idea is that to evaluate a differential term

M.𝚛𝚍L(x:T.N)

one first evaluates L and M, and then performs differentiation before evaluating further. There are two differentiation stages. First, using the closed value V of L for the differentiation variable x, N is symbolically evaluated to a trace term C, thereby removing all control constructs from N, but possibly keeping the variable x free in C, as the derivative may well depend on it. For example, when N is 𝚒𝚏x<˙0𝚝𝚑𝚎𝚗 0𝚎𝚕𝚜𝚎x, the value V allows us to evaluate the guard of the conditional, but we do not replace the occurrence of x in the 𝚎𝚕𝚜𝚎 branch with V. Second, C is symbolically differentiated at V with respect to x.

However, this idea is not enough by itself as the differential term may occur inside yet another differential term. One therefore also needs to be able to symbolically evaluate the differential term. That is done much as in the case of ordinary evaluation, but now symbolically evaluating redexes in L and M until one is left with the problem of symbolically evaluating a term of the form

W.𝚛𝚍V(x:T.N)

where V and W are values that may contain free variables. One then proceeds as above, symbolically evaluating N (now using the closed value V of V) and then performing symbolic differentiation. As there is some duplication between these two symbolic and ordinary evaluation processes, our rule for ordinarily evaluating a differential term is designed, when executed, to first symbolically evaluate the term, and then ordinarily evaluate the resulting trace term.

The need to keep track of differentiation variables and their values for symbolic evaluation leads us to use value environments for ordinary variables. It is convenient to also use them for ordinary evaluation and to use function environments for function variables for both modes of evaluation.

Values V,W,X, are terms given by the grammar:

V::=xr(r)V,WT,U

Note that, as indicated above, values may have free variables for the purposes of differentiation. Boolean values V𝚋𝚘𝚘𝚕 are boolean terms given by:

V𝚋𝚘𝚘𝚕::=𝚝𝚛𝚞𝚎𝚏𝚊𝚕𝚜𝚎

Closed values have unique types V:TV; the set of closed values of type T is ValT; and the set of boolean values is Val𝚋𝚘𝚘𝚕. We assume available operation and predicate symbol evaluation functions

ev:OpT,U×ValTValU   bev:PredT×ValTVal𝚋𝚘𝚘𝚕

We also assume that for every operator op of arity TU there is an operator opr of arity T×UT. The idea is that opr(L,M) is the reverse-mode derivative of op at L evaluated at M. We write M.opr(L) for opr(L,M). For example, for 𝐷𝑃𝑟𝑜𝑑2 we would have:

ev(𝐷𝑃𝑟𝑜𝑑2,a,b,a,b)=aa+bb

and

ev((𝐷𝑃𝑟𝑜𝑑2)r,a,b,a,b,c)=ca,cb,ca,cb

We next define (value) environments ρ, function environments φ, and (recursive function) closures Cl, the last two mutually recursively:

  • -

    Value environments are finite functions

    ρ={x0V0,,xn-1Vn-1}

    from ordinary variables to closed values.

  • -

    Every finite function

    φ={f0Cl0,,fn-1Cln-1}

    from function variables to closures is a function environment.

  • -

    If FV(M){x} and FFV(M)\{f}Dom(φ) then φ,f,x,T,U,M is a closure, written 𝐜𝐥𝐨φ(f(x:T):U.M).

For any V and ρ with FV(V)Dom(ρ), ρ(V) is the closed value obtained by substituting ρ(x) for all free occurrences of x in V.

Trace terms C,D,, are defined as follows:

C::=xr(r)C+Dop(C)𝚕𝚎𝚝x:T=C𝚒𝚗DC,DT,U𝚏𝚜𝚝T,U(C)𝚜𝚗𝚍T,U(C)

They are the terms with no conditionals, function definitions or applications, or differentiations.

We will define two ordinary evaluation relations, and one symbolic one:

  • For all φ and ρ we define evaluation relations between terms and closed values and between boolean terms and closed boolean values via rules establishing sequents of the forms:

    φρMV   φρBV𝚋𝚘𝚘𝚕
  • For all φ and ρ we define a symbolic evaluation relation between terms and trace terms via rules establishing sequents of the form:

    φρMC

Evaluation contexts (boolean evaluation contexts), ranged over by E (resp. E𝚋𝚘𝚘𝚕 ), are terms with a unique hole [] :

E::=[]E+NV+Eop(E)𝚕𝚎𝚝x:T=E𝚒𝚗NE,NT,UV,ET,U𝚏𝚜𝚝T,U(E)𝚜𝚗𝚍T,U(E)𝚒𝚏E𝚋𝚘𝚘𝚕𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎Nf(E)M.𝚛𝚍E(x:T.N)E.𝚛𝚍V(x:T.N)E𝚋𝚘𝚘𝚕::=pred(E)

We write E[M] for the term obtained by replacing the hole [] in E by the term M and Ebool[M] similarly; a context E is trivial if it is []; and FV and FFV are extended to contexts. We have FV(E[M])=FV(E)FV(M) and FFV(E[M])=FFV(E)FFV(M) and similarly for boolean contexts.

Redexes, ranged over by R, and boolean redexes, ranged over by Rbool, are given by:

R::=V+Wop(V)𝚕𝚎𝚝x:T=V𝚒𝚗N𝚏𝚜𝚝T,U(V)𝚜𝚗𝚍T,U(V)𝚒𝚏V𝚋𝚘𝚘𝚕𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎N𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗Nf(V)W.𝚛𝚍V(x:T.N)R𝚋𝚘𝚘𝚕::=pred(V)

Note that boolean expressions are useful here in that they enable separate conditional and predicate redexes, and so evaluating predicates and making choices are distinct in the operational semantics.

The next lemma is the basis of a division into cases that supports operational semantics using evaluation contexts in the style of Felleisen and Friedman.

Lemma 3.1 (Evaluation context analysis).
  1. (1)

    Every term M, other than a value, has exactly one of the following two forms:

    • E[R] for a unique evaluation context and redex, or

    • E[R𝚋𝚘𝚘𝚕] for a unique, and non-trivial, evaluation context and boolean redex.

  2. (2)

    Every boolean term B, other than a boolean value, has exactly one of the following two forms:

    • Ebool[R] for a unique, and non-trivial, boolean evaluation context and redex, or

    • Ebool[R𝚋𝚘𝚘𝚕] for a unique boolean evaluation context and boolean redex.

The next lemma is useful to track types when proving theorems about the operational semantics.

Lemma 3.2 (Evaluation context polymorphism).

Suppose that ΦΓE[M]:T. Then, for some type U we have ΦΓM:U and, whenever ΦΓN:U, we have ΦΓE[N]:T.

Analogous results hold for typings of any of the forms ΦΓE[B]:T or ΦΓEbool[M] or ΦΓEbool[B].

By the uniqueness of types, the types whose existence is claimed in the above lemma are unique.

φρVρ(V)φρVrφρWsφρV+Wt(where t=r+s)φρVVφρop(V)W(where ev(op,V)W)φρVVφρ[V/x]NWφρ𝚕𝚎𝚝x:T=V𝚒𝚗NWφρVW1,W2T,Uφρ𝚏𝚜𝚝T,U(V)W1φρVW1,W2T,Uφρ𝚜𝚗𝚍T,U(V)W2
φρMVφρ𝚒𝚏𝚝𝚛𝚞𝚎𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎NVφρNVφρ𝚒𝚏𝚏𝚊𝚕𝚜𝚎𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎NVφ[𝐜𝐥𝐨φ(f(x:T):U.M)/f]ρNVφρ𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗NVφρVVφ[φ(f)/f]{xV}MWφρf(V)W(where φ(f)=𝐜𝐥𝐨φ(f(x:T):U.M))φρW.𝚛𝚍V(x:T.N)CφρCXφρW.𝚛𝚍V(x:T.N)XφρVVφρpred(V)W𝚋𝚘𝚘𝚕(where bev(pred,V)W𝚋𝚘𝚘𝚕)
Figure 2. Ordinary operational semantics: values and redexes
φρRVφρ[V/x]E[x]WφρE[R]W  (E nontrivial, xDom(ρ))φρR𝚋𝚘𝚘𝚕V𝚋𝚘𝚘𝚕φρE[V𝚋𝚘𝚘𝚕]WφρE[R𝚋𝚘𝚘𝚕]WφρRVφρ[V/x]E𝚋𝚘𝚘𝚕[x]W𝚋𝚘𝚘𝚕φρE𝚋𝚘𝚘𝚕[R]W𝚋𝚘𝚘𝚕  (xDom(ρ))φρR𝚋𝚘𝚘𝚕V𝚋𝚘𝚘𝚕φρE𝚋𝚘𝚘𝚕[V𝚋𝚘𝚘𝚕]W𝚋𝚘𝚘𝚕φρE𝚋𝚘𝚘𝚕[R𝚋𝚘𝚘𝚕]W𝚋𝚘𝚘𝚕
Figure 3. Ordinary operational semantics: contexts
φρVVφρV+WV+Wφρop(V)op(V)φρVVφρ[V/x]NCφρ𝚕𝚎𝚝x:T=V𝚒𝚗N𝚕𝚎𝚝x:T=V𝚒𝚗Cφρ𝚏𝚜𝚝T,U(V)𝚏𝚜𝚝T,U(V)φρ𝚜𝚗𝚍T,U(V)𝚜𝚗𝚍T,U(V)
φρMCφρ𝚒𝚏𝚝𝚛𝚞𝚎𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎NCφρNCφρ𝚒𝚏𝚏𝚊𝚕𝚜𝚎𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎NCφ[𝐜𝐥𝐨φ(f(x:T):U.M)/f]ρNCφρ𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗NCφρVVφ[φ(f)/f]{xV}MCφρf(V)𝚕𝚎𝚝x:T=V𝚒𝚗C(where φ(f)=𝐜𝐥𝐨φ(f(x:T):U.M))φρVVφρ[V/x]NCφρW.𝚛𝚍V(x:T.N)W.V(x:T.C)
Figure 4. Symbolic operational semantics: values and redexes
φρRCφρCVφρ[V/x]E[x]DφρE[R]𝚕𝚎𝚝x:TV=C𝚒𝚗D(E nontrivial and xDom(ρ))φρR𝚋𝚘𝚘𝚕V𝚋𝚘𝚘𝚕φρE[V𝚋𝚘𝚘𝚕]CφρE[R𝚋𝚘𝚘𝚕]C
Figure 5. Symbolic operational semantics: contexts
W.V(x:T.y)={(0T0,,0Ti-1,W,0Ti+1,,0Tn-1)(y=xi)0T(yany xi)W.V(x:T.r)=0T  (r)W.V(x:T.D+E)=W.V(x:T.D)+TW.V(x:T.E)W.V(x:T.op(D))=𝚕𝚎𝚝x:T=V𝚒𝚗𝚕𝚎𝚝y:S=W.opr(D)𝚒𝚗y.V(x:T.D)(yFV(V),op:SU)W.V(x:T.𝚕𝚎𝚝y:S=D𝚒𝚗E)=𝚕𝚎𝚝x:T=V𝚒𝚗𝚕𝚎𝚝y:S=D𝚒𝚗W.V(x:T.E)+T(𝚕𝚎𝚝y¯:S=W.y(y:S.E)𝚒𝚗y¯.V(x:T.D))(yFV(W),y,y¯FV(V,D))W.V(x:T.)=0TW.V(x:T.M,NU,S)=𝚕𝚎𝚝y:U,z:S=W𝚒𝚗y.V(x:T.M)+Tz.V(x:T.N)(y,zFV(V,M,N))W.V(x:T.𝚏𝚜𝚝U,S(D))=𝚕𝚎𝚝x:T=V𝚒𝚗𝚕𝚎𝚝y:U×S=D𝚒𝚗W,0S.V(x:T.D)(yFV(V,W,D))W.V(x:T.𝚜𝚗𝚍U,S(D))=𝚕𝚎𝚝x:T=V𝚒𝚗𝚕𝚎𝚝y:U×S=D𝚒𝚗0U,W.V(x:T.D)(yFV(V,W,D))
Figure 6. Definition of W.V(x:T.C)

The rules for ordinary evaluation are given in Figures 2 and 3; those for symbolic evaluation are given in Figures 4 and 5. The definitions are mutually recursive. They make use of the symbolic differentiation of trace terms: given a trace term C, and values V and W (not necessarily closed), we define a trace term

W.V(x:T.C)

intended to denote the reverse-mode derivative of the function x:TC, at V, evaluated at W. A definition is given in Figure 6; in the definition we assume that xFV(V,W), and, as is common, that all binding variables are different.

Proposition 3.3 ().

The following typing rule is admissible:

Γ[x:T]C:UΓV:TΓW:UΓW.V(x:T.C):T

In large part because of the restrictions on trace terms, their symbolic differentiation is just a systematic, formal application of the chain rule. In our setting, this application requires a fair amount of attention to detail, for instance the use of the type decorations when giving derivatives of pairing and projection terms.

The reader may wish to try the following two evaluation examples with nested differentiation:

1.𝚛𝚍1(x:𝚛𝚎𝚊𝚕.x× 1.𝚛𝚍1(y:𝚛𝚎𝚊𝚕.x+y))1

and

𝚕𝚎𝚝𝚛𝚎𝚌f(x:𝚛𝚎𝚊𝚕):𝚛𝚎𝚊𝚕= 1.𝚛𝚍1(y:𝚛𝚎𝚊𝚕.x+y)𝚒𝚗  1.𝚛𝚍1(x:𝚛𝚎𝚊𝚕.x+f(x))1

Examples of this kind can be used to illustrate perturbation confusion in forward differentiation, e.g., (Siskind and Pearlmutter, 2005, 2008).

We need some basic results on our evaluation relations. Two are standard: determinacy and type safety, and are used implicitly throughout the rest of the paper. The third connects symbolic and ordinary evaluation: one can interpolate symbolic evaluation within ordinary evaluation. It is principally helpful to reduce the completeness part of symbolic evaluation to the completeness of ordinary evaluation (see Theorem 6.7).

Proposition 3.4 (Determinacy of evaluation).

The following hold:

  1. (1)

    For any φ, ρ, and M, there is at most one value V s.t. φρMV.

  2. (2)

    For any φ, ρ, and M, there is at most one trace term C s.t. φρMC.

The following interpolation proposition establishes a certain consistency between the ordinary and symbolic evaluation relations.

Proposition 3.5 (Operational interpolation).

For all φ, ρ, and closed values V, the following are equivalent:

  • (1)

    φρMV,

  • (2)

    φρMC and φρCV, for some C.

For a type safety theorem, we need typing judgments ρ:Γ, φ:Φ, and Cl:TU for environments, function environments, and closures (implicitly extending the notion of type). These are defined inductively by the following rules:

Vi:Ti(i=0,n-1){,xiVi,}:,xi:Ti,
Cli:TiUi(i=0,n-1){,fiCli,}:,fi:TiUi,
φ:ΦΦ[TU/f],x:TM:U𝐜𝐥𝐨φ(f(x:T):U.M):TU

Unique typing extends to environments, to function environments, and to closures (indeed, a closure 𝐜𝐥𝐨φ(f(x:T):U.M) can only have type TU).

Proposition 3.6 (Type safety).

Suppose ΦΓM:T, φ:Φ and ρ:Γ. Then we have:

φρMVV:T

and

φρMCΓC:T

4. Mathematical preliminaries

We now turn to the mathematical facts needed for the denotational semantics of our language. These concern the two modes of differentiation and their interaction with domain theory. We follow (Abramsky and Jung, 1994) for domain theory, but write dcppo for pointed dcpo, and say a partial order is coherent iff every compatible subset has a lub. (A subset is compatible if any two of its elements have an upper bound.) Every coherent partial order is a dcppo.

The collection of partial functions f:XY with open domain between two topological spaces forms a partial order under graph inclusion:

fgfg

equivalently, using the Kleene order 22 2 We write ee for two mathematical expressions e and e to mean that if e is defined so is e, and they are then equal.:

fg𝐱X.f𝐱g𝐱

This partial order is a coherent dcppo with the everywhere undefined function and compatible sups given by unions. A partial function f:XY is continuous if f-1(B) is open whenever B is; the subcollection of continuous partial functions forms a coherent subdcppo. This holds as, for any open set BY and compatible collection of partial functions fi(iI):XY, we have:

(iIfi)-1(B)=iIfi-1(B)

We write 𝒞[X,Y] for the dcppo of partial continuous functions from X to Y.

It is convenient to use a variation on cartesian product when working with powers of . We set:

m×˙n=defm+n(m,n0)

This version of product is associative. Vector concatenation then serves as tupling; however, for clarity, we may use the usual notation (𝐱0,,𝐱k-1) instead of 𝐱0𝐱k-1. There are evident definitions of the projections πim0,,mk-1:m0×˙×˙mk-1mi, and of the tupling

f0,,fk-1:nm0×˙×˙mk-1

of fi:nmi. We may ignore the superscripts on the projections when they can be understood from the context.

4.1. Continuity, differentiability, and smoothness

Standard multivariate analysis of vector-valued real functions from n to m (with n,m>0) considers functions f defined on an open domain of n, see, e.g., (Trench, 2003). These are precisely the partial functions:

f:nm(n,m>0)

with open domain.

When m=1, such a function f has partial derivatives

j(f):n  (j=0,n-1)

where

j(f)(x0,,xn-1)deffxj

viewing f as a function of x0,,xn-1. Taken together, these partial derivatives form its gradient

(f):nn

where

(1) (f)(𝐱)0(f)(𝐱),,n-1(f)(𝐱)

We write 𝐱(f) for (f)(𝐱).

We say f is continuously differentiable if all the j(f) are continuous with domain that of f, equivalently if (f) is continuous with domain that of f. As an example, removing 0 from the domain of definition of the non-differentiable ReLU function f(x)=max(x,0), we obtain a continuously differentiable partial function with domain \0; its derivative also has domain \0, with value 0, if x<0, and 1, if x>0.

We now turn to the general case where f:nm. The Jacobian J𝐱(f) of f at 𝐱n is the m by n matrix:

(2) J𝐱(f)i,jj(πif)(𝐱)

where the matrix is undefined if any of the j(πif)(𝐱) are. These Jacobians form a partial function:

J(f):nMat(m,n)

where Mat(m,n) is the collection of m by n matrices. Viewing Mat(m,n) as m×n, we say f is continuously differentiable if J(f) is continuous and has the same domain as f (equivalently if each component πif of f is continuously differentiable).

The differential 33 3 Differentials are discussed in (Trench, 2003) see: p325 for differentials of functions of several variables; p348 for higher-order differentials; p381 for differentials of vector-valued functions of several variables; and p388 for the chain rule in differential terms.

d(f):n×˙nm

of f is defined by:

(3) d(f)(𝐱,𝐲)J𝐱(f)𝐲

and f is continuously differentiable iff d(f) has domain Dom(f)×n and is continuous there.

We write d𝐱(f) for the partial function d(f)(𝐱,-); it is either or everywhere defined and linear, the latter occurring precisely when J𝐱(f) is defined. If f is linear then d𝐱f=f, for all 𝐱n.

In the automatic differentiation literature, d𝐱(f) is called the forward-mode derivative of f at 𝐱. For the reverse-mode derivative we define:

dr(f):n×˙mn

by:

(4) dr(f)(𝐱,𝐲)J𝐱(f)t𝐲

and write d𝐱r(f) for the partial function dr(f)(𝐱,-); f is continuously differentiable iff dr(f) has domain Dom(f)×m and is continuous there.

In terms of the differentials, the two modes are related by:

(5) d𝐱r(f)=d𝐱(f)

(setting =). So, if f is linear, then d𝐱r(f)=d𝐱(f)=f.

The semantic content of the definition of forward-mode from reverse-mode given in Section 2 is the following equality:

(6) d𝐱f=d𝟎R(d𝐱Rf)

This holds as: d𝟎R(d𝐱Rf)=(d𝐱Rf)=((d𝐱f))=d𝐱f (the first equality holds as d𝐱Rf is linear if ).

The continuously differentiable functions are closed under composition. If h:nl is the composition of two such functions f:nm and g:ml, then the chain rule expresses the derivative of h in terms of those of f and g. In terms of Jacobians, the chain rule is:

J𝐱(h)Jf(𝐱)(g)J𝐱(f)(𝐱Dom(h))

(Note that 𝐱Dom(h) iff 𝐱Dom(f) and f(𝐱)Dom(g).) In terms of forward-mode derivatives the chain rule is:

(7) d𝐱(h)=df(𝐱)(g)d𝐱(f)(𝐱Dom(h))

and in terms of reverse-mode derivatives it is:

(8) d𝐱r(h)=d𝐱r(f)df(𝐱)r(g)(𝐱Dom(h))

Derivatives with respect to two variables can be reduced to derivatives in each separately. Specifically suppose f:n+nm. Then, for 𝐱n and 𝐲n, we have:

(9) d𝐱,𝐲(f)=d𝐱(f(-,𝐲))+d𝐲(f(𝐱,-))

and

(10) d𝐱,𝐲R(f)=d𝐱R(f(-,𝐲)),d𝐲R(f(𝐱,-))

These equations are useful for dealing with fan-in.

Our programming language has all finite product types of the reals. We will therefore need to work with partial functions with open domain f:nm where n or m is zero. To this end we regard 0 as having as sole element the empty vector, the trivial topology, and the trivial vector space structure. Every such total function is linear, and this determines its adjoint.

We take such a function f:nm, where n or m is zero, to be continuously differentiable if it is continuous, and we define d(f):n×˙nm and dr(f):n×˙mn by:

d(f)(𝐱,𝐲){0(f(𝐱))(otherwise)  dr(f)(𝐱,𝐲){0(f(𝐱))(otherwise)

The derivative d(f) has domain Dom(f)×n and is continuous (and so continuously differentiable) iff f is, and a similar remark applies to dr(f). We understand d𝐱(f) and d𝐱r(f) similarly to before. In case f is linear (i.e., total) we have d𝐱(f)=f and d𝐱r(f)=f as before and equation (5) relating the two modes continues to hold, as does equation (6) and also equations (10) and (9) concerning derivatives with respect to two variables. In particular for t:n0 we have:

(d𝐱t)𝐱=  (d𝐱rt)=𝟎

Regarding compositions we note a useful fact:

Fact 1 ().

If h:RnRl(l,n0) is constant on its domain, then it is continuously differentiable iff it is continuous and then, for any x in its domain, dx(h) is the constantly 0 function, as is dxr(h).

It follows that the continuously differentiable functions, if taken in our wider sense, remain closed under composition and pointwise addition, and that the chain rule for forward derivatives continues to hold, as does that for reverse derivatives. From now on whenever we consider partial functions from an n to an m, we include the cases where n or m is 0.

The projections πim0,,mk-1:m0×˙×˙mk-1mi are total linear functions, so we have:

d𝐱πim0,,mk-1=πim0,,mk-1(d𝐱rπim0,,mk-1)𝐲=(0,,0,𝐲,0,,0)

Regarding the tupling f0,,fk-1:nm0×˙×˙mk-1 of fi:nmi we have:

d𝐱f0,,fk-1=d𝐱f0,,d𝐱fk-1(d𝐱rf0,,fk-1)(𝐲0,,𝐲k-1)(d𝐱rf0)𝐲0++(d𝐱rfk-1)𝐲k-1

For the semantics of our language we work with infinitely differentiable functions, i.e., smooth ones. First we define smoothness classes Ck. We say that a partial function f:nm is C0 if it is continuous, and, inductively, is Ck+1 if d(f) has domain Dom(f)×n and is Ck. This defines a decreasing sequence of classes of functions, and we say that f is smooth or C if it is Ck for all k. The C1 functions are precisely the continuously differentiable ones. Using the chain rule for differentials one shows that the Ck functions, and so too the smooth ones, are closed under composition. The projections are smooth, as are all linear functions and the Ck functions, and so too the smooth ones, are closed under tupling.

4.2. Cppos of differentiable functions

The subgraph partial order on partial functions between powers of interacts well with the differential structure. We have:

Proposition 4.1 ().
  1. (1)

    For any fg:nm with open domain we have:

    df=(dg)(Dom(f)×n)  drf=(drg)(Dom(f)×m)
  2. (2)

    For any compatible family of functions with open domain fi:nm(iI), we have:

    diIfi=iIdfi    driIfi=iIdrfi
Proof.

For the first part, if m or n is 0, the conclusion is immediate using Fact 1. Otherwise, as f and g agree on. an open set including x we have:

J𝐱(f)J𝐱(g)

and the conclusion follows. For the second part, set f=fi. For the forward-mode derivative, using the first part we calculate:

df=df(Dom(f)×n)=dfiI(Dom(fi)×n)=iIdf(Dom(fi)×n)=iIdfi

The proof for the reverse-mode derivative is similar.

Proposition 4.2 ().
  1. (1)

    Let fg:nm be partial functions with open domain. Then f is smooth if g is.

  2. (2)

    Let fi:nm be a compatible family of partial functions with open domain, and with sup f. Then f is smooth if all the fi are.

Proof.

For the first part, we prove by induction that if g is Ck then so is f. For k=0 we note that for any open Vm, f-1(V)=g-1(V)Dom(f). For k+1, as g is Ck+1, Dom(dg)=Dom(g)×n and dg is Ck. From part (1) of Proposition 4.1 we have dfdg and Dom(df)=Dom(f)×n. So df and dg have open domain, dfdg, and dg is Ck. It follows from the induction hypothesis that df is Ck. So f is Ck+1, as required.

For the second part we prove, by induction on k that if all the fi are Ck, then so is f. For k=0 this is clear. For k+1, we have, for all i, that Dom(dfi)=Dom(fi)×n and fi is Ck. From part (2) of Proposition 4.1 we have df=idfi. So, first,

Dom(df)=Dom(idfi)=iDom(dfi)=iDom(fi)×n=Dom(f)×n

and second, also using the induction hypothesis, we have that df is Ck. So f is Ck+1, as required.  ∎

We write 𝒮[n,m] for the coherent dcppo of smooth partial functions between n and m.

4.3. Conditionals and recursion

Differentiation and conditionals interact well. The conditional combinator Condn,m is defined for p:Rn𝕋 and f,g:Rnm by:

Condn,m(p,f,g)(𝐱){f(𝐱)(p(𝐱)=tt)g(𝐱)(p(𝐱)=ff)(otherwise)

where 𝕋={tt,ff}. The conditional combinator is continuous. For differentiability, with 𝕋 a discrete topological space, we have:

Proposition 4.3 ().

Suppose p is continuous (equivalently: both p-1(tt) and p-1(ff) are open). Then:

d(Condn,m(p,f,g))=Cond(n+n),m(pπ1,df,dg)

and

dr(Condn,m(p,f,g))=Cond(n+m),n(pπ1,drf,drg)

Further, if f,g are smooth so is Condn,m(p,f,g).

Proof.

Assume that p is continuous. Set h=Condn,m(p,f,g). The domain of h is open, indeed Dom(h)=(p-1(tt)Dom(f))(p-1(ff)Dom(g)) so dh is defined.

To prove the equality, choose 𝐱n. There are three cases. First, if p(𝐱) then h(𝐱) and so (dh)(𝐱); the equality therefore holds at 𝐱. Second if p(𝐱)=tt then, as hp-1(tt)=fp-1(tt) and p-1(tt) is open, we see that, by part (1) of Proposition 4.1, d𝐱h=d𝐱hp-1(tt)=d𝐱fp-1(tt)=d𝐱f, and so the equality again holds at 𝐱. The third case is similar to the second.

Suppose further that f,g are smooth. We have hp-1(tt)f, and so, by part (1) of Proposition 4.2, hp-1(tt) is smooth as f is and hp-1(tt) has open domain. Similarly hp-1(ff) is smooth. But then, by part (2) of Proposition 4.2, h is smooth as h=hp-1(𝚝𝚛𝚞𝚎)hp-1(ff). ∎

In less formal terms than the proof, equality holds because if, say, the condition p holds at 𝐱n, it holds in a neighborhood O of 𝐱. So f and the conditional are equal throughout O, and therefore have the same derivative there. The equality justifies the approaches to the differentiation of conditionals described in the Introduction.

Differentiation and recursion also interact well. For any continuous f:P×QQ (P a dcpo, Q a dcppo) we write μy:Q.f(x,y) for the least fixed-point (l.f.p.) of f(x,-). It is the sup of the iterates μny:Q.f(x,y), defined inductively by:

μn+1y:Q.f(x,y)=f(x,μny:Q.f(x,y))

starting from Q. As functions of P, the l.f.p. and the iterates are continuous. When f:QQ, we write μy:Q.f(y), etc.

Proposition 4.4 ().
  1. (1)

    Set Q=𝒮[m,l] and R=𝒮[m×˙m,l]. Then if F:n×QQ and G:n×Q×RR are such that

    dF(x,f)=G(x,f,df)(xn,fQ)

    we have:

    d(μf:Q.F(x,f))=μf:R.G(x,μf:Q.F(x,f),f)
  2. (2)

    Set Q=𝒮[m,l] and R=𝒮[m×˙l,m]. Then if F:n×QQ and
    G:n×Q×RR are such that

    drF(x,f)=G(x,f,drf)(xn,fQ)

    we have:

    dr(μf:Q.F(x,f))=μf:R.G(x,μf:Q.F(x,f),f)
Proof.

We only consider the forward-mode case as the reverse-mode case is similar. In one direction we prove by induction on n that

d(μnf:Q.F(x,f))μf:R.G(x,μf:Q.F(x,f),f)

This is evident for n=0. For n+1 we calculate (missing out types):

d(μn+1f.F(x,f))=d(F(x,μnf.F(x,f)))=G(x,μnf.F(x,f),dμnf.F(x,f))G(x,μf.F(x,f),μf.G(x,μf.F(x,f),f))=μf.G(x,μf.F(x,f),f)

In the other direction we prove by induction on n that

μnf:R.G(x,μf:Q.F(x,f),f)d(μf:Q.F(x,f))

This is evident for n=0. For n+1 we calculate:

μn+1f.G(x,μf.F(x,f),f)=G(x,μf.F(x,f),μnf.G(x,μf.F(x,f),f))G(x,μf.F(x,f),dμf.F(x,f))=dF(x,μf.F(x,f))=d(μf.F(x,f))

The conclusion then follows using the continuity of d (Part 2 of Proposition 4.1).

Although we do not do so here, this proposition can be used to justify code transformations of recursive function definitions.

5. Denotational semantics

We begin with a denotational semantics of types as powers of the reals:

[[𝚛𝚎𝚊𝚕]]=[[𝚞𝚗𝚒𝚝]]=0[[T×U]]=[[T]]×˙[[U]]

Note that [[T]]=|T|, where, |𝚛𝚎𝚊𝚕|=1, |𝚞𝚗𝚒𝚝|=0 and, recursively, |T×U|=|T|+|U|. Then, for the semantics of environments Γ=x0:T0,,xn-1:Tn-1 we set

[[Γ]]=[[T0]]×˙×˙[[Tn-1]]

and for that of function environments Φ=f0:T0Un,,fn-1:Tn-1Un-1 we set

[[Φ]]=𝒮[[[T0]],[[U0]]]××𝒮[[[Tn-1]],[[Un-1]]]

We use γ,δ to range over [[Γ]] and ϕ over [[Φ]].

The denotational semantics of terms ΦΓM:T will be a continuous function:

[[Φ]][[ΦΓM:T]]𝒮[[[Γ]],[[T]]]

and that of boolean terms ΦΓB will be a continuous function:

[[Φ]][[ΦΓB]]𝒞[[[Γ]],𝕋]

When the environments and types are understood from the context, we may just write [[M]] or [[B]].

For the semantics of operation and predicate symbols, for every op:TU we assume available a smooth function [[op]]:[[T]][[U]] and for every pred:T a continuous function [[pred]]:[[T]]𝕋, such that:

(11) [[op]]([[V]])[[ev(op,V)]]

for every closed value V:T, and

(12) [[pred]]([[V]])[[bev(pred,V)]]

for every closed value V:T.

[[x]]ϕγγ(x)[[r]]ϕγr  (r)[[M+N]]ϕγ[[M]]ϕγ+[[N]]ϕγ[[op(M)]]ϕγ[[op]]([[M]]ϕγ)[[𝚕𝚎𝚝x:T=M𝚒𝚗N]]ϕγ[[N]]ϕ(γ[[[M]]ϕγ/x])[[]]ϕγ[[M,NT,U]]ϕγ[[M]]ϕγ,[[N]]ϕγ[[𝚏𝚜𝚝T,U(M)]]ϕγ[[π0]]([[M]]ϕγ)[[𝚜𝚗𝚍T,U(M)]]ϕγ[[π1]]([[M]]ϕγ)[[𝚒𝚏B𝚝𝚑𝚎𝚗M𝚎𝚕𝚜𝚎N]]ϕγ{[[M]]ϕγ([[B]]ϕγtt)[[N]]ϕγ([[B]]ϕγff)(otherwise)[[𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗N]]ϕγ[[N]](ϕ[μα:𝒮[[[T]],[[U]]].λa:[[T]].[[M]](ϕ[α/f]){xa}/f])γ[[f(M)]]ϕγϕ(f)([[M]]ϕγ)[[M.𝚛𝚍L(x:T.N)]]ϕγd[[L]]ϕγr(a[[T]][[N]]ϕ(γ[a/x]))([[M]]ϕγ)[[𝚝𝚛𝚞𝚎]]ϕγtt[[𝚏𝚊𝚕𝚜𝚎]]ϕγff[[pred(M)]]ϕγ[[pred]]([[M]]ϕγ)
Figure 7. Denotational semantics

The denotational semantics is given in Figure 7. Note that it uses the no-free-variable assumption in the clause for recursive functions. Apart from the semantics of reverse differentiation, which uses the reverse-mode derivative dr, it is quite standard. However, the facts that the denotations of terms carry smooth functions to smooth functions, and that the denotations of boolean terms carry smooth functions to continuous ones, use the mathematics developed in the previous section, particularly: the chain rule, e.g., for function application and let constructs; the preservation of smooth functions by the conditional combinator; the remarks on products; and, for recursive function definitions, the fact that the lub of an increasing sequence of smooth functions is smooth.

If a term M contains no function variables (or variables), [[M]]ϕγ is independent of ϕ (and γ), and we write [[M]]γ (resp., [[M]]) for it. Trace terms C have no function variables, and closed values V have no function variables or variables.

Using the semantics of terms, we can define the denotational semantics of value environments, function environments, and closures, the latter two by a mutual structural induction.

  • For every ρ:Γ, where ρ={x0V0,,xn-1Vn-1}, we define [[ρ:Γ]][[Γ]] by:

    [[ρ:Γ]]=([[V0]],,[[Vn-1]])
  • For every φ:Φ, where φ={f0Cl0,,fn-1Cln-1}, we define [[φ:Φ]][[Φ]] by:

    [[φ:Φ]]=([[Cl0]],,[[Cln-1]])
  • For every Cl=𝐜𝐥𝐨φ(f(x:T):U.M):TU we define [[Cl]]𝒮[[[T]],[[U]]] by:

    [[Cl]]=μα:𝒮[[[T]],[[U]]].λa:[[T]].[[M]]([[φ]][α/f]){xa}

We omit Γ and Φ from [[ρ:Γ]] and [[φ:Φ]] when they can be understood from the context.

Lemma 5.1 ().

For any type T we have:

  1. (1)

    The denotation [[V]] of any value V:T exists.

  2. (2)

    For any v[[T]] there is a unique value V:T such that v=[[V]].

The following two fairly standard results about evaluation contexts are needed to show adequacy.

Lemma 5.2 (Evaluation context compositionality).

Suppose ΦΓM:U, ΦΓE[M]:T, and ΦΓN:U. Then:

[[M]]ϕγ[[N]]ϕγ[[E[M]]]ϕγ[[E[N]]]ϕγ  (ϕ[[Φ]],γ[[Γ]])

Analogous results hold for: boolean terms in evaluation contexts, E[B]; terms in boolean evaluation contexts Ebool[M]; and boolean terms in boolean evaluation contexts Ebool[B].

Lemma 5.3 (Evaluation context strictness).
  1. (1)

    Suppose that ΦΓE[M]:T and ΦΓM:U. Then, for any  xFV(E), we have:

    [[E[M]]]ϕγ[[M]]ϕγ(ϕ[[Φ]],γ[[Γ]])

    and so:

    [[E[M]]]ϕγ[[E[x]]]ϕ(γ[[[M]]ϕγ/x])(ϕ[[Φ]],γ[[Γ]])

    The analogous result holds for terms in boolean contexts E𝚋𝚘𝚘𝚕[M].

  2. (2)

    Suppose that ΦΓE[B]:T and ΦΓB. Then:

    [[E[B]]]ϕγ[[B]]ϕγ(ϕ[[Φ]],γ[[Γ]])

    The analogous result holds for boolean terms in boolean contexts E𝚋𝚘𝚘𝚕[B].

6. Adequacy

We present our main results, on the correspondence between operational and denotational semantics. Taken together these are our adequacy theorems. As well as the usual correctness and completeness theorems, there are results peculiar to differentiation, both of interest in themselves and also necessary for the others. Theorem 6.1 shows the correctness of our source code transformation of trace terms, in that formal differentiation corresponds to actual differentiation. Theorem 6.2 has two parts. The first is the usual statement of correctness for the ordinary evaluation relation. The second is a statement of correctness of symbolic evaluation. This states that the trace term resulting from symbolic evaluation of a term has the same denotation not only at the environment used for the symbolic evaluation but on a whole open set including it. This, and Theorem 6.1, are needed to prove the ordinary correctness of the ordinary evaluation relation in the case of differentiation as in that case ordinary evaluation proceeds by first symbolically differentiating and then applying our source code transformation. Finally Theorem 6.7 is the expected completeness theorem, that if the semantics of a term is defined, then both its ordinary and symbolic evaluation terminate. Its proof makes use of Proposition 3.5 which interpolates a symbolic evaluation inside any ordinary (non-boolean) evaluation.

6.1. Operational correctness

Theorem 6.1 (Reverse-mode differentiation).

Suppose that Γ[x:T]C:U, ΓV:T and ΓW:U (and so ΓW.rdV(x:T.C):T). Then, for any γ[[Γ]], we have:

[[W.V(x:T.C)]]γ[[W.𝚛𝚍V(x:T.C)]]γ
Proof.

The proof is by structural induction on C. We give a representative case. Suppose C is 𝚕𝚎𝚝y:U=D𝚒𝚗E. Set γa=γ[a/x], for any a[[T]], γV=γ[[V]]γ, and γ=γV[[[D]]γV/y]. Then

[[W.V(x:T.C)]]γ[[W.V(x:T.E)+T(𝚕𝚎𝚝y¯:S=W.y(y:S.E)𝚒𝚗y¯.V(x:T.D))]]γ

with xFV(V,W), yFV(W), and y,y¯FV(V,D). We calculate:

d[[V]]γr(a[[T]][[𝚕𝚎𝚝y:U=D𝚒𝚗E]]γa)[[W]]γd[[V]]γr(a[[T]][[E]]γa[[[D]]γa/y])[[W]]γd[[V]]γr((c[[T×U]][[E]]γπ0(c)[π1(c)/y])a[[T]]a,a[[T]][[D]]γa)[[W]]γd[[V]]γr(a[[T]]a,a[[T]][[D]]γa)[(d[[V]]γ,[[D]]γVr(c[[T×U]][[E]]γπ0(c)[π1(c)/y]))[[W]]γ]d[[V]]γr(a[[T]]a,a[[T]][[D]]γa)[d[[V]]γr(a[[T]][[E]]γa[[[D]]γV/y]),d[[D]]γVr(b[[U]][[E]]γ[[V]]γ[b/y])[[W]]γ]d[[V]]γr(a[[T]]a,a[[T]][[D]]γa)[d[[V]]γr(a[[T]][[E]]γa[[[D]]γV/y])[[W]]γ,d[[D]]γVr(b[[U]][[E]]γ[[V]]γ[b/y])[[W]]γ]d[[V]]γr(a[[T]]a)[d[[V]]γr(a[[T]][[E]]γa[[[D]]γV/y])[[W]]γ]+d[[V]]γr(a[[T]][[D]]γ)[d[[D]]γVr(b[[U]][[E]]γ[[V]]γ[b/y])[[W]]γ]d[[V]]γr(a[[T]][[E]]γa[[[D]]γV/y])[[W]]γ+d[[V]]γr(a[[T]][[D]]γ)[d[[D]]γVr(b[[U]][[E]]γ[[V]]γ[b/y])[[W]]γ][[W.V(x:T.E)+T(𝚕𝚎𝚝y¯:S=W.y(y:S.E)𝚒𝚗y¯.V(x:T.D))]]γ

Note the use of Equation (10) in the the fourth step. ∎

Theorem 6.2 (Operational correctness).

Suppose that ΦΓM:T, φ:Φ, and ρ:Γ. Then:

  1. (1)

    Operational semantics.

    φρMV[[M]][[φ]][[ρ]]=[[V]]

    (and similarly for boolean terms).

  2. (2)

    Symbolic operational semantics.

    φρMCO𝑜𝑝𝑒𝑛[[Γ]].[[ρ]]OγO.[[M]][[φ]]γ[[C]]γ
Proof.

The two parts are proved by mutual induction on the size of the proofs that establish the given operational relations, and by cases on the form of M. As an example case of the second part, suppose M has the form 𝚕𝚎𝚝x:T=V𝚒𝚗L. Then for some D and V we have a smaller proof of φρ[V/x]LD, where V=ρ(V), and C has the form 𝚕𝚎𝚝x:T=V𝚒𝚗D.

By the induction hypothesis there is an open set O such that [[ρ[V/x]]]O and, for all δO, we have [[L]][[φ]]δ[[D]]δ. Set θ(γ)=[[Γ]]γ[[[V]]γ/x]. As θ is continuous, O=defθ-1(O) is open. We show it is the required open set.

  • -

    First, [[ρ]]O as we have: θ([[ρ]])=[[ρ]][[[V]][[ρ]]/x]=[[ρ]][[[V]]/x]=[[ρ[V/x]]]O.

  • -

    Second, for any γO we have:

    [[𝚕𝚎𝚝x:T=V𝚒𝚗L]][[φ]]γ[[L]][[φ]]γ[[[V]]γ/x][[D]]γ[[[V]]γ/x][[𝚕𝚎𝚝x:T=V𝚒𝚗D]]γ

    with the second equality holding as θ(γ)O.

The following corollary shows that our strategy of first symbolically reducing to produce a trace term, then symbolically differentiating, is correct.

Corollary 6.3 ().

Suppose that ΦΓ[x:T]M:U, ΓV:T, and ΓW:U. Then, for any φ:Φ and ρ:Γ we have:

φρ[Vρ/x]MC[[W.𝚛𝚍V(x:T.M)]][[φ]][[ρ]][[W.𝚛𝚍V(x:T.C)]][[φ]][[ρ]]

6.2. Operational completeness

We turn to proving operational completeness, that the evaluation, or symbolic evaluation, of a term terminates when it should, i.e., when its denotation is defined. For terms M write φρM when, for some V, φρMV and, assuming φ and ρ known from the context, say that M terminates, and adopt similar terminology for boolean terms.

To prove operational completeness we use a standard strategy: first proving operational completeness for an auxiliary “approximation language” in which recursive definitions are replaced by approximations to them, which we call limited recursive definitions, and then lifting that result to the main language. Specifically we replace the syntactic form for recursive definitions by the family of syntactic forms:

𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M𝚒𝚗N  (n)

with the evident typing rule, and make analogous consequential changes in the various definitions.

In the definition of function environments and closures, the clause for closures becomes:

  • -

    If FFV(M)\{f}Dom(φ), FV(M){x}, and n, then

    n,φ,f,x,T,U,M

    is a closure, written as: 𝐜𝐥𝐨n,φ(f(x:T):U.M).

The limited recursive definition redexes are 𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M𝚒𝚗N; their evaluation rules are in Figure 8. There, and below, we write l for limited recursion language judgements.

φ[𝐜𝐥𝐨n,φ(f(x:T):U.M)/f]ρlNVφρl𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M𝚒𝚗NVφρlVVφ[𝐜𝐥𝐨n,φ(f(x:T):U.M)/f]{xV}lMWφρlf(V)Wwhere φ(f)=𝐜𝐥𝐨n+1,φ(f(x:T):U.M)φ[𝐜𝐥𝐨n,φ(f(x:T):U.M)/f]ρlNCφρl𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M𝚒𝚗NCφρlVVφ[𝐜𝐥𝐨n,φ(f(x:T):U.M)/f]{xV}lMCφρlf(V)Cwhere φ(f)=𝐜𝐥𝐨n+1,φ(f(x:T):U.M)
Figure 8. Operational semantics of bounded recursion

For the closure typing judgement Cl:TU we substitute:

lφ:ΦΦ,{xT}lM:Ul𝐜𝐥𝐨n,φ(f(x:T):U.M):TU

As regards the denotational semantics, the clause for limited recursive definitions is:

[[𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M𝚒𝚗N]](ϕ)(γ)[[N]](ϕ[μnα:𝒮[[[T]],[[U]]].λa:[[T]].[[M]](ϕ[α/f]){xa}/f])γ

The results for the operational and denotational semantics carry over to the restricted setting, and we refer to them in the same way as we do to the unrestricted versions.

Relating the two languages, the n-th approximant M(n) of a language term M is obtained by replacing every recursive definition in M by an n-limited one (similarly for boolean terms) and n-th approximants of closures and function environments are defined by structural recursion:

𝐜𝐥𝐨φ(f(x:T):U.M)(n)=𝐜𝐥𝐨n,φ(n)(f(x:T):U.M(n))
{,fiCli,}(n)={,fiCli(n),}

The terms M(n) can be defined by structural recursion; we just give one clause of the definition:

(𝚕𝚎𝚝𝚛𝚎𝚌f(x:T):U=M𝚒𝚗N)(n)=𝚕𝚎𝚝𝚛𝚎𝚌nf(x:T):U=M(n)𝚒𝚗N(n)

Approximation preserves typing judgments.

Termination is proved for the approximation language by structural induction via a suitable notion of computability.

  • -

    A closure

    l𝐜𝐥𝐨n,φ(f(x:T):U.M):TU

    is computable iff n=0 or n>0 and, for all lV:T we have:

    [[M]][[φ[𝐜𝐥𝐨n-1,φ(f(x:T):U.M)/f]]]{x[[V]]}φ[𝐜𝐥𝐨n-1,φ(f(x:T):U.M)/f]{xV}lM
  • -

    A function environment lφ:Φ is computable iff lφ(f):Φ(f) is a computable closure, for every fDom(φ).

  • -

    A term ΦΓlM:T is computable iff for every computable lφ:Φ and every lρ:Γ

    [[M]][[φ]][[ρ]]φ,ρlM

    (and similarly for boolean terms).

Strictly speaking, in the above we should say that it is the sequent ΦΓM:T that is computable and similarly for closures and function environments.

Lemma 6.4 ().
  1. (1)

    Every closure 𝐜𝐥𝐨n,φ(f(x:T):U.M):TU is computable.

  2. (2)

    Every function environment φ:Φ is computable.

  3. (3)

    Every well-typed term ΦΓM:T is computable.

  4. (4)

    Every well-typed boolean term ΦΓB is computable.

The next two lemmas enable us to lift completeness from the approximation language to the main one. The first lets us pass from semantic existence in the main language to semantic existence in the approximation language; the second allows us to pass in the opposite direction from termination in the approximation language to termination in the main one.

Lemma 6.5 ().

For any well-typed term M we have:

[[M]]=n[[M(n)]]

and similarly for boolean terms, closures and function environments.

Lemma 6.6 ().

For any well-typed term M we have:

φ(n)ρlM(n)VφρMV

and similarly for boolean terms.

Operational completeness follows straightforwardly from these three lemmas:

Theorem 6.7 (Operational completeness).

Suppose that ΦΓM:T, φ:Φ, and ρ:Γ, then:

  1. (1)

    Operational semantics.

    [[M]][[φ]][[ρ]]φρM

    (and similarly for boolean terms).

  2. (2)

    Symbolic operational semantics.

    [[M]][[φ]][[ρ]]C.φρMC
Proof.
  • (1)

    Suppose that [[M]][[φ]][[ρ]]. Then by Lemma 6.5 we have [[M(n)]][[φ(n)]][[ρ]], for some n. By Lemma 6.4, both M(n) and φ(n) are computable. So φ(n)ρM(n). But then, by Lemma 6.6, we have φρM, as required. The proof for boolean terms is similar.

  • (2)

    This follows from the first part and Proposition 3.5.

7. Discussion

There is much more to do on the theory of differentiable programming languages, even at a basic level; we briefly suggest some possibilities. Trace-based automatic differentiation systems generally work with A-normal forms, or equivalent structures. They also employ optimizations. For example, as mentioned in the Introduction, they may record auxiliary information in evaluation traces to reduce recomputation. Other automatic differentiation systems rely on code transformations for differentiation. It would be interesting to define and study such optimizations and alternative approaches, perhaps in the setting of our language.

Another direction of interest would be to deal with non-differentiable functions used in practice like ReLU or with non-smooth functions. For the former, one might use Clarke sub-gradients (Clarke, 1990), following (Di Gianantonio and Edalat, 2013) (the Clarke sub-gradient of ReLU at 0 is the interval [0,1]); for the latter, one may use Ck functions. Still another possible such direction of research would be to work with approximate reals, rather than reals, and to seek numerical accuracy theorems. Here it would be natural to work with Scott’s interval domain and, generalizing the Clarke sub-gradient, a domain-theoretic notion of sub-differentiation of functions over the interval domain, as discussed in (Edalat and Lieutier, 2004; Edalat and Maleki, 2018).

One would like results for richer languages, with a wider range of types or with computational effects. The problem then to be solved is how these additional features interact with differentiation. An extension to side-effects would make contact with the literature on the automatic differentiation of imperative languages, such as Fortran. An extension to probability, in some form, would make contact with stochastic optimization and, further, with probabilistic languages for statistical learning. For higher-order types, there may be a domain-theoretic analogue of convenient vector spaces that supports the combination of higher-order types and recursion. Further, one might, as suggested in (Vákár et al., 2018), seek a domain-theoretic analogue of diffeological spaces (see (Iglesias-Zemmour, 2013)); that would also accommodate sum and recursive types. One might also wish to program with Riemannian manifolds, to accommodate natural gradient descent (Amari, 1996); these too should fit into a diffeological framework. In another direction, the work on categories with differential structure may yield an axiomatic version of adequacy theorems for programming languages with differentiation constructs; such categories further equipped with structure to model partiality (Cockett et al., 2011), are of particular interest.

Finally, if perhaps orthogonally, it is important to add explicit tensor (multi-dimensional array) types, with accompanying shape analysis. There is a long history of programming-language design in this area; a salient example is the design of Remora (Slepak et al., 2014).

References

  • (1)
  • Abadi et al. (2016a) Martín Abadi, Paul Barham, Jianmin Chen, Zhifeng Chen, Andy Davis, Jeffrey Dean, Matthieu Devin, Sanjay Ghemawat, Geoffrey Irving, Michael Isard, Manjunath Kudlur, Josh Levenberg, Rajat Monga, Sherry Moore, Derek G. Murray, Benoit Steiner, Paul Tucker, Vijay Vasudevan, Pete Warden, Martin Wicke, Yuan Yu, and Xiaoqiang Zheng. 2016a. TensorFlow: a system for large-scale machine learning. In 12th USENIX Symposium on Operating Systems Design and Implementation (OSDI 16). USENIX Association, 265–283. https://www.usenix.org/conference/osdi16/technical-sessions/presentation/abadi
  • Abadi et al. (2016b) Martin Abadi, Andy Chu, Ian Goodfellow, H. Brendan McMahan, Ilya Mironov, Kunal Talwar, and Li Zhang. 2016b. Deep learning with differential privacy. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security (CCS ’16). ACM, 308–318. https://doi.org/10.1145/2976749.2978318
  • Abramsky and Jung (1994) Samson Abramsky and Achim Jung. 1994. Domain theory. In Handbook of Logic in Computer Science (Vol. 3), Samson Abramsky, Dov M. Gabbay, and T. S. E. Maibaum (Eds.). Oxford University Press, Inc., 1–168. http://dl.acm.org/citation.cfm?id=218742.218744
  • Amari (1996) Shun-ichi Amari. 1996. Neural learning in structured parameter spaces — natural Riemannian gradient. In Advances in Neural Information Processing Systems 9, NIPS, Michael Mozer, Michael I. Jordan, and Thomas Petsche (Eds.). MIT Press, 127–133. http://papers.nips.cc/paper/1248-neural-learning-in-structured-parameter-spaces-natural-riemannian-gradient
  • Baydin et al. (2018) Atilim Gunes Baydin, Barak A. Pearlmutter, Alexey Andreyevich Radul, and Jeffrey Mark Siskind. 2018. Automatic differentiation in machine learning: a survey. Journal of Machine Learning Research 18, 153 (2018), 1–43. http://jmlr.org/papers/v18/17-468.html
  • Baydin et al. (2016) Atilim Günes Baydin, Barak A. Pearlmutter, and Jeffrey Mark Siskind. 2016. Tricks from deep learning. CoRR abs/1611.03777 (2016). http://arxiv.org/abs/1611.03777
  • Beck and Fischer (1994) Thomas Beck and Herbert Fischer. 1994. The if-problem in automatic differentiation. J. Comput. Appl. Math. 50, 1-3 (May 1994), 119–131. https://doi.org/10.1016/0377-0427(94)90294-1
  • Bergstra et al. (2010) James Bergstra, Olivier Breuleux, Frédéric Bastien, Pascal Lamblin, Razvan Pascanu, Guillaume Desjardins, Joseph Turian, David Warde-Farley, and Yoshua Bengio. 2010. Theano: A CPU and GPU math expression compiler. In Proceedings of the Python for scientific computing conference (SciPy), Vol. 4. http://www-etud.iro.umontreal.ca/~wardefar/publications/theano_scipy2010.pdf
  • Bertot and Castéran (2013) Yves Bertot and Pierre Castéran. 2013. Interactive theorem proving and program development: Coq’Art: the calculus of inductive constructions. Springer Science & Business Media.
  • Blute et al. (2010) Richard Blute, Thomas Ehrhard, and Christine Tasson. 2010. A convenient differential category. arXiv preprint arXiv:1006.3140 (2010).
  • Blute et al. (2009) Richard F Blute, J Robin B Cockett, and Robert AG Seely. 2009. Cartesian differential categories. Theory and Applications of Categories 22, 23 (2009), 622–672.
  • Bucciarelli et al. (2010) Antonio Bucciarelli, Thomas Ehrhard, and Giulio Manzonetto. 2010. Categorical models for simply typed resource calculi. Electronic Notes in Theoretical Computer Science 265 (2010), 213–230.
  • Christianson (2012) Bruce Christianson. 2012. A Leibniz notation for automatic differentiation. In Recent Advances in Algorithmic Differentiation, Shaun Forth, Paul Hovland, Eric Phipps, Jean Utke, and Andrea Walther (Eds.). Lecture Notes in Computational Science and Engineering, Vol. 87. Springer, 1–9.
  • Clarke (1990) Frank H. Clarke. 1990. Optimization and nonsmooth analysis. Classics in Applied Mathematics, Vol. 5. SIAM.
  • Cockett et al. (2011) J Robin B Cockett, Geoff SH Cruttwell, and Jonathan D Gallagher. 2011. Differential restriction categories. Theory and Applications of Categories 25, 21 (2011), 537–613.
  • de Moura et al. (2015) Leonardo Mendonça de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn, and Jakob von Raumer. 2015. The Lean Theorem Prover (System Description). In Automated Deduction - CADE-25 - 25th International Conference on Automated Deduction, Berlin, Germany, August 1-7, 2015, Proceedings (Lecture Notes in Computer Science), Amy P. Felty and Aart Middeldorp (Eds.), Vol. 9195. Springer, 378–388. https://doi.org/10.1007/978-3-319-21401-6_26
  • Di Gianantonio and Edalat (2013) Pietro Di Gianantonio and Abbas Edalat. 2013. A language for differentiable functions. In Foundations of Software Science and Computation Structures, Frank Pfenning (Ed.). Springer, 337–352.
  • Edalat and Lieutier (2004) Abbas Edalat and André Lieutier. 2004. Domain theory and differential calculus (functions of one variable). Mathematical Structures in Computer Science 14, 6 (2004), 771–802. https://doi.org/10.1017/S0960129504004359
  • Edalat and Maleki (2018) Abbas Edalat and Mehrdad Maleki. 2018. Differential calculus with imprecise input and Its logical framework. In Foundations of Software Science and Computation Structures - 21st International Conference, FOSSACS 2018. 459–475. https://doi.org/10.1007/978-3-319-89366-2_25
  • Ehrhard and Regnier (2003) Thomas Ehrhard and Laurent Regnier. 2003. The differential lambda-calculus. Theoretical Computer Science 309, 1-3 (2003), 1–41.
  • Elliott (2018) Conal Elliott. 2018. The simple essence of automatic differentiation. In Proceedings of the ACM on Programming Languages (ICFP). http://conal.net/papers/essence-of-ad/
  • Felleisen and Friedman (1987) Matthias Felleisen and Daniel P. Friedman. 1987. Control operators, the SECD-machine and the λ-calculus. In Formal Description of Programming Concepts III, M. Wirsing (Ed.). Elsevier, 193–217.
  • Fischer (2001) H. Fischer. 2001. Automatic differentiation: root problem and branch problem. In Encyclopedia of Optimization, C. A. Floudas and P. M. Pardalos (Eds.). Vol. I. Kluwer Academic Publishers, 118–122.
  • Frostig et al. (2018) Roy Frostig, Matthew James Johnson, and Chris Leary. 2018. Compiling machine learning programs via high-level tracing. Presented at SysML 2018, available at https://www.sysml.cc/doc/146.pdf.
  • Goodfellow et al. (2016) Ian Goodfellow, Yoshua Bengio, and Aaron Courville. 2016. Deep Learning. MIT Press. https://www.deeplearningbook.org Available at https://www.deeplearningbook.org.
  • Griewank (2000) Andreas Griewank. 2000. Evaluating derivatives - principles and techniques of algorithmic differentiation. Frontiers in applied mathematics, Vol. 19. SIAM.
  • Hascoët and Pascual (2013) L. Hascoët and V. Pascual. 2013. The Tapenade automatic differentiation tool: principles, model, and specification. ACM Transactions On Mathematical Software 39, 3 (2013). http://dx.doi.org/10.1145/2450153.2450158
  • Iglesias-Zemmour (2013) P. Iglesias-Zemmour. 2013. Diffeology. American Mathematical Society. Available at https://books.google.com/books?id=Nb0xAAAAQBAJ.
  • Kriegl and Michor (1997) Andreas Kriegl and Peter W Michor. 1997. The convenient setting of global analysis. Vol. 53. American Mathematical Soc.
  • Maclaurin (2017) Dougal Maclaurin. 2017. The chain rule unchained: modeling, optimization and inference with Autograd. Slides of a talk based on joint work with David Duvenaud and Matthew J. Johnson, available at https://dougalmaclaurin.com/talk.pdf.
  • Maclaurin et al. (2015) Dougal Maclaurin, David Duvenaud, and Ryan P Adams. 2015. Autograd: effortless gradients in Numpy. In ICML 2015 AutoML Workshop, Vol. 238.
  • Manzyuk (2012) Oleksandr Manzyuk. 2012. A simply typed λ-calculus of forward automatic differentiation. Electronic Notes in Theoretical Computer Science 286 (2012), 257 – 272. https://doi.org/10.1016/j.entcs.2012.08.017 Proceedings of the 28th Conference on the Mathematical Foundations of Programming Semantics (MFPS XXVIII).
  • Mayero (2002) Micaela Mayero. 2002. Using theorem proving for numerical analysis (correctness proof of an automatic differentiation algorithm). In Theorem Proving in Higher Order Logics, 15th International Conference, TPHOLs 2002, Hampton, VA, USA, August 20-23, 2002, Proceedings (Lecture Notes in Computer Science), Victor Carreño, César A. Muñoz, and Sofiène Tahar (Eds.), Vol. 2410. Springer, 246–262. https://doi.org/10.1007/3-540-45685-6_17
  • Pearlmutter and Siskind (2008) Barak A. Pearlmutter and Jeffrey Mark Siskind. 2008. Reverse-mode AD in a functional framework: lambda the ultimate backpropagator. ACM Trans. Program. Lang. Syst. 30, 2 (2008), 7:1–7:36. https://doi.org/10.1145/1330017.1330018
  • PyTorch (2018) PyTorch. 2018. http://pytorch.org http://pytorch.org.
  • Selsam et al. (2017) Daniel Selsam, Percy Liang, and David L. Dill. 2017. Developing bug-free machine learning systems with formal mathematics. In Proceedings of the 34th International Conference on Machine Learning, ICML 2017, Sydney, NSW, Australia, 6-11 August 2017 (Proceedings of Machine Learning Research), Doina Precup and Yee Whye Teh (Eds.), Vol. 70. PMLR, 3047–3056. http://proceedings.mlr.press/v70/selsam17a.html
  • Shaikhha et al. (2018) Amir Shaikhha, Andrew Fitzgibbon, Dimitrios Vytiniotis, Simon Peyton Jones, and Christoph Koch. 2018. Efficient differentiable programming in a functional array-processing language. CoRR abs/1806.02136 (2018). arXiv:1806.02136 http://arxiv.org/abs/1806.02136 http://arxiv.org/abs/1806.02136.
  • Shankar and Dobson (2017) Asim Shankar and Wolff Dobson. 2017. Eager execution: an imperative, define-by-run interface to TensorFlow. https://research.googleblog.com/2017/10/eager-execution-imperative-define-by.html https://research.googleblog.com/2017/10/eager-execution-imperative-define-by.html.
  • Siskind and Pearlmutter (2005) Jeffrey Mark Siskind and Barak A. Pearlmutter. 2005. Perturbation confusion and referential transparency: correct functional implementation of forward-mode AD. In Implementation and Application of Functional Languages—17th International Workshop, IFL’05, Andrew Butterfield (Ed.). 1–9. Trinity College Dublin, Computer Science Department Technical Report TCD-CS-2005-60.
  • Siskind and Pearlmutter (2008) Jeffrey Mark Siskind and Barak A. Pearlmutter. 2008. Nesting forward-mode AD in a functional framework. Higher-Order and Symbolic Computation 21, 4 (2008), 361–376. https://doi.org/10.1007/s10990-008-9037-1
  • Slepak et al. (2014) Justin Slepak, Olin Shivers, and Panagiotis Manolios. 2014. An array-oriented language with static rank polymorphism. In Proceedings of the 23rd European Symposium on Programming Languages and Systems - Volume 8410. Springer-Verlag New York, Inc., 27–46. https://doi.org/10.1007/978-3-642-54833-8_3
  • Song et al. (2013) Shuang Song, Kamalika Chaudhuri, and Anand D. Sarwate. 2013. Stochastic gradient descent with differentially private updates. In IEEE Global Conference on Signal and Information Processing, GlobalSIP 2013, Austin, TX, USA, December 3-5, 2013. IEEE, 245–248. https://doi.org/10.1109/GlobalSIP.2013.6736861
  • Tokui (2018) Seiya Tokui. 2018. Chainer: a powerful, flexible and intuitive framework of neural networks. http://chainer.org http://chainer.org.
  • Trench (2003) W.F. Trench. 2003. Introduction to Real Analysis. Prentice Hall/Pearson Education. Available at https://books.google.com/books?id=NkFkQgAACAAJ.
  • Vákár et al. (2018) M. Vákár, O. Kammar, and S. Staton. 2018. Diffeological spaces and semantics for differential programming. https://andrejbauer.github.io/domains-floc-2018/slides/Matthijs-Kammar-Staton.pdf. Presented at Domains XIII Workshop.
  • van Merrienboer et al. (2018) Bart van Merrienboer, Dan Moldovan, and Alexander B. Wiltschko. 2018. Tangent: automatic differentiation using source-code transformation for dynamically typed array programming. In Advances in Neural Information Processing Systems 31: Annual Conference on Neural Information Processing Systems 2018, NeurIPS 2018, 3-8 December 2018, Montréal, Canada., Samy Bengio, Hanna M. Wallach, Hugo Larochelle, Kristen Grauman, Nicolò Cesa-Bianchi, and Roman Garnett (Eds.). 6259–6268. http://papers.nips.cc/paper/7863-tangent-automatic-differentiation-using-source-code-transformation-for-dynamically-typed-array-programming
  • Wang et al. (2018) Fei Wang, Xilun Wu, Grégory M. Essertel, James M. Decker, and Tiark Rompf. 2018. Demystifying differentiable programming: shift/reset the penultimate backpropagator. CoRR abs/1803.10228 (2018). arXiv:1803.10228 http://arxiv.org/abs/1803.10228 http://arxiv.org/abs/1803.10228.
  • Yu et al. (2018) Yuan Yu, Martín Abadi, Paul Barham, Eugene Brevdo, Mike Burrows, Andy Davis, Jeff Dean, Sanjay Ghemawat, Tim Harley, Peter Hawkins, Michael Isard, Manjunath Kudlur, Rajat Monga, Derek Murray, and Xiaoqiang Zheng. 2018. Dynamic control flow in large-scale machine learning. In Proceedings of the Thirteenth EuroSys Conference (EuroSys ’18). ACM, Article 18, 15 pages. https://doi.org/10.1145/3190508.3190551