diff --git a/src/Collections/Multisets/Multiset.dfy b/src/Collections/Multisets/Multiset.dfy new file mode 100644 index 00000000..0fb997d1 --- /dev/null +++ b/src/Collections/Multisets/Multiset.dfy @@ -0,0 +1,46 @@ +// RUN: %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +/******************************************************************************* +* Copyright by the contributors to the Dafny Project +* SPDX-License-Identifier: MIT +*******************************************************************************/ + +module Multiset { + + /* converts a multiset to a set */ + function method {:opaque} ToSet(s: multiset): set + { + set x: T | x in s + } + + /* proves that the cardinality of a multiset is always more than or equal to that + of the conversion to a set */ + lemma LemmaCardinalityOfSetBound(m: multiset) + ensures |ToSet(m)| <= |m| + { + reveal ToSet(); + if |m| == 0 { + } else { + var x :| x in m; + var xs := multiset{}[x := m[x]]; + assert ToSet(xs) == {x}; + var rest := m - xs; + LemmaCardinalityOfSetBound(rest); + assert ToSet(m) == ToSet(xs) + ToSet(rest); + } + } + + lemma LemmaCardinalityOfSetWithDuplicates(m: multiset, x: T) + requires m[x] > 1 + ensures |ToSet(m)| < |m| + { + reveal ToSet(); + var xs := multiset{}[x := m[x]]; + assert ToSet(xs) == {x}; + var rest := m - xs; + LemmaCardinalityOfSetBound(rest); + assert ToSet(m) == ToSet(xs) + ToSet(rest); + assert |xs| > 1; + } +} \ No newline at end of file diff --git a/src/Collections/Multisets/Multiset.dfy.expect b/src/Collections/Multisets/Multiset.dfy.expect new file mode 100644 index 00000000..ebe2328e --- /dev/null +++ b/src/Collections/Multisets/Multiset.dfy.expect @@ -0,0 +1,2 @@ + +Dafny program verifier finished with 2 verified, 0 errors diff --git a/src/Collections/Sequences/Seq.dfy b/src/Collections/Sequences/Seq.dfy index 2eb850c9..791f6ef9 100644 --- a/src/Collections/Sequences/Seq.dfy +++ b/src/Collections/Sequences/Seq.dfy @@ -14,6 +14,7 @@ * SPDX-License-Identifier: MIT *******************************************************************************/ +include "../Multisets/Multiset.dfy" include "../../Wrappers.dfy" include "../../Math.dfy" @@ -21,6 +22,7 @@ module Seq { import opened Wrappers import Math + import Multiset /********************************************************** * @@ -200,6 +202,26 @@ module Seq { } } + /* A sequence that converts to a set of the same cardinality has no duplicates */ + lemma LemmaNoDuplicatesCardinalityOfSet(s: seq) + requires |ToSet(s)| == |s| + ensures HasNoDuplicates(s) + { + reveal HasNoDuplicates(); + reveal ToSet(); + reveal Multiset.ToSet(); + // Proof by contrapositive: if there is a duplicate, then the cardinality of the + // set would be strictly less than that of the sequence, which contradicts the precondition. + if i,j :| 0 <= i < j < |s| && s[i] == s[j] { + var x := s[i]; + assert s == s[..j] + s[j..]; + assert multiset(s)[x] >= 2; + Multiset.LemmaCardinalityOfSetWithDuplicates(multiset(s), x); + assert ToSet(s) == Multiset.ToSet(multiset(s)); + assert |ToSet(s)| < |s|; + } + } + /* proves that there are no duplicate values in the multiset version of the sequence */ lemma LemmaMultisetHasNoDuplicates(s: seq) requires HasNoDuplicates(s) diff --git a/src/Collections/Sequences/Seq.dfy.expect b/src/Collections/Sequences/Seq.dfy.expect index b0a9b1ad..dacccf30 100644 --- a/src/Collections/Sequences/Seq.dfy.expect +++ b/src/Collections/Sequences/Seq.dfy.expect @@ -1,2 +1,2 @@ -Dafny program verifier finished with 69 verified, 0 errors +Dafny program verifier finished with 70 verified, 0 errors