To define a stable sorting of a list
of elements over
, we consider
again each element of the list
as a pair
, where
is the value
of the element in
and
is the number indicating the position of
in
. We define an ordering
on such pairs as follows, where now the
definition of
is slightly different given the non-strict nature of total
preorders:
iff either
or
and
.
Then, the properties of
imply that
is a (non-strict) total order, i.e.,
it is reflexive, antisymmetric, transitive, and total. From this, the definition
of a stable sorting under
of a list
of elements
from
follows exactly the same steps as before: Take the list
, find its unique ordering
under
, and output
.
The following modules WEAKLY-SORTABLE-LIST' and
SORTABLE-LIST' specify the mergesort algorithm with respect to
a total preorder and a (non-strict) total order, respectively.
Their structure is completely analogous to the structure of
WEAKLY-SORTABLE-LIST and SORTABLE-LIST already explained
above. It is described in the two diagrams of Figure 7.5,
where the sort renamings have been abbreviated to
and
,
TOTAL-PREORDER to T-PREORDER, TOTAL-ORDER to
T-ORDER, and WEAKLY-SORTABLE-LIST' W-S-LIST'.
fmod WEAKLY-SORTABLE-LIST'{X :: TOTAL-PREORDER} is
pr LIST{TOTAL-PREORDER}{X}
* (sort NeList{TOTAL-PREORDER}{X} to NeList{X},
sort List{TOTAL-PREORDER}{X} to List{X}) .
sort $Split{X} .
vars E E' : X$Elt .
vars A A' L L' : List{X} .
var N : NeList{X} .
op sort : List{X} -> List{X} .
op sort : NeList{X} -> NeList{X} .
eq sort(nil) = nil .
eq sort(E) = E .
eq sort(E N) = $sort($split(E N, nil, nil)) .
op $sort : $Split{X} -> List{X} .
eq $sort($split(nil, L, L')) = $merge(sort(L), sort(L'), nil) .
op $split : List{X} List{X} List{X} -> $Split{X} [ctor] .
eq $split(E, A, A') = $split(nil, A E, A') .
eq $split(E L E', A, A') = $split(L, A E, E' A') .
op merge : List{X} List{X} -> List{X} .
op merge : NeList{X} List{X} -> NeList{X} .
op merge : List{X} NeList{X} -> NeList{X} .
eq merge(L, L') = $merge(L, L', nil) .
op $merge : List{X} List{X} List{X} -> List{X} .
eq $merge(L, nil, A) = A L .
eq $merge(nil, L, A) = A L .
eq $merge(E L, E' L', A)
= if E <= E'
then $merge(L, E' L', A E)
else $merge(E L, L', A E')
fi .
endfm
fmod SORTABLE-LIST'{X :: TOTAL-ORDER} is
pr WEAKLY-SORTABLE-LIST'{TOTAL-ORDER}{X}
* (sort NeList{TOTAL-ORDER}{X} to NeList{X},
sort List{TOTAL-ORDER}{X} to List{X}) .
endfm
Apart from the changes in the requirement theories and the module names, the
main difference bewteen both approaches appears in the third $merge
equation. In the WEAKLY-SORTABLE-LIST module we have
eq $merge(E L, E' L', A)
= if E' < E
then $merge(E L, L', A E')
else $merge(L, E' L', A E)
fi .
Here we are dealing with a strict weak order. We test E' < E. If it is true,
then by irreflexivity we know that E < E' is false, and the element E' from
the second list is appended to the merged list. Whereas if E' < E is false, we
know that either E < E' holds or E and E' are incomparable.
Either way, the element E from the first list is appended to the merged list,
either because it is smaller or because it is incomparable and we are preserving the
original relative positions in the list (stability).
On the other hand, in the WEAKLY-SORTABLE-LIST' module we have
eq $merge(E L, E' L', A)
= if E <= E'
then $merge(L, E' L', A E)
else $merge(E L, L', A E')
fi .
In this case we are dealing with a total preorder. We test E <= E'. If it is true,
then either E' <= E is false or E and E' are equivalent. Either
way, the element E from the first list is appended to the merged list, either
because it is smaller or because it is equivalent and we are preserving the original
relative positions in the list (stability). If E <= E' is false, then E' <= E
holds by totality and therefore E' is appended to the merged list.
We can redo with these modules the same instantiation we considered above, but using now the predefined view String<= from TOTAL-ORDER to String, where <= is the non-strict lexicographic order on strings.
fmod STRING-SORTABLE-LIST' is
pr SORTABLE-LIST'{String<=} .
endfm
Maude> red in STRING-SORTABLE-LIST' :
sort("a" "quick" "brown" "fox" "jumps"
"over" "the" "lazy" "dog") .
result NeList{String<=}:
"a" "brown" "dog" "fox" "jumps" "lazy" "over" "quick" "the"
Maude> red sort("a" "quick" "brown" "fox" "jumps" "over" "the"
"lazy" "dog" "a" "quick" "brown" "fox" "jumps"
"over" "the" "lazy" "dog") .
result NeList{String<=}: "a" "a" "brown" "brown" "dog" "dog" "fox"
"fox" "jumps" "jumps" "lazy" "lazy" "over" "over" "quick" "quick"
"the" "the"