[Agda] Type-checker evaluator performance

Jacques Carette carette at mcmaster.ca
Wed Feb 3 17:40:22 CET 2016


Yes, very clear, thank you!
Jacques
PS: perhaps such pieces of advice should go on to the wiki?

On 2016-02-03 11:23 , Ulf Norell wrote:
> Abstracting from the details of this particular example, the problem 
> is the following: You want to construct a proof of some proposition P 
> using some sort of search procedure that may or may not deliver an 
> actual proof. So you define
>
>   search : Maybe P
>
>   proof : P
>   proof = unMaybe search
>
> where
>
>   unMaybe : (m : Maybe A) {_ : IsJust m} -> A
>   unMaybe nothing {}
>   unMaybe (just x) _ = x
>
> When type checking 'proof' the type checker has to run 'search' to see 
> that it is indeed 'just' something so that the implicit IsJust proof 
> can be filled in. The important thing to note here is that 'search' 
> only needs to be evaluated far enough to discover that it is a 'just' 
> and no further. This means that we should make getting to the 'just' 
> constructor as cheap as possible.
>
> Consider what happens if you implement search in the most 
> straightforward way, simply running the search in the Maybe monad. In 
> this case you need to traverse the search space and build up the proof 
> object (which may be very large), at every step checking that all the 
> substeps came back 'just'. You don't get the final 'just' until you 
> have created the entire proof object.
>
> The alternative that I'm advocating is that you split the search 
> procedure into a test and a soundness proof for the test:
>
>   test : Bool
>   sound : T test -> P
>
> Here the soundness proof is responsible for constructing the proof 
> object, assuming that the test came back 'true'. We can then implement 
> the search as follows:
>
>   search : Maybe P
>   search with T? test
>   ... | yes p = just (sound p)
>   ... | no _ = nothing
>
> Now, in order to get to the 'just' constructor we only have to run 
> 'test' and we don't have to worry at all about constructing the proof 
> object.
>
> Concretely what I did in the me-em example was replace the 'ag' and 
> 'af' functions by two new functions 'ag-now' and 'af-now' implemented 
> as 'search' above (with tests 'ag-test' and 'af-test', and soundness 
> proofs 'ag-proof' and 'af-proof').
>
> I hope this clarifies things.
>
> / Ulf
>
>
>
> On Wed, Feb 3, 2016 at 3:34 PM, Jacques Carette <carette at mcmaster.ca 
> <mailto:carette at mcmaster.ca>> wrote:
>
>     Where can one read more about "no-eta-equality" ?  I believe that
>     some of my work could benefit from this as well.
>
>     Similarly, I sought to learn from the changes you did
>     https://github.com/UlfNorell/me-em/commit/5930ad6b155244a1ba85abc36a0e79c1333ca7f4
>     but while I can "read the code", I can't quite understand how this
>     matches your high-level description.  Could you comment a bit
>     about this?  I believe that this would be well worth it, and may
>     indeed help achieve a reduction in Agda-blame, as outlined in the
>     first paragraph.
>
>     Jacques
>
>
>     On 2016-02-03 04:31 , Ulf Norell wrote:
>>     I think it's unfortunate, if perhaps not completely undeserved,
>>     that Agda gets blamed every time a program is slow or uses a lot
>>     of memory. When people are writing slow Haskell programs their
>>     first thoughts are "maybe I should try to optimise my program",
>>     not "maybe someone should optimise GHC" and I wish we could have
>>     a little more of that for Agda programs. There are certainly
>>     performance problems in Agda's compile time evaluator
>>     (call-by-name, interpretation overhead, etc) but that doesn't
>>     mean that you can't write programs that perform reasonably well.
>>
>>     I had a look at your code and the main performance problem seems
>>     to be that you are too strict in the proof objects produced by
>>     the model checker. In your example the correctness proof of
>>     Peterson's algorithm consists of four (I think) complete state
>>     graphs (with ~14k states) decorated with proofs that you build up
>>     eagerly before deciding that you have a valid proof. If you
>>     instead separate the decision procedure from the construction of
>>     the proof object you only need to run the former to be sure that
>>     you have a proof, and can evaluate the latter lazily as you need
>>     it. I forked [1] your repo and tried this out. The Examples
>>     module checks in 26s and uses 900M memory on my machine. Another
>>     thing I tried is to use a pair type without eta equality for the
>>     models (in my experience eta equality and call-by-name is a major
>>     source of inefficiency). This saves you another 30% time and space.
>>
>>     / Ulf
>>
>>     [1] https://github.com/UlfNorell/me-em
>>
>>
>>     On Mon, Feb 1, 2016 at 9:46 AM, Liam O'Connor
>>     <liamoc at cse.unsw.edu.au <mailto:liamoc at cse.unsw.edu.au>> wrote:
>>
>>         Hi all,
>>
>>         I’m currently using the development version of Agda, and I’ve
>>         been working on using the evaluation in type checking to
>>         embed proof search procedures inside Agda.
>>
>>         https://github.com/liamoc/me-em
>>
>>         Now, one of the applications of this technique is a model
>>         checker for a fragment of CTL on the guarded command language
>>         (*).
>>
>>         Here is an example, where I use the model checker to verify
>>         peterson’s synchronisation algorithm.
>>
>>         https://github.com/liamoc/me-em/blob/master/GCL/Examples.agda#L91
>>
>>         Before I cleaned this code up and put it on GitHub, it was
>>         all in one file. I can affirm that I was able to type check
>>         the code then. Today, after splitting it into multiple files,
>>         and cleaning it up a little bit, I found that Agda would just
>>         get OOM killed before finishing, and it would take at least
>>         10 minutes before getting OOM-killed, using all 8GB of my RAM
>>         and 4GB of my swap.
>>
>>         Going back to the original, single-file version, it now also
>>         fails to finish checking and gets OOM-killed, so perhaps the
>>         multiple-files thing isn’t causing the issue.
>>
>>         (Perhaps I just used a bit of disk space and now it’s running
>>         out of swap).
>>
>>         Anyway, I’ll try this on a machine with more memory (RAM and
>>         swap) later, but is there any plan to improve performance
>>         (both in time and space) of the type-checker evaluator? I
>>         appreciate that what I’m trying to do is not something which
>>         it was designed to handle, but it _was working_ at some point.
>>
>>         BTW, it seems to make no difference whether I use sharing or
>>         not, but when I got it to successfully check yesterday it was
>>         using sharing.
>>
>>         (*) If you’ve seen the paper I wrote on this, note that the
>>         model checker is substantially different now.
>>
>>         (*) Also note that originally the definition for
>>         petersons-search read:
>>
>>         petersons-search
>>            = search $
>>                and′ mutex? (and′ sf? termination?)
>>                (model petersons initialState)
>>
>>         but I gave it a fixed depth of 25 just to stop it doing any
>>         unnecessary searching.
>>
>>         Liam
>>         _______________________________________________
>>         Agda mailing list
>>         Agda at lists.chalmers.se <mailto:Agda at lists.chalmers.se>
>>         https://lists.chalmers.se/mailman/listinfo/agda
>>
>>
>>
>>
>>     _______________________________________________
>>     Agda mailing list
>>     Agda at lists.chalmers.se <mailto:Agda at lists.chalmers.se>
>>     https://lists.chalmers.se/mailman/listinfo/agda
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.chalmers.se/pipermail/agda/attachments/20160203/1ac68852/attachment-0001.html


More information about the Agda mailing list