coq-club AT inria.fr
Subject: The Coq mailing list
List archive
Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?
Chronological Thread
- From: Joachim Breitner <mail AT joachim-breitner.de>
- To: coq-club AT inria.fr
- Subject: Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?
- Date: Thu, 26 Apr 2018 11:41:07 -0400
- Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=mail AT joachim-breitner.de; spf=Neutral smtp.mailfrom=mail AT joachim-breitner.de; spf=None smtp.helo=postmaster AT hermes.serverama.de
- Ironport-phdr: 9a23:L6mdihFa3UCB9KgSJ/YED51GYnF86YWxBRYc798ds5kLTJ7zoc+wAkXT6L1XgUPTWs2DsrQY07GQ6/iocFdDyK7JiGoFfp1IWk1NouQttCtkPvS4D1bmJuXhdS0wEZcKflZk+3amLRodQ56mNBXdrXKo8DEdBAj0OxZrKeTpAI7SiNm82/yv95HJbAhEmDSwbaluIBmqsA7cqtQYjYx+J6gr1xDHuGFIe+NYxWNpIVKcgRPx7dqu8ZBg7ipdpesv+9ZPXqvmcas4S6dYDCk9PGAu+MLrrxjDQhCR6XYaT24bjwBHAwnB7BH9Q5fxri73vfdz1SWGIcH7S60/VDK/5KlpVRDokj8KOT0k/m/XlMJ+gqBUoBy9qBJ4zIHZe46VOOZkc67HZ94WWW5MU8BMXCJBGIO8aI4PAvIFM+ZftYbyu1sOrRq7BQKxGe7v0CFHhn7q3a08zeshCxzN0QslH90UsXTUqM74NKUVUe+v0KbIzTTDb/ZP1Tjm8ojHbBEhoe2KXb1ua8rd01QgGB3cg1iWtIfrMTSV1uEXvGia6eptTeCvi2k9pA5tojivx8IshpDSiYIP1F/E9Dl5wIArKt2iUkJ0fMCrHINLtyGGLYR5XsAiTH9nuSkmyr0Jo5i7fCcUx5g92xHfbPmHf5CH4hLiSOaRISp4i2l/dL2jgBay9FCsyvf9W8WuzFlFtDJJkt7Dt3wXzRPc9tKLSuZ+/kqnxD2B1BjT5/lZLU02lKfXMZoszqQumpYOv0nPBDL6lUv4gaKQa04q4PKn6/79bbXjvpKcN5F7igX5Mqk2msywH/44Mg0QUGiA4+i8z6Ps/VfnQLpUlP05iKzZv4rAKcsGuKG1Gw5V0oA95BajFzqqzdYVkHgdIF9BYh6LkZXlNl/ULPzlA/qyjUygkDJxyPDHOr3hDI/NLn/GkLr5eLZy8U9cyA4owNBd4JJbEK0OIPLyWk/0rdDXFQU5PBK1w+b7DtVyyJkeVXiSDaCHKK/Sq0OH5vozI+mQY48YoCryK/885/L3kXA5nUIdcrKy0JsMaHG4G+xmLF+DbXrthNcBC2YKsRAkQOzkkl3RGQJUMn21Ruc34iwxIIOgF4bKAI6305Kb2yLuPJpfbWBHDximC3rpa4OJQb9YbSuTJudjlTUPVbmkDoU72BCysgLgjbZqeLmHshYEvI7ugYAmr9bYkgs/oGQtXpatllqVRmQxpVsmAjo/3aRxu0t4kA7R069xiPxZEJlZ/f5ITgE3L9jQwr4gUoygakf6Zt6MDW2ebJC+GzhrF4AzxNYFY0d4Xt+4gxHf2SewRbMYxeTSWc4Et5nE1n20HP5TjnbL0K571gsmT9FKOHbgnaNl6QXJDovA1UmUxf6n
Hi,
you might enjoy looking at
https://github.com/antalsz/hs-to-coq/tree/master/examples/coinduction
where I implement such a memo table in Haskell, convert it to Coq using
hs-to-coq (the generated file is not in the git repo, so I attached it
to this mail), and then in MemoProofs.v show that it preserves the
semantics of the memoized functions.
The Time commands at the end of this function show that memoization
actually works in Coq!
Time Eval vm_compute in slowFib 25. (* Finished transaction in 2.248 secs *)
Time Eval vm_compute in slowFib 25. (* Finished transaction in 2.233 secs *)
Time Eval vm_compute in cachedFib 25. (* Finished transaction in 2.203 secs *)
Time Eval vm_compute in cachedFib 25. (* Finished transaction in 0. secs *)
Time Eval vm_compute in cachedFib 26. (* Finished transaction in 3.579 secs *)
Time Eval vm_compute in cachedFib 26. (* Finished transaction in 0. secs *)
Cheers,
Joachim
Am Mittwoch, den 25.04.2018, 12:11 -0700 schrieb
roconnor AT theorem.ca:
> I've posted this question on the cstheory stack exchange at
> https://cstheory.stackexchange.com/questions/40631/how-can-you-build-a-coinductive-memoization-table-for-recursive-functions-over-b
> but I'm hoping to reach a wider audience by also asking here on the Coq
> Club
> mailing list. I copy my question below.
>
> ----
>
> The StreamMemo library for Coq illustrates how to memoize a function f :
> nat ->
> A over the natural numbers. In particular when f (S n) = g (f n), the
> imemo_make shares the computation of recursive calls.
>
> Suppose instead of natural numbers, we want to memoize recursive functions
> over
> binary trees:
>
> Inductive binTree : Set :=
> | Leaf : binTree
> | Branch : binTree -> binTree -> binTree.
>
> Suppose we have a function f : binTree -> A that is structurally recursive,
> meaning that there is a function g : A -> A -> A such that f (Branch x y) =
> g
> (f x) (f y). How do we build a similar memo table for f in Coq such that
> the
> recursive computations are shared?
>
> In Haskell, it is not too hard to build such a memo table (see MemoTrie for
> example) and tie-the-knot. Clearly such memo tables are productive. How can
> we
> arrange things to convince a dependently typed language to accept such knot
> tying is productive?
>
> ----
>
> Even building a memotrie data type for binary trees is difficult in Coq.
> The
> natural solution calls for using a Bushy Datatype (see
> https://www.cs.ox.ac.uk/richard.bird/online/BirdMeertens98Nested.pdf) which
> doesn't pass Coq's positivity check (but does seem to pass Agda's
> positivity
> check; maybe Christine Paulin could even further relax Coq's positivity
> check.
> :) ). At the risk of prejudicing the reader, I have a gist of how I've
> worked
> around this to define a memotrie data type for binary trees in Coq at
> https://gist.github.com/roconnor/52375c3a81c927c5a8234be858f9830b
>
> My above solution to building a memotrie is moderately contrived and adhoc,
> so
> I encourage those intrested in this problem to try a solution themselves
> first
> before reading my gist. You may come up with a better solution than what I
> have.
>
> The memotrie I build in my gist doesn't memoize recursive calls of a
> structurally recursive function over binary trees. At the end I write out
> the
> type of solution one would write in Haskell to build an example memotrie
> that
> memoizes recurive calls. However, this definition fails that corecursive
> guard
> check (and rightly so I think).
>
> I don't know how to build a memotrie to memoize recursive calls in a
> structurally recursive function. I'm hoping someone one the mailing list
> might
> know a solution.
>
> --
> Russell O'Connor <http://r6.ca/>
>
--
Joachim Breitner
mail AT joachim-breitner.de
http://www.joachim-breitner.de/
(* Default settings (from HsToCoq.Coq.Preamble) *) Generalizable All Variables. Unset Implicit Arguments. Set Maximal Implicit Insertion. Unset Strict Implicit. Unset Printing Implicit Defensive. Require Coq.Program.Tactics. Require Coq.Program.Wf. (* Preamble *) Require Coq.NArith.BinNat. Require Psatz. (* There is [Coq.NArith.BinNat.N.lt_wf_0], but it is Opauqe, so we cannot compute with Program Fixpoint that recurse on [N]. Until this is fixed (in https://github.com/coq/coq/pull/7060), we we reprove this lemma and close it with [Defined]. *) Require Import Coq.NArith.BinNat. Theorem N_lt_wf : well_founded N.lt. Proof. assert (well_founded (fun n1 n2 => (N.to_nat n1) < (N.to_nat n2))) by (apply Wf_nat.well_founded_ltof). intro x. specialize (H x). induction H. constructor. intros y Hy. apply H0. Psatz.lia. Defined. Ltac solve_lookupTrie := Coq.Program.Tactics.program_simplify; try apply Wf.measure_wf; try apply N_lt_wf; try match goal with H : _ = false |- _ => apply Coq.NArith.BinNat.N.eqb_neq in H end; apply Coq.NArith.BinNat.N.div_lt; Psatz.lia. Ltac solve_fib := Coq.Program.Tactics.program_simplify; try apply N_lt_wf; repeat match goal with H : _ = false |- _ => apply Coq.NArith.BinNat.N.eqb_neq in H end; Psatz.lia. (* Converted imports: *) Require Coq.NArith.BinNat. Require Coq.Numbers.BinNums. Require GHC.Base. Require GHC.Num. Require GHC.Real. Import GHC.Base.Notations. Import GHC.Num.Notations. (* Converted type declarations: *) CoInductive NatTrie a : Type := TrieNode : a -> NatTrie a -> NatTrie a -> NatTrie a. Arguments TrieNode {_} _ _ _. (* Converted value declarations: *) Program Fixpoint lookupTrie {a} (arg_0__ : NatTrie a) (arg_1__ : Coq.Numbers.BinNums.N) {measure arg_1__ (Coq.NArith.BinNat.N.lt)} : a := match arg_0__, arg_1__ with | TrieNode here div2 minus1div2, n => if Bool.Sumbool.sumbool_of_bool (n GHC.Base.== #0) then here else if Bool.Sumbool.sumbool_of_bool (GHC.Real.odd n) then lookupTrie minus1div2 (GHC.Real.div n #2) else lookupTrie div2 (GHC.Real.div n #2) end. Solve Obligations with (solve_lookupTrie). Definition mkTrie {a} : (Coq.Numbers.BinNums.N -> a) -> NatTrie a := cofix mkTrie f := TrieNode (f #0) (mkTrie (f GHC.Base.â (fun arg_0__ => arg_0__ GHC.Num.* #2))) (mkTrie (f GHC.Base.â ((fun arg_1__ => arg_1__ GHC.Num.+ #1) GHC.Base.â (fun arg_2__ => arg_2__ GHC.Num.* #2)))). Program Fixpoint slowFib (arg_0__ : Coq.Numbers.BinNums.N) {measure arg_0__ (Coq.NArith.BinNat.N.lt)} : Coq.Numbers.BinNums.N := let 'num_1__ := arg_0__ in if Bool.Sumbool.sumbool_of_bool (num_1__ GHC.Base.== #0) then #0 else let 'num_2__ := arg_0__ in if Bool.Sumbool.sumbool_of_bool (num_2__ GHC.Base.== #1) then #1 else let 'n := arg_0__ in slowFib (n GHC.Num.- #1) GHC.Num.+ slowFib (n GHC.Num.- #2). Solve Obligations with (solve_fib). Definition cachedFib : Coq.Numbers.BinNums.N -> Coq.Numbers.BinNums.N := lookupTrie (mkTrie slowFib). (* External variables: Bool.Sumbool.sumbool_of_bool Coq.NArith.BinNat.N.lt Coq.Numbers.BinNums.N GHC.Base.op_z2218U__ GHC.Base.op_zeze__ GHC.Num.fromInteger GHC.Num.op_zm__ GHC.Num.op_zp__ GHC.Num.op_zt__ GHC.Real.div GHC.Real.odd *)
Attachment:
signature.asc
Description: This is a digitally signed message part
- [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, roconnor, 04/25/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Joachim Breitner, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Joachim Breitner, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Li-yao Xia, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Joachim Breitner, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Li-yao Xia, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Joachim Breitner, 04/26/2018
- Re: [Coq-Club] How can you build a coinductive memoization table for recursive functions over binary trees?, Joachim Breitner, 04/26/2018
Archive powered by MHonArc 2.6.18.