Termination of structural induction - recursion

I can't get Agda's termination checker to accept functions defined using structural induction.
I created the following as the, I think, simplest example exhibiting this problem.
The following definition of size is rejected, even though it always recurses on strictly smaller components.
module Tree where
open import Data.Nat
open import Data.List
data Tree : Set where
leaf : Tree
branch : (ts : List Tree) → Tree
size : Tree → ℕ
size leaf = 1
size (branch ts) = suc (sum (map size ts))
Is there a generic solution to this problem? Do I need to create a Recursor for my data type? If yes, how do I do that? (I guess if there's an example of how one would define a Recursor for List A, that would give me enough hints?)

There is a trick you can do here: you can manually inline and fuse the definitions of map and sum inside a mutual block. It's pretty anti-modular, but it's the simplest method I'm aware of. Some other total languages (Coq) can sometimes do this automatically.
mutual
size : Tree → ℕ
size leaf = 1
size (branch ts) = suc (sizeBranch ts)
sizeBranch : List Tree → ℕ
sizeBranch [] = 0
sizeBranch (x :: xs) = size x + sizeBranch xs

Related

Two different types of OCaml recursive functions

During two weeks I've been doing some simple programs in OCaml. I've noticed that when we are working with a recursive structure T and we want to have the information I on T then depending on the information I we have two types of recursive function.
For simplicity let's assume T is a binary tree. So I'll use the following type :
type 'a tree = Empty | 'a * 'a tree * 'a tree
Now let's say the information I can be calculated from left to right on the binary tree. When I am saying left to right it means that the information I can be calculated from the root to the leaves without getting backward.
To be more clear let's say the information I we want to have is simply "the number of nodes of the binary tree". Then what's nice with this information is that when we get to all leaves then we get I, so we are going left to right in the sense that we begin from the root and expend recursively to the left and right subtree and the end case is when we arrived at the leaves.
So we simply have :
let rec nodes = function
|Empty -> 0 (*it's ok we are done here*)
|Node(_,l,r) -> 1 + nodes l + nodes r
What's very nice is that when the information can be calculated left to right then OCaml's pattern matching is a very strong tool and the information I can be calculated in an easy way.
So more generally we have :
let rec get_information = function
| Empty -> (*here we are done so we return a constant value*)
|Node(_,l,r)-> (*here we apply recusrively the function to the left and right tree*)
Now here comes my problem. Let's say I is an information that can't be calculated from left to right but from right to left. So it means that to get the information I we need to begin from the leaves of the tree and extend recursively to the top and we are done only when we get to the root of the binary tree (so the end case is when we get to the root of the binary tree and not the leaves).
For example, let's say the information I is : "the binary tree has the propriety that for every node the number of nodes in his left subtree is strictly superior to the number of nodes in his right subtree". If we want to solve this in linear time then we need to begin from the leaves and expend recursively to the top (note that I don't necessarily want a solution to the problem).
So to me, it's tricky to write a function that gets the information I when I is a right to left information (it needs to begin from the leaves and extend to the top). On the contrary pattern-matching is perfect when the information is a left to right information.
So my question is how to do when we need to write a function that gets the information I (when I is right to left)? Are there techniques to solve these kind of problems? Is it still possible to use pattern matching in a tricky way in order to get the desired result?
Pattern matching is useful for writing both kinds of function. Higher order functions called folds can also be used.
First, a concrete version. We will want to know whether a tree is left leaning, and if so, how many nodes it has. An int option will represent this nicely, with None indicating any non-left leaning tree.
type 'a tree = Empty | Branch of 'a * 'a tree * 'a tree
let rec tree_info = function
| Empty -> Some 0
| Branch (_, l, r) ->
match tree_info l, tree_info r with
| Some x, Some y when x >= y -> Some (x + y + 1)
| _ -> None
let is_left_leaning tree =
match tree_info tree with
| Some _ -> true
| None -> false
(Note that the condition x >= y is not 'strictly greater than', but this is deliberate; x > y is a poor choice. I'll leave figuring out why as an exercise.)
We can also express this style of function in terms of an operation called a right fold. For this operation one provides a value for each constructor of the datatype being folded over: in each place that constructor occurs, the fold operation will use that value to compute the result of the fold:
let rec foldr empty branch = function
| Empty -> empty
| Branch (x, l, r) ->
branch x (foldr empty branch l) (foldr empty branch r)
Note that the empty value and the Empty constructor have the same arity, and the branch value and the Branch constructor have the same arity, with corresponding argument types. That's characteristic of a right fold.
Given foldr, we can easily define map:
let map f tree =
foldr Empty (fun x l r -> Branch (f x, l, r)) tree
Or of course, 'tree_info':
let tree_info tree =
foldr
(Some 0)
(fun _ l r ->
match l, r with
| Some x, Some y when x >= y -> Some (x + y + 1)
| _ -> None)
tree
This is the alternative to pattern matching on the constructors of tree.

Idris vectors vs linked lists

Does Idris do any kind of optimization under the hood of vectors? Because from the looks of it, an Idris vector is just a linked list with known size (known at compile time). In fact, in general it seems like you could express the following equivalence (I'm guessing a bit at the syntax):
Vector : Nat -> Type -> Type
Vector n t = (l: List t ** length l = n)
So while this is nice in the sense of preventing range errors, the real advantage of vectors (in the traditional usage of the term) is in terms of performance; in particular, O(1) random access. It seems that the idris vector would not support this (how would you write the indexing function to have this performance?).
Assuming that there's no wizardry going on under the hood (as happens with Nat) to reconfigure Vectors, is there a random-access data type in Idris?
How would be/is such a thing defined in an algebraic type system? Certainly it seems like it would be impossible to define it inductively.
Is it possible, within a type system like that of Idris, to create a data type which supports O(1) random access, and is aware of its length such that all access is provably valid? (Haskell has array-style Vectors, but their concrete implementation is opaque to the average user, including me)
It doesn't do anything to optimise Vector lookups (at the time of writing this answer, at least).
This isn't because of any difficulty in doing it, really, but more because I would rather have some kind of general framework for writing this kind of optimisation than hard coding lots of them. Admittedly, we already have hard coded optimisations for Nat, but I still would prefer not to add loads more in an ad-hoc fashion.
Depending on what you actually want it for, it might be that the experimental uniqueness type system will help, in that you could have a low level mutable thing under the hood and still have safe and efficient access and update in a pure style in the high level language. We'll see...
Edwin has the definitive answers on what Idris currently does. However, if you are looking for something which might be natural to optimize into constant-time lookup in some cases, the following might be a step in the right direction.
For compile-time fixed-size vectors (i.e., not under a lambda, not parameterized by length at top-level), the following structure gives you vectors and lookup functions that, for any fixed concrete length, can be compile-time normalized to functions that should be somewhat straightforwardly optimizable into constant-time functions. (Sorry, code is in Coq; I don't have a working version of Idris at the moment, and don't know it well. I'm happy to replace this with Idris code if someone suggests the right syntax, e.g., in a comment.)
Fixpoint vector (n : nat) (A : Type) :=
match n return Type with
| 0 => unit
| S n' => (A * vector n' A)%type
end.
Definition nil {A} : vector 0 A := tt.
Definition cons {n} {A : Prop} (x : A) (xs : vector n A) : vector (S n) A
:= (x, xs).
Fixpoint get {n} {A : Prop} (m : nat) (default : A) (v : vector n A) {struct n} : A
:= match n as n return vector n A -> A with
| 0 => fun _ => default
| S n' => match m with
| 0 => fun v => fst v
| S m' => fun v => #get n' A m' default (snd v)
end
end v.
The idea is that, for any fixed n, the normal form of get is non-recursive, so the compiler could, hypothetically, compile it into a function whose runtime is independent of what n happens to be.

Theorem Prover: How to optimize a backward proof search containing a "useless rule AND"

Quick review:
Inference rule = conclusion + rule + premises
Proof tree = conclusion + rule + sub-trees
Backward proof search: given an input goal, try to build a proof tree by applying inference rules in bottom-up way (for example, the goal is the final conclusion, after applying a rule, it will generate a list of new sub-goals on the premises)
Problem:
Given an input goal (e.g. A AND B,C), assume that we apply the rule AND firstly on A AND B, then get two new sub-goals, the first one is A,C, the second one is B,C.
The problem is that A and B are useless, which means we can build a complete proof tree using only C. However, we have two sub-goals, then we have to prove C two times, so it is really inefficient.
Question:
For example, we have A AND B,C AND D,E AND F,G,H AND I. In this case, we only need D and G to build a complete proof tree. So how to choose the right rules to apply?
This is an example code in Ocaml:
(* conclusion -> tree *)
let rec prove goal = (* the function builds a proof tree from an input goal *)
let rule = get_rule goal in (* get the first rule *)
let sub-goals = apply_rule goal in (* apply a rule *)
let sub-trees = List.map (fun g -> prove g) sub-goals in (* prove sub-goals recursively *)
(goal, rule, sub-trees) (* return proof tree *)
If you want the shortest (shallowest) proof, which in this case uses disjunction introduction and avoids conjunction introduction, then you can look at techniques like iterative deepening. For instance you could change your code as follows:
let rec prove n goal =
if n=0 then failwith "No proof found" else
let rule = get_rule goal in
let sub-goals = apply_rule goal in
let sub-trees = List.map (fun g -> prove (n-1) g) sub-goals in
(goal, rule, sub-trees)
let idfs maxn goal =
let rec aux n =
if n > maxn then None else
try
Some (prove n goal)
with Failure _ -> aux (n+1) in
aux 1
If you want to avoid re-doing the proof for a sub-goal that has already appeared, then you can use some form of memoization (a narrow form of lemma speculation/application really). See for instance the answers to this question, especially the second answer since prove is naturally recursive.
These suggestions do not touch the subject of how you pick the rules to apply, that is how exactly get_rule is coded. In practice, many options will be available and you would want to iterate through them.

Implementing the combinator calculus

Concept
I am implementing an interpreter that allows a user to define arbitrary combinators and apply them to arbitrary terms. For example, a user may define the Church encoding for pairs by inputting the following combinator definitions:
pair a b c → c a b
true a b → a
first a → a true
The user may then input first (pair a b), which is reduced step-by-step according to the previously defined rules:
first (pair a b)
→ pair a b true
→ true a b
→ a
Other combinators may also be defined, such as those used in the SKI combinator calculus:
S x y z → x z (y z)
K x y → x
I x → x
The identity combinator could also be defined in terms of the first two combinators by I → S S K K or I → S K (K K) or I = S K x. The universal iota combinator could then be defined by:
ι x → x S K
These examples hopefully illustrate what I am trying to do.
Implementation
I am attempting to implement this using graph reduction and a graph rewriting system. Let tree be a data type defined recursively by
tree = leaf | (tree tree)
This is a binary tree, where nodes may be either leafs (terminal nodes) or branches (internal nodes) consisting of a pair of subtrees. The branches represent the application of a term to another term, while leaves represent combinators and arguments. Let rule be a data type defined by
rule = (tree tree)
This corresponds to a reduction rule that transforms the left tree into the right tree (a → b). The list of rules may then be defined by
rules = rule | (rule rules)
Effectively, when evaluating an expression such as pair a b c → c a b, the interpreter constructs a tree of the form (((pair a) b) c) corresponding to the left hand side, a tree of the form ((c a) b) corresponding to the right hand side, constructs a pair of both trees corresponding to a rule (where a,b,c are somehow specified to be arbitrary parameters and not necessarily combinators or terminal symbols), and appends this pair to the list rules. When reducing an expression of the form first (pair a b), the interpreter constructs the corresponding tree (first ((pair a) b)) and applies the reduction rules as follows:
(first ((pair a) b))
→ (((pair a) b) true)
→ ((true a) b)
→ a
To do this, the interpreter must perform pattern matching on the tree and its subtrees, "moving around" the combinators and arbitrary parameters to construct a new tree corresponding to the right hand side of the rule. An example implementation of the tree structure in C is given by
struct tree_t {
bool is_leaf;
union {
char* symbol;
struct {
tree_t* left;
tree_t* right;
};
};
};
A pattern matching function could be implemented as
bool matches(tree_t* pattern, tree_t* replacement) {
if (pattern -> is_leaf && replacement -> is_leaf)
//do stuff, return a boolean
else if (pattern -> is_leaf && replacement -> is_branch)
//do stuff, return a boolean
else if (pattern -> is_branch && replacement -> is_leaf)
//do stuff, return a boolean
else if (pattern -> is_branch && replacement -> is_branch)
return matches(pattern -> left, replacement -> left) && matches(pattern -> right, replacement -> right);
//The above tests for equality recursively by testing for equality in each subtree.
}
However, I am unsure of how to implement important details of this process, including:
Matching an input tree with the LHS tree of a reduction rule.
Transforming the input tree into the RHS tree of the reduction rule, preserving parameters (which may be leaves or branches) and "moving them around" around to their appropriate places.
I believe pattern-matching on a node would involve examining the left child and right child of the node and so on, until terminal nodes are reached. Does anyone know of a program or tutorial online that has implemented a similar concept in C and that I could learn from? Am I even on the right track in approaching the problem through this method, or is there a simpler way?
You need to take it in two separate steps. A pattern matcher matches a pattern against a tree, and builds a dictionary mapping variables in the pattern to values in the tree.
Then you pass that dictionary to a separate function that fills in the replacement, by replacing variables with their values from the dictionary.
The pattern matching approach described in SICP will work just fine in C, though you may find it easier to use a mutable data structure for the dictionary. See https://mitpress.mit.edu/sicp/full-text/sicp/book/node99.html

Simplify pretty-printing of naturals

Let's say I wrote a function for reversing a list. I want to test it out using the value command, just to assure myself that I probably got it right. But the output looks horrible:
value "reverse [1,8,3]"
> "[1 + 1 + 1, 1 + 1 + (1 + 1) + (1 + 1 + (1 + 1)), 1]" :: "'a list"
If I tell Isabelle to treat those numeric characters as naturals, the output is even worse:
value "reverse [1::nat,8,3]"
> "[Suc (Suc (Suc 0)), Suc (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0))))))), Suc 0]" :: "nat list"
Sometimes I resort to using strings, but that's looks a bit funny with all those apostrophes everywhere:
value "reverse [''1'',''8'',''3'']"
> "[''3'', ''8'', ''1'']" :: "char list list"
Can I instruct Isabelle's pretty-printer to print Suc (Suc (Suc 0)) as 3, and so on? Perhaps by giving some magical incantation to the syntax or translations commands?
Here's my complete example, in case you'd like to paste it into Isabelle:
theory Scratch imports Main begin
fun reverse where
"reverse [] = []"
| "reverse (x#xs) = reverse xs # [x]"
value "reverse [1,8,3]"
value "reverse [1::nat,8,3]"
value "reverse [''1'',''8'',''3'']"
end
Short answer: My first thought is to use type int, since (unlike nat) its code generator setup uses a binary numeral representation by default.
Importing "~~/src/HOL/Library/Code_Target_Nat", as naT suggests, is also a good idea if you don't want to use the Suc representation for type nat.
Explanation: Numerals in Isabelle are encoded using constructors defined in Num.thy; e.g. 5 is an abbreviation for numeral (Bit1 (Bit0 One)). Here One, Bit0 and Bit1 are constructors of type num. numeral is overloaded, and works for any type with a 1 and an associative +. Here are the code equations for numeral:
lemma numeral_code [code]:
"numeral One = 1"
"numeral (Bit0 n) = (let m = numeral n in m + m)"
"numeral (Bit1 n) = (let m = numeral n in m + m + 1)"
If we generate code for 5::'a::numeral, then 1 and + on type 'a are treated as uninterpreted constants, so they remain in the output: (1 + 1) + (1 + 1) + 1.
Generating code for 5::nat works the same, except we do have code for 1 and + on type nat, in terms of Suc. Thus (1 + 1) + (1 + 1) + 1 reduces further to Suc (Suc (Suc (Suc (Suc 0)))).
Type int works differently. The code generator setup in Int.thy uses three constructor functions for type int: Pos and Neg of type num => int, as well as 0. A code_abbrev declaration causes each occurrence of numeral at type num => int to be replaced by Pos during code generation. After the code is run, Pos is then turned back into numeral before Isabelle displays the result. Thus 5::int evaluates to just 5.
Special code setup theories: src/HOL/Library contains a few different theories for customizing code generation for numerals.
"~~/src/HOL/Library/Code_Target_Nat" tells the code generator to use the target language's (e.g. SML or Haskell's) built-in numerals for type nat. For example, 5::nat is usually translated to SML as numeral (Bit1 (Bit0 One)); however, with this library loaded it gets translated as 5 in SML. Results of value are translated back into the Isabelle numeral representation afterward.
"~~/src/HOL/Library/Code_Target_Int" is the same, but for type int instead of nat.
"~~/src/HOL/Library/Code_Target_Numeral" simply loads both of the previous two libraries. It only affects types nat and int, not any other types in class numeral.
"~~/src/HOL/Library/Code_Binary_Nat" configures nat in the same style as the default code setup for int: with constructors 0 and nat_of_num::num => nat and a code_abbrev declaration. With this library, value "5::nat" also returns 5.
Note: I hope my answer here doesn't prevent Brian Huffman or Florian Haftmann from giving an answer. If it does, that would be a bad thing. Hopefully, I'm just doing some gofer work to set either of them up.
Short answer 1: The pertinent mailing list email is Re: [isabelle] value no longer pretty-prints numbers of type nat.
Short answer 2: A solution for nat is to import "~~/src/HOL/Library/Code_Target_Nat". Because I'm not clear on the details of how numeral and num are completely tied into HOL at the low level, the solution I'm giving you is not necessarily a good and final solution.
A big part of my answer here is partly to say, before Brian Huffman or Florian Haftmann get here, who are the authors of Num.thy, "I'm interested in this too, because it's related to numeral, which is a powerful part of HOL. The more info I have about the intricacies of using numeral, the better".
Basically, they made a design choice change for Isabelle2013-1, which is to have the default for nat and numeral be represented in a successor form. That's what the mailing list email is about.
If you use declare[[show_sorts=true]], you will see that your value "reverse [1,8,3]" is using type class numeral. I mention that because I've been putting a lot of effort into trying to learn about numeral, and even with concrete types, such as nat and int, the use of constants such as 44 and 5 involve numeral, at least for the input. And even with a concrete type like nat, numeral can be involved in simp rules that are being used.
Before saying more, one way to get nice nat output for value "reverse [1::nat,8,3]" is, again, to use the following import:
"~~/src/HOL/Library/Code_Target_Nat"
The reason I'm interested in your question is because that's just a plug-n-play solution I saw by Andreas Lochbihler in that email.
I can't get value "reverse [1,8,3]" to not use sums of 1 by importing this:
"~~/src/HOL/Library/Code_Target_Numeral"
So, I want to know about how to get numeral to be in that nice form we love to see.
Anyway, numeral is at the core of using number constants. Consider this:
lemma "(3::nat) = z"
using[[simp_trace, simp_trace_depth_limit=100, linarith_trace, rule_trace]]
using[[blast_trace, blast_stats]]
apply simp
oops
Part of the simp trace is this:
[1]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
3 = z
[1]Procedure "Num.reorient_numeral" produced rewrite rule:
?a1 = ?b1 ≡ ?b1 = ?a1
[1]Applying instance of rewrite rule
?a1 = ?b1 ≡ ?b1 = ?a1
[1]Rewriting:
3 = z ≡ z = 3
If you look at simp traces involving number constants, you'll see that Num rules show up a lot, which come from that most excellent of Num.thy.

Resources