Discrete Mathematics With Coding
Discrete Mathematics With Coding
with Coding
For a first undergraduate course in discrete mathematics, this book systematically explores the
relationship between discrete mathematics and computer programming. Unlike most discrete
mathematics texts focusing on one or the other, Discrete Mathematics with Coding investigates
the rich and important connection between these two disciplines and shows how each rein-
forces and enhances the other.
The mathematics in the book is self-contained, requiring only a good background in precalculus
and some mathematical maturity. New mathematical topics are introduced as needed.
The coding language used is VBA Excel. The language is easy to learn, has intuitive commands,
and the reader can develop interesting programs from the outset. Additionally, the spreadsheet
platform in Excel makes for convenient and transparent data input and output and provides a
powerful venue for complex data manipulation. Manipulating data is greatly simplified using
spreadsheet features, and visualizing the data can make programming and debugging easier.
The VBA language is seamlessly integrated into the spreadsheet environment with no other
resources required. Furthermore; as some of the modules in the book show, intricate patterns,
graphs, and animation in the form of moving cells is possible.
Features
Abstract Algebra
A First Course, Second Edition
Stephen Lovett
Classical Analysis
An Approach through Problems
Hongwei Chen
Probability and Statistics for Engineering and the Sciences with Modeling using R
William P. Fox and Rodney X. Sturdivant
https://www.routledge.com/Textbooks-in-Mathematics/book-series/CANDHTEXBOOMTH
Discrete Mathematics
with Coding
Hugo D. Junghenn
First edition published 2024
by CRC Press
6000 Broken Sound Parkway NW, Suite 300, Boca Raton, FL 33487-2742
Reasonable efforts have been made to publish reliable data and information, but the author and pub-
lisher cannot assume responsibility for the validity of all materials or the consequences of their use.
The authors and publishers have attempted to trace the copyright holders of all material reproduced
in this publication and apologize to copyright holders if permission to publish in this form has not
been obtained. If any copyright material has not been acknowledged please write and let us know so
we may rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced,
transmitted, or utilized in any form by any electronic, mechanical, or other means, now known or
hereafter invented, including photocopying, microfilming, and recording, or in any information stor-
age or retrieval system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, access www.copyright.com
or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923,
978-750-8400. For works that are not available on CCC please contact [email protected]
Trademark notice: Product or corporate names may be trademarks or registered trademarks and are
used only for identification and explanation without intent to infringe.
DOI: 10.1201/9781003351689
Typeset in CMR10
by KnowledgeWorks Global Ltd.
Publisher’s note: This book has been prepared from camera-ready copy provided by the authors.
TO MY FAMILY
Companions
in the
Great Adventure
Contents
Preface xv
I Essentials of VBA 1
1 Introduction 3
1.1 Modules, Subs, and Functions . . . . . . . . . . . . . . . . 3
1.2 Data Output and Input OutputExample,InputExample . . . 4
1.3 Cell Characteristics CellAttributes . . . . . . . . . . . . . 6
1.4 Number Formats NumberFormat . . . . . . . . . . . . . . . . 8
1.5 Passing Arguments SwitchIntegers . . . . . . . . . . . . . 8
1.6 User-Defined Data Types . . . . . . . . . . . . . . . . . . . 9
1.7 Command Buttons . . . . . . . . . . . . . . . . . . . . . . 10
1.8 Spin Buttons MixColors . . . . . . . . . . . . . . . . . . . . . 11
1.9 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 VBA Operators 15
2.1 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . 15
2.2 Comparison Operators . . . . . . . . . . . . . . . . . . . . 16
2.3 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3 Conditional Statements 19
3.1 The If Then Else Statement Grade . . . . . . . . . . . . . . 19
3.2 The Select Case Statement CycleEdges . . . . . . . . . . . . 21
3.3 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4 Loops 25
4.1 The For Next Statement . . . . . . . . . . . . . . . . . . . 25
4.2 The Do While Loop ReduceFraction, NumberOfTerms . . . . 26
4.3 The Do Until Loop . . . . . . . . . . . . . . . . . . . . . . . 27
4.4 Exit Statements . . . . . . . . . . . . . . . . . . . . . . . . 28
4.5 Finding the Zeros of a Function FindZero,FunctionVal . . . 28
4.6 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
vii
viii Contents
5 Arrays 35
5.1 Declaring Arrays . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2 First and Last Indices of an Array . . . . . . . . . . . . . . 36
5.3 Passing and Returning Arrays . . . . . . . . . . . . . . . . 36
5.4 Variants and the Array Function . . . . . . . . . . . . . . . . 37
5.5 Sorting Numeric Data NumericSort . . . . . . . . . . . . . . . 37
5.6 Finding Nearest Numbers NearestNumbers . . . . . . . . . . 39
5.7 Stacks Push,Pop . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.8 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6 String Functions 47
6.1 The VBA Concatenation Operator . . . . . . . . . . . . . . 47
6.2 The VBA Extraction Function Mid . . . . . . . . . . . . . 48
6.3 The VBA ASCII Functions Asc and Chr . . . . . . . . . . 50
6.4 VBA Data Conversion Functions CStr, CInt, CLng, CDbl . 51
6.5 The VBA Function Replace . . . . . . . . . . . . . . . . . . 51
6.6 The VBA Function InStr . . . . . . . . . . . . . . . . . . . 52
6.7 The VBA Operator Like . . . . . . . . . . . . . . . . . . . 54
6.8 The VBA Functions Join and Split . . . . . . . . . . . . . 54
6.9 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7 Grids 61
7.1 Setting up a Grid MakeGrid . . . . . . . . . . . . . . . . . . . 61
7.2 The Grid as a Torus TorusPoint . . . . . . . . . . . . . . . 64
7.3 Installing Coordinates in a Grid InstallCoord . . . . . . . 65
7.4 Sieve of Erastothenes Sieve . . . . . . . . . . . . . . . . . . 66
7.5 A Changing Rectangle CollapseExpandRectangle,Delay . . . 67
7.6 Table Sum Game TableSum . . . . . . . . . . . . . . . . . . 69
7.7 Finding the Nearest Cells NearestCells . . . . . . . . . . . 72
7.8 A Growing Spiral Spiral . . . . . . . . . . . . . . . . . . . 74
7.9 Billiard Ball BilliardBall . . . . . . . . . . . . . . . . . . . 77
7.10 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
8 Recursion 85
8.1 The Factorial Function FactRecursive . . . . . . . . . . . . 85
8.2 Binary Trees Binarytree . . . . . . . . . . . . . . . . . . . . 87
8.3 The Tower of Hanoi HanoiTower . . . . . . . . . . . . . . . 90
*8.4 A Complex Arithmetic Calculator ComplexCalc . . . . . . . 94
*8.5 A Polynomial Calculator PolyCalc . . . . . . . . . . . . . . . 101
8.6 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
14 Determinants 273
14.1 Definition and Properties . . . . . . . . . . . . . . . . . . . 273
14.2 Determinants Using VBA DetEchelon,DetRecursive . . . . 275
14.3 Cramer’s Rule CramersRule . . . . . . . . . . . . . . . . . . . 277
14.4 Collinear and Coplanar Points Using Determinants . . . . 280
14.5 Areas and Volumes Using Determinants . . . . . . . . . . . . 281
14.6 Circumscribing a Triangle Circumcenter . . . . . . . . . . . 282
14.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
IV Combinatorics 341
18 Sets 343
18.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 343
18.2 The Union of Two Sets Union . . . . . . . . . . . . . . . . 344
18.3 The Intersection of Two Sets Intersection, Card . . . . . 345
18.4 The Complement of a Set Complement . . . . . . . . . . . . 346
18.5 Extensions to Three or More Sets . . . . . . . . . . . . . . 348
18.6 Calculating Sets with VBA SetCalculator . . . . . . . . . 348
18.7 Venn Diagram Components with VBA VennParts . . . . . . 351
18.8 Laws of Set Equality . . . . . . . . . . . . . . . . . . . . . 353
18.9 Laws of Set Inclusion . . . . . . . . . . . . . . . . . . . . . 355
18.10 Cartesian Products, Relations, and Functions . . . . . . . 356
18.11 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
19 Counting 359
19.1 The Addition Principle . . . . . . . . . . . . . . . . . . . . 359
*19.2 Venn Solutions with VBA Venn3Solver . . . . . . . . . . . 360
19.3 The Multiplication Principle . . . . . . . . . . . . . . . . . 364
19.4 Permutations . . . . . . . . . . . . . . . . . . . . . . . . . . 364
19.5 Generating Permutations with VBA Permutations . . . . . 365
19.6 Combinations . . . . . . . . . . . . . . . . . . . . . . . . . 366
19.7 Generating Combinations with VBA Combinations . . . . . 368
19.8 Traveling Salesman Problem TravelSales . . . . . . . . . . 370
*19.9 Permutation Algebra MultPerm, InvPerm, PowerPerm . . . . 373
*19.10 Permutation Cycles PermCycles . . . . . . . . . . . . . . . . 376
19.11 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
V Probability 381
20 Probability 383
20.1 Sample Spaces, Probabilities, and Events . . . . . . . . . . 383
20.2 Throwing a Pair of Fair Dice DiceRelativFreq . . . . . . . 385
20.3 Poker Hands PokerHands . . . . . . . . . . . . . . . . . . . 386
20.4 Drawing Balls from an Urn . . . . . . . . . . . . . . . . . . 389
20.5 Simulation of the Binomial Distribution GaltonsBoard . . . . 391
20.6 Conditional Probability . . . . . . . . . . . . . . . . . . . . 394
20.7 Bayes’ Theorem . . . . . . . . . . . . . . . . . . . . . . . . 395
20.8 Disease Testing TruePosTrueNeg . . . . . . . . . . . . . . . . 397
20.9 Independence . . . . . . . . . . . . . . . . . . . . . . . . . 399
20.10 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
xii Contents
24 Congruence 457
24.1 Definition and Basic Properties . . . . . . . . . . . . . . . . 457
24.2 Congruence Arithmetic . . . . . . . . . . . . . . . . . . . . 458
24.3 Fermat’s Little Theorem . . . . . . . . . . . . . . . . . . . 459
24.4 Remainder of a Product ProductRmdr . . . . . . . . . . . . 460
24.5 Remainder of a Power PowerRmdr . . . . . . . . . . . . . . . 462
24.6 Solving Congruence Equations CongruenceSolver . . . . . . 463
*24.7 Modular Arithmetic CongruenceTables . . . . . . . . . . . . 464
24.8 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
25 Cryptography 467
25.1 Encoding the Alphabet . . . . . . . . . . . . . . . . . . . . . 467
25.2 Caesar’s Shift Cipher . . . . . . . . . . . . . . . . . . . . . 468
Contents xiii
Index 525
Preface
xv
xvi Preface
generator, are admittedly somewhat whimsical. But each example has been
chosen to illustrate particular coding constructs or techniques, and if a program
is visually engaging, so much the better. The modules developed in the book are
open-ended in the sense that the reader may tinker with the code to produce
modifications and extensions. Additionally, many of the coding exercises explore
new ideas. The code for the examples and exercises is available on my blog
blogs.gwu.edu/hdj.
The book has benefitted from my fortunate experience over the years in
teaching courses on discrete mathematics and math foundations. An effort was
made in these courses to emphasize the algorithmic nature of mathematics.
The book attempts, via code, to give full expression to this philosophy.
Finally, many thanks go to my editor Bob Ross for his invaluable guidance
and suggestions and to the staff at Taylor & Francis/CRC Press for their
professionalism in the development of this book.
Hugo D. Junghenn
George Washington University
Washington, D.C.
Part I
Essentials of VBA
Chapter 1
Introduction
In this chapter we describe some general features of Excel VBA, leaving coding
constructs such as conditionals and loops to later chapters. The reader is
assumed to have some familiarity with entering data into a spreadsheet and
using the arrow keys to navigate among the cells.
The VBA editor works like most editors but with some additional features
that help catch errors and make the process of coding more efficient. Once
in the editor window you can begin writing the module. Click “View Code”
under the Developers tab in the spreadsheet to get to the editor. Use ALT +
F11 to switch between editor and spreadsheet.
A module consists of one or more building blocks called procedures. These
are collections of statements executed together as a unit. Breaking up a lengthy
program into smaller procedures can improve efficiency and greatly enhance
clarity, allowing the overall logic of the program to emerge unfettered by details.
Such partitioning can also reduce code and simplify the process of debugging,
an unfortunate but inevitable and all too frequent aspect of programming.1
1 On the other hand, debugging can sometimes be an interesting logical challenge and
DOI: 10.1201/9781003351689-1 3
4 Discrete Mathematics and Coding
There are two types of procedures, sub procedures and function procedures.
They have the following similar forms:
Sub name() Function name()
Declaration of variables Declaration of variables
Statements Statements
End Sub End Function
The essential distinction between the two types of procedures is that a function
can return data while a sub cannot. However, a sub can always return data
through an argument, discussed later.
The reader may see in some sources the word Private preceding the dec-
laration Sub or Function. With this modifier the procedure may be accessed
only from another procedure in the same module. Without the modifier, the
procedure can be accessed from other modules. Since all of our programs are
single modules, the prefix Private will usually be omitted. The exception is in
the case of user defined data types, discussed in Section 1.6.
Outputting Data
The following module consists of a single sub procedure. The program does
nothing more than output text in cell A2 of Sheet1 using the Range object.
Sub OutputExample()
Sheet1.Range("A2").Value = "GREETINGS, PLANET EARTH!"
End Sub
Alternate code that accomplishes the same thing uses the Cells object, which
has the form Cells(row,column). For example, replacing the middle line of the
above code by
Sheet1.Cells(2,1).Value = "GREETINGS, PLANET EARTH!"
produces exactly the same output. Note that the row-column order is reversed
in the two notations: A2 and (2, 1) both refer to the cell located in column 1
and row 2 of Sheet1. The Cells object is particularly useful when one needs to
treat the spreadsheet as a coordinate system or when many data items need
to be read or printed.
The above project may be saved as a Macro-Enabled Workbook. To run the
program go to the text editor and click “run.” The output will then appear in
Introduction 5
Sheet1. Using the prefix “Sheet2” or “Sheet3” outputs the data accordingly.
This is occasionally useful if, for example, data needs to be “hidden” or stored
for another program run. If all output is to go to Sheet1, then the prefix may
be omitted, as it is the default.
Inputting Data
The Range and Cells objects mentioned above may also be used to input
data, that is, to read data from the spreadsheet into variables. These are
user-chosen names that refer to locations in the computer’s memory. VBA
allows many types of variables. The list below describes the most common of
these and the ones that we shall use throughout the book. Detailed descriptions
of these and other data types may be found online.
Here’s simple example that illustrates some of the features of data assign-
ment. Other features appear in examples throughout the book.
Sub InputExample()
Dim v1 As Double, v2 As Integer, v3 As Currency, v4 As String
v1 = Range("A3").Value 'read data from spreadsheet into v1
v2 = v1 'assign the value of v1 to v2
v3 = v1 'and to v3
v4 = v1 'and to v4
Range("B3").Value = v2 'output the values in cells B3, C3, D3
Range("C3").Value = v3
Range("D3").Value = v4
End Sub
Notice how the data types of the variables v1,v2,v3,v4 are declared in the
first line of the code using the keyword Dim. In the second line the program
reads a numerical quantity that was presumably entered by the user in cell A3.
Running the program causes the value to be assigned to the variable (memory
6 Discrete Mathematics and Coding
location) v1 and subsequently to the variables v2,v3,v4. The results are then
printed in cells B3, C3, and D3.
The text following the apostrophes in the above procedure is meant to
elucidate the code; it is ignored by the Excel compiler. While the code here
is largely self-explanatory, programs can be quite complex, and liberal use of
comments greatly enhances clarity. It is not uncommon for a programmer to
return to past code and wonder what the program is supposed to be doing.
(The author admits to being guilty of this on more than one occasion.)
The spreadsheet corresponding to the above procedure is depicted below.
Notice how the data output in cells B3, C3, and D3 conforms to the data
type: the original value in A3 is printed as a rounded integer in B3, as a
currency in C3, and as a string (text) in D3. VBA performs these conversions
automatically.
A B C D
3 1234.567 1235 $1,234.57 1234.567
We have used short names for the variables, but it is frequently the case
that longer names are needed to clarify the code. For example, instead of v1
we could have used any one of the following standard forms varOne, VarOne, or
var_one. Here are the rules for naming a variable:
A B C
1
2 GREETINGS,
3 PLANET EARTH !
The first two lines in the procedure expand the column width and row
height of the spreadsheet from their standard values (8.34 points and 15 points,
respectively). The code Range("A2:C3") is an example of the block feature of
the Range object. One may also use Range(Cells(2,1),Cells(3,3)). The font
“Times New Roman” is one of many that are available. The font styles are “Reg-
ular”, “Italic”, “Bold”, and “Bold Italic”. In addition to Font.Underline there
are the attributes Font.Strikethrough, Font.Subscript, and Font.Superscript.
The above procedure uses the VBA ColorIndex property to set the colors
of the interior and border of the range A2:C3. Color indices have values 1–56.
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
A B C D
1 1234.000 1,234 $1,234.00 1234
the number 1234 into cells A1 to D1. The cells are then formatted in various
ways with output shown in Figure 1.2.
Sub NumberFormat()
Range("A1:D1").Value = 1234 'output 1234 to cells in block
Range("A1").NumberFormat = ".000" 'produces 1234.000
Range("B1").NumberFormat = "#,###" 'produces 1,234
Range("C1").NumberFormat = "$#,##0.00" 'produces $1,234
Range("D1").NumberFormat = "General" 'produces 1234
End Sub
The reader may wish to experiment with other formats and cell attributes.
The ones described in this section are sufficient for our purposes.
Sub SwitchIntegers()
Dim m As Integer, n As Integer
m = 3: n = 7
Call SwitchInt(m, n)
Range("A4").Value = m: Range("B4").Value = n 'prints 7,3: switched
Call NoSwitchInt(m, n)
Range("A3").Value = m: Range("B3").Value = n 'prints 3,7: failed
End Sub
In the above code we have used a feature of VBA Excel that allows several
statements, separated by colons, to be placed on the same line. While this is a
handy space-saving device, it should be used only when it does not compromise
readability. (The author admits to occasionally ignoring his own advice in this
regard.)
A UDT declaration must be placed at the top of the module and declared
Private. Any procedure passing a UDT variable must also be declared Private.
UDT’s will be used frequently in later chapters.
• In the Developer tab, click Insert and then under ActiveX Controls click
Command Button. Click the worksheet location where you want the
button to be placed. The box may be dragged to other locations and
expanded or contracted.
• Assign code to the button as follows: Right-click on the button and then
click ‘view code’. In the resulting sub procedure that appears in the VBA
editor window, type the name of the procedures you wish to run from
the button and any additional code.
• To assign a caption to the button, right-click the button, and then click
CommandButtonObject, Edit.
• To change the properties of the button, right-click the button and then
click Format Control or Properties.
• To delete a command button, select Visual Basic from the Developer tool
bar, click Design Mode, move to the button, and hit the delete key.
To illustrate how a command button works, let’s add two buttons to the
procedure NumberFormat, one to run the program and the other to restore
the format settings to their defaults and clear the numeric content of the
spreadsheet. Here is the additional code needed:
• In the Developer tab, click Insert and then under ActiveX Controls click
Spin Button. Next, click the worksheet location where you want the
button to be placed. The box may be dragged to other locations and
expanded or contracted.
• Assign code to the button as follows: Right-click on the button and then
click ‘view code’. In the resulting code that appears in the VBA editor
window, type the name of the procedures you wish to run from the button
and any additional instructions.
• To delete a spin button click Design Mode in the Developers tab, move
to the button and hit the delete key (gently).
The module MixColors below uses a spin button to display the colors
available with the VBA function RGB. This function, together with the VBA
Color property, allows one to create hundreds of colors and hues. The syntax of
the function is RGB(red,green,blue), where the arguments red,green,blue are
integers between 0 and 255 that determine the proportions of red, green, and
blue in the color. For example, RGB(255,0,0) yields red, RGB(0,255,0) yields
green, and RGB(0,0,255) yields blue. Varying the values of the arguments
red,green,blue produces mixtures of these colors. For example, the code
snippet Range("B2").Interior.Color = RGB(249,251,219) colors the interior of
cell B2 a pale yellow.
To run the program the user enters integers from 0 to 255 in each of the
cells B4, C4, and D4, these holding values of the arguments red,green,blue of
the function RGB. Depressing the arrow keys changes the numbers and places
12 Discrete Mathematics and Coding
the corresponding color in cell B4. Figure 1.3 depicts part of the spreadsheet
showing values that result in a lavender.
A B C
1 R G B
2
3
4 240 140 255
5
Here is the code for the module. The spin buttons are linked to the cells A4,
B4, and C4; the range of values is 0–255 in steps of 1. Linking is accomplished
by right clicking on the spin button in Design mode and then filling in the
appropriate entries in the pop-up Properties box.
Sub SpinButton1_Change() 'linked to A4, 0 - 255 in steps of 1
Dim i As integer, j As integer, k As Integer
i = Range("A4").Value: j = Range("B4").Value: k = Range("C4").Value
Range("A5:C5").Interior.Color = RGB(i,j,k) 'print the color
End Sub
1.9 Exercises
1. Experiment with the procedure CellAttributes by altering values, chang-
ing colors, fonts, styles, etc. Use the With-End statement.
2. Write a procedure ElbowPath(row1 As Int, col1 As Int, row2 As Int,
col2 As Int) with a command button that takes as arguments user-
entered positions of two cells, row1,col1 and row2,col2, and draws an
Introduction 13
L-shaped yellow path from one cell to the other (see Figure 1.4). Use the
block feature of the Range object to draw and then erase the path, using
the color index xlNone for the latter. Insert the statement MsgBox"clear"
after the drawing part of the code and before the erasing part and see
what is does.
1,1
3,5
A B
1 run program
2 fiddlefaddle
3 text: fiddlefaddle
4 font: Times New Roman
5 color index: 3
+ addition
− subtraction
∗ multiplication
/ division
ˆ exponentiation
The operators follow the usual order of precedence in arithmetic. For example,
in the code 2 ∗ 3ˆ4 + 5/(6 − 7 ∗ 8), exponentiation is carried out before the
multiplication, parentheses before the division, and multiplication and division
before addition and subtraction. It should be noted that Excel has a feature
that calculates such expressions directly in a spreadsheet cell. However, this
feature may be impractical if complicated arithmetic calculations must be
performed on large data sets. Coding these operations is then a more reasonable
approach.
There are four other arithmetic operators that are of importance:
The first operator rounds down a number to the next lowest integer value. For
example Int(2.99) = 2 and Int(−2.01) = −3. The operation a Mod b produces
the remainder on division of the integer a by the integer b. For example, the
statement 14 Mod 3 returns the integer 2. The operation a\b divides the integer
DOI: 10.1201/9781003351689-2 15
16 Discrete Mathematics and Coding
a by the integer b, discards the remainder, and returns the integer part. For
example, 14\3 = 4. The operators are related by the equation
as illustrated by
Finally, the operator Abs returns a number without the sign. For example,
Abs(−2) = 2 = Abs(2).
Recall that equality is used to assign values to variables. For example, the code
x = 5 assigns the value 5 to the memory location called x. One can take this a
step further by having the right side of the assignment contain the variable
x. For example, the code x = x+2 tells the computer to add 2 to the current
value of x, which was 5, and place the resulting value 7 in the memory location
called x.
The first two connectives extend to arbitrarily many statements. For example,
the code Range("A1").Value = 2 < 3 And Not 3 < 4 Or 5 < 6 places the word
True in cell A1. The order of precedence of the operations in this statement is as
follows: After the inequalities are assigned truth values, the statement becomes
True And Not True Or True. The Not statement is then evaluated, producing
True And False Or True. Next in precedence is the And statement, yielding
False Or True. Finally, the Or statement is evaluated, producing True.
Parentheses may be used to change operator precedence. For example, the
code 2 < 3 And Not (3 < 4 Or 5 < 6) returns the value False.
If operators from more than one category appear in a line of code, they are
evaluated in the order (1) arithmetic operators, (2) comparison operators, and
(3) logical operators.
2.4 Exercises
1. Write a function Triangle that takes three lengths a, b, and c and returns
True if these can be the lengths of a triangle and False otherwise. (Hint:
The sum of two sides must be greater than the third.) Test the function
by writing a program with a command button that reads the values
of a, b, and c entered in the spreadsheet and prints out True or False
accordingly.
2. Write a function NumSeconds(h,m,s) that takes the elapsed time in hours
h, minutes m, and seconds s, and returns the number of seconds. For
example, NumSeconds(1,25,43) should return 5143. Test the function with
a program that prints out the answer. Use a command button.
3. Write a procedure TestArithOps that reads user-entered numbers a, b
from the spreadsheet and prints the difference a Mod b − b ∗ (a/b − a\b),
(which should always be zero). Use a command button.
4. Write a procedure SpinArith that uses a Spin Button to change the values
of an arithmetic expression entered in the spreadsheet. For example, you
could link spin buttons to A3, A4, and A5 and enter expressions like
= A2^2 + B2^2 + C2^2 in cell A4 (note the required equals sign).
If condition1 Then
statements1
ElseIf condition2 Then
statements2
...
ElseIf conditionk Then
statementsk
Else
statements
End If
There may be many ElseIf statements or none at all. The code executes
as follows: if condition1 is true, then statements1 are executed and control
passes to the statement following End If. On the other hand, if condition1 is
false, then condition2 is tested, etc. The Else statement, which is optional, is
executed if conditions 1 to k are false. Figure 3.1 is a schematic of the logic
for the case k = 3. It shows how the flow of the program depends on the truth
values of the conditions in the diamond-shaped boxes.
For a simple example we consider the procedure Grade below, which uses an
If Then Else statement to determine the letter grade of a test score. A score
from 0 to 100 is entered in cell B3 and the program prints the corresponding
letter grade in cell B4.
DOI: 10.1201/9781003351689-3 19
20 Discrete Mathematics and Coding
start
yes
condition 1
true?
no
execute yes
statements 1 condition 2
true?
no
execute
execute statements 2
statements 3
end
Sub Grade()
Dim score As Single, grade as String 'declare variables
score = Range("B3").Value 'read score 0 to 100 from spreadsheet
If score >= 90 Then
grade = "A" 'exit the statement and output grade A
ElseIf score >= 80 Then
grade = "B" 'exit the statement and output grade B
ElseIf score >= 70 Then
grade = "C" 'etc.
ElseIf score >= 60 Then
grade = "D"
Else
grade = "F"
End If
Range("B4").Value = grade 'output letter grade
End Sub
The code works like this: The numeric quantity TestThisQuantity is tested
against conditions 1 to k in that order. If condition1 is found to be true, then
the code statements1 is executed and control passes to the statement following
End Select. If condition1 is false, then the next condition is tested, etc. If
none of the conditions is true, then the statements under Case Else (which is
optional) are executed.
We illustrate the Select Case statement with a spin button procedure that
adds edges to a cell using the Cells.Borders feature of VBA. A variety of
such edges is available as well as a facility to remove them. For example, the
following code snippet places and then removes the left edge of a cell:
Sub SpinButton1_Change()
Dim row As Integer, col As Integer, edge As Integer, n As Integer
row = 2: col = 2 'cell B2 displays the edges
n = Range("A3").Value 'print spin button value in A3
'delete any previous edges and diagonals
Cells(row, col).Borders.LineStyle = xlNone
Cells(row, col).Borders(xlDiagonalDown).LineStyle = xlNone
Cells(row, col).Borders(xlDiagonalUp).LineStyle = xlNone
22 Discrete Mathematics and Coding
1 2 3 4 5 6
3.3 Exercises
1. Write a function EvenOdd that takes a positive integer and returns the
string “even” if the number is even and “odd” otherwise. Write code
that tests the function using a command button.
2. Write a procedure Arithmetic that reads Double values x, y entered in
the spreadsheet and returns x + y, x − y, x ∗ y, or x/y depending on the
instruction add, subtract, multiply, or divide entered (as strings) in the
spreadsheet. Use a Select Case statement.
3. Use the If Then Else statement in a function Max(a,b,c) that returns
the maximum (largest) of the (Double) numbers a,b,c. Do the same for
the minimum. Incorporate the function into a module with a command
button that takes numbers a,b,c entered into the spreadsheet by the
user and prints out the maximum and minimum values as well as the
value Min(a,b,c) + Max(-a,-b,-c), which should always be zero (why?).
4. Write a function SecondLargest(a,b,c) that takes three distinct Double
values and returns the second largest. Incorporate the function into a
module with a command button.
Conditional Statements 23
A B C
4 a= 1
5 b= 2
6 c= 3
7 real part imaginary part
8 solutions: −1 1.41421354
9 −1 −1.41421354
Figure 4.1 illustrates the flow of logic. The variable counter is given the initial
start
counter =
firstval
execute loop
statements
update
counter
counter =
lastval? no
yes
end
DOI: 10.1201/9781003351689-4 25
26 Discrete Mathematics and Coding
value firstval, the statements in the body of the loop are exercised, and
counter is incremented by the amount x, which can be negative. The process
is repeated, the final iteration occurring when counter has the value lastval.
If the code Step x is omitted, then the step is taken to be 1.
Do While condition Do
statements statements
Loop Loop While condition
In the version on the left, the Boolean expression condition is tested before
statements are executed; in the version on the right it is tested afterwards.
The looping continues as long as condition is True. Figure 4.2 illustrates the
logical flow.
start start
execute loop
false statements
condition
true true
condition
execute loop
end statements
false
end
The example below uses both the For Next and the Do While statements.
The program reads two Long integers, N1, D1, and reduces the fraction N1/D1
to its lowest terms by canceling common factors.
The program uses the VBA message feature MsgBox, which displays a message
until the icon OK is clicked.
start start
execute loop
statements
true
condition
false
false
condition
execute loop
end statements
true
end
In the version on the left, condition is tested before statements are executed;
in the version on the right it is tested after. Unlike Do While loops, Do
Until looping continues as long as condition is false. We give an example in
Section 4.5.
formula. However, in many cases one must rely on algorithms that produce
only approximations. The simplest such algorithm is the interval halving or
bisection method, which works for continuous functions, that is, those that
have no gaps or jumps in their graphs.
a z b
I1
I2
I3
I4
Sub CommandButton1_Click()
Dim left As Double, right As Double, z As Double
Dim accuracy As Double, error As Boolean, expr As String
30 Discrete Mathematics and Coding
The function FindZero takes the input data and returns an approximate
zero of the function, if possible. A Do Until loop carries out the bisections.
For each new interval, the procedure FunctionVal calculates the values of the
function at the left endpoint, right endpoint, and midpoint. A new interval is
determined from these by testing signs at these points, as mentioned earlier.
Function FindZero(expr As String, left As Double, right As Double, _
accuracy As Double, error As Boolean) As Double
Dim mid As Double, lValue As Double, rValue As Double
Dim mValue As Double, z As Double
Do
mid = (left + right) / 2 'get midpoint of current interval
lValue = FunctionVal(expr, left) 'function values at left,
rValue = FunctionVal(expr, right) 'right, and
mValue = FunctionVal(expr, mid) 'mid points
If lValue * rValue > 0 Then error = True: Exit Do 'check interval
If lValue = 0 Then z = left: Exit Do 'exit if zero found
If rValue = 0 Then z = right: Exit Do
If mValue = 0 Then z = mid: Exit Do
If lValue * mValue < 0 Then 'if different signs, then
right = mid 'new interval is left half
ElseIf rValue * mValue < 0 Then 'if different signs, then
left = mid 'new interval is right half
End If
z = mid 'tentative zero
Loop Until right - left < accuracy 'keep getting better approx.
FindZero = z
End Function
4.6 Exercises
1. Use a For Next loop in a function that returns the factorial of a nonneg-
ative integer n, defined by
n! = n · (n − 1) · (n − 2) · · · 3 · 2 · 1, 1! = 1, 0! = 1.
is a Pythagorean triple, as the reader may check. (It may be shown that
all Pythagorean triples are of this form.)
32 Discrete Mathematics and Coding
10. It may be shown that every positive integer can be written as the sum
of 4 perfect squares (some of which may be 0). For example,
2 = 12 + 12 + 02 + 02 , 5 = 22 + 12 + 02 + 02 , 79 = 12 + 22 + 52 + 72 .
A B C
3 num trials 50,000
4 lower limit 0
5 upper limit .7
6 sin cos
7 percentage hits 24.676 24.682
12. Write a program Collatz that starts with a user-entered positive integer
n and prints in a column the results of the following steps:
(1) If n is even, print n/2; if n is odd print 3n + 1.
(2) Repeat (1) with the number obtained.
For example, for n = 17 the steps are
17 → 52 → 26 → 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
Loops 33
The Collatz conjecture asserts that the process will eventually produce
the cycle 4,2,1 forever. (As of 2020, this has been found to be the case
for all initial values up to 268 .)
13. Every positive integer n of the form 8k + 1, 8k + 3, or 8k + 5 may be
written as the sum of 3 perfect squares. For example,
8 · 2 + 1 = 42 + 12 + 02 , 8 · 2 + 3 = 32 + 32 + 12 , 8 · 2 + 5 = 42 + 22 + 12 .
A B C D E
3 r 3
4 U 50
5 k 8k + r a b c
6 0 3 1 1 1
7 1 11 1 1 3
8 2 19 1 3 3
9 3 27 1 1 5
10 3 27 3 3 3
11 4 35 1 3 5
12 5 43 3 3 5
3.141592653589793238462643383279502884197169399375105820974944
A B
3 num terms
4 pi to 14
5 approximations errors
6 3.14157355512957 0.00001909846022
7 3.14161265318978 0.00001999959999
8 3.14159265320780 0.00000000038199
An array is a named list of variables of the same type whose entries may
be accessed by indices. Arrays greatly enhance the flexibility and power of
programs and are indispensable for certain tasks. In this chapter we describe
these data structures and illustrate their use in various examples.
DOI: 10.1201/9781003351689-5 35
36 Discrete Mathematics and Coding
Arrays may be allocated during run time. For example, the code snippet
ReDim arr(1 To size) uses the ReDim statement to allocate memory after the
variable size has been determined by the program. We illustrate this idea in
later modules.
The same result is achieved by using the For Each Next statement to select
the items in Arr:
Dim Arr As Variant, item As Variant, k As Integer
Arr = Array(2.3, "dog", 1 = 2) 'generate Arr with Array function
For Each item In Arr
Cells(3 + k, 1).Value = item 'print members of Arr
k = k + 1
Next item
which returns the row number of the last nonempty cell of column col. The
array data is then allocated dynamically using the ReDim statement. The
procedure reads the data into the array and passes it to the sorting procedure
BubbleSort. The latter sorts the data, which is then printed in the column
next to the original data.
38 Discrete Mathematics and Coding
Sub NumericSort()
Dim data() As Double, i As Integer
Dim numData As Integer, firstRow As Integer, lastRow As Integer
firstRow = 3 'first row of data
lastRow = Cells(Rows.count, 1).End(xlUp).row 'last row of data
numData = lastRow - firstRow + 1
ReDim data(1 To numData) 'allocate memory dynamically for array
For i = 1 To numData 'read data starting at firstrow
data(i) = Cells(i - 1 + firstRow, 1).Value
Next i
Call BubbleSort(data) 'sort the array
For i = 1 To numData
Cells(i - 1 + firstRow, 2).Value = data(i) 'print sorted data
Next i
End Sub
4 3 2 1 1 1 1
3 4 4 4 3 2 2
2 2 3 3 4 4 3
1 1 1 2 2 3 4
i=1 i=1 i=1 i=2 i=2 i=3
j=2 j=3 j=4 j=3 j=4 j=4
FIGURE 5.1: Bubble sort of 4321.
We remark that the Sort Range function in Excel VBA can sort multiple
columns on a key. For example, the code
Range("A8":"D17").Sort Key1:=Range("B8"), Order1:=xlAscending,Header:=xlNo
sorts in increasing order the data in B8:B17 as well as (in tandem) the rest
of the data in the block A8:D17. The procedure BubbleSort is nonetheless
occasionally useful in programs requiring sorted arrays.
B C D E
2 k= 3
3 1.4 0.7 2.3 3.5
4 0.7 1.4 2.3 3.5
5 3.5 4.1 2.3 1.4
6 2.3 1.4 3.5 0.7
7 4.1 3.5 2.3 1.4
The main procedure of the module first determines the number of data items
by using the rows count feature described in the last section. It then reads
the data into the array Data with a For Next loop. A second loop repeatedly
calls the procedures FindNear and PrintNear. For each i, the former finds the
indices of Data corresponding to k numbers nearest Data(i) and stores these in
the index array idxNear. The procedure PrintNear prints the k numbers next
to data item Data(i) in column B.
Sub NearestNumbers()
Dim Data() As Double, numData As Integer, i As Integer, k As Integer
Dim idxNear() As Integer, firstRow As Integer, lastRow As Integer
firstRow = 4 'first row of data
lastRow = Cells(Rows.count, 2).End(xlUp).row 'last row of data
numData = lastRow - firstRow + 1
40 Discrete Mathematics and Coding
The procedure FindNear is passed the current index i, the array Data and
the integer k. The outer For Next loop finds k numbers in Data nearest to
the data item Data(i) (excluding Data(i)) and stores the k indices of the
data in idxNear. This is accomplished by two For Next loops, the first to
get a candidate for an available nearest number and the second to find an
actual nearest number. The VBA absolute value function Abs is used to test
to measure nearness of the numbers.
Function FindNear(i, Data() As Double, k As Integer) As Integer()
Dim n As Integer, j As Integer, nearest As Double
Dim idxNear() As Integer, numData As Integer
ReDim idxNear(1 To k) 'storage for indices of Data array
numData = UBound(Data)
For n = 1 To k 'get k nearest numbers to Data(i)
For j = 1 To numData 'get a candidate for a nearest no.
If j <> i And IsAvailable(j, idxNear) Then
nearest = Data(j) 'found a candidate for a nearest no.
idxNear(n) = j 'store its index
Exit For
End If
Next j
For j = 1 To numData 'get nearer no. from unused Data
If j <> i And IsAvailable(j, idxNear) Then
If Abs(Data(i) - Data(j)) < Abs(Data(i) - nearest) Then
nearest = Data(j) 'found a nearer number
idxNear(n) = j 'store its index
End If
End If
Next j
Next n
FindNear = idxNear
End Function
The function IsAvailable used in the two inner For Next loops of FindNear
determines whether an index j is already in idxNear, that is, whether a data
item is already in the list of numbers closest to the current entry of Data. If it
is, then the function returns False, resulting in no action for that iteration.
Arrays 41
The program runs fairly quickly. For example, the reader may test its
speed by entering the numbers 1 to 100 in column A and taking k = 20.
More complicated data may be entered automatically using a random number
generator (Section 10.1).
5.7 Stacks
A stack is an abstract data type that may viewed as a column of data
entries. There are two main operations on a stack, push and pop. The former
places a data item on the top of the stack if the stack is not full, and the latter
removes a data item from the top of the stack if the stack is not empty. (See
Figure 5.5.) In this section we model stacks and the push and pop operations.
push
stack top 4 pop
stack top 3 3 stack top 3
2 2 2
1 1 1
For our stack we take a UDT that incorporates the data in the stack, the
size of the stack, and the index of the top of the stack.
42 Discrete Mathematics and Coding
The stack memory is the String data array in the UDT. The variable size refers
to the desired maximum memory of the data array, that is, Ubound(stack.data).
The variable top is the current top of the stack, that is, the largest index for
which the data array has items.
The procedure CreateStack, as the name implies, creates an instance stack
of the UDT. It is passed the variable size and returns a stack of that size.
The procedure Push takes a data item and, if there is room, places it on top
of the last one, incrementing the top of the stack by 1.
The function Pop takes a stack and returns the top item, decrementing the
top of the stack by 1.
Here’s a sample spreadsheet for the code below that shows the functions in
action. The spreadsheet illustrates the basic principle of stacks: last in, first
out.
Arrays 43
A B
3 push Aaron
4 push Betty
5 push Sally
6 pop Sally
7 pop Betty
8 pop Aaron
Sub TestPushPop()
Dim DataItem As String, stack As TStack
stack = CreateStack(3)
For n = 3 To Cells(Rows.Count, 1).End(xlUp).Row
If Cells(n, 1).Value = "push" Then 'push item in Cell(n,2)
Call Push(stack, Cells(n, 2).Value) 'onto stack
ElseIf Cells(n, 1).Value = "pop" Then 'pop item in Cell(n,2)
Cells(n, 2).Value = Pop(stack) 'from stack
End If
Next n
End Sub
5.8 Exercises
1. Write a function ArrayIndex(arr() As Integer, k As Integer) that
takes a positive integer array arr starting with index 0, and a posi-
tive integer k and returns the index of the first instance of the number k
in arr or returns −1 if k is not in the array.
2. Write a function LargestEntry that takes an array of integers starting at
index 1 and returns its largest entry.
3. Write a function LargestDiff that takes an array of numbers and
returns the absolute value of the largest difference. For example,
{4, 2, 3, 5, 8} → 6.
4. Write a function SumOdd that takes an array of positive integers and
returns the sum of the odd entries. For example, {7, 2, 3, 5, 6} → 16.
5. Write a function SumOddIdx(arr As Integer) that takes an array of posi-
tive integers and returns the sum of those entries in odd positions.
44 Discrete Mathematics and Coding
E D E
jam D C D
C
B B jerk C
A A A
VBA has a number of functions that manipulate strings (text). In this chapter
we describe the most common of these and the ones that will be needed in the
remainder of the book. We begin with the simplest operator, concatenation.
For j = 1 To 9
Cells(j, 1).Value = "A" & j
Next j
places the labels A1, A2, . . ., A9 in column one. Note that there are no quotes
around the integer j. Indeed, inserting quotes would result in the unintended
labels Aj, . . ., Aj.
Duplicating Strings
Here’s a simple example that takes a string and returns a string of duplicates
separated by a delimiter (which could be the null string "").
DOI: 10.1201/9781003351689-6 47
48 Discrete Mathematics and Coding
that returns Char repeated numChar times. For example, String(4, "A") returns
AAAA, as does String(4, "ABC").
Mid(text,start,[length])
where text is the given string, start is the position of the beginning of the
substring to be extracted, and length is the length of the substring. The
last argument is optional; if omitted the Mid function returns all characters
from the start position to the end of the string. Thus Mid("abcdef",2,3)
returns the string "bcd", while Mid("abcdef",2) returns "bcdef". Here are a
few applications of Mid.
Matching Symbols
The function IsMatch(expr,left,right) returns True if there are the same
number of occurrences of the symbol designated by the String variable left as
there are of the symbol right. This is useful for error-checking an arithmetic
expression containing various types of brackets. etc. For example the statement
IsMatch("(2+(3(-4)))","(",")") returns True since the number of left and
right parentheses are the same. The procedure uses the VBA function Len,
which returns the length of an input string.
A Variation of Mid
VBA returns an error if the number start in Mid(text,start,length) is
less than 1 or bigger than length. As this is sometimes inconvenient, we give
the following easy fix, which returns the single-space string " " in these cases.
The reader may wish instead to make the choice of the return character an
argument, say defaultreturn, passed to the function.
Function Midd(text As String, start As Integer, length As Integer) _
As String
Dim str As String
str = " " 'default return
If start + length <= Len(text) + 1 And start > 0 Then
str = Mid(text, start, length) 'no error
End If
Midd = str
End Function
• CLng: Similar to CInt but converts the argument into a Long integer.
• CDbl: Converts arithmetic strings and numeric values into Double numbers.
For example, CDbl(4*(2.3)^2 + 3.7) and CDbl("24.86") both return
the Double value 24.86.
takes every occurrence of the string find in expression and replaces it by the
string replacement. We give two applications of the function.
52 Discrete Mathematics and Coding
To see how this works, consider the string “aabbacb”. In the first iteration of
the loop result in
The third iteration reduces temp to the null string "" and produces the desired
output "abc".
the substring in the input string; otherwise it returns 0. The function performs
exact matches. Here is the general syntax for the function:
The optional argument start is the starting position of the search, with 1 as
the default. For a non case-sensitive search, set the optional argument compare
to the VBA constant vbTextCompare. Here are some examples based on the
string str = "cat in a hat":
• "Ab2De" Like "A*e" returns True and so detects strings that begin with
"A" and end with "e". The asterisk is a wild card matching any character
(including "") or sequence of characters.
• "A5e" Like "A?e" returns True and "Abde" Like "A?e" returns False.
The question mark is a wild card matching any single character.
• "A5e" Like "A#e" returns True and "Ade" Like "A#e" returns False. The
hash sign is a wild card matching any single digit 0-9.
• "R" Like "[A-Z]" returns True but "R" Like "[!A-Z]" (note the excla-
mation sign), "R" Like "[A-Q]", and "r" Like "[A-Z]" all return False.
The pattern "[A-Z]" matches any capital letter, while "[A-Q]" matches
any capital letter up to and including "Q". The analogous remarks applies
to the pattern "[a-z]"
• "bExf" Like "b[D-P]?[c-m]" and "bE5f" Like "b[D-P]#[!a-e]" both re-
turn True.
• "brJx3z" Like "b?J*" returns True. Thus the statement detects strings
with first character b, any second character, third character J, and zero
or more arbitrary remaining characters.
Join(arr[,delimiter])
String Functions 55
In the absence of a delimiter the function will separate the elements of the
array by spaces. If the delimiter is the null string "" then no separation occurs.
For example, if LBound(arr)=1 and UBound(arr)=3, then Join(arr,"*") returns
the string arr(1)*arr(2)*arr(3). If "*" is replaced by "", then the function
returns arr(1)arr(2)arr(3).
The function Split is the reverse of Join. It takes as input a string and
returns a one-dimensional array of substrings (with index starting at 0) based
on a specified delimiter, which tells the function where the input string should
be split. Here is a simplified version of the syntax, sufficient for our purposes:
The argument expression is the input string that is to be split. The argument
delimiter, which is optional, specifies where expression is to be split. If omitted
the delimiter defaults to a space character. The argument limit, which is also
optional, specifies the maximum number of substrings split from expression;
left unspecified the function will split out all the substrings. Here are some
examples:
• Split("cat*in*a*hat", "*") returns the array {“cat”, “in”, “a”, “hat”},
splitting the string at the asterisks.
• Split("cat in a hat") returns the same array using the space character
as the default delimiter.
• Split("cat*in*a*hat", "*", 2) returns {“cat”, “in*a*hat”}.
It is sometimes inconvenient that the lower bound of the array returned
by Split is zero. The following version has LBound = 1. Also, unlike Split, if
delim = "" then the function returns an array of the individual characters of
the expression
Here’s how the function works for the input string str = "aa,bbb,bbb,cc"
with the comma as delimiter. Initially, the string "aa" is extracted from str.
The function InStr then determines that "aa" is not already a part of temp,
which at this stage is the null string, and so updates temp to ",aa". The next
item checked in str is the string "bbb". The function InStr determines that
this string is not part of temp and so the string is attached to temp, which
is now ",aa,bbb". In the next iteration of the loop, "bbb" is extracted. InStr
determines that the string is already part of the current value of temp and so
the latter is not updated. In the last iteration InStr determines that the string
"cc" is not already a part of temp and so is attached to temp. The loop is then
exited. The delimiter attached to temp during the first iteration (when temp
was still the null string) is deleted by Mid and the resulting string "aa,bbb,cc"
is returned by the function.
6.9 Exercises
1. Write a function NumDigits(x) that returns the number of digits in a
Long integer x.
2. Write a function LastDigit(x) that returns the last digit of a Long
integer x.
3. Write a function RemoveLastDigit(x) that removes the last digit of a
Long integer x.
String Functions 57
4. Write a function CircularShift that takes a string, removes the last letter
and attaches it at the beginning. For example, CircularShift("abcde")
should return eabcd.
5. Write a procedure NumUpper(str) that takes a string and returns the
number of upper case letters. Write the analogous function NumLower as
well. (Use IsUpper,IsLower.)
6. Write a function IsVowel(char) that takes a character and returns True
if the character is a vowel and False otherwise. Write the analogous
function IsConsonant.
7. Write a function RemoveVowels(str) that removes the vowels from str,
collapsing the leftover letters into a single string in the same order that
they appear in str.
8. Write a function Lower2Upper(char) that takes a lower case letter char
and returns the corresponding upper case letter. Write a function
Upper2Lower(char) that does the reverse.
11. Write a function OddConcat that takes a string and returns the characters
in the odd positions, concatenated in the same order that they appear
in the string. For example, OddConcat(sweet) returns set.
12. Write a function Interlace that takes two strings of equal length and
interlaces the letters. For example, Interlace("abcde", "uvxyz") returns
aubvcxdyez.
13. Write a function DecimalPart that takes a decimal number and returns
the fractional part, if any. Thus DecimalPart(12.345) should return the
Double number .345. Write the analogous function WholePart.
14. Write a function ExpandDate that takes a date string such as “8/4/2022”
and returns the string “August 4, 2022.”
15. Write a function DupCharacters that takes a string of letters interspersed
with digits 1–9 and returns a string that duplicates each letter as indi-
cated by the numbers. For example, DupChar("3a2b4c") should return
aaabbcccc.
58 Discrete Mathematics and Coding
16. Write a function FindDoubleChars that takes a string and returns the
first pair of consecutive duplicate characters if there is such a pair and
returns the null string "" if not. For example, DoubleLetters("scoop")
returns oo while DoubleLetters("scope") returns the null string.
17. The Hamming distance between two strings of equal length is the number
of character positions where the strings differ. For example, the Hamming
distance between the strings “below” and “belie” is 2, since the strings
differ in two positions. Write a function HammingDistance that calculates
Hamming distance between two strings. The Hamming distance is used
in information theory to measure the minimum number of errors that
might have occurred in changing a string.
18. Write a function StringIntersect(Str1,Str2) that takes a two strings
and returns the common portion of the strings (which could
be null) in the order in which the letters appear. For exam-
ple, StringIntersect("impossible","implausible") returns the string
“impsible”.
19. Write a function ReverseWords(inputstr) that reverses the words in a
sentence, keeping the letters of the words in the correct order.
20. Write a function ExtractSymbols(inputstr, mode) that extracts from
an input string either all letters (mode=“letters”), all small let-
ters (mode="lower"), all capital letters (mode=“upper”), or all digits
(mode=“digits”). For example,
• ExtractSymbols("X12aBc","lower") returns ac
• ExtractSymbols("X12aBc","upper") returns XB
• ExtractSymbols("X12aBc","letters") returns XaBc
• ExtractSymbols("X12aBc","digits") returns 12
24. Write a function ASCIISort that sorts the characters of a string according
to their ASCII values. For example, if the string is "Z13y56cd24x68A"
then the function should return "12345668AZcdxy". Suggestion: Use the
sorting technique of BubbleSort (Section 4.1) and a function SwapChar
based on ReplaceChar of the preceding exercise.
25. Write a function MaxRun that takes a string str and returns the longest
substring of strictly increasing consecutive digits. If there are two such
runs it should return the first. For example, if the string is "123abd12456"
the function should return the substring "123". Use the IsDigit function.
Suggestions: Declare a String array Runs(1 To Len(str)). For each posi-
tion i in str have MaxRun call a program GetRun(str,i) that gets the run
starting at at i, which could be null.
Chapter 7
Grids
While the Excel spreadsheet is a powerful platform for reading, writing, and
crunching data, with a little tweaking it may be also used for interesting visual
effects such as dynamic evolution of Markov processes, random walks, and
maze solutions. The visual effects take place on what we shall refer to as a grid.
In the first section of this chapter we develop procedures that allow the user
to set up a grid either in the code of the host program or by specifying the
dimensions of the grid on the spreadsheet. In later sections we give applications
of cell activity on a grid. Additional applications appear throughout the text
in one form or another.
DOI: 10.1201/9781003351689-7 61
62 Discrete Mathematics and Coding
The underscore symbol in the above code is used to break up lengthy lines.
The symbol must be preceded by a space and followed by a carriage return.
The procedure GridBorder surrounds the grid with a border, as shown in
Figure 7.1, where CX = 20. For no color, set CX = 0; for no line border set
CX = −1 . In applications all cell activity takes place within the grid proper
defined by the parameters T, L, B, R, whether or not the border has color or
a line boundary.
colored border
(B,R)
The function GridsEqual returns True if the grids G1 and G2 have the same
specifications.
Private Function GridsEqual(G1 As TGrid, G2 As TGrid) As Boolean
GridsEqual = (G1.T = G2.T) And (G1.L = G2.L) And (G1.B = G2.B) And _
(G1.R = G2.R) And (G1.CW = G2.CW) And (G1.RH = G2.RH) _
And (G1.CX = G2.CX)
End Function
The procedure ClearGrid is used to remove an old grid if a new one has
been specified. The user has the option of removing the border (mode=1) or
keeping the border (mode=0). The user may occasionally have to revise the code
of the procedure to accommodate the special needs of a program. The code
uses the Selection feature of VBA that allows the user to select a group of
cells for a special purpose.
Private Sub ClearGrid(G As TGrid, mode As Integer)
If G.T <= 1 Then Exit Sub
'select a block of cells:
Sheet1.Range(Cells(G.T - mode, G.L - mode), _
Cells(G.B + mode, G.R + mode)).Select
With Selection
.Borders.LineStyle = xlLineStyleNone
.Borders(xlDiagonalDown).LineStyle = xlLineStyleNone
.Borders(xlDiagonalUp).LineStyle = xlLineStyleNone
.Interior.ColorIndex = xlNone
End With
Range(Cells(G.T, G.L), Cells(G.B, G.R)).ClearContents
End Sub
The following function detects the number of cells in the grid that are not
empty. It is useful if memory has to be allocated for an array that depends on
the number of entries in the grid.
Private Function NumOccupied(Grid As TGrid) As Integer
Dim i As Integer, j As Integer, m As Integer
For i = Grid.T To Grid.B 'count no. of occupied cells
For j = Grid.L To Grid.R
If Not IsEmpty(Cells(i, j)) Then m = m + 1
Next j
Next i
NumOccupied = m
End Function
In applications the host program sets the grid. A second run might be
necessary to produce the desired output if the host program is changing to a
different grid.
Figure 7.3 illustrates the two choices. In (a) the asterisk has (x, y) coordinates
(−2, −1); in (b) the (x, y) coordinates are (2, 1).
2 4
1 3
0 2
−1 * 1 *
−2 0
−4 −3 −2 −1 0 1 2 3 4 0 1 2 3 4 5 6 7 8
The procedure DeleteComposites uses the VBA function Mod to detect mul-
tiples of k other than k itself and then deletes them.
Private Sub DeleteComposites(G As TGrid, upperlim As Integer)
Dim i As Integer, j As Integer, cellval As Integer, k As Integer
k = 2
Do While k <= upperlim
For i = G.T To G.B 'scan grid for numbers
For j = G.L To G.R
If Not IsEmpty(Cells(i, j)) Then
cellval = Cells(i, j).Value 'get no. in nonempty cell
End If
If k <> cellval And cellval Mod k = 0 Then
Cells(i, j).Value = "" 'remove if a multiple of k
End If
Next j
Next i
k = k + 1 'next number to check
Loop
End Sub
The four procedures below do the collapsing and expanding. The first keeps
reducing R and increasing L until they differ by 1. At the end of the loop R =
L, at which time R is incremented and L is decremented so that the rectangle
is not solid. The other three procedures work analogously. The procedure
DrawRectangle is a variation of GridBorder.
L = L - 1: R = R + 1
Loop
L = L + 1: R = R - 1
End Sub
The procedure Delay uses triple nested For Next loops together with a
nonsense calculation to produce a delay. Note that the greater the value of
HowMuch, the greater the delay. The reader should experiment with various
settings, as speed may vary with computer.
Sub Delay(HowMuch As Integer)
Dim i As Integer, j As Integer, k As Integer, x As Double
For i = 1 To Int(10 * HowMuch) 'triple nested For Loops for delay
For j = 1 To Int(10 * HowMuch)
For k = 1 To Int(10 * HowMuch)
x = 987654321 / 123456789 'arbitrary calculation
Next k
Next j
Next i
End Sub
1 2 3 1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9 7 8 9
Here are the command buttons for the program. The first is activated once.
The second is activated each time a number is selected.
Sub CommandButton1_Click()
Call Initialize 'draw grid and place numbers
End Sub
Sub CommandButton2_Click()
Call SelectNumber 'press button after number in grid is selected
End Sub
The procedure Initialize sets up the table in the form of a grid with
bordered cells and places the numbers in the grid. The grid is a square with
side dimension GridDim.
Sub Initialize()
Dim G As TGrid, row As Integer, col As Integer
Dim k As Integer, GridDim As Integer
GridDim = Range("B4").Value 'read grid dimension
G = MakeGrid(3, 3, 2 + GridDim, 2 + GridDim, 7, 20, -1)
Range(Cells(G.T, G.L), Cells(G.B, G.R)).Borders.LineStyle _
= xlContinuous 'give each cell a border
row = G.T 'start numbers here
col = G.L
For k = 1 To GridDim ^ 2
Cells(row, col).Value = k 'cell gets number
col = col + 1 'move right for next cell in row
If k Mod GridDim = 0 Then 'if at end of grid then
row = row + 1 'go to next row
col = G.L 'and first column
End If
Next k
End Sub
Grids 71
After the player selects a number and presses the command button Select ,
the procedure SelectNumber is called. At this time the grid is changed if
necessary, the dimensions depending on user-entered specs. After this, the
active cell feature of VBA assigns to the variables row,col, the cell position
that the user selected. A double For Next loop assigns color1 to the cells in
the row row and the column col, and color2 to the cell in position row,col. A
running sum is kept of the numbers on cells with color2. At the end of the
game when all cells have colors, the sum equals n(n2 + 1)/2, where n is the
grid dimension.
Sub SelectNumber()
Dim i As Integer, j As Integer, row As Integer, col As Integer
Dim GridDim As Integer, check As Integer, sum As Integer, G As TGrid
Dim color1 As Integer, color2 As Integer
G = GetRecordedSpecs() 'get the grid created in Initialize
GridDim = Range("B4").Value 'read the table dimension
T = 3: L = 3: B = 2 + GridDim: R = 2 + GridDim
color1 = 27: color2 = 24
row = ActiveCell.row: col = ActiveCell.Column 'selected by user
If Not InGrid(row, col, G) Then Exit Sub
For i = T To B 'color the row and column of selection
For j = L To R
If i = row Then Cells(row, j).Interior.ColorIndex = color1
If j = col Then Cells(i, col).Interior.ColorIndex = color1
Cells(row, col).Interior.ColorIndex = color2 'new color
Next j
Next i
For i = T To B 'add the numbers of the selected cells
For j = L To R
If Cells(i, j).Interior.ColorIndex = color2 Then
sum = sum + Cells(i, j).Value
End If
Next j
Next i
Range("B5").Value = sum 'print sum
check = GridDim * (GridDim ^ 2 + 1) / 2 'which should equal this
Range("B6").Value = check
If sum = check Then
MsgBox "game over"
Range(Cells(G.T, G.L), Cells(G.B, G.R)).Interior.ColorIndex = 0
End If
End Sub
72 Discrete Mathematics and Coding
x x x x x x
x x x x
x x x x x x
x x
x x o x x o
x x x x
The main procedure introduces a new UDT TDist, which specifies the
position of a cell containing an x and its distance from the cell marked o, the
“origin.”
Private Type TDist
row As Integer: col As Integer: dist As Integer
End Type
Sub NearestCells()
Dim k As Integer, n As Integer, D() As TDist, G As TGrid
Dim orow As Integer, ocol As Integer 'origin row and column
G = MakeGrid(5, 5, 39, 53, 2.3, 15, 24)
Call ClearColors(G)
k = Range("B4").Value 'desired number of nearest cells
n = NumOccupied(G) - 1 'number of x's
Range("B6").Value = n 'print number of x's
If n < 1 Or k = 0 Or k > n Then Exit Sub 'flawed parameters
ReDim D(1 To n) 'memory for the x data
Call GetPositions(D, G, orow, ocol)
If orow = 0 Or D(1).row = 0 Then Exit Sub 'no origin or x's
Call GetDistances(D, orow, ocol) 'distances from x's to origin
Call BubbleSort(D) sort distances least to greatest
Call PrintNearest(D, k) print k nearest x's to the origin
End Sub
The procedure ClearColors removes the colors from the x’s from a previous
run, if any.
Private Sub ClearColors(G As TGrid)
Dim i As Integer, j As Integer
For i = G.T To G.B 'scan grid for the locations of o and the x's
For j = G.L To G.R
Grids 73
The procedure GetPositions fills the position part of the TDist array with
the location of the origin, labeled orow,ocol, and the location of the x’s.
The procedure GetDistances fills the distance part of the TDist array with
the distance from an x to the origin o. Distance here is simply the number of
horizontal and vertical cells in an elbow path from one cell to another.
Next i
k = 1 'reset
row = centerrow - 1: col = centercol 'cell above central cell
Sheet2.Cells(k, 3).Value = row 'position of first red cell is
Sheet2.Cells(k, 4).Value = col 'placed in columns 3 and 4 of Sheet2
For i = 1 To G.B - G.T
For j = 1 To i 'repeat each offset i times
k = k + 1
row = row + offset((i + 1) Mod 4) 'generates 0,1,0,-1
col = col + offset((i + 2) Mod 4) 'generates 1,0,-1,0
If InGrid(row, col, G) Then 'if within grid then
Sheet2.Cells(k, 3).Value = row 'record position
Sheet2.Cells(k, 4).Value = col
End If
Next j
Next i
End Sub
Sub CreateSpirals()
Dim i As Integer, row As Integer, col As Integer, lastrow As Integer
lastrow = Sheet2.Cells(Rows.Count, 1).End(xlUp).row
For i = 1 To lastrow 'last nonempty row in Sheet2, column 1
row = Sheet2.Cells(i, 1).Value 'get cell locations
col = Sheet2.Cells(i, 2).Value 'of green spiral
Cells(row, col).Interior.ColorIndex = 4 'color spiral cell green
Call Delay(5)
Next i
lastrow = Sheet2.Cells(Rows.Count, 3).End(xlUp).row
For i = 1 To lastrow 'last nonempty row in Sheet2, column 3
row = Sheet2.Cells(i, 3).Value 'get cell locations
col = Sheet2.Cells(i, 4).Value 'of red spiral
Cells(row, col).Interior.ColorIndex = 3 'color spiral cell red
Call Delay(5)
Next i
End Sub
Sub EraseSpirals()
Dim i As Integer, k As Integer, row As Integer, col As Integer
lastrow = Sheet2.Cells(Rows.Count, 1).End(xlUp).row
For i = lastrow To 1 Step -1 'erase green spiral in reverse
Call Delay(5)
row = Sheet2.Cells(i, 1).Value 'get locations of green cells
col = Sheet2.Cells(i, 2).Value
Cells(row, col).Interior.ColorIndex = 0 'remove color
Next i
Grids 77
1
2
FIGURE 7.8: Billiard ball bank shot; sank in upper left pocket.
The module uses the UDT’s TGrid and TPos. The launching program
BilliardBall introduces three TPos variables: pos1 and pos2, which are the
second to last and last positions of the ball, respectively; and pos3, the new
position to be determined from pos1 and pos2. The procedure calls the function
GetStart to find pos1 and pos2 for the entered data 1,2, returning False if
unsuccessful. If successful the numbers 1,2 are erased and the cell at pos2 is
colored red. A Do While loop then moves the ball, stopping when the path
length reaches its prescribed maximum (maxlen) or when it is notified by the
variable status that the ball has landed in a corner pocket. A Select Case
statement calls the appropriate function, DirNE, DirSE, DirNW or DirSW for
the next direction. It is these functions that are responsible for finding pos3.
The current direction is determined by the function GetDirection, which takes
78 Discrete Mathematics and Coding
the current values of pos1,pos2, which give the direction of the ball, and returns
one of the strings "NE", "SE", "NW", or "SW". After this, color is removed from
the cell at pos2, the variable then pos3 becomes the new pos2, and pos2 the
new pos1.
Sub BilliardBall()
Dim G As TGrid, pos1 As TPos, pos2 As TPos, pos3 As TPos
Dim status As String, pathlen As Integer, maxlen As Integer
G = MakeGrid(8, 5, 27, 35, 2.5, 11.5, 4)
Call ResetCorners(G) 'make corners green again
maxlen = 500 'max. no. cells in ball path (arbitrary)
If Not GetStart(pos1, pos2, G) Then MsgBox "failed": Exit Sub
dir = GetDirection(pos1, pos2)
If dir = "" Then MsgBox "failed": Exit Sub
Cells(pos1.row, pos1.col).Value = "" 'erase 1 and 2
Cells(pos2.row, pos2.col).Value = ""
Cells(pos2.row, pos2.col).Interior.ColorIndex = 3 'initial color
Do While pathlen < maxlen Or status = "SankBall"
Select Case GetDirection(pos1, pos2) 'depends on pos1, pos2
Case Is = "NE": status = DirNE(pos1, pos2, pos3, G)
Case Is = "SE": status = DirSE(pos1, pos2, pos3, G)
Case Is = "NW": status = DirNW(pos1, pos2, pos3, G)
Case Is = "SW": status = DirSW(pos1, pos2, pos3, G)
Case Is = "": Exit Do
End Select
Call Cells(pos2.row, pos2.col).Interior.ColorIndex = 0 'no color
pos1 = pos2: pos2 = pos3 'shift
Call Cells(pos2.row, pos2.col).Interior.ColorIndex = 3 'new pos.
Call Delay(12)
pathlen = pathlen + 1 'update path length
Loop
'remove last red ball on table
Range(Cells(G.T, G.L), Cells(G.B, G.R)).Interior.ColorIndex = 0
End Sub
The procedure ResetCorners makes the corners green again in case a ball
landed in a pocket on a previous run.
Here is the code for GetStart. The function scans the grid for the numbers
1,2, recording their positions and returning True if successful.
The direction functions find the new position pos3 based on the current
direction, as determined by the pair pos1,pos2. We illustrate with DirNe. There
are several cases to consider, depending on the proximity of pos2 to the grid
edge. These are shown in Figure 7.9.
3
2 Case 4 1 2
1 3
Case 2
3
2 3
1 Case 3 2
Case 1 1
Cells(pos2.row, pos2.col).Interior.ColorIndex = 0
Cells(pos2.row + 1, pos2.col - 1).Interior.ColorIndex = 3 'move
status = "SankBall" 'to lower left corner on boundary
End If
End Function
7.10 Exercises
1. Write a program NumberPainting that takes a user-entered pattern of
color index numbers in a grid and assigns the colors to the cells, as
shown in Figure 7.10. Use nested For Next loops to scan the grid for the
numbers and to paint the cells.
7 7 7 7 7 7 7 7 7
7 7
7 8 8 7
7 3 7
7 3 7
7 7
7 6 6 6 7
7 7
7 7 7 7 7 7 7 7 7
For Next loop to draw decreasing concentric squares. Have each iteration
of the loop call the procedure DrawRectangle to draw a colored square
and then, after a delay, erase it. The next iteration should draw a smaller
square by adding 1 to the top row and left column and subtracting 1
from the bottom row and right column. The process should be repeated
until the square has collapsed into a single cell. Reversing the process
should cause the square to expand.
7. Write a program ModBlinker that causes a user-entered set of positive
integers in a grid to blink according to their remainders modulo a user-
entered positive integer m, resulting in interesting patterns. For example,
if m = 2, then all odd numbers should be set to red for an instant and
then all even numbers. The case m = 3 is shown in the figure.
1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8
9 10 11 12 9 10 11 12 9 10 11 12
8. Write a program RectangleEnclose that scans a grid for user entered x’s
and encloses them in a minimal rectangle, as shown in Figure 7.14
x
x x x x
x
9. Write a program Spiral2 like Spiral but have the outer and inner spiral
start out together.
10. Write a program ZigZag that gradually creates and then erases a pattern
like the one on the left in Figure 7.15. Model the program on Spiral.
13. (Langton’s ant). The name refers to an algorithm based on a set of simple
instructions that causes a cell (“ant”) to move on a grid of black and white
cells. The cells of the grid are initially white. The ant is allowed to travel
famously define the Fibonacci sequence, the first few terms of which are
Notice that the first two numbers of the sequence are specified but successive
numbers are generated from previously calculated terms.
In programming, recursion refers to a procedure calling itself. It is similar
to looping in that statements are executed repeatedly. In a loop this happens
until a certain condition is satisfied; in recursion a procedure ends when a base
case or terminating condition is met.
Recursion typically requires more memory than looping and can increase the
time required to complete a task. On the other hand, recursion can significantly
reduce the complexity of a program, providing a relatively simple solution to
an otherwise daunting problem. Indeed, it may be the only practical technique
for implementing algorithms with many branches that are too complex for
a satisfactory looping approach. In this chapter we give several examples of
recursive programs.
DOI: 10.1201/9781003351689-8 85
86 Discrete Mathematics and Coding
To see how the recursion works suppose a program calls Fact(4), where we
have abbreviated Factorial to Fact. During execution, the statement 4*Fact(3)
is encountered. The multiplication is delayed and the function Fact(3) is called.
In the latter, the statement 3*Fact(2) is encountered, multiplication is again
delayed and Fact(2) is called. In this version the program encounters the
statement 2*Fact(1) and calls Fact(1). The latter returns the base value 1,
enabling the computation 2*Fact(1). The function Fact(2) then returns this
number to Fact(3), where the calculation 3*Fact(2) is carried out. Fact(3)
then returns this number to Fact(4), where the final calculation 4*Fact(3)
occurs. Fact(4) then returns this number to the host program. Figure 8.1
illustrates the process.
Fact(4) = 24
4 ∗ Fact(3) = 24
3 ∗ Fact(2) = 6
2 ∗ Fact(1) = 2
Fact(1) = 1
Excel gives you an overflow in both the loop and recursion versions if n
is too large, say n > 12. Higher values are possible if the Long declarations
are replaced by Double. Even higher values are possible using strings—see
Chapter 27.
All programs requiring iteration, however complex, can be written in terms
of loops. However, some of these require emulation of the compiler’s method
of executing recursion, namely via stack storage of instructions and variables.
In these situations, recursion is usually a more reasonable approach.
Recursion 87
B C
D E F G
H I J K L M N O
The main procedure of the module is BinaryTree, which sets various param-
eters including root position, numbers of levels, and offsets to the successive
levels. The latter affect the general shape of the tree.
The procedure DrawTree, as you may have deduced, draws the tree. It calls
itself to draw the left branches of a node first, then comes out of recursion to
draw a right branch. The order in which this is done for the tree in Figure 8.2
in terms of nodes is A,B,D,H,I,E,J,K,C,F,L,M,G,N,O. Figure 8.3 shows the seven
steps in the construction of the left branch. This order of node traversal is
88 Discrete Mathematics and Coding
called preorder and is summarized by the description Root, Left, Right. Other
important orders are inorder (Left, Root, Right) and postorder (Left, Right,
Root).
1 2 3 4 5
A A A A A
B B B B B
D D D D E
H H I H I
6 7
A A
B B
D E D E
H I J H I J K
Sub BinaryTree()
Dim Grid As TGrid, rootrow As Integer, rootcol As Integer
Dim Offset() As Integer
Dim height As Integer, breadth As Integer, i As Integer
Dim T As Integer, L As Integer, B As Integer, R As Integer
height = 2 ^ (lastlevel + 1) + 4 'grid dimensions determined
breadth = 2 * height + 4 'by lastlevel
T = 5: L = 5: B = T + height: R = L + breadth
Grid = MakeGrid(T, L, B, R, 0.8, 6, 0)
rootrow = T + 2: rootcol = L + breadth / 2 'middle top of grid
level = -1
ReDim Offset(0 To lastlevel)
For i = 0 To lastlevel 'offsets from root
Offset(i) = 2 ^ (lastlevel - i)
Next i
Recursion 89
7
I II III
rings are placed on rod I in order of size, forming a conical shape with the
larger rings at the bottom.. The objective is to move the rings one at a time
Recursion 91
to rod III by taking the top ring of a (source) rod and placing it on a (target)
rod. However, there is crucial restriction: no ring may ever be placed above a
smaller one, that is, the conical shape of a stack must always be preserved. A
third rod (free) is available to help with this.
The puzzle is handily solved by recursion: If at any stage it is required to
move n rings from a source rod to a target rod, then
(1) move the top n − 1 rings to the free rod,
A B C E F G H I J K
1
2 1
RUN
3 2
4 num rings 4 3
5 delay 10 4
6 step (y/n) n
The main procedure, HanoiTower, begins by setting up a grid for the rectan-
gles and reading the user-entered information, including the number of rings
and the speed of the moves. The variables source,free,target refer to column
numbers on the spreadsheet designating the rod positions. They are initially
set in that order and correspond to the rods I, II, and III. The procedure then
calls InitTower, which colors the rings, labels the rods, and places the rings on
rod I. Figure 8.5 shows the spreadsheet immediately after InitTower was called.
Note that the width of disk n counting from the top is 2n − 1. In particular,
the last disk has width 2*NumRings-1.
92 Discrete Mathematics and Coding
Calling the procedure MoveRings starts the recursion. At each stage, the
rings are moved from the current source rod to the current target rod using
the current free rod as a means to maintain the relative size configurations.
source the free rod, to move the n − 1 rings from the free rod to the target
rod.
Sub MoveRings(n As Integer, source As Integer, target As Integer, _
free As Integer)
If n = 1 Then
Call Delay(speed) 'delay, then move a ring from source to target
Call MoveRing(source, target)
Call Delay(speed)
Else
Call Delay(speed) 'delay then move n-1 rings from source to free
Call MoveRings(n - 1, source, free, target)
Call Delay(speed)'delay, then move nth ring from source to target
Call MoveRing(source, target)
Call Delay(speed) 'delay, then move n-1 rings from free to target
Call MoveRings(n - 1, free, target, source)
Call Delay(speed) 'delay some more
End If
End Sub
E F G H I J K L M N O
1
2 1
3 2 3
It is of interest to find the number of moves required to carry out the above
algorithm. For this let Mn denote the number of moves needed to transfer n
rings. From the procedure MoveRings we see that
Since M1 = 1, we have
and in general Mn = 2n −1. This the least number of steps required to solve the
puzzle. For example, 3 rings takes 7 steps, as shown in Figure 8.4. The number
of steps escalates quite rapidly with the introduction of additional rings. The
reader may check that moving one ring per second in a tower consisting of 31
rings would take almost an average lifetime. Moving 64 disks at a rate of one
per second would take over 500 billion years. (Please do not attempt this!)
a + bi (a + bi)(c − di) ac + bd bc − ad
= = 2 + 2 i
c + di (c + di)(c − di) c + d2 c + d2
−b
a − bi
Sub CommandButton1_Click()
Dim expr As String, dplaces As Integer, err As Boolean, z As String
96 Discrete Mathematics and Coding
• Complex. Takes a pair of real numbers a and b and returns the string
"a+bi". For example Complex(3,4) returns the string "3+4i".
• ImReal. Takes a complex number string and returns the real part. For
example ImReal("3+4i") returns the string "3".
• Imaginary. Takes a complex number string and returns the imaginary
part. For example Imaginary("3+4i") returns the string "4".
• ImConjugate("3+4i"). Returns the complex conjugate of a complex number
string. For example ImConjugate("3+4i") returns the string "3-4i".
• ImAbs. Returns the absolute value of a complex number. For example
ImAbs("3+4i") returns the number 5.
• ImSum. Returns the sum of a pair of complex number strings.
• ImSub. Returns the difference of a pair of complex number strings.
• ImProduct. Returns the product of a pair of complex number strings.
Recursion 97
• ImDiv. Divides the first of a pair of complex number strings by the second.
• ImPower. Takes a complex number string "a+bi" and an integer n and
returns (a + bi)n . For example, ImPower("1+i",-2) returns "-.5i".
retrieving evaluating
-2i∗(3+4i)ˆ(-5) -2i∗(3+4i)ˆ(-5)
−
2i 2i∗(3+4i)ˆ(-5)
∗
3+4i (3+4i)ˆ(-5)
ˆ
-5
Rounding
The function CxRound sets the maximum number of decimal places in the
final answer by applying the VBA function Round to the real and imaginary
parts. If decplaces is zero no rounding occurs.
Function CxRound(zStr As String, decplaces As Integer) As String
Dim WF As WorksheetFunction, xStr As String, yStr As String
Dim x As Double, y As Double
Set WF = Application.WorksheetFunction
If decplaces <= 0 Then CxRound = zStr: Exit Function
xStr = WF.ImReal(zStr): yStr = WF.Imaginary(zStr)
x = CDbl(xStr): y = CDbl(yStr)
x = Round(x, decplaces): y = Round(y, decplaces)
CxRound = WF.Complex(x, y)
End Function
Inserting Asterisks
The function InsertAsterisks uses InsertString of Section 6.2 to place an
asterisk between suitable characters in a multiplication operation.
k = k + 1
Loop
InsertAsterisks = expr
End Function
P (x) = a0 + a1 x + a2 x2 + · · · + am xm ,
(1 + x + x2 ) + (1 + x + x2 + x3 ) = (2 + 2x + 2x2 + x3 )
(1 + x + x2 ) − (1 + x + x2 + x3 ) = −x3
(1 + x + x2 )(1 + x + x2 + x3 ) = 1 + 2x + 3x2 + 3x3 + 2x4 + x5
(a0 + a1 x + a2 x2 + · · · + am xm )(b0 + b1 x + b2 x2 + · · · + bn xn )
= c0 + c1 x + c2 x2 + · · · + cm+n xm+n ,
Sub CommandButton1_Click()
Dim expr As String, error As Boolean
Range("B3").Value = "" 'erase any previous error message
Range("B4").NumberFormat = "@" 'format as text
expr = Range("B4").Value 'read expression
expr = PolyCalc(expr, error) 'expand the polynomial
If Not error Then
Range("B6").Value = expr 'print expanded polynomial
Else: Range("B3").Value = "Error"
End If
End Sub
102 Discrete Mathematics and Coding
The main procedure PolyCalc first carries out a preliminary error check of
the input expression. If no error is found, then the terms of the polynomial
are encoded for ease of programming and the evaluation procedure PolyEval
is called. As in the case of ComplexCalc, the usual hierarchy of operations is
imposed. If no calculation error is found, the result is decoded by the function
DecodePoly and then returned.
The function GetCoeff is passed the polynomial expression and the position
of an x and returns its coefficient. It also assigns a value to startpos.
Function GetCoeff(expr As String, k As Integer, _
startpos As Integer) As String
Dim coeff As String, j As Integer
ch = Midd(expr, k - 1, 1) 'character before x
If InStr("0123456789.", ch) = 0 Then 'if no coefficient then
coeff = "1": startpos = k 'set coeff. to 1 and startpos at x
Else
j = k - 1 start with character before x
Do While j > 0 And InStr("0123456789.", ch) > 0
coeff = ch & coeff 'build coeff by
j = j - 1 'moving backwards
ch = Midd(expr, j, 1)
Loop
startpos = j + 1 'position of first character in coeff
End If
GetCoeff = coeff
End Function
The function GetExp is passed the polynomial expression and the position k
of an x and returns its exponent. It also assigns a value to endpos.
Function GetExp(expr As String, k As Integer, endpos As Integer) As String
Dim exp As String, j As Integer
ch = Midd(expr, k + 1, 1) 'character after x
If ch <> "^" Then 'if no exponent then
exp = "1": endpos = k set exp to 1 and endpos at x
Else
j = k + 2 'skip ^
If Midd(expr, j, 1) = "(" Then j = j + 1 'skip left paren
104 Discrete Mathematics and Coding
The function MakePolyCode is passed the coefficient and exponent and returns
the desired bracketed expression. It uses the function DupString of Section 6.1
to fill with zeros.
The Calculations
The operations of addition, subtraction, and multiplication of polynomials
take a pair of encoded polynomials P,Q, convert them into arrays for convenience,
perform the operation, and convert the resulting array into encoded square
bracket form.
The function ArrayToPolyCode takes the array obtained from a coded poly-
nomial and converts it into an encoded polynomial. For example, the array
{0, 0, 2, 0, 0, −5.7} is converted into the string [0,0,2,0,0,-5.7].
8.6 Exercises
1. Write a program SumRecursion(n) that uses recursion to calculate the
sum of the first n positive integers. Check that this sum is n(n + 1)/2.
2. Write a recursive function PowerRecursion(b,p) that returns bp , where b
is a real number and p is a positive integer.
Recursion 109
(2n)!
1 · 3 · · · (2n − 1) = .
2n n!
a0 = a1 = a2 = 1, an = an−2 + an−3 .
1, 1, 1, 2, 2, 3, 4, 5, 7, 9, 12, 16, 21, 28, 37, 49, 65, 86, 114, 151, ...
n−1 n−1
n
= + , n ≥ 1, 1 ≤ k ≤ n − 1,
k k k−1
110 Discrete Mathematics and Coding
2 3
2 1 4
11
7 5
The first few Catalan numbers in the sequence are 1, 1, 2, 5, 14, 42,
132, 429, 1430. The numbers Cn occur in many counting problems, for
example,
q = a1 + bi + cj + dk,
12 = 1, i2 = j 2 = k2 = ijk = −1,
ij = k, jk = i, ki = j
ji = −k, kj = −i, ik = −j,
1i = i1 = i, 1j = j1 = j, 1k = k1 = k.
q ± q 0 = (a ± a0 ) + (b ± b0 )i + (c ± c0 )j + (d ± d0 )k)
and
qq −1 = q −1 q = 1.
112 Discrete Mathematics and Coding
Excel VBA has a powerful facility that can create a variety of charts and
graphs. In this chapter we describe through examples the versions that we
shall need in the book.
16
12
a c d e f g h i l m n o p r s t u w y
FIGURE 9.1: Frequencies of small letters in verse.
1 The entire poem may be found in his play The Night of the Iguana.
The program first clears any chart from a previous run by using the VBA
command ChartObjects.Delete. The array LetterArr(1 To 26) holds the num-
ber of times a particular letter is encountered in the text. Thus LetterArr(1)
holds the “a”-count, LetterArr(2) the “b”-count, etc. (we consider only lower
case letters). A For Next loop extracts a character symbol from text and finds its
ASCII value AscVal. If the symbol is a lower case letter then LetterArr(AscVal)
is incremented by one. After the frequencies have been tabulated, a second For
Next loop prints the letters a to z in column B and the frequencies in column
C. The program then invokes the chart facility.
The With End With statement in the code is used to obviate repetition
of the prefix Sheet1. The first few parts of the statement tell the program
the dimensions of the chart and where to place it on the spreadsheet. A little
experimentation may be required in applications. The next part specifies the
type of chart, namely xlColumnClustered. After this the title is set. The Range
statements in the code inform the program where the data is located, in this
case column B from row 4 to 29 for the x data that will appear along the
horizontal axis, and column C from row 4 to 29 for the y data that will appear
along the vertical axis. These statements might seem obscure but the reader
may simply use this and other examples as templates.
Sub LetterFreq()
Dim text As String, AscVal As Integer, i As Integer, chrt As Chart
Dim LetterArr(97 To 122) As Integer
Range("C4:C29").ClearContents 'clear old data
If ChartObjects.Count > 0 Then ChartObjects.Delete 'and chart
text = Range("B2").Value 'get the text
For i = 1 To Len(text) 'extract letters from text
AscVal = Asc(Mid(text, i, 1)) 'ASCII code for current letter
If 97 <= AscVal And AscVal <= 122 Then 'if lower case letter
LetterArr(AscVal) = LetterArr(AscVal) + 1 'update frequency
End If
Next i
For i = 0 To 25 'print letter and frequency of occurrence
Cells(4 + i,2) = Chr(97 + i): Cells(4 + i,3) = LetterArr(97 + i)
Next i
With Sheet1 _
.ChartObjects.Add(Left:=200, Width:=450, Top:=50, Height:=250)
.Chart.ChartType = xlColumnClustered
.Chart.HasTitle = True
.Chart.ChartTitle.text = "Letter Frequency"
.Chart.SetSourceData Source:= Range("C" & 4 & ":" & "C" & 29)
.Chart.SeriesCollection(1).XValues = Range("B" & 4 & ":" & "B" & 29)
.Chart.Axes(xlCategory).HasTitle = True
.Chart.Axes(xlCategory).AxisTitle.Text = "Letters" 'x-axis label
.Chart.Axes(xlValue, xlPrimary).HasTitle = True
.Chart.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = _
"Relative Frequency" 'y-axis label
End With
End Sub
Charts and Graphs 115
3 1,7
3
2 2 8,10,13 6
2
1 4,12
1
0 3,9 5,11
0 1 2 3 4 1 2 3 4
The main procedure GraphPoly first sets up the grid and provides it with a
coordinate system using MakeGrid and InstallCoord of Chapter 7. The function
GenerateCoord converts the row-column spreadsheet positions of the entered
numbers into grid coordinates, prints these in columns A and B starting in
row 7, and returns the row of the last position printed. The chart facility uses
this information to graph the polygonal line using the Range statement.
Sub GraphPoly()
Dim Lastrow As Integer, Grid As TGrid
If ChartObjects.Count > 0 Then ChartObjects.Delete
Call ClearColumns(7, 1, 2) 'clear cols 1,2 starting at row 7
Grid = MakeGrid(2, 4, 35, 45, 2.3, 15, 24)
Call InstallCoord(Grid, Grid.B, Grid.L) 'coordinatize grid
Lastrow = GenerateCoord(Grid) 'print coord. of entered vertices
With Sheet1 _
.ChartObjects.Add(Left:=835, Width:=700, Top:=50, Height:=500)
.Chart.ChartType = xlXYScatterLines
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Graph Polygon"
.Chart.SetSourceData Source:=Range("B" & 7 & ":" & "B" & Lastrow)
.Chart.SeriesCollection(1).XValues = _
Range("A" & 7 & ":" & "A" & Lastrow)
.Chart.SeriesCollection(1).MarkerStyle = xlNone 'no markers on graph
End With
End Sub
116 Discrete Mathematics and Coding
The function GenerateCoord below scans the grid for cells containing positive
integers, which are the vertex labels. If Cell(i,j) contains a sequence of integers,
then the cell is to be visited several times. The numbers in a cell are placed
in an array NumberArray using the VBA function Split. The coordinates of
Cell(i,j) are computed and printed in columns A and B in the order matching
that of the vertex numbers.
P2
L2
P1
(x, y) Q1
L1
Q2
If the lines are not parallel, then m1 6= m2 and one may divide by
m1 − m2 to obtain
m1 P1 (1) − m2 P2 (1) + P2 (2) − P1 (2)
x=
m1 − m2
Then y may be obtained from x using either one of the equations found
in (9.1):
y = m1 (x − P1 (1)) + P1 (2).
Here is the code for the function. It is broken up into the cases outlined
above. The intersection point is placed in the array sol, which is returned by
the function.
The following program graphs the line for user-entered points in the spread-
sheet. For this we use the graph type xlXYScatterLines.
Sub GraphLineIntersect()
Dim XRange As String, YRange As String
Dim P_1(1 To 2) As Double, Q_1(1 To 2) As Double 'arrays for points
Dim P_2(1 To 2) As Double, Q_2(1 To 2) As Double
Dim Intersection(1 To 2) As Double, error As Boolean
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear old chts
Call ClearColumns(11, 1, 2) 'clear columns 1,2 starting at row 11
'read in line2 points
P_1(1) = Cells(6, 1).Value: P_1(2) = Cells(6, 2).Value
Q_1(1) = Cells(7, 1).Value: Q_1(2) = Cells(7, 2).Value
'read in line2 points
Charts and Graphs 119
P
S
Q
The function uses LineIntersect and the fact that the slopes of perpendicular
lines are negative reciprocals of one another.
Function Point2Line(P() As Double, Q() As Double, R() As Double, _
error As Boolean) As Double()
Dim m As Double, sol() As Double, S(1 To 2) As Double
If P(1) = Q(1) Then 'if line is vertical
ReDim sol(1 To 2) 'array for projected point
sol(1) = P(1): sol(2) = R(2) 'projected point
120 Discrete Mathematics and Coding
The following program graphs the line for user entered points in the spread-
sheet.
Sub GraphPoint2Line()
Dim XRange As String, YRange As String, error As Boolean
Dim P(1 To 2) As Double, Q(1 To 2) As Double, R(1 To 2) As Double
Dim sol() As Double
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear old chts
Call ClearColumns(10, 1, 2) 'clear columns 1,2 'starting at row 10
P(1) = Cells(6, 1).Value: P(2)= Cells(6, 2).Value 'read given line
Q(1) = Cells(7, 1).Value: Q(2)= Cells(7, 2).Value 'determined by P,Q
R(1) = Cells(8, 1).Value: R(2)= Cells(8, 2).Value 'read given point
sol = Point2Line(P, Q, R, error) 'point on line
If error Then Exit Sub
Cells(10, 1).Value = P(1): Cells(10, 2).Value = P(2) 'place data in
Cells(11, 1).Value = Q(1): Cells(11, 2).Value = Q(2) 'cells for
Cells(12, 1).Value = sol(1): Cells(12, 2).Value = sol(2) 'graphing
Cells(13, 1).Value = R(1): Cells(13, 2).Value = R(2)
XRange = "A" & 10 & ":" & "A" & 13
YRange = "B" & 10 & ":" & "B" & 13
With Sheet1 _
.ChartObjects.Add(Left:=280, Width:=400, Top:=15, Height:=400)
.Chart.SetSourceData Source:=Range(YRange) 'y values
.Chart.ChartType = xlXYScatterLines 'chart type
.Chart.HasTitle = True
.Chart.ChartTitle.Text = ""
.Chart.SeriesCollection(1).XValues = Range(XRange) 'x values
End With
End Sub
may be found as follows: Let the triangle have vertices P , Q, and R and let
dRQ denote the distance between the vertices R and Q. Let X be the point
along the line from R to P at a distance dRQ from R. The midpoint Y of the
line from S to Q is then on the bisector LR of the angle at R. LQ may be
similarly calculated. LineIntersect may then be used find the intersection of
LR and LQ . Figure 9.5 illustrates the construction
X = (x1 , x2 )
P = (p1 , p2 )
P
dRQ
midpoint
Y = (y1 , y2 )
R = (r1 , r2 ) R
dRQ
Q = (q1 , q2 ) Q
The point X = (x1 , x2 ) is found by laying off the distance dRQ in the
direction of the line from R to P . Using the Euclidean distance formula we
have p
dRQ = (r1 − q1 )2 + (r2 − q2 )2
The point X is on the parametric line
so for suitable t
The desired point Y is the average of the coordinates (x1 , x2 ) and (q1 , q2 ). We
have thus obtained a point on the bisector of the angle at R:
Y = 21 [t(p1 − r1 ) + r1 + q1 ], 21 [t(p2 − r2 ) + r2 + q2 ] ,
(9.4)
122 Discrete Mathematics and Coding
where t is given by (9.3). Switching the symbols r and q in this formula gives
a point Z (not shown) on the bisector of the angle at Q:
Z = 12 t[(p1 − q1 ) + r1 + q1 ], 21 [t(p2 − q2 ) + r2 + q2 ]
(9.5)
where now
dRQ
t= p , (9.6)
(p1 − q1 )2 + (p2 − q2 )2
The function Incenter implements this process. It is passed the vertices
P , Q, R as arrays and calculates the incenter as the intersection of the angle
bisectors from R to Y and Q to Z.
Here is a program that graphs the line segments from the vertices to the
incenter and the perpendicular line segments from the incenter to the sides.
Sub GraphIncenter()
Dim XRange As String, YRange As String
Dim P() As Double, Q() As Double, R() As Double
Dim sol() As Double, Grid As TGrid, error As Boolean
Dim proj_PQ() As Double, proj_QR() As Double, proj_PR() As Double
'clear old chart and data
If ChartObjects.Count > 0 Then ChartObjects.Delete
Call ClearColumns(8, 1, 2) 'clear columns 1,2 starting at row 8
Grid = MakeGrid(3, 4, 27, 28, 2.3, 15, 24)
Call InstallCoord(Grid, Grid.B, Grid.L)
Call GetVertexCoord(Grid, P, Q, R)
sol = Incenter(P, Q, R, error)
proj_PQ = Point2Line(P, Q, sol, error) 'proj. from incenter to PQ
proj_QR = Point2Line(Q, R, sol, error) 'proj. from incenter to QR
proj_PR = Point2Line(P, R, sol, error) 'proj. from incenter to PR
'points to be connected by lines
Cells(8, 1).Value = R(1): Cells(8, 2).Value = R(2)
Cells(9, 1).Value = P(1): Cells(9, 2).Value = P(2)
Cells(10, 1).Value = Q(1): Cells(10, 2).Value = Q(2)
Cells(11, 1).Value = R(1): Cells(11, 2).Value = R(2)
Cells(12, 1).Value = sol(1): Cells(12, 2).Value = sol(2)
Charts and Graphs 123
y = 3x2 + 2/x + 1, 1 ≤ x ≤ 2
in increments of .01, one enters the values 1, 2 and .01 in cells B3, B4, and
B5, respectively, and the expression = 3*x^2 + 2/x + 1 in cell B6 (note the
equals sign). The program places the x-values in column 3. The y values are
calculated from the x-values by the function FunctionVal (Section 4.5) and
placed in column 4.
Sub GraphFunction()
Dim LeftPoint As Double, RightPoint As Double, Inc As Double
Dim NumPoints As Integer, x As Double
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear old chart
Call ClearColumns(8, 3, 4) 'clear cols 3,4 starting from row 8
LeftPoint = Range("B3").Value
RightPoint = Range("B4").Value
Inc = Range("B5").Value: expr = Range("B6").Value
NumPoints = (RightPoint - LeftPoint) / Inc
x = LeftPoint
For j = 1 To NumPoints
Cells(j + 7, 3).Value = x 'column of x values
Cells(j + 7, 4).Value = FunctionEval(expr, "x", x) 'y values
x = x + Inc
Next j
With Sheet1 _
.ChartObjects.Add(Left:=300, Width:=800, Top:=50, Height:=500)
.Chart.ChartType = xlLine
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Graph of Function"
.Chart.SetSourceData Source:= _
Range("D" & 8 & ":" & "D" & 8 + NumPoints)
.Chart.SeriesCollection(1).XValues = _
Range("C" & 8 & ":" & "C" & 8 + NumPoints)
.Chart.SeriesCollection(1).MarkerStyle = xlNone 'no graph markers
End With
End Sub
The graphing facility generates nice graphs when the increment is small.
The reader may wish to enter the following visually interesting wave functions,
Charts and Graphs 125
perhaps experimenting with the parameters, which can dramatically affect the
shape of a graph.
• 1 + SIN(1/x) Use the interval [.01, 1] and an increment of .001. The graph
is a displaced sine wave with decreasing frequency
• 1 + x*SIN(1/x) Use the interval [.05, .1] and the increment .001. The
graph is a displaced sine wave with decreasing frequency and increasing
amplitude.
126 Discrete Mathematics and Coding
y = mx + b,
where the constants m and b, called, respectively, the slope and y-intercept of
the line, are chosen so that the expression
n
X
|mxi + b − yi |2 ,
i=1
and Pn Pn
n j=1 yj − m j=1 xj
b= (9.8)
n
The least squares line is also called a trend line, as it may be used to predict
or interpolate values that are not displayed in the plot. However, care must be
taken not to read too much into a least squares line. Indeed, such a line exists
for any data, whether or not there is a trend.
Charts and Graphs 127
y
80
y = 4.64x + 9.86
60
40
20
x
2 4 6 8 10 12 14
The procedure LeastSquares generates the least squares line from x-data
entered in column B and y-data in column C. The procedure initially calls
DataCount (Section 4.2) to determine the number of data points in columns
B and C. After making a scatter plot from the data, the procedure calls
GetLineParameters, which calculates the slope and y-intercept of the least
squares line, and then calls GenerateYValues, to generates the y values of the
least squares line corresponding to the original x-values. The line is graphed
next to the scatter plot. Figure 9.7 illustrates data input-output in the program
less the scatter plot and least squares line, which appear to the right of the
data in the actual spreadsheet.
A B C D
1 X Data Y Data Y Modelled
2 1.2 .23 .36
Run Program
3 2.3 .54 .39
4 slope 3.4 .32 .42
5 .03 4.5 .61 .45
6 intercept 5.6 .39 .48
7 .33 6.7 .65 .51
8 7.8 .41 .54
The slope and intercept of the least squares line are given by the formulas
(9.7) and (9.8) translated into code notation as follows:
Ndata*sumxy - sumx*sumy sumy - slope*sumx
slope = , intercept = ,
Ndata*sumx2 - (sumx)2 Ndata
where
• sumx is the sum of the x-coordinates xi of the data,
• sumy is the sum of the y-coordinates yi of the data,
• sumxy is the sum of the products xi yi , and
• sumx2 is the sum of the squares x2i .
Sub GraphCurve()
Dim NPoints As Integer, LPoint As Double, RPoint As Double
Dim Inc As Double, t As Double, Xexpr As String, Yexpr As String
Call ClearColumns(8, 3, 4) 'clear old data
If ChartObjects.Count > 0 Then ChartObjects.Delete 'and chart
LPoint = Range("B3").Value 'get left end point
RPoint = Range("B4").Value 'get right end point
Inc = Range("B5").Value 'and the increment
Xexpr = Range("B6").Value: Yexpr = Range("B7").Value 'get functions
NPoints = (RPoint - LPoint) / Inc
t = LPoint 'initial value of parameter
For j = 1 To NPoints 'evaluate functions Xexpr, Yexpr using t values
Cells(j + 9, 2).Value = FunctionVal(Xexpr, "t", t) 'x values
Cells(j + 9, 3).Value = FunctionVal(Yexpr, "t", t) 'y values
t = t + Inc
Next j
130 Discrete Mathematics and Coding
With Sheet1 _
.ChartObjects.Add(Left:=300, Width:=500, Top:=50, Height:=400)
.Chart.ChartType = xlXYScatterLines
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Parametric Curve"
.Chart.SetSourceData Source:=Range _
("C" & 10 & ":" & "C" & 10 + NPoints)
.Chart.SeriesCollection(1).XValues = _
Range("B" & 10 & ":" & "B" & 10 + NPoints)
.Chart.SeriesCollection(1).MarkerStyle = xlNone
End With
End Sub
The reader may wish to generate the following interesting curves, varying
the parameters and noting the effect. Enter the expressions in A8 and A9 with
an increment .01. Let the interval for the first curve be [0, 7π] and the interval
for the last three [0, 4π].
• t*(Cos(t), t*Sin(t) The graph is a spiral emanating from the origin.
The program ChaosTriangleGame carries out the above steps (1)–(4) for a
triangle with vertices (0, 0), (2, 0), and (1, 2). The initial point is (x, y) = (0, 0).
At each stage the function Rnd (see Chapter 10) is used to randomly select a
vertex with equal probabilities. A new point (x, y) is then chosen according to
rule (3).
Sub ChaosTriangleGame()
Dim x0 As Double, y0 As Double, x As Double, y As Double
Dim NumIt As Integer, j As Integer, f As Double
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear charts
Call ClearColContent(8, 3, 4) 'and old data
f = 0.5 'distance fraction
NumIt = 10000 'repeat algorithm this many times
For j = 1 To NumIterations 'start initialization (x,y) = (0,0)
Randomize
Select Case Rnd 'pick vertex at random with equal prob.
Case Is < 0.33: x0 = 0: y0 = 0
Case Is < 0.67: x0 = 2: y0 = 0
Case Else: x0 = 1: y0 = 2
End Select
'print new (x,y) along line from old (x,y) to (x0,y0)
x = f * x0 + (1 - f) * x: y = f * y0 + (1 - f) * y
Cells(j + 7, 3).Value = x: Cells(j + 7, 4).Value = y
Next j
With Sheet1 _
.ChartObjects.Add(Left:=300, Width:=800, Top:=50, Height:=500)
.Chart.SetSourceData Source:=Range("D" & 8 & ":" & "D" & NumIt)
.Chart.ChartType = xlXYScatter
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Sierpinski Triangle"
.Chart.SeriesCollection(1).XValues = _
Range("C" & 8 & ":" & "C" & NumIt)
.Chart.SeriesCollection(1).MarkerStyle = xlMarkerStyleDot
End With
End Sub
where
• xn is the density of the prey population (with density = 1 characterizing
the maximum sustainable prey population),
• yn is the density of the predator population (relative to prey population),
• a is the rate of growth of prey in the absence of predators,
• b is the rate at which predators consume prey,
• c is the rate of death of predators in the absence of prey, and
• d is the rate at which the predator population increases as a result of
consuming prey.
The module PredatorPrey graphs predator-prey interactions for user-entered
parameters. An example is given in Figure 9.8.
3
2.5
1.5
.5
0
0 4 7 10 13 16 19 22 25 28 31 34 37 40
prey predator
x0 = .5, y0 = .1, a = 3, b = .5, c = .1, d = 3.5, steps = 100
Sub PredatorPrey()
Dim chrt As Chart 'declare a Chart object
Dim a As Double, b As Double, c As Double, d As Double
Dim x As Double, y As Double, oldx As Double, oldy As Double
134 Discrete Mathematics and Coding
The For Next loop generates the data using the predator prey equations with i
representing time steps. The remainder of the code is devoted to creating the
superimposed charts. The code illustrates an alternate method for specifying
chart characteristics, namely, by declaring a Chart object chrt.
The first point of the curve is the start point and the last point the end
point. The intermediate points (x1 , y1 ), . . . , (xn−1 , yn−1 ) control the shape of
the curve and as such are called control points. We shall refer to the n + 1
points as (Bezier ) data points. Bézier curves are frequently used in computer
graphics to model smooth curves. Figure 9.9 shows an example for the case
n = 3. The start and end points of the curve are shown in black. The control
points match the color of the curve. There are two for each curve. The small
boldface numbers indicate the order of the points, which is important. The
figure illustrates the basic principle of Bezier curves: the control points act as
a “magnet,” pulling the curve towards them.
(3, 5) (9, 5)
0 3
(0, 1) (12, 1)
2 (1, 0) (11, 0) 1
2 1
FIGURE 9.9: Two Bezier curves.
(c, d)
(x1 , y1 ) (x2 , y2 )
(x, y)
(a, b) (x0 , y0 )
follows: Choose a point (a, b) on the line segment from (x0 , y0 ) to (x1 , y1 ). Such
a point may be described parametrically as
a = (1 − t)x0 + tx1 , b = (1 − t)y0 + ty1 , (9.9)
where t is a number between 0 and 1. For the same value of t define the point
(c, d) by
c = (1 − t)x1 + tx2 , d = (1 − t)y1 + ty2 , (9.10)
136 Discrete Mathematics and Coding
which lies on the line segment from (x1 , y1 ) to (x2 , y2 ) at the same proportional
distance. Now set
a point on the line segment from (a, b) to (c, d), again at the same proportional
distance. Varying t from 0 to 1 produces the Bezier curve (in the direction of
the arrow.) To find the representation of (x, y) in terms of the data points,
substitute the values (9.9) and (9.10) into (9.11):
x = (1 − t) (1 − t)x0 + tx1 + t (1 − t)x1 + tx2
y = (1 − t) (1 − t)y0 + ty1 + t (1 − t)y1 + ty2
Figure 9.11 shows how moving the point (x1 , y1 ) changes the shape of the
curve.
t values
0 .2 .4 .6 .8 1 0 .2 .4 .6 .8 1
1 1
.8 .8
.6 .6
t values
.4 .4
.2 .2
0 0
The equations in (9.12) for a second order Bezier curve may be written in
terms of binomial coefficients (see Section 19.6) as
2 2
X n n−i i
X n
x(t) = (1 − t) t xi , y(t) = (1 − t)n−i ti yi , 0 ≤ t ≤ 1.
i=0
i i=0
i
This suggests the following definition for parametric equations for a general
Bezier curve:
n n
X n n−i i
X n
x(t) = (1 − t) t xi , y(t) = (1 − t)n−i ti yi , 0 ≤ t ≤ 1.
i=0
i i=0
i
Charts and Graphs 137
The start and end points are gotten by setting t equal to 0 and 1, respectively.
For n = 3 the equations simplify to
The module Bezier draws a Bezier curve using data points entered as
integers 0, 1, 2, . . . , n into the cells of a coordinatized grid. Figure 9.12 indicates
grid input for the blue Bezier curve in Figure 9.9. Here, the user has entered
5 0 3
4
3
2
1 2 1
0
0 1 2 3 4 5 6 7 8 9 10 11 12
the integers 0, 1, 2, 3 into cells of the grid, as shown. Running the program
prints the coordinates of the integers in columns A and B and then uses these
to generate the coordinates of the Bezier curve. The coordinates are obtained
by letting the parameter t take the values 0, .01, .02, . . . , 1, resulting in 101
points. The curve is generated from the coordinates.
The main procedure declares as Public variables the number of data points
and the beginning and end rows of the Bezier curve coordinates generated by
the module. After clearing previous data and setting up the grid, the procedure
calls GetDataPoints to print out the coordinates of the Bezier data points
entered by the user into the grid. The VBA chart facility produces the curve.
Sub Bezier()
Dim Grid As TGrid
If ChartObjects.count > 0 Then ChartObjects.Delete
Call ClearColumns(8, 1, 2)
Grid = MakeGrid(2, 4, 25, 35, 2.3, 15, 24)
Call InstallCoord(Grid, Grid.B, Grid.L)
NPoints = GetDataPoints(Grid) 'read pts. from grid, return number
FirstRow = 9 + NPoints 'curve data starts here
LastRow = FirstRow + 100 'and ends here
Call MakeCurve
End Sub
The function GetDataPoints scans the grid for the user-entered integers,
prints their coordinates in columns A and B, and returns the number of these
points.
138 Discrete Mathematics and Coding
The procedure MakeCurve generates points of the Bezier curve and prints
them in columns A and B under the data points. The parameter t defining
the x and y coordinates of the curve takes values from 0 to 1 in steps of .01.
For each value of t the procedure reads the control points and from these
computes the terms of the sums defining the curve. The procedure uses a
worksheet function to compute the binomial coefficients. MakeChart graphs the
curve using the generated points.
Sub MakeCurve()
Dim i As Integer, n As Integer, x As Double, y As Double
Dim sumx As Double, sumy As Double, t As Single
Dim WF As WorksheetFunction 'notation abbreviation
Set WF = Application.WorksheetFunction 'implement abbreviation
n = NPoints - 1 'degree of the Bezier curve
For t = 0 To 1 Step 0.01 'increment in steps of .01
sumx = 0: sumy = 0 'initialize each time
For i = 0 To n 'read data points and calculate Bezier sums
x = Cells(8 + i, 1).Value: y = Cells(8 + i, 2).Value
sumx = sumx + WF.Combin(n, i) * (1 - t) ^ (n - i) * t ^ i * x
sumy = sumy + WF.Combin(n, i) * (1 - t) ^ (n - i) * t ^ i * y
Next i
Cells(FirstRow + 100 * t, 1).Value = sumx 'print coordinates
Cells(FirstRow + 100 * t, 2).Value = sumy
Next t
With Sheet1 _
.ChartObjects.Add(Left:=700, Width:=650, Top:=25, Height:=500)
.Chart.ChartType = xlXYScatterLines
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Bezier Curve"
.Chart.SetSourceData Source:=Range _
("B" & FirstRow & ":" & "B" & LastRow)
.Chart.SeriesCollection(1).XValues =
Range("A" & FirstRow & ":" & "A" & LastRow)
.Chart.SeriesCollection(1).MarkerStyle = xlNone
End With
End Sub
Charts and Graphs 139
9.12 Exercises
1. (Projectile motion). This exercise is for readers with a trigonometry
background. It may be shown that a projectile launched at an angle of
θ radians from the horizontal from a point (0, y0 ) and with an initial
velocity of v0 meters per second has a path given by the equations (in
meters)
x = (v0 cos θ)t, y = y0 + (v0 sin θ)t − 12 gt2 ,
where g = 9.8 meters per second squared, the acceleration due to gravity.
(These are derived from Newton’s second law of motion under the ideal
assumption that there is no drag from air friction.) From these equations
max height
initial height
range
one can show that the maximum height ymax of the projectile and the
time tR it takes the projectile to hit the ground are given by the formulas
p
(v0 sin θ)2 v0 sin θ + (v0 cos θ)2 + 2gy0
ymax = y0 + , tR =
2g 2g
x = cos(kθ), y = sin(kθ)
where θ = 2π/n, k = 1, 2, . . . , n.
4. Write a program GraphPolyRotate that incorporates into GraphPoly the
ability to rotate the figure through a specified angle θ and about a speci-
fied axis point (x0 , y0 ) on a grid with coordinates. Use the transformation
3 2
3
2 5,8 6
2
1 1,4 7
1
0 3
0 1 2 3 4 1 2 3 4
the segment from (2, 3) to (4, 0); then 3 to 4, which draws the segment
from (4, 0) to (0, 1); then 4 to 5, which draws the segment from (0, 1) to
the midpoint of the first line segment, etc.
Use the program to verify that the three medians of a triangle intersect
in a single point (called the centroid of the rectangle), where a median
is the line segment joining a vertex with the midpoint of the opposite
side. Verify also that the line connecting the midpoints of two sides is
parallel to the third side (Figure 9.13).
In this chapter we give some applications of the Excel VBA random number
generator Rnd. Random number generators have many uses, not the least of
which is Monte Carlo simulations, which are used to approximate theoretical
outcomes of various processes. It should be remarked that the numbers gener-
ated by Rnd and similar functions in other languages are not truly random, as
they rely on deterministic algorithms and seed numbers, the latter to initiate
the algorithm. Thus knowing both the algorithm and the seed one can theoret-
ically predict the output. Nevertheless, these pseudorandom numbers, as they
are called, are sufficiently reliable to find important uses in such diverse areas
as computer simulations, cryptography, and electronic games.
Random Decimals
Since 0 ≤ 8∗ Rnd< 8, the code -3 + 8*Rnd returns a random decimal x
with −3 ≤ x < 5. The function RndDec elaborates on this idea. It takes as
arguments integer bounds lower and upper returns a random decimal x with
lower ≤ x < upper.1
In the above code we have used the statement Randomize before invoking Rnd.
This creates a new seed for Rnd to prevent successive random numbers from
following a pattern.
Random Integers
To generate a random integer one can use Rnd together with Int, which
returns the integer part of a number. For example, to generate random integers
n with 50 ≤ n ≤ 60 use the code 50 + Int(11*Rnd), since 0 ≤ 11∗ Rnd< 11.
More generally, the following function returns a random integer between lower
and upper inclusive.
Function RndInt(lower As Integer, upper As Integer) As Integer
Randomize: RndInt = lower + Int(Rnd * (upper - lower + 1))
End Function
Random Permutations
The function RndPerm(n) takes a positive integer n and returns a permutation
(rearrangement) of the integers 1, 2, . . . , n in the form of an array.
Function RndPerm(n As Integer) As Integer()
Dim perm() As Integer, i As Integer, last, repeat As Boolean
ReDim perm(1 To n)
i = 1: last = 1
perm(1) = RndInt(1, n) 'first member of permutation
Do While last < n
repeat = False
x = RndInt(1, n) 'get random integer
For i = 1 To last 'check if already used
If x = perm(i) Then repeat = True: Exit For 'dup, no good
Next
If Not repeat Then last = last + 1: perm(last) = x 'good
Loop
RndPerm = perm
End Function
Random Positions
Here’s an application that will find uses in later programs that generate
random cell movements. The function takes a cell position Pos and returns
the cell position obtained by adding one of the four random offsets (±1, 0),
(0, ±1), each with probability 1/4, to Pos.row and Pos.col.
Private Function NextRndPos(Pos As TPos) As TPos
Dim i As Integer, j As Integer, NewPos As TPos
Select Case RndInt(1, 4) 'get a random integer between 1 and 4
Case Is = 1: j = 1 'E
Case Is = 2: j = -1 'W
Random Numbers 145
Case Is = 3: i = -1 'N
Case Is = 4: i = 1 'S
End Select
NewPos.row = i + Pos.row 'new row
NewPos.col = j + Pos.col 'new column
NextRndPos = NewPos
End Function
Case Is = 5: i = 1: j = 1 'SE
Case Is = 6: i = 1: j = -1: 'SW
Case Is = 7: i = -1: j = 1: 'NE
Case Is = 8: i = -1: j = -1: 'NW
Probability Distributions
Rolling a die produces a number from 1 to 6. If the die is fair, then each
number has the same (theoretical) probability of appearing, namely 1/6. We
can summarize this with a probability array P(1 To 6), where each entry is
1/6. If, instead, the die is loaded in such a way that, say, the odd numbers
are twice as likely to appear as the even numbers, then the probability array
describing the experiment has entries P(k) = 2/9 if k = 1, 3, 5 and P(k) = 1/9
if k = 2, 4, 6.
The function RndOut, short for “random outcome,” uses Rnd to simulate an
abstract version of the die tossing experiment. The function takes as input a
probability array P whose only requirements are that the entries be positive
and add up to 1, and returns an integer in accordance with these probabilities.
Thus if Rnd produces number x that lies in the interval from 0 to P(1), the
function returns the integer 1; if x lies in the interval from P(1) to P(2), the
function returns the integer 2; etc. (Figure 10.1). Since the interval lengths
are proportional to the probabilities, the function simulates the toss of a
many-sided, possibly loaded, die.
Here is the code. A For Next loop calculates the cumulative probabilities,
that is, numbers obtained by successively adding the members of P.
The program assumes that each list starts in row 6. For each of the columns
1-7 the function RndInt generates a random row number between 6 and the
last entry in the column. The sentence component in that row is then attached
to the current sentence. The complete sentence is printed in cell C3.
Sub NonsenseGenerator()
Dim j As Integer, sentence As String, n As Integer, lRow As Integer
For j = 1 To 7 'run through the columns
lRow = Cells(Rows.count, j).End(xlUp).row 'last nonempty row
n = RndInt(6, lRow) 'get random row in column j
sentence = sentence & " " & Cells(n, j).Value 'attach component
Next j
Range("C3").Value = sentence 'return composite sentence
End Sub
.25
x
1
chapters as well.
148 Discrete Mathematics and Coding
The precise area under the curve in the example is .328125 (derived by
calculus methods). Running the program using npts= 1000, say, yields fair
approximations.
The reader may wish to generalize the program by allowing a lower curve
other than the x-axis. For example, one could use y = sin x for the upper curve
and y = 2x/π for the lower curve, where 0 ≤ x ≤ π/2.
* * *
*
* *
The main procedure RandomWalk sets the initial position of the cell in the
center of the grid. A For Next loop generates the random walk using the
procedures NextRandPos, which returns a new position, and MoveCell, which
erases the old cell and colors the new cell. The cell is moved only if the new
cell is in the grid.
Sub RandomWalk()
Dim Steps As Integer, Speed As Integer, k As Integer
Dim Grid As TGrid, Pos As TPos
Steps = 100: Speed = 15 'motion parameters
L = 5: T = 5: R = 30: B = 40 'boundaries of motion
Grid = MakeGrid(T, L, B, R, 2.5, 13, 24)
Pos.row = (L + R) / 2: Pos.col = (T + B) / 2 'initial pos. of cell
For k = 1 To 200 'do the walk
Call MoveOneStep(Pos, Grid)
Call Delay(Speed)
Next k
MsgBox "clear"
Call ClearGrid(Grid, 0)
End Sub
Figure 10.4 depicts a typical scenario. In the grid on the left, the socially
distanced population consists of 5 healthy individuals and 2 infected people.
In the middle grid, random motion has started, producing contact between
infected and noninfected individuals. The third grid reveals the unfortunate
consequences.
The program assumes that the user has entered letters g for green and r
for red in various cells of the grid on which the activity takes place. The main
procedure SpreadOfDisease calls the function NumOccupied of Section 7.1 to find
the number of individuals (red and green cells) and then calls Initialize to
populate the array Pos with their positions. A For Next loop repeatedly calls
the procedure NewPositions to change the positions of the cells. The latter
procedure also checks if a red and green cell are contiguous and if so turns the
green cell red to simulate the transfer of an infection.
Call ClearGrid(Grid, 0)
End Sub
The procedure Initialize scans the grid for cells with color letters r, g and
records the position and color of the cell. It also colors the cell and adds a
border using ColorCell and AddCellBorder.
Private Sub Initialize(Pos() As TPos, Grid As TGrid)
Dim i As Integer, j As Integer, m As Integer: m = 1
For i = Grid.T To Grid.B 'scan grid for "g", "r"
For j = Grid.L To Grid.R
If IsEmpty(Cells(i, j)) Then GoTo continue
Pos(m).row = i: Pos(m).col = j 'record position
If Cells(i, j).Value = "g" Then
Call ColorCell(Pos(m), 4)
NumGreen = NumGreen + 1 'update number of green cells
ElseIf Cells(i, j).Value = "r" Then
Call ColorCell(Pos(m), 3)
NumRed = NumRed + 1 'update number of red cells
End If
m = m + 1
continue:
Next j
Next i
End Sub
The procedure NewPositions finds new random positions for the red and
green cells using the procedure NextRndPos. The procedure runs through the
position array of the cells with a For Next loop, getting a random position for
a cell and checking if the new position is occupied. If not then the new cell
gets the color of the old cell and is colored red if it has a red neighbor.
Private Sub NewPositions(Pos() As TPos, Grid As TGrid)
Dim m As Integer, NewPos As TPos, color As Integer
For m = 1 To NumCells
NewPos = NextRndPos(Pos(m))
If Not InGrid(Pos(m), Grid) Then GoTo continue
color = CellColor(Pos(m))
If CellColor(NewPos) = xlNone Then
Call ColorCell(Pos(m), xlNone)
Call ColorCell(NewPos, color)
Pos(m) = NewPos 'update position
If NeighborRed(Pos(m)) Then 'infect neighbor
Call ColorCell(Pos(m), 3)
NumGreen = NumGreen - 1
End If
End If
continue:
Next m
End Sub
152 Discrete Mathematics and Coding
The function NeighborRed returns True if a green cell at position Pos has a
red neighbor.
MsgBox ("clear")
Call ClearGrid(G, 0)
End Sub
The procedure Truncate is used to ensure that the particle stays within the
search area, resulting in its display staying in the grid.
Function Truncate(x As Double, y As Double, z As Double) As Double
Dim u As Double
u = y
If y < x Then u = x: If y > z Then u = z
Truncate = u
End Function
Figure 10.5 depicts a typical scenario. The red particle is given a higher
probability to move right toward the green particle (best position so far) rather
than up, since the gap is greater in the former direction.
The reader may wish to test the program using the function
with, say, 30 particles and an attraction value of .35. The actual minimum
occurs at (x, y) = (2, 3); the program yields very close agreement.
Random Numbers 157
The module declares as Public the desired number NCells of plant cells, the
current number CurrNCells of cells at any given stage of growth, and the rate
of growth rate. Their values are entered into the spreadsheet by the user. After
allocating the array Pos for the cell positions, the main procedure SproutWither
calls the procedures that cause the plant to sprout and then wither.
Public NCells As Integer, CurrNCells As Integer, rate As Integer
Sub SproutWither()
Dim Pos() As TPos, Grid As TGrid
Grid = MakeGrid(5, 5, 40, 40, 2.3, 12, 24)
rate = Range("B5").Value 'rate of growth
NCells = Range("B4").Value 'desired number of plant cells
ReDim Pos(1 To NCells) 'positions of cells
Call GrowStem(Pos, Grid, 4)
Call Sprout(Pos, 4) 'grow green plant
Delay (2 * rate)
Call Wither(Pos, 9) 'turn plant brown
Delay (2 * rate)
Call Wither(Pos, 0) 'plant disintegrates
End Sub
The plant stem is located at the bottom center of the grid. The procedure
GrowStem stores the positions of the stem cells in the first four entries of the
array Pos and colors the stem.
158 Discrete Mathematics and Coding
The procedure Sprout consists of a Do While loop that repeatedly calls the
function GrowNewCell to generate the cells of the plant. The function returns
False if growth of a particular cell is impossible due to lack of sunlight, as
determined by the procedure CellOk. The procedure Wither changes the color
in the reverse order of growth by running backward through the array Pos.
Private Sub Sprout(Pos() As TPos, color As Integer)
Dim i As Integer: i = 1
Do While i <= NCells - 4 'grow a total of NCells with stem
If GrowNewCell(Pos, color) Then 'new cell ok?
i = i + 1 'yes, advance
Call Delay(rate)
End If
Loop
End Sub
nc
nc nc
to see if they are part of the plant. Not all neighbors are checked; only those
that surround the front and sides of the potential new cell, which we shall call
the cell’s aura (pictured in light yellow). If any of these are part of the plant,
that is if they are colored green, then the cell is rejected.
160 Discrete Mathematics and Coding
In Figure 10.8, the relevant neighbors (the yellow aura) of a potential new
cell are described in terms of their offsets from the cell. For example, if a new
cell is to be attached on the right, then all row offsets are checked except those
with column offset −1, since that offset refers to the column containing the
original cell. If the cells in the aura have no color or if the color is that of the
border (crawling up the border is acceptable), then CellOK returns True.
Private Function CellOk(Pos As TPos, NewPos As TPos) As Boolean
Dim i As Integer, j As Integer, C As Integer, InAura As Boolean
Dim OK As Boolean, ro As Integer, co As Integer, Neighbor As TPos
If CellColor(NewPos) <> xlNone Then 'new cell already has color
OK = False: GoTo lastline 'so reject
End If
ro = NewPos.row - Pos.row 'offsets of NewPos from Pos
co = NewPos.col - Pos.col
For i = -1 To 1 'check surrounding aura of potential new cell
For j = -1 To 1
InAura = (co > 0 And (j <> -1)) Or (co < 0 And (j <> 1)) Or _
(ro < 0 And (i <> 1)) Or (ro > 0 And (i <> -1))
If InAura Then
Neighbor.row = NewPos.row + i 'pos of aura cell
Neighbor.col = NewPos.col + j
C = CellColor(Neighbor) 'get its cell color
OK = (C = xlNone) Or (C = 24) 'no color or border color
If Not OK Then GoTo lastline
End If
Next j
Next i
lastline:
CellOk = OK
End Function
d c b b c d
a b a a b a
c c
d d
d d
c c
b a a a a b
b c d d c b
Figure 10.10 shows the rotation of the cell labelled 1 as it travels through
the regions. The row, column transformations of the points 1–8 from one region
3 2
4 1
5 8
6 7
to the next are given by the following rules, where (rk , ck ) are the spreadsheet
coordinates of cell labeled k and (r, c) are the spreadsheet coordinates of the
162 Discrete Mathematics and Coding
After setting up the grid, the main procedure RotateAndMove uses the func-
tion GetPattern to populate the first part of the array pattern with the initial
pattern entered by the user. The remaining parts are filled by GetReflections.
The procedure PrintReflections successively prints the patterns in the eight
regions of the coordinate system in a counterclockwise direction.
Public SpinRate As Integer, revolutions As Integer
Public orow As Integer, ocol As Integer
Sub RotateAndMove()
Dim G As TGrid, patterns() As TPos, size As Integer
Dim InitOrigin As TPos
G = MakeGrid(6, 6, 34, 34, 3, 13, 24)
revolutions = WorksheetFunction.Max(Range("B3").Value, 1)
SpinRate = WorksheetFunction.Max(Range("B4").Value, 1)
InitOrigin.row = (G.T + G.B) / 2: InitOrigin.col = (G.L + G.R) / 2
orow = InitOrigin.row: ocol = InitOrigin.col 'initial origin
Call ColorCell(InitOrigin, 33)
size = NumOccupied(G) 'number of cells in pattern
If size = 0 Then Exit Sub
ReDim patterns(1 To 8, 1 To size) '8 regions for pattern
Call GetPattern(patterns, G) 'initialize region 1 of pattern array
Call PrintReflections(patterns, G) 'do the reflections
Call ClearGrid(G, 0) 'clear current origin
Call ColorCell(InitOrigin, 33) 'restore origin origin
End Sub
The procedure GetPattern fills the first of the eight parts of the array
patterns. The procedure GetReflections constructs a reflected pattern from
the previous one, starting with the initial pattern entered by the user.
Private Sub GetPattern(patterns() As TPos, G As TGrid)
Dim i As Integer, j As Integer, m As Integer
m = 1
For i = G.T To G.B 'scan grid for original pattern
For j = G.L To G.R
If Not IsEmpty(Cells(i, j)) Then
'get position mth cell in initial pattern:
Random Numbers 163
The procedure ReflectCell reflects cell position FromCell through the one
of the eight axes into cell position ToCell of the next region.
The final procedure randomly translates the entire system, origin and
pattern.
The construction of the random code table consists of two short random
walks through a table initialized with 1’s, these turning into 2’s along one walk
and into 3’s along the other.
MakeRandomCodeTab = table
End Function
Here is the procedure that reads the code table from the spreadsheet if one
was entered by the user.
Function GetCodeTab() As Integer()
Dim i As Integer, j As Integer, table() As Integer
Dim m As Integer, n As Integer
Do Until IsEmpty(Cells(CodeRow + m, CodeCol)) 'get number of rows
m = m + 1 'of table
Loop
Do Until IsEmpty(Cells(CodeRow, CodeCol+n)) 'get number of columns
n = n + 1 'of table
Loop
ReDim table(1 To m, 1 To n) 'table array
For i = 1 To m
For j = 1 To n
table(i, j) = Cells(CodeRow + i - 1, CodeCol + j - 1).Value
Next j
Next i
GetCodeTab = table 'return table array
End Function
The following procedure displays the random code table if that option was
selected by the user.
Sub DisplayCodeTab(CodeTab() As Integer)
Dim i As Integer, j As Integer
For i = 1 To NumCodeRows
For j = 1 To NumCodeCols
Cells(CodeRow - 1 + i, CodeCol - 1 + j) = CodeTab(i, j)
Next j
Next i
End Sub
The function Initialize randomly fills the grid with red and blue cells
using RndInt. While the integers produced have values from 1 to density, only
the integers 1 and 2 are used. Thus the larger the value of density the less
frequently a molecule (cell) is created, hence the less dense the system.
The next procedure is heart of the module. It moves the molecules randomly
172 Discrete Mathematics and Coding
and lets the molecules through the partition, red from left to right, blue from
right to left.
Private Sub NewPositions(Mole() As TMole)
Dim m As Integer, NewPos As TPos, OldColor As Integer
For m = 1 To UBound(Mole) 'move all the molecules one step
NewPos = NextRandPos(Mole(m).Pos)
'deal with blue molecules on right side of door
If Mole(m).Pos.col = pCol + 1 _
And Mole(m).side = "R" And Mole(m).color = 8 Then
Call ColorCell(Mole(m).Pos, xlNone) 'remove color from blue
Mole(m).Pos.col = Mole(m).Pos.col - 1 'now inside door
Call ColorCell(Mole(m).Pos, Mole(m).color) 'color cell and
Call Delay(15) 'delay it as it passes through door
Call ColorCell(Mole(m).Pos, 24) 'restore partition color
Mole(m).Pos.col = Mole(m).Pos.col - 2 'on left side of door
Call ColorCell(Mole(m).Pos, Mole(m).color) 'color it
Mole(m).side = "L"
'deal similarly with red molecules on left side of door
ElseIf Mole(m).Pos.col = pCol - 1 _
And Mole(m).side = "L" And Mole(m).color = 3 Then
Call ColorCell(Mole(m).Pos, xlNone)
Mole(m).Pos.col = Mole(m).Pos.col + 1
Call ColorCell(Mole(m).Pos, Mole(m).color)
Call Delay(15)
Call ColorCell(Mole(m).Pos, 24)
Mole(m).Pos.col = Mole(m).Pos.col + 2
Call ColorCell(Mole(m).Pos, Mole(m).color)
Mole(m).side = "R"
'deal with cells not at door
ElseIf CellColor(NewPos) = xlNone Then
Call ColorCell(Mole(m).Pos, xlNone)
Call ColorCell(NewPos, Mole(m).color)
Mole(m).Pos = NewPos 'update position of mth particle
End If
Next m
End Sub
r6 r6
g5 y8 g5 y8
Figure 10.15 depicts an abbreviated version of the grid on which the motion
takes place. In the figure on the left, the user has entered into three cells data
in the form of a letter specifying the color of the organism and a number
specifying the length. Thus the label g5 in a cell designates that a green
organism of length 5 should emerge from that cell. For later reference we
refer to such a combination of letter and number as a color-length code. The
figure on the right depicts fully grown organisms executing random walks. The
program includes code to prevent the organisms from colliding.
The module uses the new data type
Here, Body contains the positions of the cells of the organism with Body(1) the
position of the head. The variable currLen is the current length of the organism
as it is growing, and fullLen its length at adulthood. The latter will always
be no bigger then maxLen, which is arbitrarily set at 100.
The main procedure is RandomWalks. The user-entered values of Speed and
Steps set the rate of motion and the number of steps the organisms will
take. The procedure declares an array Org with entries of type TOrg for the
organisms characteristics. Thus Org(m).color is the color of the mth organism,
Org(m).currLen its current size, and Org(m).fullLen its final size. The kth
cell of organism m, starting from the head, is located at Org(m).Body(k).row,
Org(m).Body(k).col. After “birth,” the organism grows from a single cell to its
specified length. During growth the value Org(m).currLen is incremented until
the organism reaches the value Org(m).fullLen. The Public variable NumOrg
contains the number of color-length codes that were entered by the user.
The function NumOccupied from Chapter 7 counts the number of cells con-
taining color-length codes. The procedure Initialize scans the grid looking
for these. Each time it finds one it records the color in Org(m).color and the
desired length in Org(m).fullLen. The current length Org(m).currLen is set to
1, which is the length at birth.
The procedure MoveOneStep moves all the organisms one step. For each m
the procedure NextRandPos of Section 10.4 finds a position for the new head
of organism m. This position is checked by the function CellOk, described in
Section 10.7, to make sure that the organism doesn’t collide with itself or
other organisms. If CellOk approves of the new position, then the organism
is allowed to move. Because the restrictions imposed by CellOk may make
forward motion impossible, after 10 attempts the tail and head are switched
and motion is reversed. It could still be the case that neither forward nor
backward motion is possible, resulting in a frustrated frozen organism, as
illustrated in Figure 10.16.
Here are the array procedures called by MoveOneStep. The first shifts down
the position entries of the mth organism to make room for a new head. The
second reverses the entries of the position array.
At the same time the tail cells are also moving randomly. These “offspring”
eventually reattach to the “mother organism” in the reverse order in which
they were shed. Figure 10.17 illustrates the various phases of the organism.
The main procedure RandomWalkShed sets up the grid for the organism and
then reads the user-entered values of NumCells (the number of cells in the
organism), rate (the rate at which the organism moves, e.g. 5 for very fast, 20
for very slow), and NumSteps (the number of steps the mother organism takes
in her journey). Next, the grid is cleared of any previous cells and Sheet2 is
cleared of any data related to the reconstitution. Memory is then allocated for
the mother and eventual offspring. The procedure Initialize causes the birth
of the mother. Shedding begins with RunShed sometime thereafter.
uses ShiftDown and ReverseCells of the preceding section with maxLen in the
code replaced by NumCells.
The procedure RunShed starts the shedding when the mother has moved one
half of the prescribed number of steps. Shedding takes place every other step
per the statement k Mod 2 = 0. Remove the statement for faster shedding, or
replace it with, say k Mod 5 = 0 for slow shedding. (Or add code that lets the
user make the decision.)
The procedure MoveOrgs moves the entire set of organisms, mother and
offspring, one step at a time.
The procedure Record keeps a log in Sheet2 of the color events of the
program. The procedure Rewind simply reverses the order of events.
Sub Rewind()
Dim i As Integer, row As Integer, col As Integer, color As Integer
For i = LogRow To 1 Step -1 'start at the bottom and work up
row = Sheet2.Cells(i, 1).Value 'get position, color of event
col = Sheet2.Cells(i, 2).Value
color = Sheet2.Cells(i, 3).Value
If color = 3 Then 'reverse color event
Cells(row, col).Interior.ColorIndex = 0
ElseIf color = xlNone Then
Cells(row, col).Interior.ColorIndex = 3
Call Delay(5)
End If
Next i
End Sub
End Select
For k = 1 To NumSteps
Select Case k
Case Is < 100: Call MoveOrgs(Org, 1) 'move original org.
Case Is = 100: Call SplitOrgs(Org, 1) 'split into 2
Case Is < 200: Call MoveOrgs(Org, 2) 'move these
Case Is = 200: Call SplitOrgs(Org, 2) 'split into 4
Case Is < 300: Call MoveOrgs(Org, 4) 'move these
Case Is = 300: Call SplitOrgs(Org, 4) 'split into 8
Case Is < 400: Call MoveOrgs(Org, 8) 'move these
Case Is = 400: Call SplitOrgs(Org, 8) 'split into 16
Case Is < 425: Call MoveOrgs(Org, 16) 'move these
Case Is = 425: Call SplitOrgs(Org, 16) 'split into 32
Case Is < 435: Call MoveOrgs(Org, 32) 'move these
Case Is = 435: Call SplitOrgs(Org, 32) 'split into 64
Case Is < 440: Call MoveOrgs(Org, 64)
End Select
'Call Delay(rate)
Next k
End Sub
The procedure SplitOrgs is passed the array Org and the current number
NumOrgs of organisms. It then proceeds to divide the arrays into twice as many,
each with half the length. Figure 10.20 indicates how this works for the row
arrays of two 32-celled organisms. (The position entries Org(i).Body(j) are
abbreviated O(i,j).) Nested For Next loops carry out the splitting, copying
the array Org(2).Body into the arrays Org(3).Body and Org(4).Body in such
a way so that Org(3).Body contains bottom half of the old Org(2).Body and
Org(3).Body contains the top half of the old Org(2).Body in reverse (causing
the new organisms to initially repel each other).
Private Sub SplitOrgs(Org() As TOrg, NumOrgs As Integer)
Dim m As Integer, k As Integer, OrgSize, Head As TPos
OrgSize = maxLen / NumOrgs
For m = NumOrgs To 1 Step -1 'm goes to 2m,2m-1
For k = 1 To OrgSize / 2 'bottom half in reverse, then 'top half
Org(2 * m).Body(k) = Org(m).Body(OrgSize - k + 1)
184 Discrete Mathematics and Coding
The procedure MoveOrgs uses a For Next loop to move the current group
of organisms precisely one step. This is done by the function MoveOneStep
using the procedures NextRandPos, CellOk, ShiftDown, and ReverseCells of the
module RandomWalks.
Private Sub MoveOrgs(Org() As TOrg, NumOrgs As Integer)
Dim m As Integer
For m = 1 To NumOrgs
Call MoveOneStep(Org(m).Body, NumOrgs) 'move organism m
Next m
LogRow = LogRow + 1 'new log row after all organisms have moved
End Sub
The procedure Record notes in row LogRow of Sheet2 the color change of
each cell using the data triple row, column, oldcolor. The variable LogRow is
incremented after all of the organisms have moved one step. Thus (except for
the initialization phase) each row of Sheet2 contains, in groups of three, the
old color information for all organisms during a single step.
Private Sub Record(Pos As TPos, oldcolor As Integer, advance As Integer)
Random Numbers 185
Dim j As Integer: j = 1
Do Until IsEmpty(Sheet2.Cells(LogRow, j)) 'find an empty spot
j = j + 1 'in LogRow
Loop
Sheet2.Cells(LogRow, j).Value = Pos.row 'first empty spot in LogRow
Sheet2.Cells(LogRow, j + 1).Value = Pos.col
Sheet2.Cells(LogRow, j + 2).Value = oldcolor
If advance = 1 Then LogRow = LogRow + 1 'next row in Sheet2
End Sub
The procedure Rewind reverses the steps of the organisms by restoring the
old color of the cells. It uses a For Next loop to run through the rows in Sheet2
in reverse.
Sub Rewind()
Dim i As Integer, j As Integer, row As Integer, col As Integer
Dim oldcolor As Integer
For i = LogRow - 1 To 1 Step -1 'run through Sheet2 rows in reverse
j = 1
Do Until IsEmpty(Sheet2.Cells(i, j))
row = Sheet2.Cells(i, j).Value
col = Sheet2.Cells(i, j + 1).Value
oldcolor = Sheet2.Cells(i, j + 2).Value
Cells(row, col).Interior.ColorIndex = oldcolor
j = j + 3
Loop
Call Delay(Speed)
Next i
End Sub
Generating a Maze
There are several algorithms that may be used to generate the walls of
a maze. We shall use the following randomized version of Prim’s algorithm,
186 Discrete Mathematics and Coding
A B C D E F G H I J K L
3
4 S
5 Set Dimensions
6 width 10
7 height 8
8 Create Maze
9
10 Solve Maze
11 F
A B C D E F G H I J K L
3
4
5 Set Dimensions
6 width 10
7 height 8
8 Create Maze
9
10 Solve Maze
11
which starts with a grid of cells, an empty list of walls, and an empty list of
visited cells and proceeds as follows:
1. Choose a cell and mark it as visited.
2. Add the walls of the cell to the wall list.
3. While there are still unvisited cells:
1. Choose a random wall from the list. If only one of the cells
separated by the wall is visited, then:
1. Mark the unvisited cell as visited.
2. Add the neighboring walls of the cell to the wall list.
2. Remove the wall from the list.
Figure 10.23 illustrates the process for a small grid consisting of 16 cells. We
have numbered the cells for ease of reference; visited cells are designated by
red numbers. Initially, cell 11 was chosen, marked as visited, and then its walls
Random Numbers 187
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 10 11 12 9 10 11 12 9 10 11 12 9 10 11 12
13 14 15 16 13 14 15 16 13 14 15 16 13 14 15 16
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 10 11 12 9 10 11 12 9 10 11 12 9 10 11 12
13 14 15 16 13 14 15 16 13 14 15 16 13 14 15 16
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 10 11 12 9 10 11 12 9 10 11 12 9 10 11 12
13 14 15 16 13 14 15 16 13 14 15 16 13 14 15 16
added. Next, the wall between 11 and 7 was randomly chosen, cell 7 marked
as visited, its walls added and the wall between 7 and 11 removed. Next, the
wall between 6 and 7 was randomly chosen, cell 6 marked as visited, its walls
added and the wall between 6 and 7 removed. The process continues until all
cells have been visited.
To implement the algorithm in VBA we shall designate a wall internally by
the pair of adjacent cells that the wall separates; externally on the spreadsheet
a wall is an edge between the cells. The data type TWall is used for this:
We shall also need the type TEdge, which refers to the sides (top, left, bottom,
right) of a cell.
The main procedure Maze sets up a grid from user information (width and
height) and initializes some parameters pertaining to the grid. It then calls
MazeGenerator to generate a random maze and later calls MazeSolver to solve
the maze, that is, find a path from user-designated start to finish.
The procedure, MazeGenerator, first reads the desired width and height of
the grid from cells B6 and B7. The grid is constructed using the procedure
MakeGrid from Chapter 7. Next, memory is allocated for the Boolean array
Visited, which keeps track of visited cells, and an array Wall, which holds the
current set of walls. The procedure then calls AddInitialWalls, which selects a
random cell, adds its walls to the list and then marks the cell as visited. A Do
While loop continues the process, repeatedly calling AddNewWalls until all cells
have been visited.
The collection of walls is an array Wall of type TWall. The kth wall is
physically an edge on the spreadsheet between the cells Wall(k).CellA and
Wall(k).CellB. The procedure AddInitialWalls chooses a random cell, adds
walls (cell pairs /edges) to the cell, and removes a random wall (cell pair /edge)
from those just added.
The procedure AddNewWalls chooses a random wall Wall(k) and adds walls
to whichever of the cells Wall(k).CellA or Wall(k).CellB has not yet been
visited, marking that cell as visited. It then removes the wall, as both cells
have now been visited.
CellA CellB
CellA CellB CellB CellA
CellB CellA
The following procedure removes the kth wall from the wall list and the
spreadsheet.
Private Sub RemoveWall(Wall() As TWall, k As Integer)
Dim i As Integer
Call RemoveEdge(Wall(k).CellA, Wall(k).CellB)
For i = k To NumWalls - 1 'shift wall list down to remove wall k
Wall(i) = Wall(i + 1)
Next i
NumWalls = NumWalls - 1
End Sub
Solving a Maze
The remaining procedures in the section are devoted to solving mazes
generated by MazeGenerator. Specifically, they find a path from a designated
Random Numbers 191
start cell marked S to a designated finish cell marked F. The main procedure
here is MazeSolver. The procedure calls StartFinish to find the start and finish
cells. It then calls procedures to solve the maze by the tree method, procedures
to solve the maze by the right hand rule, and finally a procedure to solve the
maze by random motion. The first method is the fastest, the last the slowest.
The procedure StartFinish searches the grid for the letters S and F. Failing
to find them, it uses the upper left and lower right corners, respectively.
The function WallMissing is passed a location (m, n) and an offset (i, j) and
returns True if no edge separates the cells at (m, n) and (m + i, n + j).
xlLineStyleNone)
ElseIf i = -1 Then
WallMissing = (Cells(m + i, n).Borders(xlEdgeBottom).LineStyle = _
xlLineStyleNone)
ElseIf j = 1 Then
WallMissing = (Cells(m, n + j).Borders(xlEdgeLeft).LineStyle = _
xlLineStyleNone)
ElseIf j = -1 Then
WallMissing = (Cells(m, n + j).Borders(xlEdgeRight).LineStyle = _
xlLineStyleNone)
End If
End Function
The procedure TreePath is passed the final position fpos and the tree. It
reads the number k at fpos and then backtracks up the tree, each time seeking
an accessible cell with number k − 1 until it has found the cell marked 1.
contact with a hedge you will reach every other part of the maze. Figure 10.26
shows such a path starting and ending at S.
The first step in the VBA implementation of the rule is to create an
array that lists the edges around each cell of the maze. The following function
generates a two dimensional array Edges of type TEdge that marks Edges(m,n).B
True if Cell(m,n) has a bottom edge and proceeding similarly with the other
edges.
The right-hand rule requires a direction at each juncture. We shall use the
abbreviations N,E,S,W for north (up), east (right), south (down), and west
(left). Thus a right turn means one of the following changes of direction: N
to E, E to S, S To W, or W to N. The following function returns an initial
direction by finding a missing edge in the start cell.
End Sub
10.15 Exercises
1. Write a program that generates an array of, say, 1000 random Double
numbers and calculates the average, median and mode of the numbers.
(See Exercises 7, 8, 9 of Section 5.8.)
2. Write a program Digit3Avg(numIterations) that generates random digits
0 – 9 and returns the percentage of times the digit = 3. Is this what you
would expect? (Try numIterations= 10,000).
3. Write a function RandomVowel(mode) that returns a randomly chosen
uppercase vowel if mode = “upper” or a randomly chosen lowercase
vowel if mode = “lower”. Write the analogous functions RandomConsonant
and RandomLetter
4. Write a program RandomVowelAvg(numiterations) that generates random
letters and returns the percentage of times the letter is a vowel.
5. Write a program ThreeLetters that prints in a column a list of three-
letter lower case words with the middle letter a vowel and the first and
last letters consonants, all randomly chosen. How often do the words
make sense?
6. Write a program FourLetters that prints in a column a list of four-letter
lower case words with first and third letters consonants the second and
198 Discrete Mathematics and Coding
fourth letters vowels, all randomly chosen. How often do the words make
sense?
7. For this exercise the reader should refer back to Exercise 9 of Section 6.9.
Write a program RandomPalindromes that generates a list of random words
(nonsensical or otherwise) of user-entered length that are palindromes.
8. Write a function RandOddInt that returns a random odd number strictly
between given lower and upper limits.
9. Write a procedure RandomRectangle that takes a fixed cell Cell(i, j) in the
top left corner of a grid, generates two random integer offsets r,c, and
draws the rectangle as shown in Figure 10.27. Make a loop with delay
that draws a bunch of these for an interesting visual effect,
(i, j) (i, j + c)
(i + r, j) (i + r, j + c)
Sn udduuuddu
S0
1 2 3 4 5 6 7 8 9
u = 2, d = 1/2
14. Write a program Clusters that does the following: The user enters into
cells of a grid letters referring to colors, as in the procedure LetterToColor.
Running the program should color the cells and cause the cells to execute
random motion as in the program SpreadDisease in Section 10.5. Motion
of a cell should cease as soon as it finds itself attached to a cell of the
same color, thus forming clusters of cells of the same color. Figure 10.28
shows an example. The program is another example of emergent behavior,
y p y p
r
g g
r g
r g
r
p y p y
12
7 8 9 10 11
A B A B
2 weigh 2 weigh
4 4 10
5 7 10 5 11
6 8 11 6 7 12
7 9 12 7 8
8 8 9
of the scale, column B the right. The user should enter coin numbers
in these columns. Pressing weigh should cause the program to tilt the
scale by shifting the numbers. Figure 10.30 illustrates input and output.
User should enter the solution in row 3, e.g., “3 heavy” or “5 light.” The
program should acknowledge whether the answer is correct or not.
16. Write a program RandomWalkOnPattern that produces a random walk on
a user-entered pattern of contiguous x’s in a grid.
17. Write a program RandomWalksWithBarriers, based on RandomWalks, in
which the organisms attempt to escape from enclosures or navigate
simple mazes (Figure 10.31). The user should enter these as x’s in cells;
the program should then color the blocking cells with the grid boundary
color.
x x x x x x x x x x x x x x x
x x
x x
x x x
x x
x x
x x x x x x x x x x x
r5
g3
Linear Analysis
Chapter 11
Linear Equations
The number aij in row i and column j is called the (i, j) entry of A. For
example, the (2, 3) entry of the 2 × 4 matrix [ 15 26 37 84 ] is the number 7. Two
matrices A and B are said to be equal if they have the same dimensions and
equal entries: aij = bij for all indices i and j. A 1 × n matrix is called a row
matrix and an m × 1 matrix a column matrix. The terms row vector and
column vector are also used.
In the programs that follow, matrices are stored in matrix arrays, that is, two
dimensional arrays whose indices start at (1, 1). For example, the declaration
Dim Mat(1 To 5,1 To 6) As Double provides storage for a 5 × 6 matrix array
Mat (with entries automatically initialized to 0). Note that a row matrix is
not the same as a one dimensional array. For example, the declarations Dim
Clearly, all the essential information of the system is represented by the matrix.
Thus augmented matrices provide a shorthand way to represent systems of
linear equations.
The following examples show how systems of linear equations arise in
applications.
Example 11.1. (Mixtures). A one-liter jar is filled with 5 chemicals labeled
1 to 5. The proportions are as follows: The amount of chemical 1 equals the
amount of chemicals 2 and 5 together (in liters), and one-half the amount of
3, 4 and 5 together. The amount of chemical 4 equals the amount of 2 and 3
together, and is one-half the amount of 3 and 5 together. Find the amount of
each chemical.
To describe these conditions mathematically, let xj denote the amount of
chemical j in the jar. The above conditions translate into the equations
x1 = x2 + x5 = 12 (x3 + x4 + x5 ), x4 = x2 + x3 = 12 (x3 + x5 ).
x1 − x2 − x5 =0
2x1 − x3 − x4 − x5 =0
x2 + x3 − x4 =0 (11.3)
x3 − 2x4 + x5 =0
x1 + x2 + x3 + x4 + x5 =1
1 The only purpose of the vertical bar in the matrix is to emphasize that the matrix arose
Using methods developed later in the chapter one can show that
x1 + x2 + x3 + x4 − 2x5 =0
x1 + x2 + x3 − 14x4 + x5 =0
x1 + x2 − 9x3 + x4 + x5 =0 (11.4)
x1 − 5x2 + x3 + x4 + x5 =0
10x1 + 50x2 + 100x3 + 200x4 + 500x5 = 60500
The column under Fj gives the number of hours required at each production
stage to produce one filter of type Fj. The last column gives the total number of
hours available every week for each production stage Pi. We wish to determine
the number xj of filters of type Fj that may be produced if all of the available
hours are utilized.
Here are the equations that must be satisfied:
1
2x1 + 4x2 = 6 E
2 1 x1 + 2x2 = 3 E1 ↔ E2 x1 + x2 = 2
−−−−−−→ −−−−−−→
x1 + x2 = 2 x1 + x2 = 2 x1 + 2x2 = 3
(−1)E1 + E2 x1 + x2 = 2 (−1)E2 + E1 x1 = 1
−−−−−−−−−→ −−−−−−−−−→
x2 = 1 x2 = 1
While the notation is largely self-explanatory, it should be emphasized that
in last operation, for example, it is equation one that is to be altered, not
equation two.
The important feature of equation operations is they do not change the
solutions of the system. For example, the reader may check that the solution
to each of the above systems is the trivial solution of the last one, namely
x1 = 1, x2 = 1. Equally important is the fact that operations may be reversed.
In our example, the reversed operations take the form
x1 = 1 1E2 + E1 x1 + x2 = 2 1E1 + E2 x1 + x2 = 2
−−−−−−→ −−−−−−→
x2 = 1 x2 = 1 x1 + 2x2 = 3
As with equation operations, the notation in the last row operation, for example,
is meant to indicate that it is row one that is to be altered, not row two.
The Gauss-Jordan method consists of a sequence of row operations applied
to the augmented matrix of a system of equations that transforms the matrix
into one with the following properties:
• All zero rows (rows with only zeros) are below all nonzero rows (rows
with at least one zero).
• The first nonzero entry (called the leading entry) in a nonzero row is 1.
• The leading entry in one row is to the left of all leading entries below it.
• All entries above and below a leading entry are zero.
A matrix with these properties is said to be in reduced row echelon form. For
example, the first matrix below is in reduced row echelon form but the second
is not. For emphasis we have enclosed the leading entries in the first matrix by
rectangles.
1 3 0 0 0 1 3 5 1
0 0 1 0 0 0 0 7 2
0 0 0 0 .
0 0 0 1 2
0 0 0 0 0 0 0 0 3
Any matrix may be transformed into reduced row echelon form by a sequence
of row operations. In particular this can be done for the augmented matrix of a
system of linear equations. Since the system of linear equations corresponding
to a matrix in reduced row echelon form is essentially trivial, we now have a
way of finding the solutions of any system (or determining that the system
has no solutions).
The procedure used to transform a matrix A into row reduced echelon form
is described in the following steps. (We exclude the trivial case where every
entry of A is zero.)
(a) Find the leftmost column that has at least one nonzero entry. This is
called a pivot column. The pivot position is at the top of the column in
what is called the pivot row.
(b) Choose a nonzero entry in the pivot column.
(c) Use a type 1 row operation on the matrix to move the entry to the pivot
position.
(d) Use a type 2 row operation to put a 1 in the pivot position.
(e) Use type 3 row operations to put zeros in all but the pivot position of
the pivot column.
212 Discrete Mathematics and Coding
(f) Find the leftmost non-zero column in the matrix consisting of the rows
below the last pivot row and apply steps (b)–(e). Continue the process
until there are no more rows left to modify.
We shall call the process of placing a one in the pivot position of a column
and zeros elsewhere clearing the column. Here some examples of how to apply
the algorithm to the augmented matrix of a system of linear equations.
Example 11.4. To solve the system
we use row operations to find the reduced row echelon form of the augmented
matrix. We have enclosed the entry used to clear the column in a rectangle.
1 1 32 9
2 2 3 9 1
R
2 2 2 (−4)R1 + R2
4 5 6 12 −−−→ 4 5 6 12 −−−−−−−−→
7 8 9 15 7 8 9 15 (−7)R1 + R3
3 9 3 21
1 1 2 2 (−1)R2 + R1 1 0 2 2
0 1 0 −6 −−−−−−−−→ 0 1 0 −6
3
0 1 −2 − 2 33 (−1)R 2 + R 3 0 0 − 2 − 21
3
2
3 21
2
− 3 R3 1 0 2 2
3
− 2 R3 + R1 1 0 0 0
−−−→ 0 1 0 −6 −−−−−−−−→ 0 1 0 −6
0 0 1 7 0 0 1 7
The last matrix is the augmented matrix of the trivial system
x1 =0
x2 = −6
x3 = 7
x1 − x3 = −7
x2 + 2x3 = 8
x1 + 2x2 + 3x3 = 9
4x1 + 5x2 + 6x3 = 12
7x1 + 8x2 + 9x3 = 14
obtained from the system in Example 11.5 by changing the number 15 in the
last equation to 14. This changes the number −48 in the above calculations to
−49, leading to the echelon form
1 0 −1 −7
0 1 2 8
0 0 0 1
x1 − x3 − 2x4 = −3
x2 + 2x3 + 3x4 = 4
A B C D A B C D
4 operations matrices 17 -4R1+R3 1 2 3
5 R1<->R2 7 8 9 18 0 1 2
6 1 2 3 19 4 5 6
7 4 5 6 21 3R2+R3 1 2 3
9 -7R1+R2 1 2 3 22 0 1 2
10 7 8 9 23 0 −3 −6
11 4 5 6 25 answer 1 2 3
13 (-1/6)R2 1 2 3 26 0 1 2
14 0 −6 −12 27 0 0 0
15 4 5 6
spreadsheet. The original matrix was entered in the block B5:D7 and the first
operation entered in row 5. Running the program once results in the printout
of the matrix starting in row 9. The operation in row 9 was then entered;
running the program again produces the matrix starting in row 13. The process
may be continued as long as desired. (In the next section the process is further
automated so that the row echelon form appears automatically.)
The main procedure RowOperations declares the following variables:
• op: the operation string.
Linear Equations 215
Sub RowOperations()
Dim Mat() As Double, nrows As Integer, ncols As Integer
Dim scalar As Double, rowa As Integer, rowb As Integer
Dim optype As Integer, oprow As Integer, op As String
If IsEmpty(Cells(5, 2)) Then Exit Sub 'no matrix entered
oprow = Cells(Rows.Count, 1).End(xlUp).row 'last non blank row
If oprow < 5 Then Exit Sub 'no row op entered
Mat = MatrixIn(oprow, 2) 'read the matrix in oprow
op = Cells(oprow, 1).Value 'read operation
Call ExtractOpData(op, optype, scalar, rowa, rowb)
Call RowOpCalc(optype, scalar, rowa, rowb, Mat()) 'do the row op
nrows = UBound(Mat, 1): ncols = UBound(Mat, 2)
Call MatrixOut(Mat(), oprow + nrows + 1, 2) 'print matrix
End Sub
R1<->R2 (RowOp 1), sR1 (RowOp 2), and sR1+R2 (RowOp 3),
The actual row operations are carried out by RowOpCalc. The procedure is
passed the operation type optype and returns the scalar multiplier (if relevant)
and the row numbers stated in the operation. The procedure uses a Select
Case statement to branch to the desired operation.
product prod of the matrix entries whose reciprocals are the row multipliers
used in type 2 operations of the pivoting process. These variables will be used
in the chapter on determinants and are not currently relevant.
Here is a command button procedure for running the program. The proce-
dure assumes that entry (1, 1) of the input matrix is in cell C3. The output
matrix appears one column to the right of the input matrix. An example is
depicted in Figure 11.2. The input matrix is in rows 3–5 and columns C–G.
The reduced row echelon form of the matrix appears in columns I–M.
Sub CommandButton1_Click()
Dim A() As Double, prod As Double, switches As Integer
A = MatrixIn(3, 3) 'get the matrix
A = RowEchelon(A, prod, switches) 'make the echelon form
Call MatrixOut(A, 3, 4 + UBound(A, 2)) 'one col separation
End Sub
C D E F G H I J K L M
3 1 2 3 4 5 1 0 −1 −2 −3
4 6 7 8 9 10 0 1 2 3 4
5 11 12 13 14 15 0 0 0 0 0
The function RowEchelon is able to find the row echelon form of very large
matrices, limited essentially only by spreadsheet capacity and memory.
11.6 Exercises
1. Find the solutions, if any, of the following systems by stepping through
the row echelon algorithm using the program RowOperations.
220 Discrete Mathematics and Coding
(a)
2x1 + x2 + 2x3 + 2x4 + 2x5 =0
x1 + x2 + 2x3 + 2x4 =1
x1 + 2x2 + 2x3 + x4 + 2x5 =0
x3 + x4 + x5 =1
x1 + x2 + x3 + x4 + 2x5 =1
(b)
3x1 + 3x2 + 3x3 + 2x4 + x5 =2
x2 + x3 + 2x4 + 3x5 =3
2x1 + x3 + x4 =2
2x1 + 2x3 + 3x4 =0
2x1 + 3x2 + 2x3 + x4 + 3x5 =1
(c)
− x2 + 2x3 − x4 + 3x5 =0
2x1 + 3x2 + 2x3 + 4x4 − x5 =1
2x1 + 2x2 + 4x3 − x5 =3
4x1 + x2 + 2x3 + 5x4 − 2x5 =4
x1 + x5 = −1
(d)
7x1 − 7x2 + 36x3 + 48x4 + 49x5 = 47
−17x1 + 33x2 + 24x3 + 33x4 + 4x5 = 22
21x1 + 43x2 + 48x3 − 20x4 + 40x5 =3
24x1 + 14x2 − 8x3 + 38x4 + 42x5 = −1
38x1 + 44x2 − 8x3 + 6x4 + 34x5 = −18
that is, ones along the main diagonal and zeros elsewhere. We shall see the
importance of this matrix in Chapter 13. Write a program IdentityMat
that takes a positive integer n and returns In
9. A matrix with integer entries is called an integer matrix. These may be
generated by applying row operations to the identity matrix. Write a
program RndIntMat that successively generates random integer matrices
starting with the identity matrix and proceeding for as many steps as
desired. After each step the program should print out the result. At
A B C D E F
4 steps 20 4 18 -1
5 size 3 -43 -176 -6
6 lower -4 9 35 3
7 upper 4
the next step the program should read the previous result from the
spreadsheet and start again from there. Figure 11.4 shows the input
and output, including the size of the matrices and the upper and lower
bounds for the random multiplier in operation type 3. The spreadsheet
shows the result of running 20 steps starting from the identity matrix.
Running the program again with this matrix as input would result
in much larger entries. Use the program RowOperations and RndInt to
generate the random row operations.
10. Write a program that generates random integer matrices and finds their
row echelon from. The user should enter the dimensions of the matrix
as well as the upper and lower ranges of the random entries. Use the
function RndInt.
∗11. Write a program ComplexRowOperations that is the complex number
analog of RowOperations. (Use the module ComplexEval of Section 8.4.)
∗12. Write a program ComplexRowEchelon that is the complex number analog
of RowEchelon. (See the module ComplexEval of Section 8.4.)
Chapter 12
Linear Programming
a1 x1 + a2 x2 + · · · + an xn ≤ b or a1 x1 + a2 x2 + · · · + an xn ≥ b,
where a1 , . . . an , b are real numbers and not all of the coefficients ai are zero. The
solution set of a linear inequality is the collection of all sequences (x1 , . . . , xn )
satisfying the inequality. For n = 2 the solution set of a linear inequality may be
graphed as a half-plane. For example, the solution set of 2x1 + 3x2 ≥ 6 consists
x2
2x1 + 3x2 = 6
2
2x1 + 3x2 > 6
1
2x1 + 3x2 < 6
x1
1 2 3
of the points on or above the line 2x1 + 3x2 = 6 (Figure 12.1). This may be
seen by noting that if a point on the line is moved vertically upward, thereby
increasing x2 , the value of 2x1 + 3x2 increases. Alternatively, one may take a
convenient test point either above or below the line and evaluate the expression
2x1 + 3x2 at that point to see whether it is positive or negative. For example,
the point (x1 , x2 ) = (0, 0) lies below the line and satisfies 2x1 + 3x2 < 6.
Therefore, all points below the line satisfy 2x1 + 3x2 < 6 and so all points
above the line must satisfy the reverse inequality.
A system of linear inequalities in the variables x1 , . . . , xn is a finite collection
of linear inequalities in these variables. The solution set of the system is
the collection of all values of (x1 , . . . , xn ) that simultaneously satisfy the
inequalities. This set is called the feasible region of the system.
As seen from the above discussion, a feasible region in two dimensions is
the intersection of half-planes. For example, the green region in Figure 12.2
represents the solution set of the system
2x1 + 3x2 ≤ 6, 3x1 + 2x2 ≤ 6, x1 + x2 ≥ 1, x1 ≥ 0, x2 ≥ 0.
The yellow region represents the solution set of the system
2x1 + 3x2 ≥ 6, 3x1 + 2x2 ≥ 6, 4x1 − x2 ≥ 0, x2 ≥ 0.
x2 x2
3 3
4x1 − x2 = 0
3x1 + 2x2 = 6
2 2
3x1 + 2x2 = 6
x1 + x2 = 1
x1
1 2 3 1 2 3
The vertices of these regions are called corner points and play a fundamental
role in linear programming. Since these points represent solutions of pairs of
linear equations, we shall eventually need an efficient algorithm for solving
such systems. This is developed in Section 12.4. But first we give a precise
description of the general LP problem and some examples.
shall see, the method that solves the first type may be used to solve the others.
In the following three subsections we give the general formulation as well as
examples of each type of LP problem.
Maximize z = c1 x1 + c2 x2 + · · · + cn xn subject to
a11 x1 + a12 x2 + · · · + a1n xn ≤ b1
a21 x1 + a22 x2 + · · · + a2n xn ≤ b2
..
. (12.1)
am1 x1 + am2 x2 + · · · + amn xn ≤ bm
xj ≥ 0, j = 1, . . . n.
a1j
raw a2j Manufacturing
materials .. product j
. Process
amj
This implies that for each i, ai1 x1 units of raw material i are required to
produce x1 items of product 1, ai2 x2 units of raw material i are required to
produce x2 items of product 2, etc. If there are only bi units of raw material i
on hand, then the inequality
must be satisfied. Now suppose that the company makes a profit of cj dollars
on each item of product j. It follows that the company’s total profit is
z = c1 x1 + c2 x2 + · · · + cn xn .
Maximizing total profit while respecting the raw material limitations is therefore
an LP problem of the type (12.1). ♦
226 Discrete Mathematics and Coding
Minimize w = c1 y1 + c2 y2 + · · · + cn ym subject to
a11 y1 + a12 y2 + · · · + a1n ym ≥ b1
a21 y1 + a22 y2 + · · · + a2n ym ≥ b2
..
. (12.2)
an1 y1 + an2 y2 + · · · + anm ym ≥ bn
yj ≥ 0, j = 1, . . . m,
a1j
nutrients a2j
.. supplement j
anj .
If the cost of producing one item of supplement j is cj dollars, then the quantity
w = c1 y1 + c2 y2 + · · · + cn yn
Nonstandard LP Problems
These arise in maximization or minimization problems with mixed con-
straints. For example, if in Example 12.2 it is deemed that the package should
contain no more than b1 units of nutrient element 1, then the first inequality
in (12.2) must be reversed, leading to a nonstandard problem. Here is another
example:
Linear Programming 227
weekly production
a1 a2 a3
facility 1 facility 2 facility 3
x13 x21 x23 x31
x22
x11 x12 x32 x33
three production facilities and three outlets. The quantity ai is the weekly
production of facility i, bj is the weekly demand at outlet j, and xij is the
number of items that need to shipped from facility i to outlet j. If the cost
of shipping one item from facility i to outlet j is denoted by cij , we can then
state the problem of minimizing cost as the following LP problem:
Minimize
w = c11 x11 + c12 x12 + c13 x13 + c21 x21 + c22 x22 + c23 x23
+ c31 x31 + c32 x32 + c33 x33
subject to
x11 + x12 + x13 ≤ a1
x21 + x22 + x23 ≤ a2
x31 + x32 + x33 ≤ a3
x11 + x21 + x31 ≥ b1
x12 + x22 + x32 ≥ b2
x13 + x23 + x33 ≥ b3
x11 ≥ 0, x12 ≥ 0, . . . , x33 ≥ 0. ♦
228 Discrete Mathematics and Coding
The feasible region is shown in green in Figure 12.6. The region is bounded by
the lines whose equations are obtained by changing the above inequalities to
equalities:
The vertices of the region, called corner points, are obtained by solving pairs
of linear equations. For example, the point (4, 7) is the solution of the system
x2
(0, 8) x1 + 4x2 = 32
7 (4, 7)
2x1 + 3x2 = 29
6
5 (7, 5)
4
3 3x1 + 7x2 = 52.5
2 5x1 + 3x2 = 50
The parallel dotted lines in the figure are the graphs of 3x1 + 7x2 = z,
where z = 45.5 for the lower line and z = 52.5 for the upper line. As the
dotted line moves up, the value of x2 increases, hence so does the value of
z. Thus the largest possible value of z (satisfying the given constraints) is
Linear Programming 229
attained at the instant the entire line emerges from the region, namely (by
inspection) at the point (4, 7). At this point, the objective function z has the
value 3 · 4 + 7 · 7 = 61, which is necessarily the maximum value of z on the
region. A similar analysis holds for the minimum.
The preceding example illustrates the following basic principle of linear
programming in two variables:
The first step is to convert the system of inequalities into a system of equalities.
This is accomplished by adding nonnegative slack variables s1 , s2 , and s3 to
230 Discrete Mathematics and Coding
the left sides of the first three inequalities above, resulting in the system of
linear equations
5x1 + 3x2 + s1 = 50
2x1 + 3x2 + s2 = 29
(12.3)
x1 + 4x2 + s3 = 32
−3x1 − 7x2 + z = 0
We have included in the system the objective equation z = 3x1 + 7x2 , written
in a manner consistent with that of the first three equations. We now have a
system of four linear equations in the nonnegative unknowns x1 , x2 , s1 , s2 , s3
and z. The system generally has infinitely many solutions; we seek one in the
feasible region that produces the largest value of z.
x2
x1 = s3 = 0
s2 = s3 = 0
s1 = s2 = 0
s1 = x2 = 0
x1 = x2 = 0 x1
There are several important things to notice. First, the feasible region is
described by the inequalities
x1 ≥ 0, x2 ≥ 0, s1 ≥ 0, s2 ≥ 0, s3 ≥ 0.
Second, corner points are obtained by setting certain pairs of these variables
equal to zero. For example, the corner point that is the intersection of the lines
5x1 + 3x2 = 50 and 2x1 + 3x2 + = 29 may described by the pair of equations
s1 = 0 and s2 = 0. However, not every pair of such equations gives a corner
point. For example, the pair s2 = 0 and x2 = 0 leads to the equation 2x1 = 29,
which produces a point outside the feasible region. Third, setting suitable pairs
of the variables x1 , x2 , s1 , s2 , s3 equal to zero in the first three equations of
(12.3) leads to systems that can be solved uniquely for the remaining variables,
producing a value of z. The fundamental idea behind the simplex method is to
start at the known corner point x1 = 0, x2 = 0 (at which z has the value zero)
and move to corner points that increase z the fastest until further movement
no longer produces an increase. Here are the details:
Since the maximum value of z occurs at a corner point and since these
are obtained by setting pairs of the variables x1 , x2 , s1 , s2 , and s3 equal to
zero, at each stage of the process it must be determined which pair of these
variables should be set equal to zero. These are called the inactive variables;
the remaining variables are called active variables. We start by taking x1 and
Linear Programming 231
Notice that the system variables are written along the top of the tableau and
the active variables in the left-most column (marked in red). With x1 = x2 = 0
one can read the remaining solutions s1 = 50, s2 = 29, s3 = 32, and z = 0
directly from the tableau. These values form what is called a basic solution
associated with the tableau. Note that the active variables are distinguished
by the fact that their columns contain a single one and zeros elsewhere. (The
z column also has this property.)
Having initially chosen x1 and x2 as the inactive variables, we must now
decide if this choice gives us the maximum value of z or if we should move
to another corner point, that is, make another pair of variables inactive, to
obtain a larger value of z. For this we look at the equation z = 3x1 + 7x2
and notice that an increase of 1 unit in x1 results in an increase of 3 units
in z, and an increase of one unit in x2 results in an increase of 7 units in z.
That these increases are possible is reflected in the tableau by the fact that
the entries in the last row in the columns under x1 and x2 are negative. Since
an increase of one unit in x2 results in the largest increase of z, for efficiency
we should move in the positive x2 direction. This will keep x1 inactive (its
value is still 0), but will change x2 to an active variable, requiring one of the
variables s1 , s2 , or s3 to become inactive. Because x2 is to become active, we
must construct a system equivalent to (12.3) whose augmented matrix has its
x2 column consisting of a single one and zeros elsewhere, the hallmark of an
active variable. This can be accomplished by row operations on the tableau,
pivoting on a suitable entry chosen from the first three positions of x2 column
and clearing that column. To choose the pivot entry in that column we form
the ratios of the first three entries of the last column of the tableau with the
corresponding entries of the x2 column:
50 29 32
, , and . (12.4)
3 3 4
The last ratio is the smallest, and since this corresponds to the third entry
in the x2 column, we choose that entry as the pivot. (The rationale for this
choice is explained later.) Performing row operations on the augmented matrix
232 Discrete Mathematics and Coding
of (12.3) we have
5 3 1 0 0 0 50 1
5 3 1 0 0 0 50
R
4 3 2
2 3 0 1 0 0 29 −−→ 1 3 0 1 0 0 29
1
1 4 0 0 1 0 32 1 0 0 0 8
4 4
−3 −7 0 0 0 1 0 −3 −7 0 0 0 1 0
17
0 1 0 − 34 0
−3R3 + R1 4 26
5 0 0 1 −3 0 5
−3R3 + R2
41 4
(12.5)
7R3 + R4 1
1 0 0 0 8
4 4
−−−−−−−−→ 5
−4 0 0 0 7
1 56
4
From (12.5) we obtain the new tableau
x1 x2 s1 s2 s3 z
17
s1 4 0 1 0 − 34 0 26
5
s2 4 0 0 1 − 34 0 5
x2 1 1
4 1 0 0 4 0 8
− 54 0 0 0 7
4 1 56
The variables x1 and s3 are now the inactive variables and s1 , s2 , x2 are active.
The change in the status of x2 and s3 is described by saying that x2 is the
entering variable and s3 the departing variable. The basic solution to the
system, which may be read directly from the tableau, is
x1 = 0, s3 = 0, s1 = 26, s2 = 5, x2 = 8, z = 56.
Since all variables are nonnegative, the corresponding point lies in the feasible
region and is the corner point x1 = 0, s3 = 0, that is, x1 = 0, x2 = 8. At this
point z = 56. We remark that it is precisely because we needed all the variables
to be nonnegative that we chose the entry in the x2 column corresponding
to the smallest ratio as the pivot entry. Indeed, the entries 26 and 5 in the
last column of (12.5) result from the operations (−3)8 + 50 and (−3)8 + 29,
respectively. Dividing these by 3 we obtain the expressions −8 + 50/3 and
−8 + 29/3, which are positive precisely because the ratio 32/4 = 8 in (12.4) is
less than the ratios 50/3 and 29/3. To illuminate further, suppose instead that
we had pivoted on the entry corresponding the ratio 50/3. We would then have
5
1 13 0 0 0 50
5 3 1 0 0 0 50 1 3 3
2 R
3 1
3 0 1 0 0 29 −−→ 2 3 0 1 0 0 29
1 4 0 0 1 0 32 1 4 0 0 1 0 32
−3 −7 0 0 0 1 0 −3 −7 0 0 0 1 0
5 1 50
−3R1 + R2 3 1 3 0 0 0 3
−3 0 −1 1 0 0 −21
−4R1 + R3
7R1 + R4 − 17 0 − 4
0 1 0 − 104
3 3 3
−−−−−−−−→ 26
0 7
0 0 1 350
3 3 3
Linear Programming 233
0 0 1 − 17 9
− 17 R 2 + R1 5 5 0 9
4
4 3
1
− 4 R2 + R 3
1 0 0
5 −5 0 4
5
+ 2
R R 0 1 0 −5 0 7
4 2 4 5
−−−−−−−−→ 0 0 0 1 1 1 61
This gives the tableau
x1 x2 s1 s2 s3 z
s1 0 0 1 − 17
5
9
5 0 9
x1 4 3
1 0 0 5 − 5 0 4
x2 0 1 0 −5 25 0 7
0 0 0 1 1 1 61
x1 = 4, x2 = 7, s1 = 9, s2 = s3 = 0, z = 61.
Since there are no negative entries in the last row, z cannot be further increased.
Thus the maximum value 61 of z occurs when x1 = 4 and x2 = 7, in agreement
with results of the preceding section.
234 Discrete Mathematics and Coding
The main procedure Simplex assumes that the augmented matrix of the
system is entered with the (1, 1) entry in cell D6 and the coefficients of the
objective function are entered in the row below. This provides coded input for
the program. The input for the above example is displayed in Figure 12.7. The
D E F
6 5 3 50
7 2 3 29
8 1 4 32
9 3 7
user also enters the text “max” or “min” in cell B6, informing the program
whether a maximum or a minimum is to be calculated. The following are the
main variables and arrays of the module:
• mode: set equal to “max” or “min”.
• TabRow: first row of current tableau, initially set to 6.
• TabCol: first column of current tableau. Always equals 4.
• NRows: number of rows of tableau.
• NCols: number of columns of input and, later, of tableaus.
• NumX: number of x-variables.
• NumS: number of slack variables.
• NumV: total number of variables (= NumX + NumS).
Linear Programming 235
The procedure MakeInitialTab reads the spreadsheet data into the array
Tableau, adds suitable ones and zeros, and configures the last row, which holds
the negatives of the coefficients of the objective function.
At this stage, the Tableau array for our example looks like
5 3 1 0 0 0 50
2 3 0 1 0 0 29
1 4 0 0 1 0 32
−3 −7 0 0 0 0 1
Before printing the first tableau the procedure GetLabels is called, which
places in the array VLabs the labels x1, . . ., xn, s1, . . ., sm, and z, where n =
NumX and m = NumS. These are used for the top and left sides of the tableau.
The “subscripts” of the labels are appended to x and s by the concatenation
operator &.
The procedure InitStatus initializes the array VStat. At any stage, the array
tells the program the status of the ith variable in list x1 , . . . , xn , s1 , . . . , sm .
Thus VStat(i)= 0 means that the ith variable in the list is inactive; while
VStat(i)= 1 means that it is active. For our example, calling InitStatus pro-
duces VStat = {0,0,1,1,1}.
The procedure PrintTab prints the tableaus, taking into account which
variables are active. For our example it produces
x1 x2 s1 s2 s3 z
s1 5 3 1 0 0 0 50
s2 2 3 0 1 0 0 29
s3 1 4 0 0 1 0 32
−3 −7 0 0 0 1 0
The function GetNextTab constructs a new tableau from the last tableau.
The key component is the procedure ClearMatCol, introduced in Section 11.5.
The function first determines the pivot column and the pivot row and then
calls Pivot to clear the column. The arrays Active and VStat are then updated.
The function GetPivotCol used in the preceding function finds the most
negative entry in the last row of the tableau if one exists, and returns its
column number. Otherwise the function returns zero.
The function GetPivotRow forms ratios of the last column with the pivot
column and returns the row number corresponding to the smallest ratio. It
consists of two For Next loops. The first loop finds some ratio, while the second
finds the smallest.
The procedure PrintMaxSol prints out the solution to the LP max problem,
printing the labels x1, . . ., xn, s1, . . ., sm, z first. Solutions will be placed
under these. The columns are then scanned for inactive and active variables.
If vstat(j)= 0, that is, if the jth variable in the list x1 , . . . , xn , s1 , . . . , sm is
inactive, then a zero is placed under the jth label. Otherwise, the jth variable
is active and the position i of the 1 in the jth column is determined. The
rightmost value in the tableau T(i,NCols) is then printed under the jth label.
The last value printed is z.
Next i
End If
Next j
Cells(SolRow, TabCol - 2 + NCols).Value = Tabl(NRows, NCols) '= z
Cells(SolRow, TabCol - 1).Value = "solutions:"
End Sub
0 0 0 1 1 1 61
solution: 4 7 9 0 0 61
This is the problem of Section 12.5. The last tableau of the solution for that
problem together with a new row of labels is
x1 x2 s1 s2 s3 z
s1 0 0 1 − 17
5
9
5 0 9
x1 4 3
1 0 0 5 − 5 0 4
x2 0 1 0 −5 25 0 7
0 0 0 1 1 1 61
y1 y2 y3 wmin
The minimum value is the maximum value of the dual problem and
occurs at the entries y1 , y2 , . . . in the last row under the slack variables
s1 , s2 , . . ..
Thus in our example the minimum value is 61 and it occurs at the point where
y1 = 0, y2 = 1, y3 = 1 as indicated in the tableau.
To use Simplex for minimization problems the user enters the problem
exactly as in the LP max case (see Figure 12.7). Setting mode to min causes
the program to replace the entered matrix by its transpose.
The final procedure PrintMinSol places subscripted y’s and a w under the
last row of the tableau.
Sub PrintMinSol()
Dim i As Integer, j As Integer
TabRow = TabRow + NRows 'position of solution in spreadsheet
For j = 0 To NumS - 1
Cells(TabRow, TabCol + NumX + j).Value = "y" & j + 1
Next j
Cells(TabRow, TabCol + NCols - 1).Value = "w"
End Sub
242 Discrete Mathematics and Coding
x2
x1 + x2 = 4
−4x1 + x2 = 1
4
3x1 + 2x2 = 6
3
2x1 + 3x2 = 6
2
x1
1 2 3 4
The first step is to append nonnegative variables to the left sides of the
constraint inequalities to produce equalities. This requires adding nonnegative
slack variables s3 , s4 , and s5 to the last three constraints and subtracting
nonnegative surplus variables s1 and s2 from the first two constraints. The
Linear Programming 243
x1 = x2 = 0, s1 = s2 = −6, s3 = 1, s4 = 4, s5 = 2.
x2 = s1 = s5 = 0, x1 = 2, s2 = −2, s3 = 9, s4 = 2.
244 Discrete Mathematics and Coding
Since s2 < 0, we apply the rule again. The sole nonzero entry under s2 in the
preceding tableau is in row 2, so we choose column 2, the only column with a
positive entry in row 2 (excluding the last). Thus the pivot entry is in row 2
and column 2. Applying row operations results in the tableau
x1 x2 s1 s2 s3 s4 s5 z
s1 0 0 −1 23 0 0 − 53 0 − 43
x2 0 1 0 − 13 0 0 − 23 0 2
3
s3 0 1 14 25
0 0 3 1 0 3 0 3
1
s4 0 0 0 3 0 1 − 13 0 4
3
x1 1 0 0 0 0 0 1 0 2
0 0 0 − 23 0 0 5
3 1 22
3
All solutions are nonnegative so we are in the feasible region and we can now
solve the LP max problem by applying the program Simplex. This yields the
final tableau
x1 x2 s1 s2 s3 s4 s5 z
s1 0 0 1 0 0 2 −1 0 4
x2 0 1 0 0 0 1 −1 0 2
s3 0 0 0 0 1 −1 5 0 7
s2 0 0 0 1 0 3 −1 0 4
x1 1 0 0 0 0 0 1 0 2
0 0 0 0 0 2 1 1 10
From this we see that the maximum value of z is 10 and that the maximum
occurs at the point x1 = x2 = 2.
x2
s3 = s4 = 0
s1 = s3 = 0
s4 = s5 = 0
s2 = s3 = 0
s2 = s5 = 0
x1 = x2 = 0 x1
x2 = s5 = 0
Linear Programming 245
12.8 Exercises
1. Describe the region in the figure in terms of linear inequalities.
x2
7 (2, 7)
6 (6, 6)
5
4
3 (8, 3)
2
1 (1, 2) (5, 1)
x1
1 2 3 4 5 6 7 8 9
2. Use the geometric method to find the maximum and minimum of the
objective functions (a) z = 3x − 7y and (b) z = 6x + 7y subject to
constraints
3. Use the geometric method to find the maximum and minimum of the
objective functions (a) z = x−y and (b) z = 5x+3y subject to constraints
x+2y ≥ 7, 2x−y ≥ −1, 2x−3y ≥ −11, x+2y ≤ 19, 3x−y ≤ 22, x−3y ≤ 2.
4. Solve the following standard LP max problems by hand and check your
answers with Simplex.
(a) Maximize z = 5x1 + 6x2 subject to
5x1 + x2 ≤ 5, x1 + x2 ≤ 5, x1 + x2 ≤ 2.
5. Solve the following standard LP min problems by hand and check your
answers with Simplex.
(a) Minimize w = 2x1 + 3x2 subject to
6. An ice cream store produces two flavors, chocolate and vanilla. Suppose
that each quart of chocolate sells for $7.00 and each quart of vanilla
sells for $6.00. Suppose also that a quart of chocolate requires 5 eggs,
4 cups of cream, and 3 cups of sugar, while a quart of vanilla requires
4 eggs, 3 cups of cream, and 4 cups of sugar. If the store has on hand
50 eggs, 29 cups of cream, and 32 cups of sugar, how many quarts x1
of chocolate and x2 of vanilla should be produced from this supply to
maximize revenue from the sale.
7. A company produces m different models of portable smoke shifters. A
shifter goes through a sequence of n manufacturing steps, each requiring
a certain number of hours. Suppose shifter model j requires aij hours to
complete step i and there are only bi hours available to carry out the
steps. Suppose also that the company makes a profit of cj dollars on
each item of model j. Set up the LP problem whose solution produces
the maximum total profit given the stated constraints.
8. A poultry farmer wishes to buy no less than 100 pounds of grain feed
that contains barley, corn, rye, and wheat. There are 9 feed stores in
his county, each selling premixed grain. The amount per pound of each
grain in the mixtures is given in the table. The cost per pound of each
mixture is given in the last row.
1 2 3 4 5 6 7 8 9
barley .5 .1 .5 .3 .4 .1 .1 .6 .7
corn .3 .4 .2 .4 .3 .3 .5 .2 .1
rye .1 .2 .2 .1 .2 .4 .2 .2 .1
wheat .1 .3 .1 .2 .1 .2 .3 0 .1
cost .074 .068 .072 .076 .060 .057 .044 .041 .040
Here we have used summation notation as a short way of writing the sum.
A dot is usually placed between the n-tuples to indicate a dot product. For
example,
(1, 2, 3, 4, 5) · (1, 1/2, 1/3, 1/4, 1/5) = 1 + 1 + 1 + 1 + 1 = 5.
The product AB of an m × n matrix A and an n × p matrix B is the m × p
matrix C whose (i, j)th entry is the dot product of row i of A and row j of B.
We indicate this by the following scheme:
a11 · · · a1k · · · a1n b11 · · · b1j · · · b1p c11 · · · c1j · · · c1p
.. .. .. .. .. .. .. .. ..
. . . . . . . . .
ai1 · · · aik · · · ain bk1 · · · bkj · · · bkp = ci1 · · · cij · · · cip
.. .. .. .. .. .. .. .. ..
. . . . . . . . .
am1· · · amk · · · amn bn1 · · · bnj · · · bnp cm1 · · · cmj · · · cmp .
In summation notation,
n
X
cij = aik bkj .
k=1
Note that the product is defined only when the “inner dimensions” of the
matrices (in this case n) are the same.
Here’s an example of a matrix multiplied by its transpose:
1 4
1 2 3 4 2 3 = 30 20 = 10 3 2 ;
4 3 2 1 3 2 20 30 2 3
4 1
and the other way around
1 4 17 14 11 8
2 3 1 2 3 4 14 13 12 11
3 2 4 =
11 12 13 14 .
3 2 1
4 1 8 11 14 17
250 Discrete Mathematics and Coding
The example shows that, unlike multiplication of numbers, AB and BA need not
be the same even if the dimensions are set up correctly for the multiplications.
The function MultMat(A,B,error) below returns the product of the matrix
arrays A and B in that order. The procedure sets error to True if the matrices
do not have the proper dimensions required for multiplication. If one of the
matrices has dimensions 1 × 1 we invoke scalar multiplication.
The matrix with ones and zeros in this calculation is called the 3 × 3 identity
matrix. (See Exercise 8.) The key fact here is that multiplication by the identity
matrix leaves the original matrix unchanged. More generally, the n × n identity
matrix In is defined as
1 0 0 ··· 0
0 1 0 · · · 0
In = . . . .
. . ...
.. .. ..
0 0 0 · · · 1 n×n
Matrix Algebra 251
This yields
1 0 0 1 −1 1
0 1 0 −1 0 1 , (13.1)
0 0 1 1 1 −2
which resolves into the following three systems, written in matrix form, equiv-
alent to the original ones:
1 0 0 x11 1 1 0 0 x12 −1
0 1 0 x21 = −1 , 0 1 0 x22 = 0
0 0 1 x31 1 0 0 1 x32 1
and
1 0 0 x13 1
0 1 0 x23 = 1 .
0 0 1 x33 −2
Using the identity matrix property in these equations we see that the columns
of x’s are precisely the columns of the right side of the augmented matrix
(13.1).
The method of the preceding example may be used to find the inverse of
any square matrix A (if it exists): Simply apply the row echelon algorithm to
the matrix [ A | I ] to obtain [ I | A−1 ]. The right side is then the inverse of A.
Here we have used the customary notation A−1 for the inverse.
What if a matrix has no inverse? The method just described reveals that
fact as well. For example, the matrix on the right below is the reduced row
echelon form of the matrix [ A | I ] on the left:
1 0 −1 0 − 83 5
1 2 3 1 0 0 3
7
[ A | I ] = 4 5 6 0 1 0 −−→ 0 1 2 0 3 − 34 .
7 8 9 0 0 1 0 0 0 1 −2 1
Since the identity matrix does not appear in the left half of the matrix, A has
no inverse.
The inverse matrix operation may be used to solve systems of equations
that have the same number of unknowns as equations. This involves writing
the system in (11.2) as a matrix equation AX = B, where
a11 a12 · · · a1n x1 b1
a21 a22 · · · a2n x2 b2
A= . .. .. , X = .. , and B = .. .
.. ..
. . . . .
am1 am2 ··· amn xn bm
The matrix A is called the coefficient matrix of the system. If m = n and A−1
exists, then, as in ordinary algebra, one can multiply the equation AX = B
on both sides by A−1 , resulting in A−1 AX = A−1 B. Since A−1 A = IX = X,
the solution of the system is given by the matrix equation X = A−1 B. This
Matrix Algebra 253
Here, aij is the number of units from sector i needed to produce one unit from
sector j.
The input-output matrix represents the internal demand of the economy.
There may also be additional demand from outside the system. This is repre-
sented by the so-called external demand vector
d1
D = ... ,
dn
where, di is the demand in units for the commodity from sector i (over some
fixed period of time). For the economy to meet both external and internal
demands, a certain level of production is required. This is represented by the
so-called production vector
x1
..
X = . ,
xn
where xj is the total number of units produced by sector j (over the same
time period). The problem then is to determine the values xj that allow the
sectors to satisfy both internal and external demands.
256 Discrete Mathematics and Coding
The solution of the problem rests on the observation that since aij is the
number of units from sector i required to produce one unit from sector j, the
quantity aij xj is the number of units from sector i required to produce xj
units from sector j. Letting j vary we see that for each i the sum
represents the total number of units from sector i required to produce x1 units
from sector 1, x2 units from sector 2, etc. Adding to this the external demand
di for commodity i we find that the total production xi from sector i must
satisfy
xi = ai1 x1 + ai2 x2 + · · · + ain xn + di , i = 1, . . . , n.
These equations may be assembled into a matrix equation X = AX + D, where
x1 a11 a12 · · · a1n d1
x2 a21 a22 · · · a2n d2
X = . , A = . .. .. , and D = .. .
.. .. ..
. . . .
xn an1 an2 ··· ann dn
X = (I − A)−1 D.
This represents the production levels of the sectors needed to satisfy both the
internal and external demands.
The columns of (I − A)−1 have an interesting economic interpretation:
Suppose the demand D changes by an amount ∆D, so the new demand is
D + ∆D. The production vector then changes from X to X + ∆X. Thus we
have the equations
Subtracting we get
(I − A)−1 ∆D = ∆X.
Now suppose total demand for items from sector one increases by 1 but total
demand for items from the remaining sectors stays the same. Thus ∆D has
a 1 in the first position and 0’s elsewhere. The reader may check that ∆X is
then the first column of (I − A)−1 . In general, the jth column of (I − A)−1 is
the (vector) amount that production must change in order to accommodate
an increase of 1 unit of demand from the jth sector.
The solution X of an IO model is easily obtained using the procedure
InvertMat. The module IOModel below assumes that the IO matrix A is entered
into the spreadsheet with its (1, 1) entry in cell D3 and that the demand
matrix D is entered in column 2 starting at B3. The program then prints
Matrix Algebra 257
B D E F H I
3 100 .10 .50 0 .20 1905
4 400 .20 .30 .40 .01 1673
5 300 0 .20 .10 .04 878
6 600 .30 .20 .50 .50 3890
the production vector X one column to the right of A. Figure 13.1 shows an
example. Columns B and D–H were entered by the user and column I contains
the production vector calculated by the program (rounded).
The module begins by allocating memory for various matrix arrays. The
function AddSubMat forms the matrix array Diff=I-A, and InvertMat inverts it
to form DiffInv. The procedure MultMat then produces the desired production
vector DiffInv D.
Sub IOModel()
Dim x() As Double, D() As Double, Diff() As Double
Dim DiffInv() As Double, A() As Double, Id() As Double
Dim nrows As Integer, ncols As Integer, err As Boolean
A = MatrixIn(3, 4) 'get IO matrix A
D = MatrixIn(3, 2) 'get demand vector D
nrows = UBound(A, 1): ncols = UBound(A, 2) 'IO matrix dimensions
If nrows <> ncols Then MsgBox "Matrix not square!": Exit Sub
Id = IdentityMat(nrows) 'make the identity matrix I
Diff = AddSubMat(Id, A, -1, err) 'make I-A
DiffInv = InvertMat(Diff, err)
If Not err Then
x = MultMat(DiffInv, D, err) 'find X = (I-A)^(-1)D
Call MatrixOut(x, 3, 5 + ncols) 'print X
Else
MsgBox "Solution not found."
End If
End Sub
P (x) = c0 + c1 x + c2 x2 + c3 x3
Note the reversal of notation: the c’s are the unknowns and the x’s and y’s (the
given data) are the constants. We can simplify the description of the system
by introducing the sums
n
X n
X
Sk = xki and Tk = xki yi . (13.3)
i=1 i=1
Matrix Algebra 259
c0 S0 + c1 S1 + c2 S2 + c3 S3 = T0
c0 S1 + c1 S2 + c2 S3 + c3 S4 = T1
c0 S2 + c1 S3 + c2 S4 + c3 S5 = T2
c0 S3 + c1 S4 + c2 S5 + c3 S6 = T3
Matrix methods may now be used to solve the system for the c’s in terms of
the S’s and T ’s.
It is just as easy to formulate the solution for general polynomials of degree
m. In this case one has the analogous system
c0 S0 + c1 S1 + · · · + cm Sm = T0
c0 S1 + c1 S2 + · · · + cm Sm+1 = T1
(13.4)
...
c0 Sm + c1 Sm+1 + · · · + cm S2m = Tm
If we set
S0 S1 ··· Sm c0 T0
S1 S2 ··· Sm+1 c1 T1
S= .. .. .. , C = .. and T = ..
. . ··· . . .
Sm Sm+1 ··· S2m cm Tm
then system (13.4) may be written SC = T . The polynomial of best fit therefore
has coefficients given by the matrix C = S −1 T .
It is interesting to note that if the degree m of the desired polynomial is
chosen to be one less than the number of data points n, resulting in a system of
n equations in n unknowns, then one obtains an exact fit, that is, P (xi ) = yi
for each i. This is the same thing as saying that the error term
n n
X 2 X 2
c0 + c1 xi + c2 x2i · · · + cn−1 xn−1
P (xi ) − yi = i − yi ,
i=1 i=1
is zero. This means that each of the terms in the sum is zero. It follows that
the ci ’s are then solutions of the system
1 x1 x21 · · · xn−1
1 c0 y1
1 x2 x22 · · · xn−1 c1 y2
2
.. = .. , (13.5)
..
. . .
1 xn x2n ··· xn−1
n cn−1 yn
is a consequence of the fact that the xi ’s are distinct. (This may be easily
verified using techniques from the next chapter.)
In the remainder of the section we develop a program that calculates the co-
efficients c0 , c1 , . . . , cm of the polynomial of best fit and graphs the polynomial.
Typical numerical input data is given in Figure 13.2. The coordinates of the
A B C D E
3 degree left right inc
4 5 2 7 .01
5 x data y data coeff x values y values
6 1 3
7 2 5
8 3 6
9 4 8
data points are entered in columns A and B, and the degree of the polynomial
is entered in cell B4. The left and right endpoints of the graphing interval are
entered in cells C4 and D4, respectively, and the graphing increment is entered
in cell E4.
The main procedure PolyFitData reads the x and y data from columns A
and B and then invokes PolyCoeff to calculate the coefficient matrix C. The
latter is passed to PolyPoints, which generates points for the graph of the
polynomial. The procedure ClearColContent from Section 9.2 removes any
previously generated data.
Sub PolyFitData()
Dim m As Integer, left As Double, right As Double, inc As Double
Dim XYdata() As Double, C() As Double, error As Boolean
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear charts
Call ClearColContent(6, 5, 6) 'and data
m = Range("B4").Value 'degree of polynomial
left = Range("D4").Value 'left endpoint of graphing interval
right = Range("E4").Value 'right endpoint of graphing interval
inc = Range("F4").Value
XYdata = MatrixIn(6, 1) 'read data
C = PolyCoeff(m, XYdata, error) 'calculate the coefficients
If error Then Exit Sub
Call MatrixOut(C, 6, 4) 'print coefficients
Call PolyPoints(C, left, right, inc) 'points for the graph
Call GraphPolynomial: Call GraphDataPoints()
End Sub
The procedure PolyCoeff constructs the matrices S and T . It does this using
the procedures SumPowers, which calculates the required sums of powers of the
Matrix Algebra 261
x-data, and SumProducts, which calculates the required sums of powers of the
x-data times the y-data. The matrix S is then inverted using the function
InvertMat and the result is multiplied by the column matrix T .
The functions SumPowers and SumProducts are based on the formulas in (13.3).
The function PolyPoints takes the coefficient matrix C and calculates the
values y = c0 + c1 x + · · · + cm xm for values of x determined by the given
interval and increment. The x and y values are placed in columns E and F.
Sub GraphPolynomial()
Dim lrow As Long
lrow = Cells(Rows.Count, 5).End(xlUp).row 'last row of data
With Sheet1 _
.ChartObjects.Add(left:=400, Width:=600, Top:=50, Height:=400)
.Chart.SetSourceData Source:=Range("F" & 6 & ":" & "F" & lrow)
.Chart.ChartType = xlLine
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "graph"
.Chart.SeriesCollection(1).XValues = _
Range("E" & 6 & ":" & "E" & lrow)
End With
End Sub
Sub GraphDataPoints()
Dim lrow As Long
lrow = Cells(Rows.Count, 1).End(xlUp).row
With Sheet1 _
.ChartObjects.Add(left:=1060, Width:=375, Top:=50, Height:=400)
.Chart.SetSourceData Source:=Range("B" & 6 & ":" & "B" & lrow)
.Chart.ChartType = xlXYScatter
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "graph"
.Chart.SeriesCollection(1).XValues = _
Range("A" & 6 & ":" & "A" & lrow)
End With
End Sub
Y = A1 X + B1 , Y = A2 X + B2 , . . . , Y = Ak X + Bk
D E F H J
38 1 .95 .005 −.002 .85
39 −.005 .93 .5
41 2 .035 −.11 −.05 .07
42 .27 .01 .005
44 3 −.04 .11 .083 .07
45 .27 .01 .06
47 4 0 0 0 .01
48 0 .24 −.4
(not shown) for the case of four affine transformations, that is, four pairs of
matrices A, B, and the probabilities of a pair being selected. The matrices
A are entered in columns E and F, the matrices B in column H, and the
probabilities in column J. Column D provides reference numbers for the data
sets. Running the program for this particular input produces the so-called
Barnsley fern (see Figure 13.4). Like the Sierpinski triangle, which was the
output of ChaosTriangleGame, the fern is an example of a fractal, a pattern
that looks the same at any magnification. The fern was introduced by Michael
Barnsley in his book Fractals Everywhere (1988).
264 Discrete Mathematics and Coding
Sub AffineIterations()
Dim XRange As String, YRange As String, NumIterations As Integer
If ChartObjects.Count > 0 Then ChartObjects.Delete
Call ClearColContent(8, 1, 2)
NumIterations = 10000 'specify number of iterations
Call ComputeValues(NumIterations) 'calculate points
XRange = "A" & 8 & ":" & "A" & 8 + NumIterations
YRange = "B" & 8 & ":" & "B" & 8 + NumIterations
With Sheet1 _
.ChartObjects.Add(Left:=200, Width:=800, Top:=10, Height:=500)
.Chart.ChartType = xlXYScatter
.Chart.HasTitle = True
.Chart.ChartTitle.Text = ""
.Chart.SetSourceData Source:=Range(YRange)
.Chart.SeriesCollection(1).XValues = Range(XRange)
End With
End Sub
the probability array P. This determines the row of the corresponding affine
transformation. For each iteration the point Y is calculated and printed.
Sub ComputeValues(NumIterations As Integer)
Dim j As Integer, row As Integer, P() As Double, error As Boolean
Dim A() As Double, B() As Double
Dim Y() As Double, X(1 To 2, 1 To 1) As Double
P = Probabilities() 'get the probabilities
For j = 1 To NumIterations
row = 38 + 3 * (RndOut(P) - 1)
A = MatrixIn(row, 5)
B = MatrixIn(row, 8)
Y = MultMat(A, X, error)
Y = AddSubMat(Y, B, 1, error)
Cells(j + 7, 1).Value = Y(1, 1) 'print x value of point
Cells(j + 7, 2).Value = Y(2, 1) 'print y value of point
X(1, 1) = Y(1, 1): X(2, 1) = Y(2, 1):
Next j
End Sub
The reader may wish to experiment with the program by varying the input
parameters of the Barnsley fern. Mutations of the fern may be found online.
We shall call the portion of the columns containing the user-entered matrices
the matrix queue. These start in cell C5 and the letters denoting the matrices
in cell B5. The program assumes matrices in the queue are separated by a
blank row. The answer appears one row below these. Figure 13.5 shows sample
input and output.
A B C D
3 expression 2A + B matrix queue
5 matrices A 1 2
6 3 4
8 B 1 1
9 1 1
11 answer 3 5
12 7 9
The main procedure MatrixCalculator first clears any answer from a pre-
vious run then reads the expression to be evaluated into expr. The variable
Idx points to the current symbol in expr; it ranges from 1, the beginning
of the expression, to Len(expr). After an error check, the procedure calls
InsertAsterisks, described below. The function MatEval(0) doles out the cal-
culation tasks. The 0 places the program in the lowest precedence, matrix
addition. Any other operation will be performed first. If MatEval returns with
error = False, then the matrix answer Z is printed.
Sub InsertAsterisks()
Dim char As String, nextchar As String, k As Integer: k = 1
Do While k <= Len(Expr)
char = Midd(Expr, k, 1): nextchar = Midd(Expr, k + 1, 1)
If char Like "[A-Z]" And nextchar Like "[A-Z]" Or _
char Like "[A-Z]" And InStr("0123456789.", nextchar) > 0 Or _
char Like "[A-Z]" And nextchar = "(" Or _
InStr("0123456789.", char) > 0 And nextchar Like "[A-Z]" Or _
InStr("0123456789.", char) > 0 And nextchar = "(" Or _
char = ")" And nextchar = "(" Or _
char = ")" And nextchar Like "[A-Z]" Or _
char = ")" And InStr("0123456789.", nextchar) > 0 Then
Expr = InsertString(Expr, k, "*")
End If
k = k + 1
Loop
End Sub
The procedure MatEval distributes the various calculation tasks to the matrix
calculation procedures. It is similar to the function ComplexEval of Section 8.4
in that it calls itself to perform subtasks. The procedure consists of a Do While
loop that advances the index Idx, which points to the symbols in the input
expression Expr. The loop ends when either Idx exceeds its maximum value
Len(Expr) or an error is encountered. The loop begins by extracting the current
symbol from Expr. A Select Case statement decides which action to take based
on the value of the symbol. If the symbol is a number it goes to the first case;
if it is a capital letter it goes to the second case. The remaining cases treat
the other symbols using the procedures AddSubMat, ScalarMult, MultMat, and
PowerMat described in earlier sections.
The function GetScalar extracts a number string from Expr. Since matrix
multiplication and scalar multiplication are treated similarly, the function
returns the scalar as a 1 × 1 matrix.
If (k < 48 Or k > 57) And (char <> ".") Then Exit For
x = x & char
Next i
Idx = i 'Idx now after number
Z(1, 1) = CDbl(x) * sign
GetScalar = Z
End Function
The procedure ErrorCheck, although not foolproof, catches the main types of
errors. It is similar in principle to the procedure of the same name in Section 8.4
in that each symbol has a restricted set of legal immediate predecessors and
successors. Here are the rules:
1. An operator +- must be followed by a capital letter, a left parenthesis, a
period, or a digit.
2. The operator ^ must be followed by a left parenthesis or a positive digit.
3. The operator ^ must be preceded by a right parenthesis, a capital letter,
or a number.
4. A right parenthesis or capital letter must be followed by a right or left
parenthesis, one of the operators +-^, a digit, a period, a capital letter,
or nothing.
5. A left parenthesis cannot be followed by ^.
6. There must be the same number of left parentheses as right parentheses.
Sub ErrorCheck()
Dim s As String, sprev As String, snext As String, i As Integer
Dim e(1 To 6) As Boolean
For i = 1 To Len(expr)
s = Midd(expr, i, 1)
sprev = Midd(expr, i - 1, 1): snext = Midd(expr, i + 1, 1)
e(1) = InStr("+-", s) > 0 And snext Like "[!A-Z]" And _
snext <> "(" And snext <> "." And snext Like "[!0-9]"
e(2) = (s = "^") And snext <> "(" And snext Like "[!0-9]"
270 Discrete Mathematics and Coding
e(3) = (s = "^") And sprev <> ")" And sprev Like "[!A-Z]" _
And sprev <> "." And sprev Like "[!0-9]"
e(4) = (s = ")" Or s Like "[A-Z]") And i < L And _
InStr("+-^", snext) = 0 And _
snext Like "[!A-Z]" And snext <> "(" And snext <> ")" _
And snext Like "[!0-9]" And snext <> "."
e(5) = s = "(" And snext = "^"
error = e(1) Or e(2) Or e(3) Or e(4) Or e(5)
If error Then Exit For
Next i
e(6) = Not IsMatch(expr, "(", ")")
For i = 1 To 6
If e(i) Then errorType = i: error = True: Exit Sub
Next i
End Sub
13.10 Exercises
1. Calculate the inverse by hand if it exists (the inverse, not your hand).
Check your answers using MatrixCalculator.
1 −1 0 1 2 3 1 3 5 0 3 5
(a) 0 1 −1 (b) 2 3 1 (c) 7 9 11 (d) 7 9 11
1 0 1 3 1 2 13 15 17 13 15 17
a b
= ad − bc. (14.1)
c d
To find the value of higher order determinants one has the choice of several
methods. We begin with the method called expansion along the first row. The
method is recursive in that it depends on the value of lower order determi-
nants, ultimately reducing to the calculation (14.1). Here is the definition for
determinants of order 3:
a11 a12 a13
a a23 a a23 a a22
a21 a22 a23 = a11 22 − a12 21 + a13 21 .
a32 a33 a31 a33 a31 a32
a31 a32 a33
Note that the terms in the expansion are the entries of row 1 with alternating
signs multiplied by second order determinants. These are obtained from the
original matrix by deleting row 1 and the successive columns of the row 1
entries. The calculation is completed by using (14.1). Here is an example:
1 2 3
5 6 4 6 4 5
4 5 6 =1· −2· +3· = −3 − 2(−6) + 3(−3) = 0.
8 9 7 9 7 8
7 8 9
1 2 3 4
5 6 7
0 5 6 7 8 9
=1· 0 8 9 =1·5· = 1 · 5 · 8 · 10 = 400. ♦
0 0 8 9 0 10
0 0 10
0 0 0 10
• Switching a pair of rows (or columns) changes the sign of the determinant.
For example,
2 −1 3 3 2 7
R ↔R
1 3
4 8 9 ======= − 4 8 9 .
3 2 7 2 −1 3
3 −9 12 1 −3 4
4 8 22 = 3·2·5· 2 4 11 .
35 −20 15 7 −4 3
Here, 3 was factored from the first row, 2 from the second, and 5 from
the last. Notice that this is very different from factoring a matrix, where
a factor is taken from all rows.
• Adding a multiple of one row to another does not change the value of
the determinant.
This is useful because it allows the introduction of zeros into columns,
making the resulting determinant easier to evaluate. The analogous
property for columns holds as well.
Example 14.2. Here’s an example that uses the second and third properties
above to evaluate a determinant.
2 6 0 1 3 0 1 3 0
−2R1 + R2
2 9 3 =2 2 9 3 ======= 2 0 3 3
3 14 −5 3 14 −5 −3R1 + R3 0 5 −5
1 3 0 1 3 0
−1R2 + R3
=2·3·5 0 1 1 ======= 30 · 0 1 1 = −60. ♦
0 1 −1 0 0 −2
The last calculation comes from the fact, noted earlier, that the value of an
upper triangular matrix is the product of the entries along the diagonal.
The function SubMatrix takes a square matrix, a row, and a column and
returns the matrix obtained by removing the row and column. It is a short
version of the more general program considered in Exercise 9 of Chapter 13.
Determinants 277
The reader may wish to compare the speeds of the two versions by calculating
determinants of the form
0 ··· 0 0 1
0 ··· 0 2 1
0 ··· 3 0 1
.. . .. .. ..
. .. . . .
n ··· 0 0 1
for large n. For example for n = 10 the echelon version returns the value
-3628800 almost instantaneously while the recursive version is considerably
slower. For larger values of n the recursive version is not practical on standard
computers.
It should be emphasized that Cramer’s rule applies only to the case where
the determinant of the coefficient matrix is nonzero. If this condition fails then
the system may have infinitely solutions or no solution.
Cramer’s rule is readily implemented in VBA using the determinant function
developed in the preceding section. The module Cramer assumes that the user
has entered the coefficient matrix of the system with top left corner in C3.
The right side of the system is entered one column to the right. Figure 14.1
gives an example of input and output of the program. The coefficient matrix
of the 7 × 7 system was entered in columns C–I, the right side in column K,
column J as a separator. The solution (rounded) appears in column N.
C D E F G H I K M N
3 4 3 −4 7 3 −1 7 −1 x1 = −2.28
4 2 −1 1 −9 4 3 4 2 x2 = 0.76
5 1 −2 3 1 −5 −4 9 −5 x3 = −0.09
6 3 6 8 9 6 2 3 3 x4 = −0.20
7 2 3 5 −4 7 −3 2 8 x5 = 1.17
8 2 4 1 8 9 9 5 7 x6 = −0.28
9 −4 6 −6 5 −3 2 −7 6 x7 = 0.44
Since there are two versions of Determinant, there are, accordingly, two
versions of CramersRule: CramerRuleEchelon and CramerRuleRecursive. As ex-
pected, for large systems the recursive version is considerably slower.
280 Discrete Mathematics and Coding
ax1 + by1 + c = 0
ax2 + by2 + c = 0
ax3 + by3 + c = 0
x1 y1 1
x2 y2 1 = 0.
x3 y3 1
y2 1 x 1 x y2
x− 2 y+ 2 = 0. (14.3)
y3 1 x3 1 x3 y3
Arguing as in the case of three points on a line we see that the points are
co-planar if and only if
x1 y1 z1 1
x2 y2 z2 1
= 0.
x3 y3 z3 1
x4 y4 z4 1
Thus if (x2 , y2 , z2 ), (x3 , y3 , z3 ), and (x4 , y4 , z4 ) are given points and (x1 , y1 , z1 )
is a variable point (x, y, z) then the equation of a plane passing through the
given points is
x y z 1
x2 y2 z2 1
= 0.
x3 y3 z3 1
x4 y4 z4 1
Expanding along the first row yields the alternate form
y2 z2 1 x2 z2 1 x2 y2 1 x1 x2 y2
y3 z3 1 x − x3 z3 1 y + x3 y3 1 z = x2 x3 y3 . (14.4)
y4 z4 1 x4 z4 1 x4 y4 1 x3 x4 y4
a1 = q1 − p1 , a2 = q2 − p2 , b1 = r1 − p1 , b2 = r2 − p2
It may be shown that the area A of the triangle P QR is given by the formula
1 a1 a2
± ,
2 b1 b2
not all in the same plane (see Figure 14.2). Define quantities
a1 = q1 − p1 , a2 = q2 − p2 , a3 = q3 − p3
b1 = r1 − p1 , b2 = r2 − p2 , b3 = r3 − p3
c1 = s1 − p1 , c2 = s2 − p2 , c3 = s3 − p3 .
282 Discrete Mathematics and Coding
R
S
P
It may be shown that the volume V of the tetrahedron is given by the formula
a a2 a3
1 1
± b1 b2 b3 ,
6
c1 c2 c3
whichever sign gives a positive value.
recovered from `, h, k. The center (h, k) of the circle is called the circumcenter
of the triangle; it is the also the intersection of the perpendicular bisectors of
the sides (see Figure 14.3).
The function Circumcenter(P,Q,R,h,k,r,error) implements this process. It
takes as input the three points written as 1 × 2 arrays and calculates h, k and r.
The following procedure uses the graph facility of VBA to graph the triangle
and the lines from the circumcenter to the vertices. It should be compared
with the program GraphIncenter in Section 9.5.
Sub GraphCircumcenter()
Dim XRange As String, YRange As String
Dim P() As Double, Q() As Double, R() As Double
Dim h As Double, k As Double, radius As Double
Dim sol() As Double, Grid As TGrid, error As Boolean
'clear old chart and data
If ChartObjects.Count > 0 Then ChartObjects.Delete
Call ClearColumns(8, 1, 2) 'clear columns 1,2 starting at row 8
Grid = MakeGrid(3, 4, 27, 28, 2.3, 15, 24)
Call InstallCoord(Grid, Grid.B, Grid.L)
284 Discrete Mathematics and Coding
Call GetVertexCoord(Grid, P, Q, R)
Call Circumcenter(P, Q, R, h, k, radius, error)
If error Then Exit Sub
'list the X and Y data in columns 1 and 2
Cells(8, 1).Value = P(1): Cells(8, 2).Value = P(2)
Cells(9, 1).Value = Q(1): Cells(9, 2).Value = Q(2)
Cells(10, 1).Value = R(1): Cells(10, 2).Value = R(2)
Cells(11, 1).Value = P(1): Cells(11, 2).Value = P(2)
Cells(12, 1).Value = h: Cells(12, 2).Value = k
Cells(13, 1).Value = Q(1): Cells(13, 2).Value = Q(2)
Cells(14, 1).Value = h: Cells(14, 2).Value = k
Cells(15, 1).Value = R(1): Cells(15, 2).Value = R(2)
XRange = "A" & 8 & ":" & "A" & 15
YRange = "B" & 8 & ":" & "B" & 15
With Sheet1 _
.ChartObjects.Add(Left:=580, Width:=460, Top:=15, Height:=400)
.Chart.SetSourceData Source:=Range(YRange) 'y values
.Chart.ChartType = xlXYScatterLines
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Circumcenter"
.Chart.SeriesCollection(1).XValues = Range(XRange) 'x values
End With
End Sub
14.7 Exercises
1. Use the determinant program to find the determinants of matrices A of
the form
a 0 0 0 ∗ ∗ ∗ d 0 0 0 d
∗ b 0 0 ∗ ∗ c 0 0 0 c ∗
,
∗ ∗ c 0 ∗ b 0 0 0 b ∗ ∗
∗ ∗ ∗ d a 0 0 0 a ∗ ∗ ∗
1 x1 x21 . . . xn−1
1
1 x2 x22 . . . xn−1 2
1 x3 x2 . . . xn−1
V = 3 3 .
. .. .. ..
.. . . ... .
1 xn x2n . . . xn−1 n
∗11. Write a program CxCramer that is the complex number analog of Cramer.
∗12. Refer to Section 8.5 for this exercise. Write a program PolyDeterminant
that is the polynomial analog of Determinant.
∗13. Let A be an n × n real matrix. An eigenvalue of A is a number x such
that AX = xX or, equivalently, (A − xI)X = 0 for some n × 1 matrix X
whose entries are not all zero. Eigenvalues have important applications
in physics, engineering, and data analysis, to mention just a few. If x
is an eigenvalue of A then it must be the case that det(A − xI) = 0,
286 Discrete Mathematics and Coding
otherwise Cramer’s rule would imply that the entries of X are all zero,
contradicting the definition of eigenvalue. The determinant det(A − xI)
is a polynomial in x and is called the characteristic polynomial of A.
Using the result of the previous exercise, write a program CharPoly that
reads a matrix A and returns its characteristic polynomial.
Part III
Logic
Chapter 15
Propositional Logic
We have already had some acquaintance with logic in the form of the VBA
logical operators And, Or, and Not. In this chapter we introduce mathematical
versions of these operators as well as others. The operators act on arbitrary
statements and thus place the notion of logical operator in the broader context
of formal propositional logic.
pr + r0 ≡ p + r0 (15.1)
This may be verified directly by assigning truth values or by using the program
Stmt2TruthTable. Instead, we give a proof using some of the above laws. First
we calculate the negation of the left side of (15.1):
On the other hand, the negation of the right side of (15.1) is, by DeMorgan’s
law and double negation,
(p + r0 )0 ≡ p0 r.
Thus both sides of (15.1) have the same negations and so must be equivalent.
The example shows that negating a compound statement sometimes reveals a
simplification that might otherwise go unnoticed.
B C D E F H
5 p q r s t (p + qr0 + rs0 )−> (p0 + qst0 )
6 1 1 1 1 1 0
7 1 1 1 1 0 1
8 1 1 1 0 1 0
9 1 1 1 0 0 0
10 1 1 0 1 1 0
11 1 1 0 1 0 1
row 5 starting at column B; a single column separates the variables from the
statement. The program reads the information in row 5 and generates truth
Propositional Logic 293
values for the variables (single letters) and the statement. The symbol → for
the conditional is entered by concatenating the symbols − and > to produce
−>. Similarly, the biconditional symbol ↔ is entered as <−>.
The main procedure Stmt2TruthTable uses a Do While loop to create a string
Vars from the entered variables. The input statement Stmt is then retrieved. For
the above example, Vars= "pqrst" and Stmt= "(p+qr'+rs') -> (p' + qst')".
To simplify the coding, asterisks are inserted between the character pairs
)q, )(, p(, 'p, '(, and pq, so that, for example, Stmt becomes
"(p+q*r'+r*s')->(p'+q*s*t')". A For Next loop processes each row of the
truth table. The function InsertVarValues takes Stmt and replaces the vari-
ables by their values in the row to produce VarStmt. In our example, for i = 1
the function returns the string VarStmt = "(1+1*1'+1*1')->(1'+1*1*1')". The
function Eval calculates the truth value of VarStmt.
Sub Stmt2TruthTable()
Dim Stmt As String, VarStmt As String, VarVals As String
Dim Vars As String, NVars As Integer, i As Integer
Do While Not IsEmpty(Cells(5, i + 2)) 'get variable name string
Vars = Vars & Cells(5, i + 2).Value
i = i + 1
Loop
NVars = Len(Vars)
Stmt = Cells(5, 3 + NVars).Value 'get statement
Stmt = RemoveWhiteSpace(Stmt) 'remove extra spaces
Stmt = InsertAsterisks(Stmt) 'for ease of coding
For i = 1 To 2 ^ NVars 'insert 1's and 0's into Stmt
VarStmt = InsertVarValues(Stmt, Vars, i) 'producing VarStmt
'evaluate statement for this row of variable values
Cells(5 + i, 3 + NVars).Value = Eval(VarStmt, 1, 0, err)
Next i
End Sub
The procedure TruthVal, which generates the truth values of the variables
p, q, . . ., is based on the algebraic function
(i − 1)/2n−j , 1 ≤ i ≤ 2n , 1 ≤ j ≤ n,
where n is the number of variables, i is a row number, and j is a column
number. For example, if n = 3 then 0 ≤ i − 1 ≤ 7 and the preceding formula
generates the following fractions (the denominator values for j = 1, 2, 3 are
combined for notational convenience):
i−1 0 1 2 3 4 5 6 7
= , , , , , , , .
2n−j 4, 2, 1 4, 2, 1 4, 2, 1 4, 2, 1 4, 2, 1 4, 2, 1 4, 2, 1 4, 2, 1
Taking the integer parts x of these fractions yields the corresponding sequences
x = 0, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1, 3, 1, 2, 4, 1, 2, 5, 1, 3, 6, 1, 3, 7.
(combined in accordance with the above notational scheme). These values are
then converted by the function y = (1 + (−1)x )/2 to produce eight rows with
the truth values
y = 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0.
The y values are inserted into the copy VarStmt of Stmt using the VBA function
Replace of Section 6.5.
The engine of the program is the function Eval, which takes an expression like
"(1+1*1'+1*1')->(1'+1*1*1')" and finds its value. The procedure is entirely sim-
ilar in concept to earlier calculators such as ComplexEval (Section 8.4), calling
itself to perform the calculations using the procedures Negation, Conjunction,
Disjunction, Conditional, and Biconditional.
Propositional Logic 295
B C D E
5 p q r
6 1 1 1 1
7 1 1 0
8 1 0 1 1
9 1 0 0 1
10 0 1 1
11 0 1 0
12 0 0 1
13 0 0 0
Sub CommandButton1_Click()
Call MakeTruthColumns
End Sub
Sub MakeTruthColumns()
Dim i As Integer, j As Integer, x As Integer, y As Integer
Dim N As Integer, row As Integer, col As Integer
row = 7: col = 2 'variables start here
Do While Not IsEmpty(Cells(row, N + col)) 'get no. of variables
N = N + 1
Loop
For i = 1 To 2 ^ N 'form the variable columns
For j = 1 To N '(N = number of variables)
Cells(i + row, col + j - 1).Value = TruthVal(i, j, N)
Next j
Next i
End Sub
The function FormStatement runs down the column under the desired state-
ment, selecting the appropriate basic conjunction if a 1 appears in the column,
ignoring blanks.
298 Discrete Mathematics and Coding
Sub FormStatement()
Dim i As Integer, j As Integer, Stmt As String, L As Integer
Dim N As Integer, Vars As String, row As Integer, col As Integer
row = 5: col = 2 'variables start here
Do While Not IsEmpty(Cells(row, N + col)) 'get variables
Vars = Vars & Cells(row, N + col).Value 'variables string
N = N + 1
Loop
'if a 1 is in statement column, append the conjunction to disjunction
For i = 1 To 2 ^ N
If Cells(i + row, col + N + 1).Value = 1 Then
Stmt = Stmt & MakeConj(i, Vars, row, col) & "+"
End If
Next i
'chop off last + sign
Cells(5, 3 + Len(Vars)).Value = Midd(Stmt, 1, Len(Stmt) - 1)
End Sub
Note that these arguments are valid even though most elephants cannot fly.
Arguments (a)–(d) are known, respectively, as hypothetical syllogism, dis-
junctive syllogism, modus ponens, and modus tollens. Here is a calculation
verifying the validity of the disjunctive syllogism (b):
As the last statement is a tautology so is the first, and the argument is valid.
Similar calculations establish the validity of the other arguments. Alternately,
one can use truth tables.
Sometimes a modus ponens argument is in the form illustrated by the
following examples:
300 Discrete Mathematics and Coding
These may be recast in standard form by replacing the first premise in the
first argument by ”If x is a bird, then x can fly” and the first premise in the
second argument by ”If x is a man, then x is not an island.”
An invalid argument may be phrased in the manner of a valid argument,
with premises p1 , p2 , . . . pn and conclusion q, but in this case the implication
(15.2) is no longer a tautology.
Here are some of examples of invalid arguments even though in each case
the conclusion is true.
6 2.
(e) If elephants cannot fly, then 1 =
1 6= 2.
Elephants cannot fly.
15.6 Exercises
1. Show by taking negations that (r + q 0 + rq 0 ) ≡ (r + q 0 )
2. Suppose p, q, and r are statements such that only p is true. Which of
the following are true?
(a) pq + pq 0 + r
(b) pq + p0 + r0
(c) (p0 q + pr0 )(pq 0 + p0 r)
(d) p0 + (pq + pr)
3. Construct truth tables by hand and check your answers with
Stmt2TruthTable.
(a) p0 q 0 + p + q
(b) p0 q + q 0 p
(c) (p0 + q 0 )(p + q 0 )(p0 + q)
Propositional Logic 301
(d) p → (p + q 0 )
(e) (p + p0 ) → p0
(f) p(p → q) → q
4. Use Stmt2TruthTable to determine which of the following statements are
tautologies.
(a) (p + p0 )(q 0 + r)
(b) (p + p0 ) + (q + r0 )
(c) (pq + p0 q) + (pq 0 + p0 q 0 )
(d) [p + (q 0 + r)][p + (q 0 + r0 )]
(e) [(p + q)(p0 + q)][(p + q 0 )(p0 + q 0 )]
(f) [p + (q 0 + r)] → [p + (q 0 + r0 )]
(g) [(p → q)(q → r)] → (p → r)
(h) (p + q)(q + r)(r + p) ↔ [pq + (qr + rq)]
(i) (p → q) ↔ [q(p + r) + (p + qr)]
5. Use Stmt2TruthTable to verify the following equivalences:
(a) pq + pq 0 r ≡ pq + pr
(b) (p + q)(p + q 0 + r) ≡ (p + q)(p + r)
(c) pq + pq 0 ≡ p
(d) (p + q)(p + q 0 ) ≡ p
(e) p + p0 q ≡ p + q
(f) p(p0 + q) ≡ pq
6. Use laws of logic to simplify
(a) p0 q 0 + (p + q 0 )0
(b) (pq 0 + qr)(qr0 + pr)
(c) (pq 0 + p0 q)pr((p0 + q 0 ) + (pq 0 + p0 q))
(d) (((pq 0 )0 + rp0 )0 (pq 0 r0 ))0
7. The XOR (“exclusive or”) in logic is defined by p XOR q if and only if
either p or q is true but not both. Use truth tables to show that p XOR q
is equivalent to the statement pq 0 + p0 q. Give meaning to the statement
p XOR q XOR r.
8. The Sheffer stroke2 of p and q, denoted by p | q or p NAND q, is defined
as p0 + q 0 . Thus p | q is false exactly when p and q are both true. Use
truth tables to verify the following:
(a) p0 ≡ p | p.
(b) pq ≡ (p | q) | (p | q).
(c) p + q ≡ (p | p) | (q | q).
Check your answers with Stmt2TruthTable.
9. The Peirce arrow p ↓ q of statements p, q (also written as p NOR q) is
2 Named after Henry M. Sheffer, who in 1913 showed that the standard logical operators
(e) p → [q → (r → s)]
p
s
14. Use the laws of logic to show that the hypothetical syllogism, disjunctive
syllogism, modus ponens, and modus tollens are equivalent, respectively,
to the tautologies
(a) pr0 + qr0 + p0 + r (b) p0 q 0 + p + q (c) pq 0 + p0 + q (d) pq 0 + p0 + q.
15. Since every logical statement has a truth table it follows from the discus-
sion in Section 15.4 that each such statement is equivalent to a disjunction
of basic conjunctions, that is, may be put into disjunctive normal form.
Combine the programs Stmt2TruthTable and TruthTable2DisjNormal into
a single program Stmt2DisjNormal that takes a statement and produces
its disjunctive normal form.
16. Write a program ValidArgument that takes a column of premises and a
conclusion and determines whether the argument is valid. Test it on the
arguments above.
Propositional Logic 303
16.1 Introduction
The propositional algebra described in the preceding chapter has an inter-
esting application to switching circuits. These are circuits that contain devices
such as switches, relays, or transistors that are connected by wires and have
two states, on or off. For definiteness, we shall assume that the devices are
switches. Figure 16.1 shows circuits in two states. In the circuit on the right
current flows and the battery lights the bulb; in the circuit on the left current
does not flow. Hereafter, we omit the battery and light and ignore any electrical
p
p q
pq q
p+q
former with the conjunction pq and the latter with the disjunction p + q.
A circuit is built from series and parallel circuits and thus may be represented
by a logical expression. Figure 16.3 shows some examples.
p
p q p r0
0
q
r
r q p0
q
pq + r (p + q)r r
(p + q 0 )r0 + (p0 + r)q
p r p
≡ r
q r q
pr + qr (p + q)r
p p p
≡
q r q q
p + qr (p + q)(p + r)
p q
≡ p
p
pq + p
p q
r s t
r0
s0
p q
0
t
≡ p q
the last equivalence because the term in parentheses is a tautology. Thus the
circuit in the figure may be reduced to a simple two-switch series circuit.
308 Discrete Mathematics and Coding
ladder 1
input cell q p output cell ladder 4
v r
ladder 5 s
q
w ′
t
in out
p r′ q
s′
u w
ladder 3 t s v ladder 2
v r
s
wt0
and places them in the input cells. Ladder 1 is now “empty” (Figure 16.8.)
Next, the program collapses the empty simple ladders into horizontal segments
v qp + s + wt0 r
connecting the input and output cells. Figure 16.9 shows the steps in the
collapsing until the final reduction. The program, detecting a single rung and
no more rails forms the conjunction of the expressions in the rung and prints
it in cell B2.
v qp + s + wt′ r q
(a)
p r′ q
s′
u w
t s v
′
v(qp + s + wt )r
(b) q + s′
u(pr′ + ts)w(q + v)
(c) v(qp + s + wt′ )r + (u(pr′ + ts)w(q + v)) q + s′
Sub SwitchCircuitExpr()
Dim Ladder(1 To 50) As TLadder, Grid As TGrid
Grid = MakeGrid(5, 4, 45, 45, 2.2, 10.5, 24)
Call GetCircuitBounds(Grid) 'CTop, CBot, CLeft, CRight
Call RecordCircuit 'save circuit in Sheet2 for later restoration
step = Range("B3").Value 'step through program?
Do Until SingleRung 'stop when a single rung is left
Call GetLadderSpecs(Ladder) 'detect circuit geometry
Call FormConjunctions(Ladder) 'conjunctions along rungs
Call Pause 'user's option
Call FormDisjunctions(Ladder) 'conjunctions along rails
Call Pause
Loop
Cells(2, 2).Value = Finish() 'conjunction of expr's along single rung
Call RestoreCircuit
The procedure GetCircuitBounds scans the grid for the highest (CTop), lowest
(CBot), leftmost (CLeft) and rightmost (CRight) positions of the circuit. This
is simply to condense the scanning area.
The function SingleRung scans the circuit to determine if there is more than
one rung.
Function SingleRung() As Boolean
Dim m As Integer, n As Integer, num As Integer
For n = CLeft To CRight 'run through columns
num = 0 'initialize number of rungs for each column
For m = CTop To CBot
If Cells(m, n).Interior.ColorIndex = 35 Then
num = num + 1 'found a rung in current column
End If
Next m
If num > 1 Then Exit For 'found more than one rung
Next n
SingleRung = (num = 1)
End Function
Next n
Next m
End Sub
TL v r TR
s
TL q TR
BL w t ′
TL p r′ TR TL q TR
BL s′ BR
BL u w BR
BL t s BR BL v BR
The corner locations are now in the array Ladder so the corner labels are
no longer needed.
The final step in getting the ladder specifications is to denote the simple
ladders, that is, those without inner ladders. This is done by checking if the
part of the rung inside the rails is straight. If it is not then another ladder
exists in the rails.
pr′ q
s′
u w
ts v
v qp + s + wt′ r
q + s′
u pr′ + ts w q+v
FIGURE 16.12: State of circuit after disjunctions are formed and ladders
collapsed. Process is then repeated.
Switching Circuits 317
The program can handle circuits with great complexity, limited only by
the size of the grid (which can be made quite large) and, of course, computer
memory. If it is desired to know the switch positions that result in current
flow, the expression may be run through the program Stmt2TruthTable.
16.5 Exercises
1. Draw equivalent circuits that illustrate the equivalences
(a) (pr + r0 ) ≡ (p + r0 ) (b ) (r + q 0 + rq 0 ) ≡ (r + q 0 )
2. Describe in words a circuit with four switches p, q, r, s such that closing
any one of them turns the light on.
3. Draw circuits that realize the expressions or their simplified equivalents.
(a) p + (q + r)0 (b) p(qr)0 (c) pq 0 r + p(s + t)
4. Construct an interesting circuit and run it through the program
SwitchCircuitExpr. Then run the resulting statement through the pro-
gram TruthTable2DisjNormal of Section 15.4 and draw the circuit for the
resulting statement.
5. Use logical equivalence to simplify the circuits pictured below.
Switching Circuits 319
p p p0
(a)
q q0 q0
p p0 p p
(b) 0
q q q q
r r r r0
p q r p q0
(c) p q0 r (d) r0
p q p0
r0 p q
p r
r
q
(e) p
p0
p
q0
r r 0
p q0
r
Chapter 17
Gates and Logic Circuits
A (logic) gate is a small transistor circuit that has several inputs and one
output. Input and output signals correspond to the values 1 (high voltage)
or 0 (no voltage). Gates may be wired together to form what is called a logic
circuit. We show that a logic circuit may be represented by a truth table
and hence by a compound statement. This opens up the possibility of using
propositional algebra to simplify logic circuits. We give examples of logic
circuits and show how their associated logic expressions may be generated by
VBA.
NOT AND OR
p p
p r r r
q q
Gates may be wired together to produce logic circuits with several inputs
and one output. The output values may be found by taking each set of input
values and tracing along the circuit from start to finish. A similar technique
may be used to find the logical expression associated with a circuit. An example
is given in Figure 17.2.
p+q
1 1 p
0 (p + q)(q + r)0
0
0 q
1 1 0 r q+r (q + r)0
Wiring together several AND gates produces an AND gate with multiple
inputs. A similar construction works for OR gates. Figure 17.3 gives the wiring
for three inputs.
p pq p p+q
q pqr q p+q+r
r r
pq 0
q0
p
q
r ≡ p q r
p0 q
p0
p (p(pq)0 )0 = p0 + pq
p (pq)0
q
r ≡ r
q (q(pq)0 )0 = q 0 + pq
be separated, not overlap and not touch the grid border. Figure 17.6 shows a
typical circuit with inputs p, q, r, all entered by the user. Running the program
produces the expression at the extreme right. The program populates the green
p N A N
r N
((qp + q 0 p0 )r0 )0 + p
O
cells with copies of the input and output expressions, removing the green color
in the process. Figure 17.7 shows how the program proceeds from the initial
circuit to the final expression by propagating intermediate results through
the circuit, removing green along the way to keep track of progress. The
p p p p p p p p p p p p p p
p
A A A pq pq
q
q q q q q q q q q q q q q q
Sub LogicCircuitExpr()
Dim Grid As TGrid, str As String, outrow As Integer, outcol As Integer
Grid = MakeGrid(4, 4, 50, 55, 2.1, 10.5, 24)
Call GetCircuitOutput(Grid) 'run the circuit
Call GetOutPosition(outrow, outcol, Grid) 'rightmost entry position
str = Format(Cells(outrow, outcol).Value) 'format entry there
Cells(outrow, outcol).Value = "" 'delete it
Range("B3").Value = str
MsgBox "clear"
Call CleanCircuit(Grid)
End Sub
The procedure GetOutPosition finds the rightmost nonempty cell of the grid
that holds the final (unformatted) logic expression.
Gates and Logic Circuits 325
Here is the heart of the module. It consists of a Do While loop that continues
as long as there are still empty green cells to be filled with logic expressions.
The procedure NumEmptyGreen scans the grid, counting how many green cells
remain to be populated with logic expressions.
The procedure EvalGates scans the grid for the gate letters N,A,O,X. Having
found a gate, it uses the procedure GateReady to check whether there are
sufficient inputs available. If so, it retrieves the inputs with the procedure
GateInputs, passes these to the function GateOuput, which returns the required
output depending on the type of gate. This value is then printed one cell to
the right of the gate letter.
Private Sub EvalGates(Grid As TGrid)
Dim m As Integer, n As Integer, gate As String
Dim in1 As String, in2 As String
For m = Grid.T To Grid.B
For n = Grid.L To Grid.R
If IsEmpty(Cells(m, n)) Then GoTo continue
If Not IsEmpty(Cells(m, n + 1)) Then GoTo continue
gate = Cells(m, n).Value
If 65 <= Asc(gate) And Asc(gate) <= 90 _
And GateReady(m, n) Then
Call GetGateInputs(m, n, in1, in2)
Cells(m, n + 1).Value = GateOutput(in1, in2, gate)
If pause Then MsgBox "continue" 'step through the gates?
End If
continue:
Next n
Next m
End Sub
The procedure GetGateInputs checks the neighbors to the left of a gate cell
for inputs and places them in the variables in1,in2.
Sub GetGateInputs(m As Integer, n As Integer, in1 As String, in2 As String)
Dim roff As Integer, coff As Integer
If Not IsEmpty(Cells(m, n - 1)) Then
in1 = Cells(m, n - 1).Value: in2 = ""
ElseIf Not IsEmpty(Cells(m - 1, n)) And _
Not IsEmpty(Cells(m + 1, n)) Then
in1 = Cells(m + 1, n).Value: in2 = Cells(m - 1, n).Value
End If
End Sub
The procedure GateOutput forms the required expression from the inputs
and returns a formatted version.
Function GateOutput(in1 As String, in2 As String, gate As String) As String
Dim out As String
in1 = "(" & in1 & ")" 'surround expressions with parentheses
in2 = "(" & in2 & ")"
Select Case gate
Case Is = "N": out = in1 & "'"
Case Is = "A": out = in1 & in2
Case Is = "O": out = "(" & in1 & "+" & in2 & ")"
Case Is = "X": out = "(" & in1 & in2 & "'" & _
"+" & in2 & in1 & "'" & ")"
End Select
out = Format(out) 'remove extraneous parens
GateOutput = "(" & out & ")" 'still might need them here though
End Function
The function Format takes the string returned by GateOutput and removes
unnecessary parentheses. The procedure GetMatchingParens finds the matching
parentheses, which are then removed by four functions.
328 Discrete Mathematics and Coding
lp(1) lp(2) lp(3) rp(3) lp(4) lp(5) rp(5) rp(4) rp(2) rp(1)
0
( ( ( p ) + ( ( q ) + r )0 ) )
This procedure CleanCircuit restores the original circuit, removing the litter
left on the trails by the program.
1 1 0 0
1 0 1 0
1 0 1 1 0
s s s s
p q c s binary no.
p s = sum 1 1 1 0 10
Half
q Adder c = carry 1 0 0 1 01
0 1 0 1 01
0 0 0 0 00
p q
the inputs. The user enters 1’s and 0’s here. These bits are then propagated
X pq 0 + p0 q
p q
A pq
along the green trails, the color eliminated along the way. When the bits reach
the gates they are evaluated and sent along the trails to the right, eventually
ending their journeys. Figure 17.13, shows the circuit with inputs 1 and 1.
1 1 1 1 1 1 1 1 1 1
1 1
1 X 0 0 0 0 sum out
1 1
in 1 1 1 1 1 in 1 1 1 1 1 10
1 1
1 A 1 1 1 1 carry out
1 1
1 1 1 1 1 1 1 1 1 1
The program is essentially the same as the module in Section 17.3 with
the following exceptions: (1) LogicCircuitExpr is replaced by HalfAdder below,
(2) GateOutput is modified as shown below, (3) the procedures GetOutPosition
and Format are omitted. Here is the code needed:
Sub HalfAdder()
Dim Grid As TGrid, str As String
Grid = SetGrid(5, 4, 30, 30, 2.1, 10.5): Call AddBorder(Grid, 24)
Call GetCircuitOutput(Grid) 'run the circuit
MsgBox "restore circuit"
Call CleanCircuit(Grid)
End Sub
p q cin cout s
1 1 1 1 1
p 1 1 0 1 0
cout 0
Full 1 0 1 1
q 0 1
Adder 1 0 0
cin s 0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
0 0 0 0 0
shows the circuit of the full adder as a combination of two half-adders and an
OR gate.
c1
p Half
s1 cout
q Adder
c2
Half
cin Adder s2 s
By combining 1-bit full adders in series one may add two binary numbers
of any length. For 4-bit numbers the circuit is based on the following standard
addition algorithm.
carries: 1 1 1 1 cout c3 c2 c1
1 1 0 1 p3 p2 p1 p0
1 0 1 1 q3 q2 q1 q0
sums: 1 0 0 0 s3 s2 s1 s0
Notice that the concrete example would result in an overflow for an 4-bit
machine.
334 Discrete Mathematics and Coding
Here is the circuit for a 4-bit adder in terms of 1-bit full adders. There is
a cin input in case this is the second part of an 8-bit adder formed from two
4-bit adders. Similarly, there is a cout output in case this is the first part of an
8-bit adder. With this scheme one can wire adders together to form adders
with arbitrarily many bits, subject only to memory restrictions.
s0 s1 s2 s3
c1 c2 c3
cin FA FA FA FA cout
p0 q0 p1 q1 p2 q2 p3 q3
O1 c O3 c
c H4 s1 c H8 s3
p0 H1 s q1 c p2 H5 s q3 c
q0 c p1 H3 s q2 c p3 H7 s
H2 s s0 c H6 s2 c
O2 c O4 co
ci
diagram are the outputs of the intermediate gates and are omitted in the actual
spreadsheet. The symbols p0, p1, p2, p3 and q0, q1, q2, q3 represent the digits
of input binary numbers p3p3p1p0 and q3q2q1p0. The symbol ci is the input
carry from the carry output of another (fictitious) 4-bit adder. The symbols
s0, s1, s2, s3 represent the final outputs. These are concatenated to produce
the binary sum of the inputs.
Here’s how the program works. The user enters the carry input and the
binary numbers p3p2p1p0 and q3q2q1q0 into cells B4, B5 and B6, respectively.
The digits of the numbers are extracted and placed in the required spreadsheet
locations. Running the program causes the bits to propagate along the green
Gates and Logic Circuits 335
trails leading to the half-adders and OR gates. These are evaluated and the
output printed to their right. The final sum is printed in cell B7. Figure 17.19
shows the process in midstream for the first part of the circuit. The module
1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1
1 O1 1 1 1 O3 c
1 0 1 1 H4 1 1 s1 c H8 s3
1 1 1 H1 00 0 1 1 1 1 1 0 1 H5 s 1 c
1 0 0 1 1 0
1 1 1 1 0 0 0 0 0 H3 1 1 0 0 c 1 H7 s
0 0 H2 0 0 s0 0 0 H6 s2 c
0 0 O2 0 O4 co
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0
has numerous Public variables that are used locate the positions of the inputs,
outputs, gates and half-adders. The suffixes r and c are used in these for row
and column designations. The prefixes p, q are used in the locations of the
input digits, and s in the location of the output digits. For example, H1c is the
column number of the first half adder, p3r the row number of the first digit
in the first input number, and s0c the column number of the last digit in the
output number. The letters ci and co refer to input and output carry digits,
respectively.
Public cir As Integer, cic As Integer, cor As Integer, coc As Integer
Public p0r As Integer, p0c As Integer, p1r As Integer, p1c As Integer
Public p2r As Integer, p2c As Integer, p3r As Integer, p3c As Integer
Public q0r As Integer, q0c As Integer, q1r As Integer, q1c As Integer
Public q2r As Integer, q2c As Integer, q3r As Integer, q3c As Integer
Public s0r As Integer, s0c As Integer, s1r As Integer, s1c As Integer
Public s2r As Integer, s2c As Integer, s3r As Integer, s3c As Integer
Public H1r As Integer, H1c As Integer, H2r As Integer, H2c As Integer
Public H3r As Integer, H3c As Integer, H4r As Integer, H4c As Integer
Public H5r As Integer, H5c As Integer, H6r As Integer, H6c As Integer
Public H7r As Integer, H7c As Integer, H8r As Integer, H8c As Integer
Public O1r As Integer, O1c As Integer, O2r As Integer, O2c As Integer
Public O3r As Integer, O3c As Integer, O4r As Integer, O0c As Integer
Public Binp As String, Binq As String 'binary numbers input
Public ci As String, co As String 'carry in and carry out variables
Public delayval As Integer 'delay value to slow down visual display
The sub GetLocations finds the row, column numbers of input digits, gates,
etc.
The procedure DistributeBits extracts the digits of the binary input num-
bers Binp,Binq entered in cells A5 and A6 and places them in their designated
locations on the spreadsheet.
Sub DistributeBits()
Dim p3 As String, p2 As String, p1 As String, p0 As String
Dim q3 As String, q2 As String, q1 As String, q0 As String
p3 = Mid(Binp, 1, 1): p2 = Mid(Binp, 2, 1) 'get digits of Binp
p1 = Mid(Binp, 3, 1): p0 = Mid(Binp, 4, 1)
q3 = Mid(Binq, 1, 1): q2 = Mid(Binq, 2, 1) 'get digits of Binq
q1 = Mid(Binq, 3, 1): q0 = Mid(Binq, 4, 1)
Cells(p0r, p0c).Value = p0: Cells(q0r, q0c).Value = q0 'place digits
Cells(p1r, p1c).Value = p1: Cells(q1r, q1c).Value = q1 'in the
Cells(p2r, p2c).Value = p2: Cells(q2r, q2c).Value = q2 'appropriate
Cells(p3r, p3c).Value = p3: Cells(q3r, q3c).Value = q3 'locations
Cells(cir, cic).Value = ci
End Sub
The procedure GateReady returns True if there are two inputs for the gate at
cell position m, n, these positions being one offset away from the gate location.
If the gate at cell position (m, n) is ready, then the procedure GetGateInputs
retrieves the inputs for the gate.
The procedure GateOutputs takes the inputs of a gate at cell position (m, n)
and prints the output in the appropriate position outside the gate.
Sub GateOutputs(m As Integer, n As Integer, in1 As String, in2 As String, _
gate As String)
Dim gatetype As String, OutO As String, OutC As String, OutS As String
gatetype = Mid(gate, 1, 1) 'first letter is H or O
OutO = CInt(in1) + CInt(in2)
OutC = CInt(in1) * CInt(in2)
OutS = Abs(CInt(in1) - CInt(in2))
If gatetype = "O" Then
Cells(m, n + 1).Value = OutO
ElseIf gatetype = "H" Then
Cells(m, n + 1) = OutS
Select Case gate
Case Is = "H1": Cells(m - 1, n).Value = OutC
Case Is = "H2": Cells(m - 1, n).Value = OutC
Case Is = "H3": Cells(m + 1, n).Value = OutC
Case Is = "H4": Cells(m + 1, n).Value = OutC
Case Is = "H5": Cells(m - 1, n).Value = OutC
Case Is = "H6": Cells(m - 1, n).Value = OutC
Case Is = "H7": Cells(m + 1, n).Value = OutC
Case Is = "H8": Cells(m + 1, n).Value = OutC
End Select
End If
End Sub
The last procedure reads the cells containing the digits referring to each
output sum and carry, concatenates them, and prints the result.
Sub OutputSum()
Dim s3 As String, s2 As String, s1 As String, s0 As String
s0 = Cells(s0r, s0c - 2).Value: s1 = Cells(s1r, s1c - 2).Value
s2 = Cells(s2r, s2c - 2).Value: s3 = Cells(s3r, s3c - 2).Value
co = Cells(cor, coc - 2).Value
Range("B7").Value = co & s3 & s2 & s1 & s0
End Sub
Gates and Logic Circuits 339
17.8 Exercises
1. Construct a circuit for each of the Boolean expressions:
(a) q + pr (b) q(p + r) (c) p0 q + q 0 p + r
2. Find the output Boolean expression in each of the circuits.
(a) q
(b)
q
(c) q
3. Write a program FullAdder8 that simulates an 8-bit adder. You will need
to wire together two circuits like the one used in FullAdder4. Figure 17.20
shows the circuit split into two pieces. Attach these at the cells labeled
s3, p4, q4.
340 Discrete Mathematics and Coding
O1 c O3 c
c H4 s1 c H8 s3
p0 H1 s q1 c p2 H5 s q3 c p4
q0 c p1 H3 s q2 c p3 H7 s q4
H2 s s0 c H6 s2 c
O2 c O4 c
ci
O5 c O7 c
s3 c H12 s5 c H16 s7
p4 H9 s q5 c p6 H13 s q7 c
q4 c p5 H11 s q6 c p7 H15 s
H10 s4 c H14 s6 c
O6 c O8 c co
Combinatorics
Chapter 18
Sets
18.1 Introduction
A set is a collection of objects called the members or elements of the set.
Abstract sets are usually denoted by capital letters and members of sets by
small letters. We write x ∈ A if x is a member of the set A and x 6∈ A otherwise.
The empty set, denoted by ∅, is the set with no members. While this may seem
like an odd notion, it is as important in set theory as the number zero is in
arithmetic, and indeed plays a similar role.1
Sets with just a few members may described by listing the elements between
braces. For example, the set of even integers greater than 1 and less than
9 may be described by the notation {2, 4, 6, 8}. The listing technique may
also be used for some infinite sets. For example, the set of all positive even
integers may be written as {2, 4, 6, . . .}. The three dots are called an ellipsis
and indicate an omission of information that may be inferred from context,
although admittedly this device could introduce some ambiguity.
Another way to describe sets is by set-builder notation. This has the form
{x | P (x)},
which is read “the set of all x such that P (x).” Here P (x) is a well-defined
property that x must satisfy in order to belong to the set. For example, the
set of all even positive integers may be described in set builder notation as
n | n = 2m for some positive integer m .
Note that ∅ ⊆ A for all sets A. (Can you find a member of ∅ not in A?)
Two sets A and B are said to be equal, written A = B, if A ⊆ B and B ⊆ A,
that is, if they have precisely the same members. For example,
The first example shows that members of a set need not be listed more than
once.
Relationships among sets may sometimes be illustrated to good effect by
a schematic device called a Venn diagram. Here, sets are depicted as closed
regions in a rectangle. Figure 18.1 is a Venn diagram illustrating various
membership and inclusion relations. The rectangle depicts a universal set U ,
that is, a set containing all members in a particular discussion. Universal sets,
though not unique, are frequently left unspecified, as their choice is usually
clear from context. For example, in ordinary algebra the universal set is the
set of all real numbers.
x
A
FIGURE 18.1: A ⊆ B, C 6⊆ B, x ∈ B, x 6∈ A.
Thus for something to be in the union of two sets it must be in at least one of
them. For example, if
A = 1, 2, 3, 4, 5 and B = 4, 5, 6, 7 ,
then
A + B = 1, 2, 3, 4, 5, 6, 7 .
The more traditional notation for the union is A ∪ B. We have chosen the
notation A + B to emphasize the connection between set theory and the propo-
sitional calculus and also to be able to enter set operations in a spreadsheet.
The function Union below takes as input two strings setA and setB that
represent sets and returns a string that represents the union. For example, the
statement Union("1,2,3","3,4,5") returns the string "1,2,3,4,5". The input
strings are concatenated with a comma separator to form the output string
NewSet. The function DeleteDupStr, discussed in Section 6.8, removes duplicate
members from NewSet.
then
AB = 4, 5 .
An alternate notation for intersection is A ∩ B. We have chosen the notation
AB for reasons similar to those regarding union.
The function Intersection is analogous to Union. It takes strings represent-
ing sets A and B as input and returns a string representing AB. Thus the
statement Intersect("1,2,3,4,5,6", "2,3,4,7") returns the string "2,3,4".
The procedure uses the function MidDelim discussed in Section 6.2 to find
346 Discrete Mathematics and Coding
members of the sets. It also uses the procedure Card (short for “Cardinality”)
to find the number of distinct elements of a set. It does so by converting the
comma-delimited set string to an array and then adding 1 to the upper index
of the array (whose indices start at 0).
Function Intersection(ByVal setA As String, ByVal setB As String) As String
Dim i As Integer, j As Integer, NewSet As String, memberA As String
setA = DeleteDupStr(setA, ",")
setB = DeleteDupStr(setB, ",")
For i = 1 To Card(setA) 'run through members of setA
memberA = MidDelim(setA, i, ",") 'get a member from setA
For j = 1 To Card(setB) 'check if it is also in setB
If memberA = MidDelim(setB, j, ",") Then
NewSet = NewSet & memberA & "," 'attach common member
Exit For
End If
Next j
Next i
If Len(NewSet) = 0 Then
Intersection = ""
Else
Intersection = Mid(NewSet, 1, Len(NewSet) - 1) 'avoid last comma
End If
End Function
A0 = x ∈ U | x 6∈ A .
then
AB 0 = 1, 2, 3 , and A0 B = 6, 7 .
A0 B 0
AB 0 AB A0 B
A B
U
and
ABC = x | x ∈ A and x ∈ B and x ∈ C .
One can even define the union and intersection of infinitely many sets
A1 , A2 , . . .:
A1 + A2 + · · · = x | x ∈ An for some n .
and
A1 A2 · · · = x | x ∈ An for every n .
Such sets occur frequently in probability theory (see Chapter 20).
A partition of a set S is a collection of nonempty sets S1 , S2 , . . . Sn whose
union is S and no two of the sets intersect. Figure 18.3 shows a Venn diagram
with three sets partitioned into component parts. Venn diagrams for more
than three sets are usually impractical (but see Exercise 2).
AB 0 C 0 ABC 0 A0 BC
ABC
A AB 0 C A0 BC B
0 0
ABC
A0 B 0 C 0
C U
FIGURE 18.3: Venn diagram for three sets.
spreadsheet depiction Figure 18.4. The program assumes that the universal
set U is the first set entered. The module is similar to MatrixCalculator
(Section 13.9) but easier to code since the operations are simpler and strings
rather than matrices are retrieved from the queue.
A B C
3 Expression (AB 0 C + D0 E 0 + A0 BE)0
5 Sets U 1, 2, 3, 4, 5, 6, a, b, c
6 A 1, 2, 3
7 B 3, 4, 5
8 C 1, 2, 3, 4, 5, a, b
9 D 1, 2
10 E 2, 3, 4, 5, 6
12 Answer 3, 6
The procedure SetEval doles out the tasks union, intersection, and comple-
ment. Hierarchy is enforced using the variable mode.
A B A B
4 universal set 1, 2, 3, 4, 5, 6, 7, 8, 9 12 AB 0 C empty
5 sets 13 A0 B 0 C 7, 8
6 A 1, 2, 3 14 ABC 0 3
7 B 3, 4, 5, 9 15 0 0 4, 9
A BC
8 C 5, 6, 7, 8 16 AB 0 C 0 1, 2
10 ABC empty 17 A0 B 0 C 0 empty
11 A0 BC 5
The main procedure VennParts allocates memory for the given sets
A, B, C, . . . and their complements and then calls various procedures that
do the work.
Public NumSets As Long, setlabels As String
Sub VennParts()
Dim i As Integer, sets() As String, complements() As String
Dim MaxSets As Integer, U As String, binary() As Integer
MaxSets = 10 'this gives max 1024 parts
ReDim sets(1 To MaxSets) 'array for the sets
ReDim complements(1 To MaxSets) 'array for their complements
U = Range("B4").Value 'universal set
Call GetSetLabels 'set labels string
NumSets = Len(setlabels)
If NumSets > MaxSets Then MsgBox "Too many sets": Exit Sub
Call GetSets(sets)
Call GetComplements(U, sets, complements)
Call GenerateVennParts(sets, complements)
End Sub
The procedure GetSetLabels forms a Public string setlabels from the set
labels in column 1.
Sub GetSetLabels()
Dim i As Integer
352 Discrete Mathematics and Coding
The procedure GetSets places the set elements entered in column 2 in the
array sets and GetComplements places their complements with respect to the
universal set U in the array complements.
Sub GetSets(sets() As String)
Dim i As Integer
i = 1
Do While Not IsEmpty(Cells(5 + i, 2))
sets(i) = Cells(5 + i, 2).Value
i = i + 1
Loop
End Sub
The procedure GenerateVennParts generates the set labels for the Venn
parts as well as the sets corresponding to the labels. It does this by generating
binary sequences, that is, sequences of ones and zeros precisely like those in
truth tables (but in a different order). These sequences determine whether to
include a set or its complement: a zero means include the set, a one to include
its complement. For example, for three sets A, B, C the binary sequences
generated are
000, 100, 010, 110, 001, 101, 011, 111
These tell the program to generate the sets
one might guess at a connection based on the fact that union, intersection,
and complement are defined using the logical operators “or”, “and”, “not”,
respectively.
Laws of sets naturally fall into two classes: the laws of equality and the laws
of inclusion. We treat the former in this section, the latter in the next.
The reader will notice that the above properties may be formally obtained
from the laws of logic in Section 15.2 by replacing ≡ by =. To see why this is
the case, let’s give an argument to establish the validity of the first distributive
law. The heart of the argument is to show that an arbitrary member of each
side of the equality is a member of the other. We proceed as follows: An element
x is in A(B + C) if and only if x ∈ A and x ∈ B + C, which is the case if and
only if x ∈ A and (x ∈ B or x ∈ C). By the first distributive law of logical
equivalence, the last statement is equivalent to
x ∈ A and x ∈ B or x ∈ A and x ∈ C ,
which is the statement x ∈ AB + AC. We have used the first distributive law
of logical equivalence to prove the first distributive law of sets. The other laws
may be proved in a similar manner.
The preceding discussion suggests that the validity of equality between two
general set expressions may be established with the program Stmt2TruthTable.
In Exercise 10 the reader is asked to carry this out in the more general setting
of set inclusion.
Sets 355
Let’s prove one the inclusion equivalence in the last property that says that
A ⊆ B is equivalent to AB = B. Suppose first that A ⊆ B. To prove that
AB = A, first choose a member x of the left side. Then x is in both A and B
and so x is in the right side. Now choose a member x of the right side. Then,
of course x ∈ A, and since A ⊆ B, x ∈ B as well. Therefore, x is in the right
side. We have proved that A ⊆ B implies AB = A. The converse is proved in
a similar manner.
Set inclusion may be used to deduce certain consequences in a logical
problem. Here is a typical example:
Example 18.1. Determine what conclusions may be drawn from the following
statements:
(a) A person who is not well-read is not educated.
(b) A well-read person never makes a mistake.
(c) Philosophers are well-educated.
(d) Every philosopher makes mistakes.
R0 ⊆ E 0 , R ⊆ M 0 , P ⊆ E, P ⊆ M,
356 Discrete Mathematics and Coding
which lead to
P ⊆ E ⊆ R ⊆ M 0 ⊆ P 0.
However, the inclusion P ⊆ P 0 is possible only if P is empty. Thus we are led
to the sad conclusion that are no philosophers. ♦
members here are the sets [x], called equivalence classes, which contain precisely
those members y for which xRy.
Heretofore, we have used the notion of function informally. It is now possible
place the concept in the precise setting of set theory. Let A and B be nonempty
sets. A function F from A to B, denoted by F : A → B, is a relation with
the property that for each x ∈ A there exists a unique y ∈ B such that
(x, y) ∈ F . In this case we write y = F (x). We may then think of F as a
rule that transforms a member of A into a member of B, thus retrieving the
standard informal notion of function.
If G : A → B and F : B → C are functions with G(x) ∈ B for all x ∈ A,
then the composition of F and G, denoted by F ◦ G : A → C is defined by
(F ◦ G)(x) = F (G(x)). If C = A and (F ◦ G)(x) = x for all x ∈ A and
(G ◦ F )(y) = y for all y ∈ B, then G is called the inverse of F . We shall see
these notions later in the context of permutations.
18.11 Exercises
1. In Figure 18.3 shade the following sets:
(a) AB 0 + A0 C (b) AB 0 + AC + B 0 C (c) (A0 + B)(A + C)
2. Fill in the regions in the following Venn diagram for 4 sets with suitable
set labels.
A B
(a) There are no women premed students who are not good at physics.
(b) Students who do not take calculus are not good at physics.
(c) Students who take calculus are not good at biology.
Which is the following may be deduced from this information?
(1) No premed student is good at physics.
(2) All premed students take calculus and biology.
(3) All premed students are good at physics.
(4) Women premed students are not good at biology.
5. Render the following statements into inclusions.
(a) Every member of the Smith family eats broccoli.
(b) Every member of the Jones family eats kale.
(c) No member of either the Smith family or the Jones family eats
both broccoli and kale.
(d) Allison eats broccoli.
Which is the following may be deduced from this information?
(1) Allison is a member of the Smith family.
(2) Allison is not a member of the Jones family.
6. Simplify as much as possible.
(a) (A + B)(A0 + C)(B 0 + C 0 )
(b) A + A0 B
(c) AB 0 + ABC + AB
(d) A + B + C + A0 B 0 C 0
(e) (A + B + C)(A + AB + ABC)
(f) (A0 B 0 + A0 B + AB 0 )0
7. Write a function SetsEqual(setA,setB) that returns True if the sets are
equal and False otherwise. The members of each set are entered by the
user.
8. Write a program SetOperations that reads a collection of sets entered in
column one and prints their union and intersection.
∗9. Write a program Cartesian that generates the Cartesian product of
arbitrarily many sets entered by the user.
∗10. Write a program SetInclusion(expr1, expr2) that takes as input two
abstract set expressions and decides whether expr1 included in expr2 and
vice versa. For example, if expr1 = AB+C and expr1 = AC+B the program
should return False. (Suggestion: Give the sets in expr1 all possible truth
values 1,0 (meaning that an arbitrary x is or isn’t in a set). For each
combination of values that results in expr1 = 1, give those variables in
expr2 that are not in expr1 all possible truth values. If in this process
there is an overall combination that result in expr2 = 0, then expr1 is
not contained in expr2.
Chapter 19
Counting
In this chapter we consider methods that allow one to calculate the number
of ways various tasks can be carried out. The computational techniques here
have important applications in geometry, network analysis, algebra, computer
science and, as we shall see in the next several chapters, probability theory.
The following example illustrates how the addition principle may be used
in certain counting problems.
Example 19.1. A survey of 300 people questioning their participation in
regular exercise activities A, B, and C revealed the following:
• 100 participate in activity A
• 100 participate in activity B
• 120 participate in activity C
• 70 participate in B but not in A
• 80 participate in A but not in C
• 40 participate in B but not in A or C
• 10 participate in all three.
abc0 a0 bc0
ab0 c0
abc
0
ab c a0 bc
A B
a0 b0 c
a0 b0 c0
C
We wish to find the number of people in the survey that participate in exercises
B and C but not A.
To this end let A, B, and C denote the sets of people that participate in
activities A, B, and C, respectively, and let U denote the population surveyed.
Using shorthand such as a = n(A), a0 b = n(A0 B), etc. we may summarize the
given information as
a = b = 100, c = 120, a0 b = 70, ac0 = 80, a0 bc0 = 40, abc = 10, and u = 300.
The diagram in Figure 19.1 may then be used to derive additional information.
For example, from the diagram we see that a0 bc + a0 bc0 = a0 b. This, together
with the given information a0 bc0 = 40 and a0 b = 70, implies that a0 bc = 30, the
solution to our problem. ♦
A B C A B C A B C
a 0
7 1 100 16 10 ac 80 25 19 abc 10
0 0 0
8 2 a 200 17 11 ab 70 26 20 ab c 10
9 3 b 100 18 12 a0 b0 130 27 21 abc0 20
0 0 0 0
10 4 b 200 19 13 ac 100 28 22 ab c 60
11 5 c 120 20 14 a0 c0 100 29 23 a0 bc 30
0 0 0
12 6 c 180 21 15 bc 40 30 24 abc 70
ab 0 0 0
13 7 30 22 16 bc 60 31 25 a bc 40
14 8 ab0 70 23 17 b0 c 80 32 26 a0 b0 c0 60
ac 0 0
15 9 20 24 18 bc 120 33 27 u 300
(shown in the figure in non-boldface) and prints these in the appropriate rows
of column C.
The program works as follows: The unknown Venn numbers are calculated
using the 27 equations that are listed in Table 19.1. Each equation has a
three digit code to its right that refers to the components of the equation.
For example, the equation a = ab + ab0 has components a, ab, and ab0 . Since
the labels in column A for these components are 1,7, and 8, respectively, the
equation receives the code 1,7,8. The program assumes that the equation codes
have been entered in Sheet2 as a 27 × 3 matrix with the (1, 1) entry in cell B2.
The main procedure Venn3Solver begins by allocating the array E for the 27
equation codes and the array V for the 27 Venn numbers that will eventually
appear in column C. It then calls GetEqnCodes, which retrieves the equation
codes from Sheet2 and stores them in the array E. For example, for the fourth
362 Discrete Mathematics and Coding
In the first iteration of the Do While loop, the procedure GetNumbers retrieves
the Venn numbers entered by the user. If Venn number i is missing, then V (i)
is set to −1. For our example, the retrieved numbers are
Additional entries of V are calculated (and the −1’s removed) during successive
iterations as long as the variable status remains zero.
V (E(i, j)), j = 1, 2, 3,
step one
step two
FIGURE 19.3: The multiplication principle.
Applications of the principle are given in the next section and in Chapter 20.
19.4 Permutations
Consider the problem of counting the number of three letter sequences that
can be formed from the letters of the word “computer,” where no letter is
used more than once. We can describe the task of forming such a sequence
Counting 365
The following figure shows how the program works for the case of three letters
abc. The down arrows indicate going into recursion, the up arrows coming out
of recursion. The pairs of numbers labeling the up and down arrows are the
values of idx and i, respectively, and indicate the swap S(idx) ↔ S(1).
abc
19.6 Combinations
While a permutation is an ordered list, a combination is an unordered
list. More precisely, if n and r are positive integers with 1 ≤ r ≤ n, then a
combination of n items taken r at a time is a set of r items chosen from the n
items. For example, the combinations of the five letters a, b, c, d, and e taken
three at a time (written, without set braces or comma separators) are
abc, abd, abe, acd, ace, ade, bcd, bce, bde, and cde.
Counting 367
Here are two examples combining the multiplication and addition principles.
Example 19.3. A bag contains 5 red, 4 yellow, and 3 green marbles. In how
many ways is it possible to randomly draw from the bag 4 marbles consisting
of exactly 2 reds and no more than 2 greens?
We have the following decision scheme:
Case 1: No green marbles.
Step 1: Choose 2 reds: 52 = 60 possibilities.
Here is a combinatorial argument that shows why the formula holds. Ex-
panding (a + b)n results in a sum of products each having n factors consisting
of a’s and b’s. For each k = 0, 1, . . . n collect together all products that have
exactly k a’s. Each such product may be written as ak bn−k . There are as
many of these
as there are ways to choose k spots out of n. Thus for each k
there are nk terms of the form ak bn−k , proving the theorem. Another proof,
somewhat more rigorous, uses the prnciple of mathematical induction discussed
in Section 23.5.
For an application we show that a set S with n members has 2n subsets
(including S and ∅). Indeed, since nr gives the number of subsets of size r,
the total number of subsets of S (including S and ∅) is
n n n
+ + ··· +
0 1 n
Sub CommandButton1_Click()
Dim Combo() As String, SetStr As String, SubSize As Integer
Call ClearColumns(8, 1, 1)
SetStr = Range("B5").Value 'get the set S as a string
SubSize = Range("B6").Value 'get desired size of the subsets of S
Combo = Combinations(SetStr, SubSize)
For k = 1 To UBound(Combo)
Cells(7 + k, 1).Value = Combo(k)
Next k
End Sub
Binary sequences are generated by nested For Next loops using the function
ZeroOne(i,j) of Section 18.7 The function NumOnes returns the number of
ones in a sequence. If that number equals the subset size, then the function
SelectSubset is called to extract a subset according to the rule in the preceding
paragraph. The subset is stored in the next available spot in the list of
combinations.
The function NumOnes(bin) simply removes all zeros from bin and returns
the length of the resulting string.
The function SelectSubset takes as input the binary selector sequence bin
and the string SetS. A For Next loop runs through the members of the binary
sequence extracting the ith member of SetS precisely when the ith character in
bin is one. The subset string SubS is built from these members by concatenation
and then returned by the function.
370 Discrete Mathematics and Coding
x x 0 2
x 1
x x 9 3
x 4
x 6
x x 8 5
x 7
The module in this section takes the brute force approach. The user places
x’s on a spreadsheet grid for the towns. The program then finds a shortest
route, which we shall call a best path, the distance between towns taken as the
number of cells one must traverse in horizontal and vertical directions to get
from one town to another. Figure 19.4 shows the state of the spreadsheet for
10 towns before and after the program has run. The program labels the towns
0 – 9 in an order that gives a shortest route, in this case comprised of 32 cells.
1 More than 11 towns is generally not feasible on a typical computer.
Counting 371
The choice of the origin town is immaterial; one could start with any town, as
paths are circuits.
The main procedure TravelSales begins by setting up the grid that displays
the towns and allocating memory for the position array Loc of town locations,
the current path array CurrPath, and the current best path array LeastPath. It
then calls InitialData, which scans the grid for towns, recording their locations
in Loc, and initializes CurrPath and LeastPath. The position of the ith town
in the scan (which is left to right, top to bottom) is recorded as Loc(i). The
first town encountered in the scan (at location Loc(0)) is designated as town 0.
The sequence 0, 1, 2, . . . , k, 0 then represents the path through the towns in the
order obtained from the scan. An arbitrary path is represented by a sequence
0, n1 , n2 , . . . , nk , 0, where n1 , n2 , · · · , nk is a permutation of 1, 2, . . . , k. The
zeros are redundant, so a path may be represented simply by n1 , n2 , . . . , nk .
The distance from town i to town j is stored as entry (i, j) of a k + 1 by k + 1
matrix D. The matrix is constructed by the function GetDistances.
m = m + 1
End If
Next j
Next i
NumTowns = m
End Sub
The distances between the towns are calculated from the position arrays
by the procedure GetDistances. The distance D(i, j) between the ith and jth
towns encountered in the initial scan is the length of the elbow path connecting
them. It is calculated using the VBA function Abs. The distances are printed
in matrix form on the spreadsheet.
Private Sub GetDistances(Loc() As TPos, D() As Integer)
Dim i As Integer, j As Integer
For i = 0 To NumTowns - 1
For j = 0 To NumTowns - 1
D(i, j) = Abs(Loc(i).row - Loc(j).row) + _
Abs(Loc(i).col - Loc(j).col)
Cells(31 + i, j + 2).Value = D(i, j) 'print as matrix
Next j
Next i
End Sub
The function GetPathLength sums the distances from town 0 to the first
and last towns in the route described in Path and then adds to the sum the
intermediate distances between the towns.
Function GetPathLength(CurrPath() As Integer, D() As Integer)
Dim length As Integer, i As Integer
'distance from town 0 to towns Path(1) and Path(NumTowns - 1))
length = D(0, CurrPath(1)) + D(0, CurrPath(NumTowns - 1))
For i = 1 To NumTowns - 2 'get distances for towns in between
length = length + D(CurrPath(i), CurrPath(i + 1))
Next i
GetPathLength = length
End Function
While the latter notation more cumbersome, it has the advantage of increased
clarity when performing operations on permutations.
The set of permutations of the integers 1, 2, . . . , k may be given an alge-
braic structure. The fundamental operation of the system is product of two
permutations p and q, denoted by the juxtaposition of the permutations and
defined as illustrated by the following example:
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
pq = = (19.4)
4 3 5 1 2 3 5 1 2 4 5 2 4 3 1
We call the second permutation on the left side of the equation the identity
permutation. The analogous equation with the order of the permutations on
the left reversed also holds.
The function MultPerm returns the product of two permutations. The
input permutations are written as strings permA and permB as is the out-
put permutation permC = permA permB. For example, referring to (19.4),
MultPerm("4,3,5,1,2","3,5,1,2,4") returns the string "5,2,4,3,1".
Notice that
−1
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
= ,
3 5 2 1 4 3 5 2 1 4 1 2 3 4 5
The program PermCycle below prints out the cycles of a permutation. The
user enters the permutation in cell B6 as a comma separated string or lets
RndIntList do this. The string is then converted into a string array Q. The
program then calculates
setting these array members to the null string "" as they are used up. The pro-
cess continues as far as possible, that is, until a null string string is encountered.
If Q(2) is not the null string the program calculates the cycle
This continues until all of the entries of Q are null strings. Here is the code:
Sub PermCycles()
Dim perm As String, m As Integer
Dim L As Integer, cycle As String
Dim P() As Integer, Q() As String, prod As String
Counting 377
Q(i) = CStr(P(i))
Next i
Convert2StringArray = Q
End Function
19.11 Exercises
1. A restauranteur needs to hire a pastry chef, a roast chef, a vegetable
chef, and three fry chefs. If there are 10 applicants equally qualified for
the positions, in how many ways can the positions be filled?
2. A bag contains 5 red, 4 yellow, and 3 green marbles. In how many ways
is it possible to draw 5 marbles at random from the bag with exactly 2
reds and no more than 1 green?
3. How many different 12-letter arrangements of the letters of the word
“arrangements” are there?
4. Work the following problem by hand and then check your answer with
Venn3Solver. A sample of 100 people resulted in the following data:
(a) 60 play tennis
(b) 45 play basketball
(c) 45 play soccer
(d) 15 play basketball and soccer
(e) 25 play basketball and tennis
(f) 20 play soccer and tennis
(g) 5 play all three
How many
(1) play no sports?
(2) play exactly one sport?
(3) play exactly two sports?
5. Work the following problem by hand and then check your answer with
Venn3Solver. A sample of the music tastes of 100 people resulted in the
following data:
(a) 52 like classical
(b) 45 like jazz
(c) 60 like rock
(d) 25 like classical and jazz
(e) 30 like classical and rock
(f) 28 like jazz and rock
(g) 6 liked none of these
Counting 379
(3,4,2,1,5)(2,1,5,3,4)^(-3)(3,5,1,4,2)^2
Probability
Chapter 20
Probability
Another example of a random experiment is the flip of a fair coin. If the coin
is flipped twice, then the sample space Ω may be written as {HH, HT, T H, T T },
where, for example, the notation HT signifies that the coin came up heads on
the first flip and tails on the second. Since the coin is fair we would expect
these outcomes to be equally likely and therefore assign the probability 1/4 to
each. Thus the probability distribution of the experiment is
If all outcomes of a random experiment are equally likely, as was the case in
the coin flip and dice toss examples, then the values P(ω) are all the same and
so must equal 1/n(Ω), where the notation n(A) means the number (cardinality)
of outcomes in a set A (see Chapter 19). It follows that
1 1 1 n(A)
P(A) = + + ··· + = ,
n(Ω) n(Ω) n(Ω) n(Ω)
| {z }
n(A) terms
The sample space then consists of all ordered pairs (i, j), where 1 ≤ i, j ≤ 6.
As there are 36 equally likely outcomes, the probability of each toss is 1/36.
We could also consider the numbers 2, . . . , 12 as outcomes, these being the
sums of the dots on the top faces. For example, the outcome 7 is represented
by the event {(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1)} and so has probability
6/36 = 1/6. Figure 20.1 gives theoretical probabilities of the outcomes 2, . . . , 12
in chart form.
.1667
.1389
.1111
.0833
.0556
.0278
2 3 4 5 6 7 8 9 10 11 12
The following program simulates the experiment by “tossing” the dice many
times and calculating the relative frequency of the outcomes 2, . . . , 12. Relative
frequencies are sometimes called empirical probabilities in contrast to the
theoretical probabilities obtained by logical deduction. The use of empirical
probabilities is sometimes necessary as theoretical probabilities may be difficult
to deduce. The justification for the use of empirical probabilities is the law of
large numbers, discussed in the next chapter.
386 Discrete Mathematics and Coding
The procedure below tabulates the frequency of the sums red + green,
where red is the number on the red die and green the number on the green
die. The numbers are chosen with the function RndInt (Section 10.1). A For
Next loop carries out the throws NumThrows times, a value entered by the user
in cell B5. The array freq counts the number of times a particular sum red +
green comes up. For example, if a toss comes up red = 4 and green = 3 then
the array entry freq(7) is incremented by one. A For Next loop prints the
sums 2–12 and their relative frequencies (frequency divided by NumThrows). The
procedure then graphs the probabilities.
Sub DiceRelativeFreq()
Dim freq(2 To 12) As Long, red As Integer, green As Integer
Dim k As Long, NumThrows As Long
Range("B7:C38").NumberFormat = ".000000" 'format
NumThrows = Range("B5").Value 'user entered no. of dice throws
For k = 1 To NumThrows 'toss the dice this many times
red = RndInt(1, 6) 'throw red die
green = RndInt(1, 6) 'throw red die
freq(red + green) = freq(red + green) + 1 'increment freq.
Next k
For k = 2 To 12 'print sums and their relative frequencies
Cells(6 + k, 1).Value = k
Cells(6 + k, 2).Value = freq(k) / NumThrows 'form averages
Next k
With Sheet1 _
.ChartObjects.Add(Left:=250, Width:=300, Top:=80, Height:=200)
.Chart.SetSourceData Source:=Range("B8:B18") 'y values
.Chart.ChartType = xlColumnClustered 'chart type
.Chart.HasTitle = True
.Chart.ChartTitle.Text = "Relative Frequencies"
.Chart.SeriesCollection(1).XValues = Range("A8:A18") 'x values
End With
End Sub
• Single pair : To find the number of such hands first select a denomination for
the pair (13 choices), then select a pair from the four cards in the denomination,
( 42 = 6 choices), then select the remaining three cards, avoiding cards in
previously chosen denominations (48 · 44 · ·40/3! = 14, 080 choices). By the
multiplication principle the total number of hands with a single pair is therefore
13 · 6 · 14, 080 = 1, 098, 240 hence the probability of getting a single pair is
1, 098, 240
= 0.4225690376
2, 598, 960
• Two distinct pairs: The number of such hands is obtained as follows:
First choose two denominations for the pairs ( 13
2 = 78 choices), then choose
4 2
two cards from each denomination ( 2 = 36 choices), and finally choose the
remaining card avoiding the selected denominations (44 choices). The number
of possible hands with two distinct pairs is therefore
78 · 36 · 44 = 123, 552
and so the probability of such a hand is
123, 552
= 0.0475390156
2, 598, 960
• Three of a kind (the remaining cards not a pair): To find the number
of such hands first choose a denomination for the triple (13 choices). Then
select three cards from that denomination (4 choices). Finally, choose the
remaining two cards, avoiding the denomination for the triple as well as pairs
( 48·44
2 = 1056) choices. (The divisor 2 is needed since, for example, the choice
5, 8 is the same as the choice 8, 5.) Thus the number of poker hands with three
of a kind is 13 · 4 · 1056 = 54, 912 and so the probability of such a hand is
54, 912
= .0211284514
2, 598, 960
• Full house (3 cards of one denomination and 2 cards of another, for
example, three kings and two jacks): For the number of such hands first
choose denominations for the triple and pair ( 13
2 = 78 choices). Then select
4
2 cards from one denomination ( 2 = 6 choices) and 3 cards from the other
denomination (4 choices). Thus the number of full house poker hands is
78 · 6 · 4 · 2 = 3744 so the probability for such a hand is
3744
= .001440576
2, 598, 960
• Four of a kind : Choose a denomination (13 choices) for the quadruple
then choose 1 card from the remaining 48, giving 13 · 48 = 624 choices. Thus
the probability for such a hand is
624
= .000240096
2, 598, 960
388 Discrete Mathematics and Coding
The procedure Eval finds the number of pairs, triples, and full houses by
making a frequency chart of the denominations.
Next i
For i = 1 To 13 'check for pairs, triples, and quadruples
If DenFreq(i) = 2 Then NumPairs = NumPairs + 1
If DenFreq(i) = 3 Then NumTrips = NumTrips + 1
If DenFreq(i) = 4 Then NumQuads = NumQuads + 1
Next i
'update count of pairs, etc.
If NumPairs = 0 And NumTrips = 1 Then NumTriples = NumTriples + 1
If NumPairs = 1 And NumTrips = 0 Then Num1Pairs = Num1Pairs + 1
If NumPairs = 2 Then Num2Pairs = Num2Pairs + 1
If NumPairs = 1 And NumTrips = 1 Then NumFull = NumFull + 1
End Sub
Since there are five ways to draw a red ball, the probability of doing so is
5/11. Similarly, the probability of drawing a yellow ball is 6/11. We now draw
five balls, replacing each ball before drawing the next and ask What is the
probability of drawing the particular sequence RRRYY, that is, first three
red balls and then two yellow balls? To answer this we use the multiplication
principle described in Section 19.3. Since there are five red balls, each may be
chosen in any one of 5 ways. Similarly, since there are six yellow balls, each of
these may be chosen in any one of six ways. By the multiplication principle,
the sequence RRRYY may be drawn in any one of 5 · 5 · 5 · 6 · 6 ways. Since
there are 11 · 11 · 11 · 11 · 11 possible sequences, each equally likely to appear,
the probability of the sequence RRRYY is
3 2
5·5·5·6·6
5 6
= .
11 · 11 · 11 · 11 · 11 11 11
If we set
5 6
p= and q = (= 1 − p)
11 11
these being, respectively, the probabilities of drawing a red ball and yellow ball,
then we may write the result symbolically as P(RRRYY) = p3 q 2 . Notice that
390 Discrete Mathematics and Coding
the order of the R’s and Y’s is immaterial; only the number of each matters.
Thus one also has P(YRRYR) = p3 q 2 .
Now we ask: if we draw five balls with replacement, what is the probability
of getting three red balls and two yellow balls in any order? The event in
question now consists of all sequences XXXXX with 3 R’s and 2 Y’s, not just
the particular sequence RRRYY. For the solution, note that there are 53 such
sequences, corresponding to the number of ways of choosing subsets of size 3
from the set of X’s. As noted above, each such sequence has probability p3 q 2 .
5 3 2
Therefore, the desired probability is the sum of these, namely 3 p q .
More generally, suppose that the urn contains r red balls and y yellow balls.
If a sample of size n is drawn with replacement, then an argument similar
to the one in the preceding paragraph shows that the probability of drawing
exactly k red balls in this sample is
n k s−k
p q , 0 ≤ k ≤ n, (20.1)
k
where
r y
p= and q = (= 1 − p), 0 ≤ k ≤ n.
r+y r+y
Note that the expression in (20.1) is the kth term (starting at 0) of the binomial
expansion of (p + q)n (see Section 19.6). The probabilities in (20.1) form the
so-called binomial distribution. Figure 20.2 graphs the binomial probabilities
for n = 6 and three values of p.
.3
.2
.1
0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6
p = .3 p = .5 p = .7
FIGURE 20.2: Binomial probability distribution.
The urn problem may be cast in the following more general setting: Call
each drawing a trial and call the selection of a red ball a success and the
selection of a yellow ball a failure. Equation (20.1) then gives the probability of
k successes in n trials. Note that because the urn configuration is restored after
each drawing the trials are independent, that is, the probabilities for each trial
are the same and do not depend on results of previous trials. Any experiment
consisting of n independent trials, each of which has two outcomes, arbitrarily
called success and failure, with respective probabilities p and q := 1 − p has
the binomial probability distribution (20.1).
FIGURE 20.3: Red ball’s progress and the result of many balls.
The module GaltonsBoard in ths section displays a red cell (ball) bouncing
off black cells (the pegs) until it reaches the last row, when it is placed in the
column underneath it. The columns grow downward to allow bins of arbitrary
392 Discrete Mathematics and Coding
size (Figure 20.4). The main procedure Galton begins by retrieving user-entered
The procedure DrawGalton draws the pegs as black cells. It begins by coloring
the top cell at (startrow,startcol) then moves down the rows by two cells.
Each row starts two cells to the left of the previous row. Black cells in a
particular row are printed every 4th cell.
Probability 393
The procedure RollBalls iterates RollBall. The latter causes a ball (red
cell) to drop through the grid. The direction is determined by ProbLeft and
the function Rnd.
select an individual from the group, then the probability that the person
prefers classical music to jazz is (20 + 15)/100 = 7/20. The sample space in
this case is the set of 100 people. However, if we incorporate the knowledge
that the person selected is a woman, then sample space reduces to the set of
60 women, and the new probability is 20/60 = 1/3. We can symbolize these
calculations as follows: Let A denote the event that the person selected prefers
classical music to jazz and B the event that the person selected is a women.
The original probability is
n(A)
P(A) =
n(Ω)
and the new probability is
n(AB) n(AB)/n(Ω) P(AB)
= = .
n(B) n(B)/n(Ω) P(B)
The example suggests the following general definition: If A and B are events
in an experiment and P(B) > 0, then the conditional probability of A given B
is defined as
P(AB)
P(A | B) = . (20.2)
P(B)
Note that P(A | B) is undefined if P(B) = 0.
Probability 395
Example 20.1. A jar contains 5 red and 6 yellow marbles. Randomly draw
3 marbles in succession without replacement. Let R1 denote the event that
the first marble is red, R2 the event that the second marble is red, and Y3 the
event that the third marble is yellow. By the multiplication rule the probability
that the first two marbles are red and the third is yellow is
P(R1 R2 Y3 ) = P(R1 )P(R2 | R1 )P(Y3 | R1 R2 ) = (5/11)(4/10)(6/9) ≈ .12 ♦
The point here is that the conditional probability P(A | B), where the event
B is the given information, is expressed in terms of “reversed” conditional
probabilities, where now A is the given information.
Bayes’ theorem may be extended to arbitrarily many events A1 , A2 , . . . An ,
where
Ω = A1 + A2 + · · · + An and Ai Aj = ∅ (i 6= j).
Indeed, by (20.4),
P(B | Ak ) P(Ak )
P(Ak | B) = (20.6)
P(B)
Using the expansion
P(B | Ak )P(Ak )
P(Ak | B) = .
P(B | A1 )P(A1 ) + P(B | A2 )P(A2 ) + · · · + P(B | An )P(An )
Example 20.2. A factory has three machines that manufacture knortin rods.
The following table gives data regarding production and defects. What is
the probability that a randomly chosen defective knortin rod comes from
machine 3?
machine % of production % of defects
1 40 1
2 35 2
3 25 3
To solve the problem, let B denote the event that a defective rod was chosen
and let Ak be the event that the rod came from machine k. We then have the
probabilities P(A1 ) = .4, P(A2 ) = .35, P(A3 ) = .25, and P(B | Ak ) = (.01)k.
Thus by Bayes’ theorem,
P(B | A3 )P(A3 )
P(A3 | B) =
P(B | A1 )P(A1 ) + P(B | A2 )P(A2 ) + P(B | A3 )P(A3 )
(.03)(.25)
=
(.01)(.4) + (.02)(.35) + (.03)(.25)
75
=
40 + 70 + 75
≈ .405 ♦
Probability 397
The first three are the given data. The remaining quantities are calculated in
terms of this data by Bayes’ theorem:
P(P | D)P(D) SE · P R
TP = =
P(P | D)P(D) + P(P | D0 )P(D0 ) SE · P R + (1 − SP ) · (1 − P R)
P(P 0 | D0 )P(D0 ) SP · (1 − P R)
TN = =
P(P 0 | D0 )P(D0 ) + P(P 0 | D)P(D) SP · (1 − P R) + (1 − SE) · P R
398 Discrete Mathematics and Coding
Sub TruePosTrueNeg()
Dim NumPoints As Integer, Inc As Double, j As Integer
Dim XRange As String, YRange As String, prevalence As Single
Dim sensitivity As Single, specificity As Single
If ChartObjects.Count > 0 Then ChartObjects.Delete 'clear old chart
Call ClearColumns(8, 3, 5) 'and data
Inc = 0.0005: NumPoints = 40 'graph parameters
sensitivity = Range("B4").Value
specificity = Range("B5").Value
For j = 1 To NumPoints 'calculate the formulas
Cells(j + 7, 1).Value = prevalence
Cells(j + 7, 2).Value = sensitivity * prevalence /
(sensitivity * prevalence + (1 - specificity) * (1 - prevalence))
Cells(j + 7, 3).Value = specificity * (1 - prevalence) /
(specificity * (1 - prevalence) + (1 - sensitivity) * prevalence)
prevalence = prevalence + Inc
Next j
XRange = "A" & 8 & ":" & "A" & 7 + NumPoints
YRange = "B" & 8 & ":" & "B" & 7 + NumPoints
Call MakeChart(xlXYScatter, XRange, YRange, 250, 400, 50, 350, _
"True Positive")
XRange = "A" & 8 & ":" & "A" & 7 + NumPoints
YRange = "C" & 8 & ":" & "C" & 7 + NumPoints
Call MakeChart(xlXYScatter, XRange, YRange, 650, 400, 50, 350, _
"True Negative")
End Sub
20.9 Independence
Events A and B in a probability experiment are said to be independent if
P(AB) = P(A)P(B).
P(AB) P(A)P(B)
P(A | B) = = = P(A) and
P(B) P(B)
P(AB) P(A)P(B)
P(B | A) = = = P(B).
P(A) P(A)
Thus the information imparted by either event does not affect the probability
of the other.
Example 20.3. In the dice throw experiment, let A be the event that the
sum of the dice is 7, B the event that the sum of the dice is 8, and C the event
that the first die is even. Then P(A) = 1/6, P(B) = 5/36, P(C) = 1/2, and
P(AC) = P(AB) = 1/12, so the events A and C are independent, but B and
C are not. ♦
An arbitrary collection of events is said to be independent if for all choices
A1 , A2 , . . ., An in the collection
Successive coin flips are independent, as a coin has no memory.2 For example if
you toss a coin 3 times in succession and Aj is the event that the jth toss comes
up heads, then A1 , A2 , and A3 are easily seen to be independent. This explains
the use of the phrase “independent trials.” Here is another such example:
Example 20.4. An urn contains 5 red and 6 yellow marbles. We randomly
draw marbles one at a time, each time replacing the marble. Let R1 denote
the event that the first marble is red, R2 the event that the second marble is
red, and Y3 the event that the third marble is yellow. Since the marbles were
2 A common fallacy is that a long string of successive heads in the toss of a fair coin
replaced, the events are independent. Thus the probability that the first two
marbles are red and the third is yellow is
P(R1 R2 Y3 ) = P(R1 )P(R2 )P(Y3 ) = (5/11)(5/11)(6/11) ≈ .113.
Note that, unlike Example 20.1, the original marble configuration in the urn is
restored after each draw, ensuring independence. ♦
20.10 Exercises
1. You have 5 history books, 4 mathematics books, and 3 physics books
that you randomly place next to each other on a shelf. What is the
probability that all books within the same subject will be adjacent?
2. A group of 3 women and 3 men line up for a photograph. Find the
probability that at least two people of the same gender are adjacent.
3. Hanna and Eric intend to have a ping pong tournament, the grand
winner being the first one who wins 3 games. Based on previous games
the probability of Eric winning a particular game is p, while that of Hanna
is q. Find the probability that Hanna wins the tournament. Assume that
there are no ties (p + q = 1).
4. A “loaded” die has the property that the numbers 1 to 5 are equally
likely but the number 6 is three times as likely to occur as any of the
others. What is the probability that the die comes up even?
5. Balls are randomly thrown one at a time at a row of 30 open-topped jars
numbered 1 to 30. Assuming that each ball lands in some jar, find the
smallest number N of throws required so that there is a better than a
60% chance that two balls land in the same jar.
6. A hat contains six slips of paper numbered 1 through 6. A slip is drawn
at random, the number is noted, the slip is replaced in the hat, and the
procedure is repeated. What is the probability that after three draws
the slip numbered 1 was drawn exactly twice, given that the sum of the
numbers on the three draws is 8.
7. An urn contains 12 marbles: 3 reds, 4 greens, and 5 yellows. A handful
of 6 marbles is drawn at random. Let A be the event that there are at
least 3 green marbles and B the event that there is exactly 1 red. Find
P(A|B). Are the events independent?
8. Write a program DiceProbabilities that calculates and graphs the the-
oretical probabilities in a dice throw by keeping track of the number
of pairs (i, j) that add up to k = 2, 3, . . . , 12 and dividing this number
by 36.
Probability 401
9. Roll a fair die twice. Let A be the event that the first roll comes up odd,
B the event that the second roll is odd, and C the event that the sum
of the dice is odd. Show that any two of the events A, B, and C are
independent but the events A, B, and C are not independent.
10. Write a program Bayes that calculates Bayes probabilities. Figure 20.6
depicts a possible spreadsheet with input in columns B and D and output
(rounded to two places) in column F.
A B C D E F
6 P(A1) = .09 P(B | A1) = .04 P(A1 | B) = .11
7 P(A2) = .23 P(B | A2) = .02 P(A2 | B) = .14
8 P(A3) = .16 P(B | A3) = .06 P(A3 | B) = .29
9 P(A4) = .12 P(B | A4) = .01 P(A4 | B) = .04
10 P(A5) = .35 P(B | A5) = .03 P(A5 | B) = .32
11 P(A6) = .05 P(B | A6) = .07 P(A6 | B) = .11
form what is called the probability distribution of X. For example, the random
variable S mentioned in the introduction has probability distribution
If we select a student ω at random then we are also selecting the student’s grade
X(ω), one of the eight numbers in the last row of the table. The probability
distribution of X is therefore given by
9 17 6
P(X = 2.2) = , P(X = 2.3) = , . . . , P(X = 3.5) = .
100 100 100
This process may be carried out for any data set. ♦
Example 21.2. (Bernoulli random variable X with parameter p): X takes
on two values, 1 and 0, with probabilities p and 1 − p, respectively:
P(X = 1) = p, P(X = 0) = 1 − p.
An example is the number of heads (one or zero) that come up on the toss of
a single coin with probability of heads p. ♦
Example 21.3. (Binomial random variable X with parameters n, p): X takes
on the values 0, 1, . . . , n with probabilities
n k n−k
P(X = k) = p q , q = 1 − p, k = 0, 1, . . . , n.
k
An example is the number of heads that come up in the toss of n coins, where
p is the probability of heads in a single toss. ♦
The above random variables take on only finitely many values. However,
there are many important random variables that take on infinitely many values.
Here is an example.
Example 21.4. (Geometric random variable X with parameter p): X takes
on the values 1, 2, 3 . . . with probabilities
P(X = k) = q k−1 p, q = 1 − p, k = 1, 2, 3, . . . , n.
An example is the number coin tosses required until the first head appears,
where p is the probability of a head on a single toss. Thus X = 5 if and only if
the first four tosses result in tails and the fifth toss in a head, this occurring
with probability qqqqp = q 4 p. ♦
Random variables with values in a finite or infinite set of the form
{x1 , x2 , x3 , . . .} are called discrete. Random variables that take on all val-
ues in an interval are said to be continuous. The latter typically arise from
continuous data such as weight of a new born baby, inches of rainfall, or stock
values. Probability distributions for continuous random variables are given by
a “smooth histogram.” The most important example of these is the following.
Example 21.5. (Normal random variable X with parameters µ and σ): The
probability P(a < X < b) that X lies in an interval (a, b) is defined as the area
under the bell-shaped curve with equation
1 x−µ 2
y= √ e−( σ ) /2 .
σ 2π
Random Variables 405
The maximum of the curve occurs at µ. The parameter σ controls the shape:
the larger the value of σ the flatter the curve. In the figure µ = 4 and σ = 1.
The shaded region in the figure is the probability P(2.7 < X < 4.5).
0.3
0.2
0.1
0
0 2 4 6 8
Normal random variables are important in statistics and are often used in
situations involving random variables whose distributions are unknown. Their
importance derives largely from the Central Limit Theorem, discussed later. ♦
As the example suggests, the average of any collection of data may be described
in this way.
We can write the expected value of a random variable X in another way.
Recall that the probability of the event {X = xk } is the sum of the individual
probabilities of the outcomes comprising the event:
X
P(X = xk ) = P(ωi )
i:X(ωi )=xk
406 Discrete Mathematics and Coding
where the notation means that the quantities P(ωi ) are added over all indices
i satisfying X(ωi ) = xk . Substituting this into (21.1) we obtain
m
X X
E(X) = xk P(ωi )
k=1 i:X(ωi )=xk
For each k we can take xk inside the second sum where it becomes X(ωi ). The
resulting double sum is then the sum over all ωi . Thus we have the alternate
form
Xn
E(X) = X(ωi )P(ωi ). (21.2)
i=1
Therefore,
6
1 X 6 · 21 + 6 · 21
E(S) = (6i + 21) = = 7.
36 i=1 36
Thus the average roll of the dice is seven. ♦
Example 21.8. (Binomial random variable X). Recalling that
n k
P (X = k) = p (1 − p)k , k = 0, 1, . . . , n,
k
we have
n n
X X n k n−k
E(X) = kP(X = k) = k p q .
k
k=1 k=1
Now write the general term in the sum on the right as
n! (n − 1)!
k pk q n−k = np pk−1 q (n−1)−(k−1) .
k! (n − k)! (k − 1)! (n − 1) − (k − 1) !
Random Variables 407
Using the Binomial Theorem (Section 19.6) on the last expression we see that
the expected value of the stock after n days is S0 (up + dq)n .
The binomial stock price model has been used extensively in the pricing of
stock options. ♦
The mean of a random variable X that takes on infinitely many values
x1 , x2 , . . . is defined as in the finite case except that the sum is infinite. We
illustrate with the following example.
Example 21.10. (Expectation of a geometric random variable X). Recall
that X has distribution
P(X = k) = q k−1 p, q = 1 − p, k = 1, 2, 3, . . . , n.
where
Pn the infinite sum on the right is defined as the limit of the finite sums
k−1
k=1 kq p as n gets larger and larger. It may be shown by standard methods
that E(X) = 1/p. Thus, on average, it takes two tosses of a fair coin to produce
a head. ♦
Example 21.11. (Expectation of a normal random variable). It may be shown
by standard calculus methods that the mean of the random variable X of
Exercise 21.5 is µ. ♦
Thus
E(R · G) = E(R) · E(G)
The above properties hold in general. Here is a summary of the most common
properties of expectation, where X and Y are arbitrary random variables:
Both quantities measure how much a random variable deviates from its mean:
the smaller the variance or standard deviation the closer the data clusters
around the mean. Here are the main properties of variance:
(a) V(X) = E X 2 − m2 .
and
2
[E(aX + b)]2 = (am + b) = a2 m2 + 2abm + b2 .
Subtracting these equations and using part (a) yields the desired result. To
prove (c) note that
and
2
[E(X + Y )]2 = [E(X) + E(Y )] = E2 (X) + 2E(X)E(Y ) + E2 (Y ).
Subtracting these equations and using independence and part (a) establishes
the result.
Example 21.12. (Variance of a Bernoulli random variable X). Recalling that
the mean of X is p we see that
Example 21.13. (Variance of a binomial random variable X). Since the mean
of X is np we see that V(X) = E(X 2 ) − (np)2 . With a bit of work one can
show that E(X 2 ) = (np)2 + np(1 − p). Thus
Example 21.14. (Variance of a binomial random variable X). Since the mean
of X is np we see that V(X) = E(X 2 ) − (np)2 . With a bit of work one can
show that E(X 2 ) = (np)2 + np(1 − p). Thus
Bernoulli–Laplace model
Consider the following experiment. There are two urns. Urn one contains
an even number of red balls and and urn two an equal number of yellow balls.
At each trial a ball is chosen at random from each urn and the balls switched,
so the number of balls in each urn is constant. The experiment is performed
until there are an equal number of red and yellow balls in urn one (hence
also in urn two). Suppose it takes N trials for this to happen. The program
BernoulliLaplaceMeanTime calculates the average value of N
Sub BernoulliLaplaceMeanTime()
Dim NumBalls As Integer, CurrNumRed1 As Integer, count As Long
Dim color As Integer, Balls1() As Integer, Balls2() As Integer
Dim TotalCount As Long, NumTrials As Long, n As Long
Dim BallOne As Integer, BallTwo As Integer
Dim red As Integer, yellow As Integer
NumBalls = Range("B2").Value 'enter number of balls in each urn
red = 1: yellow = 2
ReDim Balls1(1 To NumBalls) 'urn 1 initially all red
ReDim Balls2(1 To NumBalls) 'urn 2 initially all yellow
NumTrials = Range("B3").Value
For n = 1 To NumTrials 'do the trials
Call Init(Balls1, 1): Call Init(Balls2, 2) 'fill urns
CurrNumRed1 = NumBalls 'urn 1 has this many red balls initially
count = 0 'reset after each trial
Do While CurrNumRed1 > NumBalls / 2
Idx1 = RandInt(1, NumBalls) 'choose ball in urn 1
BallOne = Balls1(Idx1)
Idx2 = RandInt(1, NumBalls) 'choose ball in urn 2
BallTwo = Balls2(Idx2)
If BallOne = red And BallTwo = yellow Then _
CurrNumRed1 = CurrNumRed1 - 1
If BallOne = yellow And BallTwo = red Then _
CurrNumRed1 = CurrNumRed1 + 1
Random Variables 413
X n − µn X −µ
P ≤x ≈P ≤x ,
σn σ
Setting
Sn = X1 + · · · + Xn = nX n
we may write the assertion as
Sn − nµ X −µ
P √ ≤x ≈P ≤x ,
σ n σ
414 Discrete Mathematics and Coding
In the special case that theprandom variables Xj are Bernoulli with parameter
p ∈ (0, 1), µ = p and σ = p(1 − p) so the approximation becomes
!
Sn − np X −µ
P p ≤x ≈P ≤x ,
np(1 − p) σ
21.7 Exercises
1. Consider the experiment of throwing a pair of dice n times. Let S1 denote
the sum on the first toss, S2 the sum on the second toss, etc. The sample
averages are
S1 + S2 + · · · + Sn
.
n
The LLN asserts that as we take larger and larger n, these sample
averages get closer and closer to the expected value of S, namely 7. Write
a procedure DiceSampleAvg that simulates the experiment and prints the
sample average over, say, 100, 000 trials. How close do the averages come
to 7?
2. Write a program MeanTimeForFirstH that is the one-head analog of
MeanTimeForFirstHH
A Markov chain is a system that changes over time and at any instant can
be in any one of m states, which we shall represent by the integers 1, 2, . . . , m.
The state of the system at time k is denoted by sk , which can have any one of
the values 1, 2, . . . , m. Thus at time 0 the system is in the initial state s0 , at
time 1 the system is in state s1 , etc. The history of the system at time k is
the sequence s0 , s1 , . . . , sk . A probability law governs the transition from one
state to the next. The key feature of a Markov chain is that the probability
of going from state sk to state sk+1 depends only on sk ; the previous states
s0 , s1 , . . . , sk−1 of the system are irrelevant in this transition
Markov chains arise in many common circumstances. For example, an
investor might decide to buy or sell a stock depending on its current value and
not on how the stock reached that value (although that may be shortsighted!).
A gambler might fashion a wager based on her current winnings, not on how
she achieved the winnings. A robot is essentially Markovian, acting only on the
information gleaned from its current position. Word completion in computer
programs is another example: the current state is the last word (or last few
words) entered. Words that could come next are assigned probabilities based
on a large volume of textual data.
In this chapter we develop the basic mathematics of Markov chains and
show how they may be modelled using VBA.
p21 p32
p12 p23
2
p22
Example 22.2. (Weather model). Let the state of the weather on any given
day be represented by s: sunny, c: cloudy, r: rainy. Define weather transition
probabilities psc , the probability that it will be cloudy tomorrow given that
it’s sunny today; prs , the probability that it will be sunny tomorrow given
it’s raining today; etc. The actual values could be determined from weather
statistics. The transition matrix is
pss psc psr
pcs pcc pcr ♦
prs prc prr
where pyy denotes the probability that “yes” is delivered as “yes,” etc. ♦
Example 22.4. (Consumer preference). In order to better serve its customers
the TV production company NutFlocks has collected data related to viewer
preference. It has discovered that of its customers who recently watched
an action movie, 70% selected another action movie, 20% selected a horror
movie, and 10% selected a comedy. We can interpret this data as transition
probabilities:
paa = .7, pah = .2, and pac = .1
where, for example, pah is the probability that a customer chose a horror movie
after watching an action movie. Similar data gives rise to the other transition
probabilities yielding the following possible transition matrix:
paa pah pac .7 .2 .1
pha phh phc = .3 .6 .1 ♦
pca pch pcc .2 .1 .7
and that the system is currently in state 2. The probability of being in state 3
in one time step is p23 . We are interested in finding the probability of being
(2)
in state 3 after 2 steps. We denote this probability by p23 . (Caution: the
superscript is not an exponent.) The transition from state 2 to state 3 in two
steps can be achieved by the following one-step transitions:
p21 p13 p22 p23 p23 p33
2 −→ 1 −→ 3, 2 −→ 2 −→ 3, 2 −→ 3 −→ 3.
By the multiplication rule, these 2-step transitions have probabilities p21 p13 ,
p22 p23 , and p23 p33 , respectively. By the addition rule, the desired probability
is the sum of these:
(2)
p23 = p21 p13 + p22 p23 + p23 p33 .
Note that this is the (2, 3) entry of the square P 2 of the transition matrix.
(n)
By the same analysis, the probability pij of going from state i to state j in
n
n time steps is the (i, j) entry of P . The reasoning here applies to Markov
chains with any number of states.
Example 22.5. (Transmission of information). Assume in Example 22.3 that
there is a 95% chance that a “yes” will be relayed as a “yes” and a 95% chance
that a “no” will be relayed as a “no.” Given that the current answer is “yes,”
the probability that it will be “yes” 30 people from now is the (1, 1)-entry of
30
.95 .05 .52 .48
= ,
.05 .95 .48 .52
[p(0)
1
(0)
p2 ···
(0)
pm ] = [p1 p2 ··· pm ].
(1)
To find p1 we argue as follows: To get to state 1 in one step either the system
was initially in state 1 and it transitioned in one step to state 1, or the system
was initially in state 2 and it transitioned in one step to state 1, etc. By the
multiplication rule, the probabilities of events are, respectively, p1 p11 , p2 p21 ,
etc. Since the events are mutually exclusive, the addition law implies that
(1)
p1 = p1 p11 + p2 p21 + · · · + pm pm1 .
The 1 × m matrix on the left in (22.1) is called the n-step distribution vector.
Example 22.6. (Weather model). Recall that in this model the state of the
weather on any given day is represented by s: sunny, c: cloudy, r: rainy. Suppose
that the transition matrix is
pss psc psr .9 .05 .05
pcs pcc pcr = .2 .6 .2 ,
prs prc prr .1 .1 .8
so that it is more likely than not that the weather will be the same tomorrow.
Given that it is sunny today, the probability that it will be sunny 3 days from
now is the (1, 1) entry of
3
.9 .05 .05 .8 .1 .1
.2 .6 .2 ≈ .4 .3 .3 .
.1 .1 .8 .25 .15 .5
422 Discrete Mathematics and Coding
Suppose now that the forecast for today’s weather is 80% sunny, 10% cloudy,
and 10% rain. The probability distribution for today’s weather is the row
matrix
ps pc pr = .8 .1 .1 .
From the calculation
.8 .1 .1 h i
.2 = p(3) (3) (3)
.8 .1 .1 .4 .3 .3 ≈ .7 .1 s pc pr
.25 .15 .5
we see that the probability that it will be sunny 3 days from now is only .7.
As the days progress, sunshine is less and less likely. ♦
Example 22.7. (Genotypes). Humans and animals inherit characteristics
that depend on the genetic code of their parents. We consider only the simplest
of these traits: those that depend on a single gene. Each gene has two forms,
dominant and recessive. We label the former by the letter G and the latter by
the letter g. An offspring receives one gene from each parent; these combine to
form the genotypes GG, Gg, gG and gg. A trait is said to be dominant if it
is associated with the gene GG, recessive if it is associated with the gene gg,
and hybrid if it is associated with the gene Gg or gG. The last two types are
nearly indistinguishable and so may be assumed to be the same.
Now consider what happens when a GG individual (the “mother”) breeds
with other individuals (“fathers”). Suppose that mother GG is bred with father
GG. The offspring will then be GG with probability pGG,GG = 1. If mother
GG is bred with father Gg then the offspring will be GG with probability
pGg,GG = .5 and Gg with probability pGg,Gg = .5. If GG is bred with gg then
the offspring will be Gg with probability pgg,Gg = .5. If the states of the system
are the various genotypes and the transitions are from father genotype to
offspring genotype, then the transition probabilities are given by the matrix
pGG,GG pGG,Gg pGG,gg 1 0 0
P = pGg,GG pGg,Gg pGg,gg = .5 .5 0
pgg,GG pgg,Gg pgg,gg 0 1 0
If the genotypes of the initial population of fathers are equally distributed,
that is, 1/3 of each type, then the genotypes of successive generations are given
by
1/3 1/3 1/3 P n
Using PowerMat from Section 13.5 for large powers of n we see that P n is
approximately
1 0 0
1 0 0
1 0 0
hence [1/3, 1/3, 1, 3]P n = [1, 0, 0]. Thus mating a mother with fathers
of uniform genotype distribution eventually results in a population of GG
genotypes. ♦
Markov Chains 423
One can show that this happens if for some n the matrix P n has no zero
entries. To compute q in this case, multiply on the right by P to conclude that
p1 p2 · · · pm P n P → qP as n gets larger.
The program in this section allows the user to enter formulas for transition
probabilities P L, P U , and P R in cells B3 – B5 (preceded by an equal sign, as
shown). It is not necessary to enter a formula for P D since this is calculated as
1 − (P L + P U + P R). After each movement of the cell, the entries in B1 and
B2, which contain, respectively, the row and column of the cell, are updated
and new transition probabilities are calculated from these values. A typical
input is summarized in Figure 22.2, where we have used the above formulas to
calculate the probabilities.
A B
1 row 17
2 col 22
3 PL = (1/2)*(B1 + 2)/(B1 + B2)
4 PR = (1/2)*(B1− 2)/(B1 + B2)
5 PU = (1/2)*(B2 − 2)/(B1 + B2)
FIGURE 22.2: Input for PositionRandWalk().
With the initial row and columns values in B1 and B2 as shown, the initial
probabilities are
17 + 2 17 − 2 22 − 2
PL = ≈ .244, P U = ≈ .192, P R = ≈ .256.
2(17 + 22) 2(17 + 22) 2(17 + 22)
Markov Chains 425
Sub PositionRandomWalk()
Dim Steps As Integer, Speed As Integer, k As Integer
Dim Grid As TGrid, Pos As TPos, NewPos As TPos
Dim PL As Single, PU As Single, PR As Single
Steps = 100: Speed = 12 'motion parameters
Grid = MakeGrid(8, 5, 45, 40, 2.2, 11, 24)
Call ClearGrid(Grid,0)
Call AddBorder(Grid, color)
Pos.col = (Grid.L + Grid.R) / 2 'initial position of cell
Pos.row = (Grid.T + Grid.B) / 2
Range("B2").Value = Pos.row: Range("B3").Value = Pos.col
Call PrintCell(Pos, 3) 'print a red cell
For k = 1 To Steps
If Not GetTransitionProb(PL, PU, PR) Then Exit Sub
NewPos = NextRandPos(PL, PL, PL, Pos)
If (Cells(NewPos.row, NewPos.col).Interior.ColorIndex <= 0) Then
Call MoveCell(Pos, NewPos) 'erase at Pos, print at NewPos
Pos = NewPos 'update
Range("B2").Value = NewPos.row
Range("B3").Value = NewPos.col
Call Delay(Speed) 'delay before the next move
End If
Next k
End Sub
the same color is added to the urn. The process is repeated as many times
as desired. The state of the system at a particular time is the number r of
red balls and the number g of green balls in the urn, symbolized by (r, g).
The probability of transition to the state (r + 1, g) (a red ball was drawn) is
r/(r + g), the probability of drawing a red ball in an urn with r red balls and g
green balls. Similarly, the transition probability to the state (r, g + 1) (a green
ball was drawn) is g/(r + g). Figure 22.3 shows the process for three draws.
r+3
r+2 g
g r+2
r+1 g+1
g r+2
r+1 g+1
g+1 r+1
r g+2
g r+2
r+1 g+1
g+1 r+1
r g+2
g+1 r+1
r g+2
g+2 r
g+3
The module PolyaUrn in this section simulates the experiment. The urn is
pictured in the spreadsheet as a bottomless grid with dimensions given by the
UDT TUrn. The user enters the desired initial number of red and green balls
in cells B3 and B4. The main procedure DrawBall calls FillUrn to place the
balls, pictured in the grid as colored cells or, alternately, as colored letter O’s,
in the urn. A For Next loop executes the sequence of draws. The numbers
NumRed and NumGreen of red and green balls are updated after each draw by the
procedures DrewRed and DrewGreen. The VBA function Rnd is called to simulate
the drawing a red ball or a green ball.
The procedure DrewRed adds another red ball to the urn, using the procedure
EmptyCell to find a spot for the new red ball. DrewGreen performs the analogous
task.
The function EmptyCell scans the urn and returns the first empty position.
i = i + 1
Loop
line: em.row = i: em.col = j: EmptyCell = em
End Function
The procedure FillUrn uses PrintBall to populates the grid with the initial
number of red and green cells (or O’s) representing the balls (Figure 22.4).
A B C D E F G H I J K L M O P Q
2 draws 20
3 current red 44
4 current green 39
5 urn top 2
6 urn bottom 8
7 urn left 4
8 urn right 16
the state of the system to be the number of balls in urn 1. If that number is
i = 0, 1, . . . , N , then the transition probabilities are
i
pi,i−1 = (i ≥ 1), (ball was chosen from urn 1 and placed in urn 2).
N
and
N −i
pi,i+1 = (i < N ), (ball was chosen from urn 2 and placed in urn 1).
N
The transition probabilities pij for all other values of i and j are zero. The
model, named after physicists Tatiana and Paul Ehrenfest, has been used to
describe the exchange of gas molecules between two containers. (Figure 22.5.)
The module EhrenfestUrns simulates the diffusion model. The user enters
the number of desired balls for each urn and the number of desired diffusion
steps. An array of type TUrn holds the dimensions of the urns as well as the
numbers of balls. The procedure FillUrns fills each urn with an initial number
of balls, displayed as O’s in the spreadsheet. The variables Urn(1).N and
Urn(2).N keep track of the number of balls in the urns at any given moment. A
Do While loop carries out the diffusion steps. The probability of drawing from
a particular urn is proportional to the number of balls in the urn—the higher
the number of balls in an urn the more likely it is that that urn will be chosen.
Ultimately the system arrives at equilibrium, the number of balls in the urns
differing by at most one. The VBA function Rnd carries out the drawings by
respecting the proportion of balls in the urns, a method analogous to that of
the Polya model.
430 Discrete Mathematics and Coding
Sub EhrenfestUrn()
Dim x As Double, NumBalls As Integer, i As Integer, Urn() As TUrn
Columns("C:AZ").ColumnWidth = 2.5 'compress columns
ReDim Urn(1 To 2
Urn(1).N = Range("B5").Value 'initial no. of balls in urn 1
Urn(2).N = Range("B6").Value 'initial no. of balls in urn 2
Urn(1).T = 3: Urn(1).L = 4: Urn(1).R = 20 'urn dimensions
Urn(2).T = 3: Urn(2).L = 24: Urn(2).R = 40
Call ClearColumns(Urn(1).T, Urn(1).L, Urn(2).R)
Call FillUrns(Urn)
Do While Abs(Urn(1).N - Urn(2).N)) > 1 'continue until steady state
i = i + 1
Randomize: x = Rnd
If x <= Urn(1).N / (Urn(1).N + Urn(2).N) Then
Call DrewFromUrn(1, Urn)
Else
Call DrewFromUrn(2, Urn)
End If
Loop
End Sub
The procedure DrewFromUrn carries out the transfer of balls from one urn to
the other.
Private Sub DrewFromUrn(whichUrn As Integer, Urn() As TUrn)
If whichUrn = 1 Then 'update urns
Urn(2).N = Urn(2).N + 1: Urn(1).N = Urn(1).N - 1
Call AddToUrn(Urn(2)): Call RemoveFromUrn(Urn(1))
Else
Urn(1).N = Urn(1).N + 1: Urn(2).N = Urn(2).N - 1
Call AddToUrn(Urn(1)): Call RemoveFromUrn(Urn(2))
End If
End Sub
1 2 3
4 0 5 4
1 2 3 1 2 3 1 6 7 8 6
4 0 5 4 0 5 4
6 7 8 6 7 8 6
2 3 1
Sub SteppingStone()
Dim Grid As TGrid, Colors() As Integer, Pos() As TPos
Dim i As Long, NumDisplays As Long
NumDisplays = Range("B2").Value 'number of displays
Grid = MakeGrid(5, 5, 26, 26, 2.2, 11, 0)
Colors = InitialColors(Grid) 'store, print random cell colors
Pos = MakeTorus(Grid) 'transforms row T-1 to row B, etc.
For i = 1 To NumDisplays
Range("C2").Value = NumDisplays - i
Call ColorNextCell(Pos, Colors, Grid)
Next i
End Sub
Next coff
Next roff
For color = 1 To 56 'get freq. distribution of neighbor colors
For k = 1 To 8 'run through the neighbors
If color = NborColors(k) Then 'kth neighbor color
ColorFreq(color) = ColorFreq(color) + 1 'tally
End If
Next k
Next color
For color = 1 To 56 'convert freq. to to prob. distribution
ColorFreq(color) = ColorFreq(color) / 8
Next color
Colors(i, j) = RndOut(ColorFreq) 'get random color
Call PrintCell(Pos(i,j), Colors(i, j))
End Sub
22.9 Exercises
1. Let coins A and B have probabilities pa and pb of heads on a single
toss. Initially, coin A is tossed until heads comes up, at which time coin
B is tossed until heads comes up, then coin A again. Write a program
SwitchCoinToss that simulates the experiment, printing out the sequence
of A’s and B’s in one column and the sequence of H’s and T’s in an
adjacent column.
2. (Direction dependent random walk). Consider again a single red cell
moving in a spreadsheet grid. Define the system to be in state
1 if the cell just moved right, 2 if the cell just moved left,
3 if the cell just moved up, 4 if the cell just moved down.
(This assumes that at time zero the cell was in motion, establishing
an initial direction.) Denote by pij the transition probabilities that
govern the motion of the cell. For example, p11 is the probability that
the cell moves right, given that it just moved right, and p23 is the
probability that it moves up, given that is just moved left. Write a
program DirectionRandomWalk that simulates the experiment. You will
have to enter the transition matrix of your choice in the spreadsheet.
3. Write a program PolyaUrn2 that modifies the module PolyaUrn as follows:
Draw ball at random from the urn, note the color, replace it, and add to
the urn s balls of the same color and o balls of the opposite color.
Markov Chains 435
4. (Moran urn model). Simulate the following variation of the Pólya urn
model:
(1) Draw a ball randomly from an urn containing red and green balls.
(2) Return the ball together with a ball of the same color.
(3) Remove a ball randomly from the urn.
The new feature is (3), which results in the number of balls in the urn
not changing, but of course the color distribution does. What happens
in the long run? The Moran urn model has been used to study genetic
drift in populations.
5. (Hoppe urn model). Simulate the following variation of the Pólya urn
scheme: An urn contains b black balls. At any draw, if a black ball is
drawn replace the ball along with a ball of a non-black color randomly
generated from the numbers 2, · · · , 56. If a non-black ball is chosen,
return the ball and add another ball of the same color, as in the Pólya
urn scheme. Thus the number of black balls remains constant. For a
visually interesting effect place the non-black ball in the position of the
black ball drawn and then add back the black ball at the bottom of the
urn grid.
6. The version of SteppingStone changed one cell at a time. Make a version
SteppingStoneSimultaneous that changes the whole grid before displaying
the new colors. Suggestion: For each transition, copy the existing color
configuration into a temporary array TempColors, carry out the transition
rules using this array, copy back to Colors, and then print the colors. You
may wish to to allow the user to enter the number of times the transitions
are carried out before the next display Choosing a large number speeds
up the “evolution” of the color configuration.
7. Find the steady state by hand for the following matrices P
.9 .1 .7 .3 .2 .8 .07 .93
(a) (b) (c) (d)
.4 .6 .5 .5 .1 .9 .84 .16
Properties of Numbers
Chapter 23
Divisibility and Prime Numbers
The procedures Qtnt and Rmdr below return q and r given a and b.
Function Qtnt(a As Long, b As Long) As Long
Dim q As Long
If b = 0 Then Exit Function
If a = Int(a / b) * b Or 0 < b And 0 < a Then
q = Int(a / b)
ElseIf b < 0 And 0 < a Then
q = -Int(a / (-b))
ElseIf a < 0 And 0 < b Then
q = -Int((-a) / b) - 1
ElseIf b < 0 And a < 0 Then
q = Int((-a) / -(b)) + 1
End If
Qtnt = q
End Function
One could use Double instead of Long in the above code if larger integers a, b
are desired.
123456 = 8818 · 14 + 4
8818 = 629 · 14 + 12
629 = 44 · 14 + 13 32DC414
44 = 3 · 14 + 2
3 = 0 · 14 + 3
The reverse procedure ToBase10 takes a number in base b and returns the
number in base 10.
For i = 0 To Len(num_b) - 1
d = Mid(num_b, i + 1, 1)
For j = 0 To 35 'find number corresponding to digit
If d = Digit(j) Then Exit For
Next j
num_10 = j * base_b ^ i + num_10
Next i
ToBase10 = CStr(num_10) 'return base_b input number in base 10
End Function
The following function combines the two procedures. It takes a pair of bases
a, b and a number in base a and returns the number in base b.
Function BaseToBase(num_a As String, base_a As Long, base_b As Long) _
As String 'convert base_a number num_a to base_b
Dim num_10 As String, num_b As String
num_10 = ToBase10(num_a, base_a)
num_b = FromBase10(num_10, base_b)
BaseToBase = FromBase10(num_10, base_b)
End Function
change to white. In the fourth pattern the central cell is white as is its right
neighbor, and its left neighbor is red. In this case the rule requires the cell color
to change to red. The top pattern in Figure 23.3 shows the result of applying
the rules 17 times with a single 1 in the first row. The bottom pattern in the
figure shows the result of applying the rule over 60 times, with interesting
patterns beginning to emerge.
7 6 5 4 3 2 1 0
1 1 1 1 1 0 1 0 1 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0
0 0 0 1 1 1 1 0
The cells in Figure 23.1 have been labelled with 1’s and 0’s, 1 for red and 0
for white. In the first row these have been interpreted as binary numbers with
values 7–0. Similarly, the second row is binary for the number 30, accounting
for the rule’s name. Changing the number changes the rule. Thus there are as
many rules as there 8 digit binary numbers, namely 28 = 256. The rule of 22
is given in Figure 23.2.
7 6 5 4 3 2 1 0
1 1 1 1 1 0 1 0 1 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0
0 0 0 1 0 1 1 0
The program WolframRules allows the user to enter any one of the 256
numbers 0–255. Running the program then produces the corresponding con-
figuration. The number is entered in cell B5 and digits 1 are entered in row
6; the rest of the cells are assumed to be 0. Entering a single 1 produces the
triangular shapes in the figures. Entering several 1’s can produce interesting
competing triangular shapes.
Public L As Integer, R As Integer, T As Integer, B As Integer
Sub WolframRules()
Dim states(0 To 7) As Integer, i As Integer, rule As Integer
L = 3: R = 150: T = 6: B = 90 'grid position
Range(Cells(T, L), Cells(B, R)).ClearFormats
Range(Cells(, L), Cells(, R)).ColumnWidth = 1.7 'compress columns
Range(Cells(T, L), Cells(B, R)).RowHeight = 8 'and rows
rule = Range("B5").Value 'get Wolfram rule number
Call Binary(rule, states) 'convert rule to binary states
Call FirstGen 'initialize first row T
For i = T + 1 To B
Call NextGen(states, i) 'color row i using previous generation
Next i
End Sub
The procedure Binary converts the rule number into binary form
d7 d6 . . . d1 d0 and stores the digits in the array states with states(0)= d0 ,
states(1)= d1 , etc. For example, if the rule number is 30 then states(j) = 1
for j = 1, 2, 3, 4, and 0 otherwise. One could use the procedure FromBase10 for
this but Binary is more direct.
Sub Binary(rule As Integer, states() As Integer)
Dim q1 As Integer, q As Integer
q = rule
For i = 0 To 7
states(i) = q Mod 2 'remainder on division by 2
q1 = q \ 2 'quotient of last quotient
q = q1 'new quotient
Next i
End Sub
Divisibility and Prime Numbers 445
The procedure FirstGen simply colors red any cell in the top row T containing
a digit 1.
Sub FirstGen()
Dim j As Integer
For j = L To R 'read first generation row T, color cells with a 1 red
If Cells(T, j).Value = 1 Then Cells(T, j).Interior.ColorIndex = 3
Next j
End Sub
The procedure NextGen is given a row and runs through the row’s columns
applying the binary rules.
Sub NextGen(states() As Integer, row As Integer)
Dim j As Integer For j = L + 1 To R - 1
Call ApplyRules(states, row, j) 'apply rules for the entire row
Next j
End Sub
The heart of the module is the procedure ApplyRules. It is given the rule
stored in the array states and also the row, column position of a new cell.
The cell immediately above it and the left and right neighbors of this cell
are assigned binary digits: 1 if the color of the cell is red, 0 otherwise. These
form a three digit binary number Lcell Mcell Rcell with decimal value 0–7.
The number is then converted into decimal form c. The number states(c) is
either 0 or 1 depending on the rule, and the cell is colored accordingly. For
example, for the configuration in Figure 23.1 labelled 2, Lcell=0, Mcell=1,
Rcell=0. Since for rule 30 states(2)=1, the new cell gets the color red.
the last example with the aid of the module GCD below.
The division algorithm gives us a way to calculate the gcd of an arbitrary
pair of positive integers a, b. For this we may assume without loss of generality
that a > b. Assuming this, we successively apply the division algorithm in the
following manner, where r1 = a and r2 = b:
In general, we divide rn−2 by rn−1 to produce the quotient qn−2 and the
remainder rn :
rn−2 = qn−2 rn−1 + rn , , 0 ≤ rn < rn−1 . (23.2)
Since the remainders are strictly decreasing and nonnegative, there is a smallest
n for which rn+1 = 0. It may be shown that for this n, rn = gcd(a, b). We
illustrate this for a = 74, b = 22:
r1 q1 r2 r3 r2 q2 r3 r4 r3 q3 r4 r5 r4 q4 r5 r6
74 = 3 · 22 + 8 , 22 = 2 · 8 + 6 , 8 = 1 · 6 + 2 , 6 = 3 · 2 + 0
so gcd(74, 22) = r5 = 2.
The above scheme may be easily implemented with VBA. Rather than
do this, however, we give an algorithm that not only calculates the gcd of
user-entered positive integers a, b, but also finds integers x and y such that
gcd(a, b) = xa + yb.
As we shall see, this is a very useful property of the gcd. Here’s an obvious
and sometimes useful consequence:
The converse of this is also true: if 1 = ax + by holds for some x and y, then
gcd(a, b) = 1. Indeed, any common factor of a and b must be a factor of 1 and
so must equal 1.
Divisibility and Prime Numbers 447
r3 = r1 − q1 r2
r4 = r2 − q2 r3 = r2 − q2 (r1 − q1 r2 ) = −q2 r1 + (1 + q1 q2 )r2
(23.4)
r5 = r3 − q3 r4 = r1 − q1 r2 − q3 (−q2 r1 + (1 + q1 q2 )r2 )
= (1 + q2 q3 )r1 − (q1 + q3 + q1 q2 q3 )r2
Continuing this process we see that for each n ≥ 3 there exist integers xn and
yn (not necessarily positive) such that rn = xn r1 + yn r2 . Recalling that for
some n the remainder rn is the gcd of a = r1 and b = r2 , we conclude that the
gcd may be expressed in the desired form xa + yb.
To calculate x and y define y1 = 0, y2 = 1 and notice that the coefficients
yn of r2 in (23.4) follow the rules
y1 − q1 y2 = −q1 = y3
y2 − q2 y3 = 1 − q2 (−q1 ) = 1 + q1 q2 = y4
y3 − q3 y4 = (−q1 ) − q3 (1 + q1 q2 ) = −(q1 + q3 + q1 q2 q3 ) = y5
Equations (23.3) and (23.5) form the basis of the extended Euclidean algorithm
x = (g - b * y) / a
If switched Then Call SwitchValues(x, y) 'x goes with a, y with b
GCD = g
End Function
The greatest common divisor may be extended to more than two numbers.
For example, gcd(a1 , a2 , a3 ) is defined as the largest common divisor of a1 , a2 ,
and a3 . It follows easily that
gcd(a1 , a2 , a3 ) = gcd(gcd(a1 , a2 ), a3 ),
The reader may wish to write a simple recursive program that uses this equation
to find the gcd of a user-entered or randomly generated list of integers.
One need not start the induction at 1; any positive integer may be used. The
principle has been loosely described as the “domino principle”: If dominoes
are lined up vertically so that the (n + 1)st domino will fall if the nth one falls,
then, if the first domino is tipped, all the dominoes will fall.
The proof of the divisibility property uses induction starting at n = 2: For
this case we need to show that if p | a1 a2 , then either p | a1 or p | a2 . Now,
by hypothesis, a1 a2 = pk for some integer k. If p | a1 then we are done, so
assume that p - a1 . Then, because p is prime, p and a1 have no common factors
other than 1, that is, gcd(a1 , p) = 1. By Bézout’s equation (Section 23.4),
a1 x + py = 1 for some integers x and y. Multiplying the equation by a2 we
then have
For example
Since the p’s are strictly increasing, the q’s in this scheme are as well. By the
prime divisibility property, all the q’s in the original expansion are accounted
for in (23.8) and it follows that m = n and pk = qk for all k. Thus from (23.7)
which is possible only if ek = fk for all k. (If, say, e1 > f1 , then canceling the
factor pf11 would result in p1 dividing the left side but not the right).
The procedure AddPrime is passed the array TestPrimes, which holds the
test primes obtained so far, and is also passed an integer x and the index of
the last prime in the array. A new prime k ≤ x is added to the array if k is
not divisible by any of the previous test primes.
Sub AddPrime(TestPrimes() As Integer, x As Long, idx As Long)
Dim k As Long, j As Long
For k = 3 To x 'check numbers k <= x for primality
For j = 1 To idx
If k Mod TestPrimes(j) = 0 Then GoTo Next_k 'k not prime
Next j
TestPrimes(idx + 1) = k 'k prime; add it to array
Exit For 'done
Next_k:
Next k
End Sub
√ integer N ≥ 2 is
The following function detects if a user-entered positive
prime. It does so by checking whether N has a divisor ≤ N . It is unnecessary
to check for larger divisors as these
√ occur in pairs m, k with N = mk, and not
both of these can be larger than N .
Function IsPrime(N As Long) As Boolean 'return True if N is prime
Dim i As Long, m As Long, PrimeNumber As Boolean
PrimeNumber = True 'default
m = Int(N ^ (1 / 2)) 'no need to test for larger factors
For i = 2 To m 'check if i a factor of N
If N Mod i = 0 Then PrimeNumber = False: Exit For 'N not prime
Next i
IsPrime = PrimeNumber
End Function
23.8 Exercises
1. The least common multiple (LCM) of a pair of positive integers a, b,
denoted lcm(a, b), is the smallest positive integer that is both a multiple
of a and a multiple of b. For example, lcm(3, 4) = 12. Write a function
LCM(a,b) that returns lcm(a, b). Check that lcm(a, b) · gcd(a, b) = ab.
5. Use the program GCD to generate gcd(a + 2b, 2a + b) for various relatively
prime a, b. What are your conclusions?
6. Write a program Primes-n-To-2n that lists all the primes between n and
2n for n ≤ some user entered integer N . (A theorem of Chebyshev asserts
that there is always at least one such prime.) The following is a sample
spreadsheet.
A B
2 N= 50
3 n 2n primes
4 1 2 2
5 2 4 2,3
6 3 6 2,3,5
53 50 100 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
7. Two odd consecutive numbers that are both prime are called twin primes.
For example, the first eight pairs of twin primes are
(3, 5), (11, 13), (17, 19), (29, 31), (41, 43), (59, 61), (71, 73), (101, 103).
17 16 15 14 13 30
18 5 4 3 12 29
19 6 1 2 11 28
20 7 8 9 10 27
21 22 23 24 25 26
Gardener and S. Ulam discovered that in large spirals there are many
prominent lines containing a large number of primes. Large spirals may
be achieved by using a grid with very small cells without the numbers
and displaying a prime as a red cell and a non prime as an empty cell.
Figure 23.7 was generated using 15000 numbers.
In this chapter we explore another kind of arithmetic, one that is based on the
notion of congruence. The theory was developed by the German mathematician
Carl Friedrich Gauss in the late 18th century. It has since become an important
tool in the study of divisibility and an integral component of cryptography.
While the notion in its abstract form may be unfamiliar to the reader, the idea
of congruence is implicit in ordinary “clock arithmetic.”
a 6≡ b (mod m) or a 6≡m b.
For example,
a = qm + r, 0 ≤ r < m,
(1) a ≡m a. (reflexivity)
(2) If a ≡m b, then b ≡m a. (symmetry)
(3) If a ≡m b and b ≡m c, then a ≡m c (transitivity)
For example, to verify (3) note that the hypotheses state that a − b = jm
and b − c = km for some integers j and k. Adding these equations we obtain
a − c = (j + k)m, which shows that a ≡m c.
(a + c) − (b + d) = (a − b) + (c − d) = jm + km = (j + k)m.
which may be verified by multiplying out the right side and cancelling terms.
Since by hypothesis a − b is divisible by m, so is an − bn .
Example 24.1. (Casting out nines). Since 10 ≡ 1 (mod 9) , it follows from
(4) that 10n ≡ 1 (mod 9) for any natural number n. Now let a be a positive
integer with decimal digit representation a = ak ak−1 . . . a1 a0 , so that
a = a0 + a1 · 10 + a2 · 102 + · · · + ak · 10k .
Congruence 459
Let a∗ = a0 +a1 +a2 +· · ·+ak , the sum of the digits of a. We claim that a ≡9 a∗ .
Indeed, since 10n ≡9 1 it follows from (3) that an · 10n ≡9 an (n = 1, 2, . . . , k).
Adding these congruences and using (1) verifies the assertion. For example,
successively adding digits we see that
77777777 ≡9 56 ≡9 11 ≡9 2.
The result may be used as a check for multiplication. For example, using
similar notation, property (3) and the result of the previous paragraph imply
that
(ab)∗ ≡9 ab ≡9 a∗ b∗ .
Thus if (ab)∗ 6≡9 a∗ b∗ , then the multiplication ab is incorrect. ♦
As in ordinary arithmetic, congruence arithmetic also has a cancellation
law, but with an important caveat:
The property provides the theoretical basis of the RSA cipher algorithm
discussed in the next chapter. We prove it by induction on the positive integer
a (Section 23.5). For a = 1 the assertion is trivial. Now suppose that ap ≡
460 Discrete Mathematics and Coding
To verify (24.2), note first that because a ≡ R(a) and b ≡ R(b), by the product
property
ab ≡ R(a)R(b) ≡ R(R(a)R(b)).
Congruence 461
The reader may check that the function works well for large lists of factors
not exceeding 15 digits. Using Long instead of Double decreases this to 9 digits.
462 Discrete Mathematics and Coding
All but the third term (which corresponds to the 0 digit in 110112 are used as
factors.
The function PowerRmdr implements the algorithm. It is passed the base,
exponent, and modulus, and returns the remainder.
Function PowerRmdr(c As Double, e As Double, m As Double) As Double
Dim i As Integer, j As Integer, r As Double
Dim eBase2 As String, L As Integer, Factors() As Double
eBase2 = FromBase10(e,2) 'get base 2 representation
ReDim Factors(1 To NumFactors(eBase2)) 'NumFactors = no. of 1's
L = Len(eBase2) 'L = no. of digits
r = c : i = 1 'initializations
If Mid(eBase2, L, 1) = 1 Then 'if rightmost digit is 1
Factors(1) = c 'then first factor is c
i = i + 1 'get ready for next factor
End If
For j = 1 To L - 1 'run through digits of eBase2
r = Rmdr(r ^ 2, m) 'get remainder of successive squares
If Mid(eBase2, L - j, 1) = 1 Then 'if digit = 1 then
Factors(i) = r: i = i + 1 'add r to list
End If
Next j 'next digit
PowerRmdr = ProductRmdr(Factors, m) 'product of factors
End Function
The function NumFactors counts the number of ones in the base 2 represen-
tation of the exponent. This is precisely the number of factors in ce .
Sub CongruenceTables()
Dim m As Integer, i As Integer, j As Integer, PRow As Integer
Dim PCol As Integer, TRow As Integer, TCol As Integer
Columns("C:ZZ").ColumnWidth = 3.5 'compress columns
Rows("3:50").RowHeight = 18
Range("D3:ZZ1000").ClearContents 'clear previous tables
m = Range("B3").Value
PRow = 3: PCol = 4 'position of + sign
TRow = PRow + m + 2: TCol = PCol 'position of * sign
Cells(PRow, PCol).Value = "+" 'labels for the tables
Cells(TRow, TCol).Value = "*"
For i = 0 To m - 1
For j = 0 To m - 1
Cells(PRow + 1 + i, PCol).Value = i 'col labels for +
Cells(PRow, PCol + 1 + j).Value = j 'row labels for +
Cells(PRow + 1 + i, PCol + 1 + j).Value = (i + j) Mod m
Cells(TRow + 1 + i, TCol).Value = i 'col labels for *
Cells(TRow, TCol + 1 + j).Value = j 'row labels for *
Cells(TRow + 1 + i, TCol + 1 + j).Value = (i * j) Mod m
Next j
Next i
End Sub
24.8 Exercises
1. Write a program SquareRootModp that takes as input a number M and a
prime p and prints out all numbers n ≤ M that have an integer square
root k modulo p, that is, k 2 ≡ n (mod p) . Print the k’s next to the n’s.
2. Write a program AddSubMatMod that returns the sum or difference of
two integer matrices modulo m. Do the same for ScalarMultMod, and
MultMatMod.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 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
that these numbers are the remainders modulo 26, allowing the introduction of
mathematical techniques via the modulus function. We shall call the number
that corresponds to a letter the alpha value or alpha number of that letter. In
this regard the following functions will occasionally be useful:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
0 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
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2
These formulas suggest how the process of encrypting and decrypting can be
implemented by a computer program.
The Caesar cipher is not particularly useful as it is easily broken and
therefore offers little security. It does find use, however, as part of more
complex ciphers such as the Vigenerère Cipher described in Section 25.7.
Cryptography 469
LOCATETHEFILETHEYAREHERE
L T E E Y H
O A E H F L T E A E E E
C T I H R R
Notice that there are 6 letters in the top and bottom rows and twice that many
in the third row, 24 letters in all. Thus the ratios of the rows are 1:2:1. The
encrypted message is then obtained by concatenating the rows (called “rails”):
LTEEYHOAEHFLTEAEEECTIHRR
The receiver notes the number of letters in the ciphertext, partitions them
into rows with the ratios 1:2:1, and replicates the diagram in Figure 25.3, thus
retrieving the original message.
The scheme works for any plaintext that can be rendered into rows with
ratios 1:2:1. Thus if the length is L then there must be an integer n such that
L = n + 2n + n = 4n. Otherwise the message must be padded with enough
“dummy letters” to achieve this (X’s are usually used for this purpose).
complete square with an odd number of letters on each side. For example,
consider the message ”Rendezvous tonight at the same time and same place.”
Capitalizing and padding leads to the square in Figure 25.4, which we take as
a matrix. Note that the first letter R of the message is the center of the matrix
and the rest of the message spirals outward in a clockwise direction.
A N D T H E S
E N I G H T A
M O N D E A M
I T E R Z T E
T S U O V T P
E M A S E H L
X X X X E C A
The X’s pad the message so that each side of the square has an odd length and
hence an exact center. The rows are then concatenated to form the ciphertext
ANDTHESENIGHTAMONDEAMITERZTETSUOVTPEMASEHLXXXXECA
The pair row,col are the current indices of the spiral matrix, nRows is the
number of rows, and center is the row and column of the central entry of the
matrix.
Encryption
The procedure Encrypt reads the message entered in B3 and pads it with X’s,
if necessary, to obtain a message whose spiral matrix is square with an odd num-
ber of rows and columns. The plaintext is then converted into the spiral matrix
using the procedure ptext2spiralMat. The procedure Spiral2ctext(spiralMat)
concatenates the rows of the matrix to form the ciphertext.
Sub Encrypt()
Dim spiralMat() As String, ptext As String, ctext As String
ptext = PadX(Range("B3").Value)
msgLen = Len(ptext)
nRows = msgLen ^ (1 / 2)
center = Int(nRows / 2) + 1 'nRows is odd
spiralMat = ptext2spiralMat(ptext)
ctext = Spiral2ctext(spiralMat) 'convert matrix to ctext
Range("B5").Value = ctext
End Sub
Cryptography 471
The function PadX finds the smallest perfect square k 2 greater than or equal
to the length of the plaintext. If k is not odd, the function increases k by one.
The plaintext is then padded with k 2 − n X’s.
The function ptext2spiralMat takes the padded plaintext and places its
letters in a matrix in spiral form. The method used here is similar to that of
the program GrowingSpiral of Section 7.8. It uses offsets 0, ±1 to move from
one leg of the spiral to the next, the legs increasing in length, causing the
spiral to grow.
Decryption
The decryption process is similar to encryption. It starts with the ciphertext,
creates a matrix by splitting the text into rows, and then unwinds the matrix,
viewed as a spiral.
Sub Decrypt()
Dim spiralMat() As String, ctext As String
ctext = Range("B5").Value 'read the ciphertext
msgLen = Len(ctext)
nRows = msgLen ^ (1 / 2)
center = Int(nRows / 2)
spiralMat = ctext2Spiral(ctext) 'create matrix by row concatenation
Range("B6").Value = Spiral2ptext(spiralMat)
End Sub
The procedure Spiral2ptext unwinds the spiral matrix to form the original
plaintext. It is entirely similar to ptext2spiralMat except that instead of writing
a character into the matrix the procedure reads it.
dupcount = 1: k = 1
row = center: col = center
ptext = spiralMat(row, col)
Do While k <= msgLen
'go left for dupcount steps
Call GetLeg(spiralMat, ptext, 0, -1, k, dupcount)
'go up for dupcount steps
Call GetLeg(spiralMat, ptext, -1, 0, k, dupcount)
dupcount = dupcount + 1 'increase leg length by one
'go right for dupcount steps
Call GetLeg(spiralMat, ptext, 0, 1, k, dupcount)
'go down for dupcount steps
Call GetLeg(spiralMat, ptext, 1, 0, k, dupcount)
dupcount = dupcount + 1
Loop
Spiral2ptext = ptext
End Function
Since the right side is known one can find p and therefore recover the message.
474 Discrete Mathematics and Coding
Sub CommandButton2_Click()
Dim ciphertext As String, a As Long, b As Long
a = Range("B3").Value
b = Range("B4").Value
ciphertext = Range("B6").Value
Range("B7").Value = AffDecrypt(ciphertext, a, b)
End Sub
which we abbreviate by the bottom row 3,5,4,2,1 (see Section 19.9). Divide the
compressed and capitalized message ABLEWASIEREISAWELBA into message
units of five letters each:
where we have filled out the last block with the letter X. The sender applies
the permutation 3,5,4,2,1 to each block: letter 3 is written first, then letter 5,
etc. This produces the blocks
The receiver breaks up the enciphered message into blocks and applies the
permutation to each, obtaining the message units (25.1). Concatenating these
and dropping the X produces the original compressed message.
The function PadX takes plaintext and blocksize as arguments and returns
the padded message. It first determines the number of X’s to add to the
incomplete block, if any, by finding the remainder r when the message length is
divided by the block size. As r is the size of the last block, the number of X’s to
be added is the block size minus the remainder. The procedure uses the VBA
function String to make the required string of X’s. For example, PadX takes the
string ABLEWASIEREISAWELBA and returns ABLEWASIEREISAWELBAX. In
this example, the message length is 19, the block size is 5, and the remainder
is 4, so exactly one X must be added.
Function PadX(plaintext As String, blocksize As Integer) As String
Dim i As Integer, Xstr As String
r = Len(plaintext) Mod blocksize 'size of incomplete block
If r <> 0 Then
Xstr = String(blocksize - r, "X") 'X's
End If
PadX = plaintext & Xstr 'return padded message
End Function
A B
3 permutation 3,5,4,2,1
5 encrypt ABLEWASIEREISAWELBA
6 decrypt LWEBAIRESASWAIEBXALE
7 ABLEWASIEREISAWELBA
For an example, suppose the message is MOVEINATDAWN and the text key
is FIDDLESTICKS. The first letter F in the key directs the sender to row F
of the table. The first letter M of the message is then encrypted by the letter
appearing in row F and column M, namely the letter R. These are underlined
in the table for the purposes of illustration. Similarly, the second letter O of
the message is encrypted by the letter appearing in row I, the second letter of
the key, and column O, the second letter of the message, namely W. If one
views the table as a String array VIG(0 to 25,0 to 25), then one can write
the relationships in code as
Cryptography 479
R = VIG(Alph2Val(F),Alph2Val(M)), W = VIG(Alph2Val(I),Alph2Val(O)).
and the letter itself is Chr(Alph2Val(Cletter)) (see Figure 25.7). The formula
is the basis of both the encryption and decryption process.
T,19
I,8 B,1
The function VEncrypt is passed the plaintext and keyword and returns
the ciphertext. A For Next loop uses the string function Mid to retrieve the
message and keyword characters. These are converted to their alpha values
m and k, respectively. If the word is shorter than the message, then the
keyword characters are recycled. For example, suppose that the message is
MOVEINATDAWN and the keyword is FIDDLE. When the index i equals 7, the
seventh letter of the message is retrieved. Since FIDDLE has only six letters, its
first letter F is reused. This is done by the formula ((i-1) Mod LenK) + 1, where
480 Discrete Mathematics and Coding
LenK= 6, the length of the keyword. As i runs from 1 to LenM = 12, the message
length, the formula takes on the values 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6.
Function VEncrypt(plaintext As String, keyword As String) As String
Dim i As Integer, LenM As Integer, LenK As Integer, ctext As String
Dim m As Integer, k As Integer, Mletter As String, Kletter As String
LenM = Len(plaintext) 'length of message
LenK = Len(keyword) 'length of keyword
For i = 1 To LenM
Mletter = Mid(plaintext, i, 1) 'extract plaintext letter
Kletter = Mid(keyword, (i - 1) Mod LenK + 1, 1) 'key letter
m = Alph2Val(Mletter): k = Alph2Val(Kletter) 'alpha values
ctext = ctext & Chr(65 + (m + k) Mod 26) 'append to ciphertext
Next i
VEncrypt = ctext 'return ciphertext
End Function1
The function Lookup is passed the alpha numbers of the current ciphertext
letter and keyword letter and returns the alpha number of the corresponding
message letter found in the top row of the table.
Function Lookup(c As Integer, k As Integer) As Integer
Dim m As Integer
For m = 0 To 25 'run through the header row of table to find
If (m + k) Mod 26 = c Then Exit For 'the cipher letter in table
Next m
Lookup = m 'got the message letter
End Function
Cryptography 481
Sub CommandButton2_Click()
Dim keyword As String, ciphertext As String
keyword = Range("B2").Value ciphertext = Range("B6").Value
Range("B7").Value = VDecrypt(ciphertext, keyword) 'print message
End Sub
The sender enters the keyword and message into cells B2 and B4, respectively,
and then presses the command button encrypt . The encrypted message
appears in cell B6 and is sent to the receiver. The recipient, who has the
identical program, enters the keyword and encrypted message into cells B2 and
B6, respectively, and presses the command button decrypt . The decrypted
message then appears in B7. The figure depicts the spreadsheet after both
buttons were pressed.
A B
2 keyword FIDDLE
3
4 encrypt MOVEINATDAWN
5
6 decrypt RWYHTRFBGDHR
7 MOVEINATDAWN
message and the key words should not contain a Q. (Alternately, one could
merge the infrequent letter J with I.)
A B C D E H O W C A
F G H I K L M Y D E
L M N O P S T I V B
Q R S T U R N K G F
V W X Y Z J P U X Z
W I T H O A B C D E
U A C R Y F G H I K
P E N B L L M N O P
F D S G J Q R S T U
K M V X Z V W X Y Z
GO DE
The figure, which actually depicts part of the spreadsheet for the VBA
implementation of the cipher, illustrates the case for the keywords
HOWCALMYDESTIVBRNKGFJPUXZ
in Table 2 and
WITHOUACRYPENBLFDSGJKMVXZ
in Table 3. The tables were derived, respectively, from the following lines from
the first verse of a poem by Tennessee Williams in his play The Night of the
Iguana.
“How calmly does the olive branch observe the sky begin to blanch”
and
A B
2 encrypt GONOWANDTAKETHEFILESWITHYOU
4 table 2 key HOWCALMLYDOESTHEOLIVEBRANCHOBSERVE. . .
6 table 3 key WITHOUTACRYWITHOUTAPRAYERWITHNO. . .
8 decrypt EEBBXDETJHFIANVCTR
10 GONOWANDTAKETHEFILESWITHYOU
the tables in Figure 25.9 with spreadsheet the letter A of table 1 appearing
in cell C10. The encryption is generated from the tables. This is sent to the
receiver, who enters the keywords in cells B4 and B5 and encrypted message
in cell B8. Pressing decrypt generates the tables and the decryption, which is
placed in cell B10. For the sake of illustration the program assumes the part
of both the receiver and the sender.
The module contains a number of Public variables. The first group gives
the positions of the row and column of upper left entries of tables 1–4. For
example, the letter A in table 1 has row-column position Top1,Left1.
The second group are string variables that hold the keys:
The third group are string variables that hold the plaintext and ciphertext:
There is also a Public integer variable rate which determines how fast letter
pairs are deciphered. A high value slows down the procedure for illustrative
purposes.
Encryption
Here is the procedure that is activated by the encrypt command button.
After the grid for the tables is created, the procedure sets the positions and
reads the message and keywords. The procedure then calls ModifyKey to reduce
the keys as explained earlier. The alphabet tables 1 and 4 and key tables 2
and 3 are then created and the ciphertext derived from them.
484 Discrete Mathematics and Coding
Sub Encrypt()
Dim Grid As TGrid
Grid = MakeGrid(4, 4, 30, 30, 3, 13, -1)
Top1 = 10: Left1 = 3 'set the positions of the upper
Top2 = Top1: Left2 = Left1 + 6 'left corners of the tables
Top3 = Top1 + 6: Left3 = Left1
Top4 = Top3: Left4 = Left3 + 6
ptext = Range("B2").Value 'read the message
rate = Range("B11").Value 'rate letter pairs are deciphered
Table2Key = Range("B4").Value 'get user-entered table keys
Table3Key = Range("B6").Value
Call ModifyKey(Table2Key) 'removing duplicates and attach
Call ModifyKey(Table3Key) 'letters from rest of the alphabet
Call MakeAlphabetTables 'make tables 1 and 4 from alphabet
Call MakeKeyTables 'make tables 2 and 3 from keys
Call MakeCtext 'use tables to make ciphertext
End Sub
The procedure ModifyKey takes a keyword, removes Q’s if any, and then
runs through the alphabet to see if a letter is in the key. If not it attaches
the letter to the key. The process continues until the reduced key reaches 25
letters.
Sub MakeAlphabetTables()
Dim i As Integer, j As Integer, k As Integer
k = 65 'start with ASCII A
For i = 0 To 4 'populate spreadsheet with alphabet
For j = 0 To 4 'letters at table 1,4 positions
Cryptography 485
If k = Asc("Q") Then k = k + 1
Cells(i + Top1, j + Left1) = Chr(k)
Cells(i + Top4, j + Left4) = Chr(k)
k = k + 1
Next j
Next i
End Sub
Sub MakeKeyTables()
Dim i As Integer, j As Integer, k As Integer
k = 1
For i = 0 To 4 'populate spreadsheet with letters from
For j = 0 To 4 'Table2Key in table 2 positions
Cells(i + Top2, j + Left2) = Mid(Table2Key, k, 1)
k = k + 1
Next j
Next i
k = 1
For i = 0 To 4 'populate spreadsheet with letters from
For j = 0 To 4 'Table3Key in table 2 positions
Cells(i + Top3, j + Left3) = Mid(Table3Key, k, 1)
k = k + 1
Next j
Next i
End Sub
The procedure MakeCtext locates the current pair of ptext letters located in
tables 1,4, finds their row column positions with the function LetterToPosition,
the positions being the endpoints of the diagonal of a rectangle as described
earlier, and then computes the positions of the ctext pair located at the ends of
the opposite diagonal. These are concatenated to form the ctext. The procedure
uses the green-red scheme illustrated in Figure 25.9 so the user can watch how
the ctext is created
Sub MakeCtext()
Dim pPos1 As TPos, pPos4 As TPos 'letter positions in tables 1,4
Dim cPos2 As TPos, cPos3 As TPos 'letter positions in tables 2,3
Dim pLetter1 As String, pLetter4 As String 'letter pair in tables 1,4
Dim cLetter2 As String, cLetter3 As String 'letter pair in tables 2,3
Dim i As Integer
Range("B8").Value = "" 'remove old ctext
If Len(ptext) Mod 2 <> 0 Then
ptext = ptext & "X" 'append if odd length
End If
For i = 1 To Len(ptext) - 1 Step 2 'run through ptext pairs
pLetter1 = Mid(ptext, i, 1) 'extract a pair of letters
pLetter4 = Mid(ptext, i + 1, 1)
pPos1 = LetterToPosition(pLetter1, Top1, Left1) 'find positions
pPos4 = LetterToPosition(pLetter4, Top4, Left4) 'in tables 1, 4
Cells(pPos1.row, pPos1.col).Interior.ColorIndex=4'green cells for
Cells(pPos4.row, pPos4.col).Interior.ColorIndex=4 'ptext pair
486 Discrete Mathematics and Coding
Decryption
The process of decryption is entirely similar to that of encryption. The
second command button on the spreadsheet invokes the procedure Decrypt.
Which is the same as Encrypt except that the last line of code MakeCtext is
replaced by the code MakePtext. The latter procedure differs from the former
in that the roles of Tables 1,4 and Tables 2,3 are switched in calculating letter
pair locations. The code for the decryption process is omitted.
padding. The blocks are written as column vectors of alpha numbers. These
are multiplied by a matrix (the key) whose inverse has integer entries.1 The
resulting column vectors are sent to the receiver in letter form. The receiver
knows the matrix key and so can retrieve the message by multiplying by the
inverse of the matrix. We give the details in the following subsections and
implement the process with VBA.
the last one padded with X’s to fill out the block. The blocks are converted
into columns of alpha numbers and assembled into a 5 × 6 matrix:
17 25 18 8 12 2
4 21 0 12 4 4
BlockMat =
13 14 12 4 15 23.
(25.3)
3 20 4 18 11 23
4 18 19 0 0 23
The matrix BlockMat is now multiplied on the left by KeyMat producing the
matrix
72 215 73 118 91 156
334 849 331 440 385 576
KeyMat · BlockMat =
470 1277 476 670 542 825
.
313 927 310 504 384 634
148 451 146 248 186 316
The entries are then reduced modulo 26 and converted to letters:
20 7 21 14 13 0 U H V O N A
22 17 19 24 21 4 W R T Y V E
→ C D Z U
2 3 25 20 22 19 W T (25.4)
1 17 24 10 20 10 B R Y K U K
18 9 16 14 4 4 S J Q O E E
1 One way to obtain such a matrix is to start with the identity matrix and apply random
row operations.
488 Discrete Mathematics and Coding
The procedure MakeText is passed the matrices KeyMat and BlockMat in that
order and returns the ciphertext.
A B
3 encrypt RENDEZVOUSSAMETIMESAMEPLACE
4
5 decrypt UWCBSHRDRJVTZYQOYUKONVWUEAETKE
6 RENDEZVOUSSAMETIMESAMEPLACE
The program GCD in Section 23.4 may be used for this. Note that the conditions
imply that
gcd e, (p − 1)(q − 1) = 1
Indeed, by Bézout’s equation, 1 = ue + v(p − 1), and 1 = we + x(q − 1) for
some integers u, v, w, x; multiplying the two equations yields an equation of
the form 1 = ye + z(p − 1)(q − 1), from which the assertion follows.
The pair (n, e) is the RSA public key for that person; it is available to
everyone in the group. The person also has a private key d that satisfies the
equation
ed ≡ 1 (mod (p − 1)(q − 1)) . (25.5)
This key is known to no one else. Its value may be found with the following
“brute force” function, which takes the primes p and q and the value e, and
returns d. (We use the type Double to accommodate larger numbers.)
Aaron now converts his message into a string of double digit alpha values
MEETMETONIGHT → 12 04 04 19 12 04 19 14 13 08 06 07 19 (25.6)
The digit string in (25.6) is too long to work with mathematically, so Aaron
divides it into blocks. For the algorithm to work properly, each block must
have the property that the integer it represents is less than n, the product of
primes Betty has selected. This will be the case if the block size is one less
than the number of digits in n. Applying this rule (assumed to be universally
followed) Aaron chooses the block size to be 6 − 1 = 5 and groups the digits in
(25.6) accordingly:
12040 41912 04191 41308 06071 9. (25.7)
As the last block is incomplete, Aaron appends the digits 2323 (two X’s) to
the digital message to obtain the full blocks
12040 41912 04191 41308 06071 92323. (25.8)
Notice that the number of digits in the last block of (25.7), namely 1, is the
remainder when the total number of digits in the string is divided by the
number of complete blocks. The function MakeBlocks carries out this operation
and returns the padded string as in (25.8) (with a single separating space
between blocks).
Function MakeBlocks(digitstr As String, n As Double) As String
Dim blksize As Integer, padsize As Integer, outblks As String
Dim numblks As Integer, numdigits As Integer, i As Integer
blksize = Len(CStr(n)) - 1 'apply universal rule
numdigits = Len(digitstr)
numblks = numdigits \ blksize 'number of full blocks
padsize = blksize - numdigits Mod numblks 'how much to pad
If padsize <> 0 Then 'pad with X's if needed
For i = 1 To padsize
digitstr = digitstr & "23"
Next i
numblks = numblks + 1 'update number of full blocks
End If
digitstr = Mid(digitstr, 1, numblks * blksize) 'chop any excess
For i = 0 To numblks - 1 'break padded digit into blocks
outblks = outblks & " " & Mid(digitstr, i*blksize+1, blksize)
Next i
MakeBlocks = Mid(outblks, 2, Len(outblks) - 1) 'remove last space
End Function
Cryptography 493
Each block of the padded digit string is now converted into an integer P
and raised to the power e using the formula
Notice that converting a block with leading zeros, say 000001 (AAB), into
P removes the leading zeros. These must be restored during the decryption
process. The numbers C are then converted into blocks. The following function
does this. It takes as arguments the modulus n, an exponent x (= e in this
subsection), and the string of blocks, as in (25.8). The function first splits
the input string into an array Blocks and then runs a For Next loop, which
employs PowerRmdr of Section 24.5 to raise each block to the power x modulo
n.
Function BlockPowers(blks As String, x As Double, n As Double) As String
Dim i As Integer, blksize As Integer, outblks As String
Dim Blocks() As String, power As Double
blksize = Len(CStr(n)) - 1 'general rule for blockize
Blocks = Split(blks, " ") 'put input blocks into an array
For i = 0 To UBound(Blocks) 'generate string of blocks^x
power = PowerRmdr(CDbl(Blocks(i)), x, n) 'raise block to x
outblks = outblks & " " & CStr(power) 'build string of powers
Next i
BlockPowers = Mid(outblks,2,Len(outblks) - 1) 'remove last space
End Function
Decryption
The decryption process relies on the formulas
P ≡ C d (mod n) . (25.11)
Betty uses the function BlockPowers to make the conversion producing (25.8),
but without the leading zeros lost during encryption. Betty then uses the
following function to add back the missing leading zeros and condense the
string.
Finally, Betty must take the string of digits (no spaces) returned by
InsertZeros and convert the alpha number pairs to letters, yielding the original
message. The following function does the work.
Sub CommandButton1_Click()
Dim ptext As String, n As Double, e As Double
Dim digits As String, digitblks As String
n = Range("B4").Value: e = Range("B5").Value 'receiver's key
ptext = Range("B6").Value 'plaintext entered by sender
digits = TextToDigits(ptext) 'convert to alpha numbers
digitblks = MakeBlocks(digits, n)
Range("B12").Value = BlockPowers(digitblks, e, n) 'encryption
End Sub
Sub CommandButton2_Click()
Dim cdigits As String, pdigits As String, n As Double
Dim e As Double, d As Double, p As Double, q As Double
n = Range("B4").Value: e = Range("B5").Value
p = Range("B10").Value: q = Range("B11").Value
d = GetPrivateKey(p, q, e)
cdigits = Range("B12").Value 'ciphertext entered by receiver
pdigits = BlockPowers(cdigits, d, n)
Cryptography 495
pdigits = InsertZeros(pdigits, n)
Range("B13").Value = DigitsToText(pdigits) 'plaintext output
End Sub
Figure 25.12 shows the spreadsheet after Aaron enters Betty’s key n, e and his
message and depresses encrypt ; and Betty enters her primes p, q and Aaron’s
message and depresses decrypt .
A B
3 receiver’s key
4 n= 589597
5 e= 7
6 encrypt MEETMEATMIDNIGHT
8 encryption 540639 280186 286584 433967 326148 42852
9 receiver’s primes
10 p= 727
11 q= 811
12 decrypt 540639 280186 286584 433967 326148 42852
13 decryption MEETMEATMIDNIGHTXX
25.11 Exercises
1. Encode by hand the message “Remove the troops now” using
(a) the permutation cipher with the permutation 4,2,5,1,3
(b) the Vigener cipher with keyword BANANASTAND
5 −1 2
(c) the Hill cipher with matrix 12 −3 4.
4 −1 1
Check your answers with the programs.
2. Implement the ZigZag cipher in VBA.
Each letter is assigned its row an column so that, for example, the
plaintext RETREAT becomes 42 15 44 42 15 11 44. To decipher a
message simply find the letter in the specified row and column. Write a
VBA implementation PBSquareCipher.
4. (Columnar transposition cipher). In this cipher a key word or phrase
is used to permute the columns of a message. For example, consider
the message “Execute plan B of the evacuation” with the key word
RANDOM. Break up the message into stacked blocks of length 6 (the
number of letters in the key), to form the ptext matrix
E X E C U T
E P L A N B
O F T H E E
V A C U A T
I O N X X X
(The matrix has been suitably padded with X’s.) The idea is to rearrange
the columns as follows: Number the letters of the key RANDOM by
123456. Then rearrange the letters alphabetically to get ADMNOR and
the corresponding permutation 246351. The latter gives the column
rearrangement: column 2 is chosen first, then column 4, then column 6,
etc., yielding the ctext matrix
X C T E U E
P A B L N E
F H E T E O
A U T C A V
O X X N X I
Use this to rearrange the ptext matrix into the ctext matrix.
Cryptography 497
(a) If the pair is in the same row, replace each by the letter to
the immediate right, going back to the beginning of the row if
necessary.
(b) If the pair is in the same column, replace each letter by the letter
immediately below, going back to the beginning of the column if
necessary.
(c) Neither (a) nor (b) holds. Then the letters are in positions that
form the diagonal of a rectangle. The pair is then replaced by the
pair at the ends of the other diagonal, preserving the up-down
direction. This simply means that the columns of the letters are
switched.
In the decryption process the rules are applied in reverse. Figure 25.13
illustrates the rules for the first eight letters of the message STORMY-
TOMORROW. Write a program PFCipher that encrypts and decrypts
A B C D E A B C D E A B C D E A B C D E
F G H I K F G H I K F G H I K F G H I K
L M N O P L M N O P L M N O P L M N O P
Q R S T U Q R S T U Q R S T U Q R S T U
V W X Y Z V W X Y Z V W X Y Z V W X Y Z
ST → TU OR → MT MY → OW TO → YT
26.1 Description
The machine has three rotating disks called rotors, each labelled with the
26 letters of the alphabet. Each side of a rotor has 26 electrical contacts. The
contacts are wired internally so that current can pass from one side of the
rotor to the other, effectively converting one letter to another and therefore
acting as a permutation of the alphabet. There is also a reflector disk that
entry
reflector rotor 3 rotor 2 rotor 1 wheel
A
B
C
D
E
F
A B C D E F
A B C D E F
sends the current back through the rotors along a different route. Letters to
be encrypted or decrypted are typed into the machine with a keyboard. An
entry wheel connects a keyboard to the rotors. When a key is pressed, current
is sent to the entry wheel and passes through the rotors from right to left.
The reflector causes the current to flow back through the rotors left to right,
eventually lighting a letter above the keyboard.1 For example, by following
the wiring in Figure 26.1 one sees that the depressed letter C on the keyboard
undergoes several disk permutations and is ultimately transformed into the
lighted letter A. The contacts are indicated by the black dots and the internal
wiring by black lines.2
The complicating factor in all of this is that, after a key press, rotor 1 moves
one position. After 26 key presses, rotor 1 returns to its initial position and
rotor 2 moves one position, etc. Figure 26.2 shows the state of the machine
after the initial key press C. 3 Pressing C again results in E being lighted. Thus
the text CC encrypts to AE.
A
B
C
D
E
F
A B C D E F
A B C D E F
The rim of each rotor of the Enigma machine is labelled with the capital
letters of the alphabet, enabling the operator to view the position of the rotors
through small windows (indicated by yellow in Figure 26.3). The setting may
be changed by the operator. The same setting used to encrypt must be used
to decrypt.
In Figure 26.4 we have labeled each side of the rotors with the letters to
show how one letter is transformed into another. From this we see that each
rotor acts as a pair of permutations, one going from right to left and the other,
its inverse, going from left to right. We denote the permutations for the rotors
going right to left by R1 , R2 , and R3 , the permutation for the reflector by R4 ,
1 The reflector allows the operator to encrypt and decrypt using the same procedure,
thus eliminating the need for an additional mechanism to switch modes. For example, in
Figure 26.1 not only does pressing C on the keyboard light A, but also pressing A lights C.
2 For the purposes of illustration, we have used an abbreviated alphabet. In the module
rotor 1. Thus the red dots are connected to each other as are the blue dots.
The Enigma Machine 501
A A A D C B
B B B E D C
C C C F E D
D D D A F E
E E E B A F
F F F C B A
and the permutations for the rotors going left to right by R5 , R6 , and R7 , the
inverses of the permutations R3 , R2 , R1 , respectively. Thus if the machine is in
state AAA, as is the case in Figure 26.4, then its internal operation is described
mathematically by the permutation product R7 R6 R5 R4 R3 R2 R1 . We return
to this idea later.
A B C D E F G
2 Wire disks
3 R1 R2 R3 R4 R5 R6 R7
4 B E C C C F B
5 A C D E E D A
6 F D A A A B E
7 E B F F B C F
8 C F B B F A D
9 D A E D D E C
InvPerm of Section 19.9 is then used to generate the rotor permutations in the
left to right direction. The function TwoCycles is used to wire the rotor. The
functions work on the integers 1–26, which represent the alphabet—a deviation
from the alpha number system used in the previous chapter.
Sub WireDisks()
Dim R1() As Integer, R2() As Integer, R3() As Integer
Dim R4() As Integer, R5() As Integer, R6() As Integer
Dim R7() As Integer, i As Integer,
R1 = RndPerm(26): R2 = RndPerm(26): R3 = RndPerm(26) 'right to left
R4 = TwoCycles() 'reflector
R5 = InvPerm(R3): R6 = InvPerm(R2): R7 = InvPerm(R1) 'left to right
For i =1 To 26 'print the permutations as letters
Sheet2.Cells(i + 3, 1).Value = Chr(R1(i) + 64)
Sheet2.Cells(i + 3, 2).Value = Chr(R2(i) + 64)
Sheet2.Cells(i + 3, 3).Value = Chr(R3(i) + 64)
Sheet2.Cells(i + 3, 4).Value = Chr(R4(i) + 64)
Sheet2.Cells(i + 3, 5).Value = Chr(R5(i) + 64)
Sheet2.Cells(i + 3, 6).Value = Chr(R6(i) + 64)
Sheet2.Cells(i + 3, 7).Value = Chr(R7(i) + 64)
Next i
End Sub
The function TwoCycles wires together pairs of contacts for the reflector.
It does so by first generating a permutation perm of the numbers 1–26 and
then associating adjacent numbers to produce a new permutation outperm. For
example if in our abbreviated alphabet
1 2 3 4 5 6
perm = = 5, 3, 6, 1, 4, 2,
5 3 6 1 4 2
then we wire 5 to 3, 6 to 1, and 4 to 2 to produce the permutation
1 2 3 4 5 6
outperm =
6 4 5 2 3 1
The Enigma Machine 503
The remaining activity of the module takes place in Sheet1. There are
two ways to process text: letters may be entered one at a time using a
simulated keyboard, the input and output letters appearing in cells B3 and B4,
respectively, or to speed things up the text may be entered all at once in cell
B3 and processed with the command button In . In either case, the user may
observe the (simulated) path of the current through the wheels. Figure 26.6
depicts the spreadsheet with the original full German keyboard but with only
A–F active because of space limitations. The code in CommandButton1_Click,
A B D E G H J K M N
3 In C ref rotor 3 rotor 2 rotor 1 ent
4 Out A B B C C E E A
5 B C C D D F F B
6 Set at BCE C D D E E A A C
7 D E E F F B B D
8 current BCE E F F A A C C E
9 speed 20 F A A B B D D F
Q W E R T Z U I O
A S D F G H J K
P Y X C V B N M L
The function Convert runs a letter through the rotors right to left, then
through the reflector, and finally back through the rotors left to right, producing
an encrypted or decrypted letter. It uses the function Disk, which takes the
row of an input letter in the column representing the disk and returns the row
of the output letter. The column numbers are stored in the array DiskCol. The
columns are indicated by the narrow double lines in Figure 26.6. There are
nine entries since the current travels through the entry and exit disk (which
are same), the reflector, and the three rotors right to left and left to right. The
function also colors the path through the disks so that the user may follow the
current through the wiring. (See Figure 26.7.)
Function Convert(InLetter As String) As String
Dim rate As Integer, DiskCol(0 To 8) As Integer
Dim InRow As Integer, OutRow As Integer
DiskCol(0) = 14: DiskCol(1) = 12: DiskCol(2) = 9 'column numbers
DiskCol(3) = 6: DiskCol(4) = 3: DiskCol(5) = 6 'of the disks
DiskCol(6) = 9: DiskCol(7) = 12: DiskCol(8) = 14
Range(Cells(4, 3), Cells(29, 14)).Interior.ColorIndex = 0 'old path
InRow = 4 + Alph2Val(InLetter) 'entry row of InLetter
For i = 0 To 8
OutRow = Disk(InRow, DiskCol(i), i): InRow = OutRow
Next i
Call MoveRotors(DiskCol) 'shift rotor column letters up by one
Convert = Cells(OutRow, DiskCol(0)).Value 'return converted letter
End Function
The function Disk takes as arguments the row number InRow of the input
letter to the disk, the column number of the disk, and the disk number. It
outputs the row OutRow of the output letter of the disk. The output letter is
found in Sheet2, which contains the permutations representing the disk wiring.
The row of the output letter of the disk in Sheet1 is found by LookUpRow, which
scans a disk column for the specified output letter and returns its row.
Function Disk(InRow As Integer, dcol As Integer, dnum As Integer) _
As Integer
Dim OutRow As Integer, OutCol As Integer, InCol As Integer
Dim InLetter As String, OutLetter As String, color As Integer
If dnum = 0 Or dnum = 8 Then 'if entry or exit, color red or green
Cells(InRow, dcol).Interior.ColorIndex = 4 - dnum / 8
Disk = InRow 'output row same as input row
Exit Function
End If
If 1 <= dnum And dnum <= 3 Then 'rotors right to left
InCol = dcol + 1: OutCol = dcol - 1: color = 4
ElseIf dnum = 4 Then 'reflector
The Enigma Machine 505
The procedure MoveRotors shifts rotor 1 letters up after each input letter is
processed. If rotor 1 returns to its original setting, then the letters of rotor 2
are shifted up. If rotor 2 returns to its original setting, letters of rotor 3 are
shifted up.
The procedure DisplayPositions simply lets the user know the top three
letters in the rotor columns (which, can also be read directly from the columns).
The procedure MakePath connects the letter at InRow of a disk to the letter
at OutRow with a colored path. A delay is added to slow down the “current”
for visual purposes.
ref rotor 3 rotor 2 rotor 1 ent ref rotor 3 rotor 2 rotor 1 ent
A B B C C E E A A B B C C E E A
B C C D D F F B B C C D D F F B
C D D E E A A C C D D E E A A C
D E E F F B B D D E E F F B B D
E F F A A C C E E F F A A C C E
F A A B B D D F F A A B B D D F
FIGURE 26.7: Green: right to left; violet: reflector; red: left to right.
Sub CommandButton2_Click()
Dim DiskCol(0 To 4) As Integer, i As Integer, setting As String
Dim R1 As Integer, R2 As Integer, R3 As Integer
DiskCol(0) = 14: DiskCol(1) = 12: DiskCol(2) = 9
DiskCol(3) = 6: DiskCol(4) = 3
setting = Range("B6").Value
R3 = Alph2Val(Mid(setting, 1, 1))
R2 = Alph2Val(Mid(setting, 2, 1))
R1 = Alph2Val(Mid(setting, 3, 1))
For i = 0 To 25
Cells(4 + i, DiskCol(3) + 1).Value = Chr((i + R3) Mod 26 + 65)
Cells(4 + i, DiskCol(3) - 1).Value = Chr((i + R3) Mod 26 + 65)
Cells(4 + i, DiskCol(2) + 1).Value = Chr((i + R2) Mod 26 + 65)
Cells(4 + i, DiskCol(2) - 1).Value = Chr((i + R2) Mod 26 + 65)
Cells(4 + i, DiskCol(1) + 1).Value = Chr((i + R1) Mod 26 + 65)
Cells(4 + i, DiskCol(1) - 1).Value = Chr((i + R1) Mod 26 + 65)
Next i
Call DisplayPositions(DiskCol)
End Sub
Note that in state AAA the bottom row of R1 is the input to the second
rotor, etc. Moreover, the machine in this state is described by the permutation
product R7 R6 R5 R4 R3 R2 R1 . To incorporate shifting of the rotors into the
mathematical model we use the left and right shift permutations defined,
respectively, by
A B C D E F A B C D E F
σ= , σ −1 =
B CD E F A F A B C DE
Now suppose key D is pressed in state AAA. Current from letter D enters
rotor 1 at contact D, travels to contact E, and enters rotor 2 at contact E.
The machine is now in state AAB, rotor 1 having shifted up as in Figure 26.8.
508 Discrete Mathematics and Coding
Pressing key D again now causes current from letter D to enter rotor 1 at
contact E = σ(D), travel to contact C in rotor 1, and enter rotor 2 at contact
B = σ −1 (C). The net effect is given by the permutation product σ −1 R1 σ.
4 We have actually incorporated this idea into the Enigma code available on the author’s
blog.
Chapter 27
Large Numbers
Arithmetic in VBA Excel is naturally limited by the size of Long and Double
data types. However, by using strings instead of numbers, one can perform
arithmetic on numbers of virtually any size. In this chapter we develop pro-
cedures that add, subtract, multiply, and divide integers and decimals whose
size is limited only by the constraints of the spreadsheet. The results of the
chapter suggest several interesting applications to cryptography. The reader is
encouraged to devise and implement some of these.
Formatting
Since addition and subtraction of two numbers are performed digit by digit,
it is convenient that the numbers be of equal length. The first procedure below
takes a pair of digit strings and attaches leading zeros to whichever number
is shorter. The second procedure removes leading zeros that may have been
attached during an operation.
1 1
1022 1012 101 9
899 899 89 8
3 23 123
The function Borrow(num) subtracts 1 from num. It uses the VBA function
String to attach 9’s if needed, so, for example, Borrow(123500) = 123499. Since
num could be large, ordinary subtraction may not work here.
n = CInt(Mid(num, i, 1))
If n <> 0 Then Exit For 'found a nonzero digit n (= 1st digit<>0
Next i 'from the right; at position i from left) (n = 5)
If n > 0 Then
num = Mid(num, 1, i - 1) '123500 becomes 1235 (L = 6, i = 4)
num = num & n - 1 '1235 becomes 1234
num = num & String(L - i, "9") '1234 becomes 123499
End If
lastline:
Borrow = num
End Function
2 1 1
1234 1234 1234 1234 1234
5 5 5 5 5
0 70 170 6170
371 quotient
divisor 123 45678 dividend
369
877
861
168
123
45 remainder
namely 3. A For Next loop then multiplies 123 by digits i = 0 to 9 until the
product exceeds 456, at which point i = 4. The values of the product and of i
are then reduced to the preceding values 369 and 3, respectively. The digit 3
is appended to the quotient and the product 369 is subtracted from 456 to
obtain a remainder of 87. The variable j is then incremented to 4 and the next
digit in the dividend, 7, is appended to the remainder to obtain the new value
str = 877. The process is repeated one more time (j = 5).
Multiplication of Integers
The product of signed integers is calculated by considering the signs of the
numbers and applying MultPosInt.
Decimal Points
The following procedures facilitate the transition from signed integer arith-
metic to decimal arithmetic. The first, SplitDec(a,s,w,f), takes a decimal
string a and splits it into three strings: the sign s (either "-" or ""), the whole
part w, and the fractional part f. For example, SplitDec("-123.45",s,w,f)
returns "-", "123", and "45" in the variables s,w,f, respectively. For uniformity,
the program returns f=0 if a is a whole number.
intsum = AddInt(x, y)
AddDec = RestoreDecPt(intsum, dright)
End Function
Decimal Multiplication
The function MultDec(a,b) first splits a and b into their parts, adds trailing
zero for balance, reassembles the parts into whole numbers and applies MultInt.
Function MultDec(a As String, b As String) As String
Dim x As String, y As String, prod As String, d_right As Integer
Dim a_s As String, a_w As String, a_f As String
Dim b_s As String, b_w As String, b_f As String
Call SplitDec(a, a_s, a_w, a_f)
Call SplitDec(b, b_s, b_w, b_f)
Call AddTrailingZeros(a_f, b_f, d_right)
x = a_s & a_w & a_f: y = b_s & b_w & b_f
prod = RestoreDecPt(MultInt(x, y), 2 * d_right)
MultDec = prod
End Function
Decimal Division
The function DivDec(a,b,n) returns the quotient a/b carried out to n places.
The procedure starts out as usual by splitting a and b into its constituent
parts. Trailing zeros are added where needed and the parts reassembled to
reduce the problem to division by integers. The numerator is then effectively
multiplied by 10n and DivAlg is called. The result is then effectively divided
by 10n , which achieves the desired accuracy. For example, for n = 3 we have
1234.56 1234560 1 1234560000 1 9871q + r q r
= = 3 = 3 = 3+
9.871 9871 10 9871 10 9871 10 9871000
125069 r r
= + = 125.069 +
103 9871000 9871000
where we have applied the division algorithm to the numerator 1234560000,
yielding q = 125069 and r = 3901. From the inequality 0 ≤ r < 9871 we see
that 0 ≤ r/9871000 < .0001, hence the approximation q/103 = 125.069 agrees
with the actual value 1234.56/9.871 = 125.0693952 in three decimal places.
Function DivDec(a As String, b As String, divplaces As Integer) As String
Dim x As String, y As String, q As String, r As String
Dim a_s As String, a_w As String, a_f As String, d_right As Integer
Dim b_s As String, b_w As String, b_f As String
Call SplitDec(a, a_s, a_w, a_f) '1234, 56
520 Discrete Mathematics and Coding
The function LargeRound rounds a decimal digit string to any desired number
of places.
Function LargeRound(a As String, rndplaces As Integer) As String
Dim a_s As String, a_w As String, a_f As String
Dim b As String, c As String
If InStr(a, ".") = 0 Then 'if no decimal point then
LargeRound = a: Exit Function 'return a
End If
Call SplitDec(a, a_s, a_w, a_f) 'get decimal components
If rndplaces >= Len(a_f) Then 'if too many places then
LargeRound = a
Exit Function 'return a
End If
If rndplaces = 0 Then 'if zero places then
LargeRound = a_w
Exit Function 'return whole part of a
End If
b = a_w & "." & Mid(a_f, 1, rndplaces) 'chop fractional part of a
If CInt(Mid(a_f, rndplaces + 1, 1)) >= 5 Then 'if next place >= 5
c = "0." & String(rndplaces - 1, "0") & 1
b = AddDec(b, c) 'then round up
End If
LargeRound = b
End Function
Decimal Exponentiation
The function PowerDec(b, e) uses MultDec repeatedly to calculate be , where
e is an integer.
Function PowerDec(base As String, exp As Integer) As String
Dim i As Integer, p As String, attach_neg As Boolean
If exp = 0 Then p = 1: GoTo lastline
If exp = 1 Then p = base: GoTo lastline
If IsNeg(base) And Abs(exp) Mod 2 <> 0 Then 'is b < 0 and exp odd?
attach_neg = True 'yes: answer negative
Large Numbers 521
End If
base = AbsVal(base) 'remove sign
If exp < 0 Then
base = DivDec(1, base, n) 'replace base by 1/base
exp = -exp 'make power positive
End If
p = 1
For i = 1 To exp
p = MultDec(base, p)
Next i
lastline: If attach_neg Then p = "-" & p
PowerDec = p
End Function
27.5 Exercises
1. Write a program LargeFactorial that calculates large factorials.
2. Write a program LargeBinomial that calculates large binomial coefficients.
3. Write a program LargeSevenRule that extends SevenRule of Exercise 2 in
Chapter 23 to digit strings.
4. Write a program LargeThirteenRule that extends ThirteenRule of Exer-
cise 3 in Chapter 23 to digit strings.
5. Write a program LargeGCD that extends GCD of Section 23.4 to digit
strings.
6. Write a program LargeSieve that is the large string analog of the pro-
gram Sieve of Chapter 7.
7. Write a function LargeSymbolicAddFrac(frac1,frac2) that returns the
string obtained by adding the fractions. Each fraction should be a
string of the form num/den, where num,den are digit strings. For example,
LargeAddFrac("1/2","3/4") should return "5/4". Write similar programs
for subtraction, multiplication and division.
524 Discrete Mathematics and Coding
525
526 Index