\documentclass[12pt]{article}
\usepackage{fullpage,amsmath} 
%\usepackage{isolatin1} 
 
\usepackage[latin1]{inputenc} 
\usepackage[T1]{fontenc} 
 
 
\usepackage{hyperref} 
 
\usepackage{xspace} 
\usepackage[french]{babel} 


\usepackage{hyperref}

\usepackage{listings}




\def\lstlanguagefiles{lstlang1.sty,lstlang2.sty,lstlang3.sty}
\lstloadlanguages{[Objective]Caml}


\lstset{%
language=[Objective]Caml,%
flexiblecolumns=false,%
keywordstyle=\footnotesize\bfseries,%
commentstyle=\it,%
basicstyle=\footnotesize,%
showstringspaces=false,%
%extendedchar=true,%
escapeinside={(*@}{@*)}%
%numbers=left,%
%numberstyle=\tiny,%
%stepnumber=1,%
%numbersep=15pt%
}



\lstset{literate=%
  {=>}{{$\Rightarrow$}}1%
  {>->}{{$\rightarrowtail$}}2%
  {->}{{$\to$}}1%
  {~}{{$\neg$}}1}



\pagestyle{empty}  
\thispagestyle{empty}  
\sloppy  

 
\title{An exercise on proving programs with Why}  
 
 
\author{Jean-Christophe Filliâtre and Simão Melo de Sousa} 
 
\date{November 2010} 
\begin{document}  
 
\maketitle  
\tableofcontents 

\section{Introduction}

Programmer -- bien, c'est concevoir une solution informatique
adéquate, aussi systématique et efficace que possible à un problème
soluble concret donné.

Or, concevoir une telle solution n'est pas en générale une tache
triviale.  Une approche classique et rigoureuse voudrait que le
processus de conception soit, dans le cadre de la conception
d'algorithme, constitué des phases suivantes:

%\begin{itemize}
%\item Analyse du problème et de ces pré-requis
%\item Modélisation de la solution
%\item Codification de la solution dans un langage de programmation
%\item Analyse de performance
%\item Validation de la solution et de son code
%\end{itemize} 
%
%Si nous laissons le cadre général du génie logiciel et nous nous
% restreignons au cadre de la conception algorithmique, l'approche
% précédente peut se réécrire en

\begin{itemize}
\item Définition du problème et de ces contraintes
\item Conception algorithmique de la solution
\item Codification de la solution dans un langage de programmation
\item Analyse la complexité algorithmique de la solution proposée
\item Preuve de correction (totale) et de complétude.
\end{itemize}

La pratique habituelle de la programmation ignore néanmoins ou
minimise les activités liées aux deux dernière phases, de nature plus
formelles ou mathématiques, en les remplaçant au mieux par une mesure
expérimentale de performance et de validation par le biais d'une
activité de test ou d'exécution contrôlée.


%%% j'aime pas trop la formulation commentée qui suit, 
%%% mais l'idée est lá 

%--
Si la situation semble moins critique sur le premier de ces deux
derniers points, ce n'est pas encore vraiment le cas pour le deuxième.

%De fait, la formation en complexité algorithmique est maintenant
%répandue et l'analyse de la complexité dans le pire des cas est un
%bagage standard de tout informaticien. Reconnaitre une solution au
%comportement exponentielle est accessible à l'informaticien standard.
%L'analyse de performance, essentiellement dans le pire des cas,
%dispose aussi maintenant d'outils automatiques assez performants.
%--


Nous allons ainsi montrer par la pratique qu'il est possible
d'entreprendre l'approche rigoureuse jusqu'à son terme en s'attaquant
à la dernière des phases: la vérification de la correction et de la
complétude.


Si cette tâche est possible, elle n'est, bien entendu, pas forcément
aisée. La difficulté de cet exercice est clairement liée à la
complexité ou subtilité de la solution algorithmique/programmatique
proposée.

Une solution efficace se distancie en générale d'une solution
naturelle souvent simples mais inefficace. Comprendre et accepter sa
correction peux exiger une certaine réflexion. L'argumenter ne sera
donc pas forcement une tâche immédiate.



Tout comme en programmation où il y a un fossé entre la connaissance
du langage de programmation et la maîtrise de la conception de
programmes, si il y a une science de la preuve de programme, il existe
également tout un art, un savoir-faire, dans la construction d'une
preuve, surtout si l'on vise une preuve élégante ou aussi automatique
que possible.  Comprendre quelle spécification rendra la preuve plus
aisée requiert une certaine expérience.


Ce document s'attache donc à explorer un exemple de cette catégorie et
à introduire l'exercice de démonstration de correction et de
complétude assistée par ordinateur.


\section{Organisation du document}

\section{Définition du problème}

