\section{Monovariant Analysis and \ptime}
% \chaptermark{Monovariant Analysis and PTIME}
\label{chapter-0cfa}

The monovariant form of flow analysis defined over the pure
$\lambda$-calculus has emerged as a fundamental notion of flow
analysis for higher-order languages, and some form of flow analysis is
used in most analyses for higher-order languages
\cite{heintze-mcallester-pldi97}.

In this chapter, we examine several of the most well-known variations
of monovariant flow analysis: Shivers' 0CFA
\shortcite{shivers-pldi88}, Henglein's simple closure analysis
\shortcite{henglein92d}, Heintze and McAllester's subtransitive flow
analysis \shortcite{heintze-mcallester-pldi97}, Ashley and Dybvig's
sub-0CFA \shortcite{ashley-dybvig-toplas98}, Mossin's single
source/use analysis \shortcite{mossin-njc98}, and others.

In each case, evaluation and analysis are proved equivalent for the
class of linear programs and a precise characterization of the
computational complexity of the analysis, namely \ptime-completeness,
is given.

\subsection{The Approximation of Monovariance}

To ensure tractability of any static analysis, there has to be an {\em
  approximation} of something, where information is deliberately {\em
  lost} in the service of providing what is left in a reasonable
amount of time.  A good example of what is lost during {\em
  monovariant} static analysis is that the information gathered for
