/*
Illustrates instability in a sort
*/
module unstable_sort
-- define a set of elements
-- with a total ordering lt
-- and some equality eq that's any equivalence
-- models idea that element equality may be determined
-- by contents of elements
sig Elt {lt, eq: set Elt}
fact {TotalOrder (Elt$lt, Elt$eq) && Equivalence (Elt$lt)}
-- define a set of indexes
-- with a total ordering lt
-- and an equality eq that is just simple equality
sig Index {lt, eq: set Index}{eq = this}
fact {TotalOrder (Index$lt, Index$eq)}
-- r is a total order, with equality decided by eq
fun TotalOrder [t] (r,eq: t->t) {
-- r is transitive
r.r in r
-- r is antisymmetric
r & ~r in eq
-- r is reflexive
eq in r
-- any pair are comparable
univ[r] in r + ~r
}
-- r is an equivalence
fun Equivalence [t] (r: t->t) {
-- r is transitive
r.r in r
-- r is symmetric
r = ~r
-- r is reflexive
iden[t] in r
}
-- a' has same elements as a, but in sorted order
fun Sort (a, a': Index ->? Elt) {
-- precondition: no duplicates
#Index.a = #a
-- sorting preserves set of elements and count
Index.a = Index.a'
#a = #a'
-- after, elements are in sorted order
all i, j: a.Elt | i in j.lt => a'[i] in a'[j].lt
}
-- show a sort that exchanges two elements unnecessarily
fun Unstable (a,a': Index ->? Elt) {
Sort (a, a')
-- find two indexes such that ..
some i, j: a.Elt {
-- their elements are equivalent
a[i] in a[j].eq
-- i precedes j
i in j.lt
-- but the indexes of the elements at i and j are
-- not in the same order in a'
a'.(a[i]) !in a'.(a[j]).lt
}
}
run Unstable for 2