Keywords

figure a
figure b

1 Introduction

It is hardly a surprising idea that term rewriting can serve as a vehicle for reasoning about programs. During the last decade or so, the term rewriting community has seen a line of work that translates real-world problems from program analysis into questions about term rewriting systems, which include, for example, termination (see, e.g., [8, 10, 15, 37]) and equivalence (see, e.g., [9, 13, 36]). Such applications take place across programming paradigms due to the versatile nature of term rewriting, and often materialize into automatable solutions.

Data types are a central building block of programs and must be properly handled in program analysis. While it is rarely a problem for term rewriting systems to represent (co)inductively defined data types, others such as integers and arrays traditionally require encoding; think of \( {\textsf{neg}}\ {({\textsf{suc}}\ {({\textsf{suc}}\ {({\textsf{suc}}\ {\textsf{zero}})})})} \) encoding \( -3 \). This usually turns out to cause more obfuscation than clarification to the methods applied and the results obtained. An alternative is to incorporate primitive data types into the formalism, which contributes to the proliferation of subtly different formalisms that are generally incompatible with each other, and it is often difficult to transfer techniques between such formalisms.

Logically constrained term rewriting systems (LCTRSs) [12, 27] emerged from this proliferation as a unifying formalism seeking to be general in both the selection of primitive data types (little is presumed) and the applicability of varied methods (many are extensible). LCTRSs thus allow us to benefit from the broad term rewriting arsenal in a wide range of scenarios for program analysis (see, e.g., [23, 24, 32]). In particular, rewriting induction on LCTRSs [12, 30] offers a powerful tool for program verification.

As a first-order formalism, LCTRSs only naturally accommodate imperative programs. This paper aims to generalize this formalism in a higher-order setting.

Motivation. Below is a first-order LCTRS implementing the factorial function:

$$\begin{aligned} {\textsf{fact}}\ {n} \rightarrow 1 \quad [n \le 0] \qquad {\textsf{fact}}\ {n} \rightarrow n * {\textsf{fact}}\ {(n - 1)} \quad [n > 0] \end{aligned}$$

where \( n \le 0 \) and \( n > 0 \) are logical constraints, which the integer \( n \) must satisfy respectively when the corresponding rewrite rule is applied. Suppose we have access to higher-order functions, a defining feature of functional programming; now we have the following alternative implementation of \( \textsf{fact}\):

$$\begin{aligned}\begin{gathered} {\textsf{fact}}\ {n} \rightarrow {{{\textsf{fold}}\ {(*)}}\ {1}}\ {({\textsf{genlist}}\ {n})}\\ \begin{aligned} {\textsf{genlist}}\ {n} \rightarrow \textsf{nil}\quad [n \le 0] \qquad & {\textsf{genlist}}\ {n} \rightarrow {{\textsf{cons}}\ {n}}\ {({\textsf{genlist}}\ {(n - 1)})} \quad [n > 0]\\ {{{\textsf{fold}}\ {f}}\ {y}}\ {\textsf{nil}} \rightarrow y \qquad & {{{\textsf{fold}}\ {f}}\ {y}}\ {({{\textsf{cons}}\ {x}}\ {l})} \rightarrow {{f}\ {x}}\ {({{{\textsf{fold}}\ {f}}\ {y}}\ {l})} \end{aligned} \end{gathered}\end{aligned}$$

Here \( \textsf{fold}\) takes an argument \( f \), which itself represents a function. Higher-order functions such as \( \textsf{fold}\) do not fit into first-order LCTRSs, which leads to the first reason to generalize this formalism: to overcome the limitation of its expressivity.

There is another reason for higher-order LCTRSs. The latter implementation of \( \textsf{fact}\) reflects a pattern of functional programming: the combination of “standard” higher-order building blocks such as \( \textsf{fold}\) and \( \textsf{map} \), and functions that are specific to the problem at hand. We note that a higher-order formalism can reveal more modularity in programs. It would be valuable to exploit such modularity in analyses as well.

With higher-order LCTRSs, we would like to explore automatable solutions to the termination problem of functional programs in the same fashion as the first-order case [25, 27], or even better, to the finding of their complexity by term rewriting. Moreover, given two programs supposedly implementing the same function, a method that derives whether they are indeed equivalent is also desirable. For example, a proof that the above two implementations of \( \textsf{fact}\) are equivalent may serve as a correctness proof of the latter, less intuitive implementation (which in general might be an outcome of code refactoring). Such methods have been explored in a first-order setting [7, 12].

Higher-order LCTRSs will broaden the horizons of both LCTRSs and higher-order term rewriting. The eventual goal is to have a formalism that can be deployed to analyze both imperative and functional programs, so that through this formalism, the abundant techniques based on term rewriting may be applied to automatic program analysis. This paper is a step toward that goal.

Contributions. The presentation begins with our perspective on higher-order term rewriting (without logical constraints) in Section 2. The contributions of this paper follow in subsequent sections:

  • We propose the formalism of logically constrained simply-typed term rewriting systems (LCSTRSs), a higher-order generalization of LCTRSs, in Section 3.

  • We adapt reduction orderings and rule removal to the newly proposed formalism, and define (as well as prove the soundness of) constrained HORPO—a variant of HORPO [21]—in Section 4. This includes changes to fit HORPO to curried notation and partial application, and to handle theory symbols and logical constraints in a similar way to RPO for first-order LCTRSs [27]. While this version of HORPO is not the most powerful higher-order termination technique, it offers a simple yet self-contained solution, and serves to illustrate how existing techniques may be extended.

  • We have developed for our formalism the foundation of a new open-source analysis tool, in which an implementation of constrained HORPO is provided. It requires several new insights, especially with regard to the way theories and logical constraints are handled, and is discussed in Section 6.

2 Preliminaries

One of the first problems that a student of higher-order term rewriting faces is the absence of a standard formalism on which the literature agrees. This variety reflects the diverse interests and needs held by different authors.

In this section, we present simply-typed term rewriting systems (STRSs) [29] as the unconstrained basis of our formalism. This is one of the simplest higher-order formalisms, and closely resembles simple functional programs. We choose this formalism as our starting point because it is already powerful, while avoiding many of the complications that may be interesting for equational reasoning purposes but are not needed in program analysis, such as reduction modulo \( \beta \).

Types and Terms. Types rule out undesired terms. We consider simple types: given a non-empty set \( \mathcal {S}\) of sorts (or base types), the set \( \mathcal {T}\) of simple types over \( \mathcal {S}\) is generated by the grammar \( \mathcal {T}:\,\!:=\mathcal {S}\mid (\mathcal {T}\rightarrow \mathcal {T}) \). Right-associativity is assigned to \( \rightarrow \) so we can omit some parentheses. The order of a type \( A\), denoted by \( {\text {ord}}({A}) \), is defined as follows: \( {\text {ord}}({A}) = 0 \) for \( A\in \mathcal {S}\) and \( {\text {ord}}({A\rightarrow B}) = \max ({\text {ord}}({A}) + 1, {\text {ord}}({B})) \).

Given disjoint sets \( \mathcal {F}\) and \( \mathcal {V}\), whose elements we call function symbols and variables, respectively, the set \( \mathfrak {T}\) of pre-terms over \( \mathcal {F}\) and \( \mathcal {V}\) is generated by the grammar \( \mathfrak {T}:\,\!:=\mathcal {F}\mid \mathcal {V}\mid ({\mathfrak {T}}\ {\mathfrak {T}}) \). Left-associativity is assigned to the juxtaposition operation, called application, so \( {{t_0}\ {t_1}}\ {t_2} \) stands for \( ({({t_0}\ {t_1})}\ {t_2}) \), for example.

We assume that every function symbol and variable is assigned a unique type. Typing works as expected: if pre-terms \( t_0 \) and \( t_1 \) have types \( A\rightarrow B\) and \( A\), respectively, \( {t_0}\ {t_1} \) has type \( B\). The set of terms over \( \mathcal {F}\) and \( \mathcal {V}\), denoted by \( T({\mathcal {F}}, {\mathcal {V}}) \), is the subset of \( \mathfrak {T}\) consisting of pre-terms with a type. We write \( t:A\) if a term \( t\) has type \( A\). The set of variables occurring in a term \( t\in T({\mathcal {F}}, {\mathcal {V}}) \), denoted by \( {\text {Var}}({t}) \), is defined as follows: \( {\text {Var}}({f}) = \emptyset \) for \( f\in \mathcal {F}\), \( {\text {Var}}({x}) = \left\{ \, x \,\right\} \) for \( x\in \mathcal {V}\) and \( {\text {Var}}({{t_0}\ {t_1}}) = {\text {Var}}({t_0}) \cup {\text {Var}}({t_1}) \). A term \( t\) is called ground if \( {\text {Var}}({t}) = \emptyset \). The set of ground terms over \( \mathcal {F}\) is denoted by \( T({\mathcal {F}}, {\emptyset }) \).

Substitutions and Contexts. Variables occurring in a term can be seen as placeholders: the occurrences of a variable may be replaced with terms which have the same type as the variable does. Type-preserving mappings from \( \mathcal {V}\) to \( T({\mathcal {F}}, {\mathcal {V}}) \) are called substitutions. Every substitution \( \sigma \) extends to a type-preserving mapping \( \bar{\sigma } \) from \( T({\mathcal {F}}, {\mathcal {V}}) \) to \( T({\mathcal {F}}, {\mathcal {V}}) \). We write \( t\sigma \) for \( \bar{\sigma }(t) \) and define it as follows: \( f\sigma = f\) for \( f\in \mathcal {F}\), \( x\sigma = \sigma (x) \) for \( x\in \mathcal {V}\) and \( ({t_0}\ {t_1}) \sigma = {(t_0 \sigma )}\ {(t_1 \sigma )} \).

Term formation gives rise to the concept of a context: a term containing a hole. Formally, let \( \square \) be a special terminal symbol denoting the hole, and the grammar \( \mathfrak {C}:\,\!:=\square \mid ({\mathfrak {C}}\ {\mathfrak {T}}) \mid ({\mathfrak {T}}\ {\mathfrak {C}}) \) with the above rule for \( \mathfrak {T}\) generates pre-terms containing exactly one occurrence of the hole. Given a type for the hole, a context is an element of \( \mathfrak {C}\) which is typed as a term is. Let \( {C}[{}]_A\) denote a context in which the hole has type \( A\); filling the hole with a term \( t:A\) produces the term \( {C}[{t}]_A\) defined as follows: \( {\square }[{t}]_A= t\), \( {({{C_0}[{}]_A}\ {t_1})}[{t}]_A= {{C_0}[{t}]_A}\ {t_1} \) and \( {({t_0}\ {{C_1}[{}]_A})}[{t}]_A= {t_0}\ {{C_1}[{t}]_A} \). We usually omit types in the above notation, and in \( {C}[{t}] \), \( t\) is understood as a term which has the same type as the hole does.

Rules and Rewriting. Now we have all the ingredients in our recipe for higher-order term rewriting. A rewrite rule \( \ell \rightarrow r\) is an ordered pair of terms where \( \ell \) and \( r\) have the same type, \( {\text {Var}}({\ell }) \supseteq {\text {Var}}({r}) \) and \( \ell \) assumes the form \( {f}\ {{t}_{1} \cdots {t}_{n}} \) for some function symbol \( f\). Formally, a simply-typed term rewriting system (STRS) is a quadruple \( (\mathcal {S}, \mathcal {F}, \mathcal {V}, \mathcal {R}) \) where every element of \( \mathcal {F}\cup \mathcal {V}\) is assigned a simple type over \( \mathcal {S}\) and \( \mathcal {R}\subseteq T({\mathcal {F}}, {\mathcal {V}}) \times T({\mathcal {F}}, {\mathcal {V}}) \) is a set of rewrite rules. We usually let \( \mathcal {R}\) alone stand for the system and keep the details of term formation implicit.

The set \( \mathcal {R}\) of rewrite rules induces the rewrite relation \( {\rightarrow _\mathcal {R}} \subseteq T({\mathcal {F}}, {\mathcal {V}}) \times T({\mathcal {F}}, {\mathcal {V}}) \): \( t\rightarrow _\mathcal {R}t^\prime \) if and only if there exist a rewrite rule \( \ell \rightarrow r\in \mathcal {R}\), a substitution \( \sigma \) and a context \( {C}[{}] \) such that \( t= {C}[{\ell \sigma }] \) and \( t^\prime = {C}[{r\sigma }] \). When there is no ambiguity about the system in question, we may simply write \( \rightarrow \) for \( \rightarrow _\mathcal {R}\).

Given a relation \( {\succ } \subseteq X\times X\), an element \( x\) of \( X\) is called terminating with respect to \( \succ \) if there is no infinite sequence \( x= x_0 \succ x_1 \succ \cdots \), and \( \succ \) is called well-founded if all the elements of \( X\) are terminating with respect to \( \succ \). An STRS \( \mathcal {R}\) is called terminating if \( \rightarrow _\mathcal {R}\) is well-founded.

Example 1

The following rewrite rules constitute a terminating system:

$$\begin{aligned} {{\textsf{take}}\ {\textsf{zero}}}\ {l} \rightarrow \textsf{nil}\quad {{\textsf{take}}\ {n}}\ {\textsf{nil}} \rightarrow \textsf{nil}\quad {{\textsf{take}}\ {({\textsf{suc}}\ {n})}}\ {({{\textsf{cons}}\ {x}}\ {l})} \rightarrow {{\textsf{cons}}\ {x}}\ {({{\textsf{take}}\ {n}}\ {l})} \end{aligned}$$

