-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathch09.tex
More file actions
executable file
·1747 lines (1597 loc) · 80.1 KB
/
Copy pathch09.tex
File metadata and controls
executable file
·1747 lines (1597 loc) · 80.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\chapter{Sorting}
\label{ch:sorting}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "book"
%%% End:
The task of sorting records into a desired order
(alphabetical order, for example, or chronological order,
or numeric order by an identifying key)
is one of the most studied problems in computing.
Solutions abound,
and a good one can save an enormous amount of time.
A sorting operator that is twice as fast
as a slower operator when rearranging a few hundred records
will typically be many times faster than the slow operator
for thousands of records and thousands of times faster
when there are millions of records to be arranged.
Data archives with thousands or millions of records
are common, and that makes the sorting process important.\footnote{The
difference between using a fast sorting operator and a slow one
can be dramatic.
\index{sorting!bubble sort vs quicksort}\label{bubble-vs-quicksort-example}Some
years ago, one of the authors helped the US Forest Service
figure out why their central computing system
was bogged down.
The culprit turned out to be about two dozen lines
of code in their road design system.
Those lines defined a slow sorting method
known as bubble sort. Replacing it with a fast sorting
method known as quicksort cut the amount of computation
attributable to the road design system from over a hundred
hours a week on each of eight mainframe computers to a few hours
a week on one.}
This chapter will discuss two sorting operators that
deliver the same results but differ
greatly in the amount of time they take to do the job.
Since they deliver the same results,
they are equivalent operators in a mathematical sense,
but they are vastly different computationally.
We will discuss both the computational differences
and the \index{operators, equivalence of}
\index{equivalence!of operators}mathematical equivalence.
Deriving the resource requirements of an operator from
the equations that define it is
similar to deriving other properties.
Previously, we have been mostly concerned with meeting
expectations with regard to the form of the results
of an operation, not the time it takes to deliver those results.
Now we will discuss engineering choices that affect the usefulness of
software as the amount of data increases.
Engineering requires not only producing the expected
results but also dealing with scale in effective ways.
\section{Insertion-Sort}
\label{sec:insertion-sort}
To focus our attention on the essentials of
arranging records in order by a key, we will
assume that the entire content of a record
resides in its key.
In practice, there is usually a lot of information
in a record, not just an identifying key,
but the process of arranging the records
in order by key is the same, regardless
of what information is associated with each key.
To simplify the discussion,
we will use numbers for keys
and discuss operators that rearrange lists
of numbers into increasing order.
For example, if the operand of the sorting
operator were the list \textsf{[5 9 4 6 5 2]},
the operator would deliver the list \textsf{[2 4 5 5 6 9]},
which contains the same numbers, but arranged so
that the smallest one comes first, increasing up the
line to the largest at the end.
In practice, keys need not be numbers,
but they do need to be comparable
to determine an ordering (alphabetical, chronological, and so on).
If the keys aren't numbers,
then the numeric comparisons
($<$, $>$) in our discussion would be replaced by
other operators designed to compare
keys to see which one precedes the other
in the desired ordering.
The sorting method is the same, regardless
of how keys are compared.
Suppose someone has defined an operator that,
given a list of numbers that has
already been arranged into increasing order,
along with a new number to put in the list,
delivers a list with the new number inserted
in a place that preserves the ordering.
If we call the operator \textsf{insert}, then
the formula \textsf{(insert 8 [2 4 5 5 6 9])} would
deliver \textsf{[2 4 5 5 6 8 9]}.
What are some equations that we would expect
the \textsf{insert} operator to satisfy?
If the list were empty, then the operator
would deliver a list whose only element would
be the number
\index{equation, by name!\{ins0\}, \{ins1\}, \{ins2\}}\index{axiom, by name!\{ins0\}, \{ins1\}, \{ins2\}}to be inserted in the list.
\vspace{2mm}\\
%\begin{quote}
\hspace*{5mm}\textsf{(insert $x$ nil) $=$ (cons $x$ nil)} ~~~~ \{\emph{ins0}\}
\vspace{2mm}
%\end{quote}
If the number to be inserted is less than or equal to the
first number in the list, the operator could simply
insert the number at the beginning of the list.
\vspace{2mm}\\
%\begin{quote}
\hspace*{5mm}\textsf{(insert $x$ (cons $x_1$ $xs$)) $=$ (cons $x$ (cons $x_1$ $xs$))} if $x \le x_1$ ~~~~\{\emph{ins1}\}
\vspace{2mm}
%\end{quote}
If the number to be inserted is greater than the first number
in the list, we don't know where it will go in the list,
but we do know it won't come first.
The first number in the list will still be the first number
after the new one is inserted somewhere down the line.
If we trust the operator to put it in the right place,
we can make a new list starting with the same first number
and then let the insertion operator put the new number
where it belongs among the numbers after the first one.
That leads to an inductive equation for the operator
\index{axiom, by name!\{ins0\}, \{ins1\}, \{ins2\}}\index{equation, by name!\{ins0\}, \{ins1\}, \{ins2\}}\textsf{insert}.
\vspace{2mm}\\
%\begin{quote}
\hspace*{5mm}\textsf{(insert $x$ (cons $x_1$ $xs$)) $=$ (cons $x_1$ (insert $x$ $xs$))} if $x > x_1$ ~~~~ \{\emph{ins2}\}
\vspace{2mm}
%\end{quote}
The equations \{\emph{ins0}\}, \{\emph{ins1}\}, and \{\emph{ins2}\}
are comprehensive, consistent, and computational,
so they define the operator \textsf{insert}
(three C's, figure~\ref{fig:inductive-def-keys}, page \pageref{fig:inductive-def-keys}).
The following definition in ACL2 transliterates the three equations
but consolidates \{\emph{ins0}\} and \{\emph{ins1}\} into one equation
by observing that the right-hand sides of both equations
are the same formula: \textsf{(cons $x$ $s$)}, where $s$ is the second operand
on the left-hand side
(which is \textsf{nil} in equation \{\emph{ins0}\} and
\textsf{(cons $x_1$ $xs$)} in equation \{\emph{ins1}\}).
\label{defun:insert-isort}\index{axiom, by name!\{ins0\}, \{ins1\}, \{ins2\}}\index{equation, by name!\{ins0\}, \{ins1\}, \{ins2\}}
\index{operator, by name!insert (in order)}\seeonlyindex{insert, in order}{operator}
\index{sorting!insert (in order)}
\begin{code}
\begin{verbatim}
(defun insert (x xs) ; assume x1 <= x2 <= x3 ...
(if (and (consp xs) (> x (first xs)))
(cons (first xs) (insert x (rest xs))) ; {ins2}
(cons x xs))) ; {ins1}
\end{verbatim}
\end{code}
Now suppose someone has defined a sorting operator called \textsf{isort}
(insertion-sort).
Empty lists and one-element lists already have their
elements in order, by default.
Therefore, the formula \textsf{(isort nil}) would deliver \textsf{nil}
and the formula \textsf{(isort (cons $x$ nil))} would deliver
\textsf{(cons $x$ nil)}.
That is, \textsf{(isort $xs$) $=$ $xs$} when $xs$ has one element or none.
\begin{center}
\label{eq:isrt0}\label{eq:isrt1}
\index{equation, by name!\{isrt0\}, \{isrt1\}, \{isrt2\}}\index{axiom, by name!\{ins0\}, \{ins1\}, \{ins2\}}
\begin{tabular}{ll}
\textsf{(isort nil) $=$ nil} & \{\emph{isrt0}\} \\
\textsf{(isort (cons $x$ nil)) $=$ (cons $x$ nil)} & \{\emph{isrt1}\} \\
\end{tabular}
\end{center}
If the list to be sorted has two or more elements,
it has the form \textsf{(cons $x_1$ (cons $x_2$ $xs$))}
(\{consp\} axiom, page \pageref{consp-axiom}).
If the \textsf{isort} operator works properly,
the formula \textsf{(isort (cons $x_2$ $xs$))} would be
a list made up of the number $x_2$ and all the numbers in the list $xs$
taken together and
arranged in increasing order.
Given that list, the \textsf{insert} operator can put the number $x_1$ in
the right place, producing a list made up of all the
numbers in the original list rearranged into increasing order.
\begin{center}
\label{eq:isrt2}
\begin{tabular}{ll}
\textsf{(isort(cons $x_1$ (cons $x_2$ $xs$))) $=$ (insert $x_1$ (isort(cons $x_2$ $xs$)))} & \{\emph{isrt2}\} \\
\end{tabular}
\end{center}
The equations \{\emph{isrt0}\}, \{\emph{isrt1}\}, and \{\emph{isrt2}\}
are comprehensive (the operand is either empty, has one element, or
has more than one element) and consistent (no overlapping cases).
They are computational because the operand of \textsf{isort}
on the right-hand side of the inductive equation
\{\emph{isrt2}\}, namely \textsf{(cons $x_2$ $xs$)},
has fewer elements than the operand on the left-hand side,
which is \textsf{(cons $x_1$ (cons $x_2$ $xs$))}.
Therefore, the operand on the right-hand side is
closer than the operand on the left-hand side to a list
of the form \textsf{(cons $x$ nil)}, which is
the operand on the left-hand side of the
noninductive equation \{\emph{isrt1}\}.
Therefore, the equations satisfy the three C's requirements %'
(figure~\ref{fig:inductive-def-keys}, page \pageref{fig:inductive-def-keys}),
which means that they define the operator \textsf{isort}.
The three equations can be consolidated into two because
\{\emph{isrt0}\} and \{\emph{isrt1}\}
are both the same equation: \textsf{(isort $xs$)} $=$ $xs$,
where $xs$ is \textsf{nil} in equation \{\emph{isrt0}\}
and \textsf{(cons $x$ nil)} in equation \{\emph{isrt1}\}.
\label{defun:isort}\index{axiom, by name!\{isrt0\}, \{isrt1\}, \{isrt2\}}\index{equation, by name!\{isrt0\}, \{isrt1\}, \{isrt2\}}\index{operator, by name!isort (insertion-sort)}\seeonlyindex{isort}{operator}\index{insertion-sort}\index{sorting!insertion-sort (isort)}
\begin{code}
\begin{verbatim}
(defun isort (xs)
(if (consp (rest xs)) ; xs has 2 or more elements?
(insert (first xs) (isort (rest xs))) ; {isrt2}
xs)) ; (len xs) <= 1 ; {isrt1}
\end{verbatim}
\end{code}
We expect the insertion-sort operator to preserve
the number of elements in its operand and to
neither add nor drop values from the list.
Theorems stating these properties would be
similar to the corresponding theorems for
the multiplex and demultiplex operators discussed
in chapter \ref{ch:mux-dmx}.
The theorem on preservation of values is
stated as a
\index{Boolean!equivalence ($\leftrightarrow$, iff)}\index{operator, by name!iff (Boolean equivalence)}\index{operator, logic!Boolean equivalence ($\leftrightarrow$, iff)}\index{equivalence!Boolean ($\leftrightarrow$, iff)}\index{iff (\emph{see also} operator)}Boolean
equivalence
and uses the \textsf{occurs-in }predicate
(box \ref{aside:mux-val-thm}, page \pageref{aside:mux-val-thm}) %(page \pageref{def:occurs-in})
for determining
whether or not a value occurs in a list
(box~\ref{aside:mux-val-thm}, page \pageref{aside:mux-val-thm}, and
exercise \ref{ex:mul-val-thm}, page \pageref{ex:mul-val-thm}).\footnote{Preservation
of length and values does not guarantee
that the operator delivers the correct result.
For example, the lists \textsf{[1 1 2]} and \textsf{[1 2 2]} have the
same length and the same values
but \textsf{(isort [1 1 2]) $\neq$ [1 2 2]}.
The sorted list must be a permutation of the original list.
The permutation property is not much harder
to prove than length and value preservation,
but it does require a definition of permutation
(exercise~\ref{ex:permp-isort}, page~\pageref{ex:permp-isort}).}
\label{defthm:isort-len}
\label{defthm:isort-val}
\index{theorem, by name!\{isort-len\}, \{isort-ord\}, \{isort-val\}}
\begin{code}
\begin{verbatim}
(defthm isort-len-thm
(= (len (isort xs)) (len xs)))
(defthm isort-val-thm
(iff (occurs-in e xs)
(occurs-in e (isort xs))))
\end{verbatim}
\end{code}
We also expect the numbers in the list
that the \textsf{isort} operator
delivers to be in increasing order.
To state that property, we need a predicate
to distinguish between lists containing numbers in increasing order
and lists that have some numbers out of order.
A list with only one element or none is automatically in order.
A list with two or more elements is in order
if its first element doesn't exceed its second and if
all the elements after the first element are in order.
These observations lead to the following
ACL2 definition of a predicate \textsf{up},
which is true when its operand is a list
of numbers that is in increasing order and false otherwise:
%%%\hspace{1cm} (up(cons $x_1$ (cons $x2$ $xs$))) = ($x_1 \le x_2$) $\wedge$ (up(cons $x_2$ $xs$))
%%%\hfill \{\emph{up2}\}
\index{compare!numbers ($<$, $<=$, $=$, $>=$, $>$)}
\index{predicate!numeric order ($<$, $<=$, $=$, $>=$, $>$)}
\index{order!numeric ($<$, $<=$, $=$, $>=$, $>$)}
\index{operator!numeric order ($<$, $<=$, $=$, $>=$, $>$)}
\index{number!order ($<$, $<=$, $=$, $>=$, $>$)}
\seeonlyindex{less or equal ($<=$)}{predicate}
\label{defun:up}
\index{operator, by name!up (\emph{see} predicate)}
\index{predicate, by name!up (increasing order)}
\seeonlyindex{up (increasing order)}{predicate}
\begin{code}
\begin{verbatim}
(defun up (xs) ; (up[x1 x2 x3 ...]): x1 <= x2 <= x3 ...
(or (not (consp (rest xs))) ; (len xs) <= 1
(and (<= (first xs) (second xs)) ; x1 <= x2
(up (rest xs))))) ; x2 <= x3 <= x4 ...
\end{verbatim}
\end{code}
Our expectations about ordering in the list that the \textsf{isort} operator
delivers can be expressed formally in ACL2 in terms of the \textsf{up} predicate.
ACL2 succeeds without assistance in proving
all three properties: length preservation,
value preservation, and ordering.
The proof can induct on the length
of the list supplied as the operand of \textsf{isort}.
\label{defthm:isort-ord-thm}
\index{sorting!insertion-sort (isort)}\index{theorem!insertion-sort (isort)}
\index{theorem, by name!\{isort-len\}, \{isort-ord\}, \{isort-val\}}
\begin{code}
\begin{verbatim}
(defthm isort-ord-thm
(up (isort xs)))
\end{verbatim}
\end{code}
Later, we will analyze the computational behavior of the \textsf{isort} operator
and will find that it is extremely slow for long lists.
The next section begins a discussion of a sorting operator
that is fast, even on long lists.
\begin{exercises}
\exer {Do a paper-and-pencil proof that the \textsf{isort} operator
preserves the values in its operand
(\textsf{isort-val-thm}, above).}%page \pageref{defthm:isort-val}).}
\exer {Do a paper-and-pencil proof that the \textsf{isort} operator
preserves the length of its operand
(\textsf{isort-len-thm}, page \pageref{defthm:isort-len}).
You may assume theorem \{\emph{insert-len}\}: \textsf{(len(insert $x$ $xs$)) $=$ $1$ $+$ (len xs)}.}
\exer {Do a paper-and-pencil proof that the \textsf{isort} operator
delivers a list arranged in increasing order
(\textsf{isort-ord-thm}, page \pageref{defthm:isort-ord-thm}).}
\exer {\label{ex:ct}%
Suppose \textsf{(ct $x$ $xs$)} delivers a count
equal to the number of times
the value $x$ occurs in the list $xs$.
\subexer {What value should the operator \textsf{ct} deliver if $xs$ has no elements?}
\subexer {State a theorem in ACL2 that expresses the
number of occurrences of a value $x$ in the list \textsf{(cons $x$ $xs$)}
in terms of the number of occurrences of $x$ in $xs$.}
\subexer {State a theorem in ACL2 that expresses the
number of occurrences of a value $x$ in the list \textsf{(cons $y$ $xs$)}
when $y$ is not equal to $x$.}
\subexer {Use the above observations to define the operator \textsf{ct}.}
}
\begin{code}
\begin{verbatim}
(defun ct (x xs) ; number of occurrences of x in xs
...)
\end{verbatim}
\end{code}
\exer {The \index{operator, by name!del (delete list element)}
\seeonlyindex{del (delete list element)}{operator}\textsf{del} operator
deletes an occurrence of $x$ in $xs$
if $x$ occurs in $xs$.
\label{defun:del}}
\begin{code}
\begin{verbatim}
(defun del (x xs)
(if (not(consp xs))
nil
(if (equal x (first xs))
(rest xs)
(cons (first xs) (del x (rest xs))))))
\end{verbatim}
\end{code}
\begin{quote}
Define a theorem in ACL2 that
expresses the number of occurrences of $x$ in \textsf{(del $x$ $xs$)}
in terms of the number of occurrences of $x$ in $xs$.
Refer to the operator \textsf{ct} (exercise~\ref{ex:ct}).\\
\emph{Hint}: Be careful to take into account the possibility that
$x$ does not occur in $xs$.
\end{quote}
\exer {\label{ex:permp-isort}%
The predicate
\index{predicate, by name!permp (permutation)}\index{operator, by name!permp (\emph{see} predicate)}\seeonlyindex{permp}{predicate}\textsf{permp},
defined as follows, is true if its second operand
is a permutation of its first operand and false otherwise:\footnote{The
predicate \textsf{occurs-in} is defined in
box~\ref{aside:mux-val-thm} (page \pageref{aside:mux-val-thm}).}}
\label{defun:permp}
\begin{code}
\begin{verbatim}
(defun permp (xs ys)
(if (not(consp xs))
(not(consp ys))
(and (occurs-in (first xs) ys)
(permp (rest xs) (del (first xs) ys)))))
\end{verbatim}
\end{code}
\begin{quote}
Define a theorem in ACL2 stating that \textsf{(isort $xs$)} is a
permutation of $xs$, and
get ACL2 to prove the theorem.
Since the theorem will refer to the predicate \textsf{permp}
and \textsf{permp} refers to the operators \textsf{occurs-in} and \textsf{del},
ACL2 will need to admit definitions of those operators
to its logic before it can attempt to prove the theorem.
\end{quote}
\end{exercises}
\section{Order-Preserving Merge}
\label{sec:mrg}
The multiplex operator (\textsf{mux}, section \ref{sec:mux})
combines two lists into one in a perfect shuffle.
The merge operator is another way to combine lists.
It combines ordered lists
in a way that preserves order.
If both lists contain numbers arranged in increasing order,
the merge operator \textsf{mrg}
will combine the two lists
into one in which all of the elements from both lists
are arranged in increasing order.
Two of the equations for \textsf{mrg}
specify the results when one of the lists is empty.
The equations for \textsf{mrg} in those cases are the same as
the corresponding equations for the multiplex operator
(\{\emph{mux0x}\} and \{\emph{mux0y}\}, page \pageref{def:mux}).
\begin{center}\index{equation, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}\index{axiom, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}
\begin{tabular}{ll}
\textsf{(mrg nil $ys$) $=$ $ys$} & \{\emph{mg0}\} \\
\textsf{(mrg $xs$ nil) $=$ $xs$} & \{\emph{mg1}\} \\
\end{tabular}
\end{center}
When both lists are nonempty, the merged list will
start with either the first element of the first operand
or the first element of the second operand,
depending on which is smaller.
The remaining elements in the merged list come from
merging what's left of the list whose first element is smaller
with all of the elements in the other list.
That divides the nonempty case into two
subcases, one when the first operand starts with a smaller number
than the second operand
and the other when the second operand begins with the smaller number.
\begin{center}\index{equation, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}\index{axiom, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}
\begin{tabular}{ll}
\textsf{(mrg (cons $x$ $xs$) (cons $y$ $ys$)) $=$ (cons $x$ (mrg $xs$ (cons $y$ $ys$)))} if $x \le y$ & \{\emph{mgx}\} \\
\textsf{(mrg (cons $x$ $xs$) (cons $y$ $ys$)) $=$ (cons $y$ (mrg (cons $x$ $xs$) $ys$))} if $x > y$ & \{\emph{mgy}\} \\
\end{tabular}
\end{center}
The four equations, taken as a whole, are comprehensive
because either one list is empty or the other one is empty
or both lists are nonempty,
in which case the first element of one of them
is less than or equal to the first element of the other.
They are consistent because, as with the \textsf{mux} operator,
the only overlapping situation is when
both lists are empty, in which case equation \{\emph{mg0}\}
delivers the same result as equation \{\emph{mg1}\}.
Two of the equations (\{\emph{mgx}\} and \{\emph{mgy}\}) are inductive,
so we need to make sure they are computational.
In both equations, there are fewer elements in the operands
on the right-hand side than on the left-hand side.
That is, the total number of elements to be merged
on the right-hand side of the inductive equation \{\emph{mgx}\}
is less than the total on the left-hand side.
That makes the operands on the right-hand side closer to
a noninductive case than the operands on the left-hand side.
Therefore, the equations are computational.
That covers the three C's
(figure~\ref{fig:inductive-def-keys}, page \pageref{fig:inductive-def-keys}),
so we can take the equations as axioms that define the \textsf{mrg} operator.
A formal definition in ACL2 can be constructed from
the equations \{\emph{mg0}\}, \{\emph{mg1}\}, \{\emph{mgx}\}, and \{\emph{mgy}\}.
However, ACL2 needs some help in finding an induction scheme
to prove that the equations lead to a terminating computation.
We reasoned that the merge equations are computational
because the total number of elements in the two operands
is smaller on the right-hand side of the inductive equations
than on the left-hand side.
The \textsf{declare} directive in the following ACL2 definition suggests
basing the proof by induction on this total,
and that suggestion is enough to get the mechanized logic on the right track.
\begin{code}\label{defun:mrg}\index{axiom, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}\index{equation, by name!\{mg0\}, \{mg1\}, \{mgx\}, \{mgy\}}\index{operator, by name!mrg (ordered merge)}\seeonlyindex{mrg (ordered merge)}{operator}\index{sorting!merge, ordered (mrg)}\index{merge, ordered (mrg)}\index{defun!induction hint}\index{definition!defun hint}\index{directive!induction hint}
\begin{verbatim}
(defun mrg (xs ys)
(declare (xargs :measure (+ (len xs) (len ys)))); induction scheme
(if (and (consp xs) (consp ys))
(let* ((x (first xs)) (y (first ys)))
(if (<= x y)
(cons x (mrg (rest xs) ys)) ; {mgx}
(cons y (mrg xs (rest ys))))) ; {mgy}
(if (not (consp ys))
xs ; ys is empty ; {mg0}
ys))) ; xs is empty ; {mg1}
\end{verbatim}
\end{code}
The \textsf{mrg} operator preserves the total length of its operands,
and it neither adds nor drops any of the values in those operands.
The equations specifying these properties are like those of the
corresponding properties of the \textsf{mux} operator, namely,
the mux-length theorem (page \pageref{mux-length-thm}) and the
mux-val theorem (page \pageref{thm:mux-val}).\footnote{As
with the theorems about
\textsf{mux}, \textsf{dmx}, and \textsf{isort}, length and value preservation
do not guarantee that \textsf{mrg} delivers a correct result.
The result must be a permutation
of the elements of the lists to be merged,
which is a more restrictive property than
preservation of length and values
(see exercise~\ref{ex:permp-isort}, page~\pageref{ex:permp-isort}).}
The \textsf{mrg} operator also preserves order.
If the numbers in both operands are in increasing order,
the numbers in the list it delivers are in increasing order.
A formal statement of this property can employ the same order predicate
(\textsf{up}, page \pageref{defun:up}) that was used to specify a
similar property of the \textsf{isort} operator.
However, in the case of the \textsf{mrg} operator,
the property is guaranteed only under the condition
that both operands are already in order,
so the property is stated as an implication.
\label{defthm:mrg-ord}\index{theorem, by name!\{mrg-length\}, \{mrg-ord\}, \{mrg-val\}}
\index{theorem!merge, ordered}
\begin{code}
\begin{verbatim}
(defthm mrg-ord-thm
(implies (and (up xs) (up ys))
(up (mrg xs ys))))
\end{verbatim}
\end{code}
ACL2 can verify this property without assistance.
The induction scheme for proving that
the \textsf{mrg} operator terminates,
namely, induction on the total number of elements in the operands,
also works in the proof of the merge order theorem.
A paper-and-pencil proof could follow the same strategy.
\begin{exercises}
\exer {\label{ex:mrg-length-thm}%
\index{theorem, by name!\{mrg-length\}, \{mrg-ord\}, \{mrg-val\}}Using the mux-length theorem (page \pageref{mux-length-thm})
as a model, make a formal ACL2 statement of the mrg-length theorem.}
\exer {Do a paper-and-pencil proof of the mrg-length theorem
of exercise \ref{ex:mrg-length-thm}.}
\exer {\label{ex:mrg-ord-thm}%
Do a paper-and-pencil proof of \textsf{mrg-ord-thm} (see \textsf{defthm}, above).}%(page \pageref{defthm:mrg-ord}).}
\exer {\label{ex:mrg-val-thm}%
\index{theorem, by name!\{mrg-length\}, \{mrg-ord\}, \{mrg-val\}}Using the mux-val theorem (page \pageref{thm:mux-val})
as a model, make a formal ACL2 statement of the mrg-val theorem.}
\exer {Do a paper-and-pencil proof of the mrg-val theorem of exercise \ref{ex:mrg-val-thm}.}
\end{exercises}
\section{Merge-Sort}
\label{sec:msort}
We can use the \textsf{mrg} operator (page \pageref{defun:mrg}),
together with the demultiplexer (\textsf{dmx}, page \pageref{dmx-defun}),
to define a sorting operator \textsf{msort} (merge-sort) that is fast for long lists.
The \textsf{msort} operator uses \textsf{dmx} to split the list into two parts,
sorts each part inductively into increasing order, and finally
uses the \textsf{mrg} operator to combine the sorted parts into one list.
If the operand of \textsf{msort} has only one element or none,
it is already in increasing order,
so the equations in that case,
like those for \textsf{isort} (page \pageref{eq:isrt0}),
are not inductive.
If the operand of \textsf{msort} has two or more elements,
the defining equation is inductive and
involves two sorting operations,
one for each of the two lists delivered by applying
\textsf{dmx} to the operand.
\begin{center}
\label{eq:msrt1}\index{axiom, by name!\{msrt0\}, \{msrt1\}, \{msrt2\}}\index{equation, by name!\{msrt0\}, \{msrt1\}, \{msrt2\}}
\label{eq:msrt0}
\label{eq:msrt2}
\begin{tabular}{ll}
\textsf{(msort nil) $=$ nil} & \{\emph{msrt0}\} \\
\textsf{(msort (cons $x$ nil)) $=$ (cons $x$ nil)} & \{\emph{msrt1}\} \\
\textsf{(msort (cons $x_1$ (cons $x_2$ xs))) $=$ (mrg (msort odds) (msort evns))} & \{\emph{msrt2}\} \\
~~~~ where & \\
~~~~ \textsf{[odds, evns] $=$ (dmx (cons $x_1$ (cons $x_2$ xs)))} & \\
\end{tabular}
\end{center}
The inductive equation will be computational only if
both of the lists that \textsf{dmx} delivers are strictly
shorter than the operand of \textsf{msort}.
We expect this to be true because half
of the elements go into each list
(\textsf{dmx} length theorems, page \pageref{thm:dmx-length-first-second}).
The following formal definition expresses the \textsf{msort}
equations (\{\emph{msrt0}\}, \{\emph{msrt1}\}, \{\emph{msrt2}\}) in ACL2
but consolidates the equations for lists with one element or none in the
manner of the ACL2 definition of \textsf{isort} (page \pageref{defun:isort}):
\label{defun:msort}\label{eq:msrt1}\index{axiom, by name!\{msrt0\}, \{msrt1\}, \{msrt2\}}\index{equation, by name!\{msrt0\}, \{msrt1\}, \{msrt2\}}
\index{operator, by name!msort (merge-sort)}\index{defun!lemma hint}\index{defun!induction hint}\index{directive!induction hint}\index{directive!lemma hint}\seeonlyindex{msort (merge-sort)}{operator}\index{merge-sort}\index{sorting!merge-sort (msort)}
\begin{code}
\begin{verbatim}
(defun msort (xs)
(declare (xargs
:measure (len xs)
:hints (("Goal"
:use ((:instance dmx-shortens-list-thm))))))
(if (consp (rest xs)) ; 2 or more elements?
(let* ((splt (dmx xs))
(odds (first splt))
(evns (second splt)))
(mrg (msort odds) (msort evns))) ; {msrt2}
xs)) ; (len xs) <= 1 ; {msrt1}
\end{verbatim}
\end{code}
The definition of \textsf{msort} includes
a \textsf{declare} directive
to help ACL2 verify that \textsf{msort} terminates.
The directive suggests basing the induction on the length of the operand.
To apply this inductive measure successfully,
ACL2 needs a hint suggesting the use of a lemma\footnote{Since
the theorem about the lengths of the lists
delivered by \textsf{dmx} is cited in the proof of another theorem
(namely, the theorem stating that \textsf{msort} terminates),
we refer to it as a \index{lemma}lemma.
The lemma could be derived from length theorems about \textsf{dmx}
proven in section \ref{sec:dmx} (page \pageref{thm:dmx-length-first-second}),
but a weaker form of those theorems turns out to be just what
ACL2 needs for its proof that \textsf{msort} terminates.}
stating that the \textsf{dmx} operator splits its
operand into two lists, both of which are strictly shorter than its operand.
ACL2 proves the lemma without assistance,
and it then admits (with the help of the \textsf{declare} directive)
the definition of \textsf{msort} to its mechanized logic.
\label{defthm:dmx-shortens-list}
\index{theorem, by name!\{dmx-shortens-list\}}
\begin{code}
\begin{verbatim}
(defthm dmx-shortens-list-thm ; lemma helps ACL2 admit def of msort
(implies (consp (rest xs)) ; can't shorten 0- or 1-element lists
(let* ((odds (first (dmx xs)))
(evns (second (dmx xs))))
(and (< (len odds) (len xs))
(< (len evns) (len xs))))))
\end{verbatim}
\end{code}
%'
Like \textsf{isort}, the \textsf{msort} operator puts the elements of its operand
in increasing order and preserves length and values.
The following statements of these properties, like those for \textsf{isort},
use the predicates \textsf{up} (page \pageref{defun:up})
and \textsf{occurs-in} (page \pageref{def:occurs-in}).\footnote{The
theorem statements employ the ACL2 operator \textsf{iff}, which is
\index{Boolean!equivalence ($\leftrightarrow$, iff)}\index{operator, by name!iff (Boolean equivalence)}\index{operator, logic!Boolean equivalence ($\leftrightarrow$, iff)}\index{iff (\emph{see also} operator)}\index{equivalence!Boolean ($\leftrightarrow$, iff)}Boolean equivalence
(box~\ref{aside:boolean-equivlance}, page \pageref{aside:boolean-equivlance}).}
Like \textsf{isort}, \textsf{(msort $xs$)} delivers a permutation of $xs$
(exercise~\ref{ex:permp-isort}, page \pageref{ex:permp-isort}),
but the proof is trickier for \textsf{msort}.
It might make a good project for ambitious readers.
ACL2 verifies the \textsf{msort} ordering property without help,
but it needs some lemmas stating the base case and the inductive case for
the proof of the length property.
ACL2 fails on the value property, so
we will settle for a paper-and-pencil proof of that one
(exercise \ref{msort-val-thm-pencil}, page \pageref{msort-val-thm-pencil}).
Figure~\ref{fig:msort-thms} (page \pageref{fig:msort-thms})
states the \textsf{msort} theorems and lemmas in ACL2.
\begin{figure}
\begin{code}
\begin{verbatim}
(defthm msort-order-thm
(up (msort xs)))
(defthm msort-len-lemma-base-case
(implies (not (consp (rest xs)))
(= (len (msort xs)) (len xs))))
(defthm msort-len-lemma-inductive-case
(= (len (msort (cons x xs)))
(1+ (len (msort xs)))))
(defthm msort-len-thm
(= (len (msort xs))
(len xs)))
(defthm msort-val-thm
(iff (occurs-in e xs)
(occurs-in e (msort xs))))
\end{verbatim}
\end{code}
\label{defthm:msort-len}\label{defthm:msort-val}\index{sorting!msort theorems}\index{theorem!merge-sort (msort)}\index{theorem, by name!\{msort-len\}, \{msort-ord\}, \{msort-val\}}
\caption{Theorems and lemmas about merge-sort.}
\label{fig:msort-thms}
\label{defthm:msort-ord}
\end{figure}
\begin{exercises}
\exer {Do a paper-and-pencil proof that, under certain conditions, the \textsf{dmx} operator
delivers lists that are shorter than its operand
(\textsf{dmx-shortens-list-thm}, above).} % page \pageref{defthm:dmx-shortens-list}).
\exer {Do a paper-and-pencil proof that the \textsf{msort} operator
delivers a list that is in increasing order
(\textsf{msort-order-thm}, above).
You may cite \textsf{mrg-ord-thm}
(exercise \ref{ex:mrg-ord-thm}, page \pageref{ex:mrg-ord-thm}).}%page \pageref{defthm:msort-ord}).}
\exer {\label{msort-val-thm-pencil}%
Do a paper-and-pencil proof that the \textsf{msort} operator
preserves the values in its operand
(\textsf{msort-val-thm}, page \pageref{defthm:msort-val}).
You may cite the mrg-val theorem
(exercise \ref{ex:mrg-val-thm}, page \pageref{ex:mrg-val-thm}).}
\exer {Do a paper-and-pencil proof that the \textsf{msort} operator
preserves the length of its operand
(\textsf{msort-len-thm}, page \pageref{defthm:msort-len}).
You may cite the merge-length theorem
(exercise \ref{ex:mrg-length-thm}, page \pageref{ex:mrg-length-thm}).}
\exer {Do a paper-and-pencil proof that the \textsf{msort} operator
delivers a permutation of its operand (see exercise~\ref{ex:permp-isort}, page \pageref{ex:permp-isort}).
\emph{Caveat}: This is a project, not an exercise.}
\end{exercises}
\section{Analysis of Sorting Algorithms}
\label{sec:sort-analysis}
\seeonlyindex{algorithm analysis}{computation steps}\seeonlyindex{time of computation}{computation steps}In
this section, we discuss a
\index{computation steps!ACL2}computation model for ACL2
that gives us a way to count the number of computation steps required
to compute the value denoted by a formula.
We use the equations defining
the \textsf{msort} operator to derive inductive equations
for the number of computation steps that \textsf{msort} requires to rearrange lists
into increasing order.
Then, we assert a formula for the number of computation steps required
by \textsf{msort} and prove, by mathematical induction,
that the formula is correct.
\index{sorting!msort vs isort}
It turns out that the number of steps in the computation
\textsf{(msort [$x_1$, $x_2$, $\dots$ $x_n$])}
is proportional to $n~log(n)$.
We do the same for \textsf{isort}.
The number of steps in the \textsf{isort} computation varies widely,
depending on the order of the values in the operand,
so we estimate the average over randomized lists.
That average turns out to be proportional
to the square of the number of elements in the operand.
Finally, we compare the computation steps required by
the two operators, \textsf{msort} and \textsf{isort}, and find that
\textsf{msort} is much faster for long lists.
\subsection{Counting Computation Steps}
\label{subsec:counting-computation-steps}
A definition of an operator in ACL2
is a collection of equations that
reduces invocations of the operator
to computations of the result.
Predicates determine
which equations to select from the definition.
Both the formula that computes the result and
the predicate formulas that control
its selection invoke other operators.
In the case of an inductive equation,
the selected formula may invoke the operator
defined by the definition.
The computation eventually boils down to a sequence of basic,
\index{computation steps!counting}\index{computation steps!ACL2}one-step operations.
Analyzing the number of steps required to compute a result
amounts to counting the number of steps in that sequence.
A detailed analysis would allow a different
computation time for each basic operator.
That is, a model for detailed analysis could associate
several computation steps with one basic operator
and associate only a few steps with another operator.
There would also be a scale establishing a relationship between
computation steps and \index{computation time}computation time.
Our analysis will provide a less refined picture than such
a model because we will assume that each basic operator
delivers its result in just one computation step.
In the worst case, this would throw comparisons between
the number of steps in different computations off
by the ratio between the time required by the slowest basic
operator and the fastest. That is, comparisons
based on our crude model
will be off by a small factor,
but they will provide a
rough estimate of the ratio between the computation speed of
one operator and another.
\begin{figure}\index{computation steps!one-step operators}\index{computation steps!ACL2}\index{computation steps!counting}
\begin{center}
\begin{spacing}{0.9}
\begin{tabular}{ll}
Insertion: \textsf{(cons $x$ $xs$)} & \\
Extraction: \textsf{(first $xs$)}, \textsf{(rest $xs$)} & \emph{operators that add one step} \\
Arithmetic: \textsf{($+$ $x$ $y$)}, \textsf{($-$ $x$ $y$)}, \textsf{($*$ $x$ $y$)}, \dots & ~~\emph{to a computation} \\
Boolean: \textsf{(and $x$ $y$)}, \textsf{(or $x$ $y$)}, \textsf{(not $x$)}, \dots & ~~~~\emph{(after computing needed operands)} \\
Comparison: \textsf{(< $x$ $y$)}, \textsf{(<= $x$ $y$)}, \textsf{(= $x$ $y$)}, \dots & \\
Cons predicate: \textsf{(consp $xs$)} & \\
Selection: \textsf{(if $p$ $x$ $y$)} & \emph{computes} $p$\emph{, then} $x$ \emph{or} $y$\emph{, but not both}
\end{tabular}
\end{spacing}
\end{center}
\vspace{-4mm}
\caption{Basic one-step operators.}
\label{fig:basic-one-step-ops}
\end{figure}
Figure~\ref{fig:basic-one-step-ops} %(page \pageref{fig:basic-one-step-ops})
specifies the basic, one-step operators of
the computation model.
Each basic operator in a formula contributes one step
to the computation, so
counting the number of steps in a computation is straightforward
if the definitions of the operators it invokes refer only
to the operators listed in the figure.
For example, analyzing the formula for constructing
the list \textsf{[1 2 3 4]} reveals a four-step computation.\vspace{2mm}\\
\hspace*{1cm}\textsf{[1 2 3 4]} denotes \textsf{(cons 1 (cons 2 (cons 3 (cons 4 nil))))}\\
\hspace*{1cm}Four Steps: \textsf{(cons 4 nil)}, \textsf{(cons 3 [4])}, \textsf{(cons 2 [3 4])}, \textsf{(cons 1 [2 3 4])}\vspace{2mm}
\begin{figure}
\begin{center}
\begin{tabular}{lcl}
\hline
\hspace*{5mm}\emph{formula} &\emph{steps}&~~~\emph{step 1, step 2, \dots}\\ \hline
\textsf{(cons 1 (cons 2 (cons 3 (cons 4 nil))))} & 4 &\textsf{(cons 4 nil)}, \textsf{(cons 3 \dots)},\\
& &~~~\textsf{cons}, \textsf{cons}\\
\textsf{(second [1 2 3])} & 2 &\textsf{(rest [1 2 3])}, \textsf{(first [2 3])}\\
\textsf{(if ($>$ 7 3) ($+$ 3 ($*$ 5 4)) ($+$ 2 2))} & 4 &\textsf{($>$ 7 3)}, \textsf{(if T $\Box$ $\Box$)}, \textsf{($*$ 5 4)},\\
& &~~~\textsf{($+$ 3 20)}\\
\textsf{(if ($<$ 7 3) ($+$ 3 ($*$ 5 4)) ($+$ 2 2))} & 3 &\textsf{($<$ 7 3)}, \textsf{(if nil $\Box$ $\Box$)}, \textsf{($+$ 2 2)}\\
\end{tabular}
\end{center}
\caption{Computation steps in formulas with basic operators.}
\label{fig:basic-op-formulas}
\end{figure}
Figure~\ref{fig:basic-op-formulas} %(page \pageref{fig:basic-op-formulas})
displays a similar analysis on some formulas
composed of basic operations. The same kind of
analysis applies when the formulas invoke defined operators
rather than intrinsic ones like
\textsf{cons}, \textsf{first}, and \textsf{rest}.
For example, the operator \textsf{F-from-C}, defined
as follows, converts a temperature from degrees Celsius to
degrees Fahrenheit. It multiplies the temperature by the ratio \textsf{180/100}
(to adjust from Celsius degrees to the
more refined scale of Fahrenheit degrees), then adds 32
(to adjust the freezing point from zero to 32).\footnote{Ratios
in ACL2 are designated
by two integers separated by a slash.
The notation represents the number itself, not a computation:
\textsf{1/2} represents one-half, just as \textsf{2} represents two.
No computation is involved.}
That makes two basic operations in all, so the formula
\textsf{(F-from-C $100$)} represents a two-step computation.
\index{Fahrenheit vs Celsius}\index{Celsius vs Fahrenheit}\index{operator, by name!F-from-C}\seeonlyindex{F-from-C}{operator}
\begin{code}
\begin{verbatim}
(defun F-from-C (C)
(+ (* 180/100 C) 32))
\end{verbatim}
\end{code}
The formula \textsf{(list (F-from-C $0$) (F-from-C $100$))}
makes a list in Fahrenheit degrees of two important
points on the temperature scale:
the freezing point of water ($0$ $^\circ$C) and the boiling point ($100$ $^\circ$C).
To count the number of steps in this computation,
we need to write the formula in terms of basic operations.
The operator \textsf{list} is shorthand for a sequence of nested
\textsf{cons} operations to build a list,
so in terms of basic operations, the formula is
\textsf{(cons (F-from-C $0$) (cons (F-from-C $100$) nil))}.
The total step-count comes to six: two for each \textsf{F-from-C} invocation
and one for each \textsf{cons}.
Another example:
the operator \textsf{swap2}, defined as follows, interchanges the
first two elements of a list if the list has at least two elements.
If not, it leaves the list as is.
\begin{code}\index{operator, by name!swap2}\seeonlyindex{swap2}{operator}
\begin{verbatim}
(defun swap2 (xs)
(if (consp (rest xs))
(cons (second xs) (cons (first xs)) (rest (rest xs)))
xs))
\end{verbatim}
\end{code}
It refers to the operator that extracts the second element from a list,
which is shorthand for using the basic operator \textsf{rest} to drop the
first element, then the operator \textsf{first} to extract the first element
of what remains.
\label{steps-in-second-op}\index{computation steps!counting}\index{computation steps!ACL2}So,
the formula \textsf{(second $xs$)} would add two steps
to the computation. The number of steps in the computation \textsf{(swap2 $xs$)}
depends on how many elements $xs$ has. If $xs$ has two or more elements,
then \textsf{(swap2 $xs$)} takes ten steps:
\textsf{if}, \textsf{consp}, \textsf{rest}, \textsf{cons},
two steps for \textsf{second},
\textsf{cons} again, \textsf{first}, and \textsf{rest} again, twice.
If $xs$ has fewer than two elements, then \textsf{(swap2 $xs$)} takes three steps:
\textsf{if}, \textsf{consp}, and \textsf{rest}.
\begin{exercises}
\exer {Count the number of steps in \textsf{($-$ (F-from-C $100$) (F-from-C $0$))}.}
\exer {\label{ex:swap2-count}%
Count the number of steps in \textsf{(swap2 (list 1 2 3))}.\\
\emph{Note}: \textsf{(list 1 2 3)} is shorthand for nested \textsf{cons} operations
(figure~\ref{fig:list-nested-cons}, page \pageref{fig:list-nested-cons}).}
\exer {Count the number of steps in \textsf{(swap2 (list 1))}.}
\exer {Count the number of steps in
\textsf{(list (third $xs$) (second $xs$) (first $xs$))},
where the formula \textsf{(third $xs$)} is shorthand for
\textsf{(first (rest (rest $xs$)))}.}
\exer {Define an operator \textsf{C-from-F} that converts degrees Fahrenheit
to degrees Celsius, and count the number of operations
required to compute \textsf{(C-from-F (F-from-C $20$))}.}
\exer {What is \textsf{(C-from-F (F-from-C $x$))}?
What is \textsf{(F-from-C (C-from-F $x$))}?}
\exer {Define a theorem about \textsf{(C-from-F (F-from-C $x$))}
and get ACL2 to prove it. \\
\emph{Note}: The complicated formula must be on the left-hand side of the
equation.\footnote{Constraints on the order of operands
in equations have to do with strategic considerations
in the ACL2 theorem-proving engine that are
beyond the scope of the treatment here. If you want to track
down those ideas, read about rewrite rules in the ACL2 documentation.}\\
\emph{Note}: The predicate \textsf{ACL2-numberp} is true
if its operand is a number and false otherwise.
The theorem must constrain the domain to numbers
(use \textsf{ACL2-numberp} and \textsf{implies}).}
\end{exercises}
\subsection{Computation Steps in Demultiplex}
\label{subsec:dmx-steps}
The demultiplex operator, \textsf{dmx} (page \pageref{dmx-defun}),
parcels out the elements of a list
into two separate lists, with every other element going into one list
and the remaining elements going into the other list.
We repeat its definition here for convenience in counting steps.
\begin{code}\label{defun:dmx-copy}\index{axiom, by name!\{dmx0\}, \{dmx1\}, \{dmx2\}}\index{equation, by name!\{dmx0\}, \{dmx1\}, \{dmx2\}}\index{operator, by name!dmx (demultiplexer)}
\begin{verbatim}
(defun dmx (xys)
(if (consp (rest xys)) ; 2 or more elements?
(let* ((x (first xys))
(y (second xys))
(xsys (dmx (rest (rest xys))))
(xs (first xsys))
(ys (second xsys)))
(list (cons x xs) (cons y ys))) ; {dmx2}
(list xys nil))) ; 1 element or none ; (dmx1}
\end{verbatim}
\end{code}
From the inductive equations for \textsf{dmx},