each occurrence of a bound variable is merged.  When variable $f$
occurs twice in function position with two different arguments,
\begin{displaymath}
%% f(\lambda x.e') \cdots f (\lambda y.e'')
(f\;v_1) \cdots (f\;v_2)
\end{displaymath}
a monovariant flow analysis will blur which copy of the function is
applied to which argument.  If a function $\lambda z.e$ flows into $f$
in this example, the analysis treats occurrences of $z$ in $e$ as
bound to {\em both} $v_1$ and
$v_2$. %% $\lambda x.e'$ and $\lambda y.e''$.

Shivers' 0CFA is among the most well-known forms of monovariant flow
analysis; however, the best known algorithm for 0CFA requires nearly
cubic time in proportion to the size of the analyzed program.

It is natural to wonder whether it is possible to do better, avoiding
this bottleneck, either by improving the 0CFA algorithm in some clever
way or by {\em further} approximation for the sake of faster
computation.

Consequently, several analyses have been designed to approximate 0CFA
by trading precision for faster computation.  Henglein's simple
closure analysis, for example, forfeits the notion of directionality
in flows.  Returning to the earlier example,
\begin{displaymath}
f(\lambda x.e') \cdots f (\lambda y.e'')
\end{displaymath}
simple closure analysis, like 0CFA, will blur $\lambda x.e'$ and
$\lambda y.e''$ as arguments to $f$, causing $z$ to be bound to both.
But unlike 0CFA, a {\em bidirectional} analysis such as simple closure
analysis will identify two $\lambda$-terms with each other.  That is,
because both are arguments to the same function, by the
bi-directionality of the flows, $\lambda x.e'$ may flow out of $\lambda
y.e''$ and {\em vice versa}.

Because of this further curtailing of information, simple closure
analysis enjoys an ``almost linear'' time algorithm.  But in making
trade-offs between precision and complexity, what has been given up
and what has been gained?  Where do these analyses differ and where do
they coincide?

We identify a core language---the linear $\lambda$-calculus---where
0CFA, simple closure analysis, and many other known approximations or
restrictions to 0CFA are rendered identical.  Moreover, for this core
language, analysis corresponds with (instrumented) evaluation.
Because analysis faithfully captures evaluation, and because the
linear $\lambda$-calculus is complete for \ptime, we derive
\ptime-completeness results for all of these analyses.

Proof of this lower bound relies on the insight that linearity of
programs subverts the approximation of analysis and renders it
equivalent to evaluation.  We establish a correspondence between
Henglein's simple closure analysis and evaluation for linear terms.
In doing so, we derive sufficient conditions effectively
characterizing not only simple closure analysis, but many known flow
analyses computable in less than cubic time, such as Ashley and
Dybvig's sub-0CFA, Heintze and McAllester's subtransitive flow
analysis, and Mossin's single source/use analysis.

By using a nonstandard, symmetric implementation of Boolean logic
within the linear lambda calculus, it is possible to simulate circuits
at analysis-time, and as a consequence, we prove that all of the above
analyses are complete for \ptime.  Any sub-polynomial algorithm for
these problems would require (unlikely) breakthrough results in
complexity, such as \ptime\ $=$ \logspace.

We may continue to wonder whether it is possible to do better, either
by improving the 0CFA algorithm in some clever way or by further
approximation for faster computation.  However these theorems
demonstrate the limits of both avenues.  0CFA is inherently
sequential, and so is {\em any} algorithm for it, no matter how
clever.  Designing a provably efficient parallel algorithm for 0CFA is
as hard as parallelizing all polynomial time computations.  On the
other hand, further approximations, such as simple closure analysis
and most other variants of monovariant flow analysis, make no
approximation on a linear program.  This means they too are inherently
sequential and no easier to parallelize.


\subsection{0CFA}
\label{sec:0cfa}

Something interesting happens when $k=0$.  Notice in the application
rule of the $k$CFA abstract evaluator of \autoref{fig-a-imperative}
that environments are extended as $\rho[x\mapsto
\lceil\delta\ell\rceil_k]$.  When $k=0$,
$\lceil\delta\ell\rceil_0=\epsilon$.  All contour environments map to
the empty contour, and therefore carry no contextual information.  As
such, 0CFA is a ``monovariant'' analysis, analogous to simple-type
inference, which is a monovariant type analysis.

Since there is only one constant environment (the ``everywhere
$\epsilon$'' environment), environments of \autoref{sec:ai} can be
eliminated from the analysis altogether and the cache no longer needs
a contour argument.  Likewise, the set of abstract values collapses
from $\mathcal{P}(\Term\times\Env)$ into $\mathcal{P}(\Term)$.

The result of 0CFA is an {\em abstract cache} that maps each program
point (i.e., label) to a set of lambda abstractions which potentially
flow into this program point at run-time:
\begin{displaymath}
\begin{array}{ccl}
\cache & : & \Lab \rightarrow \mathcal{P}(\Term) \\
%& \qquad\mbox{abstract 0CFA caches}\\
\aenv & : & \Var \rightarrow \mathcal{P}(\Term)\\
\\
\ACache & = & (\Lab \rightarrow \mathcal{P}(\Term)) \times
              (\Var \rightarrow \mathcal{P}(\Term))  
\end{array}
\end{displaymath}
Caches are extended using the notation $\cache[\ell \mapsto s]$, and
we write $\cache[\ell \mapsto^+ s]$ to mean $\cache[\ell \mapsto
(s\cup \cache(\ell))]$.  It is convenient to sometimes think of caches
as mutable tables (as we do in the algorithm below), so we abuse
syntax, letting this notation mean both functional extension and
destructive update.  It should be clear from context which is implied.

\paragraph{The Analysis:} We present the specification of the analysis
here in the style of Nielson, Nielson, and Hankin
\shortcite{nielson-nielson-hankin}. 
%
Each subexpression is identified with a unique superscript {\em label}
$\ell$, which marks that program point; $\cache(\ell)$ stores all
possible values flowing to point $\ell$, $\aenv(x)$ stores all
possible values flowing to the definition site of $x$.  An {\em
  acceptable} 0CFA analysis for an expression $e$ is written
$\cache,\aenv\models e$ and derived according to the scheme given in
\autoref{fig-0cfa-acceptability}.

\begin{figure}[h]
\begin{displaymath}
\begin{array}{lcl}
\cache,\aenv \models x^\ell &
\mbox{ iff } &
\aenv(x) \subseteq \cache(\ell)\\
%%
\cache,\aenv \models (\lambda x .e)^\ell &
\mbox{ iff } &
\lambda x.e \in \cache(\ell)\\
%%
\cache,\aenv \models (t^{\ell_1}\ t^{\ell_2})^\ell &
\mbox{ iff } &
\cache,\aenv\models t^{\ell_1}\ \wedge
\cache,\aenv\models t^{\ell_2}\ \wedge \\
\ & \ & \quad \forall \lambda x.t^{\ell_0} \in \cache(\ell_1) : \\
\ & \ & \qquad \cache(\ell_2) \subseteq \aenv(x)\ \wedge\ \\
\ & \ & \qquad \cache,\aenv \models t^{\ell_0}\ \wedge \\
\ & \ & \qquad \cache(\ell_0) \subseteq \cache(\ell)
\end{array}
\end{displaymath}
\caption{0CFA abstract cache acceptability.}
\label{fig-0cfa-acceptability}
\end{figure}

The $\models$ relation needs to be coinductively defined since
verifying a judgment $\cache,\aenv \models e$ may obligate
verification of $\cache,\aenv \models e'$ which in turn may require
verification of $\cache,\aenv \models e$.  The above specification of
acceptability, when read as a table, defines a functional, which is
monotonic, has a fixed point, and $\models$ is defined coinductively
as the greatest fixed point of this functional.\footnote{See Nielson,
  Nielson, and Hankin \shortcite{nielson-nielson-hankin} for details
  and a thorough discussion of coinduction in specifying static
  analyses.}

Writing $\cache,\aenv \models t^\ell$ means ``the abstract cache
contains all the flow information for program fragment $t$ at program
point $\ell$.''  The goal is to determine the {\em least} cache
solving these constraints to obtain the most precise analysis.  Caches
are partially ordered with respect to the program of interest:
\begin{displaymath}
\begin{array}{lllcl}
\cache & \sqsubseteq & \cache' & 
\mbox{ iff } & 
\forall \ell : \cache(\ell) \subseteq \cache'(\ell)\\
%%
\aenv & \sqsubseteq & \aenv' & 
\mbox{ iff } & 
\forall x : \aenv(x) \subseteq \aenv'(x)
\end{array}
\end{displaymath}

These constraints can be thought of as an abstract evaluator---
$\cache,\aenv \models t^\ell$ simply means {\em evaluate} $t^\ell$, which
serves {\em only} to update an (initially empty) cache.

\begin{figure}[h]
\begin{displaymath}
\begin{array}{lcl}
\avz{x^\ell} & = & 
\cache(\ell) \leftarrow \aenv(x)\\
%%
\avz{(\lambda x.e)^\ell} & = & 
\cache(\ell) \leftarrow \{ \lambda x.e \}\\
%%
\avz{(t^{\ell_1}\ t^{\ell_2})^\ell} & = & 
\avz{t^{\ell_1}};\ \ \avz{t^{\ell_2}};\\
\ &\ & \mbox{\bf for each }\lambda x.t^{\ell_0} \mbox{\bf\ in\ } \cache(\ell_1)\mbox{\bf\ do }\\
\ &\ &   \quad   \aenv(x) \leftarrow \cache(\ell_2);\\ 
\ &\ &   \quad   \avz{t^{\ell_0}};\\
\ &\ &   \quad   \cache(\ell) \leftarrow \cache(\ell_0)
\end{array}
\end{displaymath}
\caption{Abstract evaluator $\mathcal{A}_0$ for 0CFA, imperative style.}
\label{fig-0cfa-imperative}
\end{figure}

The abstract evaluator $\avz\cdot$ is iterated until the finite cache
reaches a fixed point.

\paragraph{Fine Print:} A single iteration of $\avz{e}$ may in turn
make a recursive call $\avz{e}$ with no change in the cache, so care
must be taken to avoid looping.  This amounts to appealing to the
coinductive hypothesis $\cache,\aenv \models e$ in verifying
$\cache,\aenv \models e$.  However, we consider this inessential
detail, and it can safely be ignored for the purposes of obtaining our
main results in which this behavior is {\em never triggered}.

Since the cache size is polynomial in the program size, so is the
running time, as the cache is {\em monotonic}---values are put in, but
never taken out.  Thus the analysis and any decision problems
answered by the analysis are clearly computable within polynomial
time.

\begin{lemma}
The control flow problem for 0CFA is contained in \ptime.
\end{lemma}
\begin{proof}
0CFA computes a binary relation over a fixed structure.  The
computation of the relation is monotone: it begins as empty and is
added to incrementally.  Because the structure is finite, a fixed
point must be reached by this incremental computation.  The binary
relation can be at most polynomial in size, and each increment is
computed in polynomial time.
\end{proof}


\paragraph{An Example:} 

Consider the following program, which we will return to discuss
further in subsequent analyses:

\begin{displaymath}
((\lambda f.((f^1 f^2)^3(\lambda y.y^4)^5)^6)^7 (\lambda
x.x^8)^9)^{10}
\end{displaymath}

The least 0CFA is given by the following cache:
\begin{displaymath}
\begin{array}{l@{\:=\:}l@{\hspace{10pt}}l@{\:=\:}l}
\cache(1) & \{ \lambda x \} &
\cache(6) & \{ \lambda x, \lambda y \} \\
\cache(2) & \{ \lambda x \} &
\cache(7) & \{ \lambda f \} \\
\cache(3) & \{ \lambda x, \lambda y \} &
\cache(8) & \{ \lambda x, \lambda y \} \\
\cache(4) & \{ \lambda y \} &
\cache(9) & \{ \lambda x \} \\
\cache(5) & \{ \lambda y \} &
\cache(10)& \{ \lambda x, \lambda y \}
\end{array}
\hspace{10pt}
\begin{array}{l@{\:=\:}l}
\aenv(f) & \{ \lambda x \} \\
\aenv(x) & \{ \lambda x, \lambda y \}\\
\aenv(y) & \{ \lambda y \}
\end{array}
\end{displaymath}
where we write $\lambda x$ as shorthand for $\lambda x.x^8$, etc.


\subsection{Henglein's Simple Closure Analysis}
\label{sec:simple}

Simple closure analysis follows from an observation by Henglein some
15 years ago ``in an influential though not often credited technical
report'' [page 4] \cite{midtgaard-07}: he noted that the standard
control flow analysis can be computed in dramatically less time by
changing the specification of flow constraints to use equality rather
than containment \cite{henglein92d}.  The analysis bears a strong
resemblance to simple-type inference---analysis can be performed by
emitting a system of equality constraints and then solving them using
{\em unification}, which can be computed in almost linear time with a
union-find data structure.

Consider a program with both $(f\;x)$ and $(f\;y)$ as subexpressions.
Under 0CFA, whatever flows into $x$ and $y$ will also flow into the
formal parameter of all abstractions flowing into $f$, but it is not
necessarily true that whatever flows into $x$ {\em also} flows into
$y$ and {\em vice versa}.  However, under simple closure analysis,
this is the case.  For this reason, flows in simple closure analysis
are said to be {\em bidirectional}.

\paragraph{The Analysis:} 

The specification of the analysis is given in
\autoref{fig-simple-declarative}.

\begin{figure}[h]
\begin{displaymath}
\begin{array}{lcl}
\cache,\aenv \models x^\ell & 
\mbox{ iff } &
\aenv(x) = \cache(\ell)\\
%%
\cache,\aenv \models (\lambda x .e)^\ell &
\mbox{ iff } &
\lambda x.e \in \cache(\ell)\\
%% 
\cache,\aenv \models (t^{\ell_1}\ t^{\ell_2})^\ell & 
\mbox{ iff } &
\cache,\aenv \models t^{\ell_1} \wedge \cache,\aenv \models t^{\ell_2}\ \wedge\\
\ & \ & \quad \forall \lambda x.t^{\ell_0} \in \cache(\ell_1) : \\
\ & \ & \qquad \cache(\ell_2) = \aenv(x)\ \wedge\\
\ & \ & \qquad \cache,\aenv \models t^{\ell_0}\ \wedge \\
\ & \ & \qquad \cache(\ell_0) = \cache(\ell)
\end{array}
\end{displaymath}
\caption{Simple closure analysis abstract cache acceptability.}
\label{fig-simple-declarative}
\end{figure}

\paragraph{The Algorithm:} 

We write $\cache[\ell \leftrightarrow \ell']$ to mean
$\cache[\ell\mapsto^+ \cache(\ell')][\ell'\mapsto^+ \cache(\ell)]$.

\begin{displaymath}
\begin{array}{lcl}
\avz{x^\ell}               & = & \cache(\ell) \leftrightarrow \aenv(x) \\
\avz{(\lambda x.e)^\ell} & = & \cache(\ell) \leftarrow \{ \lambda x.e \}\\
\avz{(t^{\ell_1}_1 t^{\ell_2}_2)^\ell} & = & \avz{t^{\ell_1}_1};\ \ \avz{t^{\ell_2}_2};\\
\ &\ & \mbox{\bf for each }\lambda x.t^{\ell_0}_0 \mbox{\bf\ in\ } \cache(\ell_1)\mbox{\bf\ do }\\
\ &\ & \quad \aenv(x)\leftrightarrow\cache(\ell_2);\\
\ &\ & \quad \avz{t^{\ell_0}_0};\\
\ &\ & \quad \cache(\ell)\leftrightarrow\cache(\ell_0)
\end{array}
\end{displaymath}
The abstract evaluator $\avz\cdot$ is iterated until a fixed point
is reached.\footnote{The fine print of \autoref{sec:0cfa} applies as
well.}  By similar reasoning to that given for 0CFA, simple closure
analysis is clearly computable within polynomial time.

\begin{lemma}
The control flow problem for simple closure analysis is contained in \ptime.
\end{lemma}

\paragraph{An Example:}

Recall the example program of the previous section:
\begin{displaymath}
((\lambda f.((f^1 f^2)^3(\lambda y.y^4)^5)^6)^7 (\lambda
x.x^8)^9)^{10}
\end{displaymath}

Notice that $\lambda x.x$ is applied to itself and then to $\lambda
y.y$, so $x$ will be bound to both $\lambda x.x$ and $\lambda y.y$,
which induces an equality between these two terms.  Consequently,
everywhere that 0CFA was able to deduce a flow set of $\{ \lambda x
\}$ or $\{ \lambda y \}$ will be replaced by $\{ \lambda x, \lambda y
\}$ under a simple closure analysis.  The least simple closure
analysis is given by the following cache (new flows are underlined):
\begin{displaymath}
\begin{array}{l@{\:=\:}l@{\hspace{10pt}}l@{\:=\:}l}
\cache(1) & \{ \lambda x, \underline{\lambda y} \} &
\cache(6) & \{ \lambda x, \lambda y \} \\
\cache(2) & \{ \lambda x, \underline{\lambda y} \} &
\cache(7) & \{ \lambda f \} \\
\cache(3) & \{ \lambda x, \lambda y \} &
\cache(8) & \{ \lambda x, \lambda y \} \\
\cache(4) & \{ \lambda y, \underline{\lambda x} \} &
\cache(9) & \{ \lambda x, \underline{\lambda y} \} \\
\cache(5) & \{ \lambda y, \underline{\lambda x} \} &
\cache(10)& \{ \lambda x, \lambda y \}
\end{array}
\hspace{10pt}
\begin{array}{l@{\:=\:}l}
\aenv(f) & \{ \lambda x, \underline{\lambda y} \} \\
\aenv(x) & \{ \lambda x, \lambda y \}\\
\aenv(y) & \{ \lambda y, \underline{\lambda x} \}
\end{array}
\end{displaymath}

\subsection{Linearity: Analysis is Evaluation}
\label{sec:linearity}

It is straightforward to observe that in a {\em linear}
$\lambda$-term, each abstraction $\lambda x.e$ can be applied to at
most one argument, and hence the abstracted value can be bound to at
most one argument.\footnote{Note that this observation is clearly
untrue for the {\em nonlinear} $\lambda$-term $(\lambda f.f (a (f b)))
(\lambda x.x)$, as $x$ is bound to $b$, and also to $ab$.}
Generalizing this observation, analysis of a linear $\lambda$-term
coincides exactly with its evaluation.  So not only are the analyses
equivalent on linear terms, but they are also synonymous with
evaluation.

A natural and expressive class of such linear terms are the ones which
implement Boolean logic.  When analyzing the coding of a Boolean
circuit and its inputs, the Boolean output will flow to a
predetermined place in the (abstract) cache.  By placing that value in
an appropriate context, we construct an instance of the control flow
problem: a function $f$ flows to a call site $a$ iff the Boolean
output is $\True$.

Since the circuit value problem \cite{ladner-75}, which is complete
for \ptime, can be reduced to an instance of the 0CFA control flow
problem, we conclude this control flow problem is \ptime-hard.
Further, as 0CFA can be computed in polynomial time, the control flow
problem for 0CFA is \ptime-complete.


One way to realize the computational potency of a static analysis is
to subvert this loss of information, making the analysis an {\em
exact} computational tool.  Lower bounds on the expressiveness of an
analysis thus become exercises in hacking, armed with this newfound
tool.  Clearly the more approximate the analysis, the less we have to
work with, computationally speaking, and the more we have to do to
undermine the approximation.  But a fundamental technique has emerged
in understanding expressivity in static analysis---{\em linearity}.


In this section, we show that when the program is {\em linear}---every
bound variable occurs exactly once---analysis and evaluation are
synonymous.

First, we start by considering an alternative evaluator, given in
\autoref{figure-eval-alt}, which is slightly modified from the one
given in \autoref{figure-eval}.  Notice that this evaluator
``tightens'' the environment in the case of an application, thus
maintaining throughout evaluation that the domain of the environment
is exactly the set of free variables in the expression.  When
evaluating a variable occurrence, there is only one mapping in the
environment: the binding for this variable. Likewise, when
constructing a closure, the environment does not need to be
restricted: it already is.


\begin{figure}
\begin{displaymath}
\begin{array}{lcl}
\evalf['] & : & \Exp \times \Env \rightharpoonup \Val\\
\\
\eval[']{x^\ell}[x \mapsto v]   & = & v\\
\eval[']{(\lambda x.e)^\ell}\rho & = & \langle\lambda x.e,\rho\rangle \\
\eval[']{(e_1\ e_2)^\ell}\rho & = &
       \mbox{\bf let }\langle\lambda x.e_0,\rho'\rangle = 
                      \eval[']{e_1}\rho\restrict\fv{e_1}\mbox{\bf\ in }\\
\ &\ & \mbox{\bf let }v = 
                      \eval[']{e_2}\rho\restrict\fv{e_2}\mbox{\bf\ in }\\
\ &\ &   \quad   \eval[']{e_0}{\rho'[x \mapsto v]}
\end{array}
\end{displaymath}
\caption{Evaluator $\evalf[']$.}
\label{figure-eval-alt}
\end{figure}

% We use $\rho$ to range over {\em environments}, $\Env = \Var
% \rightharpoonup \langle\Term,\Env\rangle$, and let $v$ range over {\em
% closures}, each comprising a term and an environment that closes the
% term.  

This alternative evaluator $\evalf[']$ will be useful in reasoning
about linear programs, but it should be clear that it is equivalent to
the original, standard evaluator $\evalf$ of \autoref{figure-eval}.

\begin{lemma}
$\eval{e}\rho \Longleftrightarrow \eval[']{e}\rho$, when $\dom{\rho} = \fv{e}$.
\end{lemma}

In a linear program, each mapping in the environment corresponds to
the single occurrence of a bound variable.  So when evaluating an
application, this tightening {\em splits} the environment $\rho$ into
$(\rho_1,\rho_2)$, where $\rho_1$ closes the operator, $\rho_2$ closes
the operand, and $\dom{\rho_1} \cap \dom{\rho_2} = \emptyset$.

\begin{definition}
Environment $\rho$ {\em linearly closes} $t$ (or $\langle
t,\rho\rangle$ is a {\em linear closure}) iff $t$ is linear, $\rho$
closes $t$, and for all $x\in\dom{\rho}$, $x$ occurs exactly once
(free) in $t$, $\rho(x)$ is a linear closure, and for all
$y\in\dom{\rho}, x$ does not occur (free or bound) in $\rho(y)$. The
{\em size} of a linear closure $\langle t,\rho\rangle$ is defined as:
\begin{eqnarray*}
|t,\rho| & = & |t|+|\rho|\\
|x| & = & 1\\
|(\lambda x.t^\ell)| & = & 1+|t|\\
|(t_1^{\ell_1}\; t_2^{\ell_2})| & = & 1+|t_1|+|t_2|\\
|[x_1\mapsto c_1,\dots,x_n\mapsto c_n]| & = & n+\sum_i |c_i|
\end{eqnarray*}
\end{definition}

The following lemma states that evaluation of a linear closure cannot
produce a larger value.  This is the environment-based analog to the
easy observation that $\beta$-reduction {\em strictly} decreases the
size of a linear term.
\begin{lemma}\label{lem:smaller}
If $\rho$ linearly closes $t$ and $\eval[']{t^\ell}\rho = c$, then
$|c|\leq|t,\rho|$.
\end{lemma}
\begin{proof}
Straightforward by induction on $|t,\rho|$, reasoning by case analysis
on $t$.  Observe that the size strictly decreases in the application
and variable case, and remains the same in the abstraction case.
\end{proof}

The function $\lab{\cdot}$ is extended to closures and environments by
taking the union of all labels in the closure or in the range of the
environment, respectively.

\begin{definition}
The set of labels in a given term, expression, environment, or closure
is defined as follows:
\begin{displaymath}
\begin{array}{rcl@{\qquad}rcl}
  \lab{t^\ell}      &=& \lab{t}\cup\{\ell\}      & 
  \lab{e_1\;e_2}    &=& \lab{e_1} \cup \lab{e_2} \\
  \lab{x}           &=& \{x\}                    & 
  \lab{\lambda x.e} &=& \lab{e}\cup\{x\}         \\
  \lab{t,\rho}      &=& \lab{t}\cup\lab{\rho}   & 
  \lab{\rho}        &=& \bigcup_{x\in\dom\rho} \lab{\rho(x)}
\end{array}
\end{displaymath}
\end{definition}

\begin{definition}
  A cache $\cache,\aenv$ {\em respects} $\langle t,\rho\rangle$
  (written $\cache,\aenv\loves t,\rho$) when,
\begin{enumerate}
\item $\rho$ linearly closes $t$,
%
\item $\forall x \in \dom{\rho} . \rho(x) = \langle t',\rho'\rangle
\Rightarrow \aenv(x) = \{t'\} \mbox { and } \cache,\aenv\loves t',\rho'$,
%
\item $\forall \ell \in \lab{t}, \cache(\ell) = \emptyset$, and
%
\item $\forall x \in \bv{t}, \aenv(x) = \emptyset$.
\end{enumerate}
\end{definition}
Clearly, $\emptyset\loves t,\emptyset$ when $t$ is closed and linear,
i.e.~$t$ is a linear 

\begin{figure}[h]
\begin{displaymath}
\begin{array}{lcl}
\avf_0 & : & \Exp \times \ACache\rightarrow \ACache\\ 
\\
%%%%%%%%%%%%%%%%%%
%% Var
\avz{x^\ell}\;\cache,\aenv & = & 
\cache[\ell \mapsto \aenv(x)], \aenv\\
%%%%%%%%%%%%%%%%%%
%% Lam
\avz{(\lambda x.e)^\ell}\;\cache,\aenv & = & 
\cache[\ell \mapsto \{\lambda x.e\}], \aenv\\
%%%%%%%%%%%%%%%%%%
%% App
\avz{(t^{\ell_1}\ t^{\ell_2})^\ell}\;\cache,\aenv & = &
\cache_3[\ell\mapsto \cache_3(\ell_0)],\aenv_3,\mbox{ where}\\
\ &\ &\begin{array}{lcl}
  \delta' & = & \lceil\delta\ell\rceil_k\\
  \cache_1,\aenv_1 & = & \avz{t^{\ell_1}}\;\cache,\aenv\\
  \cache_2,\aenv_2 & = & \avz{t^{\ell_2}}\;\cache_1,\aenv_1\\
  \cache_3,\aenv_3 & = & \\
\multicolumn{3}{c}{
\bigsqcup\nolimits_{\lambda x.t^{\ell_0}}^{\cache_2(\ell)}
\left(\avz{t^{\ell_0}}\;\cache_2,\aenv_2[x\mapsto \cache_2(\ell_2)]\right)}
\end{array}
\end{array}
\end{displaymath}
\caption{Abstract evaluator $\mathcal{A}_0$ for 0CFA, functional style.}
\label{fig-0cfa-functional}
\end{figure}

\autoref{fig-0cfa-functional} gives a ``cache-passing'' functional
algorithm for $\avz{\cdot}$ of \autoref{sec:simple}.  It is equivalent
to the functional style abstract evaluator of
\autoref{fig-a-functional} specialized by letting $k = 0$.
%
We now state and prove the main theorem of this section in terms of
this abstract evaluator.

\begin{theorem}\label{thm:main}
  If $\cache,\aenv\loves t,\rho$, $\cache(\ell)=\emptyset$,
  $\ell\notin\lab{t,\rho}$, $\eval[']{t^\ell}{\rho} = \langle
  t',\rho'\rangle$, and $\avz{t^\ell}{\cache,\aenv} = \cache',\aenv'$,
  then $\cache'(\ell) = \{ t' \}$, $\cache'\loves t',\rho'$, and
  $\cache',\aenv'\models t^\ell$.
\end{theorem}
An important consequence is noted in Corollary \ref{cor:normal}.

\begin{proof} By induction on $|t,\rho|$, reasoning by case analysis on $t$.
\begin{itemize}
\item Case $t\equiv x$.

Since $\cache\loves x,\rho$ and $\rho$ linearly closes $x$, thus $\rho
= [x\mapsto \langle t',\rho'\rangle]$ and $\rho'$ linearly closes
$t'$.  By definition,
\begin{eqnarray*}
\eval[']{x^\ell}\rho &=& \langle t',\rho'\rangle, \mbox{ and}\\
\avz{x^\ell}\cache &=& \cache[x\leftrightarrow \ell].
\end{eqnarray*}
Again since $\cache\loves x,\rho$, $\cache(x) = \{t'\}$, with which the
assumption $\cache(\ell)=\emptyset$ implies
\begin{displaymath}
\cache[x\leftrightarrow\ell](x) =
\cache[x\leftrightarrow\ell](\ell) = 
\{t'\},
\end{displaymath}
and therefore $\cache[x\leftrightarrow\ell]\models x^\ell$.  It
remains to show that $\cache[x\leftrightarrow\ell]\loves t',\rho'$.
By definition, $\cache\loves t',\rho'$.  Since $x$ and $\ell$ do not
occur in $t',\rho'$ by linearity and assumption, respectively, it
follows that $\cache[x\mapsto\ell]\loves t',\rho'$ and the case
holds.

\item Case $t\equiv \lambda x.e_0$.

By definition,
\begin{eqnarray*}
\eval[']{(\lambda x.e_0)^\ell}\rho & = & \langle\lambda x.e_0,\rho\rangle,\\
\avz{(\lambda x.e_0)^\ell}\cache & = & \cache[\ell\mapsto^+ \{\lambda x.e_0\}],
\end{eqnarray*}
and by assumption $\cache(\ell) = \emptyset$, so $\cache[\ell\mapsto^+
\{\lambda x.e_0\}](\ell) = \{\lambda x.e_0\}$ and therefore
$\cache[\ell\mapsto^+ \{\lambda x.e_0\}]\models (\lambda x.e_0)^\ell$.
By assumptions $\ell\notin\lab{\lambda x.e_0,\rho}$ and
$\cache\loves\lambda x.e_0,\rho$, it follows that
$\cache[\ell\mapsto^+ \{\lambda x.e_0\}]\loves\lambda x.e_0,\rho$ and
the case holds.

\item Case $t\equiv t_1^{\ell_1}\; t_2^{\ell_2}$. Let
\begin{eqnarray*}
\eval[']{t_1}\rho\restrict\fv{t_1^{\ell_1}} &=& \langle v_1,\rho_1\rangle = \langle\lambda x.t_0^{\ell_0},\rho_1\rangle,\\
\eval[']{t_2}\rho\restrict\fv{t_2^{\ell_2}} &=& \langle v_2,\rho_2\rangle,\\
\avz{t_1}\cache &=& \cache_1, \mbox{ and}\\
\avz{t_2}\cache &=& \cache_2.
\end{eqnarray*}
Clearly, for $i \in \{1,2\}$, $\cache\loves t_i,\rho\restrict\fv{t_i}$ and
\begin{eqnarray*}
1+\sum_i |t_i^{\ell_i},\rho\restrict\fv{t_i^{\ell_i}}| &=& |(t_1^{\ell_1}\;t_2^{\ell_2}),\rho|.
\end{eqnarray*}

By induction, for $i\in\{1,2\} : \cache_i(\ell_i) = \{v_i\},
\cache_i\loves\langle v_i,\rho_i\rangle,$ and $\cache_i\models
t_i^{\ell_i}$.  From this, it is straightforward to observe that
$\cache_1 = \cache \cup \cache'_1$ and $\cache_2 = \cache \cup
\cache'_2$ where $\cache'_1$ and $\cache'_2$ are disjoint.  So let
$\cache_3 = (\cache_1 \cup \cache_2)[x\leftrightarrow \ell_2]$.  It is
clear that $\cache_3\models t_i^{\ell_i}$.  Furthermore,
\begin{eqnarray*}
\cache_3 &\loves& t_0,\rho_1[x\mapsto \langle v_2,\rho_2\rangle],\\
\cache_3(\ell_0) &=& \emptyset,\mbox{ and}\\
\ell_0 &\notin& \lab{t_0,\rho_1[x\mapsto \langle v_2,\rho_2\rangle]}.
\end{eqnarray*}

By Lemma \ref{lem:smaller},
$|v_i,\rho_i| \leq |t_i,\rho\restrict\fv{t_i}|$, therefore 
\begin{eqnarray*}
|t_0,\rho_1[x\mapsto \langle v_2,\rho_2\rangle]| &<& |(t_1^{\ell_1}\;t_2^{\ell_2})|.
\end{eqnarray*}
Let
\begin{eqnarray*}
\eval[']{t_0^{\ell_0}}\rho_1[x\mapsto \langle v_2,\rho_2\rangle] &=& \langle v',\rho'\rangle,\\
\avz{t_0^{\ell_0}}\cache_3 &=& \cache_4,
\end{eqnarray*}
and by induction, $\cache_4(\ell_0) = \{v'\}$, $\cache_4\loves
v',\rho'$, and $\cache_4\models v'$.  Finally, observe that
$\cache_4[\ell\leftrightarrow\ell_0](\ell) =
\cache_4[\ell\leftrightarrow\ell_0](\ell_0) = \{v'\}$,
$\cache_4[\ell\leftrightarrow\ell_0]\loves v',\rho'$, and
$\cache_4[\ell\leftrightarrow\ell_0]\models
(t_1^{\ell_1}\;t_2^{\ell_2})^\ell$, so the case holds.
\end{itemize}
\end{proof}
We can now establish the correspondence between analysis and
evaluation.

\begin{corollary}\label{cor:normal}
If $\cache$ is the simple closure analysis of a linear program
$t^\ell$, then $\eval[']{t^\ell}\emptyset = \langle v,\rho'\rangle$ where
$\cache(\ell) = \{v\}$ and $\cache\loves v,\rho'$.
\end{corollary}

By a simple replaying of the proof substituting the containment
constraints of 0CFA for the equality constraints of simple closure
analysis, it is clear that the same correspondence can be established,
and therefore 0CFA and simple closure analysis are identical for
linear programs.

\begin{corollary}
If $e$ is a linear program, then $\cache$ is the simple closure
analysis of $e$ iff $\cache$ is the 0CFA of $e$.
\end{corollary}

\paragraph{Discussion:}

Returning to our earlier question of the computationally potent
ingredients in a static analysis, we can now see that when the term is
linear, whether flows are directional and bidirectional is irrelevant.
For these terms, simple closure analysis, 0CFA, and evaluation are
equivalent.  And, as we will see, when an analysis is {\em exact} for
linear terms, the analysis will have a \ptime-hardness bound.
%% The key to designing sub-\ptime\ analyses therefore is to do something
%% less precise on linear terms.


\subsection{Lower Bounds for Flow Analysis}
\label{sec:circuits}


There are at least two fundamental ways to reduce the complexity of
analysis.  One is to compute more approximate answers, the other is to
analyze a syntactically restricted language.

We use {\em linearity} as the key ingredient in proving lower bounds
on analysis.  This shows not only that simple closure analysis and
other flow analyses are \ptime-complete, but the result is rather
robust in the face of analysis design based on syntactic restrictions.
This is because we are able to prove the lower bound via a highly
restricted programming language---the linear $\lambda$-calculus.  So
long as the subject language of an analysis includes the linear
$\lambda$-calculus, and is exact for this subset, the analysis must be
at least \ptime-hard.

The decision problem answered by flow analysis, described in
\autoref{chap:foundations}, is formulated for monovariant analyses as
follows:
\begin{description}
\item[Flow Analysis Problem:] Given a closed expression $e$, a term
$v$, and label $\ell$, is $v \in \cache(\ell)$ in the analysis of $e$?
\end{description}

\begin{theorem}
If analysis corresponds to evaluation on linear terms, it is
\ptime-hard.
\end{theorem}
The proof is by reduction from the canonical \ptime-complete problem
of circuit evaluation \cite{ladner-75}:
\begin{description}
\item[Circuit Value Problem:] Given a Boolean circuit $C$ of $n$
inputs and one output, and truth values $\vec{x} = x_1,\dots,x_n$, is
$\vec{x}$ accepted by $C$?
\end{description}

An instance of the circuit value problem can be compiled, using only
logarithmic space, into an instance of the flow analysis problem.  The
circuit and its inputs are compiled into a linear $\lambda$-term,
which simulates $C$ on $\vec{x}$ via {\em evaluation}---it normalizes
to true if $C$ accepts $\vec{x}$ and false otherwise.  But since the
analysis faithfully captures evaluation of linear terms, and our
encoding is linear, the circuit can be simulated by flow analysis.

The encodings work like this: \TT\ is the identity on pairs, and \FF\
is the swap.  Boolean values are either $\langle\TT,\FF\rangle$ or
$\langle\FF,\TT\rangle$, where the first component is the ``real''
value, and the second component is the complement.  
\begin{displaymath}
\begin{array}{rcl@{\qquad}rcl}
\TT & \equiv & \lambda p . \mbox{let }\langle x,y \rangle = p\mbox{ in } \langle x, y\rangle &
\True & \equiv &\langle \TT,\FF \rangle\\
\FF & \equiv & \lambda p . \mbox{let }\langle x,y \rangle = p\mbox{ in } \langle y, x\rangle &
\False & \equiv &\langle \FF,\TT \rangle
\end{array}
\end{displaymath}

The simplest connective is \Not, which is an inversion on pairs, like
\FF.  A {\em linear} copy connective is defined as:
\begin{eqnarray*}
\Copy & \equiv & \lambda b.\mbox{let }\langle u,v\rangle = b\mbox{ in }
\langle u\langle \TT,\FF\rangle, v\langle \FF,\TT\rangle\rangle.
\end{eqnarray*}
The coding is easily explained: suppose $b$ is \True, then $u$ is
identity and $v$ twists; so we get the pair
$\langle\True,\True\rangle$.  Suppose $b$ is \False, then $u$ twists
and $v$ is identity; we get $\langle\False,\False\rangle$.  We write
$\Copy_n$ to mean $n$-ary fan-out---a straightforward extension of the
above.

The \AND\ connective is defined as follows:
\begin{displaymath}
\begin{array}{rcl}
\AND & \equiv & \lambda b_1.\lambda b_2.\\
\ & \ & \quad\mbox{let }\langle u_1,v_1\rangle = b_1\mbox{ in}\\
\ & \ & \quad\mbox{let }\langle u_2,v_2\rangle = b_2\mbox{ in}\\
\ & \ & \quad\mbox{let }\langle p_1,p_2\rangle = u_1\langle u_2, \FF\rangle \mbox{ in}\\
\ & \ & \quad\mbox{let }\langle q_1,q_2\rangle = v_1\langle \TT, v_2\rangle \mbox{ in}\\
\ & \ & \qquad\langle p_1, q_1 \circ p_2 \circ q_2 \circ \FF \rangle.
\end{array}
\end{displaymath}
Conjunction works by computing pairs $\langle p_1,p_2\rangle$ and
$\langle q_1,q_2\rangle$.  The former is the usual conjunction on the
first components of the Booleans $b_1,b_2$: $u_1\langle u_2,
\FF\rangle$ can be read as ``if $u_1$ then $u_2$, otherwise false
(\FF).''  The latter is (exploiting De Morgan duality) the disjunction
of the complement components of the Booleans:
$v_1\langle\TT,v_2\rangle$ is read as ``if $v_1$ (i.e.~if not $u_1$)
then true (\TT), otherwise $v_2$ (i.e.~not $u_2$).''  The result of
the computation is equal to $\langle p_1,q_1\rangle$, but this leaves
$p_2,q_2$ unused, which would violate linearity.  However, there is
symmetry to this {\em garbage}, which allows for its disposal.  Notice
that, while we do not know whether $p_2$ is \TT\ or \FF\ and similarly
for $q_2$, we do know that {\em one of them is \TT\ while the other is
  \FF}.  Composing the two together, we are guaranteed that $p_2 \circ
q_2 = \FF$.  Composing this again with another twist (\FF) results in
the identity function $p_2 \circ q_2 \circ \FF = \TT$.  Finally,
composing this with $q_1$ is just equal to $q_1$, so $\langle p_1, q_1
\circ p_2 \circ q_2 \circ \FF \rangle = \langle p_1, q_1\rangle$,
which is the desired result, but the symmetric garbage has been {\em
  annihilated}, maintaining linearity.

Similarly, we define truth-table implication:
\begin{displaymath}
\begin{array}{rcl}
\Implies & \equiv & \lambda b_1.\lambda b_2.\\
\ & \ & \quad\mbox{let }\langle u_1,v_1\rangle = b_1\mbox{ in}\\
\ & \ & \quad\mbox{let }\langle u_2,v_2\rangle = b_2\mbox{ in}\\
\ & \ & \quad\mbox{let }\langle p_1,p_2\rangle = u_1\langle u_2, \TT\rangle \mbox{ in}\\
\ & \ & \quad\mbox{let }\langle q_1,q_2\rangle = v_1\langle \FF, v_2\rangle \mbox{ in}\\
\ & \ & \qquad\langle p_1, q_1 \circ p_2 \circ q_2 \circ \FF \rangle
\end{array}
\end{displaymath}
Let us work through the construction once more: Notice that if $b_1$
is \True, then $u_1$ is \TT, so $p_1$ is \TT\ iff $b_2$ is \True.  And
if $b_1$ is \True, then $v_1$ is \FF, so $q_1$ is \FF\ iff $b_2$ is
\False.  On the other hand, if $b_1$ is \False, $u_1$ is \FF, so $p_1$
is \TT, and $v_1$ is \TT, so $q_1$ is \FF.  Therefore $\langle
p_1,q_1\rangle$ is \True\ iff $b_1 \supset b_2$, and \False\
otherwise. Or, if you prefer, $u_1 \langle u_2,\TT\rangle$ can be read
as ``if $u_1$, then $u_2$ else $\TT$''---the if-then-else description
of the implication $u_1\supset u_2$ ---and $v_1 \langle \FF,
v_2\rangle$ as its De Morgan dual $\neg(v_2\supset v_1)$.  Thus
$\langle p_1,q_1\rangle$ is the answer we want---and we need only
dispense with the ``garbage'' $p_2$ and $q_2$.  De Morgan duality
ensures that one is $\TT$, and the other is $\FF$ (though we do not
know which), so they always compose to $\FF$.

However, simply returning $\langle p_1,q_1\rangle$ violates linearity since
$p_2,q_2$ go unused.  We know that $p_2 = \TT$ iff $q_2 = \FF$ and
$p_2 = \FF$ iff $q_2 = \TT$.  We do not know which is which, but
clearly $p_2 \circ q_2 = \FF\circ\TT = \TT\circ\FF = \FF$.  Composing $p_2\circ
q_2$ with $\FF$, we are guaranteed to get $\TT$.  Therefore $q_1
\circ p_2 \circ q_2 \circ \FF = q_1$, and we have used all bound
variables exactly once.

This hacking, with its self-annihilating garbage, is an improvement
over that given by Mairson \shortcite{mairson-jfp04} and allows
Boolean computation without K-redexes, making the lower bound
stronger, but also preserving all flows.  In addition, it is the best
way to do circuit computation in multiplicative linear logic, and is
how you compute similarly in non-affine typed $\lambda$-calculus
\cite{mairson-geocal06}.

By writing continuation-passing style variants of the logic gates, we
can encode circuits that look like straight-line code.  For example,
define CPS logic gates as follows:
\begin{eqnarray*}
  \Andgate  & \equiv & \lambda b_1.\lambda b_2.\lambda k.k(\AND\;b_1\;b_2)\\
  \Orgate   & \equiv & \lambda b_1.\lambda b_2.\lambda k.k(\Or\;b_1\;b_2)\\
  \Implgate & \equiv & \lambda b_1.\lambda b_2.\lambda k.k(\Implies\;b_1\;b_2)\\
  \Notgate  & \equiv & \lambda b.\lambda k. k(\Not\;b)\\
  \Copygate & \equiv & \lambda b.\lambda k.k(\Copy\;b)
\end{eqnarray*}

Continuation-passing style code such as $\Andgate\;b_1\;b_2\;(\lambda
r. e)$ can be read colloquially as a kind of low-level, straight-line
assembly language: ``compute the $\AND$ of registers $b_1$ and $b_2$,
write the result into register $r$, and goto $e$.''

\begin{figure} 
  \centering 
  \includegraphics{figure.18}
  \caption{An example circuit.}
  \label{fig-circuit}
\end{figure}

An example circuit is given in \autoref{fig-circuit}, which can be
encoded as:
\begin{eqnarray*}
\mbox{\tt Circuit} & \equiv & 
\lambda e_1.\lambda e_2.\lambda e_3\lambda e_4.\lambda e_5.\lambda e_6.\\
& & \Andgate\; e_2\; e_3\; (\lambda e_7.\\
& & \Andgate\; e_4\; e_5\; (\lambda e_8.\\
& & \Copygate\; f\; (\lambda e_9.\lambda e_{10}.\\
& & \Orgate\; e_1\; e_9\; (\lambda e_{11}.\\
& & \Orgate\; e_{10}\; e_6\; (\lambda e_{12}.\\
& & \Orgate\; e_{11}\; e_{12}\; (\lambda o.o))))))
\end{eqnarray*}
Notice that each variable in this CPS encoding corresponds to a wire
in the circuit.

The above code says:
\begin{itemize} 
\item compute the \AND\ of $e_2$ and $e_3$, putting the result in
  register $e_7$,
\item compute the \AND\ of $e_4$ and $e_5$, putting the result in
  register $e_8$,
\item compute the \AND\ of $e_7$ and $e_8$, putting the result in
  register $f$,
\item make two copies of register $f$, putting the values in registers
  $e_9$ and $e_{10}$,
\item compute the \Or\ of $e_1$ and $e_9$, putting the result in
  register $e_{11}$,
\item compute the \Or\ of $e_{10}$ and $e_6$, putting the result in
  register $e_{12}$,
\item compute the \Or\ of $e_{11}$ and $e_{12}$, putting the result in
  the $o$ (``output'') register.
\end{itemize}

We know from corollary~\ref{cor:normal} that evaluation and analysis
of linear programs are synonymous, and our encoding of circuits will
faithfully simulate a given circuit on its inputs, evaluating to true
iff the circuit accepts its inputs.  But it does not immediately
follow that the circuit value problem can be reduced to the flow
analysis problem.  Let $||C,\vec{x}||$ be the encoding of the circuit
and its inputs.  It is tempting to think the instance of the flow
analysis problem could be stated:
\begin{center}
is \True\ in $\cache(\ell)$ in the analysis
of $||C,\vec{x}||^\ell$?
\end{center}
The problem with this is there may be many syntactic instances of
``\True.''  Since the flow analysis problem must ask about a particular
one, this reduction will not work.  The fix is to use a context which
expects a Boolean expression and induces a particular flow (that can
be asked about in the flow analysis problem) iff that expression
evaluates to a true value.

We use The Widget to this effect.  It is a term expecting a Boolean
value.  It evaluates as though it were the identity function on
Booleans, $\Widget\; b = b$, but it induces a specific flow we can ask
about. If a true value flows out of $b$, then $\True_W$ flows out of
$\Widget\; b$.  If a false value flows out of $b$, then $\False_W$
flows out of $\Widget\; b$, where $\True_W$ and $\False_W$ are
distinguished terms, and the only possible terms that can flow out.
We usually drop the subscripts and say ``does \True\ flow out of
$\Widget\; b$?''  without much ado.
\begin{eqnarray*}
\Widget & \equiv & \lambda b.\\
\ & \ & \quad \mbox{let }\langle u,v\rangle = b\mbox{ in}\\
\ & \ & \quad \mbox{let }\langle x,y\rangle = u\langle f,g\rangle\mbox{ in}\\
\ & \ & \quad \mbox{let }\langle x',y'\rangle = u'\langle f',g'\rangle\mbox{ in}\\
\ & \ & \qquad \langle\langle x a, y n\rangle, \langle x' a', y' b'\rangle\rangle
\end{eqnarray*}

%% Affine widget from SAS.
%% \begin{eqnarray*}
%% \Widget & \equiv & \lambda b.\mbox{let }\langle u,v\rangle=b\mbox{ in }
%% \pi_1 (u\langle\True_W,\False_W\rangle)
%% \end{eqnarray*}

Because the circuit value problem is complete for \ptime, we
conclude:

\begin{theorem}
The control flow problem for 0CFA is complete for \ptime.
\end{theorem}

\begin{corollary}
The control flow problem for simple closure analysis is complete for \ptime.
\end{corollary}

\subsection{Other Monovariant Analyses}

In this section, we survey some of the existing monovariant analyses
that either approximate or restrict 0CFA to obtain faster analysis
times.  In each case, we sketch why these analyses are complete for
\ptime.

Shivers \shortcite{shivers-sigplan04} noted in his retrospective on
control flow analysis that ``in the ensuing years [since 1988],
researchers have expended a great deal of effort deriving clever ways
to tame the cost of the analysis.''  Such an effort prompts a
fundamental question: to what extent is this possible?

Algorithms to compute 0CFA were long believed to be at least cubic in
the size of the program, proving impractical for the analysis of large
programs, and Heintze and McAllester
\shortcite{heintze-mcallester-lics97} provided strong evidence to
suggest that in general, this could not be improved.  They reduced the
problem of computing 0CFA to that of deciding two-way nondeterministic
push-down automata acceptance (2NPDA); a problem whose best known
algorithm was cubic and had remained so since its discovery
\cite{aho-hopcroft-ullman-ic68}---or so it was believed; see
\autoref{sec-2npda} for a discussion.

In the face of this likely insurmountable bottleneck, researchers
derived ways of further approximating 0CFA, thereby giving up
information in the service of quickly computing a necessarily less
precise analysis in order to avoid the ``cubic bottleneck.''

Such further approximations enjoy linear or near linear algorithms and
have become widely used for the analysis of large programs where the
more precise 0CFA would be to expensive to compute.  But it is natural
to wonder if the algorithms for these simpler analyses could be
improved.  Owing to 0CFA's \ptime-lower bound, its algorithms are
unlikely to be effectively parallelized or made memory efficient.  But
what about these other analyses?

\subsubsection{Ashley and Dybvig's Sub-0CFA}
\label{sec:sub0}

\citet{ashley-dybvig-toplas98} developed a general framework for
specifying and computing flow analyses; instantiations of the
framework include 0CFA and the polynomial 1CFA of
\citet{jagannathan-weeks-popl95}, for example.  They also developed a
class of instantiations, dubbed {\em sub-0CFA}, that are faster to
compute, but less accurate than 0CFA.

This analysis works by explicitly bounding the number of times the
cache can be updated for any given program point.  After this
threshold has been crossed, the cache is updated with a distinguished
$\unknown$ value that represents all possible $\lambda$-abstractions
in the program.  Bounding the number of updates to the cache for any
given location effectively bounds the number of passes over the
program an analyzer must make, producing an analysis that is $O(n)$ in
the size of the program.  Empirically, Ashley and Dybvig observe that
setting the bound to 1 yields an inexpensive analysis with no
significant difference in enabling optimizations with respect to 0CFA.
%% Following Ashley and Dybvig, we refer to the analysis with the bound
%% set to 1 as sub-0CFA and will refer explicitly to the {\em class} of
%% sub-0CFA analyses when speaking of all possible bounds.

The idea is the cache gets updated once ($n$ times in general) before
giving up and saying all $\lambda$-abstractions flow out of this
point.  But for a linear term, the cache is only updated at most once
for each program point.  Thus we conclude even when the sub-0CFA bound
is 1, the problem is \ptime-complete.

As Ashley and Dybvig note, for any given program, there exists an
analysis in the sub-0CFA class that is identical to 0CFA (namely by
setting $n$ to the number of passes 0CFA makes over the given
program).  We can further clarify this relationship by noting that for
all linear programs, all analyses in the sub-0CFA class are identical
to 0CFA (and thus simple closure analysis).

\subsubsection{Subtransitive 0CFA}

\citet{heintze-mcallester-lics97} have shown the ``cubic bottleneck''
of computing full 0CFA---that is, computing all the flows in a
program---cannot be avoided in general without combinatorial
breakthroughs: the problem is {\sc{2npda}}-hard, for which the ``the
cubic time decision procedure [\dots] has not been improved since its
discovery in 1968.''

Forty years later, that decision procedure was improved to be slightly
subcubic by \citet{chaudhuri-popl08}.  However, given the strong
evidence at the time that the situation was unlikely to improve in
general, \citet{heintze-mcallester-pldi97} identified several simpler
flow questions\footnote{Including the decision problem discussed in
  this dissertation, which is the simplest; answers to any of the
  other questions imply an answer to this problem} and designed
algorithms to answer them for simply-typed programs. Under certain
typing conditions, namely that the type is within a bounded size,
these algorithms compute in less than cubic time.

The algorithm constructs a graph structure and runs in time linear in a
program's graph.  The graph, in turn, is bounded by the size of the
program's type.  Thus, bounding the size of a program's type results
in a linear bound on the running times of these algorithms.  

If this type bound is removed, though, it is clear that even these
simplified flow problems (and their bidirectional-flow analogs), are
complete for \ptime: observe that every linear term is simply typable,
however in our lower bound construction, the type size is proportional
to the size of the circuit being simulated.  As they point out, when
type size is not bounded, the flow graph may be exponentially larger
than the program, in which case the standard cubic algorithm is
preferred.

Independently, \citet{mossin-njc98} developed a type-based analysis
that, under the assumption of a constant bound on the size of a
program's type, can answer restricted flow questions such as single
source/use in linear time with respect to the size of the explicitly
typed program.  But again, removing this imposed bound results in
\ptime-completeness.

As \citet{hankin-games} point out: both Heintze and McAllester's and
Mossin's algorithms operate on type structure (or structure isomorphic
to type structure), but with either implicit or explicit
$\eta$-expansion.  For simply-typed terms, this can result in an
exponential blow-up in type size.  It is not surprising then, that
given a much richer graph structure, the analysis can be computed
quickly.  

In this light, the results of \autoref{chap:linear-logic} on 0CFA of
$\eta$-expanded, simply-typed programs can be seen as an improvement
of the subtransitive flow analysis since it works equally well for
languages with first-class control and can be performed with only a
fixed number of pointers into the program structure, i.e.~it is
computable in \logspace\ (and in other words, \ptime\ $=$ \logspace\
up to $\eta$).

% \dvhnote{Something should be said, perhaps not here, about the
% practical importance of the sub-cubic analysis, ie.~they are the only
% ones used in practice (Might said this).}

% \dvhnote{Is it worth saying the following? ``Generally speaking, it's
% become inevitable for every CFA, there's an alias analysis, and for
% every alias analysis, there's a CFA.  (I bet it's possible to
% formalize this.)'' \cite{might-correspondence}.  It gives us the
% opportunity to 1) tie in (ubiquitous) work on alias analysis in first
% order languages, 2) re-iterate the case for complexity theoretic
% understanding of analyses in order to relate what is seemingly
% disparate. }


%% But what is the usefulness of an analysis if there is no difference
%% between analyzing and running a program?

%% It remains open whether there are useful analyses for linear programs
%% that can be computed with less resources than it takes to evaluate the
%% program.

\subsection{Conclusions}

When an analysis is {\em exact}, it will be possible to establish a
correspondence with evaluation.  The richer the language for which
analysis is exact, the harder it will be to compute the analysis.  As
an example in the extreme, \citet{mossin-sas97} developed a flow
analysis that is exact for simply-typed terms.  The computational
resources that may be expended to compute this analysis are {\em ipso
facto} not bounded by any elementary recursive function
\cite{statman79}.  However, most flow analyses do not approach this kind
of expressivity.  By way of comparison, 0CFA only captures \ptime, and
yet researchers have still expending a great deal of effort deriving
approximations to 0CFA that are faster to compute.  But as we have
shown for a number of them, they all coincide on linear terms, and so
they too capture \ptime.

We should be clear about what is being said, and not said.  There is a
considerable difference in practice between linear algorithms
(nominally considered efficient) and cubic---or near
cubic---algorithms (still feasible, but taxing for large inputs), even
though both are polynomial-time.  \ptime-completeness does not
distinguish the two.  But if a sub-polynomial (e.g., \logspace)
algorithm was found for this sort of flow analysis, it would depend on
(or lead to) things we do not know (\logspace\ $=$ \ptime).  

Likewise, were a parallel implementation of this flow analysis to run
in logarithmic time (i.e., \nc), we would consequently be able to
parallelize every polynomial time algorithm.  \ptime-complete problems
are considered to be the least likely to be in \nc.  This is because
logarithmic-space reductions (such as our compiler from circuits to
$\lambda$-terms) preserve parallel complexity, and so by composing
this reduction with a (hypothetical) logarithmic-time 0CFA analyzer
(or equivalently, a logarithmic-time linear $\lambda$-calculus
evaluator) would yield a fast parallel algorithm for {\em all}
problems in \ptime, which are by definition, logspace-reducible to the
circuit value problem [page 377] \cite{Papadimitriou94}.

The practical consequences of the \ptime-hardness result is that we
can conclude any analysis which is exact for linear programs, which
includes 0CFA, and many further approximations, does not have a fast
parallel algorithm unless \ptime\ $=$ \nc.