where \( \textsf{zero}:\textsf{nat}\), \( \textsf{suc}:\textsf{nat}\rightarrow \textsf{nat}\), \( \textsf{nil}:\textsf{natlist}\), \( \textsf{cons}:\textsf{nat}\rightarrow \textsf{natlist}\rightarrow \textsf{natlist}\) and \( \textsf{take}:\textsf{nat}\rightarrow \textsf{natlist}\rightarrow \textsf{natlist}\) are function symbols, and \( l :\textsf{natlist}\), \( n :\textsf{nat}\) and \( x :\textsf{nat}\) are variables.

Example 2

The following rewrite rule constitutes a non-terminating system:

$$\begin{aligned} {{\textsf{iterate}}\ {f}}\ {x} \rightarrow {{\textsf{cons}}\ {x}}\ {({{\textsf{iterate}}\ {f}}\ {({f}\ {x})})} \end{aligned}$$

where \( \textsf{cons}:\textsf{nat}\rightarrow \textsf{natlist}\rightarrow \textsf{natlist}\) and \( \textsf{iterate}:(\textsf{nat}\rightarrow \textsf{nat}) \rightarrow \textsf{nat}\rightarrow \textsf{natlist}\) are function symbols, and \( f :\textsf{nat}\rightarrow \textsf{nat}\) and \( x :\textsf{nat}\) are variables.

Limitations. The above formalism does not offer product types, polymorphism or \( \lambda \)-abstractions. What it does offer is its already expressive syntax enabling us, in a higher-order setting, to generalize LCTRSs and to discover what challenges one may face when extending existing unconstrained techniques. We expect that, once preliminary higher-order results are developed, we will adopt more features from other higher-order formalisms in future extensions.

The exclusion of \( \lambda \)-abstractions does not rid us of first-class functions, thanks to curried notation. For example, the occurrence of \( \textsf{suc}\) in \( {{\textsf{iterate}}\ {\textsf{suc}}}\ {\textsf{zero}} \) is partially (in this case, not at all) applied and still forms a term, which can be passed as an argument. Also, a term such as \( {{\textsf{iterate}}\ {(\lambda {x}.\, {\textsf{suc}}\ {({\textsf{suc}}\ {x})})}}\ {\textsf{zero}} \) can be simulated at the cost of an extra rewrite rule (in this case, \( {\textsf{add2}}\ {x} \rightarrow {\textsf{suc}}\ {({\textsf{suc}}\ {x})} \)). There are also straightforward ways of encoding product types.

Notions of Termination. If we combine the two systems from Examples 1 and 2, the outcome is surely non-terminating: \( {{\textsf{take}}\ {\textsf{zero}}}\ {({{\textsf{iterate}}\ {\textsf{suc}}}\ {\textsf{zero}})} \) is not terminating, for example. From a Haskell programmer’s perspective, however, this term is “terminating” due to the non-strictness of Haskell. In general, every functional language uses a certain evaluation strategy to choose a specific redex, if any, to rewrite within a term, whereas the rewrite relation we define in this section corresponds to full rewriting: the redex is chosen non-deterministically.

Furthermore, programmers usually care only about the termination of terms that are reachable from the entry point of a program and seldom consider full termination: the termination of all terms, i.e., the well-foundedness of the rewrite relation. We study full termination with respect to full rewriting in this paper, as it implies any other termination properties and full termination is often a prerequisite for determining properties such as confluence and equivalence.

3 Logically Constrained STRSs

Term rewriting systems do not have primitive data types built in; with some function symbols constructing (introducing) values of a certain type and pattern matching rules deconstructing (eliminating) those values, a term rewriting system relies on (co)inductively defined data types. While (co)inductive reasoning is straightforward this way, data types such as integers and arrays require encoding, which can be convoluted; think of the space-consuming unary representation of a number or a binary representation which takes less space but shifts the burden to rewrite rules defining arithmetic, and negative numbers bring up even more complications. Besides, such encoding neglects advances in modern SMT solvers.

In this section, we extend unconstrained STRSs with logical constraints so that data types that are not (co)inductively defined can be represented directly, and analysis tools can take advantage of existing SMT solvers. We follow the ideas of first-order LCTRSs [12, 27]. Specifically, we will consider systems over arbitrary first-order theories, i.e., we are not bound to, say, systems over integers, while avoiding higher-order logical constraints. In the unconstrained part of such a system (outside theories), however, higher-order arguments and results are still completely usable.

3.1 Terms Modulo Theories

Following Section 2, we postulate a set \( \mathcal {S}\) of sorts, a set \( \mathcal {F}\) of function symbols and a set \( \mathcal {V}\) of variables where every element of \( \mathcal {F}\cup \mathcal {V}\) is assigned a simple type over \( \mathcal {S}\). First, we assume that there is a distinguished subset \( {\mathcal {S}}_\vartheta \) of \( \mathcal {S}\), called the set of theory sorts. The grammar \( {\mathcal {T}}_\vartheta :\,\!:={\mathcal {S}}_\vartheta \mid ({\mathcal {S}}_\vartheta \rightarrow {\mathcal {T}}_\vartheta ) \) generates the set \( {\mathcal {T}}_\vartheta \) of theory types over \( {\mathcal {S}}_\vartheta \). Note that the order of a theory type is never greater than one. Next, we assume that there is a distinguished subset \( {\mathcal {F}}_\vartheta \) of \( \mathcal {F}\), called the set of theory symbols, and that the type of every theory symbol is in \( {\mathcal {T}}_\vartheta \), which means that the type of any argument passed to a theory symbol is a theory sort. Elements of \( T({{\mathcal {F}}_\vartheta }, {\mathcal {V}}) \) are called theory terms. Last, for technical reasons, we assume that there are infinitely many variables of each type.

Theory symbols are interpreted in an underlying theory: given an \( {\mathcal {S}}_\vartheta \)-indexed family of sets \( (\mathfrak {X}_A)_{A\in {\mathcal {S}}_\vartheta } \), we extend it to a \( {\mathcal {T}}_\vartheta \)-indexed family by letting \( \mathfrak {X}_{A\rightarrow B} \) be the set of mappings from \( \mathfrak {X}_A\) to \( \mathfrak {X}_B\); an interpretation of theory symbols is a \( {\mathcal {T}}_\vartheta \)-indexed family of mappings \( ([\![\cdot ]\!]_A)_{A\in {\mathcal {T}}_\vartheta } \) where \( [\![\cdot ]\!]_A\) assigns to each theory symbol of type \( A\) an element of \( \mathfrak {X}_A\) and is bijectiveFootnote 1 if \( A\in {\mathcal {S}}_\vartheta \). Theory symbols whose type is a theory sort are called values. Given an interpretation of theory symbols \( ([\![\cdot ]\!]_A)_{A\in {\mathcal {T}}_\vartheta } \), we extend each indexed mapping \( [\![\cdot ]\!]_B\) to one that assigns to each ground theory term of type \( B\) an element of \( \mathfrak {X}_B\) by letting \( [\![{t_0}\ {t_1}]\!]_B\) be \( [\![t_0]\!]_{A\rightarrow B}([\![t_1]\!]_A) \). We usually write just \( [\![\cdot ]\!] \) when the type can be deduced.

Example 3

Let \( {\mathcal {S}}_\vartheta \) be \( \left\{ \, \textsf{int} \,\right\} \). Then \( \textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}\) is a theory type over \( {\mathcal {S}}_\vartheta \) while \( (\textsf{int}\rightarrow \textsf{int}) \rightarrow \textsf{int}\) is not. Let \( {\mathcal {F}}_\vartheta \) be \( \left\{ \, \textsf{sub} \,\right\} \cup \left\{ \, \bar{n} \,\left| \, n \in \mathbb {Z}\right. \,\right\} \) where \( \textsf{sub}:\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}\) and \( \bar{n} :\textsf{int}\). The values are the elements of \( \left\{ \, \bar{n} \,\left| \, n \in \mathbb {Z}\right. \,\right\} \). Let \( \mathfrak {X}_\textsf{int}\) be \( \mathbb {Z}\), \( [\![\cdot ]\!]_\textsf{int}\) be the mapping \( \bar{n} \mapsto n \) and \( [\![\textsf{sub}]\!] \) be the mapping \( \lambda {m}.\, \lambda {n}.\, m - n \). The interpretation of \( {\textsf{sub}}\ {\bar{1}} \) is the mapping \( \lambda {n}.\, 1 - n \).

We are not limited to the theory of integers:

Example 4

To reason about integer arrays, we could either represent them as lists and simulate random access through more costly list traversal (which affects the complexity), or consider a theory of bounded arrays as follows: Let \( {\mathcal {S}}_\vartheta \) be \( \left\{ \, \textsf{int}, \textsf{intarray} \,\right\} \) and \( {\mathcal {F}}_\vartheta \) be the union of \( \left\{ \, \textsf{size}, \textsf{select}, \textsf{store} \,\right\} \), \( \left\{ \, \bar{n} \,\left| \, n \in \mathbb {Z}\right. \,\right\} \) and \( \left\{ \, \langle {\bar{n}}_{0} , \ldots , {\bar{n}}_{k - 1}\rangle \,\left| \, k \in \mathbb {N}\text { and } \forall {i}.\, n_i \in \mathbb {Z}\right. \,\right\} \) where \( \textsf{size}:\textsf{intarray}\rightarrow \textsf{int}\), \( \textsf{select}:\textsf{intarray}\rightarrow \textsf{int}\rightarrow \textsf{int}\), \( \textsf{store}:\textsf{intarray}\rightarrow \textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{intarray}\), \( \bar{n} :\textsf{int}\) and \( \langle {\bar{n}}_{0} , \ldots , {\bar{n}}_{k - 1}\rangle :\textsf{intarray}\). Let \( \mathfrak {X}_\textsf{int}\) and \( \mathfrak {X}_\textsf{intarray}\) be \( \mathbb {Z}\) and \( \mathbb {Z}^* \), respectively. Let \( [\![\cdot ]\!]_\textsf{int}\) be the mapping \( \bar{n} \mapsto n \) and \( [\![\cdot ]\!]_\textsf{intarray}\) be the mapping \( \langle {\bar{n}}_{0} , \ldots , {\bar{n}}_{k - 1}\rangle \mapsto {n}_{0} \ldots {n}_{k - 1} \). Let \( [\![\textsf{size}]\!]({n}_{0} \ldots {n}_{k - 1}) \) be \( k \). Let \( [\![\textsf{select}]\!]({n}_{0} \ldots {n}_{k - 1}, i) \) be \( n_i \) if \( 0 \le i < k \), and \( 0 \) otherwise. Let \( [\![\textsf{store}]\!]({n}_{0} \ldots {n}_{k - 1}, i, m) \) be \( {n}_{0} \ldots {n}_{i - 1} m {n}_{i + 1} \ldots {n}_{k - 1} \) if \( 0 \le i < k \), and \( {n}_{0} \ldots {n}_{k - 1} \) otherwise. Note that the values include theory symbols \( \langle {\bar{n}}_{0} , \ldots , {\bar{n}}_{k - 1}\rangle :\textsf{intarray}\) as well as \( \bar{n} :\textsf{int}\).

In this paper, we largely consider the theory of integers in Example 3 when giving examples because it is easy to understand. This particular theory does not play a special role for the formalism we will shortly present; in fact, the theory of bit vectors may be more appropriate to real-world programs using integers, and our formalism is not biased toward any choice of theories. In particular, we do not have to choose predefined theories from SMT-LIB [3]. The theory of bounded arrays in Example 4 is an instance of such a “non-standard” theory (which can nevertheless be encoded within the theory of functional arrays). On the other hand, theories supported by SMT solvers are preferable in light of automation.

3.2 Constrained Rewriting

Constrained rewriting requires the theory sort \( \textsf{bool}\): we henceforth assume that \( \textsf{bool}\in {\mathcal {S}}_\vartheta \), \( \left\{ \, \mathfrak {f}, \mathfrak {t} \,\right\} \subseteq {\mathcal {F}}_\vartheta \), \( \mathfrak {X}_\textsf{bool}= \left\{ \, 0, 1 \,\right\} \), \( [\![\mathfrak {f}]\!]_\textsf{bool}= 0\) and \( [\![\mathfrak {t}]\!]_\textsf{bool}= 1\). A logical constraint is a theory term \( \varphi \) such that \( \varphi \) has type \( \textsf{bool}\) and the type of each variable in \( {\text {Var}}({\varphi }) \) is a theory sort. A (constrained) rewrite rule is a triple \( {\ell }\rightarrow {r}\ [{\varphi }] \) where \( \ell \) and \( r\) are terms which have the same type, \( \varphi \) is a logical constraint, the type of each variable in \( {\text {Var}}({r}) \setminus {\text {Var}}({\ell }) \) is a theory sort and \( \ell \) is a term that assumes the form \( {f}\ {{t}_{1} \cdots {t}_{n}} \) for some function symbol \( f\) and contains at least one function symbol in \( \mathcal {F}\setminus {\mathcal {F}}_\vartheta \).Footnote 2

This definition can be obscure at first glance, especially when compared with its unconstrained counterpart in Section 2: variables which do not occur in \( \ell \) are allowed to occur in \( r\), not to mention the logical constraint \( \varphi \) as a brand-new component. Given a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \), the idea is that variables occurring in \( \varphi \) are to be instantiated to values which make \( \varphi \) true and other variables which occur in \( r\) but not in \( \ell \) are to be instantiated to arbitrary values—note that the type of each of these variables is a theory sort. Formally, given an interpretation of theory symbols \( [\![\cdot ]\!] \), a substitution \( \sigma \) is said to respect a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) if \( \sigma (x) \) is a value for all \( x\in {\text {Var}}({\varphi }) \cup ({\text {Var}}({r}) \setminus {\text {Var}}({\ell })) \) and \( [\![\varphi \sigma ]\!] = 1\).

