\section{\kcfa\ and \exptime}
\label{chapter-kcfa}

In this chapter, we give an exact characterization of the
computational complexity of the $k$CFA hierarchy.  For any $k > 0$, we
prove that the control flow decision problem is complete for
deterministic exponential time.  This theorem validates empirical
observations that such control flow analysis is intractable.  It also
provides more general insight into the complexity of abstract
interpretation.


\subsection{Shivers' \kcfa}

As noted in \autoref{sec-overview}, practical flow analyses must
negotiate a compromise between complexity and precision, and their
{\em expressiveness} can be characterized by the computational
resources required to compute their results.

Examples of simple yet useful flow analyses include Shivers' 0CFA
\shortcite{shivers-pldi88} and Henglein's simple closure analysis
\shortcite{henglein92d}, which are {\em monovariant}---functions
that are closed over the same $\lambda$-expression are identified.
Their expressiveness is characterized by the class \ptime\
(\autoref{chapter-0cfa}).

As described in \autoref{chapter-0cfa}, a monovariant analysis is one
that approximates at points of nonlinearity.  When a variable appears
multiple times, flow information is merged together for all sites.

So for example, in analyzing the program from \autoref{sec:0cfa},
\begin{displaymath}
(\lambda f. (ff)(\lambda y.y))(\lambda x.x),
\end{displaymath}
a monovariant analysis such as 0CFA or simple closure analysis will
merge the flow information for the two occurrences of $f$.
Consequently both $\lambda x.x$ and $\lambda y.y$ are deemed to flow
out of the whole expression.

More precise analyses can be obtained by incorporating
context-sensitivity to distinguish multiple closures over the same
$\lambda$-term, resulting in ``finer grained approximations, expending
more work to gain more information'' \cite{shivers-pldi88,shivers-phd}.
This context-sensitivity will allow the two occurrences of $f$ to be
analyzed independently.  Consequently, such an analysis will determine
that only $\lambda y.y$ flows out of the expression.

To put it another way, a context-sensitive analysis is capable of
evaluating this program.

As a first approximation to understanding, the added precision of
$k$CFA can be thought of as the ability to do partial reductions
before analysis.  If were to first reduce all of the apparent redexes
in the program, and {\em then} do 0CFA on the residual, our example
program would look like
\begin{displaymath}
(\lambda x_1.x_1)(\lambda x_2.x_2)(\lambda y.y).
\end{displaymath}
Being a linear program, 0CFA is sufficient to prove only $\lambda y.y$
flows out of this residual.  The polyvariance of $k$CFA is powerful
enough to prove the same, however it is important to note that it is
{\em not} done by a bounded reduction of the program.  Instead, the
$k$CFA hierarchy uses the last $k$ calling contexts to distinguish
closures.

The increased precision comes with an empirically observed increase in
cost. As Shivers noted in his retrospective on the $k$CFA work
\shortcite{shivers-sigplan04}:
\begin{quote}%
It did not take long to discover that the basic analysis, for any $k >
0$, was intractably slow for large programs. In the ensuing years,
researchers have expended a great deal of effort deriving clever ways
to tame the cost of the analysis.
\end{quote}

A fairly straightforward calculation---see, for example,
\citet{nielson-nielson-hankin}---shows that 0CFA can be computed in
polynomial time, and for any $k>0$, $k$CFA can be computed in
exponential time.  


These naive upper bounds suggest that the $k$CFA hierarchy is
essentially {\em flat}; researchers subsequently ``expended a great
deal of effort'' trying to improve them.\footnote{Even so, there is a
big difference between algorithms that run in $2^n$ and $2^{n^2}$
steps, though both are nominally in \exptime.}  For example, it seemed
plausible (at least, to us) that the $k$CFA problem could be in \np\
by {\em guessing} flows appropriately during analysis.

As this dissertation shows, the naive algorithm is essentially the
best one, and the {\em lower} bounds are what needed improving.  We
prove that for all $k>0$, computing the $k$CFA analysis requires (and
is thus complete for) deterministic exponential time.  There is, in
the worst case---and plausibly, in practice---no way to tame the cost
of the analysis.  Exponential time is required.

\paragraph{Why should this result matter to functional programmers?}

\begin{itemize}

\item This result concerns a fundamental and ubiquitous static
  analysis {\em of} functional programs.

  The theorem gives an analytic, scientific characterization of the
  expressive power of $k$CFA.  As a consequence, the {\em empirically
    observed} intractability of the cost of this analysis can be
  understood as being {\em inherent in the approximation problem being
    solved}, rather than reflecting unfortunate gaps in our
  programming abilities.

  Good science depends on having relevant theoretical understandings
  of what we observe empirically in practice.

  This connection between theory and experience contrasts with the
  similar result for ML-type inference \cite{mairson-popl90}: while
  the problem of recognizing ML-typable terms is complete for
  exponential time, programmers have happily gone on programming.  It
  is likely that their need of higher-order procedures, essential for
  the lower bound, is not
  considerable.\footnote{\citet{kuan-macqueen-ml-07} have recently
    provided a refined perspective on the complexity of ML-type
    inference that explains why it works so quickly in practice.}

  But static flow analysis really has been costly, and this theorem
  explains why.

\item The theorem is proved {\em by} functional programming.

  We take the view that the analysis itself is a functional
  programming language, albeit with implicit bounds on the available
  computational resources.  Our result harnesses the approximation
  inherent in $k$CFA as a computational tool to hack exponential time
  Turing machines within this unconventional language.  The hack used
  here is completely unlike the one used for the ML analysis, which
  depended on complete developments of {\tt let}-redexes.  The theorem
  we prove in this paper uses approximation in a way that has little
  to do with normalization.
\end{itemize}

We proceed by first bounding the complexity of $k$CFA from above,
showing that $k$CFA can be solved in exponential time
(\autoref{sec-kcfa-in-exptime}).
%
This is easy to calculate and is known \cite{nielson-nielson-hankin}.
%
Next, we bound the complexity from below by using $k$CFA as a
SAT-solver.
%
This shows $k$CFA is at least \np-hard\ (\autoref{sec-kcfa-np-hard}).
The intuitions developed in the \np-hardness proof can be improved to
construct a kind of exponential iterator. 
%
A small, elucidative example is developed in \autoref{sec-toy}.
%
These ideas are then scaled up and applied in
\autoref{sec-kcfa-exptime-hard} to close the gap between the \exptime\
upper bound and \np\ lower bound by giving a construction to simulate
Turing machines for an exponential number of steps using $k$CFA, thus
showing $k$CFA to be complete for \exptime.

\subsection{\kcfa\ is in \exptime}
\label{sec-kcfa-in-exptime}

Recall the definition of $k$CFA from \autoref{sec:ai}.
%
The cache, $\cache,\aenv$, is a finite mapping and has $n^{k+1}$
entries.
%
Each entry contains  a set of closures.
%
The environment component of each closure maps $p$ free variables to
any one of $n^k$ contours.
%
There are $n$ possible $\lambda$-terms and $n^{kp}$ environments, so
each entry contains at most $n^{1+kp}$ closures.
%
Analysis is monotonic, and there are at most $n^{1+(k+1)p}$ updates to
the cache.
%
Since $p\leq n$, we conclude:

\begin{lemma}
The control flow problem for $k$CFA is contained in \exptime.
\end{lemma}

It is worth noting that this result shows, from a complexity
perspective, the flatness of the $k$CFA hierarchy: {\em for any
  constant} $k$, $k$CFA is decidable in exponential time.
%
It is not the case, for example, that 1CFA requires exponential time
(for all $j$, $\mbox{\dtime}(2^{n^j}) \subseteq \mbox{\exptime}$),
while 2CFA requires {\em doubly} exponential time (for all $j$,
$\mbox{\dtime}(2^{2^{n^j}}) \subseteq \mbox{2\exptime}$), 3CFA
requires {\em triply} exponential time, etc.
%
There are strict separation results for these classes, $\mbox\exptime
\subset \mbox{2\exptime} \subset \mbox{3\exptime}$, etc., so we know
from the above lemma there is no need to go searching for lower bounds
greater than \exptime.


\subsection{\kcfa\ is \np-hard}
\label{sec-kcfa-np-hard}

Because $k$CFA makes approximations, many closures can flow to a
single program point and contour.  In 1CFA, for example, $\lambda
w.wx_1x_2\cdots x_n$ has $n$ free variables, with an exponential
number of possible associated environments mapping these variables to
program points (contours of length 1).  Approximation allows us to
bind each $x_i$, independently, to either of the closed
$\lambda$-terms for \True\ or \False\ that we saw in the
\ptime-completeness proof for 0CFA.  In turn, application to an
$n$-ary Boolean function necessitates computation of all $2^n$ such
bindings in order to compute the flow out from the application site.
The term \True\ can only flow out if the Boolean function is
satisfiable by some truth valuation.
\begin{figure}[h]
\begin{eqnarray*}
&& (\lambda f_1. (f_1\ \True) (f_1\ \False))\\
&& (\lambda x_1.\\
&& \TB (\lambda f_2. (f_2\ \True) (f_2\ \False))\\
&& \TB (\lambda x_2.\\
&& \TB\TB (\lambda f_3. (f_3\ \True) (f_3\ \False))\\
&& \TB\TB (\lambda x_3.\\
&& \TB\TB\TB\TB \cdots\\
&& \TB\TB\TB\TB (\lambda f_n. (f_n\ \True) (f_n\ \False))\\
&& \TB\TB\TB\TB (\lambda x_n.\\
&& \TB\TB\TB\TB\TB C[(\lambda v.\phi\ v)(\lambda w.wx_1x_2\cdots x_n)])\cdots ))))
\end{eqnarray*}
\caption{\np-hard construction for $k$CFA.}
\end{figure}
For an appropriately chosen program point (label) $\ell$, the cache
location $\cache(v,\ell)$ will contain the set of all possible
closures which are approximated to flow to $v$.  This set is that of
all closures
\begin{displaymath}
\langle(\lambda w.wx_1x_2\cdots x_n),\ce\rangle
\end{displaymath} 
where $\ce$ ranges over all assignments of {\tt True} and {\tt False}
to the free variables (or more precisely assignments of locations in
the table containing {\tt True} and {\tt False} to the free
variables).  The Boolean function $\phi$ is completely linear, as in
the \ptime-completeness proof; the context $C$ uses the Boolean
output(s) as in the conclusion to that proof: mixing in some ML, the
context is:
\begin{quote}
{\small
\begin{verbatim}
- let val (u,u')= [---] in
  let val ((x,y),(x',y'))= (u (f,g), u' (f',g')) in 
      ((x a, y b),(x' a', y' b')) end end;
\end{verbatim}
}
\end{quote}
Again, {\tt a} can only flow as an argument to {\tt f} if {\tt True} flows to {\tt (u,u')},
leaving {\tt (f,g)} unchanged, which can only happen if {\em some} closure
$\langle(\lambda w.wx_1x_2\cdots x_n),\ce\rangle$ provides a satisfying truth valuation for $\phi$.
We have as a consequence:

\begin{theorem}
The control flow problem for 1CFA is \np-hard.
%% Determining the existence of a single flow in 1CFA is \np-hard.
\end{theorem}

Having established this lower bound for 1CFA, we now argue the result
generalizes to all values of $k > 0$.
%
Observe that by going from $k$CFA to $(k+1)$CFA, further
context-sensitivity is introduced.
%
But, this added precision can be undone by inserting an identity
function application at the point relevant to answering the flow
question.
%
This added calling context consumes the added bit of precision in the
analysis and renders the analysis of rest of the program equivalently
to the courser analysis.
%
Thus, it is easy to insert an identity function into the above
construction such that 2CFA on this program produces the same results
as 1CFA on the original.
%
So for any $k > 1$, we can construct an \np-hard computation by
following the above construction and inserting $k-1$ application sites
to eat up the precision added beyond 1CFA.
%
The result is equivalent to 1CFA on the original term, so we conclude:

\begin{theorem}
The control flow problem for $k$CFA is \np-hard, for any $k > 0$.
%% Determining the existence of a single flow in 1CFA is \np-hard.
\end{theorem}

At this point, there is a tension in the results.  On the one hand,
$k$CFA is contained in \exptime; on the other, $k$CFA requires at
least \np-time to compute.
%
So a gap remains; either the algorithm for computing $k$CFA can be
improved and put into \np, or the lower bound can be strengthened by
exploiting more computational power from the analysis.

We observe that while the computation of the {\em entire} cache
requires exponential time, perhaps the existence of a {\em specific}
flow in it may well be computable in \np.
%
A non-deterministic algorithm might compute using the ``collection
semantics'' $\ev{t^\ell}{\ce}{\delta}$, but rather than compute entire
sets, {\em choose} the element of the set that bears witness to the
flow.
%
If so we could conclude $k$CFA is \np-complete.

However, this is not the case.
%
We show that the lower bound can be improved and $k$CFA is complete
for \exptime.
%
The improvement relies on simulating an exponential iterator using
analysis.
%
The following section demonstrates the core of the idea.


\subsection{Nonlinearity and Cartesian Products:\texorpdfstring{\\ \qquad}{} a toy calculation, with insights}
\label{sec-toy}

A good proof has, at its heart, a small and simple idea that makes it
work.  For our proof, the key idea is how the approximation of
analysis can be {\em leveraged} to provide computing power {\em above
and beyond} that provided by evaluation.  The difference between the
two can be illustrated by the following term:
\begin{displaymath}
\begin{array}{l}
(\lambda f. (f\;\mbox{\tt True}) (f\;\mbox{\tt False}))\\
(\lambda x.\Implies\, x\, x)
\end{array}
\end{displaymath}
Consider evaluation: Here $\Implies\, x\, x$ (a tautology) is evaluated
twice, once with $x$ bound to \True, once with $x$ bound to \False.
But in both cases, the result is \True.  Since $x$ is bound to \True\
or \False\, both occurrences of $x$ are bound to \True\ or to
\False---but it is never the case, for example, that the first
occurrence is bound to \True, while the second is bound to \False.
The values of each occurrence of $x$ is dependent on the other.

On the other hand, consider what flows out of $\Implies\,x\, x$ according
1CFA: both \True\ and \False.  Why? The approximation incurs analysis
of $\Implies\,x\, x$ for $x$ bound to \True\ and \False, but it considers
{\em each occurrence of $x$ as ranging over \True\ and \False,
independently}.  In other words, for the set of values bound to $x$,
we consider their {\em cross product} when $x$ appears nonlinearly.
The approximation permits one occurrence of $x$ be bound to \True\
while the other occurrence is bound to \False; and somewhat alarmingly,
$\Implies\,\True\,\False$ causes \False\ to flow out.  Unlike in normal
evaluation, where within a given scope we know that multiple
occurrences of the same variable refer to the same value, in the
approximation of analysis, multiple occurrences of the same variable
range over {\em all} values that they are possible bound to {\em
independent of each other}.  

Now consider what happens when the program is expanded as follows:
\begin{displaymath}
\begin{array}{l}
(\lambda f. (f\,\mbox{\tt True}) (f\,\mbox{\tt False}))\\
(\lambda x. (\lambda p. p (\lambda u. p (\lambda v. \Implies\, u v))) (\lambda w.wx))
\end{array}
\end{displaymath}
Here, rather than pass $x$ directly to \Implies, we construct a unary
tuple $\lambda w.wx$.  The tuple is used nonlinearly, so $p$ will
range over {\em closures} of $\lambda w.wx$ with $x$ bound to \True\
and \False, again, independently.

A closure can be approximated by an exponential number of values.  For
example, $\lambda w.wz_1z_2\dots z_n$ has $n$ free variables, so there
are an exponential number of possible environments mapping these
variables to program points (contours of length 1).  If we could apply
a Boolean function to this tuple, we would effectively be evaluating
all rows of a truth table; following this intuition leads to
\np-hardness of the 1CFA control flow problem.

Generalizing from unary to $n$-ary tuples in the above example, an
exponential number of closures can flow out of the tuple.  For a
function taking two $n$-tuples, we can compute the function on the
cross product of the exponential number of closures.

This insight is the key computational ingredient in simulating exponential
time, as we describe in the following section.

\subsection{\kcfa\ is \exptime-hard}
\label{sec-kcfa-exptime-hard}

\subsubsection{Approximation and \exptime}
%% \subsubsection{Simulating Turing machines for exponential time}

Recall the formal definition of a Turing machine: a 7-tuple
\[
\langle Q,\Sigma,\Gamma,\delta,q_0,q_a,q_r\rangle
\]
where $Q$, $\Sigma$, and $\Gamma$ are finite sets,  $Q$ is the set of
machine states (and $\{q_0,q_a,q_r\}\subseteq Q$),  $\Sigma$ is the
input alphabet, and $\Gamma$ the tape alphabet, where
$\Sigma\subseteq\Gamma$.  The states $q_0$, $q_a$, and $q_r$ are the
machine's initial, accept, and reject states, respectively.
The complexity class \exptime\ denotes the languages
that can be decided by a Turing machine in time  exponential in the
input length.  

Suppose we have a deterministic Turing machine $M$ that accepts or
rejects its input $x$ in time $2^{p(n)}$, where $p$ is a polynomial
and $n=|x|$.  We want to simulate the computation of $M$ on $x$ by
$k$CFA analysis of a $\lambda$-term $E$ dependent on $M,x,p$, where a
particular closure will flow to a specific program point iff $M$
accepts $x$.  It turns out that $k=1$ suffices to carry out this
simulation.  The construction, computed in logarithmic space, is
similar for all constant $k>1$ modulo a certain amount of padding
as described in \autoref{sec-kcfa-np-hard}.

\subsubsection{Coding Machine IDs}

The first task is to code machine IDs.  Observe that each
value stored in the abstract cache $\cache$ is a {\em closure}---a
$\lambda$-abstraction, together with an environment for its free variables.
The number of such abstractions is bounded by the program size, as is the {\em domain}
of the environment---while the number of such {\em environments} is exponential in the program size.
(Just consider a program of size $n$ with, say, $n/2$ free variables mapped to only 2 program points
denoting bindings.)

Since a closure only has polynomial size, and a Turing machine ID has
exponential size, we represent the latter by splitting its information
into an exponential number of closures.  Each closure represents a
tuple $\langle T,S,H,C,b\rangle$, which can be read as
\begin{quote}\it
``At time $T$, Turing machine $M$ was in state $S$, the tape position
was at cell $H$, and cell $C$ held contents $b$.''
\end{quote}
$T$, $S$, $H$, and $C$ are blocks of bits ($\Zero \equiv \True$,
$\One\equiv\False$) of size polynomial in the input to the Turing machine.  As such, each block
can represent an exponential number of values.
A single machine ID is represented
by an exponential number of tuples (varying $C$ and $b$).  Each such tuple can in turn be
coded as a $\lambda$-term $\lambda w.wz_1z_2\cdots z_N$, where $N=O(p(n))$.

We still need to be able to generate an exponential number of closures
for such an $N$-ary tuple.  The construction is only a modest,
iterative generalization of the construction in our toy calculation
above:
\begin{figure}[h]
\begin{displaymath}
\begin{array}{rcl}
\ & \ & (\lambda f_1.(f_1\;\Zero)(f_1\;\One))\\
\ & \ & (\lambda z_1.\\
\ & \ &\quad(\lambda f_2.(f_2\;\Zero)(f_2\;\One))\\
\ & \ &\quad(\lambda z_2.\\
\ & \ &\qquad\cdots\\
\ & \ &\quad\qquad(\lambda f_N. (f_N\;\Zero) (f_N\;\One))\\
\ & \ &\quad\qquad(\lambda z_N.((\lambda x.x)(\lambda w.wz_1z_2\cdots z_N))^{\ell})\cdots))
\end{array}
\end{displaymath}
\caption{Generalization of toy calculation for $k$CFA.}
\label{fig-kcfa-construction}
\end{figure}

In the inner subterm,
\begin{displaymath}
((\lambda x.x)(\lambda w.wz_1z_2\cdots z_N))^{\ell},
\end{displaymath}
the function $\lambda x.x$ acts as a very important form of {\em
  padding}.  Recall that this is $k$CFA with $k=1$---the expression
$(\lambda w.wz_1z_2\cdots z_N)$ is evaluated an exponential number of
times---to see why, normalize the term---but in each instance, the
contour is always $\ell$.  (For $k>1$, we would just need more padding
to evade the {\em polyvariance} of the flow analyzer.)  As a
consequence, each of the (exponential number of) closures gets put in
the {\em same} location of the abstract cache $\cache$, while they are
placed in unique, {\em different} locations of the exact cache
$\ecache$.  In other words, the approximation mechanism of $k$CFA
treats them as if they are all the same.  (That is why they are put in
the same cache location.)

\subsubsection{Transition Function}

Now we define a binary transition function $\delta$, which does a {\em
  piecemeal} transition of the machine ID.  The transition function is
represented by three rules, identified uniquely by the time stamps $T$
on the input tuples.

The first {\em transition rule} is used when the
tuples agree on the time stamp $T$, and the head and cell address of the
first tuple coincide:
\begin{displaymath}
\begin{array}{l}
\delta\langle T,S,H,H,b\rangle \langle T,S',H',C',b'\rangle\; = \\
\qquad\qquad\qquad\qquad % hack
\langle T+1, \delta_Q(S,b), \delta_{LR}(S,H,b), H, \delta_\Sigma(S,b) \rangle
\end{array}
\end{displaymath}
This rule {\em computes} the transition to the next ID.  The first
tuple has the head address and cell address coinciding, so it has all
the information needed to compute the next state, head movement, and
what to write in that tape cell.  The second tuple just marks that
this is an instance of the {\em computation} rule, simply indicated by
having the time stamps in the tuples to be identical.  The Boolean functions
$\delta_Q,\delta_{LR},\delta_\Sigma$ compute the next state, head position, and 
what to write on the tape.

The second {\em communication rule} is used when the tuples have time
stamps $T+1$ and $T$: in other words, the first tuple has information
about state and head position which needs to be communicated to every
tuple with time stamp $T$ holding tape cell information for an arbitrary such cell, as it
gets updated to time stamp $T+1$:
\begin{displaymath}
\begin{array}{l}
\delta\langle T+1,S,H,C,b\rangle \langle T,S',H',C',b'\rangle = \langle T+1, S, H, C',b'\rangle\\
\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad % hack
(H'\not=C')
\end{array}
\end{displaymath}
(Note that when $H'=C'$, we have already written the salient tuple using the transition rule.)
This rule {\em communicates} state and head position (for the first
tuple computed with time stamp $T+1$, where the head and cell address
coincided) to all the other tuples coding the rest of the Turing
machine tape.  

Finally, we define a {\em catch-all rule}, mapping any other
pairs of tuples (say, with time stamps $T$ and $T+42$) to some
distinguished null value (say, the initial ID).  We need this rule just to make sure that
$\delta$ is a totally defined function.
\begin{displaymath}
\begin{array}{l}
\delta\langle T,S,H,C,b\rangle \langle T',S',H',C',b'\rangle\; =\ \Null\qquad\qquad\qquad\qquad\\
\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad % hack
(T\not=T'\mbox{\ and\ } T\not=T'+1)
\end{array}
\end{displaymath}

Clearly, these three rules can be coded by a single Boolean circuit,
and we have all the required Boolean logic at our disposal from
\autoref{sec:circuits}.

Because $\delta$ is a binary function, we need to compute a {\em cross
  product} on the coding of IDs to provide its input.  The transition
function is therefore defined as in \autoref{fig-transition}.
\begin{figure}[h]
\begin{displaymath}
\begin{array}{rcl}
\Phi &\equiv& \lambda p.\\
\ &\ &\quad\mbox{let }\langle u_1,u_2,u_3,u_4,u_5\rangle = \Copy_5\; p\mbox{ in}\\
\ &\ &\quad\mbox{let }\langle v_1,v_2,v_3.v_4,v_5\rangle = \Copy_5\; p\mbox{ in}\\
\ &\ &\qquad(\lambda w . w(\phi_T u_1 v_1) (\phi_S u_2 v_2) \dots (\phi_b u_5 v_5))\\
\ &\ &\qquad(\lambda w_T. \lambda w_S. \lambda w_H. \lambda w_C. \lambda w_b.\\
\ &\ &\quad\qquad w_T(\lambda z_1.\lambda z_2\dots\lambda z_T.\\
\ &\ &\qquad\qquad w_S(\lambda z_{T+1}.\lambda z_{T+2}\dots\lambda z_{T+S}.\\
\ &\ &\quad\qquad\qquad \dots\\
\ &\ &\qquad\qquad\qquad w_b(\lambda z_{C+1}.\lambda z_{C+2}\dots\lambda z_{C+b=m}.\\
\ &\ &\quad\qquad\qquad\qquad \lambda w.wz_1z_2\dots z_m)\dots)))
\end{array}
\end{displaymath}
\caption{Turing machine transition function construction.}
\label{fig-transition}
\end{figure}
The {\tt Copy} functions just copy enough of the input for the separate calculations to
be implemented in a linear way.
Observe that this $\lambda$-term is entirely linear {\em except} for
the two occurrences of its parameter $p$.  In that sense, it serves a
function analogous to $\lambda x.\Implies\, x\, x$ in the toy
calculation.  Just as $x$ ranges there over the closures for $\True$
and for $\False$, $p$ ranges over all possible IDs flowing to the
argument position.  Since there are two occurrences of $p$, we have
two entirely separate iterations in the $k$CFA analysis.  These
separate iterations, like nested ``for'' loops, create the equivalent
of a cross product of IDs in the ``inner loop'' of the flow analysis.

\subsubsection{Context and Widget}

The context for the Turing machine simulation needs to set up the
initial ID and associated machinery, extract the Boolean value telling
whether the machine accepted its input, and feed it into the flow
widget that causes different flows depending on whether the value flowing in is
$\True$ or $\False$.
\begin{figure}
\begin{displaymath}
\begin{array}{rcl}
C &\equiv & (\lambda f_1.(f_1\;\Zero)(f_1\;\One))\\
\ & \ & (\lambda z_1.\\
\ & \ &\quad(\lambda f_2.(f_2\;\Zero)(f_2\;\One))\\
\ & \ &\quad(\lambda z_2.\\
\ & \ &\qquad\cdots\\
\ & \ &\quad\qquad(\lambda f_N. (f_N\;\Zero) (f_N\;\One))\\
\ & \ &\quad\qquad(\lambda z_N.((\lambda x.x) (\Widget (\Extract[\;]))^\ell)^{\ell'})\cdots))
\end{array}
\end{displaymath}
\caption{\exptime-hard construction for $k$CFA.}
\end{figure}
In this code, the $\lambda x.x$ (with label $\ell'$ on its application) serve as padding, so that the term within is always applied in the same contour.
\Extract\ extracts a final ID, with its time stamp, and checks if it
codes an accepting state, returning \True\ or \False\ accordingly.
\Widget\ is our standard control flow test.  The context is
instantiated with the coding of the transition function, iterated over
an initial machine ID,
\begin{displaymath}
\begin{array}{l}
%% 2^n\;\Phi\;\langle\Zero\dots\Zero, Q_0, H_0, \lambda w.wz_1 z_2\dots z_N, \Zero\rangle,
2^n\;\Phi\; \lambda w.w\Zero\dots\Zero\cdots Q_0\cdots H_0\cdots z_1 z_2\dots z_N \Zero,
\end{array}
\end{displaymath}
where $\Phi$ is a coding of transition function for $M$.  The
$\lambda$-term $2^n$ is a fixed point operator for $k$CFA, which can
be assumed to be either $\mathbf{Y}$, or an exponential function
composer.  There just has to be enough iteration of the transition
function to produce a fixed point for the flow analysis.

To make the coding easy, we just assume without loss of generality
that $M$ starts by writing $x$ on the tape, and then begins the
generic exponential-time computation.  Then we can just have all
zeroes on the initial tape configuration.

\begin{lemma}
  For any Turing machine $M$ and input $x$ of length $n$, where $M$
  accepts or rejects $x$ in $2^{p(n)}$ steps, there exists a
  logspace-constructable, closed, labeled $\lambda$-term $e$ with distinguished label
  $\ell$ such that in the $k$CFA analysis of $e$ ($k>0$), $\True$ flows into
  $\ell$ iff $M$ accepts $x$.
\end{lemma}
\begin{theorem}
The control flow problem for $k$CFA is complete
for \exptime\ for any $k > 0$.
\end{theorem}

\subsection{Exact \kcfa\ is \ptime-complete}

At the heart of the \exptime-completeness result is the idea that the
{\em approximation} inherent in abstract interpretation is being
harnessed for computational power, quite apart from the power of {\em
exact} evaluation.  To get a good lower bound, this is necessary: it
turns out there is a dearth of computation power when $k$CFA
corresponds with evaluation, i.e.~when the analysis is exact.

As noted earlier, approximation arises from the truncation of contours
during analysis.  Consequently, if truncation never occurs, the
instrumented interpreter and the abstract interpreter produce
identical results for the given program.  But what can we say about
the complexity of these programs?  In other words, what kind of
computations can $k$CFA analyze exactly when $k$ is a constant,
independent of the program analyzed?  What is the intersection between
the abstract and concrete interpreter?

An answer to this question provides another point in the
characterization of the expressiveness of an analysis.  For 0CFA, the
answer is \ptime\ since the evaluation of linear terms is captured.
For $k$CFA, the answer remains the same.

For any fixed $k$, $k$CFA can only analyze polynomial time programs
exactly, since, in order for an analysis to be exact, there can only
one entry in each cache location, and there are only $n^{k+1}$
locations. But from this it is clear that only through the use of
approximation that a exponential time computation can be simulated,
but this computation has little to do with the actual running of the
program.  A program that runs for exponential time cannot be analyzed
exactly by $k$CFA for any constant $k$.

Contrast this with ML-typability, for example, where the evaluation of
programs that run for exponential time can be simulated via type
inference.

Note that if the contour is never truncated, every program point is
now approximated by at most one closure (rather than an exponential
number of closures).  The size of the cache is then bounded by a
polynomial in $n$; since the cache is computed monotonically, the
analysis and the natural related decision problem is constrained by
the size and use of the cache.

\begin{proposition}
Deciding the control flow problem for exact $k$CFA is complete for
\ptime.
\end{proposition}

This proposition provides a characterization of the computational
complexity (or expressivity) of the language evaluated by the
instrumented evaluator $\mathcal{E}$ of section
\autoref{section-instrumented} as a function of the contour length.

It also provides an analytic understanding of the empirical
observation researchers have made: computing a more precise analysis
is often cheaper than performing a less precise one, which ``yields
coarser approximations, and thus induces more merging. More merging
leads to more propagation, which in turn leads to more reevaluation''
\cite{wright-jagannathan-toplas98}.  \citet{might-shivers-icfp06} make
a similar observation: ``imprecision reinforces itself during a flow
analysis through an ever-worsening feedback loop.''  This
ever-worsening feedback loop, in which we can make \False\
(spuriously) flow out of $\Implies\,x\,x$, is the critical ingredient
in our \exptime\ lower bound.

Finally, the asymptotic differential between the complexity of exact
and abstract interpretation shows that abstract interpretation is
strictly more expressive, for any fixed $k$.



%\dvhnote{Need also to insert $n$CFA stuff from ICFP'07}


\subsection{Discussions}

% \paragraph{Discussion:} 

We observe an ``exponential jump'' between contour length and
complexity of the control flow decision problem for every
polynomial-length contour, including contours of constant length.
Once $k=n$ (contour length equals program size), an exponential-time
hardness result can be proved which is essentially a linear circuit
with an exponential iterator---very much like \citet{mairson-popl90}.
When the contours are exponential in program length, the decision
problem is doubly exponential, and so on.

The reason for this exponential jump is the cardinality of
environments in closures.  This, in fact, is the bottleneck for
control flow analysis---it is the reason that 0CFA (without closures)
is tractable, while 1CFA is not.  If $f(n)$ is the
contour length and $n$ is the program length, then
\begin{displaymath}
|\CEnv| = |\Var \rightarrow \Delta^{\leq f(n)}| = (n^{f(n)})^n = 2^{f(n)n \lg n}
\end{displaymath}
This cardinality of environments effectively determines the size of
the universe of values for the abstract interpretation realized by CFA.


When $k$ is a constant, one might ask why the inherent complexity is
exponential time, and not more---especially since one can iterate (in
an untyped world) with the $\mathbf{Y}$ combinator.  Exponential time
is the ``limit'' because with a polynomial-length tuple (as
constrained by a logspace reduction), you can only code an exponential
number of closures.


The idea behind $k$CFA is that the precision of could {\em dialed up},
but there are essentially two settings to the $k$CFA hierarchy: {\em
  high} ($k > 0$, \exptime) and {\em low} $(k = 0)$.  We can see, from
a computational complexity perspective, that 0CFA is strictly less
expressive than $k$CFA.  In turn, $k$CFA is strictly less expressive
than, for example, Mossin's flow analysis \shortcite{mossin-sas97}.
Mossin's analysis is a stronger analysis in the sense that it is exact
for a larger class of programs than 0CFA or $k$CFA---it exact not only
for linear terms, but for all simply-typed terms.  In other words, the
flow analysis of simply-typed programs is synonymous with running the
program, and hence non-elementary.  This kind of expressivity is also
found in Burn-Hankin-Abramsky-style strictness analysis
\shortcite{burn-hankin-abramsky}.  But there is a considerable gap
between $k$CFA and these more expressive analyses.  What is in between
and how can we build a real {\em hierarchy} of static analyses that
occupy positions within this gap?


This argues that the relationship between dial level $N$ and $N+1$
should be exact. This is the case with say simple-typing and
ML-typing.  (ML = simple + let reduction).  There is no analogous
relationship known between $k$ and $k+1$CFA.  A major computational
expense in $k$CFA is the approximation engendering further
approximation and re-evaluation.  Perhaps by staging analysis into
polyvariance and approximation phases, the feedback loop of spurious
flows can be avoided. 

If you had an analysis that did some kind of exact, bounded,
evaluation of the program and then analyzed the residual with 0CFA,
you may have a far more usable analysis than with the $k$CFA
hierarchy.

The precision of $k$CFA is highly sensitive to syntactic structure.
Simple program refactorings such as $\eta$-expansion have drastic
effects on the results of $k$CFA and can easily undermine the added
work of a more and more precise analysis.  Indeed, we utilize these
simple refactorings to undermine the added precision of $k$CFA to
generalize the hardness results from the case of 1CFA to all $k > 0$
CFA.  But an analysis that was robust in the face of these
refactorings could undermine these lower bounds.

In general, techniques that lead to increased precision will take
computational power {\em away} from our lower bound constructions.
For instance, it is not clear what could be said about lower bounds on
the complexity of a variant of $k$CFA that employed abstract garbage
collection \cite{might-shivers-icfp06}, which allows for the safe
removal of values from the cache during computation.  It is critical
in the lower bound construction that what goes into the cache, stays
in the cache.


L\'evy's notion of labeled reduction \shortcite{levy-phd, levy-80}
provides a richer notion of ``instrumented evaluation'' coupled with a
richer theory of exact flow analysis, namely the geometry of
interaction \cite{girard-goi89, gonthier-abadi-levy-popl92}.  With the
proper notion of abstraction and simulated reduction, we should be
able to design more powerful flow analyses, filling out the hierarchy
from 0CFA up to the expressivity of Mossin's analysis in the limit.


\subsection{Conclusions}

Empirically observed increases in costs can be understood analytically
as {\em inherent in the approximation problem being solved}.

We have given an exact characterization of the $k$CFA approximation
problem.  The \exptime\ lower bound validates empirical observations
and shows that there is no tractable algorithm for $k$CFA.

The proof relies on previous insights about linearity, static
analysis, and normalization (namely, when a term is linear, static
analysis and normalization are synonymous); coupled with new insights
about using nonlinearity to realize the full computational power of
approximate, or abstract, interpretation.


Shivers wrote in his best of PLDI retrospective
\shortcite{shivers-sigplan04},
\begin{quote}%%
Despite all this work on formalising CFA and speeding it up, I have
been disappointed in the dearth of work extending its {\em
power}.
\end{quote}
This work has shown that work spent on speeding up $k$CFA is an
exercise in futility; there is no getting around the exponential
bottleneck of $k$CFA.  The one-word description of the bottleneck is {\em closures},
which do not exist in 0CFA, because free variables in a closure would necessarily map to $\epsilon$,
and hence the environments are useless.

This detailed accounting of the ingredients that combine to make
$k$CFA hard, when $k > 0$, should provide guidance in designing new
abstractions that avoid computationally expensive components of
analysis.
%
A lesson learned has been that {\em closures}, as they exist when
$k>0$, result in an exponential value space that can be harnessed for
the \exptime\ lower-bound construction.

% Finally, we need to emphasize the importance of linearity in static
% analysis.  Static analysis makes approximations to be tractable, but
% with linear terms, there is no approximation.  We carefully admitted a
% certain, limited nonlinearity in order to increase the lower bound.


