---
abstract: 'This paper presents a new method for automatically generating numerical invariants for imperative programs. Given a program, our procedure computes a binary input/output relation on program states which over-approximates the behaviour of the program. It is compositional in the sense that it operates by decomposing the program into parts, computing an abstract meaning of each part, and then composing the meanings. Our method for approximating loop behaviour is based on first approximating the meaning of the loop body, extracting recurrence relations from that approximation, and then using the closed forms to approximate the loop. Our experiments demonstrate that on verification tasks, our method is competitive with leading invariant generation and verification tools.'
author:
- Azadeh Farzan and Zachary Kincaid
title: Compositional Invariant Generation via Linear Recurrence Analysis
---

Introduction {#sec:intro}
============

Compositional program analyses operate by decomposing a program into parts, computing an abstract meaning of each part, and then composing the meanings. Compositional analyses have a number of desirable properties, including scalability, parallelizability, and applicability to incomplete programs. However, compositionality comes with a price: since each program fragment is analyzed independently of its context, the analysis cannot benefit from contextual information. This paper presents a compositional method for numerical invariant generation which, despite loss of contextual information, compares favourably with leading (non-compositional) verification techniques.

The analysis proposed in this paper aims to compute a *transition relation* which over-approximates the behaviour of a given program. The use of transition relations in compositional analysis (e.g., [@Muller-Olm2004; @Popeea2006; @Ammarguellat1990; @Monniaux2009; @Kroening2008; @Biallas2012]) stems from the fact that they can be composed: for example, consider a program $P = P_1;P_2$ which consists of two sub-programs $P_1$ and $P_2$ which are executed in sequence. A transition invariant ${\llbracket P \rrbracket}$ for $P$ can be computed by computing transition invariants ${\llbracket P_1 \rrbracket}$ and ${\llbracket P_2 \rrbracket}$ for the subprograms and then taking ${\llbracket P \rrbracket}$ to be the relational composition: ${\llbracket P \rrbracket} = \{ (s,s'') : \exists s'. (s,s') \in {\llbracket P_1 \rrbracket} \land (s',s'') \in
{\llbracket P_2 \rrbracket} \}.$

A crucial question is how to compute abstractions of loops (i.e., *loop summaries* [@Kroening2008]). Our analysis is based on a classical idea: find recurrence relations for variables modified in the body of a loop, and then use the closed forms for these recurrences as the abstraction of the loop. The focus of research on recurrence analysis has mainly been on computing the *exact* behaviour of a (necessarily) limited class loops, e.g. loops where the body is a sequence of affine assignments (see Section \[sec:relwork\] for a discussion of related literature). We shift the goal to computing *over-approximate* behaviour of *arbitrary* loops. The main novelty of our approach is to make synergistic use of recurrence analysis and compositionality: on one hand, recurrence analysis can be used to compute accurate transition formulas for loops; on the other hand, transition formulas for loop *bodies* can be mined for recurrence relations to enable recurrence analysis.

Compositionality enables using recurrence analysis for arbitrary loops in two ways. First, the fact that the transition formula for a loop is computed from a transition formula for its body makes the control structure of the loop irrelevant (e.g., whether it is a sequence of assignments or contains branching or nested loops – its transition formula is just a formula). Second, having access to a loop body formula when computing a loop summary opens the door to using Satisfiability Modulo Theories (SMT) solvers to extract a broad range *semantic* recurrences. In particular, our analysis is able to exploit *approximate recurrences* (inequations over linear terms) to compute interesting loop invariants even for variables which do not satisfy recurrence equations in the classical sense, thus extending the applicability of recurrence-based invariant generation and overcoming a major barrier in its practical use.

In summary, this paper presents a compositional method for generating numerical invariants (polynomial inequalities of unbounded degree among integer and rational variables) for programs. The main technical contributions are as follows.

We give a method for computing abstractions of loops using summaries for their bodies. This allows our analysis to apply to arbitrary code (with nested loops, unstructured loops, and arbitrary branching). It also makes it possible to use SMT solvers to extract *semantic* recurrence relations rather than syntactic recurrences obtained by pattern-matching source code.

We identify a class recurrence (in)equations that can be efficiently extracted from loop bodies using SMT solving technology and solved using simple linear algebra.

We give a *linearization* algorithm which enables tractable (but necessarily approximate) reasoning about non-linear formulas over rationals and integers (Section \[sec:discussion\]).

We collect ideas from a diverse range of sources (including algebraic program analysis [@Farzan2013], recurrence analysis [@Ammarguellat1990; @Kovacs2008; @Ancourt2010], linearization [@Mine2006], and symbolic abstraction [@Reps2004; @Monniaux2010; @Li2014]), and synthesize them into a cohesive presentation which can be used as a foundation for futher research on recurrence analysis.

We implemented linear recurrence analysis and used it to verify assertions for a suite of benchmarks. Linear recurrence analysis is able to prove the correctness of more benchmarks in this suite than any of the leading verification tools for integer programs.

Overview {#sec:motivation}
========

We will adopt a simple intraprocedural model in which a program is represented by a control flow automaton (CFA) where edges are labeled by program statements. Figure \[fig:example\] depicts such a CFA for a program which computes the quotient and remainder of division of a variable [x]{} by a variable [y]{}. We use this model for the sake of simplicity and to help keep the presentation of our analysis short and self-contained. We hope that the basic idea behind the extension to procedures (implemented in the tool), using the analysis to compute procedure summaries [@Sharir1981], is clear without formal explanation.

Our analysis, linear recurrence analysis (LRA), is presented in the algebraic framework described in [@Farzan2013]. Suppose that we wish to prove that the assertion `assert(x = q*y + r)` always succeeds. We begin by computing the set of paths from ${v^{\textsf{entry}}}$ to $v_8$ (the location corresponding to the [assert]{} statement in the CFA). This set of paths is represented by a *path expression* for the vertex $v_8$, which is a regular expression over an alphabet of control flow edges. In principle, this can be accomplished by Kleene’s well-known algorithm for converting a finite automaton into a regular expression [@Kleene1956] (but more efficient algorithms exist [@Tarjan1981]). For example, the following is a path expression for $v_8$: [$${\langle {v^{\textsf{entry}}},v_1 \rangle}\!\cdot\!{\langle v_1,v_2 \rangle}\!\cdot\!\underbrace{\big({\langle v_2,v_3 \rangle}\!\cdot\!{\langle v_3,v_4 \rangle}\!\cdot\!\overbrace{({\langle v_4,v_5 \rangle}\!\cdot\!{\langle v_5,v_6 \rangle}\!\cdot\!{\langle v_6,v_4 \rangle})^*}^{\text{Inner loop}}\!\cdot {\langle v_4,v_7 \rangle}\!\cdot\!{\langle v_7,v_2 \rangle}\big)^*}_{\text{Outer loop}}\!\cdot{\langle v_2,v_8 \rangle}$$ ]{}

Once we have a path expression representing the paths to $v_8$, we compute an over-approximation of the executions to $v_8$ by [*evaluating*]{} the path expression in some abstract domain. The main benefit of this algebraic framework is that an analysis is defined simply by providing an interpretation for each of the regular expression operators (sequencing, choice, and iteration, corresponding to the control structures of structured programs), and then we may rely on a path expression algorithm ([@Kleene1956; @Tarjan1981]) to efficiently “lift” the analysis to programs with arbitrary control flow.

Formally, a program analysis (in the framework of [@Farzan2013]) is defined by an *interpretation*, which consists of a *semantic algebra* and a *semantic function*. A semantic algebra consists of a *universe* which defines the space of possible program meanings, and *sequencing*, *choice*, and *iteration* operators, which define how to compose program meanings. A semantic function is a mapping from control flow edges to elements of the universe which defines the meaning of each control flow edge. A path expression is *evaluated* by interpreting the individual edges using the semantic function, and interpreting the regular expression operators using the corresponding operators of the semantic algebra (to compose the interpretations of individual edges into interpretations of sets of program paths).

Keeping this overall algorithm in mind, we proceed to describe the interpretation which defines linear recurrence analysis.

#### **LRA Universe.**

The semantic universe of LRA (i.e., the space of program meanings) is the set of (not necessarily linear) arithmetic *transition formulas*. If we let ${\textsf{Var}}$ denote the set of program variables and ${\textsf{Var}}'$ the set of “primed” copies of program variables, then a transition formula is an arithmetic formula with free variables in ${\textsf{Var}}\cup {\textsf{Var}}'$. Such a formula represents an input/output relation between program states.

#### **LRA Semantic Function.**

The semantic function ${\llbracket \cdot \rrbracket}$ is a function that maps each edge of a control flow automaton to its interpretation as a transition formula. For example (again, considering Figure \[fig:example\]), we have $$\begin{aligned}
  {\llbracket {\langle {v^{\textsf{entry}}},v_1 \rangle} \rrbracket} &= {\fbox{$r' = x \land {\mathit{stable}}(\{q, t, x, y\})$}}\\
  {\llbracket {\langle v_1,v_2 \rangle} \rrbracket} &= {\fbox{$q' = 0 \land {\mathit{stable}}(\{r, t, x, y\})$}}\\
  {\llbracket {\langle v_2,v_3 \rangle} \rrbracket} &= {\fbox{$r > y \land {\mathit{stable}}(\{q, r, t, x, y\})$}}\end{aligned}$$ where for $X \subseteq {\textsf{Var}}$, we have ${\mathit{stable}}(X) {\triangleq}{\fbox{$\bigwedge_{x
    \in X} x' = x$}}$; we use this to factor out equalities from the formulas and make them more legible. Boxes around formulas have no meaning, and are used only to make it easier to distinguish between equalities in formulas and the meta-language.

#### **LRA Operators.**

The sequencing and choice operators of our analysis are defined as follows: $$\begin{aligned}
  \varphi {\odot}\psi &= \exists x''. \varphi[x''/x'] \land \psi[x''/x] &
  \text{Sequencing}\\ \varphi {\oplus}\psi &= \varphi \lor \psi & \text{Choice}\end{aligned}$$ (where $\varphi[x''/x']$ denotes $\varphi$ with each primed variable $x'$ replaced by its double-primed counterpart $x''$, and $\psi[x''/x]$ similarly replaces unprimed variables with double-primed variables).

The semantic function, sequencing, and choice operators are sufficient to analyze loop-free code. For example, we may consider how LRA computes a transition invariant for the body of the inner loop of Figure \[fig:example\]: $$\begin{aligned}
  {\llbracket {\langle v_4,v_5 \rangle}\cdot {\langle v_5,v_6 \rangle} \rrbracket} &= {\llbracket {\langle v_4,v_5 \rangle} \rrbracket} {\odot}{\llbracket {\langle v_5,v_6 \rangle} \rrbracket}\\
  &={\fbox{$t > 0 \land r'=r-1 \land {\mathit{stable}}(\{q, t, x, y\})$}}\end{aligned}$$ $$\begin{aligned}
  {\llbracket {\langle v_4,v_5 \rangle} \cdot {\langle v_5,v_6 \rangle} \cdot {\langle v_6,v_4 \rangle} \rrbracket} &=
  {\llbracket {\langle v_4,v_5 \rangle} \!\cdot\! {\langle v_5,v_6 \rangle} \rrbracket} {\odot}{\llbracket {\langle v_6,v_4 \rangle} \rrbracket}\\
  &= {\fbox{$t > 0 \land r'=r-1 \land t'=t-1 \land {\mathit{stable}}(\{q, x, y\})$}}\end{aligned}$$

The final step in describing our analysis is to provide a definition of the iteration operator (${\ostar}$) of LRA. The idea behind the definition of the iteration operator is to use an SMT solver to extract recurrence relations from the loop body, and then use the closed form of these recurrences for the abstraction of the loop. We explain this in detail in Section \[sec:lra\]. Here, we illustrate how LRA works on the running example to provide some intuition on the analysis.

After computing a formula ${\varphi}_{\textsf{inner}}$ representing the body of the inner loop (as given above), we apply the iteration operator ${\ostar}$ to compute a formula representing any number of executions of the inner loop. The iteration operator begins by extracting the recurrence equations shown to the right. It then computes closed forms for these recurrences, also shown to the right (where $x^{(k)}$ denotes the value that the variable $x$ takes on the $k$th iteration of the loop). Note that this table omits “uninteresting” recurrences (such as $q' = q + 0$) which indicate that a variable does not change in a loop. These closed forms are used to abstract the loop as follows:

$$\begin{aligned}
  \varphi_{\textsf{inner}}^{\ostar}&=  {\fbox{$\exists k. k \geq 0 \land r' = r - k \land t' = t - k \land {\mathit{stable}}(\{q, x, y\})$}}\\
  &= {\fbox{$r' = r + t' - t \land t' \leq t \land {\mathit{stable}}(\{q, x, y\})$}}\end{aligned}$$

We may use this summary $\varphi_{\textsf{inner}}^{\ostar}$ for the inner loop to compute a transition formula representing the body of the outer loop: $$\begin{aligned}
  \varphi_{\textsf{outer}} &= {\llbracket {\langle v_2,v_3 \rangle} \rrbracket} {\odot}{\llbracket {\langle v_3,v_4 \rangle} \rrbracket} {\odot}\varphi_{\textsf{inner}}^{\ostar}{\odot}{\llbracket {\langle v_4,v_7 \rangle} \rrbracket} {\odot}{\llbracket {\langle v_7,v_2 \rangle} \rrbracket}\\
  &= {\fbox{$q' = q + 1 \land r' = r + t' - y \land t' = 0 \land r \geq y \land {\mathit{stable}}(\{x, y\})$}} \end{aligned}$$

We then apply the iteration operator to compute a transition formula for the outer loop. The recurrences found for the outer loop and their closed forms are shown to the right (again, with “uninteresting” recurrences omitted). We note that our algorithm extracts these recurrences from ${\varphi}_{\textsf{outer}}$ using only semantic operations: the fact that ${\varphi}_{\textsf{outer}}$ is an abstraction of a looping computation is completely transparent to the analysis. Using the closed forms of the recurrences to the right, we compute the following transition formula for the outer loop:

$$\begin{aligned}
  \varphi_{\textsf{outer}}^{\ostar}&=  {\fbox{$\exists k. k \geq 0 \land q' = q + k \land r' = r - ky \land {\mathit{stable}}(\{x, y\})$}}\\
  &= {\fbox{$q' \geq q \land r' = r - (q'-q)y \land {\mathit{stable}}(\{x, y\})$}}\end{aligned}$$

Finally, we compute a transition formula which approximates all executions which end at $v_8$ as follows: $$\begin{aligned}
  \varphi_P &= {\llbracket {\langle {v^{\textsf{entry}}},v_1 \rangle}\cdot{\langle v_1,v_2 \rangle} \rrbracket} {\odot}\varphi_{\textsf{outer}}^{\ostar}{\odot}{\llbracket {\langle v_2,v_8 \rangle} \rrbracket}\\
  &= {\fbox{$q' \geq 0 \land r' = x - q'y \land r \leq y \land {\mathit{stable}}(\{x, y\})$}}\end{aligned}$$

This formula is strong enough to imply that assertion $x' = q'*y'+r'$ holds at $v_8$. This is particularly interesting because it requires proving a *non-linear* transition invariant for the loop, which is out of scope for many state-of-the-art program analyzers.

Abstracting Loops with Linear Recurrence Analysis {#sec:lra}
=================================================

In this section, we describe the iteration operator of linear recurrence analysis. Suppose that we have a formula ${{\varphi}_{\textsf{body}}}$ which approximates the behaviour of the body of a loop. Our goal is to compute a formula ${{\varphi}_{\textsf{body}}}^{\ostar}$ which represents the effect of zero or more executions of the loop body. Our iteration operator works by extracting recurrence relations from the formula ${{\varphi}_{\textsf{body}}}$ and then computing closed forms for these relations. We present our iteration operator in three stages, based on the types of recurrence relations being considered: *simple recurrence equations*, *stratified recurrence equations*, and *linear recurrence (in)equations*. Simple and stratified recurrences are classical classes of recurrence equations. Linear recurrence (in)equations generalize the class of inequations presented in [@Ancourt2010] by using stratified recurrences to generate polynomial (rather than just linear) inequations. The main conceptual contribution of this section is the idea to use SMT solvers to extract recurrences (and other relevant information) from a loop body formula.

In the remainder of this section, we fix a formula ${{\varphi}_{\textsf{body}}}$ representing the body of a loop. We assume that ${{\varphi}_{\textsf{body}}}$ is expressed in linear (rational and integer) arithmetic; our strategy for dealing with non-linear arithmetic is described in Section \[sec:discussion\]. We also assume that ${{\varphi}_{\textsf{body}}}$ is satisfiable (if it is not, then we can take ${{\varphi}_{\textsf{body}}}^{\ostar}$ to be $\bigwedge_{x \in {\textsf{Var}}} x' = x$, which represents zero iterations of the loop).

Simple recurrence equations
---------------------------

We start by defining simple recurrences and induction variables.

A simple recurrence for a formula ${\varphi}$ is an equation of the form $x' = x +
c$ (for a constant $c$) such that ${\varphi}\models x' = x + c$. If $x' = x + c$ is a simple recurrence for ${\varphi}$, we say that $x$ *satisfies* the recurrence $x' = x + c$, and if there is some $c$ such that $x$ satisfies the recurrence $x' = x + c$, we say that $x$ is an *induction variable*.

Simple recurrences can be detected by first querying an SMT solver for a model $m$ of ${{\varphi}_{\textsf{body}}}$, and then asking whether ${{\varphi}_{\textsf{body}}}$ implies $x' =
x + {{\llbracket x'-x \rrbracket}^{m}}$ (where ${{\llbracket x'-x \rrbracket}^{m}}$ denotes the interpretation of the term $x'-x$ in the model $m$). This implication holds iff $x$ is an induction variable.

If $x$ is an induction variable that satisfies the recurrence $x' = x + c$, then the closed form for $x$ is $x^{(k)} = x^{(0)} + kc$ (writing $x^{(k)}$ for the value that $x$ obtains on the $k$th iteration of the loop). To provide some early intuition on the iteration operator to be developed in the remainder of this section, let us suppose that we are only interested in simple recurrences. Then a possible definition for the iteration operator is $${{\varphi}_{\textsf{body}}}^{\ostar}{\triangleq}{\fbox{$\exists k \geq 0. \bigwedge \{ x' = x + kc : x' = x + c \in \textit{SR}({{\varphi}_{\textsf{body}}}) \}$}}$$ where $\textit{SR}({{\varphi}_{\textsf{body}}})$ is the set of simple recurrences satisfied by ${{\varphi}_{\textsf{body}}}$.

The iteration operator defined above is sound (it over-approximates the behaviour of any number of iterations of the loop, since each variable is either described exactly by a recurrence or is not constrained at all), but it is imprecise. The remainder of this section discusses more general recurrence equations which can be used to compute more precise transition invariants for loops.

Stratified recurrences equations {#sec:stratified}
--------------------------------

Consider the loop shown to the right. We can see that `x` satisfies a simple recurrence equation $\texttt{x}' = \texttt{x} + 1$, and that `y` satisfies a (non-simple) recurrence equation $\texttt{y}' = \texttt{y} +
\texttt{x} + 1$. A closed form for `y`’s recurrence is $y^{(k)} =
\texttt{y}^{(0)} + \sum_{i=0}^{k-1} (\texttt{x}^{(i)} + 1)$. Since `x` satisfies a simple recurrence ($x' = x + 1$), we have a closed form for $\texttt{x}^{(i)}$, so we may simplify this recurrence and remove the summation:

$$\texttt{y}^{(k)} =
\texttt{y}^{(0)} + \sum_{i=0}^{k-1} (\texttt{x}^{(0)} + i + 1) = \texttt{y}^{(0)} + k\texttt{x}^{(0)} + k + \sum_{i=0}^{k-1} i = \texttt{y}^{(0)} +
k\texttt{x}^{(0)} + \frac{k(k+1)}{2}.$$

*Stratified recurrence equations* generalize this idea: starting from simple recurrence equations, we solve more and more complicated recurrences using the closed forms for simpler ones. As with the example above, stratified recurrences have non-linear closed forms. Non-linear invariant generation is not the main focus of our work, but it is sometimes a necessary intermediate step for proving *linear* invariants in a compositional setting: since our analysis cannot take advantage of contextual information when analyzing a loop, we generate a non-linear invariant and then, after the analysis has examined more context, simplify it (using the linearization algorithm from Section \[sec:discussion\]).

Let ${\varphi}$ be a formula. The stratified recurrence equations (and stratified induction variables) of ${\varphi}$ are defined inductively as:

A simple recurrence equation which is satisfied by ${\varphi}$ is a stratified recurrence equation of ${\varphi}$ (and a simple induction variable is a stratified induction variable) at stratum 0.

Let $\vec{y}$ denote a vector of the stratified induction variables of strata $\leq N$. A recurrence of the form $x' = x + \vec{c}\vec{y}$ (where $\vec{c}$ is a vector of constants) is a stratified recurrence at stratum $N+1$ (and if $x$ satisfies such a recurrence, it is a stratified induction variable at stratum $N+1$).

We use ${\textsf{siv}}({\varphi})$ to denote the set of all stratified induction variables of ${\varphi}$.

$H \gets \bot$; $\psi \gets {{\varphi}_{\textsf{body}}}$

Let us now discuss how stratified recurrences are detected from a loop body formula ${{\varphi}_{\textsf{body}}}$. We begin by computing the affine hull ${\textit{aff}}({{\varphi}_{\textsf{body}}})$ of ${{\varphi}_{\textsf{body}}}$ (Algorithm \[alg:affine\_hull\]).[^1]

The *affine hull* ${\textit{aff}}({\varphi})$ of a formula ${\varphi}$ is the smallest affine set which contains ${\varphi}$, represented as (the set of solutions to) a system of equations $A\vec{x} = \vec{b}$, where $\vec{x} = \begin{bmatrix*}x_1 & \dotsi & x_n & x_1' & \dotsi & x_n' \end{bmatrix*}$. Logically, ${\textit{aff}}({\varphi})$ is a system of equations which satisfies the following three properties: (1) ${\varphi}\models {\textit{aff}}({\varphi})$, (2) every linear equation over ${\textsf{Var}}\cup {\textsf{Var}}'$ which is implied by ${\varphi}$ is also implied by ${\textit{aff}}({\varphi})$, and (3) no equation in ${\textit{aff}}({\varphi})$ is implied by the others.

Our strategy for detecting stratified recurrences is based on the following lemma. Combined with property (2) of ${\textit{aff}}({{\varphi}_{\textsf{body}}})$ above, this lemma implies that any equation implied by ${{\varphi}_{\textsf{body}}}$ can be expressed as a linear combination of the equations in ${\textit{aff}}({{\varphi}_{\textsf{body}}})$.

Let $A$ be a matrix, $\vec{b}$ be a column vector, $\vec{c}$ be a row vector, and $d$ be a constant. Assume that the system $A\vec{x} = b$ has a solution. Then $A\vec{x} = \vec{b}$ implies $\vec{c}\vec{x} = d$ iff there is a row vector $\vec{\lambda}$ such that $\vec{\lambda}A = \vec{c}$ and $\vec{\lambda}\vec{b} = d$.

Let us write ${\textit{aff}}({{\varphi}_{\textsf{body}}})$ as $A\vec{x} = \vec{b}$. Suppose that we have detected all recurrences of strata $< N$, and that we want to determine whether a variable $x_i$ ($0 \leq i \leq n$) is an induction variable at stratum $N$. Then we ask whether there exists $\vec{\lambda}$, $\vec{c}$, and $d$ such that:

$\vec{\lambda} A = \vec{c}$ and $\vec{\lambda}\vec{b} = d$ (i.e, $\vec{c}\vec{x} = d$ is implied by ${\textit{aff}}({{\varphi}_{\textsf{body}}})$ and thus by ${{\varphi}_{\textsf{body}}}$)

$c_i = 1$ and $c_{i+n} = -1$ (the coefficients of $x_i$ and $x_i'$ are 1 and -1, respectively)

For all $j$ such that $j \neq i+n$ and $n \leq j \leq 2n$, $c_{j} = 0$ (except for $x_i'$, all coefficients of primed variables are 0).

For all $j$ such that $j \neq i$ such that $x_j$ is not an induction variable of strata $< N$ and $n \leq j \leq 2n$, $c_{j} = 0$ (except for $x_i$ and induction variables of strata $< N$, all coefficients for unprimed variables are 0).

Thus, after computing the affine hull of ${{\varphi}_{\textsf{body}}}$, determining whether a given variable satisfies a stratified recurrence is simply a matter of solving a system of linear equations (e.g., using Gaussian elimination).

### Closed forms for stratified recurrences.

We first state a lemma:

The closed form for a stratified induction variable of strata $N$ is of the form $$x^{(k)} = p_0(k) + p_1(k)y_1^{(0)} + \dotsi + p_n(k)y_n^{(0)}$$ where each $y_i$ is a stratified induction variable of strata $<N$ and each $p_i(k) \in \mathbb{Q}[k]$ is a polynomial of one variable with rational coefficients.

Our algorithm for solving stratified recurrences is based on a constructive proof for this lemma. We proceed by induction on strata. The base case is trivial. Suppose that we have a recurrence at strata $N$ (and all $y_1,...,y_n$ are of strata $<N$): $x' = x + c_1y_1 + \dotsi + c_ny_n + b$. Then we may write $x^{(k)} = x^{(0)} + \sum_{i=0}^{k-1} \big(c_1y_1^{(i)} + \dotsi + c_ny_n^{(i)} + b\big)$. By our induction hypothesis, each $y_j^{(i)}$ can be written as a linear term with coefficients from $\mathbb{Q}[k]$. It follows that there exists $p_0,...,p_n \in \mathbb{Q}[k]$ so that $$c_1y_1^{(i)} + \dotsi + c_ny_n^{(i)} + b = p_0(i) + p_1(i)y_{1}^{(0)} + \dotsi + p_n(i)y_n^{(0)}$$ Thus we have $$\begin{aligned}
  x^{(k)} &= x^{(0)} + \sum_{i=0}^{k-1} p_0(i) + p_1(i)y_{1}^{(0)} + \dotsi + p_n(i)y_n^{(0)}\\
  &= x^{(0)} + \sum_{i=0}^{k-1} p_0(i) + y_{1}^{(0)}\sum_{i=0}^{k-1} p_1(i) + \dotsi + y_{n}^{(0)}\sum_{i=0}^{k-1} p_n(i)\end{aligned}$$

The closed form of a summation of a polynomial of degree $m$ is a polynomial of degree $m+1$. We can find this polynomial via curve fitting (i.e., we compute the first $m+1$ terms of the summation and then solve the corresponding linear system of equations for the coefficients of the polynomial).

Linear recurrence (in)equations {#sec:lr_ineq}
-------------------------------

Recurrence equations (such as the simple and stratified varieties) yield very accurate approximations for *some* variables, but what about variables which do not satisfy *any* recurrence equation? For example, consider that neither `x` nor `y` satisfy a recurrence equation in the loop to the right. However, they *do* satisfy recurrence *inequations*: $\texttt{x}-1 \leq \texttt{x}'$, $\texttt{x}' \leq
\texttt{x}$, $\texttt{y}-1 \leq \texttt{y}'$, and $\texttt{y}' \leq
\texttt{y}$. These inequations can be closed to yield $\texttt{x}^{(0)} - k
\leq \texttt{x}^{(k)}$ and $\texttt{x}^{(k)} \leq \texttt{x}^{(0)}$, $y^{(0)}
- k\leq y^{(k)}$, and $y^{(k)} \leq y^{(0)}$. In this section, we discuss linear recurrence (in)equations, which allow us to compute good approximations for loops that cannot be completely described by recurrence equations.

\[def:lri\] A *linear recurrence (in)equation* of a formula ${\varphi}$ is an (in)equation which is implied by ${\varphi}$ and which is of the form $$\vec{c}\vec{x}' \bowtie \vec{c}\vec{x} + \vec{b}\vec{y} + d$$ where $\mathop{\bowtie} \in \{ <, \leq, =\}$, $\vec{x}$ is any vector of variables, $\vec{y}$ is a vector of stratified induction variables in ${{\varphi}_{\textsf{body}}}$, $\vec{c}$, $\vec{b}$ are constant vectors, and $d$ is a constant.

Linear recurrence (in)equations generalize recurrence equations in two ways: first, they allow for *inequalities* rather than equations. Second, they allow recurrences for *linear terms*, rather than just variables. For example, the linear recurrence equation $(\texttt{x}' +
\texttt{y}') = (\texttt{x} + \texttt{y}) + 1$ is satisfied by the body of the loop above, which can be closed to yield $(\texttt{x}^{(k)} +
\texttt{y}^{(k)}) = (\texttt{x}^{(0)} + \texttt{y}^{(0)}) + k$.

We now describe our method for detecting and solving linear recurrence (in)equations. We begin by introducing a set of *difference variables* $\delta_x$, one for each variable $x \notin {\textsf{siv}}({{\varphi}_{\textsf{body}}})$ (variables which do belong to ${\textsf{siv}}({{\varphi}_{\textsf{body}}})$ are already precisely described by recurrence equations, so we need not approximate them). We then compute (via Algorithm \[alg:convex\_hull\]) the convex hull of the formula $\psi$ defined as:

$$\psi {\triangleq}\exists X. {{\varphi}_{\textsf{body}}}\land \bigwedge \{ \delta_x = x' - x : x \in {\textsf{Var}}\setminus {\textsf{siv}}({{\varphi}_{\textsf{body}}}) \}$$ where $X$ is ${\textsf{Var}}' \cup ({\textsf{Var}}\setminus {\textsf{siv}}({{\varphi}_{\textsf{body}}}))$.

$P \gets \bot$

Geometrically, the convex hull ${\textit{hull}}({{\varphi}_{\textsf{body}}})$ is the smallest convex polyhedron which contains ${{\varphi}_{\textsf{body}}}$. Logically, it is a set of (in)equations such that (1) every (in)equation in ${\textit{hull}}({{\varphi}_{\textsf{body}}})$ is implied by ${{\varphi}_{\textsf{body}}}$, and (2) any linear (in)equation (over ${\textsf{Var}}\cup {\textsf{Var}}'$) which is implied by ${{\varphi}_{\textsf{body}}}$ is also implied by ${\textit{hull}}({{\varphi}_{\textsf{body}}})$. For example, ${\textit{hull}}({{\varphi}_{\textsf{body}}})$ for the loop above is: $$0 \leq \delta_x \land \delta_x \leq 1 \land 0 \leq \delta_y \land \delta_y \leq 1 \land \delta_x + \delta_y = 1$$

We note that the only variables which appear in the (in)equations in ${\textit{hull}}({{\varphi}_{\textsf{body}}})$ are (stratified) induction variables and difference variables. Thus, we may write any (in)equation in ${\textit{hull}}({{\varphi}_{\textsf{body}}})$ as $\vec{c}\vec{\delta}
\bowtie \vec{b}\vec{y} + d$ (where $\vec{\delta}$ is the vector of difference variables, $\vec{y}$ is the vector of stratified induction variables, $\vec{c}$ and $\vec{b}$ are constant vectors, and $d$ is a constant). Recalling the definition of the difference variables, we may rewrite such an inequation as $\vec{c}\vec{(\vec{x}'-\vec{x})} \bowtie \vec{b}\vec{y} + d$ and then rewrite again as $\vec{c}\vec{x}' \bowtie \vec{c}\vec{x} + \vec{b}\vec{y}
+ d$, which matches the definition of linear recurrence (in)equations given in Definition \[def:lri\].

We may close such a linear recurrence (in)equation as follows: $$\vec{c}\vec{x}^{(k)} \bowtie \vec{c}\vec{x}^{(0)} + \sum_{i=0}^{k-1} \vec{b}\vec{y}^{(i)} + d$$ We can compute a closed form for the summation $\sum_{i=0}^{k-1}
\vec{b}\vec{y}^{(i)} + d$ as in the preceding section.

Loop guards
-----------

A loop body typically contains crucial information about the execution of the loop that cannot be captured by recurrence relations. For example, consider the loop in Section \[sec:stratified\]. Supposing that the loop executes $n$ times, we must have that $\texttt{x}^{(k)} \leq 10$ for each $k < n$. Further, consider that the variable `z` is a function of the simple induction variable `x`, and so $\texttt{z}^{(k)}$ can be described precisely in terms of the pre-state variables (even though it does not itself satisfy any recurrence): $$\texttt{z}^{(k)} = 
\begin{cases}
  \texttt{z}^{(0)} & \text{if } k = 0\\
  2(\texttt{x}^{(0)} + k + 1) & \text{otherwise.}
\end{cases}$$ The question is: how can we recover this type of information from a loop body formula?

We define the *guard* of a transition formula ${\varphi}$ as follows: $$guard({\varphi}) {\triangleq}{\fbox{$(\exists {\textsf{Var}}. {\varphi}) \land (\exists {\textsf{Var}}'. {\varphi})$}}$$ If ${\varphi}$ is a loop body formula, then $guard({\varphi})$ is a formula which over-approximates the effect of executing *at least one* execution of the loop. Intuitively, $(\exists {\textsf{Var}}. {\varphi})$ as a precondition that must hold before every iteration of the loop and $(\exists {\textsf{Var}}'. {\varphi})$ as a post-condition of the loop that must hold after each iteration.

Consider again the example loop in Section \[sec:stratified\], we have the following loop body formula $${\varphi}_{\textsf{body}} = {\fbox{$x \leq 10 \land x' = x + 1 \land y' = y + x' \land z' = 2x'$}}$$ We compute $guard({\varphi}_{\textsf{body}})$ as follows: $$\begin{aligned}
  guard({\varphi}_{\textsf{body}}) &= {\fbox{$(\exists \texttt{x},\texttt{y},\texttt{z}. {\varphi}_{\textsf{body}}) \land (\exists \texttt{x'},\texttt{y'},\texttt{z'}. {\varphi}_{\textsf{body}})$}} \\
  &\equiv {\fbox{$(\texttt{x} \leq 10) \land (\texttt{x'} \leq 11 \land \texttt{z} = 2\texttt{x'})$}}\ ,\end{aligned}$$ and thereby recover the desired information about `x` and `z`.

Since loop body formulas may be large, it may be adventageous in practice to simplify the guard formula by eliminating the quantifiers (as we did above). A second option, which is more efficient but less precise, is to over-approximate quantifier elimination. Two possibilities are to use Algorithm \[alg:convex\_hull\] to compute the convex hull of $guard({{\varphi}_{\textsf{body}}})$, or to use optimization modulo theories [@Li2014] to compute intervals for each pre- and post-state variable in ${\varphi}_{\textsf{body}}$.

Bringing it all together
------------------------

We close this section by describing how the pieces defined in this section fit into the iteration operator of linear recurrence analysis. We let $\textit{CR}({{\varphi}_{\textsf{body}}})$ denote the set of closed linear recurrence (in)equations (including simple and stratified recurrence equations) satisfied by ${{\varphi}_{\textsf{body}}}$. Each such (in)equation is of the form $\vec{c}\vec{x}^{(k)} \bowtie t$, where the free variables of $t$ are drawn from $\{ x^{(0)} : x \in {\textsf{Var}}\}$ and a distinguished variable $k \notin {\textsf{Var}}$ indicating the loop iteration. We define $${{\varphi}_{\textsf{body}}}^+ {\triangleq}{\fbox{$\exists k. k \geq 1  \land \bigwedge \{ \vec{c}\vec{x'} \bowtie t[\vec{x}^{(0)} \mapsto \vec{x}] : \vec{c}\vec{x}' \bowtie t \in \textit{CR}({{\varphi}_{\textsf{body}}}) \}$}}$$ where $t[\vec{x}^{(0)} \mapsto \vec{x}]$ denotes the term $t$ with every variable of the form $x^{(0)}$ is replaced by the corresponding variable $x$.

Finally, our iteration operator is defined as: $${{\varphi}_{\textsf{body}}}^{\ostar}{\triangleq}{\fbox{$({{\varphi}_{\textsf{body}}}^+ \land \textit{guard}({{\varphi}_{\textsf{body}}})) \lor \bigwedge_{x \in {\textsf{Var}}} x' = x.$}}$$

Linearization {#sec:discussion}
=============

The iteration operator presented in the previous section relies heavily on using an SMT solver to extract information from loop body formulas. This strategy requires that loop body formulas are expressed in a decidable theory which is supported by SMT solvers (in particular, linear arithmetic). However, a program may contain non-linear instructions, and even if it does not, our iteration operator may introduce non-linearity (consider Example \[fig:example\], where the transition formula for the outer loop ${\varphi}_{\textsf{outer}}^{\ostar}$ contains the non-linear proposition $r' =
x-q'y$). Our solution to this problem is to *linearize* non-linear formulas before passing them to the iteration operator.

Linearization is an operation that, given an (arbitrary) arithmetic formula ${\varphi}$, computes a formula $\textit{lin}({\varphi})$ which over-approximates ${\varphi}$ (i.e., ${\varphi}\Rightarrow \textit{lin}({\varphi})$), but which is expressed in linear arithmetic. There is generally no best approximation of a non-linear formula as a linear formula, so our method is (necessarily) a heuristic.

We explain our linearization algorithm informally using an example. Consider the following non-linear formula (where $w,x,y,z$ are integers): $$\psi {\triangleq}1 \leq w = x < y < 5 \land w * y \leq z \leq x * y$$ Our algorithm begins by normalizing $\psi$, separating it into a linear part and a set of non-linear equations (introducing existentially quantified temporary variables as necessary). For example, the result of normalizing $\psi$ is: $$\big(1 \leq w = x < y < 5 \land \leq \gamma_0 \leq z \leq \gamma_1 \big) \land \big( \gamma_0 = w*y \land \gamma_1 = x*y \big)$$

The left conjunct is a linear over-approximation of $\psi$, but it is very imprecise: semantically equal (but syntactically distinct) non-linear terms become semantically *un*equal in the over-approximation, and all information about the magnitude of non-linear terms is lost. To increase precision of this approximation, we use two strengthening steps.

We replace the non-linear operations with uninterpreted function symbols and then compute the affine hull of the resulting formula to infer equalities between non-linear terms. For our example $\psi$, the we discover that $\gamma_0 = \gamma_1$.

We compute concrete and symbolic intervals for non-linear terms. Consider $\gamma_0 = x*y$ from our example $\psi$. We first compute concrete ($x \in [1,3]$ and $y \in [2,4]$) and symbolic ($x \in [x,x]$ and $y \in [y,y]$) intervals for the operands $x$ and $y$, using symbolic optimization [@Li2014] to compute the concrete intervals. We obtain a concrete interval for $x*y$ ($x*y \in [2,12]$) by multiplying the concrete intervals of its operands. We obtain symbolic intervals for $x*y$ ($x*y \in
  [y,3y]$ and $x*y \in [2x, 4x]$) by multiplying the concrete interval for $x$ by the symbolic interval for $y$ and vice-versa. As a result of interval computation, we discover: $2 \leq \gamma_1 \leq 12 \land y \leq \gamma_1 \leq 3y \land 2x \leq \gamma_1 \leq 4x$

Finally, we take $\textit{lin}(\psi)$ to be the initial coarse linear approximation of $\psi$ conjoined with the facts discovered by the two strengthening steps.

We expect linearization to have broad applications outside of the context in which we presented it, particularly in program analysis, where over-approximation can be tolerated but non-linear terms cannot. Finding improved linearization heuristics is an interesting direction of future work.

Experiments {#sec:experiments}
===========

We wrote a tool which implements LRA and analyzes C code (using the CIL [@cil] frontend).[^2] We use Z3 [@z3] to resolve SMT queries that result from applying the iteration operator and checking assertion violations. Polyhedra operations are passed to the New Polka library implemented in Apron [@apron]. The quantifier elimination algorithm from [@Monniaux2010] is used to compute loop guards. We tested two different configurations of LRA: one which is fully compositional ([LRA-Comp]{}) and does not take advantage of contextual information, and one ([LRA]{}) which uses an intraprocedural polyhedron analysis [@Cousot1978] to gain *some* contextual information, but which is otherwise compositional. We compare LRA’s performance against the state-of-the-art invariant generation and verification tools [CPAChecker]{} (overall winner of the 2015 Software Verification Competition) and [SeaHorn]{} (winner of the loops category among tools which are sound for verification).

To evaluate the precision of LRA we used it to verify the correctness of a suite of 119 small loop benchmarks of varying difficulty. Our benchmark suite was drawn from the *loops* category of the 2015 Software Verification Competition (SVComp-15), as well as a set of *non-linear* benchmarks (Non-linear), such as the one in Figure \[fig:example\]. The results for the 81 safe, integer-only benchmarks from these suites are shown in Table \[tab:lra\]. The suite also contains 38 *unsafe* benchmarks: [LRA]{} and [LRA-Comp]{} have no false negatives on these benchmarks; [CPAChecker]{} has 3 and [SeaHorn]{} has 2.

[|l|c||c|c|c|c|]{} Benchmark suite & \# Bench & [LRA]{} & [LRA-Comp]{} & [CPAChecker]{} & [SeaHorn]{}\

SVComp-15 & 74 & 65 & 60 & 37 & 65\
Non-linear & 7 & 6 & 5 & 1 & 3\
Total & 81 & 71 (88%) & 65 (80%) & 38 (47%) & 68 (85%)\
\
& 5.4s & 3.0s & 42.4s & 37.7s\
& 0.8s & 0.8s & 1.6s & 0.2s\

Our results demonstrate that LRA is an effective invariant generation algorithm. Even the fully compositional variant of LRA ([LRA-Comp]{}) is able to prove safety for 80% of the benchmarks we considered). We also note that there are 8 benchmarks for which LRA can prove safety but which [ CPAChecker]{} and [SeaHorn]{} cannot.

Related work {#sec:relwork}
============

There is a great deal of work on compositional invariant generation and acceleration which is related to the technique described in this paper. In this section, we compare our technique to a sampling of this work.

***Recurrence analysis.*** The idea of using closed forms of recurrence relations to approximate loops has appeared in a number of other papers. Generally speaking, our work differs from previous work in two essential ways: first, we use an SMT solver to extract *semantic* recurrences, rather than *syntactic* recurrences. Second, we consider *approximate recurrences* (inequations over linear terms) rather than exact recurrences (equations over variables). A survey of some of this work follows.

Ammarguellat and Harrison present a method for detecting induction variables which is compositional in the sense that it uses closed forms for inner loops in order to recognize nested recurrences [@Ammarguellat1990]. Maps from variables to symbolic terms (effectively a symbolic constant propagation domain) is used as the abstract domain. Kovács presents a technique for discovering invariant polynomial equations based on solving recurrence relations [@Kovacs2008]. The simple and stratified recurrence equations considered in this paper are a strict subset of the recurrences considered in [@Kovacs2008], but our algorithm for solving recurrences is simpler. Kroening et al. [@Kroening2013] presents a technique for computing *under*-approximations of loops which uses polynomial curve-fitting to directly compute closed forms for recurrences rather than extracting recurrences and then solving them in a separate step.

Ancourt et al. present a method for computing recurrence inequations for while loops with affine bodies [@Ancourt2010]. Like the method we present on Section \[sec:lr\_ineq\], their method is based on using difference variables and polyhedral projections. Our method generalizes this work by (1) extending it to arbitary control flow, with (possibly non-linear) formulas as bodies rather than affine transformations, (2) integrating recurrence inequations with stratified induction variables, thereby allowing enabling the computation of invariant polynomial inequations. Ancourt et al. briefly discuss a method for computing invariant polynomial inequations, but it is based on higher-order differences rather than stratified recurrence inequations. For example, in Figure \[fig:example\], the analysis discussed in [@Ancourt2010] would be able to prove that `r` is decremented by a constant amount at every loop iteration, but could not prove that the constant amount is exactly `y`.

***Acceleration**.* *Acceleration* is a technique closely related to recurrence analysis that was pioneered in infinite-state model checking [@Boigelot1994; @Finkel2002; @Bardin2005], and which has recently found use in program analysis [@Gonnord2006; @Leroux2007; @Jeannet2014]. Given a set of reachable states and an affine transformation describing the body of a loop, acceleration computes an *exact* post-image which describes the set of reachable states after executing any number of iterations of the loop (although there is recent work on *abstract acceleration* uses computes over-approximate post-images [@Gonnord2006; @Jeannet2014]). In contrast, our technique is *approximate* rather than exact, and computes loop summaries rather than post-images. A result of these two features is that our analysis to be applied to arbitrary loops, while acceleration is classically limited to simple loops where the body consists of a sequence of assignment statements.

***Compositional program analysis.*** Compositional program analysis has a long history. Particular examples are interprocedural analyses based on summarization [@Sharir1981] and elimination-style dataflow analyses (a good overview of which can be found in [@Ryder1986]). The following surveys recent work on compositional analysis for numerical invariants.

Kroening et al. [@Kroening2008] and Biallas et al. [@Biallas2012] present compositional analysis techniques based on predicate abstraction. In addition to predicate abstraction, there are a few papers which use numerical abstract domains for compositional analysis. These include an algorithm for detecting affine equalities between program variables [@Muller-Olm2004], an algorithm for detecting polynomial equalities between program variables [@Colon2004], a disjunctive polyhedra analysis which uses widening to compute loop summaries [@Popeea2006], and a method for automatically synthesizing transfer functions for template abstract domains using quantifier elimination [@Monniaux2009]. Our abstract domain is the set of arbitrary arithmetic formula, which is more expressive than these domains, but which (as usual) incurs a price in performance. It would be interesting to apply abstractions to our formulas to improve the performance of our analysis.

***Linearization.*** Our linearization algorithm was inspired by Miné’s procedure for approximating non-linear abstract transformers [@Mine2006]. Miné’s procedure abstracts non-linear terms by linear terms with interval coefficients using the abstract value in the pre-state to derive intervals for variables. Our algorithm abstracts non-linear terms by sets of symbolic and concrete intervals, and applies to the more general setting of approximating arbitrary formulas.

Conclusion {#sec:conclusion}
==========

This paper presents a fully compositional algorithm for generating numerical invariants of imperative programs. Our method for abstracting loops makes essential use of compositionality: we assume that we are given a formula which approximates the body of a loop, and we use an SMT solver to extract recurrence relations and then use the closed forms of these recurrences to approximate the loop. We have demonstrated experimentally that our method is competitive with leading invariant generation and verification tools.

[10]{}

Z. Ammarguellat and W. L. Harrison, III. Automatic recognition of induction variables and recurrence relations by abstract interpretation. PLDI, pages 283–295, 1990.

C. Ancourt, F. Coelho, and F. Irigoin. A modular static analysis approach to affine loop invariants detection. , 267(1):3–16, Oct. 2010.

S. Bardin, A. Finkel, J. Leroux, and P. Schnoebelen. Flat acceleration in symbolic model checking. In [*ATVA*]{}, pages 474–488. 2005.

J. Bertrand and A. Min[é]{}. Apron: A library of numerical abstract domains for static analysis. In [*CAV*]{}, pages 661–667, 2009.

S. Biallas, J. Brauer, A. King, and S. Kowalewski. Loop leaping with closures. In [*SAS*]{}, pages 214–230, 2012.

B. Boigelot and P. Wolper. Symbolic verification with periodic sets. In [*CAV*]{}, pages 55–67. 1994.

M. A. Colón. Approximating the algebraic relational semantics of imperative programs. In [*SAS*]{}, pages 296–311. 2004.

P. Cousot and N. Halbwachs. Automatic discovery of linear restraints among variables of a program. In [*POPL*]{}, pages 84–96, 1978.

L. De Moura and N. Bj[ø]{}rner. Z3: an efficient [SMT]{} solver. TACAS, pages 337–340, 2008.

A. Farzan and Z. Kincaid. An algebraic framework for compositional program analysis. , abs/1310.3481, 2013.

A. Finkel and J. Leroux. How to compose [P]{}resburger-accelerations: Applications to broadcast protocols. In [*FST TCS*]{}, pages 145–156, 2002.

L. Gonnord and N. Halbwachs. Combining widening and acceleration in linear relation analysis. In [*SAS*]{}, pages 144–160. 2006.

B. Jeannet, P. Schrammel, and S. Sankaranarayanan. Abstract acceleration of general linear loops. In [*POPL*]{}, pages 529–540, 2014.

S. Kleene. Representation of events in nerve nets and finite automata. In C. Shannon and J. Mccarthy, editors, [*Automata Studies*]{}, pages 3–42. Princeton University Press, Princeton, N.J., 1956.

L. Kovács. Reasoning algebraically about [P]{}-solvable loops. In [*TACAS*]{}, pages 249–264. 2008.

D. Kroening, M. Lewis, and G. Weissenbacher. Under-approximating loops in [C]{} programs for fast counterexample detection. In [*CAV*]{}, pages 381–396. 2013.

D. Kroening, N. Sharygina, S. Tonetta, A. Tsitovich, and C. Wintersteiger. Loop summarization using abstract transformers. In [*ATVA*]{}, pages 111–125. 2008.

J. Leroux and G. Sutre. Accelerated data-flow analysis. In [*SAS*]{}, pages 184–199, 2007.

Y. Li, A. Albarghouthi, Z. Kincaid, A. Gurfinkel, and M. Chechik. Symbolic optimization with [SMT]{} solvers. In [*POPL*]{}, pages 607–618, 2014.

A. Min[é]{}. Symbolic methods to enhance the precision of numerical abstract domains. In [*VMCAI*]{}, pages 348–363, 2006.

D. Monniaux. Automatic modular abstractions for linear constraints. In [*POPL*]{}, pages 140–151, 2009.

D. Monniaux. Quantifier elimination by lazy model enumeration. In [*CAV*]{}, pages 585–599, 2010.

M. Müller-Olm and H. Seidl. Precise interprocedural analysis through linear algebra. POPL, pages 330–341, 2004.

G. C. Necula, S. McPeak, S. P. Rahul, and W. Weimer. : Intermediate language and tools for analysis and transformation of [C]{} programs. In [*CC*]{}, pages 213–228, 2002.

C. Popeea and W.-N. Chin. Inferring disjunctive postconditions. ASIAN, pages 331–345, 2007.

T. W. Reps, S. Sagiv, and G. Yorsh. Symbolic implementation of the best transformer. In [*VMCAI*]{}, pages 252–266, 2004.

B. G. Ryder and M. C. Paull. Elimination algorithms for data flow analysis. , 18(3):277–316, Sept. 1986.

A. Schrijver. . John Wiley & Sons, Inc., New York, NY, USA, 1986.

M. Sharir and A. Pnueli. , chapter 7, pages 189–234. Prentice-Hall, Englewood Cliffs, NJ, 1981.

R. E. Tarjan. Fast algorithms for solving path problems. , 28(3):594–614, July 1981.

[^1]: This algorithm is a specialization of the one in [@Reps2004] to the abstract domain of linear equalities.

[^2]: The tool and benchmarks are available at <http://cs.toronto.edu/~zkincaid/lra>.