Le problème considéré ici a été proposé comme défi au concours de
programmation MIUP'2010 (Maratona Inter-Universitária de Programação,
épreuve nacional portugaise du circuit de concours ACM-ICPC) qui a eu
lieu a l'Université d'Évora - Portugal le 16 Octobre 2010.


The digit sum $d(x)$ of a natural number $x$ is the sum of its
digits. For instance $d(10043827) = 25$.
  
Given two natural numbers $y$ and $z$ such that $0<y < 90\,000$ and
$z$ has at most $10\, 000$ digits, compute the smallest natural number
$x$ such that $z<x$ and $d(x)=y$.

The input is organized in exactly two lines, each one with one
integer. The first one is $y$ and the second one is $z$.

The expected output consists in exactly one line and is the number $x$.  

\section{Résolution algorithmique}

\subsection{Quelques considérations initiales}

Analysons premièrement quelques particularités et faits remarquables
liés au problème.


La première remarque que l'on peut faire est que les limites du 
problème indiquent clairement  la solution à formuler doit être
efficace pour pouvoir traiter des données du problème  
en temps raisonnable. Énumérer les entiers plus grand que $z$ jusqu'à 
trouver le bon candidat n'est simplement pas raisonnable.

Étant donné un entier $a$, le plus petit entier $b$ tel que $d(b)=a$ a
comme longueur $\lceil \frac{a}{9}\rceil$ et est $i\overbrace{9 \ldots
  9}^{\lfloor \frac{a}{9}\rfloor}$ où $i = a\mod 9$.


Ainsi, dans le cas limite où $y$ est $89999$, le plus petit entier
ayant cette digit-sum a pour longueur $\lceil \frac{89999}{9}\rceil $,
soit 10\,000, et est égal à $8\overbrace{9 \ldots 9}^{9\,999}$.

Une autre remarque intéressante est la suivante. S'il est possible de
trouver un nombre $b$ de taille $c$ dont la digit-sum est $a$, il est
possible de trouver un nombre de taille $c+1$ ayant la même digit-sum.
Par exemple, il suffit de rajouter un $0$ à droite de $b$, ou alors de
baisser d'une unité n'importe quel chiffre non nul de $b$ et
d'intercaler le chiffre $1$ dans n'importe quelle position dans $b$,
etc.


Ainsi, étant donnée les limites du problème, il est clair que aucun
des nombres à calculer aura plus de $10\,001$ chiffres, vu qu'il est
possible de trouver un nombre $x$ avec exactement $10\,0001$ chiffres
tel que $d(x)=y$ quelque soit l'entier non nul $y$ inférieur
strictement à $90000$.

Par exemple, si $y= 99$, alors on peut choisir $x=1\overbrace{0\ldots
  0}^{9\,989}\overbrace{9\ldots 9}^{10}8$. En effet $d(x)=y=99$ et $x$
a $10\,001$ chiffres.  Un autre exemple peut être $y=89\,999$. Alors
on peut choisir $x=18\overbrace{9 \ldots 9}^{9\,998}$. Signalons
néanmoins que si nous devions choisir un entier plus grand que
$8\overbrace{9 \ldots 9}^{9\,999}$ nous aurions pu choisir
$x=98\overbrace{9\ldots 9}^{9\,998}$ et rester dans les limites des
$10\,000$ chiffres.


Ces considérations nous permettent de fixer une borne supérieure
raisonnable à la taille de l'entier à calculer $x$ connaissant $y$ et
$z$.  Considérons $u=\lceil \frac{y}{9} \rceil$ le nombre de chiffres
du plus petit entier dont la digit-sum est $y$ et $v$ le nombre de
chiffre de $z$.

Si $u$ est strictement plus grand que $v$ alors la borne est
nécessairement $u$ (et dans ce cas on sait même quelle est la valeur
de $x$), dans le cas contraire la taille de $x$ sera au mieux $v$ et
au plus $v+1$.  Car on se sait pas a priori s'il existe des nombres de
taille $v$ plus grand de $z$ qui ont $y$ comme digit-sum, mais
certainement que l'on arrive à en trouver avec $v+1$ chiffres.

 
\subsection{Représentation des données}




Le premier choix à considérer au niveau de la solution est celle de la
représentation des données que la solution manipulera. Les nombres
manipulés sont potentiellement très grand, et la solution aura à
manipuler en particulier les chiffres de ces nombres. Ainsi il est
assez naturel de choisir représenter les entiers manipulés (ici $x$)
par la séquence de ces chiffres.  Comme nous allons le voir, la
solution choisie devra parcourir le nombre du chiffre de poids le moins
significatif au chiffre de poids le plus significatif. Pour cela il
sera plus convenable représenter les chiffre dans l'ordre inverse dans
le tableau. Ainsi le parcours se fera ainsi de gauche a droite dans le
tableau.