We summarize all the above ingredients in the following definition:

Definition 1

A logically constrained STRS (LCSTRS) consists of \( \mathcal {S}\), \( {\mathcal {S}}_\vartheta \), \( \mathcal {F}\), \( {\mathcal {F}}_\vartheta \), \( \mathcal {V}\), \( (\mathfrak {X}_A) \), \( [\![\cdot ]\!] \) and \( \mathcal {R}\) where

  1. 1.

    \( \mathcal {S}\) is a set of sorts,

  2. 2.

    \( {\mathcal {S}}_\vartheta \subseteq \mathcal {S}\) is a set of theory sorts which contains \( \textsf{bool}\),

  3. 3.

    \( \mathcal {F}\) is a set of function symbols in which every function symbol is assigned a simple type over \( \mathcal {S}\),

  4. 4.

    \( {\mathcal {F}}_\vartheta \subseteq \mathcal {F}\) is a set of theory symbols in which the type of every theory symbol is a theory type over \( {\mathcal {S}}_\vartheta \), with \( \mathfrak {f}:\textsf{bool}\) and \( \mathfrak {t}:\textsf{bool}\) elements of \( {\mathcal {F}}_\vartheta \),

  5. 5.

    \( \mathcal {V}\) is a set of variables disjoint from \( \mathcal {F}\) in which every variable is assigned a simple type over \( \mathcal {S}\) and there are infinitely many variables to which every type is assigned,

  6. 6.

    \( (\mathfrak {X}_A) \) is an \( {\mathcal {S}}_\vartheta \)-indexed family of sets such that \( \mathfrak {X}_\textsf{bool}= \left\{ \, 0, 1 \,\right\} \),

  7. 7.

    \( [\![\cdot ]\!] \) is an interpretation of theory symbols such that \( [\![\mathfrak {f}]\!] = 0\) and \( [\![\mathfrak {t}]\!] = 1\), and

  8. 8.

    \( \mathcal {R}\subseteq T({\mathcal {F}}, {\mathcal {V}}) \times T({\mathcal {F}}, {\mathcal {V}}) \times T({{\mathcal {F}}_\vartheta }, {\mathcal {V}}) \) is a set of rewrite rules.

We usually let \( \mathcal {R}\) alone stand for the system.

And the following definition concludes the elaboration of constrained rewriting:

Definition 2

Given an LCSTRS \( \mathcal {R}\), the set of rewrite rules induces the rewrite relation \( {\rightarrow _\mathcal {R}} \subseteq T({\mathcal {F}}, {\mathcal {V}}) \times T({\mathcal {F}}, {\mathcal {V}}) \) such that \( t\rightarrow _\mathcal {R}t^\prime \) if and only if one of the following conditions is true:

  1. 1.

    There exist a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \in \mathcal {R}\), a substitution \( \sigma \) which respects \( {\ell }\rightarrow {r}\ [{\varphi }] \) and a context \( {C}[{}] \) such that \( t= {C}[{\ell \sigma }] \) and \( t^\prime = {C}[{r\sigma }] \).

  2. 2.

    There exist theory symbols \( v_1 :A_1, \ldots , v_n :A_n, v^\prime :B\) and \( f:{A}_{1} \rightarrow \cdots \rightarrow {A}_{n} \rightarrow B\) for \( n > 0 \) and \( {A}_{1} , \ldots , {A}_{n}, B\in {\mathcal {S}}_\vartheta \) such that \( [\![{f}\ {{v}_{1} \cdots {v}_{n}}]\!] = [\![v^\prime ]\!] \), and a context \( {C}[{}] \) such that \( t= {C}[{{f}\ {{v}_{1} \cdots {v}_{n}}}] \) and \( t^\prime = {C}[{v^\prime }] \).

Note that the above conditions are mutually exclusive for any given context \( {C}[{}] \): \( {f}\ {{v}_{1} \cdots {v}_{n}} \) is a theory term, whereas \( \ell \) in any rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) is not. If \( t\rightarrow _\mathcal {R}t^\prime \) due to the second condition, we also write \( t\rightarrow _\kappa t^\prime \) and call it a step of calculation. When no ambiguity arises, we may simply write \( \rightarrow \) for \( \rightarrow _\mathcal {R}\).

Example 5

We can rework Example 1 into an LCSTRS:

$$\begin{aligned} {{\textsf{take}}\ {n}}\ {l} &\rightarrow \textsf{nil}{} & {} [n \le 0] & {{\textsf{take}}\ {n}}\ {\textsf{nil}} &\rightarrow \textsf{nil}\\ {{\textsf{take}}\ {n}}\ {({{\textsf{cons}}\ {x}}\ {l})} &\rightarrow {{\textsf{cons}}\ {x}}\ {({{\textsf{take}}\ {(n - 1)}}\ {l})} {} & {} [n > 0] \end{aligned}$$

where \( \mathcal {S}= {\mathcal {S}}_\vartheta \cup \left\{ \, \textsf{intlist} \,\right\} \), \( {\mathcal {S}}_\vartheta = \left\{ \, \textsf{bool}, \textsf{int} \,\right\} \), \( \mathcal {F}= {\mathcal {F}}_\vartheta \cup \left\{ \, \textsf{nil}, \textsf{cons}, \textsf{take} \,\right\} \), \( {\mathcal {F}}_\vartheta = \left\{ \, \le , >, -, \mathfrak {f}, \mathfrak {t} \,\right\} \cup \mathbb {Z}\), \( \mathcal {V}\supseteq \left\{ \, l, n, x \,\right\} \), \( {\le } :\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{bool}\), \( {>} :\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{bool}\), \( {-} :\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}\), \( \mathfrak {f}:\textsf{bool}\), \( \mathfrak {t}:\textsf{bool}\), \( v:\textsf{int}\) for all \( v\in \mathbb {Z}\), \( \textsf{nil}:\textsf{intlist}\), \( \textsf{cons}:\textsf{int}\rightarrow \textsf{intlist}\rightarrow \textsf{intlist}\), \( \textsf{take}:\textsf{int}\rightarrow \textsf{intlist}\rightarrow \textsf{intlist}\), \( l :\textsf{intlist}\), \( n :\textsf{int}\) and \( x :\textsf{int}\).

Here and henceforth we let integer literals and operators, e.g., \( 0 \), \( 1 \), \( \le \), > and \( - \), denote both the corresponding theory symbols and their respective images under the interpretation—in contrast to Examples 3 and 4, where we pedantically make a distinction between, say, \( \bar{1} \) and \( 1 \). We also use infix notation for some binary operators to improve readability, and omit the logical constraint of a rewrite rule when it is \( \mathfrak {t}\). Below is a rewrite sequence:

$$\begin{aligned} {{\textsf{take}}\ {1}}\ {({{\textsf{cons}}\ {x}}\ {({{\textsf{cons}}\ {y}}\ {l})})} &\rightarrow {{\textsf{cons}}\ {x}}\ {({{\textsf{take}}\ {(1 - 1)}}\ {({{\textsf{cons}}\ {y}}\ {l})})}\\ \rightarrow _\kappa {{\textsf{cons}}\ {x}}\ {({{\textsf{take}}\ {0}}\ {({{\textsf{cons}}\ {y}}\ {l})})} &\rightarrow {{\textsf{cons}}\ {x}}\ {\textsf{nil}} \end{aligned}$$

Example 6

In Section 1, the rewrite rules implementing the factorial function by \( \textsf{fold}\) constitute an LCSTRS. Below is a rewrite sequence:

$$\begin{aligned} {\textsf{fact}}\ {1} &\rightarrow {{{\textsf{fold}}\ {(*)}}\ {1}}\ {({\textsf{genlist}}\ {1})} \rightarrow {{{\textsf{fold}}\ {(*)}}\ {1}}\ {({{\textsf{cons}}\ {1}}\ {({\textsf{genlist}}\ {(1 - 1)})})}\\ &\rightarrow _\kappa {{{\textsf{fold}}\ {(*)}}\ {1}}\ {({{\textsf{cons}}\ {1}}\ {({\textsf{genlist}}\ {0})})} \rightarrow {{{\textsf{fold}}\ {(*)}}\ {1}}\ {({{\textsf{cons}}\ {1}}\ {\textsf{nil}})}\\ &\rightarrow {{(*)}\ {1}}\ {({{{\textsf{fold}}\ {(*)}}\ {1}}\ {\textsf{nil}})} \rightarrow {{(*)}\ {1}}\ {1} \rightarrow _\kappa 1 \end{aligned}$$

Example 7

Consider the rewrite rule \( \textsf{readint}\rightarrow n \), in which the variable \( n :\textsf{int}\) occurs on the right-hand side of \( \rightarrow \) but not on the left. Unconstrained STRSs do not permit such a rewrite rule, but LCSTRSs do. It looks as if we might rewrite \( \textsf{readint}\) to a variable but it is not the case: all the substitutions which respect this rewrite rule must map \( n \) to a value. Indeed, \( \textsf{readint}\) is always rewritten to a value of type \( \textsf{int}\). We may have, say, \( \textsf{readint}\rightarrow 42 \). Such variables can be used to model user input.

Example 8

Getting input by means of the rewrite rule from Example 7 has one flaw: in case of multiple integers to be read, the order of reading each is non-deterministic. Even in the presence of an evaluation strategy, the order may not be the desired one. We can use continuation-passing style to choose an order:

$$\begin{aligned} {\textsf{readint}}\ {k} \rightarrow {k}\ {n} \quad {{{\textsf{comp}}\ {g}}\ {f}}\ {x} \rightarrow {g}\ {({f}\ {x})} \quad \textsf{sub}\rightarrow {\textsf{readint}}\ {({{\textsf{comp}}\ {\textsf{readint}}}\ {(-)})} \end{aligned}$$

where \( \textsf{comp}:((\textsf{int}\rightarrow \textsf{int}) \rightarrow \textsf{int}) \rightarrow (\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}) \rightarrow \textsf{int}\rightarrow \textsf{int}\). If the first and the second integers to be read were \( 1 \) and \( 2 \), respectively, the following rewrite sequence would be the only one starting from \( \textsf{sub}\):

$$\begin{aligned} \textsf{sub}&\rightarrow {\textsf{readint}}\ {({{\textsf{comp}}\ {\textsf{readint}}}\ {(-)})} \rightarrow {{{\textsf{comp}}\ {\textsf{readint}}}\ {(-)}}\ {1}\\ &\rightarrow {\textsf{readint}}\ {({(-)}\ {1})} \rightarrow {{(-)}\ {1}}\ {2} \rightarrow _\kappa -1 \end{aligned}$$

Since there is no way to specify the actual input within an LCSTRS, rewrite sequences such as the one above cannot be derived deterministically. Nevertheless, this example demonstrates that the newly proposed formalism can represent relatively sophisticated control mechanisms utilized by functional programs.

Remarks. We reflect on some of the concepts presented in this section:

  • We use the phrase “terms modulo theories” in line with “satisfiability modulo theories”: some function symbols are interpreted within a theory. While such an interpretation gives rise to a way of identifying certain terms, namely those that are convertible to each other with respect to \( \rightarrow _\kappa \), we do not consider them identified (in other words, modulo \( \kappa \)) in this paper.

  • First-order LCTRSs can be seen as instances of the newly proposed formalism, i.e., ones in which the type order of each function symbol is no greater than one, variables with a non-zero type order (i.e., higher-order variables) are excluded, and the type of both sides of a rewrite rule is always a sort.

  • Logical constraints are essentially first-order: the type order of a theory symbol cannot be greater than one while higher-order variables are excluded. This restriction rules out, for example, the following implementation:

    $$\begin{aligned} {{\textsf{filter}}\ {f}}\ {({{\textsf{cons}}\ {x}}\ {l})} &\rightarrow {{\textsf{cons}}\ {x}}\ {({{\textsf{filter}}\ {f}}\ {l})} {} & {} [{f}\ {x}] & {{\textsf{filter}}\ {f}}\ {\textsf{nil}} &\rightarrow \textsf{nil}\\ {{\textsf{filter}}\ {f}}\ {({{\textsf{cons}}\ {x}}\ {l})} &\rightarrow {{\textsf{filter}}\ {f}}\ {l} {} & {} [{\lnot }\ {({f}\ {x})}] \end{aligned}$$

    The filter function can actually be implemented in an LCSTRS as follows:

    $$\begin{aligned}\begin{gathered} {{\textsf{filter}}\ {f}}\ {({{\textsf{cons}}\ {x}}\ {l})} \rightarrow {{{\textsf{if}}\ {({f}\ {x})}}\ {({{\textsf{cons}}\ {x}}\ {({{\textsf{filter}}\ {f}}\ {l})})}}\ {({{\textsf{filter}}\ {f}}\ {l})}\\ {{\textsf{filter}}\ {f}}\ {\textsf{nil}} \rightarrow \textsf{nil}\qquad {{{\textsf{if}}\ {\mathfrak {t}}}\ {l}}\ {l^\prime } \rightarrow l \qquad {{{\textsf{if}}\ {\mathfrak {f}}}\ {l}}\ {l^\prime } \rightarrow l^\prime \end{gathered}\end{aligned}$$

    In the former implementation, the problem is not the higher-order variable \( f \) itself but its occurrence in logical constraints. In this case, because the filter function is usually meant to be used in combination with “user-defined” predicates—which are function symbols defined by rewrite rules and therefore do not belong to the theories—it makes sense to disallow \( f \) from occurring in logical constraints. In general, we may encounter use cases for higher-order constraints; until then, we focus on first-order constraints, which are very common in functional programs.

