forked from ldct/isicp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
2-3-symbolic.html
1315 lines (1007 loc) · 70.3 KB
/
2-3-symbolic.html
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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="web-worker-interpreter/deps/codemirror/lib/codemirror.css" />
<link rel="stylesheet" type="text/css" href="css/isicp.css" />
<link rel="stylesheet" type="text/css" href="css/footnotes.css" />
<link rel="stylesheet" type="text/css" href="css/theme.css" />
<script src="js/helper.js"></script>
<script src="js/jquery.min.js"></script>
<script src="web-worker-interpreter/deps/codemirror/lib/codemirror.js"></script>
<script src="web-worker-interpreter/deps/codemirror/mode/scheme/scheme.js"></script>
<script src="web-worker-interpreter/coding.js"> </script>
<script>
set_interpreter_path("web-worker-interpreter/");
set_language("scheme");
</script>
<script src="js/footnotes.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$']]}
});
</script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<title> iSICP 2.3 - Symbolic Data </title>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36868476-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="sidebox">
<div class="tab"></div>
<div class="content">
<p>
<a href="index.html" class="navlink"> <img src='images/home.svg' width=32 height=32> </a>
<span id="toc-link" class="navlink"> <img src='images/list.svg' width=32 height=32> </span>
<span id="currently-editing-link" class="navlink"> <img src='images/file-edit.svg' width=32 height=32> </span>
<script src="http://cdn.jotfor.ms/static/feedback2.js?3.2.310" type="text/javascript">
new JotformFeedback({
formId:'40222623177447',
base:'http://jotform.me/',
windowTitle:'Notify Me',
background:'#FFA500',
fontColor:'#FFFFFF',
type:false,
height:500,
width:700
});
</script>
<a class="lightbox-40222623177447" style="cursor:pointer;color:blue;text-decoration:underline;"><img src='images/envelope.svg' width=32 height=32></a>
<p>
<div id="currently-editing"> </div>
<script>
function hideAll() {
$("#currently-editing").hide();
$("#toc").hide();
}
$("#currently-editing-link").click(function() {
hideAll();
$("#currently-editing").show();
});
$("#toc-link").click(function() {
hideAll();
$("#toc").show();
});
</script>
<div id="toc"> </div>
<p style='font-size:12px'> (Click on the left edge of this green box to hide it!)
<script>
hideAll();
$("#toc").show();
</script>
</div>
</div>
<script>
$('#sidebox .tab').toggle(function(){
$('#sidebox').animate({'right':'0%'});
}, function(){
$('#sidebox').animate({'right':'-30%'});
});
$(document).ready(createTOC);
</script>
<div id="main">
<a href='index.html' style="float:left"> <img src='images/chevron-up.svg' height=64 width=64> </a>
<span style="float:right">
<a href='2-2-closure.html'> <img src='images/chevron-left.svg' height=64 width=64> </a>
<a href='2-4-representation.html'> <img src='images/chevron-right.svg' height=64 width=64> </a>
</span>
<br> <br>
<h2> Symbolic Data </h2>
<p> All the compound data objects we have used so far were constructed ultimately from numbers. In this section we extend the representational capability of our language by introducing the ability to work with arbitrary symbols as data.
<h3> Quotation </h3>
<p> If we can form compound data using symbols, we can have lists such as
<div id="scheme-list-eg">
(a b c d)
(23 45 17)
((Norah 12) (Molly 9) (Anna 7) (Lauren 6) (Charlotte 4))
</div>
<script>
no_output_prompt("scheme-list-eg");
</script>
<p> Lists containing symbols can look just like the expressions of our language:
<div id="scheme-list-exp-eg">
(* (+ 23 45) (+ x 9))
(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))
</div>
<script>
no_output_prompt("scheme-list-exp-eg");
</script>
<p> In order to manipulate symbols we need a new element in our language: the ability to <tt>quote</tt> a data object. Suppose we want to construct the list <tt>(a b)</tt>. We can't accomplish this with <tt>(list a b)</tt>, because this expression constructs a list of the <tt>values</tt> of <tt>a</tt> and <tt>b</tt> rather than the symbols themselves. This issue is well known in the context of natural languages, where words and sentences may be regarded either as semantic entities or as character strings (syntactic entities). The common practice in natural languages is to use quotation marks to indicate that a word or a sentence is to be treated literally as a string of characters. For instance, the first letter of ``John'' is clearly ``J.'' If we tell somebody ``say your name aloud,'' we expect to hear that person's name. However, if we tell somebody ``say `your name' aloud,'' we expect to hear the words ``your name.'' Note that we are forced to nest quotation marks to describe what somebody else might say.<a name="footnote_link_2-32" class="footnote_link" href="#footnote_2-32">32</a>
<p> We can follow this same practice to identify lists and symbols that are to be treated as data objects rather than as expressions to be evaluated. However, our format for quoting differs from that of natural languages in that we place a quotation mark (traditionally, the single quote symbol <tt>'</tt>) only at the beginning of the object to be quoted. We can get away with this in Scheme syntax because we rely on blanks and parentheses to delimit objects. Thus, the meaning of the single quote character is to quote the next object.<a name="footnote_link_2-33" class="footnote_link" href="#footnote_2-33">33</a>
<p> Now we can distinguish between symbols and their values:
<div id="scheme-define-a-b">
(define a 1)
(define b 2)
</div>
<script>
prompt("scheme-define-a-b");
</script>
<p>
<div id="scheme-list-a-b">
(list a b)
</div>
<script>
promptDep("scheme-list-a-b", ["scheme-define-a-b"]);
</script>
<p>
<div id="scheme-list-qa-qb">
(list 'a 'b)
</div>
<script>
promptDep("scheme-list-qa-qb", ["scheme-define-a-b"]);
</script>
<p>
<div id="scheme-list-qa-b">
(list 'a b)
</div>
<script>
promptDep("scheme-list-qa-b", ["scheme-define-a-b"]);
</script>
<p> Quotation also allows us to type in compound objects, using the conventional printed representation for lists:<a name="footnote_link_2-34" class="footnote_link" href="#footnote_2-34">34</a>
<div id="scheme-car-qabc">
(car '(a b c))
</div>
<script>
prompt("scheme-car-qabc");
</script>
<p>
<div id="scheme-cdr-qabc">
(cdr '(a b c))
</div>
<script>
prompt("scheme-cdr-qabc");
</script>
<p> In keeping with this, we can obtain the empty list by evaluating <tt>'()</tt>, and thus dispense with the variable <tt>nil</tt>.
<p> One additional primitive used in manipulating symbols is <tt>eq?</tt>, which takes two symbols as arguments and tests whether they are the same.<a name="footnote_link_2-35" class="footnote_link" href="#footnote_2-35">35</a> Using <tt>eq?</tt>, we can implement a useful procedure called <tt>memq</tt>. This takes two arguments, a symbol and a list. If the symbol is not contained in the list (i.e., is not <tt>eq?</tt> to any item in the list), then <tt>memq</tt> returns false. Otherwise, it returns the sublist of the list beginning with the first occurrence of the symbol:
<div id="scheme-define-memq">
(define (memq item x)
(cond ((null? x) false)
((eq? item (car x)) x)
(else (memq item (cdr x)))))
</div>
<script>
prompt("scheme-define-memq");
</script>
<p> For example, the value of
<div id="scheme-memq-apple-pear-banana-prune">
(memq 'apple '(pear banana prune))
</div>
<script>
promptDep("scheme-memq-apple-pear-banana-prune", ["scheme-define-memq"]);
</script>
<p> is false, whereas the value of
<div id="scheme-memq-apple-apple-sauce-apple-pear">
(memq 'apple '(x (apple sauce) y apple pear))
</div>
<script>
promptDep("scheme-memq-apple-apple-sauce-apple-pear", ["scheme-define-memq"]);
</script>
<p> is <tt>(apple pear)</tt>.
<div class="exercise">
<p> <b>Exercise 2.53:</b> What would the interpreter print in response to evaluating each of the following expressions?
<div id="scheme-ex-interpret-quotes">
(list 'a 'b 'c)
(list (list 'george))
(cdr '((x1 x2) (y1 y2)))
(cadr '((x1 x2) (y1 y2)))
(pair? (car '(a short list)))
(memq 'red '((red shoes) (blue socks)))
(memq 'red '(red shoes blue socks))
</div>
<script>
prompt("scheme-ex-interpret-quotes");
</script>
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.54:</b> Two lists are said to be <tt>equal?</tt> if they contain equal elements arranged in the same order. For example,
<div id="scheme-equal?-this-is-a-list">
(equal? '(this is a list) '(this is a list))
</div>
<script>
prompt("scheme-equal?-this-is-a-list");
</script>
<p> is true, but
<div id="scheme-equal?-nested-this-is-a-list">
(equal? '(this is a list) '(this (is a) list))
</div>
<script>
prompt("scheme-equal?-nested-this-is-a-list");
</script>
<p> is false. To be more precise, we can define <tt>equal?</tt> recursively in terms of the basic <tt>eq?</tt> equality of symbols by saying that <tt>a</tt> and <tt>b</tt> are <tt>equal?</tt> if they are both symbols and the symbols are <tt>eq?</tt>, or if they are both lists such that <tt>(car a)</tt> is <tt>equal?</tt> to <tt>(car b)</tt> and <tt>(cdr a)</tt> is <tt>equal?</tt> to <tt>(cdr b)</tt>. Using this idea, implement <tt>equal?</tt> as a procedure.<a name="footnote_link_2-36" class="footnote_link" href="#footnote_2-36">36</a>
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.55:</b> Eva Lu Ator types to the interpreter the expression
<div id="scheme-car-qqabracadabra">
(car ''abracadabra)
</div>
<script>
no_output_frozen_prompt("scheme-car-qqabracadabra");
</script>
<p> To her surprise, the interpreter prints back <tt>quote</tt>. Explain.
</div>
<h3> Example: Symbolic Differentiation </h3>
<p> As an illustration of symbol manipulation and a further illustration of data abstraction, consider the design of a procedure that performs symbolic differentiation of algebraic expressions. We would like the procedure to take as arguments an algebraic expression and a variable and to return the derivative of the expression with respect to the variable. For example, if the arguments to the procedure are ax^2 + bx + c and x, the procedure should return 2ax + b. Symbolic differentiation is of special historical significance in Lisp. It was one of the motivating examples behind the development of a computer language for symbol manipulation. Furthermore, it marked the beginning of the line of research that led to the development of powerful systems for symbolic mathematical work, which are currently being used by a growing number of applied mathematicians and physicists.
<p> In developing the symbolic-differentiation program, we will follow the same strategy of data abstraction that we followed in developing the rational-number system of section 2-1-1. That is, we will first define a differentiation algorithm that operates on abstract objects such as ``sums,'' ``products,'' and ``variables'' without worrying about how these are to be represented. Only afterward will we address the representation problem.
<h4> The differentiation program with abstract data </h4>
<p> In order to keep things simple, we will consider a very simple symbolic-differentiation program that handles expressions that are built up using only the operations of addition and multiplication with two arguments. Differentiation of any such expression can be carried out by applying the following reduction rules:
$$
\frac{dc}{dx} = 0 \text{ for $c$ a constant, or a variable different from $x$} \\
\frac{dx}{dx} = 1 \\
\frac{d(u + v)}{dx} = \frac{du}{dx} + \frac{dv}{dx} \\
\frac{d(uv)}{dx} = u\left(\frac{dv}{dx}\right) + v\left(\frac{du}{dx}\right)
$$
<p> Observe that the latter two rules are recursive in nature. That is, to obtain the derivative of a sum we first find the derivatives of the terms and add them. Each of the terms may in turn be an expression that needs to be decomposed. Decomposing into smaller and smaller pieces will eventually produce pieces that are either constants or variables, whose derivatives will be either 0 or 1.
<p> To embody these rules in a procedure we indulge in a little wishful thinking, as we did in designing the rational-number implementation. If we had a means for representing algebraic expressions, we should be able to tell whether an expression is a sum, a product, a constant, or a variable. We should be able to extract the parts of an expression. For a sum, for example we want to be able to extract the addend (first term) and the augend (second term). We should also be able to construct expressions from parts. Let us assume that we already have procedures to implement the following selectors, constructors, and predicates:
<pre>
(variable? e) Is <tt>e</tt> a variable?
(same-variable? v1 v2) Are <tt>v1</tt> and <tt>v2</tt> the same variable?
(sum? e) Is <tt>e</tt> a sum?
(addend e) Addend of the sum <tt>e</tt>.
(augend e) Augend of the sum <tt>e</tt>.
(make-sum a1 a2) Construct the sum of <tt>a1</tt> and <tt>a2</tt>.
(product? e) Is <tt>e</tt> a product?
(multiplier e) Multiplier of the product <tt>e</tt>.
(multiplicand e) Multiplicand of the product <tt>e</tt>.
(make-product m1 m2) Construct the product of <tt>m1</tt> and <tt>m2</tt>.
</pre>
<p> Using these, and the primitive predicate <tt>number?</tt>, which identifies numbers, we can express the differentiation rules as the following procedure:
<div id="scheme-define-deriv">
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
(else
(error "unknown expression type -- DERIV" exp))))
</div>
<script>
prompt("scheme-define-deriv",
["scheme-define-variablep",
"scheme-define-same-variablep",
"scheme-define-sump",
"scheme-define-addend",
"scheme-define-augend",
"scheme-define-multiplier",
"scheme-define-multiplicand",
"scheme-define-productp",
"scheme-define-make-sum-product"
]);
</script>
<p> This <tt>deriv</tt> procedure incorporates the complete differentiation algorithm. Since it is expressed in terms of abstract data, it will work no matter how we choose to represent algebraic expressions, as long as we design a proper set of selectors and constructors. This is the issue we must address next.
<h4> Representing algebraic expressions </h4>
<p> We can imagine many ways to use list structure to represent algebraic expressions. For example, we could use lists of symbols that mirror the usual algebraic notation, representing $ax + b$ as the list <tt>(a * x + b)</tt> . However, one especially straightforward choice is to use the same parenthesized prefix notation that Lisp uses for combinations; that is, to represent $ax + b$ as <tt>(+ (* a x) b)</tt>. Then our data representation for the differentiation problem is as follows:
<ul>
<li>
<p> The variables are symbols. They are identified by the primitive predicate
<tt>symbol?</tt>:
<div id="scheme-define-variablep">
(define (variable? x) (symbol? x))
</div>
<script>
prompt("scheme-define-variablep");
</script>
</li>
<li>
<p> Two variables are the same if the symbols representing them are <tt>eq?</tt>:
<div id="scheme-define-same-variablep">
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
</div>
<script>
prompt("scheme-define-same-variablep");
</script>
</li>
<li>
<p> Sums and products are constructed as lists:
<div id="scheme-define-make-sum-product">
(define (make-sum a1 a2) (list '+ a1 a2))
(define (make-product m1 m2) (list '* m1 m2))
</div>
<script>
prompt("scheme-define-make-sum-product");
</script>
</li>
<li>
<p> A sum is a list whose first element is the symbol <tt>+</tt>:
<div id="scheme-define-sump">
(define (sum? x)
(and (pair? x) (eq? (car x) '+)))
</div>
<script>
prompt("scheme-define-sump");
</script>
</li>
<li>
<p> The addend is the second item of the sum list:
<div id="scheme-define-addend">
(define (addend s) (cadr s))
</div>
<script>
prompt("scheme-define-addend");
</script>
</li>
<li>
<p> The augend is the third item of the sum list:
<div id="scheme-define-augend">
(define (augend s) (caddr s))
</div>
<script>
prompt("scheme-define-augend");
</script>
</li>
<li>
<p> A product is a list whose first element is the symbol <tt>*</tt>:
<div id="scheme-define-productp">
(define (product? x)
(and (pair? x) (eq? (car x) '*)))
</div>
<script>
prompt("scheme-define-productp");
</script>
</li>
<li>
<p> The multiplier is the second item of the product list:
<div id="scheme-define-multiplier">
(define (multiplier p) (cadr p))
</div>
<script>
prompt("scheme-define-multiplier");
</script>
</li>
<li>
<p> The multiplicand is the third item of the product list:
<div id="scheme-define-multiplicand">
(define (multiplicand p) (caddr p))
</div>
<script>
prompt("scheme-define-multiplicand");
</script>
</ul>
<p> Thus, we need only combine these with the algorithm as embodied by <tt>deriv</tt> in order to have a working symbolic-differentiation program. Let us look at some examples of its behavior:
<div id="scheme-deriv-x-3">
(deriv '(+ x 3) 'x)
</div>
<script>
promptDep("scheme-deriv-x-3", ["scheme-define-deriv"]);
</script>
<p>
<div id="scheme-deriv-x-y">
(deriv '(* x y) 'x)
</div>
<script>
promptDep("scheme-deriv-x-y", ["scheme-define-deriv"]);
</script>
<p>
<div id="scheme-deriv-x-y-x-3">
(deriv '(* (* x y) (+ x 3)) 'x)
</div>
<script>
promptDep("scheme-deriv-x-y-x-3", ["scheme-define-deriv"]);
</script>
<p> The program produces answers that are correct; however, they are unsimplified. It is true that
$$
\frac{d(xy)}{dx} = x \cdot 0 + 1 \cdot y
$$
<p> but we would like the program to know that $x * 0 = 0$, $1 * y = y$, and $0 + y = y$. The answer for the second example should have been simply <tt>y</tt>. As the third example shows, this becomes a serious issue when the expressions are complex.
<p> Our difficulty is much like the one we encountered with the rational-number implementation: we haven't reduced answers to simplest form. To accomplish the rational-number reduction, we needed to change only the constructors and the selectors of the implementation. We can adopt a similar strategy here. We won't change <tt>deriv</tt> at all. Instead, we will change <tt>make-sum</tt> so that if both summands are numbers, <tt>make-sum</tt> will add them and return their sum. Also, if one of the summands is 0, then <tt>make-sum</tt> will return the other summand.
<div id="scheme-define-simplifying-make-sum">
(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (list '+ a1 a2))))
</div>
<script>
promptDep("scheme-define-simplifying-make-sum", ["scheme-define-equal-numberp"]);
</script>
<p> This uses the procedure <tt>=number?</tt>, which checks whether an expression is equal to a given number:
<div id="scheme-define-equal-numberp">
(define (=number? exp num)
(and (number? exp) (= exp num)))
</div>
<script>
prompt("scheme-define-equal-numberp");
</script>
<p> Similarly, we will change <tt>make-product</tt> to build in the rules that 0 times anything is 0 and 1 times anything is the thing itself:
<div id="scheme-define-simplifying-make-product">
(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list '* m1 m2))))
</div>
<script>
prompt("scheme-define-simplifying-make-product");
</script>
<p> Here is how this version works on our three examples:
<div id="scheme-define-simplifying-deriv">
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
(else
(error "unknown expression type -- DERIV" exp))))
</div>
<script>
hidden_prompt("scheme-define-simplifying-deriv",
["scheme-define-variablep",
"scheme-define-same-variablep",
"scheme-define-sump",
"scheme-define-addend",
"scheme-define-augend",
"scheme-define-multiplier",
"scheme-define-multiplicand",
"scheme-define-productp",
"scheme-define-simplifying-make-sum",
"scheme-define-simplifying-make-product",
]);
</script>
<div id="scheme-test-simplifying-deriv-x-3">
(deriv '(+ x 3) 'x)
</div>
<script>
prompt("scheme-test-simplifying-deriv-x-3", ["scheme-define-simplifying-deriv"]);
</script>
<p>
<div id="scheme-test-simplifying-deriv-x-y">
(deriv '(* x y) 'x)
</div>
<script>
prompt("scheme-test-simplifying-deriv-x-y", ["scheme-define-simplifying-deriv"]);
</script>
<p>
<div id="scheme-test-simplifying-deriv-x-y-x-3">
(deriv '(* (* x y) (+ x 3)) 'x)
</div>
<script>
prompt("scheme-test-simplifying-deriv-x-y-x-3", ["scheme-define-simplifying-deriv"]);
</script>
<p> Although this is quite an improvement, the third example shows that there is still a long way to go before we get a program that puts expressions into a form that we might agree is ``simplest.'' The problem of algebraic simplification is complex because, among other reasons, a form that may be simplest for one purpose may not be for another.
<div class="exercise">
<p> <b>Exercise 2.56:</b> Show how to extend the basic differentiator to handle more kinds of expressions. For instance, implement the differentiation rule
$$
\frac{d(u^n)}{dx} = nu^{n-1}\left(\frac{du}{dx}\right)
$$
by adding a new clause to the <tt>deriv</tt> program and defining appropriate procedures <tt>exponentiation?</tt>, <tt>base</tt>, <tt>exponent</tt>, and <tt>make-exponentiation</tt>. (You may use the symbol <tt>**</tt> to denote exponentiation.) Build in the rules that anything raised to the power $0$ is $1$ and anything raised to the power $1$ is the thing itself.
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.57:</b> Extend the differentiation program to handle sums and products of arbitrary numbers of (two or more) terms. Then the last example above could be expressed as
<div id="scheme-ex-test-deriv-sum">
(deriv '(* x y (+ x 3)) 'x)
</div>
<script>
prompt("scheme-ex-test-deriv-sum");
</script>
<p> Try to do this by changing only the representation for sums and products, without changing the <tt>deriv</tt> procedure at all. For example, the <tt>addend</tt> of a sum would be the first term, and the <tt>augend</tt> would be the sum of the rest of the terms.
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.58:</b> Suppose we want to modify the differentiation program so that it works with ordinary mathematical notation, in which <tt>+</tt> and <tt>*</tt> are infix rather than prefix operators. Since the differentiation program is defined in terms of abstract data, we can modify it to work with different representations of expressions solely by changing the predicates, selectors, and constructors that define the representation of the algebraic expressions on which the differentiator is to operate.
<ul>
<li>
<p> Show how to do this in order to differentiate algebraic expressions presented in infix form, such as <tt>(x + (3 * (x + (y + 2))))</tt>. To simplify the task, assume that <tt>+</tt> and <tt>*</tt> always take two arguments and that expressions are fully parenthesized.
</li>
<li>
<p> The problem becomes substantially harder if we allow standard algebraic notation, such as <tt>(x + 3 * (x + y + 2))</tt>, which drops unnecessary parentheses and assumes that multiplication is done before addition. Can you design appropriate predicates, selectors, and constructors for this notation such that our derivative program still works?
</li>
</ul>
</div>
<h3> Example: Representing Sets </h3>
<p> In the previous examples we built representations for two kinds of compound data objects: rational numbers and algebraic expressions. In one of these examples we had the choice of simplifying (reducing) the expressions at either construction time or selection time, but other than that the choice of a representation for these structures in terms of lists was straightforward. When we turn to the representation of sets, the choice of a representation is not so obvious. Indeed, there are a number of possible representations, and they differ significantly from one another in several ways.
<p> Informally, a set is simply a collection of distinct objects. To give a more precise definition we can employ the method of data abstraction. That is, we define ``set'' by specifying the operations that are to be used on sets. These are <tt>union-set</tt>, <tt>intersection-set</tt>, <tt>element-of-set?</tt>, and <tt>adjoin-set</tt>. <tt>Element-of-set?</tt> is a predicate that determines whether a given element is a member of a set. <tt>Adjoin-set</tt> takes an object and a set as arguments and returns a set that contains the elements of the original set and also the adjoined element. <tt>Union-set</tt> computes the union of two sets, which is the set containing each element that appears in either argument. <tt>Intersection-set</tt> computes the intersection of two sets, which is the set containing only elements that appear in both arguments. From the viewpoint of data abstraction, we are free to design any representation that implements these operations in a way consistent with the interpretations given above.<a name="footnote_link_2-37" class="footnote_link" href="#footnote_2-37">37</a>
<h4> Sets as unordered lists </h4>
<p> One way to represent a set is as a list of its elements in which no element appears more than once. The empty set is represented by the empty list. In this representation, <tt>element-of-set?</tt> is similar to the procedure <tt>memq</tt> of section 2-3-1. It uses <tt>equal?</tt> instead of <tt>eq?</tt> so that the set elements need not be symbols:
<div id="scheme-define-element-of-setp">
(define (element-of-set? x set)
(cond ((null? set) false)
((equal? x (car set)) true)
(else (element-of-set? x (cdr set)))))
</div>
<script>
prompt("scheme-define-element-of-setp");
</script>
<p> Using this, we can write <tt>adjoin-set</tt>. If the object to be adjoined is already in the set, we just return the set. Otherwise, we use <tt>cons</tt> to add the object to the list that represents the set:
<div id="scheme-define-adjoin-set">
(define (adjoin-set x set)
(if (element-of-set? x set)
set
(cons x set)))
</div>
<script>
prompt("scheme-define-adjoin-set");
</script>
<p> For <tt>intersection-set</tt> we can use a recursive strategy. If we know how to form the intersection of <tt>set2</tt> and the <tt>cdr</tt> of <tt>set1</tt>, we only need to decide whether to include the <tt>car</tt> of <tt>set1</tt> in this. But this depends on whether <tt>(car set1)</tt> is also in <tt>set2</tt>. Here is the resulting procedure:
<div id="scheme-define-intersection-set">
(define (intersection-set set1 set2)
(cond ((or (null? set1) (null? set2)) '())
((element-of-set? (car set1) set2)
(cons (car set1)
(intersection-set (cdr set1) set2)))
(else (intersection-set (cdr set1) set2))))
</div>
<script>
prompt("scheme-define-intersection-set");
</script>
<p> In designing a representation, one of the issues we should be concerned with is efficiency. Consider the number of steps required by our set operations. Since they all use <tt>element-of-set?</tt>, the speed of this operation has a major impact on the efficiency of the set implementation as a whole. Now, in order to check whether an object is a member of a set, <tt>element-of-set?</tt> may have to scan the entire set. (In the worst case, the object turns out not to be in the set.) Hence, if the set has n elements, <tt>element-of-set?</tt> might take up to n steps. Thus, the number of steps required grows as $\Theta(n)$. The number of steps required by <tt>adjoin-set</tt>, which uses this operation, also grows as $\Theta(n)$. For <tt>intersection-set</tt>, which does an <tt>element-of-set?</tt> check for each element of <tt>set1</tt>, the number of steps required grows as the product of the sizes of the sets involved, or $\Theta(n^2)$ for two sets of size n. The same will be true of <tt>union-set</tt>.
<div class="exercise">
<p> <b>Exercise 2.59:</b> Implement the <tt>union-set</tt> operation for the unordered-list representation of sets.
</div>
<p>
<div class="exercise">
<b>Exercise 2.60:</b> We specified that a set would be represented as a list with no duplicates. Now suppose we allow duplicates. For instance, the set <tt>{1,2,3}</tt> could be represented as the list <tt>(2 3 2 1 3 2 2)</tt>. Design procedures <tt>element-of-set?</tt>, <tt>adjoin-set</tt>, <tt>union-set</tt>, and <tt>intersection-set</tt> that operate on this representation. How does the efficiency of each compare with the corresponding procedure for the non-duplicate representation? Are there applications for which you would use this representation in preference to the non-duplicate one?
</div>
<h4> Sets as ordered lists </h4>
<p> One way to speed up our set operations is to change the representation so that the set elements are listed in increasing order. To do this, we need some way to compare two objects so that we can say which is bigger. For example, we could compare symbols lexicographically, or we could agree on some method for assigning a unique number to an object and then compare the elements by comparing the corresponding numbers. To keep our discussion simple, we will consider only the case where the set elements are numbers, so that we can compare elements using <tt>></tt> and <tt><</tt>. We will represent a set of numbers by listing its elements in increasing order. Whereas our first representation above allowed us to represent the set <tt>{1,3,6,10}</tt> by listing the elements in any order, our new representation allows only the list <tt>(1 3 6 10)</tt>.
<p> One advantage of ordering shows up in <tt>element-of-set?</tt>: In checking for the presence of an item, we no longer have to scan the entire set. If we reach a set element that is larger than the item we are looking for, then we know that the item is not in the set:
<div id="scheme-define-ordered-element-of-setp">
(define (element-of-set? x set)
(cond ((null? set) false)
((= x (car set)) true)
((< x (car set)) false)
(else (element-of-set? x (cdr set)))))
</div>
<script>
prompt("scheme-define-ordered-element-of-setp");
</script>
<p> How many steps does this save? In the worst case, the item we are looking for may be the largest one in the set, so the number of steps is the same as for the unordered representation. On the other hand, if we search for items of many different sizes we can expect that sometimes we will be able to stop searching at a point near the beginning of the list and that other times we will still need to examine most of the list. On the average we should expect to have to examine about half of the items in the set. Thus, the average number of steps required will be about $\frac{n}{2}$. This is still $\Theta(n)$ growth, but it does save us, on the average, a factor of 2 in number of steps over the previous implementation.
<p> We obtain a more impressive speedup with <tt>intersection-set</tt>. In the unordered representation this operation required $\Theta(n^2)$ steps, because we performed a complete scan of <tt>set2</tt> for each element of <tt>set1</tt>. But with the ordered representation, we can use a more clever method. Begin by comparing the initial elements, <tt>x1</tt> and <tt>x2</tt>, of the two sets. If <tt>x1</tt> equals <tt>x2</tt>, then that gives an element of the intersection, and the rest of the intersection is the intersection of the <tt>cdr</tt>s of the two sets. Suppose, however, that <tt>x1</tt> is less than <tt>x2</tt>. Since <tt>x2</tt> is the smallest element in <tt>set2</tt>, we can immediately conclude that <tt>x1</tt> cannot appear anywhere in <tt>set2</tt> and hence is not in the intersection. Hence, the intersection is equal to the intersection of <tt>set2</tt> with the <tt>cdr</tt> of <tt>set1</tt>. Similarly, if <tt>x2</tt> is less than <tt>x1</tt>, then the intersection is given by the intersection of <tt>set1</tt> with the <tt>cdr</tt> of <tt>set2</tt>. Here is the procedure:
<div id="scheme-define-ordered-intersection-set">
(define (intersection-set set1 set2)
(if (or (null? set1) (null? set2))
'()
(let ((x1 (car set1)) (x2 (car set2)))
(cond ((= x1 x2)
(cons x1
(intersection-set (cdr set1)
(cdr set2))))
((< x1 x2)
(intersection-set (cdr set1) set2))
((< x2 x1)
(intersection-set set1 (cdr set2)))))))
</div>
<script>
prompt("scheme-define-ordered-intersection-set");
</script>
<p> To estimate the number of steps required by this process, observe that at each step we reduce the intersection problem to computing intersections of smaller sets---removing the first element from <tt>set1</tt> or <tt>set2</tt> or both. Thus, the number of steps required is at most the sum of the sizes of <tt>set1</tt> and <tt>set2</tt>, rather than the product of the sizes as with the unordered representation. This is $\Theta(n)$ growth rather than $\Theta(n^2)$ – a considerable speedup, even for sets of moderate size.
<div class="exercise">
<p> <b>Exercise 2.61:</b> Give an implementation of <tt>adjoin-set</tt> using the ordered representation. By analogy with <tt>element-of-set?</tt> show how to take advantage of the ordering to produce a procedure that requires on the average about half as many steps as with the unordered representation.
</div>
<div class="exercise">
<p> <b>Exercise 2.62:</b> Give a $\Theta(n)$ implementation of <tt>union-set</tt> for sets represented as ordered lists.
</div>
<h4> Sets as binary trees </h4>
<p> We can do better than the ordered-list representation by arranging the set elements in the form of a tree. Each node of the tree holds one element of the set, called the ``entry'' at that node, and a link to each of two other (possibly empty) nodes. The ``left'' link points to elements smaller than the one at the node, and the ``right'' link to elements greater than the one at the node. Figure 2-16 shows some trees that represent the set <tt>{1,3,5,7,9,11}.</tt> The same set may be represented by a tree in a number of different ways. The only thing we require for a valid representation is that all elements in the left subtree be smaller than the node entry and that all elements in the right subtree be larger.
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-51.gif">
<p> <b>Figure 2.16:</b> Various binary trees that represent the set $\{1,3,5,7,9,11\}$.
</div>
<p> The advantage of the tree representation is this: Suppose we want to check whether a number x is contained in a set. We begin by comparing x with the entry in the top node. If x is less than this, we know that we need only search the left subtree; if x is greater, we need only search the right subtree. Now, if the tree is ``balanced,'' each of these subtrees will be about half the size of the original. Thus, in one step we have reduced the problem of searching a tree of size n to searching a tree of size n/2. Since the size of the tree is halved at each step, we should expect that the number of steps needed to search a tree of size n grows as $\Theta(\log(n))$.<a name="footnote_link_2-38" class="footnote_link" href="#footnote_2-38">38</a> For large sets, this will be a significant speedup over the previous representations.
<p> We can represent trees by using lists. Each node will be a list of three items: the entry at the node, the left subtree, and the right subtree. A left or a right subtree of the empty list will indicate that there is no subtree connected there. We can describe this representation by the following procedures:<a name="footnote_link_2-39" class="footnote_link" href="#footnote_2-39">39</a>
<div id="scheme-define-binary-entry-branch-make-tree">
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
</div>
<script>
prompt("scheme-define-binary-entry-branch-make-tree");
</script>
<p> Now we can write the <tt>element-of-set?</tt> procedure using the strategy described above:
<div id="scheme-define-binary-element-of-setp">
(define (element-of-set? x set)
(cond ((null? set) false)
((= x (entry set)) true)
((< x (entry set))
(element-of-set? x (left-branch set)))
((> x (entry set))
(element-of-set? x (right-branch set)))))
</div>
<script>
prompt("scheme-define-binary-element-of-setp", ["scheme-define-entry-branch-make-tree"]);
</script>
<p> Adjoining an item to a set is implemented similarly and also requires $\Theta(\log(n))$ steps. To adjoin an item $x$, we compare $x$ with the node entry to determine whether $x$ should be added to the right or to the left branch, and having adjoined $x$ to the appropriate branch we piece this newly constructed branch together with the original entry and the other branch. If $x$ is equal to the entry, we just return the node. If we are asked to adjoin $x$ to an empty tree, we generate a tree that has $x$ as the entry and empty right and left branches. Here is the procedure:
<div id="scheme-define-binary-adjoin-set">
(define (adjoin-set x set)
(cond ((null? set) (make-tree x '() '()))
((= x (entry set)) set)
((< x (entry set))
(make-tree (entry set)
(adjoin-set x (left-branch set))
(right-branch set)))
((> x (entry set))
(make-tree (entry set)
(left-branch set)
(adjoin-set x (right-branch set))))))
</div>
<script>
prompt("scheme-define-binary-adjoin-set", ["scheme-define-binary-entry-branch-make-tree"]);
</script>
<p> The above claim that searching the tree can be performed in a logarithmic number of steps rests on the assumption that the tree is ``balanced,'' i.e., that the left and the right subtree of every tree have approximately the same number of elements, so that each subtree contains about half the elements of its parent. But how can we be certain that the trees we construct will be balanced? Even if we start with a balanced tree, adding elements with <tt>adjoin-set</tt> may produce an unbalanced result. Since the position of a newly adjoined element depends on how the element compares with the items already in the set, we can expect that if we add elements ``randomly'' the tree will tend to be balanced on the average. But this is not a guarantee. For example, if we start with an empty set and adjoin the numbers 1 through 7 in sequence we end up with the highly unbalanced tree shown in Figure 2-17. In this tree all the left subtrees are empty, so it has no advantage over a simple ordered list. One way to solve this problem is to define an operation that transforms an arbitrary tree into a balanced tree with the same elements. Then we can perform this transformation after every few <tt>adjoin-set</tt> operations to keep our set in balance. There are also other ways to solve this problem, most of which involve designing new data structures for which searching and insertion both can be done in $\Theta(\log(n))$ steps.<a name="footnote_link_2-40" class="footnote_link" href="#footnote_2-40">40</a>
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-52.gif">
<p> <b>Figure 2.17:</b> Unbalanced tree produced by adjoining 1 through 7 in sequence.
</div>
<div class="exercise">
<p> <b>Exercise 2.63:</b> Each of the following two procedures converts a binary tree to a list.
<div id="scheme-define-list-to-tree-1-2">
(define (tree->list-1 tree)
(if (null? tree)
'()
(append (tree->list-1 (left-branch tree))
(cons (entry tree)
(tree->list-1 (right-branch tree))))))
(define (tree->list-2 tree)
(define (copy-to-list tree result-list)
(if (null? tree)
result-list
(copy-to-list (left-branch tree)
(cons (entry tree)
(copy-to-list (right-branch tree)
result-list)))))
(copy-to-list tree '()))
</div>
<script>
prompt("scheme-define-list-to-tree-1-2");
</script>
<ul>
<li>
<p> Do the two procedures produce the same result for every tree? If not, how do the results differ? What lists do the two procedures produce for the trees in Figure 2-16?
</li>
<li>
<p> Do the two procedures have the same order of growth in the number of steps required to convert a balanced tree with n elements to a list? If not, which one grows more slowly?
</li>
</ul>
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.64:</b> The following procedure <tt>list->tree</tt> converts an ordered list to a balanced binary tree. The helper procedure <tt>partial-tree</tt> takes as arguments an integer n and list of at least n elements and constructs a balanced tree containing the first n elements of the list. The result returned by <tt>partial-tree</tt> is a pair (formed with <tt>cons</tt>) whose <tt>car</tt> is the constructed tree and whose <tt>cdr</tt> is the list of elements not included in the tree.
<div id="scheme-define-list-to-tree">
(define (list->tree elements)
(car (partial-tree elements (length elements))))
(define (partial-tree elts n)
(if (= n 0)
(cons '() elts)
(let ((left-size (quotient (- n 1) 2)))
(let ((left-result (partial-tree elts left-size)))
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
(right-size (- n (+ left-size 1))))
(let ((this-entry (car non-left-elts))
(right-result (partial-tree (cdr non-left-elts)
right-size)))
(let ((right-tree (car right-result))
(remaining-elts (cdr right-result)))
(cons (make-tree this-entry left-tree right-tree)
remaining-elts))))))))
</div>
<script>
prompt("scheme-define-list-to-tree");
</script>
<ul>
<li>
<p> Write a short paragraph explaining as clearly as you can how <tt>partial-tree</tt> works. Draw the tree produced by <tt>list->tree</tt> for the list <tt>(1 3 5 7 9 11)</tt>.
</li>
<li>
<p> What is the order of growth in the number of steps required by <tt>list->tree</tt> to convert a list of n elements?
</li>
</ul>
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.65:</b> Use the results of Exercise 2-63 and Exercise 2-64 to give $\Theta(n)$ implementations of <tt>union-set</tt> and <tt>intersection-set</tt> for sets implemented as (balanced) binary trees.<a name="footnote_link_2-41" class="footnote_link" href="#footnote_2-41">41</a>
</div>
<h4> Sets and information retrieval </h4>
<p> We have examined options for using lists to represent sets and have seen how the choice of representation for a data object can have a large impact on the performance of the programs that use the data. Another reason for concentrating on sets is that the techniques discussed here appear again and again in applications involving information retrieval.
<p> Consider a data base containing a large number of individual records, such as the personnel files for a company or the transactions in an accounting system. A typical data-management system spends a large amount of time accessing or modifying the data in the records and therefore requires an efficient method for accessing records. This is done by identifying a part of each record to serve as an identifying <tt>key</tt> . A key can be anything that uniquely identifies the record. For a personnel file, it might be an employee's ID number. For an accounting system, it might be a transaction number. Whatever the key is, when we define the record as a data structure we should include a <tt>key</tt> selector procedure that retrieves the key associated with a given record.
<p> Now we represent the data base as a set of records. To locate the record with a given key we use a procedure <tt>lookup</tt>, which takes as arguments a key and a data base and which returns the record that has that key, or false if there is no such record. <tt>Lookup</tt> is implemented in almost the same way as <tt>element-of-set?</tt>. For example, if the set of records is implemented as an unordered list, we could use
<div id="scheme-define-lookup">
(define (lookup given-key set-of-records)
(cond ((null? set-of-records) false)
((equal? given-key (key (car set-of-records)))
(car set-of-records))
(else (lookup given-key (cdr set-of-records)))))
</div>
<script>
prompt("scheme-define-lookup");
</script>
<p> Of course, there are better ways to represent large sets than as unordered lists. Information-retrieval systems in which records have to be ``randomly accessed'' are typically implemented by a tree-based method, such as the binary-tree representation discussed previously. In designing such a system the methodology of data abstraction can be a great help. The designer can create an initial implementation using a simple, straightforward representation such as unordered lists. This will be unsuitable for the eventual system, but it can be useful in providing a ``quick and dirty'' data base with which to test the rest of the system. Later on, the data representation can be modified to be more sophisticated. If the data base is accessed in terms of abstract selectors and constructors, this change in representation will not require any changes to the rest of the system.
<div class="exercise">
<b>Exercise 2.66:</b> Implement the <tt>lookup</tt>
procedure for the case where the set of records is structured as a binary tree,
ordered by the numerical values of the keys.
</div>
<h3> Example: Huffman Encoding Trees </h3>
<p> This section provides practice in the use of list structure and data abstraction to manipulate sets and trees. The application is to methods for representing data as sequences of ones and zeros (bits). For example, the ASCII standard code used to represent text in computers encodes each character as a sequence of seven bits. Using seven bits allows us to distinguish 2^(7), or 128, possible different characters. In general, if we want to distinguish n different symbols, we will need to use <tt>log</tt>_2 n bits per symbol. If all our messages are made up of the eight symbols A, B, C, D, E, F, G, and H, we can choose a code with three bits per character, for example
<pre>
A 000 C 010 E 100 G 110
B 001 D 011 F 101 H 111
</pre>
<p> With this code, the message
<pre>
BACADAEAFABBAAAGAH
</pre>
<p> is encoded as the string of 54 bits
<pre>
001000010000011000100000101000001001000000000110000111
</pre>
<p> Codes such as ASCII and the A-through-H code above are known as <tt>fixed-length</tt> codes, because they represent each symbol in the message with the same number of bits. It is sometimes advantageous to use <tt>variable-length</tt> codes, in which different symbols may be represented by different numbers of bits. For example, Morse code does not use the same number of dots and dashes for each letter of the alphabet. In particular, E, the most frequent letter, is represented by a single dot. In general, if our messages are such that some symbols appear very frequently and some very rarely, we can encode data more efficiently (i.e., using fewer bits per message) if we assign shorter codes to the frequent symbols. Consider the following alternative code for the letters A through H:
<pre>
A 0 C 1010 E 1100 G 1110
B 100 D 1011 F 1101 H 1111
</pre>
<p> With this code, the same message as above is encoded as the string
<pre>
100010100101101100011010100100000111001111
</pre>
<p> This string contains 42 bits, so it saves more than 20% in space in comparison with the fixed-length code shown above.
<p> One of the difficulties of using a variable-length code is knowing when you have reached the end of a symbol in reading a sequence of zeros and ones. Morse code solves this problem by using a special <tt>separator code</tt> (in this case, a pause) after the sequence of dots and dashes for each letter. Another solution is to design the code in such a way that no complete code for any symbol is the beginning (or <tt>prefix</tt> ) of the code for another symbol. Such a code is called a <tt>prefix code</tt> . In the example above, A is encoded by 0 and B is encoded by 100, so no other symbol can have a code that begins with 0 or with 100.
<p> In general, we can attain significant savings if we use variable-length prefix codes that take advantage of the relative frequencies of the symbols in the messages to be encoded. One particular scheme for doing this is called the Huffman encoding method, after its discoverer, David Huffman. A Huffman code can be represented as a binary tree whose leaves are the symbols that are encoded. At each non-leaf node of the tree there is a set containing all the symbols in the leaves that lie below the node. In addition, each symbol at a leaf is assigned a weight (which is its relative frequency), and each non-leaf node contains a weight that is the sum of all the weights of the leaves lying below it. The weights are not used in the encoding or the decoding process. We will see below how they are used to help construct the tree.
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-53.gif">
<b>Figure 2.18:</b> A Huffman encoding tree.
</div>
<p> Figure 2-18 shows the Huffman tree for the A-through-H code given above. The weights at the leaves indicate that the tree was designed for messages in which A appears with relative frequency 8, B with relative frequency 3, and the other letters each with relative frequency 1.
<p> Given a Huffman tree, we can find the encoding of any symbol by starting at the root and moving down until we reach the leaf that holds the symbol. Each time we move down a left branch we add a 0 to the code, and each time we move down a right branch we add a 1. (We decide which branch to follow by testing to see which branch either is the leaf node for the symbol or contains the symbol in its set.) For example, starting from the root of the tree in Figure 2-18, we arrive at the leaf for D by following a right branch, then a left branch, then a right branch, then a right branch; hence, the code for D is 1011.