% voir si cette note est utile
Il pourra être pertinent garantir que la représentation des entiers
est cohérente. C'est à dire que les éléments du tableau sont des
entiers entre $0$ et $9$, qu'à gauche du premier chiffre il n'y a, le
cas échéant, que des $0$ (dans le cas de la représentation des chiffre
en ordre inverse, à droite du dernier chiffre représentatif il n'y a
que des $0$).  Nous reviendrons sur ce point le moment venu.



\subsection{L'algorithme}


Considérons que la solution $x$ soit constitué des chiffre $x_m\ldots
x_1x_0$ et que $z$ soit constitué des chiffres $z_m\ldots z_1z_0$ (les
chiffres à gauche pouvant être des $0$ si nécessaire).

Comme $x$ est le premier entier qui suit $z$ (suivant l'ordre
croissant) et qui a pour digit-sum $y$, remarquons qu'il doit exister
un indice $d$ tel que qu'à gauche de cet indice $x$ coïncide avec $z$
($\forall i, d<i\leq m \implies x_i=z_i$) et que ce qui reste de $x$ à
droite (d inclus) soit un nombre plus grand strictement que ce qui
reste de $z$ à droite de $d$ ($x_d\ldots x_0 > z_d\ldots z_0$).
 
Dans ce cas notons aussi que $\Sigma_{i=d+1}^m x_i=\Sigma_{i=d+1}^m z_i$
(soit $a$ cette valeur).  Soient $b_x=\Sigma_{i=0}^d x_i$ et $b_z =
\Sigma_{i=0}^d z_i$, nous avons $b_x>b_z$. Il est facile de voir que
$y=a+b_x$ et $d(z)=a+b_z$.

Trouver le plus petit $x$ c'est donc, partant de $z$, trouver un
indice $d$ plus à droite possible dans $z$ tel qu'il soit possible de
trouver la plus petite augmentation de $z_d$ ($x_d$) qui rende
possible l'expression d'un nombre $x_{d-1}\ldots x_0$ ayant comme
digit-sum $y-a-x_d$ (c'est à dire, $\Sigma_{i=0}^{d-1}x_i = y-a-x_d$).


Pour cela remarquons qu'il nous suffit de parcourir $z$ de $z_0$ à
$z_m$ et que pour chacun des $z_i$ essayer (dans l'ordre) les différents chiffres qui suivent $z_i$.
Une tentative réussi si l'on réussi à exprimer avec $i-1$ chiffres le plus petit nombre qui complète la digit-sum.
Si aucune tentative réussi alors $z_i$ n'est pas le bon chiffre ($i$ n'est pas $d$), il faut tenter $z_{i+1}$. 



\begin{lstlisting}

(*reading the input*)
let ys = Sys.argv.(1)
let zs = Sys.argv.(2)

(*n is the size of z*)
let n = String.length zs
let y = int_of_string ys

(* bound for the size of x*)
let max_digits = 1 + max n (y / 9)

(* x is initialized as z (with the digit in reverse order)*)
let x = Array.create max_digits 0
let () = 
  for i = 0 to n - 1 do x.(n - 1 - i) <- Char.code zs.[i] - Char.code '0' done

let () =
  (* let s be the digit-sum of x / z*)
  let s = ref 0 in
  for i = 0 to max_digits - 1 do s := !s + x.(i) done;
  
  (* we try for each digit, staring from the rightmost digit*)
  for d = 0 to max_digits - 1 do
    (* s is the sum of digits d..n-1 *)
    (* solution with digits > d intacts, and digit d increased by 1 or more *)
    for c = x.(d) + 1 to 9 do
      let delta = y - !s - c + x.(d) in
      if 0 <= delta && delta <= 9 * d then 
      begin
      	x.(d) <- c;
		let k = delta / 9 in
		for i = 0 to d-1 do 
	  	  x.(i) <- if i < k then 9 else if i = k then delta mod 9 else 0
		done;
		for i = max d (n-1) downto 0 do Format.printf "%d" x.(i) done;
		Format.printf "@.";
		exit 0
      end
    done;
    s := !s - x.(d)
  done
\end{lstlisting}

\section{Considérations sur la complexité de la solution}
\section{Considérations sur la vérification formelle de la solution}
\section{Un courte introduction à la preuve de programmes avec l'outils Why}
\section{Preuve incrémentale de correction et de complétude de la solution}
\section{Conclusion}
\end{document}  
 
%%% Local Variables: 
%%% mode: latex 
%%% ispell-local-dictionary: "francais" 
%%% End: 
 
% LocalWords:  BNF q Orl\'{e}ans