4 Constrained Higher-Order Recursive Path Ordering

Recall that an important part of our goal is to allow the abundant term rewriting techniques to be applied toward program analysis. We have defined a formalism for constrained higher-order term rewriting; now it remains to be seen that—or how—existing techniques can be extended to it.

In the rest of this paper, we consider termination, an important aspect of program analysis and a topic that has been studied by the term rewriting community for decades. Not only is termination itself critical to the correctness of certain programs, but it also facilitates other analyses by admitting well-founded induction on terms.

In this section, we adapt HORPO [21] to our formalism. This is one of the oldest, yet still effective techniques for higher-order termination. HORPO can be used either as a stand-alone method or in a higher-order version of the dependency pair framework [1, 11, 25, 39]. Hence, this adaptation offers a solid basis for use in an analysis tool’s termination module. We will discuss the use of HORPO within the dependency pair framework in Section 5, and its automation in Section 6.

Constrained RPO for first-order LCTRSs was proposed in [27]. We take inspiration from it for its approach to theory terms, formalize the ideas, and add support for (higher) types as well as partial application.

4.1 HORPO, Unconstrained and Uncurried

We first recall HORPO in its original form. Note that the original definition is based on an unconstrained and uncurried format, and a thorough discussion on it is beyond the scope of this paper. The following presentation is mostly informal and only serves the purposes of comparison and inspiration.

We begin with two standard definitions:

Definition 3

Given relations \( \succsim \) and \( \succ \) over \( X\), the generalized lexicographic ordering \( {\succ ^\mathfrak {l}} \subseteq X^* \times X^* \) is induced as follows: \( {x}_{1} \ldots {x}_{m} \succ ^\mathfrak {l}{y}_{1} \ldots {y}_{n} \) if and only if there exists \( k \le \min (m, n) \) such that \( x_i \succsim y_i \) for all \( i < k \) and \( x_k \succ y_k \).

Definition 4

Given relations \( \succsim \) and \( \succ \) over \( X\), the generalized multiset ordering \( {\succ ^\mathfrak {m}} \subseteq X^* \times X^* \) is induced as follows: \( {x}_{1} \ldots {x}_{m} \succ ^\mathfrak {m}{y}_{1} \ldots {y}_{n} \) if and only if there exist a non-empty subset \( I\) of \( \left\{ \, 1, \ldots , m \,\right\} \) and a mapping \( \pi \) from \( \left\{ \, 1, \ldots , n \,\right\} \) to \( \left\{ \, 1, \ldots , m \,\right\} \) such that

  1. 1.

    \( \forall {i \in I}.\, \forall {j \in \pi ^{-1}(i)}.\, x_i \succ y_j \),

  2. 2.

    \( \forall {i \in \left\{ \, 1, \ldots , m \,\right\} \setminus I}.\, \forall {j \in \pi ^{-1}(i)}.\, x_i \succsim y_j \), and

  3. 3.

    \( \forall {i \in \left\{ \, 1 ,\ldots , m \,\right\} \setminus I}.\, \left|\pi ^{-1}(i)\right| = 1 \).

Here the generalized multiset ordering is formulated in terms of lists because we will compare argument lists by this ordering and this formulation facilitates implementation. In the following definition of HORPO, when we refer to the above definitions, \( \succsim \) is the equality over terms and \( \succ \) is HORPO itself.

Roughly, HORPO extends a given ordering over function symbols, and when considering terms headed by the same function symbol, compares the arguments by either of the above orderings. Given a well-founded ordering \( {\blacktriangleright } \subseteq \mathcal {F}\times \mathcal {F}\), called the precedence, and a mapping \( {\mathfrak {s}}: \mathcal {F}\rightarrow \left\{ \, \mathfrak {l}, \mathfrak {m} \,\right\} \), called the status, HORPO is a type-preserving relation \( \succ \) such that \( s\succ t\) if and only if one of the following conditions is true:

  1. 1.

    \( s= f({s}_{1} , \ldots , {s}_{m}) \), \( f\in \mathcal {F}\) and \( \exists {k}.\, s_k \succeq t \).

  2. 2.

    \( s= f({s}_{1} , \ldots , {s}_{m}) \), \( f\in \mathcal {F}\), \( t= @(\ldots @({@({t_0}, {t_1})}, {t_2}) \ldots , t_n) \) and \( \forall {i}.\, s\succ t_i \vee \exists {k}.\, s_k \succeq t_i \).

  3. 3.

    \( s= f({s}_{1} , \ldots , {s}_{m}) \), \( t= g({t}_{1} , \ldots , {t}_{n}) \), \( f\in \mathcal {F}\), \( g\in \mathcal {F}\), \( f\blacktriangleright g\) and \( \forall {i}.\, s\succ t_i \vee \exists {k}.\, s_k \succeq t_i \).

  4. 4.

    \( s= f({s}_{1} , \ldots , {s}_{m}) \), \( t= f({t}_{1} , \ldots , {t}_{m}) \), \( f\in \mathcal {F}\), \( {\mathfrak {s}}(f) = \mathfrak {l}\), \( {s}_{1} \ldots {s}_{m} \succ ^\mathfrak {l}{t}_{1} \ldots {t}_{m} \) and \( \forall {i}.\, s\succ t_i \vee \exists {k}.\, s_k \succeq t_i \).

  5. 5.

    \( s= f({s}_{1} , \ldots , {s}_{m}) \), \( t= f({t}_{1} , \ldots , {t}_{m}) \), \( f\in \mathcal {F}\), \( {\mathfrak {s}}(f) = \mathfrak {m}\) and \( {s}_{1} \ldots {s}_{m} \succ ^\mathfrak {m}{t}_{1} \ldots {t}_{m} \).

  6. 6.

    \( s= @({s_0}, {s_1}) \), \( t= @({t_0}, {t_1}) \) and \( s_0 s_1 \succ ^\mathfrak {m}t_0 t_1 \).

  7. 7.

    \( s= \lambda {x}.\, s_0 \), \( t= \lambda {x}.\, t_0 \) and \( s_0 \succ t_0 \).

Here \( \succeq \) denotes the reflexive closure of \( \succ \).

We call this format uncurried because every function symbol has an arity, i.e., the number of arguments guaranteed for each occurrence of the function symbol in a term. This is indicated by the functional notation \( f({s}_{1} , \ldots , {s}_{m}) \) as opposed to \( {f}\ {{s}_{1} \cdots {s}_{m}} \). If \( f\) has arity \( m \), its occurrence in a term must take \( m \) arguments so \( f({s}_{1} , \ldots , {s}_{m - 1}) \) is not a well-formed term, for example. A function symbol’s type (or more technically, its type declaration) can permit more arguments than its arity guarantees. Such an extra argument is supplied through the syntactic form \( @({\cdot }, {\cdot }) \). For example, if the same function symbol \( f\) is given an extra argument \( s_{m + 1} \), we write \( @({f({s}_{1} , \ldots , {s}_{m})}, {s_{m + 1}}) \). This syntactic form is also used to pass arguments to variables and \( \lambda \)-abstractions.

The difference between an uncurried and a curried format is more than a notational issue, and poses technical challenges to our extension of HORPO. Another source of challenges is, as one would expect, constrained rewriting.

4.2 Rule Removal

HORPO is defined as a reduction ordering \( \succ \), which is a type-preserving, stable (i.e., \( t\succ t^\prime \) implies \( t\sigma \succ t^\prime \sigma \)), monotonic (i.e., \( t\succ t^\prime \) implies \( {C}[{t}] \succ {C}[{t^\prime }] \)) and well-founded relation. Note that despite its name, HORPO is not necessarily transitive. If such a relation orients all the rewrite rules in \( \mathcal {R}\) (i.e., \( \ell \succ r\) for all \( \ell \rightarrow r\in \mathcal {R}\)), we can conclude that the rewrite relation \( \rightarrow _\mathcal {R}\) is well-founded.

A similar strategy for LCSTRSs requires a few tweaks. First, stability should be tightly coupled with rule orientation because every rewrite rule now is equipped with a logical constraint, which decides what substitutions are expected when the rewrite rule is applied. Second, the monotonicity requirement can be weakened because \( \ell \) is never a theory term in a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \). We define as follows:

Definition 5

A type-preserving relation \( {\Rightarrow } \subseteq T({\mathcal {F}}, {\mathcal {V}}) \times T({\mathcal {F}}, {\mathcal {V}}) \) is said

  1. 1.

    to stably orient a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) if \( \ell \sigma \Rightarrow r\sigma \) for each substitution \( \sigma \) which respects the rewrite rule, and

  2. 2.

    to be rule-monotonic if \( t\Rightarrow t^\prime \) implies \( {C}[{t}] \Rightarrow {C}[{t^\prime }] \) when \( t\notin T({{\mathcal {F}}_\vartheta }, {\mathcal {V}}) \).

Besides having rewrite rules stably oriented, we need to deal with calculation. It turns out to be unnecessary to search for a well-founded relation which includes \( \rightarrow _\kappa \), given the following observation:

Lemma 1

\( \rightarrow _\kappa \) is well-founded.

Proof

The term size strictly decreases through every step of calculation.    \(\square \)

We rather look for a type-preserving and well-founded relation \( \succ \) which stably orients every rewrite rule, is rule-monotonic, and is compatible with \( \rightarrow _\kappa \), i.e., \( {\rightarrow _\kappa }\mathrel {;}{\succ } \subseteq {\succ ^+} \) or \( {\succ }\mathrel {;}{\rightarrow _\kappa } \subseteq {\succ ^+} \). This strategy is an instance of rule removal:

Theorem 1

Given an LCSTRS \( \mathcal {R}\), the rewrite relation \( \rightarrow _\mathcal {R}\) is well-founded if and only if there exist sets \( \mathcal {R}_1 \) and \( \mathcal {R}_2 \) such that \( \rightarrow _{\mathcal {R}_1} \) is well-founded and \( \mathcal {R}_1 \cup \mathcal {R}_2 = \mathcal {R}\), and type-preserving, rule-monotonic relations \( \Rightarrow \) and \( \succ \) such that

  1. 1.

    \( \Rightarrow \) includes \( \rightarrow _\kappa \) and stably orients every rewrite rule in \( \mathcal {R}_1 \),

  2. 2.

    \( \succ \) is well-founded and stably orients every rewrite rule in \( \mathcal {R}_2 \), and

  3. 3.

    \( {\Rightarrow }\mathrel {;}{\succ } \subseteq {\succ ^+} \) or \( {\succ }\mathrel {;}{\Rightarrow } \subseteq {\succ ^+} \).

Here \( \rightarrow _{\mathcal {R}_1} \) assumes the same term formation and interpretation as \( \rightarrow _\mathcal {R}\) does.

Proof

If \( \rightarrow _\mathcal {R}\) is well-founded, take \( \mathcal {R}_1 = \emptyset \), \( \mathcal {R}_2 = \mathcal {R}\), \( {\Rightarrow } = {\rightarrow _\kappa } \) and \( {\succ } = {\rightarrow _\mathcal {R}} \). Note that \( {\rightarrow _\emptyset } = {\rightarrow _\kappa } \) by definition.

Now assume given \( \mathcal {R}_1 \), \( \mathcal {R}_2 \), \( \Rightarrow \) and \( \succ \). Since \( \Rightarrow \) is rule-monotonic, includes \( \rightarrow _\kappa \) and stably orients every rewrite rule in \( \mathcal {R}_1 \), \( {\rightarrow _{\mathcal {R}_1}} \subseteq {\Rightarrow } \). So the compatibility of \( \succ \) with \( \Rightarrow \) implies its compatibility with \( \rightarrow _{\mathcal {R}_1} \), which in turn implies the well-foundedness of \( {\rightarrow _{\mathcal {R}_1}} \cup {\succ } \), given that both \( \rightarrow _{\mathcal {R}_1} \) and \( \succ \) are well-founded. Since \( \mathcal {R}_1 \cup \mathcal {R}_2 = \mathcal {R}\) and \( \succ \) is a rule-monotonic relation which stably orients every rewrite rule in \( \mathcal {R}_2 \), \( {\rightarrow _\mathcal {R}} \subseteq {\rightarrow _{\mathcal {R}_1}} \cup {\succ } \). Hence, \( \rightarrow _\mathcal {R}\) is well-founded.    \(\square \)

In a termination proof of \( \mathcal {R}\), Theorem 1 allows us to remove rewrite rules that are in \( \mathcal {R}_2 \) from \( \mathcal {R}\). If none of the rewrite rules are left after iterations of rule removal, the termination of the original system can be concluded with Lemma 1.

4.3 Constrained HORPO for LCSTRSs

Before adapting HORPO for LCSTRSs, we discuss how the theories may be handled. Let us consider the following system:

$$\begin{aligned} {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \rightarrow x \quad [n \le 0] \qquad {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \rightarrow {{f}\ {(n - 1)}}\ {({{{\textsf{rec}}\ {(n - 1)}}\ {x}}\ {f})} \quad [n > 0] \end{aligned}$$

where \( \textsf{rec}:\textsf{int}\rightarrow \textsf{int}\rightarrow (\textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}) \rightarrow \textsf{int}\). In the second rewrite rule, the left-hand side of \( \rightarrow \) is \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \) while the right-hand side has a subterm \( {{{\textsf{rec}}\ {(n - 1)}}\ {x}}\ {f} \). It is natural to expect \( n \succ n - 1 \) in the construction of HORPO. Note that this is impossible with respect to any recursive path ordering for unconstrained rewriting because \( n \) is a variable occurring in \( n - 1 \); in an unconstrained setting, we actually have \( n - 1 \succ n \). Hence, we must somehow take the logical constraint \( n > 0 \) into account. To this end, we largely follow the ideas of constrained RPO for first-order LCTRSs [27].

