Trying to setup a few functions for a quicksort implementation I got stuck on the following lemmas, filterLemmaExtra and filterLemmaSizes.
function filter<T(==)>(xs: seq<T>, p: (T) -> bool): seq<T>
ensures forall x: T :: x in xs && p(x) ==> x in filter(xs, p)
ensures forall x: T :: x !in xs && p(x) ==> x !in filter(xs, p)
ensures forall x: T :: x in filter(xs, p) ==> p(x)
ensures forall x: T :: x in filter(xs, p) ==> x in xs[0..|xs|]
ensures forall x: T :: x in filter(xs, p) ==> x in xs
ensures forall x: T :: x in xs && !p(x) ==> x !in filter(xs, p)
ensures forall i: nat :: i < |filter(xs, p)| ==> filter(xs, p)[i] in xs
{
if xs == [] then [] else if p(xs[0]) then [xs[0]] + filter(xs[1..], p) else filter(xs[1..], p)
}
lemma filterLemmaSizes<T(==)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
ensures multiset(filter(xs,p)) <= multiset(xs)
{
}
lemma filterLemmaExtra<T(==)>(xs: seq<T>, p: (T) -> bool, i: nat)
requires 0 <= i <= |xs|
ensures filter(xs, p) == filter(xs[0..i], p) + filter(xs[i..], p)
{
}
predicate isNegatedBooleanFn<T(==)>(xs: seq<T>, p: (T) -> bool, q: (T) -> bool) {
forall x: T :: x in xs && p(x) ==> !q(x)
}
function filter_mset<T(==)>(ms: multiset<T>, p: (T) -> bool): multiset<T>
ensures forall x :: x in ms && p(x) ==> x in filter_mset(ms, p) && ms[x] == filter_mset(ms, p)[x]
ensures forall x :: x in filter_mset(ms, p) ==> p(x)
ensures forall x :: x in filter_mset(ms, p) ==> x in ms
{
if ms == multiset{} then multiset{} else
var x :| x in ms; if p(x) then var result := multiset{}; result[x := ms[x]] + filter_mset(ms[x := 0], p) else filter_mset(ms[x := 0], p)
}
lemma filterAndFilterMset<T(==)>(ms: seq<T>, p: (T) -> bool)
ensures multiset(filter(ms, p)) == filter_mset(multiset(ms), p)
{
assert forall x :: x in filter(ms, p) ==> x in multiset(filter(ms, p)) && p(x);
assert forall x :: x in filter(ms, p) ==> x in filter_mset(multiset(ms), p);
assert forall x :: x in filter_mset(multiset(ms), p) ==> x in filter(ms, p);
filterLemmaSizes(ms, filter(ms, p), p);
assert forall x :: x in filter(ms, p) ==> multiset(filter(ms, p))[x] == filter_mset(multiset(ms), p)[x];
}
lemma filterMS<T(==)>(xs: seq<T>, p: (T) -> bool)
ensures exists q: (T) -> bool :: isNegatedBooleanFn(xs, p, q)
{
var q: (T) -> bool := y => !p(y);
forall x | x in xs
ensures x in xs && p(x) ==> !q(x)
{
if p(x) {
assert !q(x);
}
}
assert isNegatedBooleanFn(xs, p, q);
// assert forall x: T :: x in xs && p(x) ==> !q(x);
}
lemma filterMsetAndSum<T(==)>(xs: seq<T>, ms: multiset<T>, p: (T) -> bool)
requires ms == multiset(xs)
ensures exists Q: (T) -> bool :: isNegatedBooleanFn(xs, p, Q) && (filter_mset(ms, p) + filter_mset(ms, Q)) == ms
{
filterMS(xs, p);
var Q :| isNegatedBooleanFn(xs, p, Q);
var sum_ms := filter_mset(ms, p) + filter_mset(ms, Q);
forall x | x in ms
ensures ms[x] == sum_ms[x]
{
if p(x) {
assert x in filter_mset(ms, p);
assert filter_mset(ms, p)[x] == ms[x];
assert x in sum_ms;
assert sum_ms[x] == ms[x];
}else {
assert x in filter_mset(ms, Q);
assert filter_mset(ms, Q)[x] == ms[x];
assert x in sum_ms;
assert sum_ms[x] == ms[x];
}
}
assert sum_ms == ms;
}
My initial implementation of filterLemmaExtra gets bogged down when I try to assert the indices of the concatenated sequences are equal to the filter.
lemma filterLemmaExtra<T(==)>(xs: seq<T>, p: (T) -> bool, i: nat)
requires 0 <= i <= |xs|
ensures filter(xs, p) == filter(xs[0..i], p) + filter(xs[i..], p)
{
assert xs == xs[0..i] + xs[i..];
var allxs := set x | x in xs && p(x);
var leftxs := set x | x in xs[0..i] && p(x);
var rightxs := set x | x in xs[i..] && p(x);
assert allxs == leftxs + rightxs;
forall x | x in filter(xs, p)
ensures x in filter(xs[0..i], p) || x in filter(xs[i..], p)
{
assert x in xs ==> x in xs[0..i] || x in xs[i..];
}
var all := filter(xs[0..i], p) + filter(xs[i..], p);
assert |filter(xs, p)| == |all|;
// forall i: nat | i < |filter(xs,p)| //explodes
// ensures filter(xs, p)[i] == (filter(xs[0..i], p) + filter(xs[i..], p))[i]
// {
// }
}
For the filterLemmaSizes I thought of two approaches. Initially trying to break down the seqences and the filtered sequence but apart from the case that the first element in both sequences match I can't see how to do induction on the rest of the cases.
Then I thought maybe that I could try to do a proof by negation on the multiset values but I'm not sure of how to write those statements. It seems you should be able to assert that that if multiset(xs)[x] == #non-zero number then there exist that many indices in the original array that satisfy p(x) and so they should also be in filter(xs, p);.
lemma filterLemmaSizes<T(==)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
ensures multiset(filter(xs,p)) <= multiset(xs)
{
forall x | x in xs && p(x)
ensures multiset(xs)[x] == multiset(fxs)[x]
{
assert x in multiset(xs);
assert x in xs[0..|xs|];
assert x in multiset(fxs);
assert x in fxs[0..|fxs|];
if multiset(xs)[x] != multiset(fxs)[x] && multiset(xs)[x] < multiset(filter(xs, p))[x] {
} else if multiset(xs)[x] != multiset(fxs)[x] && multiset(xs)[x] > multiset(filter(xs, p))[x] {
}
// if xs != [] && p(xs[0]) && x == xs[0] {
// assert xs == [xs[0]] + xs[1..];
// assert multiset(xs) == multiset{xs[0]} + multiset(xs[1..]);
// assert multiset(xs)[x] == multiset{xs[0]}[x] + multiset(xs[1..])[x];
// assert multiset(xs)[x] == multiset{xs[0]}[x] + multiset(xs[1..])[x];
// assert xs[0] == fxs[0];
// assert multiset(fxs) == multiset{xs[0]} + multiset(filter(xs[1..],p));
// assert x in xs;
// if x in xs[1..] {
// calc {
// multiset(xs)[x];
// ==
// multiset{x}[x] + multiset(xs[1..])[x];
// == {assert 1 == multiset{xs[0]}[x];}
// 1 + multiset(xs[1..])[x];
// == { filterLemmaSizes(xs[1..], filter(xs[1..],p), p); }
// 1 + multiset(filter(xs[1..], p))[x];
// ==
// multiset{xs[0]}[x] + multiset(filter(xs[1..],p))[x];
// ==
// multiset(fxs)[x];
// }
// } else{
// assert multiset(xs[1..])[x] == 0;
// assert multiset(filter(xs[1..], p))[x] == 0;
// }
// assert multiset(xs)[xs[0]] == multiset(fxs)[xs[0]];
// } else if xs != [] && x != xs[0] {
// assert xs[0] == fxs[0];
// } else{
// }
}
}
Proving both lemma need appeal to induction. See the code snippet below, I have n't proved first post condition in second lemma but it should be doable using induction too.
function filter<T>(s: seq<T>, p: T -> bool) : seq<T>
{
if s == [] then []
else if p(s[0]) then [s[0]] + filter(s[1..], p)
else filter(s[1..], p)
}
lemma filterSplit<T>(s: seq<T>, p: T -> bool, idx: nat)
requires 0 <= idx <= |s|
ensures filter(s, p) == filter(s[..idx], p) + filter(s[idx..], p)
{
if idx == 0 {
}
else {
filterSplit(s[1..], p, idx-1);
assert filter(s[1..], p) == filter(s[1..][..(idx-1)], p) + filter(s[1..][(idx-1)..], p);
if p(s[0]) {
calc {
filter(s, p);
[s[0]] + filter(s[1..], p);
[s[0]] + filter(s[1..][..(idx-1)], p) + filter(s[1..][(idx-1)..], p);
{
assert s[..idx] == [s[0]] + s[1..idx];
assert s[1..idx] == s[1..][..(idx-1)];
}
filter(s[..idx], p) + filter(s[1..][(idx-1)..], p);
{
assert s[1..][(idx-1)..] == s[idx..];
}
filter(s[..idx], p) + filter(s[idx..], p);
}
}
else {}
}
}
lemma filterMultiSet<T>(s: seq<T>, p: T -> bool)
ensures multiset(filter(s, p)) <= multiset(s)
{
if s == [] {
}
else {
filterMultiSet(s[1..], p);
calc <= {
multiset(filter(s, p));
multiset([s[0]]) + multiset(filter(s[1..], p));
multiset([s[0]]) + multiset(s[1..]);
{
assert s == [s[0]] + s[1..];
}
multiset(s);
}
}
}
Update : See code snippet below for first postcondition of second lemma
function filter<T>(s: seq<T>, p: T -> bool) : seq<T>
ensures forall x :: x !in s ==> x !in filter(s, p)
{
if s == [] then []
else if p(s[0]) then [s[0]] + filter(s[1..], p)
else filter(s[1..], p)
}
lemma filterIncludeMultiSet<T>(s: seq<T>, p: T -> bool)
ensures forall x :: x in s && p(x) ==> multiset(s)[x] == multiset(filter(s, p))[x]
{
if s == [] {}
else {
var rs := s[1..];
filterIncludeMultiSet(rs, p);
assert forall x :: x in rs && p(x) ==> multiset(rs)[x] == multiset(filter(rs, p))[x];
forall x | x in s && p(x) ensures multiset(s)[x] == multiset(filter(s, p))[x] {
if x == s[0] {
if x in rs {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
1 + multiset(filter(rs, p))[x];
}
}
else {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
1;
}
calc {
multiset(filter(s, p))[x];
multiset([s[0]] + filter(rs, p))[x];
multiset([s[0]])[x] + multiset(filter(rs, p))[x];
1;
}
}
}
else {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
multiset(rs)[x];
multiset(filter(rs, p))[x];
}
}
}
}
I found another way to verify the filterLemmaSizes.
lemma filterLemmaSizes<T(!new)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
{
if xs == [] {
} else {
assert xs == [xs[0]] + xs[1..];
filterLemmaSizes(xs[1..], filter(xs[1..], p), p);
if p(xs[0]) {
calc {
multiset(fxs)[xs[0]];
==
multiset(filter(xs[..1], p))[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
multiset(filter([xs[0]], p))[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
multiset([xs[0]])[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
1 + multiset(filter(xs[1..], p))[xs[0]];
==
multiset{xs[0]}[xs[0]] + multiset(xs[1..])[xs[0]];
==
multiset(xs)[xs[0]];
}
} else{
assert xs[0] !in filter(xs, p);
}
}
}
I'm trying to prove the simple gcd algorithm in Dafny, so I wrote the following, but it seems I can not use the method divides inside the loop invariants:
method divides(d: int, x: int) returns (result: bool)
requires d > 0
requires x > 0
ensures (result == true ) ==> (exists q : int :: (d * q == x))
ensures (result == false) ==> (forall q : int :: (d * q != x))
{
// code omitted
}
method gcd(a: int, b: int) returns (result: int)
requires a > 0
requires b > 0
ensures (forall d : int :: ((exists q1 : int :: q1 * d == a) && (exists q2 :: (q2 * d == b))) ==>
(exists q3 : int :: (q3 * d == result)))
{
var x := a;
var y := b;
var fuel := a+b;
while ((x != y) && (fuel > 0))
decreases fuel
invariant x > 0
invariant y > 0
invariant (forall d : int :: (divides(d,x) && divides(d,y)) ==> (divides(d,a) && divides(d,b)))
{
// code omitted
}
return x;
}
Is there anyway to use a divides method/function/macro inside invariants?
Unlike methods, functions can appear in expressions. You can create a function:
function div(d: int, x: int): bool
{
if (d != 0 && x % d == 0) then true else false
}
Then in your method divides, you can have
ensures result == div(d,x)
and in your method gcd you can use the function div in your invariant.
Note, from the Dafny guide: One caveat of functions is that not only can they appear in annotations, they can only appear in annotations. Functions are never part of the final compiled program, they are just tools to help us verify our code.
For the following code I get that it cannot establish the existence of LHS values that satisfy the such-that predicate. How could I prove the right side holds and such an x exists?
method Main() {
var n : int := 10;
var x : seq<int> :| n == |x| && forall i :: 0 <= i < |x| ==> -1 <= x[i] <= 1;
}
https://rise4fun.com/Dafny/TiO5
You need to provide a witness. The following assertion does the trick:
method Main() {
var n : int := 10;
assert |[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]| == 10;
var x : seq<int> :| n == |x| && forall i :: 0 <= i < |x| ==> -1 <= x[i] <= 1;
}
However, this brings you to the next point, which is that
It seems that even something trivial like this is not supported at the moment:
method Main() {
var n : int := 10;
var y : seq<int> :| y == [3];
var x : seq<int> :| x == y;
var z : seq<int> :| |z| == |y|;
}
Dafny manages to instantiate x, but not z.
Maybe post it in their GitHub/Issues?
I have a bunch of Grails domain classes that I want to be able to treat as Numbers, Integers in particular. For the most part, they are just numeric values with a few extra properties that are used as meta-data. Here's an example:
class Score {
String meaning
Integer value
static hasMany = [responses:Response]
static constraints = {
meaning blank: false, maxSize: 100, unique: true
value min: 1, unique: true // Assume we're using a base-1 ranking system, where 1 is the lowest
}
}
I tried to add #Delegate to the value field, but it didn't seem to have any impact: I still couldn't do 7 + myScore. All I get is missing method exceptions because Integer doesn't have a signature matching plus(Score).
What is the correct way to go about doing this, since #Delegate doesn't seem to work?
Note: I also have a need to turn my domain classes into various Collections with meta data, but I expect it will be the same solution.
I'm imagining everyone has moved on, now that this question is over a year and a half old, but still, I'm surprised that no one offered up Groovy categories as a solution. Indeed, it seems to me that categories are the most natural solution to this problem. Without changing the "Grailsiness" of the original domain class, you can still instill the desired numeric behavior relatively easily.
First define the category class:
class ScoreCategory {
static asType(Score s, Class newClass) {
switch (newClass) {
case Integer.class:
case Integer.TYPE:
case Number.class: return s?.value ?: 0
default: throw new GroovyCastException("Cannot cast to ${newClass}")
}
}
static boolean equals(Score me, def you) {
you instanceof Score && me as int == you as int
}
static Score plus(Score a, b) { plusImpl(a, b) }
static Score plus(Score a, Number b) { plusImpl(a, b) }
static Score plus(Number a, Score b) { plusImpl(a, b) }
private static plusImpl(a, b) { new Score(value: (a as int) + (b as int)) }
static Score minus(Score a, b) { minusImpl(a, b) }
static Score minus(Score a, Number b) { minusImpl(a, b) }
static Score minus(Number a, Score b) { minusImpl(a, b) }
private static minusImpl(a, b) { a + -b }
static Score multiply(Score a, Number b) { multImpl(a,b) }
static Score multiply(Number a, Score b) { multImpl(a,b) }
private static multImpl(a,b) { new Score(value: (a as int) * (b as int)) }
static Integer div(Score a, b) { (a as int).intdiv(b as int) }
static Score div(Score a, Number b) { new Score(value:(a as int).intdiv(b as int)) }
static Score negative(Score a) { new Score(value: -(a as int)) }
static Score abs(Score a) { new Score(value: (a as int).abs())}
}
Then, at some suitably global place in the application declare the mixins:
Number.metaClass.mixin ScoreCategory
Score.metaClass.mixin ScoreCategory
After all this, as demonstrated below, Score objects should now behave like numeric quantities:
def (w, x, y, z) = [54, 78, 21, 32]
def (s1, s2) = [new Score(value:w), new Score(value:x)]
assert (s1 + s2) == new Score(value: w + x)
assert (s1 + y) == new Score(value: w + y)
assert (z + s2) == new Score(value: z + x)
assert (s1 - s2) == new Score(value: w - x)
assert (s1 - y) == new Score(value: w - y)
assert (z - s2) == new Score(value: z - x)
assert (s1 * y) == new Score(value: w * y)
assert (z * s2) == new Score(value: z * x)
assert (s2 / s1) == x.intdiv(w)
assert (s1 / y) == new Score(value: w / y)
You answer can be operator overloding. Here you are overloading the plus method to operate with integers and doubles:
class Score {
...
int plus(int otherValue){
return otherValue + value
}
double plus(double otherValue){
return (value as double) + otherValue
}
// And you can avoid my pitfall overriding asType method
Object asType(Class clazz) {
if (clazz == Integer) {
return value
}
else if(class == Double){
return value as Double
}
else {
super.asType(clazz)
}
}
}
assert new Score(value: 4) + 15 == 19
assert new Score(value: 4) + 15.32 == 19.32
assert 15.32 + (new Score(value: 4) as Double) == 19.32
assert 15 + (new Score(value: 4) as Integer) == 19
Add an overload for the plus operator on the Number metaclass:
Number.metaClass.plus = { Score s -> delegate + s.value }
Add this in BootStrap.groovy in your app, or in doWithDynamicMethods in a plugin.
Edit:
As pointed out in the comments, this doesn't work if the Score is on the left side of the operation. Add a plus method to the Score class to handle that:
Number plus(Number n) { value + n }
You can also extend Number.
class Score extends Number {
Integer value
public int intValue() { return value }
public double doubleValue() { return value }
public long longValue() { return value }
public float floatValue() { return value }
}
Score sc = new Score( value: 5 );
println 10 + sc