Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Translating Scala Programs to Isabelle/HOL

Translating Scala Programs to Isabelle/HOL

Lars Hupel, Viktor Kuncak: Translating Scala Programs to Isabelle/HOL
Paper: https://lars.hupel.info/pub/translating-scala.pdf
Presented at IJCAR 2016, Coimbra, Portugal

We present a trustworthy connection between the Leon verification system and the Isabelle proof assistant. Leon is a system for verifying functional Scala programs. It uses a variety of automated theorem provers (ATPs) to check verification conditions (VCs) stemming from the input program. This process is completely automatic: no user intervention is required for proving these conditions. Isabelle, on the other hand, is an interactive theorem prover used to verify mathematical specifications using its own input language Isabelle/Isar. Users specify (inductive) definitions and write proofs about them manually, albeit with the help of semi-automated tactics. The integration of these two system allows us to exploit Isabelle's rich standard library and give greater confidence guarantees in the correctness of analysed programs.

Lars Hupel

June 30, 2016
Tweet

More Decks by Lars Hupel

Other Decks in Research

Transcript

  1. Translating Scala Programs to Isabelle/HOL
    Lars Hupel
    Technical University of Munich
    Viktor Kuncak
    École polytechnique fédérale de Lausanne
    June 30, 2016

    View Slide

  2. A Taste of Scala & Isabelle
    2

    View Slide

  3. Scala
    functional & object-oriented language
    initially developed at EPFL by Martin Odersky
    3

    View Slide

  4. Scala
    functional & object-oriented language
    initially developed at EPFL by Martin Odersky
    runs on JVM, Javascript and LLVM
    3

    View Slide

  5. Scala
    functional & object-oriented language
    initially developed at EPFL by Martin Odersky
    runs on JVM, Javascript and LLVM
    strong industry support
    3

    View Slide

  6. Scala Example
    sealed abstract class List[A]
    case class Cons[A](head: A, tail: List[A]) extends List[A]
    case class Nil[A]() extends List[A]
    def size[A](l: List[A]): BigInt = l match {
    case Nil() => BigInt(0)
    case Cons(_, xs) => 1 + size(xs)
    }
    4

    View Slide

  7. Isabelle
    interactive proof assistant
    powerful automation
    5

    View Slide

  8. Isabelle
    interactive proof assistant
    powerful automation
    classical and equational reasoning
    decision procedures (e.g. linear arithmetic)
    integration with external automated theorem provers
    ...
    5

    View Slide

  9. Isabelle/HOL
    LCF tradition: small proof kernel
    6

    View Slide

  10. Isabelle/HOL
    LCF tradition: small proof kernel
    most prominent logic: HOL
    offers commands for functional programming
    recursive functions, datatypes, ... are definitional
    6

    View Slide

  11. Isabelle/HOL Example
    datatype α list = Nil | Cons α (α list)
    primrec size :: α list ⇒ int where
    size Nil = 0
    | size(Cons x xs) = 1+size xs
    7

    View Slide

  12. Isabelle/HOL Example
    datatype α list = Nil | Cons α (α list)
    primrec size :: α list ⇒ int where
    size Nil = 0
    | size(Cons x xs) = 1+size xs
    lemma size xs ≥ 0
    by(inductxs) simp+
    7

    View Slide

  13. Leon
    A Verification & Synthesis Toolkit for Scala
    8

    View Slide

  14. Leon
    automated verification system for a subset of Scala
    9

    View Slide

  15. Leon
    automated verification system for a subset of Scala
    functions & datatypes can be annotated with assertions
    (require, ensuring, assert)
    9

    View Slide

  16. Leon
    automated verification system for a subset of Scala
    functions & datatypes can be annotated with assertions
    (require, ensuring, assert)
    uses SMT solvers to discharge conditions
    9

    View Slide

  17. Leon
    automated verification system for a subset of Scala
    functions & datatypes can be annotated with assertions
    (require, ensuring, assert)
    uses SMT solvers Isabelle to discharge conditions
    9

    View Slide

  18. Scala Example
    sealed abstract class List[A]
    case class Cons[A](head: A, tail: List[A]) extends List[A]
    case class Nil[A]() extends List[A]
    def size[A](l: List[A]): BigInt = l match {
    case Nil() => BigInt(0)
    case Cons(_, xs) => 1 + size(xs)
    }
    10

    View Slide

  19. Leon Example
    sealed abstract class List[A]
    case class Cons[A](head: A, tail: List[A]) extends List[A]
    case class Nil[A]() extends List[A]
    def size[A](l: List[A]): BigInt = (l match {
    case Nil() => BigInt(0)
    case Cons(_, xs) => 1 + size(xs)
    }) ensuring(_ >= 0)
    10

    View Slide

  20. 11

    View Slide

  21. Bridging the Gap
    12

    View Slide

  22. Bridging the Gap
    ... but why?
    12

    View Slide

  23. Motivation
    Isabelle brings a lot to the table ...
    20+ years of development
    1M+ lines of libraries
    trustworthiness through LCF approach
    rich specification & proof language
    13

    View Slide

  24. Motivation
    Leon brings a lot to the table ...
    readily-available verification for a wide-spread language
    Goal: Introduce developers to formal methods?
    14

    View Slide

  25. Bridging the Gap
    15

    View Slide

  26. Bridging the Gap
    ... with as little unverified code as possible
    15

    View Slide

  27. Bridging the Gap
    Problem
    Input: Scala AST
    Translation: ???
    Output: Isabelle ???
    Possible solution
    Textual code generation
    16

    View Slide

  28. Bridging the Gap
    Problem
    Input: Scala AST
    Translation: ???
    Output: Isabelle ???
    Possible solution
    Textual code generation
    FRAGILE
    16

    View Slide

  29. Bridging the Gap
    Problem
    Input: Scala AST
    Translation: ???
    Output: Isabelle API calls
    Reasonable solution
    Talk directly to Isabelle’s API
    16

    View Slide

  30. Bridging the Gap
    Problem
    Input: Scala AST
    Translation: ???
    Output: Isabelle API calls
    Reasonable solution
    Talk directly to Isabelle’s API
    16

    View Slide

  31. Talking to Isabelle: libisabelle
    there is a Scala API for Isabelle, but it’s very low-level
    libisabelle is a high-level-wrapper
    17

    View Slide

  32. Talking to Isabelle: libisabelle
    there is a Scala API for Isabelle, but it’s very low-level
    libisabelle is a high-level-wrapper
    supports multiple Isabelle versions
    supports multiple simultaneous processes
    supports Java & Scala
    can be used like an asynchronous RPC library
    setup-free
    17

    View Slide

  33. Talking to Isabelle: libisabelle
    there is a Scala API for Isabelle, but it’s very low-level
    libisabelle is a high-level-wrapper
    supports multiple Isabelle versions
    supports multiple simultaneous processes
    supports Java & Scala
    can be used like an asynchronous RPC library
    setup-free
    can be used for other projects
    17

    View Slide

  34. Talking to Isabelle: libisabelle
    there is a Scala API for Isabelle, but it’s very low-level
    libisabelle is a high-level-wrapper
    supports multiple Isabelle versions
    supports multiple simultaneous processes
    supports Java & Scala
    can be used like an asynchronous RPC library
    setup-free
    can be used for other projects
    still: manual work required
    17

    View Slide

  35. Translating Datatypes
    Datatypes are almost straightforward.
    18

    View Slide

  36. Translating Functions
    Scala input
    def size(xs: List[A]): BigInt = xs match {
    case Nil() => 0
    case Cons(_, xs) => 1 + size(xs)
    }
    19

    View Slide

  37. Translating Functions
    Scala input
    def size(xs: List[A]): BigInt = xs match {
    case Nil() => 0
    case Cons(_, xs) => 1 + size(xs)
    }
    Isabelle output
    fun size xs = (case xs ofNil ⇒ 0 | Cons x xs ⇒ 1+sizexs)
    19

    View Slide

  38. Translating Functions
    Scala input
    def size(xs: List[A]): BigInt = xs match {
    case Nil() => 0
    case Cons(_, xs) => 1 + size(xs)
    }
    Ambitious Isabelle output
    fun size where
    size Nil = 0
    | size(Cons x xs) = 1+size xs
    19

    View Slide

  39. Translating Functions
    Scala input
    def size(xs: List[A]): BigInt = xs match {
    case Nil() => 0
    case Cons(_, xs) => 1 + size(xs)
    }
    Ambitious Isabelle output
    fun size where
    size Nil = 0
    | size(Cons x xs) = 1+size xs
    VERIFIED
    19

    View Slide

  40. Evaluation
    20

    View Slide

  41. Coverage of Leon’s Library
    almost complete
    21

    View Slide

  42. Coverage of Leon’s Library
    almost complete
    ... including gnarly pattern matches
    21

    View Slide

  43. Coverage of Leon’s Library
    almost complete
    ... including gnarly pattern matches
    Isabelle can prove 71% of the verification conditions
    automatically
    21

    View Slide

  44. Coverage of Leon’s Library
    almost complete
    ... including gnarly pattern matches
    Isabelle can prove 71% of the verification conditions
    automatically
    missing: array, string operations
    21

    View Slide

  45. Coverage of Leon’s Library
    almost complete
    ... including gnarly pattern matches
    Isabelle can prove 71% of the verification conditions
    automatically
    missing: array, string operations
    takes ≈ 40 seconds on a fast machine
    21

    View Slide

  46. Reuse
    sealed abstract class List[T] {
    def size: BigInt = ... // implementation
    }
    case class Cons[T](h: T, t: List[T]) extends List[T]
    case class Nil[T]() extends List[T]
    22

    View Slide

  47. Reuse
    @isabelle.typ(name = "List.list")
    sealed abstract class List[T] {
    @isabelle.function(term = "Int.int o List.length")
    def size: BigInt = ... // implementation
    }
    @isabelle.constructor(name = "List.list.Cons")
    case class Cons[T](h: T, t: List[T]) extends List[T]
    @isabelle.constructor(name = "List.list.Nil")
    case class Nil[T]() extends List[T]
    22

    View Slide

  48. Reuse
    @isabelle.typ(name = "List.list")
    sealed abstract class List[T] {
    @isabelle.function(term = "Int.int o List.length")
    def size: BigInt = ... // implementation
    }
    @isabelle.constructor(name = "List.list.Cons")
    case class Cons[T](h: T, t: List[T]) extends List[T]
    @isabelle.constructor(name = "List.list.Nil")
    case class Nil[T]() extends List[T]
    VERIFIED
    22

    View Slide

  49. Integration
    @proof(method = "(clarsimp, induct rule: list_induct2, auto)")
    def mapFstZip[A, B](xs: List[A], ys: List[B]) = {
    require(length(xs) == length(ys))
    xs.zip(ys).map(_._1)
    } ensuring { _ == xs }
    23

    View Slide

  50. Trustworthiness
    Scala and Isabelle/HOL are quite different
    translation is more intricate than we’d like it to be
    24

    View Slide

  51. Trustworthiness
    Scala and Isabelle/HOL are quite different
    translation is more intricate than we’d like it to be
    but: just 3500 lines of code (including verified code)
    24

    View Slide

  52. Trustworthiness
    Scala and Isabelle/HOL are quite different
    translation is more intricate than we’d like it to be
    but: just 3500 lines of code (including verified code)
    user doesn’t see resulting terms and definitions
    24

    View Slide

  53. Trustworthiness
    Scala and Isabelle/HOL are quite different
    translation is more intricate than we’d like it to be
    but: just 3500 lines of code (including verified code)
    user doesn’t see resulting terms and definitions
    countermeasure: print report
    looks almost like an Isabelle theory
    can be copy-pasted into IDE
    24

    View Slide

  54. Conclusion
    prove Scala code correct with high assurance
    co-develop specifications in Isabelle and Scala
    zero setup required, integrates seamlessly
    groundwork for using Isabelle as an API has been laid
    25

    View Slide

  55. Q & A
    26

    View Slide