The occurrence of \( n \) in the logical constraint ensures that \( n \) is instantiated to a value, say \( 42 \), when the rewrite rule is applied, and it is sensible to have \( 42 \succ 42 - 1 \). Also, \( n > 0 \) guarantees that all the sequences of such descents are finite, i.e., the ordering \( \lambda {m}.\, \lambda {n}.\, m > 0 \wedge m > n \), denoted by \( \sqsupset \), is well-founded. Let \( \varphi \models \varphi ^\prime \) denote, on the assumption that \( \varphi \) and \( \varphi ^\prime \) are logical constraints such that \( {\text {Var}}({\varphi }) \supseteq {\text {Var}}({\varphi ^\prime }) \), that \( [\![\varphi \sigma ]\!] = 1\) implies \( [\![\varphi ^\prime \sigma ]\!] = 1\) for each substitution \( \sigma \) which maps variables in \( {\text {Var}}({\varphi }) \) to values. Then we have \( n > 0 \models n \sqsupset n - 1 \). We thus would like to have \( s\succ t\) if \( \varphi \models s\sqsupset t\).

However, with the same ordering \( \sqsupset \), we have both \( m > 0 \wedge m > n \models m \sqsupset n \) and \( n > 0 \wedge n > m \models n \sqsupset m \), whereas we cannot have both \( m \succ n \) and \( n \succ m \) without breaking the well-foundedness of \( \succ \). To resolve this issue, we split \( \succ \) into a family of relations \( (\succ _\varphi ) \) indexed by logical constraints, and let \( s\succ _\varphi t\) be true if \( \varphi \models s\sqsupset t\). We also introduce a separate family of relations \( (\succsim _\varphi ) \) such that \( s\succsim _\varphi t\) if \( \varphi \models s\sqsupseteq t\) where \( \sqsupseteq \) is the reflexive closure of \( \sqsupset \). Hence, \( \succsim _\varphi \) is not necessarily the reflexive closure of \( \succ _\varphi \); if it was, even \( n \succsim _{n \ge 1} 1 \) would not be obtainable.

Now we have a family of pairs \( (\succsim _\varphi , \succ _\varphi ) \), which does not seem to suit rule removal; after all, the essential requirement is a fixed relation which is type-preserving, rule-monotonic, well-founded and at least compatible with \( \rightarrow _\kappa \). When the definition of constrained HORPO is fully presented, we will show that \( \succ _\mathfrak {t}\)—the irreflexive relation indexed by the boolean \( \mathfrak {t}\)—is such a relation and stably orients a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) if \( \ell \succ _\varphi r\).

The annotation \( \varphi \) of HORPO does not capture variables in \( {\text {Var}}({r}) \setminus {\text {Var}}({\ell }) \), which also have a part to play in the decision of what substitutions are expected when \( {\ell }\rightarrow {r}\ [{\varphi }] \) is applied. We may use a new annotation to accommodate these variables but there is a hack (also present in [38]): given a variable in \( {\text {Var}}({r}) \setminus {\text {Var}}({\ell }) \), it can be harmlessly appended to \( \varphi \), syntactically and without tampering with any interpretation. We henceforth assume that \( {\text {Var}}({r}) \setminus {\text {Var}}({\ell }) \subseteq {\text {Var}}({\varphi }) \) for each rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \). We also say that a substitution \( \sigma \) respects a logical constraint \( \varphi \) if \( \sigma (x) \) is a value for all \( x\in {\text {Var}}({\varphi }) \) and \( [\![\varphi \sigma ]\!] = 1\).

Before presenting constrained HORPO, we recall that in [21] all sorts collapse into one, and for example, \( \textsf{int}\rightarrow \textsf{int}\rightarrow \textsf{int}\) and \( \textsf{int}\rightarrow \textsf{intlist}\rightarrow \textsf{intlist}\) are considered equal. The idea is that the original rewrite relation can be embedded in the single-sorted one, and if the latter is well-founded, so is the former. We follow this convention and henceforth compare types by their \( \rightarrow \)-structure only.

Below \( \succ _\varphi ^\mathfrak {l}\) and \( \succ _\varphi ^\mathfrak {m}\) are induced by \( \succsim _\varphi \) and \( \succ _\varphi \):

Definition 6

Constrained HORPO depends on the following parameters:

  1. 1.

    The interpretation of theory symbols \( \sqsupset _A:A\rightarrow A\rightarrow \textsf{bool}\) for all \( A\in {\mathcal {S}}_\vartheta \) such that \( [\![\sqsupset _A]\!] \) is a well-founded ordering over \( \mathfrak {X}_A\). The interpretation \( [\![\sqsupseteq _A]\!] \) is assumed to be the reflexive closure of \( [\![\sqsupset _A]\!] \). We usually write just \( \sqsupset \) and \( \sqsupseteq \) because sorts collapse. Consider \( [\![\sqsupset ]\!] \) the union \( \bigcup _{A\in {\mathcal {S}}_\vartheta } [\![\sqsupset _A]\!] \), and \( [\![\sqsupseteq ]\!] \) likewise.

  2. 2.

    The precedence \( \blacktriangleright \), a well-founded ordering over \( \mathcal {F}\) such that \( f\blacktriangleright g\) for all \( f\in \mathcal {F}\setminus {\mathcal {F}}_\vartheta \) and \( g\in {\mathcal {F}}_\vartheta \).

  3. 3.

    The status \( {\mathfrak {s}}\), a mapping from \( \mathcal {F}\) to \( \left\{ \, \mathfrak {l}, \mathfrak {m}_2, \mathfrak {m}_3, \ldots \,\right\} \).

The higher-order recursive path ordering (HORPO) is a family of pairs of type-preserving relations \( (\succsim _\varphi , \succ _\varphi ) \) indexed by logical constraints and defined by the following conditions:

  1. 1.

    \( s\succsim _\varphi t\) if and only if one of the following conditions is true:

    1. (a)

      \( s\) and \( t\) are theory terms whose type is a sort, \( {\text {Var}}({s}) \cup {\text {Var}}({t}) \subseteq {\text {Var}}({\varphi }) \) and \( \varphi \models s\sqsupseteq t\).

    2. (b)

      \( s\succ _\varphi t\).

    3. (c)

      \( s\downarrow _\kappa t\).

    4. (d)

      \( s\) is not a theory term, \( s= {s_0}\ {s_1} \), \( t= {t_0}\ {t_1} \), \( s_0 \succsim _\varphi t_0 \) and \( s_1 \succsim _\varphi t_1 \).

  2. 2.

    \( s\succ _\varphi t\) if and only if one of the following conditions is true:

    1. (a)

      \( s\) and \( t\) are theory terms whose type is a sort, \( {\text {Var}}({s}) \cup {\text {Var}}({t}) \subseteq {\text {Var}}({\varphi }) \) and \( \varphi \models s\sqsupset t\).

    2. (b)

      \( s\) and \( t\) have equal types and \( s\mathrel {\triangleright }_\varphi t\).

    3. (c)

      \( s\) is not a theory term, \( s= {f}\ {{s}_{1} \cdots {s}_{n}} \) for some \( f\in \mathcal {F}\), \( t= {f}\ {{t}_{1} \cdots {t}_{n}} \), \( \forall {i}.\, s_i \succsim _\varphi t_i \) and \( \exists {k}.\, s_k \succ _\varphi t_k \).

    4. (d)

      \( s\) is not a theory term, \( s= {x}\ {{s}_{1} \cdots {s}_{n}} \) for some \( x\in \mathcal {V}\), \( t= {x}\ {{t}_{1} \cdots {t}_{n}} \), \( \forall {i}.\, s_i \succsim _\varphi t_i \) and \( \exists {k}.\, s_k \succ _\varphi t_k \).

  3. 3.

    \( s\mathrel {\triangleright }_\varphi t\) if and only if \( s\) is not a theory term, \( s= {f}\ {{s}_{1} \cdots {s}_{m}} \) for some \( f\in \mathcal {F}\) and one of the following conditions is true:

    1. (a)

      \( \exists {k}.\, s_k \succsim _\varphi t \).

    2. (b)

      \( t= {t_0}\ {{t}_{1} \cdots {t}_{n}} \), \( \forall {i}.\, s\mathrel {\triangleright }_\varphi t_i \).

    3. (c)

      \( t= {g}\ {{t}_{1} \cdots {t}_{n}} \), \( f\blacktriangleright g\), \( \forall {i}.\, s\mathrel {\triangleright }_\varphi t_i \).

    4. (d)

      \( t= {f}\ {{t}_{1} \cdots {t}_{n}} \), \( {\mathfrak {s}}(f) = \mathfrak {l}\), \( {s}_{1} \ldots {s}_{m} \succ _\varphi ^\mathfrak {l}{t}_{1} \ldots {t}_{n} \), \( \forall {i}.\, s\mathrel {\triangleright }_\varphi t_i \).

    5. (e)

      \( t= {f}\ {{t}_{1} \cdots {t}_{n}} \), \( {\mathfrak {s}}(f) = \mathfrak {m}_k \), \( k \le n \), \( {s}_{1} \ldots {s}_{\min (m, k)} \succ _\varphi ^\mathfrak {m}{t}_{1} \ldots {t}_{k} \), \( \forall {i}.\, s\mathrel {\triangleright }_\varphi t_i \).

    6. (f)

      \( t\) is a value or a variable in \( {\text {Var}}({\varphi }) \).

Here \( s\downarrow _\kappa t\) if and only if there exists a term \( r\) such that \( s\rightarrow _\kappa ^* r\) and \( t\rightarrow _\kappa ^* r\).

Comparison to the Original HORPO. Conditions 1d, 2c and 2d are included in the definition so that \( \succsim _\varphi \) and \( \succ _\varphi \) are rule-monotonic. We stress that it is mandatory to use the weakened, rule-monotonicity requirement instead of the traditional monotonicity requirement: if \( \succ _\mathfrak {t}\) is monotonic, \( 1 \succ _\mathfrak {t}0 \) implies \( 1 - 1 \succ _\mathfrak {t}1 - 0 \), but \( \mathfrak {t}\models (1 - 0) \sqsupset (1 - 1) \), i.e., \( \succ _\mathfrak {t}\) cannot possibly be well-founded.

From curried notation, another issue related to rule-monotonicity arises, which leads to the above definition of \( \mathrel {\triangleright }_\varphi \). If we had the original HORPO naively mirrored, the definition of \( \succ _\varphi \) would include a condition which corresponds to condition 3b and reads: “\( s\succ _\varphi t\) if \( s\) is not a theory term, \( s= {f}\ {{s}_{1} \cdots {s}_{m}} \) for some \( f\in \mathcal {F}\), \( t= {t_0}\ {{t}_{1} \cdots {t}_{n}} \) and \( \forall {i}.\, s\succ _\varphi t_i \vee \exists {k}.\, s_k \succsim _\varphi t_i \)”. Assume given such terms \( s\) and \( t\), and that, say, \( s\succ _\varphi t_1 \). Now if there is a term \( r\) to which \( s\) can be applied, we have a problem with proving \( {s}\ {r} \succ _\varphi {t}\ {r} = {{t_0}\ {{t}_{1} \cdots {t}_{n}}}\ {r} \) because \( {s}\ {r} \succ _\varphi t_1 \) is not obtainable due to the type restriction. Note that \( \succsim _\varphi \) and \( \succ _\varphi \) are by definition type-preserving, whereas \( \mathrel {\triangleright }_\varphi \) is not.

This limitation is overcome by means of \( \mathrel {\triangleright }_\varphi \), which actually makes the overall definition more powerful, and is reminiscent of the distinction between \( \succ \) and \( \succ _{\mathcal {T}_S} \) in later versions of HORPO (e.g., [5]). Other extensions from these works, however, are not yet included in the above definition, and except for the type restriction and uncurried notation, the conditions of \( \mathrel {\triangleright }_\varphi \) largely match those of the original HORPO.

Another subtle difference is the use of generalized lexicographic and multiset orderings: in the original HORPO, \( \succsim \) is the reflexive closure of \( \succ \), and therefore it suffices to use the more traditional definitions of lexicographic and multiset orderings. Here, as observed above, this would be unnecessarily restrictive.

The split of a single multiset status label in \( \mathfrak {m}_2, \mathfrak {m}_3, \ldots \) is due to curried notation—in particular, the possibility of partial application. If we had only a single multiset status label, which would admit, for example, both \( {{f}\ {2}}\ {2} \mathrel {\triangleright }_\mathfrak {t}{f}\ {1} \) and \( {{f}\ {1}}\ {3} \succ _\mathfrak {t}{{f}\ {2}}\ {2} \), it would be possible that \( \succ _\mathfrak {t}\) is not well-founded: note that \( {g}\ {({f}\ {1})} \succ _\mathfrak {t}{{f}\ {1}}\ {3} \) due to, among others, conditions 2b and 3b, and if \( f\blacktriangleright g\), we would then have \( {{f}\ {2}}\ {2} \succ _\mathfrak {t}{g}\ {({f}\ {1})} \) due to, among others, conditions 2b and 3c. This change adds some power to constrained HORPO: we can prove, for example, the termination of the single-rule system \( {{{\textsf{f}}\ {x}}\ {\textsf{a}}}\ {y} \rightarrow {{{\textsf{f}}\ {\textsf{b}}}\ {x}}\ {({\textsf{g}}\ {y})} \) by choosing \( {\mathfrak {s}}(\textsf{f}) = \mathfrak {m}_2 \), which is not possible if all arguments must be considered, as the original HORPO requires. We do not need \( \mathfrak {m}_1 \) because this case is already covered by choosing \( \mathfrak {l}\).

