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.