-1

While working with leon and rationals, I encountered the following issue: the verification of the inverse1 function gives a counter-example but it doesn't make much sense, while inverse2 verifies.

import leon.lang._

case class Rational (n: BigInt, d: BigInt) {

  def +(that: Rational): Rational = {
    require(isRational && that.isRational)
    Rational(n * that.d + that.n * d, d * that.d)
  } ensuring { _.isRational }

  def *(that: Rational): Rational = {
    require(isRational && that.isRational)
    Rational(n * that.n, d * that.d)
  } ensuring { _.isRational }

  def <=(that: Rational): Boolean = {
    require(isRational && that.isRational)
    if (that.d * d > 0)
      n * that.d <= d * that.n
    else
      n * that.d >= d * that.n
  }

  def ==(that: Rational): Boolean = {
    require(isRational && that.isRational)
    //that <= this && this <= that
    true // for testing purpose of course!
  }

  // fails to verify
  def inverse1: Rational = {
    require(isRational && nonZero)
    Rational(d, n)
  }.ensuring { res => res.isRational && res.nonZero && res * this == Rational(1, 1) }

  // verifies
  def inverse2: Rational = {
    require(isRational && nonZero)
    Rational(d, n)
  }.ensuring { res => res.isRational && res.nonZero /*&& res * this == Rational(1, 1)*/ }

  def isRational = !(d == 0)
  def nonZero = n != 0

}

The counter example leon gives me is this:

[  Info  ]  - Now considering 'postcondition' VC for Rational$inverse1 @33:16...
[ Error  ]  => INVALID
[ Error  ] Found counter-example:
[ Error  ]   $this -> Rational(-2, -2)

But it makes no sense mathematically speaking.

I was expecting this code to call the == operator I've defined but since this one always returns true and the function doesn't verify, I'm inclined to think otherwise...

Could someone indicate what's wrong with this program or my understanding of Scala/leon? Thanks.

Hiura
  • 3,500
  • 2
  • 20
  • 39

1 Answers1

3

I'm afraid this is not possible. As you can see here and here in the source, == is not treated by Leon as an ordinary method call, but it's turned into a special AST node called Equals.

But there's a simple fix: Just call your equality === instead of ==.

Samuel Gruetter
  • 1,713
  • 12
  • 11
  • Thanks Samuel. I was hoping for a different answer but at least now I know why it behaves that way. – Hiura May 25 '15 at 18:02