Given an LCSTRS \( \mathcal {R}\), if we can divide the set of rules into two subsets \( \mathcal {R}_1 \) and \( \mathcal {R}_2 \), and find a combination of \( [\![\sqsupset ]\!] \), \( \blacktriangleright \) and \( {\mathfrak {s}}\) that guarantees \( \ell \succsim _\varphi r\) for all \( {\ell }\rightarrow {r}\ [{\varphi }] \in \mathcal {R}_1 \) and \( \ell \succ _\varphi r\) for all \( {\ell }\rightarrow {r}\ [{\varphi }] \in \mathcal {R}_2 \), the termination of \( \mathcal {R}\) is reduced to that of \( \mathcal {R}_1 \). Before proving the soundness, we check out some examples:

Example 9

We continue the analysis of the motivating example \( \textsf{rec}\). Let \( [\![\sqsupset _\textsf{int}]\!] \) be \( \lambda {m}.\, \lambda {n}.\, m > 0 \wedge m > n \) as above. There is only one function symbol in \( \mathcal {F}\setminus {\mathcal {F}}_\vartheta \), and it turns out that \( \blacktriangleright \) can be any precedence. Let \( {\mathfrak {s}}\) be a mapping such that \( {\mathfrak {s}}(\textsf{rec}) = \mathfrak {l}\). The first rewrite rule can be removed due to conditions 2b and 3a. The second rewrite rule can be removed as follows:

  1. 1.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \succ _{n > 0} {{f}\ {(n - 1)}}\ {({{{\textsf{rec}}\ {(n - 1)}}\ {x}}\ {f})} \) by 2b, 2.

  2. 2.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \mathrel {\triangleright }_{n > 0} {{f}\ {(n - 1)}}\ {({{{\textsf{rec}}\ {(n - 1)}}\ {x}}\ {f})} \) by 3b, 3, 4, 5.

  3. 3.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \mathrel {\triangleright }_{n > 0} f \) by 3a, 6.

  4. 4.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \mathrel {\triangleright }_{n > 0} n - 1 \) by 3a, 7.

  5. 5.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \mathrel {\triangleright }_{n > 0} {{{\textsf{rec}}\ {(n - 1)}}\ {x}}\ {f} \) by 3d, 8, 4, 9, 3.

  6. 6.

    \( f \succsim _{n > 0} f \) by 1c.

  7. 7.

    \( n \succsim _{n > 0} n - 1 \) by 1a.

  8. 8.

    \( n \succ _{n > 0} n - 1 \) by 2a.

  9. 9.

    \( {{{\textsf{rec}}\ {n}}\ {x}}\ {f} \mathrel {\triangleright }_{n > 0} x \) by 3a, 10.

  10. 10.

    \( x \succsim _{n > 0} x \) by 1c.

Example 10

Consider Example 5. Let \( [\![\sqsupset _\textsf{int}]\!] \) be \( \lambda {m}.\, \lambda {n}.\, m > 0 \wedge m > n \). Let \( \blacktriangleright \) be a precedence such that \( \textsf{take}\blacktriangleright \textsf{nil}\) and \( \textsf{take}\blacktriangleright \textsf{cons}\). Let \( {\mathfrak {s}}\) be a mapping such that \( {\mathfrak {s}}(\textsf{take}) = \mathfrak {l}\). Then we can remove all of the rewrite rules. Note that to establish \( {{\textsf{take}}\ {n}}\ {({{\textsf{cons}}\ {x}}\ {l})} \succ _{n > 0} {{\textsf{cons}}\ {x}}\ {({{\textsf{take}}\ {(n - 1)}}\ {l})} \), we need \( {{\textsf{cons}}\ {x}}\ {l} \succsim _{n > 0} x \), which is obtainable because \( \textsf{intlist}\) is not distinguished from \( \textsf{int}\).

4.4 Properties of Constrained HORPO

The soundness of constrained HORPO as a technique for rule removal relies on the following properties, which we now prove.

Rule Orientation. The goal consists of two parts: \( \succsim _\mathfrak {t}\) stably orients a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) if \( \ell \succsim _\varphi r\), and \( \succ _\mathfrak {t}\) stably orients a rewrite rule \( {\ell }\rightarrow {r}\ [{\varphi }] \) if \( \ell \succ _\varphi r\). The core of the argument is to prove the following lemma:

Lemma 2

Given logical constraints \( \varphi \) and \( \varphi ^\prime \) such that \( {\text {Var}}({\varphi }) \supseteq {\text {Var}}({\varphi ^\prime }) \) and \( \varphi \models \varphi ^\prime \), \( \mathfrak {t}\models \varphi ^\prime \sigma \) holds for each substitution \( \sigma \) which respects \( \varphi \).

Proof

It follows from \( \varphi \models \varphi ^\prime \) that \( [\![\varphi ^\prime \sigma ]\!] = 1\). Note that \( {\text {Var}}({\varphi ^\prime \sigma }) = \emptyset \), and therefore \( \varphi ^\prime \sigma \sigma ^\prime = \varphi ^\prime \sigma \) for all \( \sigma ^\prime \). Hence, \( \mathfrak {t}\models \varphi ^\prime \sigma \).    \(\square \)

And the rest is routine:

Theorem 2

Given a logical constraint \( \varphi \), terms \( s\) and \( t\), the following statements are true for each substitution \( \sigma \) which respects \( \varphi \):

  1. 1.

    \( s\succsim _\varphi t\) implies \( s\sigma \succsim _\mathfrak {t}t\sigma \).

  2. 2.

    \( s\succ _\varphi t\) implies \( s\sigma \succ _\mathfrak {t}t\sigma \).

  3. 3.

    \( s\mathrel {\triangleright }_\varphi t\) implies \( s\sigma \mathrel {\triangleright }_\mathfrak {t}t\sigma \).

Proof

By mutual induction on the derivation. Note that \( \rightarrow _\kappa \) is stable.    \(\square \)

Rule-Monotonicity. Both \( \succsim _\varphi \) and \( \succ _\varphi \) are rule-monotonic for all \( \varphi \). The former is trivial to prove, and the key to proving the latter is the following lemma:

Lemma 3

\( {{f}\ {{s}_{1} \cdots {s}_{m}}}\ {r} \mathrel {\triangleright }_\varphi t\) if \( {f}\ {{s}_{1} \cdots {s}_{m}} \mathrel {\triangleright }_\varphi t\).

Proof

By induction on the derivation.    \(\square \)

Now we can prove the rule-monotonicity:

Theorem 3

\( \succ _\varphi \) is rule-monotonic.

Proof

By induction on the context \( {C}[{}] \). Essentially, we ought to prove that given terms \( s\) and \( t\) which have equal types, if \( s\) is not a theory term and \( s\succ _\varphi t\), \( {s}\ {r} \succ _\varphi {t}\ {r} \) for all \( r\), and \( {r}\ {s} \succ _\varphi {r}\ {t} \) for all \( r\). We prove the former by case analysis on the derivation of \( s\succ _\varphi t\), and prove the latter by case analysis on \( r\): \( r= {f}\ {{r}_{1} \cdots {r}_{n}} \) for some \( f\in \mathcal {F}\) or \( r= {x}\ {{r}_{1} \cdots {r}_{n}} \) for some \( x\in \mathcal {V}\).    \(\square \)

Compatibility. The strict relation \( \succ _\mathfrak {t}\) is compatible with its non-strict counterpart \( \succsim _\mathfrak {t}\); we prove that \( {\succsim _\mathfrak {t}}\mathrel {;}{\succ _\mathfrak {t}} \subseteq {\succ _\mathfrak {t}} \cup ({\succ _\mathfrak {t}}\mathrel {;}{\succ _\mathfrak {t}}) \), given the following observation:

Theorem 4

\( {\succsim _\mathfrak {t}} = {\succ _\mathfrak {t}} \cup {\downarrow _\kappa } \).

Proof

By definition, \( {\succsim _\mathfrak {t}} \supseteq {\succ _\mathfrak {t}} \cup {\downarrow _\kappa } \). We prove \( {\succsim _\mathfrak {t}} \subseteq {\succ _\mathfrak {t}} \cup {\downarrow _\kappa } \) by induction on the derivation of \( s\succsim _\mathfrak {t}t\). Only two cases are non-trivial. If \( s\) and \( t\) are ground theory terms whose type is a sort and \( [\![s\sqsupseteq t]\!] = 1\), we have either \( [\![s\sqsupset t]\!] = 1\) or \( [\![s]\!] = [\![t]\!] \), and the former implies \( s\succ _\mathfrak {t}t\) while the latter implies \( s\downarrow _\kappa t\). On the other hand, if \( s\) is not a theory term, \( s= {s_0}\ {s_1} \), \( t= {t_0}\ {t_1} \), \( s_0 \succsim _\mathfrak {t}t_0 \) and \( s_1 \succsim _\mathfrak {t}t_1 \), by induction, if \( s_0 \succ _\mathfrak {t}t_0 \) or \( s_1 \succ _\mathfrak {t}t_1 \), we can prove \( s\succ _\mathfrak {t}t\) in the same manner as we prove the rule-monotonicity of \( \succ _\mathfrak {t}\), or \( s_0 \downarrow _\kappa t_0 \) and \( s_1 \downarrow _\kappa t_1 \), then \( s\downarrow _\kappa t\).    \(\square \)

Theorem 4 plays an important role in the well-foundedness proof of \( \succ _\mathfrak {t}\) as well.

For the compatibility of \( \succ _\mathfrak {t}\) with \( \succsim _\mathfrak {t}\), it remains to prove that \( {\downarrow _\kappa }\mathrel {;}{\succ _\mathfrak {t}} \subseteq {\succ _\mathfrak {t}} \), which is implied by the following lemma:

Lemma 4

Given terms \( s\) and \( s^\prime \) such that \( s\rightarrow _\kappa s^\prime \), the following statements are true for all \( t\):

  1. 1.

    \( s\succsim _\mathfrak {t}t\) if and only if \( s^\prime \succsim _\mathfrak {t}t\).

  2. 2.

    \( s\succ _\mathfrak {t}t\) if and only if \( s^\prime \succ _\mathfrak {t}t\).

  3. 3.

    \( s\mathrel {\triangleright }_\mathfrak {t}t\) if and only if \( s^\prime \mathrel {\triangleright }_\mathfrak {t}t\).

Proof

By mutual induction on the derivation for “if” and “only if” separately. Note that \( \rightarrow _\kappa \) is confluent.    \(\square \)

The compatibility follows as a corollary:

Corollary 1

\( {\succsim _\mathfrak {t}}\mathrel {;}{\succ _\mathfrak {t}} \subseteq {\succ _\mathfrak {t}} \cup ({\succ _\mathfrak {t}}\mathrel {;}{\succ _\mathfrak {t}}) \).

Well-Foundedness. Following [21], we base the well-foundedness proof of \( \succ _\mathfrak {t}\) on the predicate of computability [17, 40]. There are, however, two major differences, which pose new technical challenges: \( \succsim _\mathfrak {t}\) is no more the reflexive closure of \( \succ _\mathfrak {t}\) and curried notation instead of uncurried notation is in use.

In Definition 6, \( \succ _\varphi ^\mathfrak {l}\) and \( \succ _\varphi ^\mathfrak {m}\) are induced by \( \succsim _\varphi \) and \( \succ _\varphi \). We need certain properties of \( \succ _\mathfrak {t}^\mathfrak {l}\) and \( \succ _\mathfrak {t}^\mathfrak {m}\) to prove that \( \succ _\mathfrak {t}\) is well-founded. Because \( \succsim _\mathfrak {t}\) is neither the equality over terms nor the reflexive closure of \( \succ _\mathfrak {t}\), those properties are less standard and deserve inspection. The property of \( \succ _\mathfrak {t}^\mathfrak {l}\) is relatively easy to prove:

Theorem 5

Given relations \( \succsim \) and \( \succ \) over \( X\) such that \( \succ \) is well-founded and \( {\succsim }\mathrel {;}{\succ } \subseteq {\succ ^+} \), \( \succ ^\mathfrak {l}\) is well-founded over \( X^n \) for all \( n \).

Proof

The standard method used when \( \succsim \) is the equality still applies.    \(\square \)

We refer to [41] for the proof of the following property of \( \succ _\mathfrak {t}^\mathfrak {m}\):

Theorem 6

Given relations \( \succsim \) and \( \succ \) over \( X\) such that \( \succsim \) is a quasi-ordering, \( \succ \) is well-founded and \( {\succsim }\mathrel {;}{\succ } \subseteq {\succ } \), \( \succ ^\mathfrak {m}\) is well-founded over \( X^* \).

Proof

See Theorem 3.7 in [41].    \(\square \)

In comparison to [41], we waive the transitivity requirement for \( \succ \) above, but we cannot get around the requirement that \( \succsim \) is a quasi-ordering without significantly changing the proof. This seems problematic because \( \succsim _\mathfrak {t}\) is not necessarily transitive due to its inclusion of \( \succ _\mathfrak {t}\). Fortunately, one observation resolves this issue: \( \succ _\mathfrak {t}^\mathfrak {m}\) can equivalently be seen as induced by \( \downarrow _\kappa \) and \( \succ _\mathfrak {t}\) due to Theorem 4. In the same spirit, we can prove the following property:

Theorem 7

