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.

A1216674d5c9747bcdcc716872439137?s=128

Lars Hupel

June 30, 2016
Tweet

Transcript

  1. 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
  2. 4.

    Scala functional & object-oriented language initially developed at EPFL by

    Martin Odersky runs on JVM, Javascript and LLVM 3
  3. 5.

    Scala functional & object-oriented language initially developed at EPFL by

    Martin Odersky runs on JVM, Javascript and LLVM strong industry support 3
  4. 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
  5. 8.

    Isabelle interactive proof assistant powerful automation classical and equational reasoning

    decision procedures (e.g. linear arithmetic) integration with external automated theorem provers ... 5
  6. 10.

    Isabelle/HOL LCF tradition: small proof kernel most prominent logic: HOL

    offers commands for functional programming recursive functions, datatypes, ... are definitional 6
  7. 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
  8. 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
  9. 15.

    Leon automated verification system for a subset of Scala functions

    & datatypes can be annotated with assertions (require, ensuring, assert) 9
  10. 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
  11. 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
  12. 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
  13. 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
  14. 20.

    11

  15. 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
  16. 24.

    Motivation Leon brings a lot to the table ... readily-available

    verification for a wide-spread language Goal: Introduce developers to formal methods? 14
  17. 27.

    Bridging the Gap Problem Input: Scala AST Translation: ??? Output:

    Isabelle ??? Possible solution Textual code generation 16
  18. 28.

    Bridging the Gap Problem Input: Scala AST Translation: ??? Output:

    Isabelle ??? Possible solution Textual code generation FRAGILE 16
  19. 29.

    Bridging the Gap Problem Input: Scala AST Translation: ??? Output:

    Isabelle API calls Reasonable solution Talk directly to Isabelle’s API 16
  20. 30.

    Bridging the Gap Problem Input: Scala AST Translation: ??? Output:

    Isabelle API calls Reasonable solution Talk directly to Isabelle’s API 16
  21. 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
  22. 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
  23. 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
  24. 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
  25. 36.

    Translating Functions Scala input def size(xs: List[A]): BigInt = xs

    match { case Nil() => 0 case Cons(_, xs) => 1 + size(xs) } 19
  26. 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
  27. 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
  28. 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
  29. 43.

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

    matches Isabelle can prove 71% of the verification conditions automatically 21
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 55.