wip on report
This commit is contained in:
parent
05490f52d3
commit
2a1ceb0cbf
7 changed files with 640 additions and 83 deletions
303
.gitignore
vendored
Normal file
303
.gitignore
vendored
Normal file
|
@ -0,0 +1,303 @@
|
|||
*.dll
|
||||
*.runtimeconfig.json
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
# *.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
# *.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
|
@ -0,0 +1,5 @@
|
|||
# Assignment 1 -- Software Analysis
|
||||
|
||||
Dafny *pygments* lexer stored in `pygmentize.py` directory thanks to:
|
||||
|
||||
https://github.com/Locke/pygments-dafny/
|
91
pygmentize.py
Executable file
91
pygmentize.py
Executable file
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
pygments.lexers.dafny
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Lexers for Dafny.
|
||||
|
||||
:copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from pygments.lexer import RegexLexer, include, bygroups
|
||||
from pygments.token import *
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import pygments.cmdline as _cmdline
|
||||
import pygments.lexer as _lexer
|
||||
import pygments.token as _token
|
||||
|
||||
|
||||
def main(args):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-l', dest='lexer', type=str)
|
||||
opts, rest = parser.parse_known_args(args[1:])
|
||||
if opts.lexer == 'dafny':
|
||||
args = [__file__, '-l', __file__ + ':DafnyLexer', '-x', *rest]
|
||||
_cmdline.main(args)
|
||||
|
||||
|
||||
class DafnyLexer(RegexLexer):
|
||||
"""
|
||||
For Dafny source code.
|
||||
"""
|
||||
|
||||
name = 'Dafny'
|
||||
aliases = ['dafny']
|
||||
filenames = ['*.dfy']
|
||||
mimetypes = []
|
||||
|
||||
flags = re.DOTALL | re.UNICODE | re.MULTILINE
|
||||
|
||||
valid_name = r'[\w_]+'
|
||||
|
||||
tokens = {
|
||||
'commentsandwhitespace': [
|
||||
(r'\s+', Text),
|
||||
(r'//.*?\n', Comment.Single),
|
||||
(r'/\*.*?\*/', Comment.Multiline),
|
||||
],
|
||||
'string': [
|
||||
(r'"(\\\\|\\"|[^"])*"', String.Double),
|
||||
(r"'(\\\\|\\'|[^'])*'", String.Single),
|
||||
],
|
||||
'root': [
|
||||
include('commentsandwhitespace'),
|
||||
(r'(:=)', Operator),
|
||||
(r'(\|)', Operator),
|
||||
(r'(;|::|:|\.\.|`)', Punctuation),
|
||||
(r'[{(\[,.\])}]', Punctuation),
|
||||
(r'(==|!=|<=|>=|=|&&|[-<>+*/%])', Operator),
|
||||
(r'(in)\b', Operator),
|
||||
(r'(this|old|print)\b', Name.Function.Magic),
|
||||
(r'(multiset)(\s*)(\()', bygroups(Name.Function.Magic, Text, Punctuation)),
|
||||
(r'(reads|modifies|ensures|requires|assert|assume|expect|invariant|decreases|constructor)\b', Keyword),
|
||||
(r'(if|then|else|while|returns|forall)\b', Keyword),
|
||||
(r'(function|method|predicate|lemma)(\s+\{[^\}]+\}\s+)(\w+)', bygroups(Keyword.Declaration, Text, Name.Function)),
|
||||
(r'(function|method|predicate|lemma)(\s+)(\w+)', bygroups(Keyword.Declaration, Text, Name.Function)),
|
||||
(r'(function|method|predicate|lemma)', Keyword.Declaration),
|
||||
(r'(trait|class|datatype)(\s+\{[^\}]+\}\s+)(\w+)', bygroups(Keyword.Declaration, Text, Name.Class)),
|
||||
(r'(trait|class|datatype)(\s+)(\w+)', bygroups(Keyword.Declaration, Text, Name.Class)),
|
||||
(r'(trait|class|datatype)', Keyword.Declaration),
|
||||
(r'(extends)(\s+)(\w+)', bygroups(Keyword, Text, Name.Class)),
|
||||
(r'(extends)', Keyword),
|
||||
(r'(var)(\s+)(\w+)', bygroups(Keyword.Declaration, Text, Name)), # actually Name.Variable.Instance, but that would be inconsistent, as we don't know this information on other occurrences
|
||||
(r'(var|ghost)\b', Keyword.Declaration),
|
||||
(r'(true|false)\b', Keyword.Constant),
|
||||
(r'(array|seq|set|multiset|int|nat|string|char)\b', Keyword.Type),
|
||||
(r'[0-9]+', Number.Integer),
|
||||
include('string'),
|
||||
|
||||
(valid_name, Name),
|
||||
]
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
|
BIN
report.pdf
Normal file
BIN
report.pdf
Normal file
Binary file not shown.
230
report.tex
Normal file
230
report.tex
Normal file
|
@ -0,0 +1,230 @@
|
|||
\documentclass[11pt,a4paper]{scrartcl}
|
||||
\usepackage{algorithm}
|
||||
\usepackage{algpseudocode}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[margin=2.25cm]{geometry}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{lmodern}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{float}
|
||||
\usepackage{tikz}
|
||||
\usepackage{listings}
|
||||
\usepackage{pgfplots}
|
||||
\pgfplotsset{compat=1.18}
|
||||
\usepackage{subcaption}
|
||||
\setlength{\parindent}{0cm}
|
||||
\setlength{\parskip}{0.3em}
|
||||
\hypersetup{pdfborder={0 0 0}}
|
||||
%\usepackage[nomessages]{fp} no easter eggs this time
|
||||
\usepackage{amsmath}
|
||||
\DeclareMathOperator*{\argmax}{arg\,max}
|
||||
\DeclareMathOperator*{\argmin}{arg\,min}
|
||||
\usepackage{minted}
|
||||
|
||||
\renewcommand{\MintedPygmentize}{python3 ./pygmentize.py}
|
||||
|
||||
\definecolor{codegreen}{rgb}{0,0.6,0}
|
||||
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
|
||||
\definecolor{codepurple}{rgb}{0.58,0,0.82}
|
||||
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
|
||||
|
||||
\lstdefinestyle{mystyle}{
|
||||
backgroundcolor=\color{backcolour},
|
||||
commentstyle=\color{codegreen},
|
||||
keywordstyle=\color{magenta},
|
||||
keywordstyle=[2]{\color{olive}},
|
||||
numberstyle=\tiny\color{codegray},
|
||||
stringstyle=\color{codepurple},
|
||||
basicstyle=\ttfamily\footnotesize,
|
||||
breakatwhitespace=false,
|
||||
breaklines=true,
|
||||
captionpos=b,
|
||||
keepspaces=true,
|
||||
numbers=left,
|
||||
numbersep=5pt,
|
||||
showspaces=false,
|
||||
showstringspaces=false,
|
||||
showtabs=false,
|
||||
tabsize=2,
|
||||
aboveskip=0.8em,
|
||||
belowcaptionskip=0.8em
|
||||
}
|
||||
\lstset{style=mystyle}
|
||||
|
||||
\geometry{left=2cm,right=2cm,top=2cm,bottom=3cm}
|
||||
\title{
|
||||
\vspace{-5ex}
|
||||
Assignment 1 -- Software Analysis \\\vspace{0.5cm}
|
||||
\Large Deductive verification with Dafny
|
||||
\vspace{-1ex}
|
||||
}
|
||||
\author{Claudio Maggioni}
|
||||
\date{\vspace{-3ex}}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
\tableofcontents
|
||||
|
||||
\section{Choice of Sorting Algorithm}
|
||||
|
||||
I decide to implement and verify the correctness of selection sort. The
|
||||
algorithm sorts a given list in place with average and worst-case complexity
|
||||
$O(n^2)$. It works by iteratively finding either the minimum or maximum element
|
||||
in the list, pushing it to respectively either the beginning or the end of the
|
||||
list, and subsequently running the next iteration over the remaining $n-1$
|
||||
elements.
|
||||
|
||||
For the sake of this assignment, I choose to implement and analyze the variant
|
||||
where the minimum element is computed. The pseudocode of selection sort is given
|
||||
in algorithm \ref{alg:sel}.
|
||||
|
||||
\begin{algorithm}
|
||||
\caption{Selection sort}\label{alg:sel}
|
||||
\begin{algorithmic}[1]
|
||||
\Require $a$ list of values
|
||||
\Ensure $a$ is sorted in-place
|
||||
\If{$a = \emptyset$}
|
||||
\State \Return
|
||||
\EndIf
|
||||
|
||||
\State $s \gets 0$
|
||||
\While{$s < |a|$}
|
||||
\State {$m \gets \argmin_x{a[x]}$ for $s \leq x < |a|$}
|
||||
\State {\textbf{swap} $a[x]$, $a[s]$}
|
||||
\State {$s \gets s + 1$}
|
||||
\EndWhile
|
||||
\end{algorithmic}
|
||||
\end{algorithm}
|
||||
|
||||
I choose this algorithm due to its procedural nature, since I feel more
|
||||
comfortable tackling loops instead of recursive calls when writing verification
|
||||
code as we already covered them in class.
|
||||
|
||||
Additionally, given the algorithm incrementally places a ever-growing portion of
|
||||
sorted elements at the beginning of the list as $s$ increases, finding a loop
|
||||
invariant for the \textbf{while} loop shown in the pseudocode should be simple
|
||||
as I can formalize this fact into a predicate.
|
||||
|
||||
\subsection{Dafny implementation}
|
||||
|
||||
To implement and verify the algorithm I use
|
||||
\href{https://dafny.org/}{\color{blue} Dafny}, a programming language that is
|
||||
verification-aware and equipped with a static program verifier.
|
||||
|
||||
I first write an implementation of the pseudocode, listed below.
|
||||
|
||||
\begin{listing}[H]
|
||||
\begin{minted}[linenos]{dafny}
|
||||
method SelectionSort(a: array<int>)
|
||||
{
|
||||
if (a.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var s := 0;
|
||||
|
||||
while (s < a.Length - 1)
|
||||
{
|
||||
var min: int := s;
|
||||
var i: int := s + 1;
|
||||
|
||||
while (i < a.Length)
|
||||
{
|
||||
if (a[i] < a[min]) {
|
||||
min := i;
|
||||
}
|
||||
i := i + 1;
|
||||
}
|
||||
|
||||
a[s], a[min] := a[min], a[s];
|
||||
s := s + 1;
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
\caption{Implementation of selection sort in Dafny}
|
||||
\label{lst:sel}
|
||||
\end{listing}
|
||||
|
||||
The implementation is only slightly different from the pseudocode. The biggest
|
||||
difference lies in the inner \textbf{while} loop at lines 14-20. This is just a
|
||||
procedural implementation of the assignment
|
||||
|
||||
$$m \gets \argmin_x{l[x]} \text{\hspace{1cm} for \hspace{1cm}} s \leq x < |l|$$
|
||||
|
||||
at line 6 of the pseudocode.
|
||||
|
||||
\section{Verification}
|
||||
|
||||
I now verify that the implementation in listing \ref{lst:sel} is correct by
|
||||
adding a specification to it, namely a method precondition, a method
|
||||
postcondition, and invariants and variants for the outer and inner loop.
|
||||
|
||||
\subsection{Method precondition and postcondition}
|
||||
|
||||
Aside the \mintinline{dafny}{array<int>} type declaration, no other condition is
|
||||
needed to constrain the input parameter \texttt{a} as a sorting algorithm should
|
||||
sort any list. Therefore, the method precondition is
|
||||
|
||||
\begin{center}
|
||||
\mintinline{dafny}{requires true}
|
||||
\end{center}
|
||||
|
||||
which can just be omitted.
|
||||
|
||||
Regarding postconditions, as the assignment description suggests, we need to
|
||||
verify that the method indeed sorts the values, while preserving the values in
|
||||
the list (i.e. without adding or deleting values).
|
||||
|
||||
We can define the sorted condition by saying that for any pair of monotonically
|
||||
increasing indices of $a$ the corresponding elements should be monotonically
|
||||
non-decreasing. This can be expressed with the predicate:
|
||||
|
||||
\begin{minted}{dafny}
|
||||
predicate sorted(s: seq<int>)
|
||||
{
|
||||
forall i,j: int :: 0 <= i < j < |s| ==> s[i] <= s[j]
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
According to advice given during lecture, we can express order-indifferent
|
||||
equality with the predicate:
|
||||
|
||||
\begin{minted}{dafny}
|
||||
predicate sameElements(a: seq<int>, b: seq<int>)
|
||||
{
|
||||
multiset(a) == multiset(b)
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
Therefore, the method signature including preconditions and postconditions
|
||||
is:
|
||||
|
||||
\begin{minted}{dafny}
|
||||
method SelectionSort(a: array<int>)
|
||||
modifies a
|
||||
ensures sorted(a[..])
|
||||
ensures sameElements(a[..], old(a[..]))
|
||||
\end{minted}
|
||||
|
||||
\subsection{Outer loop variant and invariant}
|
||||
{\color{red}TBD}
|
||||
|
||||
\subsection{Inner loop variant and invariant}
|
||||
{\color{red}TBD}
|
||||
|
||||
|
||||
\begin{verbatim}
|
||||
Did you introduce some that you then realized were not needed?
|
||||
|
||||
Any details of the algorithm’s implementation that you may have had to adjust to
|
||||
make specification or verification easier.
|
||||
> if list is empty
|
||||
|
||||
What were the hardest steps of the verification process?
|
||||
\end{verbatim}
|
||||
|
||||
\end{document}
|
||||
|
|
@ -1,11 +1,17 @@
|
|||
predicate sorted(s: seq<int>) {
|
||||
predicate sorted(s: seq<int>)
|
||||
{
|
||||
forall i,j: int :: 0 <= i < j < |s| ==> s[i] <= s[j]
|
||||
}
|
||||
|
||||
predicate sameElements(a: seq<int>, b: seq<int>)
|
||||
{
|
||||
multiset(a) == multiset(b)
|
||||
}
|
||||
|
||||
method SelectionSort(a: array<int>)
|
||||
modifies a
|
||||
ensures sorted(a[..]);
|
||||
ensures multiset(a[..]) == multiset(old(a[..]));
|
||||
ensures sorted(a[..])
|
||||
ensures sameElements(a[..], old(a[..]))
|
||||
{
|
||||
if (a.Length == 0) {
|
||||
return;
|
||||
|
@ -14,7 +20,7 @@ method SelectionSort(a: array<int>)
|
|||
var s := 0;
|
||||
|
||||
while (s < a.Length - 1)
|
||||
invariant multiset(a[..]) == multiset(old(a[..]));
|
||||
invariant sameElements(a[..], old(a[..]))
|
||||
invariant forall i,j: int :: 0 <= i < s <= j < a.Length ==> a[i] <= a[j]
|
||||
invariant s <= a.Length - 1
|
||||
invariant s >= 1 ==> sorted(a[0..s])
|
||||
|
@ -24,7 +30,7 @@ method SelectionSort(a: array<int>)
|
|||
var i: int := s + 1;
|
||||
|
||||
while i < a.Length
|
||||
invariant multiset(a[..]) == multiset(old(a[..]));
|
||||
invariant sameElements(a[..], old(a[..]))
|
||||
invariant s <= min < a.Length
|
||||
invariant s + 1 <= i <= a.Length
|
||||
invariant forall j: int :: s <= j < i ==> a[min] <= a[j]
|
||||
|
|
78
slowsort.dfy
78
slowsort.dfy
|
@ -1,78 +0,0 @@
|
|||
predicate sorted(s: seq<int>) {
|
||||
forall i,j: int :: 0 <= i < j < |s| ==> s[i] <= s[j]
|
||||
}
|
||||
|
||||
predicate sameElements(sa: seq<int>, sb: seq<int>) {
|
||||
multiset(sa) == multiset(sb)
|
||||
}
|
||||
|
||||
lemma SubSort(s: seq<int>, i: int, j: int)
|
||||
requires sorted(s)
|
||||
requires 0 <= i < j <= |s|
|
||||
ensures sorted(s[i..j])
|
||||
{
|
||||
}
|
||||
|
||||
method SlowSortHelper(a: array<int>, startIdx: int, endIdx: int)
|
||||
requires 0 <= startIdx <= endIdx < a.Length
|
||||
modifies a
|
||||
ensures a[..startIdx] == old(a[..startIdx])
|
||||
ensures endIdx < a.Length ==> a[endIdx + 1..] == old(a[endIdx + 1..])
|
||||
ensures sorted(a[startIdx..endIdx + 1])
|
||||
ensures multiset(a[startIdx..endIdx + 1]) == multiset(old(a[startIdx..endIdx + 1]))
|
||||
decreases endIdx - startIdx
|
||||
{
|
||||
if (endIdx == startIdx) {
|
||||
return;
|
||||
}
|
||||
|
||||
var middleIdx: int := (startIdx + endIdx) / 2;
|
||||
assert sameElements(a[startIdx..endIdx + 1], old(a[startIdx..endIdx + 1]));
|
||||
|
||||
SlowSortHelper(a, startIdx, middleIdx);
|
||||
SlowSortHelper(a, middleIdx + 1, endIdx);
|
||||
|
||||
assert 0 <= startIdx <= middleIdx < endIdx;
|
||||
assert a[..startIdx] == old(a[..startIdx]);
|
||||
assert endIdx < a.Length ==> a[endIdx + 1..] == old(a[endIdx + 1..]);
|
||||
|
||||
assert sorted(a[startIdx..middleIdx + 1]);
|
||||
assert sorted(a[middleIdx + 1..endIdx + 1]);
|
||||
|
||||
if (a[endIdx] < a[middleIdx]) {
|
||||
a[endIdx], a[middleIdx] := a[middleIdx], a[endIdx];
|
||||
}
|
||||
|
||||
assert a[middleIdx] <= a[endIdx];
|
||||
assert forall j: int :: startIdx <= j <= endIdx ==> a[j] <= a[endIdx];
|
||||
|
||||
SlowSortHelper(a, startIdx, endIdx - 1);
|
||||
|
||||
assert 0 <= startIdx <= middleIdx < endIdx;
|
||||
assert sorted(a[startIdx..endIdx]);
|
||||
assert multiset(a[startIdx..endIdx]) == multiset(old(a[startIdx..endIdx]));
|
||||
assert forall j: int :: startIdx <= j <= endIdx ==> old(a[j]) <= a[endIdx];
|
||||
|
||||
|
||||
// assert 0 <= startIdx < middleIdx + 1 <= endIdx;
|
||||
// assert sorted(a[startIdx..endIdx]);
|
||||
|
||||
// assert a[..startIdx] == old(a[..startIdx]);
|
||||
// assert endIdx < a.Length ==> a[endIdx + 1..] == old(a[endIdx + 1..]);
|
||||
|
||||
// assert sorted(a[startIdx..endIdx]);
|
||||
// assert middleIdx <= endIdx ==> a[middleIdx] < a[endIdx];
|
||||
|
||||
// assert forall j: int :: startIdx <= j < endIdx ==> a[j] <= a[endIdx];
|
||||
|
||||
}
|
||||
|
||||
method SlowSort(a: array<int>)
|
||||
modifies a
|
||||
ensures sorted(a[..])
|
||||
ensures sameElements(a[..], old(a[..]))
|
||||
{
|
||||
if (a.Length > 1) {
|
||||
SlowSortHelper(a, 0, a.Length - 1);
|
||||
}
|
||||
}
|
Reference in a new issue