\( {\downarrow _\kappa ^\mathfrak {m}}\mathrel {;}{\succ _\mathfrak {t}^\mathfrak {m}} \subseteq {\succ _\mathfrak {t}^\mathfrak {m}} \) where \( {s}_{1} \ldots {s}_{n} \downarrow _\kappa ^\mathfrak {m}{t}_{1} \ldots {t}_{n} \) if and only if there exists a permutation \( \pi \) over \( \left\{ \, 1, \ldots , n \,\right\} \) such that \( s_{\pi (i)} \downarrow _\kappa t_i \) for all \( i \).

Proof

See Lemma 3.2 in [41].    \(\square \)

Our definition of computability (or reducibility [17]) is standard:

Definition 7

A term \( t_0 \) is called computable if either

  1. 1.

    the type of \( t_0 \) is a sort and \( t_0 \) is terminating with respect to \( \succ _\mathfrak {t}\), or

  2. 2.

    the type of \( t_0 \) is \( A\rightarrow B\) and \( {t_0}\ {t_1} \) is computable for all computable \( t_1 :A\).

In [21], a term is called neutral if it is not a \( \lambda \)-abstraction. Due to the exclusion of \( \lambda \)-abstractions, one might consider all LCSTRS terms neutral. This naive definition, however, does not capture the essence of neutrality: if a term \( t_0 \) is neutral, a one-step reduct (with respect to \( \succ _\mathfrak {t}\)) of \( {t_0}\ {t_1} \) can only be \( {t_0^\prime }\ {t_1^\prime } \) where \( t_0^\prime \) and \( t_1^\prime \) are reducts of \( t_0 \) and \( t_1 \), respectively. Because of curried notation, neutral LCSTRS terms should be defined as follows:

Definition 8

A term is called neutral if it assumes the form \( {x}\ {{t}_{1} \cdots {t}_{n}} \) for some variable \( x\).

And we recall the following results:

Theorem 8

Computable terms have the following properties:

  1. 1.

    Given terms \( s\) and \( t\) such that \( s\succ _\mathfrak {t}t\), if \( s\) is computable, so is \( t\).

  2. 2.

    All computable terms are terminating with respect to \( \succ _\mathfrak {t}\).

  3. 3.

    Given a neutral term \( s\), if \( t\) is computable for all \( t\) such that \( s\succ _\mathfrak {t}t\), so is \( s\).

Proof

The standard proof still works despite the seemingly different definition of neutrality.    \(\square \)

In addition, we prove the following lemma:

Lemma 5

Given terms \( s\) and \( t\) such that \( s\downarrow _\kappa t\), if \( s\) is computable, so is \( t\).

Proof

By induction on the type of \( s\) and \( t\).    \(\square \)

And we have the following corollary due to Theorem 4:

Corollary 2

Given terms \( s\) and \( t\) such that \( s\succsim _\mathfrak {t}t\), if \( s\) is computable, so is \( t\).

The goal is to prove that all terms are computable. To do so, the key is to prove that \( {f}\ {{s}_{1} \cdots {s}_{m}} \) is computable where \( f\) is a function symbol if \( s_i \) is computable for all \( i \). In [21], this is done on the basis that \( {f}\ {{s}_{1} \cdots {s}_{m}} \) is neutral, which is not true in our case. We do it differently and start with a definition:

Definition 9

Given \( f:{A}_{1} \rightarrow \cdots \rightarrow {A}_{n} \rightarrow B\) where \( f\in \mathcal {F}\) and \( B\in \mathcal {S}\), let \( {\text {ar}}({f}) \) be \( n \). We introduce a special symbol \( \top \) and extend our previous definitions so that \( \top \succ _\mathfrak {t}t\) for all \( t\in T({\mathcal {F}}, {\mathcal {V}}) \) and \( \top \downarrow _\kappa \top \). This way \( \top \succsim _\mathfrak {t}t\) if \( t\in T({\mathcal {F}}, {\mathcal {V}}) \) or \( t= \top \). Given terms \( \bar{t} = {t}_{1} \ldots {t}_{n} \), let \( ({\bar{t}})_{k} \) be \( t_k \) if \( k \le n \), and \( \top \) if \( k > n \). Given terms \( s= {f}\ {{s}_{1} \cdots {s}_{m}} \) and \( t= {g}\ {{t}_{1} \cdots {t}_{n}} \) where \( f\in \mathcal {F}\), \( g\in \mathcal {F}\), all \( s_i \) and \( t_i \) are computable, we define \( \succ _c\) such that \( s\succ _ct\) if and only if \( f\blacktriangleright g\), or \( f= g\) and

  • \( {\mathfrak {s}}(f) = \mathfrak {l}\) and \( {(\bar{s})}_{1} \ldots {(\bar{s})}_{{\text {ar}}({f})} \succ _\mathfrak {t}^\mathfrak {l}{(\bar{t})}_{1} \ldots {(\bar{t})}_{{\text {ar}}({f})} \), or

  • \( {\mathfrak {s}}(f) = \mathfrak {m}_k \) and

    • \( {(\bar{s})}_{1} \ldots {(\bar{s})}_{k} \succ _\mathfrak {t}^\mathfrak {m}{(\bar{t})}_{1} \ldots {(\bar{t})}_{k} \), or

    • \( {(\bar{s})}_{1} \ldots {(\bar{s})}_{k} \downarrow _\kappa ^\mathfrak {m}{(\bar{t})}_{1} \ldots {(\bar{t})}_{k} \), \( \forall {i > k}.\, ({\bar{s}})_{i} \succsim _\mathfrak {t}({\bar{t}})_{i} \) and \( \exists {i > k}.\, ({\bar{s}})_{i} \succ _\mathfrak {t}({\bar{t}})_{i} \).

This gives us a well-founded relation:

Lemma 6

\( \succ _c\) is well-founded.

Proof

Since all computable terms are terminating with respect to \( \succ _\mathfrak {t}\), \( \succ _\mathfrak {t}\) is well-founded over computable terms. The introduction of \( \top \) clearly does not break this well-foundedness. The outermost layer of \( \succ _c\) regards \( \blacktriangleright \), which is well-founded by definition. We need only to fix the function symbol \( f\) and to go deeper. If \( {\mathfrak {s}}(f) = \mathfrak {l}\), we know that \( \succ _\mathfrak {t}^\mathfrak {l}\) is well-founded over lists of length \( {\text {ar}}({f}) \) because of Theorem 5. If \( {\mathfrak {s}}(f) = \mathfrak {m}_k \), \( \succ _c\) splits each list of arguments in two and performs a lexicographic comparison. We can go past the first component because of Theorems 6 and 7. And the rest, a pointwise comparison, is also well-founded. So we can conclude that \( \succ _c\) is well-founded.    \(\square \)

Now we prove the aforementioned statement:

Lemma 7

Given a term \( s= {f}\ {{s}_{1} \cdots {s}_{m}} \) where \( f\) is a function symbol, if \( s_i \) is computable for all \( i \), so is \( s\).

Proof

By well-founded induction on \( \succ _c\). We consider the type of \( s\):

  • If the type is a sort, we ought to prove that \( s\) is terminating with respect to \( \succ _\mathfrak {t}\). We need only to consider the cases in which \( s\) is not a theory term because all theory terms are terminating with respect to \( \succ _\mathfrak {t}\) due to the well-foundedness of \( [\![\sqsupset ]\!] \). Take an arbitrary term \( t\) such that \( s\succ _\mathfrak {t}t\). We prove that \( t\) is terminating with respect to \( \succ _\mathfrak {t}\) by case analysis on the derivation of \( s\succ _\mathfrak {t}t\). If \( t= {f}\ {{t}_{1} \cdots {t}_{m}} \), \( \forall {i}.\, s_i \succsim _\mathfrak {t}t_i \) and \( \exists {k}.\, s_k \succ _\mathfrak {t}t_k \), we can prove that \( s\succ _ct\). By induction, \( t\) is computable and therefore terminating with respect to \( \succ _\mathfrak {t}\). If \( s\mathrel {\triangleright }_\mathfrak {t}t\), we prove that \( t\) is computable for all \( t\) such that \( s\mathrel {\triangleright }_\mathfrak {t}t\) (\( t\) is generalized) by inner induction on the derivation of \( s\mathrel {\triangleright }_\mathfrak {t}t\):

    1. 1.

      If \( \exists {k}.\, s_k \succsim _\mathfrak {t}t \), \( t\) is computable due to Corollary 2.

    2. 2.

      If \( t= {t_0}\ {{t}_{1} \cdots {t}_{n}} \) and \( \forall {i}.\, s\mathrel {\triangleright }_\mathfrak {t}t_i \), \( t_i \) is computable for all \( i \) by inner induction. By definition, \( t\) is computable.

    3. 3.

      If \( t= {g}\ {{t}_{1} \cdots {t}_{n}} \), \( f\blacktriangleright g\) and \( \forall {i}.\, s\mathrel {\triangleright }_\mathfrak {t}t_i \), \( t_i \) is computable for all \( i \) by inner induction. It follows from \( f\blacktriangleright g\) that \( s\succ _ct\), and \( t\) is computable by outer induction.

    4. 4.

      If \( t= {f}\ {{t}_{1} \cdots {t}_{n}} \), \( {\mathfrak {s}}(f) = \mathfrak {l}\), \( {s}_{1} \ldots {s}_{m} \succ _\mathfrak {t}^\mathfrak {l}{t}_{1} \ldots {t}_{n} \) and \( \forall {i}.\, s\mathrel {\triangleright }_\mathfrak {t}t_i \), \( t_i \) is computable for all \( i \) by inner induction. Likewise, \( s\succ _ct\).

    5. 5.

      If \( t= {f}\ {{t}_{1} \cdots {t}_{n}} \), \( {\mathfrak {s}}(f) = \mathfrak {m}_k \), \( k \le n \), \( {s}_{1} \ldots {s}_{\min (m, k)} \succ _\mathfrak {t}^\mathfrak {m}{t}_{1} \ldots {t}_{k} \) and \( \forall {i}.\, s\mathrel {\triangleright }_\mathfrak {t}t_i \), \( t_i \) is computable for all \( i \) by inner induction. Likewise, \( s\succ _ct\).

    6. 6.

      If \( t\) is a value, \( t\) is terminating with respect to \( \succ _\mathfrak {t}\) and its type is a sort.

  • If the type is \( A\rightarrow B\), take an arbitrary computable \( s_{m + 1} :A\). We prove that \( s\succ _c{s}\ {s_{m + 1}} = {f}\ {{s}_{1} \cdots {s}_{m + 1}} \). Note that \( ({{s}_{1} \ldots {s}_{m}})_{i} = ({{s}_{1} \ldots {s}_{m + 1}})_{i} \) for all \( i \le m \) and \( ({{s}_{1} \ldots {s}_{m}})_{m + 1} = \top \succ _\mathfrak {t}({{s}_{1} \ldots {s}_{m + 1}})_{m + 1} \). Consider \( {\mathfrak {s}}(f) = \mathfrak {l}\), \( {\mathfrak {s}}(f) = \mathfrak {m}_k \) while \( k > m \), and \( {\mathfrak {s}}(f) = \mathfrak {m}_k \) while \( k \le m \). We have \( s\succ _c{s}\ {s_{m + 1}} \) in each case. By induction, \( {s}\ {s_{m + 1}} \) is computable. Hence, \( s\) is computable.

We conclude that \( s\) is computable.    \(\square \)

Now the well-foundedness of \( \succ _\mathfrak {t}\) follows immediately:

Theorem 9

\( \succ _\mathfrak {t}\) is well-founded.

Proof

We prove that every term \( t\) is computable by induction on \( t\). Given Lemma 7, we need only to prove that variables are computable, which is the case because variables are neutral and in normal form with respect to \( \succ _\mathfrak {t}\).    \(\square \)

5 Discussion: HORPO and Dependency Pairs

In Section 4, we discussed rule removal, and presented a reduction ordering to prove termination. However, in practice it is not so common to directly use reduction orderings as a termination method. Rather, the norm in the literature nowadays is to use dependency pairs.

The dependency pair framework [1, 16] allows a single term rewriting system to be split into multiple “DP problems”, each of which can then be analyzed independently. The framework operates by iteratively simplifying DP problems until none remain, in which case the original system is proved terminating. There are variants for many styles of term rewriting, including first-order LCTRSs [25] and unconstrained higher-order TRSs [11, 25, 39].

Importantly, many existing techniques can be reformulated as “processors” (DP problem simplifiers) in the dependency pair framework. Such techniques include reduction orderings, which are at the heart of the dependency pair framework. This combination is far more powerful than using reduction orderings directly because the monotonicity requirement is replaced by weak monotonicity, and we do not have to orient the entire system in one go.

Consider the following first-order LCTRS:

$$\begin{aligned} {{\textsf{u}}\ {x}}\ {y} &\rightarrow {{\textsf{u}}\ {(x + 1)}}\ {(y * 2)} \quad [x < 100] & {\textsf{v}}\ {y} \rightarrow {\textsf{v}}\ {(y - 1)} \quad [y > 0]\\ {{\textsf{u}}\ {100}}\ {y} &\rightarrow {\textsf{v}}\ {y} \end{aligned}$$

This system cannot be handled by HORPO directly: the ordering \( [\![\sqsupset _\textsf{int}]\!] \) needs to be fixed globally, so we can either orient the rewrite rule at the top-left corner or the one at the top-right corner, but not both at the same time. We could address this dilemma by using a more elaborate definition of HORPO (for example, by giving every function symbol an additional status that indicates the theory ordering to be used for each of its arguments), but this seems redundant: in practice, such a system would be handled by the dependency pair framework. Following the definition in [25], the above system would be split in two separate DP problems corresponding to the two loops:

$$\begin{aligned} \left\{ \, {{\textsf{u}^\sharp }\ {x}}\ {y} \rightarrow {{\textsf{u}^\sharp }\ {(x + 1)}}\ {(y * 2)} \quad [x < 100] \,\right\} \qquad \left\{ \, {\textsf{v}^\sharp }\ {y} \rightarrow {\textsf{v}^\sharp }\ {(y - 1)} \quad [y > 0] \,\right\} \end{aligned}$$

which could then be handled independently.

While dependency pairs for LCSTRSs are not yet defined (and beyond the scope of this paper), we postulate that the definitions for curried higher-order rewriting in [11] and first-order constrained rewriting in [25] can be combined in a natural way. In this setting, HORPO would naturally be combined with argument filterings [1, 11]. That is, since we only require weak monotonicity, some arguments can be removed. For example, the first DP problem above can be handled by showing the following inequalities:

$$\begin{aligned} {\textsf{u}^\sharp }\ {x} \succ _{x < 100} {\textsf{u}^\sharp }\ {(x + 1)} \qquad \textsf{u} \succsim _{x < 100} \textsf{u} \qquad \textsf{v} \succsim _{y > 0} \textsf{v} \qquad \textsf{u} \succsim _\mathfrak {t}\textsf{v} \end{aligned}$$

This is the case with \( \textsf{u} \blacktriangleright \textsf{v} \).

6 Implementation

A preliminary implementation of LCSTRSs is available in Cora through the link:

Cora is an open-source analyzer for constrained rewriting, which can be used both as a stand-alone tool and as a library. Note that Cora is still in active development, and its functionalities, as well as its interface, are subject to change. Nevertheless, Cora is already used in several student projects. Cora supports only the theories of integers and booleans so far, but is intended to eventually support any theory, provided that an SMT solver is able to handle it. Example input files are supplied in the above repository. The version of this paper is available in [28].

Automating Constrained HORPO. Cora includes an implementation of constrained HORPO. Following existing termination tools such as AProVE [14], NaTT [42] and Wanda [26], we use an SMT encoding such that a satisfying assignment to variables in the SMT problem corresponds to a combination of the precedence \( \blacktriangleright \), the status \( {\mathfrak {s}}\) and the ordering \( [\![\sqsupset _\textsf{int}]\!] \) that proves the termination of the encoded system by constrained HORPO. As for booleans, we simply choose the ordering \( [\![\sqsupset _\textsf{bool}]\!] \) such that \( [\![\mathfrak {t}\sqsupset _\textsf{bool}\mathfrak {f}]\!] = 1\).

To encode the precedence and the status, we introduce integer variables \( \texttt{prec}_{f} \) and \( \texttt{stat}_{f} \) for each function symbol \( f\) that is not a value. We require that \( \texttt{prec}_{f} < 0 \) if \( f\) is a theory symbol, and that \( \texttt{prec}_{f} \ge 0 \) otherwise—so that \( \texttt{prec}_{f} > \texttt{prec}_{g} \) corresponds to \( f\blacktriangleright g\). The value \( k \) of \( \texttt{stat}_{f} \) indicates \( {\mathfrak {s}}(f) = \mathfrak {l}\) if \( k = 1 \), and \( {\mathfrak {s}}(f) = \mathfrak {m}_k \) if \( k > 1 \). We let \( \texttt{down}\) be a boolean variable which indicates the choice between two possibilities for \( [\![\sqsupset _\textsf{int}]\!] \): \( \lambda {m}.\, \lambda {n}.\, m > {- M} \wedge m > n \) and \( \lambda {m}.\, \lambda {n}.\, m < M \wedge m < n \) (the choice of \( M \) is discussed below).

In the derivation of \( s\succ _\varphi t\), all assertions assume the form \( s^\prime \mathrel {R}_\varphi t^\prime \) where \( s^\prime \) and \( t^\prime \) are subterms of \( s\) and \( t\), respectively (see Example 9). Hence, given a finite set of rewrite rules, there are only finitely many possible assertions to be analyzed. By inspecting the definition of constrained HORPO, we also note that there are no cyclic dependencies. For all \( {\ell }\rightarrow {r}\ [{\varphi }] \), respective subterms \( s\) and \( t\) of \( \ell \) and \( r\), and \( R \in \left\{ \, {\succsim }, {\succ }, {\mathrel {\triangleright }}, \text {1a}, \text {1b}, \ldots , \text {3f} \,\right\} \), we thus introduce a variable \( \langle s\,\mathrel {R}_\varphi t \rangle \) with its defining constraint. Without going into detail for all the cases, we provide a few key examples:

  • If \( s\) and \( t\) do not have equal types, we add \( \lnot \langle s\,\succsim _\varphi t \rangle \); otherwise, we add \( \langle s\,\succsim _\varphi t \rangle \implies \langle s\,{\text {1a}}_\varphi t \rangle \vee \langle s\,{\text {1b}}_\varphi t \rangle \vee \langle s\,{\text {1c}}_\varphi t \rangle \vee \langle s\,{\text {1d}}_\varphi t \rangle \), which states that if \( s\succsim _\varphi t\) holds, it must hold in one of the defining cases 1a, 1b, 1c and 1d. Each of these cases in turn has its defining constraint.

  • \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3c}}_\varphi {g}\ {{t}_{1} \cdots {t}_{n}} \rangle \implies \texttt{prec}_{f} > \texttt{prec}_{g} \wedge \bigwedge _j \langle {f}\ {{s}_{1} \cdots {s}_{m}} \mathrel {\triangleright }_\varphi t_j \rangle \).

  • We come up with the defining constraint of \( \langle s\,{\text {2a}}_\varphi t \rangle \) by case analysis:

    • If either of \( s\) and \( t\) is not a theory term, or their respective types are not the same theory sort, or \( {\text {Var}}({s}) \cup {\text {Var}}({t}) \nsubseteq {\text {Var}}({\varphi }) \), we add \( \lnot \langle s\,{\text {2a}}_\varphi t \rangle \).

    • Otherwise, we consider the type of \( s\) and \( t\):

      1. *

        The type is \( \textsf{int}\). We respectively check if \( \varphi \implies s> {- M} \wedge s> t\) and \( \varphi \implies s< M \wedge s< t\) are valid. If the former is not valid, we add \( \langle s\,{\text {2a}}_\varphi t \rangle \implies \lnot \texttt{down}\); if the latter is not valid, we add \( \langle s\,{\text {2a}}_\varphi t \rangle \implies \texttt{down}\). That is, if both of the validity checks fail, both of the constraints are added, which is equivalent to adding \( \lnot \langle s\,{\text {2a}}_\varphi t \rangle \).

      2. *

        The type is \( \textsf{bool}\). We add \( \lnot \langle s\,{\text {2a}}_\varphi t \rangle \) if \( \varphi \implies s\wedge \lnot t\) is not valid; if it is valid, nothing is added and the SMT solver is free to set true for the variable \( \langle s\,{\text {2a}}_\varphi t \rangle \).

    Here \( M \) is twice the largest absolute value of integers occurring in the rewrite rules, or just 1000 if that is too large—this value is chosen arbitrarily. Note that the validity checks are not included as part of the SMT problem: if they were included, the satisfiability problem would contain universal quantification, which is typically hard to solve. We rather pose a separate question to the SMT solver every time we encounter theory comparison, and for integers, consider whether the pair can be oriented downward with \( \lambda {m}.\, \lambda {n}.\, m > {- M} \wedge m > n \), upward with \( \lambda {m}.\, \lambda {n}.\, m < M \wedge m < n \), or not at all. Hence, we must fix the bound \( M \) beforehand.

  • The hardest is 3e: we need not only to encode the multiset comparison, but also to make sure that only \( k \) arguments are to be considered on both sides (should there be more). Following Definition 4, we introduce boolean variables \( \texttt{strict}_{1}, \ldots , \texttt{strict}_{m} \) where \( \texttt{strict}_{i} \) indicates \( i \in I\), and integer variables \( \pi (1), \ldots , \pi (n) \). The defining constraint of \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \) is the conjunction of the following components:

    • \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \implies 2 \le \texttt{stat}_{f} \le n \).

    • \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \implies \bigwedge _j \langle {f}\ {{s}_{1} \cdots {s}_{m}} \mathrel {\triangleright }_\varphi t_j \rangle \).

    • \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \implies \bigvee _i \texttt{strict}_{i} \).

    • For all \( i \in \left\{ \, 1, \ldots , m \,\right\} \), \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \wedge \texttt{strict}_{i} \implies i \le \texttt{stat}_{f} \). That is, \( I\subseteq \left\{ \, 1, \ldots , k \,\right\} \) if \( {\mathfrak {s}}(f) = \mathfrak {m}_k \).

    • For all \( j \in \left\{ \, 1, \ldots , n \,\right\} \), \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \wedge j \le \texttt{stat}_{f} \implies 1 \le \pi (j) \wedge \pi (j) \le m \wedge \pi (j) \le \texttt{stat}_{f} \). That is, \( 1 \le \pi (j) \le \min (m, k) \) for all \( j \in \left\{ \, 1, \ldots , k \,\right\} \) if \( {\mathfrak {s}}(f) = \mathfrak {m}_k \).

    • For all \( i \in \left\{ \, 1, \ldots , m \,\right\} \), \( j \in \left\{ \, 1, \ldots , n - 1 \,\right\} \) and \( j^\prime \in \left\{ \, j + 1, \ldots , n \,\right\} \), \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \implies \texttt{strict}_{i} \vee \pi (j) \ne i \vee \pi (j^\prime ) \ne i \). That is, \( \left|\pi ^{-1}(i)\right| \le 1 \) for all \( i \in \left\{ \, 1, \ldots , m \,\right\} \setminus I\)—which suffices because we can add to \( I\) all \( i \in \left\{ \, 1, \ldots , \min (m, k) \,\right\} \setminus I\) such that \( \left|\pi ^{-1}(i)\right| = 0 \) without changing the generalized multiset ordering if \( {\mathfrak {s}}(f) = \mathfrak {m}_k \).

    • For all \( i \in \left\{ \, 1, \ldots , m \,\right\} \) and \( j \in \left\{ \, 1, \ldots , n \,\right\} \), \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \wedge \pi (j) = i \wedge \texttt{strict}_{i} \implies \langle s_i \succ _\varphi t_j \rangle \).

    • For all \( i \in \left\{ \, 1, \ldots , m \,\right\} \) and \( j \in \left\{ \, 1, \ldots , n \,\right\} \), \( \langle {f}\ {{s}_{1} \cdots {s}_{m}} {\text {3e}}_\varphi {f}\ {{t}_{1} \cdots {t}_{n}} \rangle \wedge \pi (j) = i \wedge \lnot \texttt{strict}_{i} \implies \langle s_i \succsim _\varphi t_j \rangle \).

Cora succeeds in proving that all the examples in this paper are terminating, except Example 2, which is non-terminating.

7 Related Work

In this section, we assess the newly proposed formalism and the prospects for its application by comparing and relating it to the literature.

Term Rewriting. The closest related work is LCTRSs [12, 27], the first-order formalism for constrained rewriting upon which the present work is built. Similarly, there are numerous formalisms for higher-order term rewriting, but without built-in logical constraints, e.g., [21, 22, 31]. It seems likely that the methods for analyzing those can be extended with support for SMT, as what is done for HORPO in this paper.

Also worth mentioning is the K Framework [35], which, like our formalism, can be used as an intermediate language for program analysis and is based on a form of first-order rewriting. The K tool includes techniques through reachability logic, rather than methods like HORPO.

There are several works that analyze functional programs using term rewriting, e.g., [2, 15]. However, they typically use translations to first-order systems. Hence, some of the structure of the initial problem is lost, and their power is weakened.

HORPO. Our definition of constrained HORPO is based on the first-order constrained RPO for LCTRSs [27] and the first definition of higher-order RPO [21]. There have been other HORPO extensions since, e.g., [5, 6], and we believe that the ideas for these extensions can also be applied to constrained HORPO. We have not done so because the purpose of this paper is to show that and how techniques for analyzing higher-order systems extend, not to introduce the most powerful (and consequently more elaborate) ones.

Also worth mentioning is [4], a higher-order RPO for \( \lambda \)-free systems. This variant is defined for the purpose of superposition rather than termination analysis, and is ground-total but generally not monotonic.

Functional Programming. There are many works performing direct analyses of functional programs, including termination analysis, although they typically concern specific programming languages such as Haskel (e.g., [19]) and OCaml (e.g., [20]). A variety of techniques have been proposed, such as sized types [33] and decreasing measures on data [18], but as far as we can find, there is no real parallel of many rewriting techniques such as RPO. We hope that, through LCSTRSs, we can help make the techniques of term rewriting available to the functional programming community.

8 Conclusion and Future Work

In summary, we have defined a higher-order extension of logically constrained term rewriting systems, which can represent realistic higher-order programs in a natural way. To illustrate how such systems may be analyzed, we have adapted HORPO, one of the oldest higher-order termination techniques, to handle logical constraints. Despite being a very basic method, this is already powerful enough to handle examples in this paper. Both LCSTRSs and constrained HORPO are implemented in our new analysis tool Cora.

In the future, we intend to extend more techniques, both first-order and higher-order, to this formalism, and to implement them in a fully automatic tool. We hope that this will make the methods of the term rewriting community available to other communities, both by providing a powerful backend tool, and by showing how existing techniques can be adapted—so they may also be natively adopted in program analysis.

A natural starting point is to increase our power in termination analysis by extending dependency pairs [1, 11, 25, 39] and various supporting methods like the subterm criterion and usable rules. In addition, methods for analyzing complexity, reachability and equivalence (e.g., through rewriting induction [12, 34]), which have been defined for first-order LCTRSs, are natural directions for higher-order extension as well.