Principles of Computing
Principles of Computing
4:02 PM
The class pages linked below cover a selected set of math topics associated with the course. For
students whose math background may be in need of supplement, we have also included links to related
material from two sections of the Khan Academy: Algebra 2 (specifically functions and their graphs,
polynomial and rational functions, exponential and logarithmic functions) and Pre-calculus (specifically
probability and combinatorics as well as series, sequences and induction).
Overall - Entering math expressions in homework
Week 1 - Functions - supplemental material at the Khan Academy
Week 2 - Grid representations
Week 3 - Basic probability - supplemental material at the Khan Academy
Week 3 - Expected value - supplemental material at the Khan Academy
Week 4 - Enumeration
Week 4 - Permutations and combinations - supplemental material at the Khan Academy
Week 5 - Arithmetic sums - supplemental material at the Khan Academy
Week 5 - Logarithms and exponentials - supplemental material at the Khan Academy
Week 5 - Growth rates of functions - supplemental material at the Khan Academy
From <https://class.coursera.org/principlescomputing1-003/wiki/video_notes>
4:03 PM
For some homework questions, you will be asked to enter a math expression (instead of a number) as
the answer to a problem. Coursera's quiz system can recognize and symbolically processes math
expressions created using a combination of standard mathematical constants and functions as well as
unknown variables. For example, you can enter the math expression (1+x)2 as the text (1 + x) ^ 2. The
power of Coursera's system is that it will automatically check whether the expression you entered is
equivalent to the answer entered by the instructor, even if the two answers are in different forms. For
example, the expression 1 + 2 * x + x ^ 2 will be recognized as equivalent to (1+x)2 while 1 + x + x ^ 2 will be
recognized as being different.
This guide outlines the basics of entering mathematical expression in the form that Coursera
expects. Remember that you can use the "Preview answer" button to check whether you have properly
formatted your answer according to Coursera's specifications. Listed below the mathematical functions
and constants that Coursera's system recognizes:
abs
Principles of Computing Page 2
abs
arg (returns phase in radians of a complex number)
ceiling
conjugate
deg (converts radians to degrees)
exp
floor
gcd (2 arguments only; otherwise you must type it as "gcd((a, b, c, d))" or "gcd([a, b, c, d])" e.g. a list/tuple)
im (get imaginary part of a number)
lcm (2 arguments only; otherwise you must type it as "gcd((a, b, c, d))" or "gcd([a, b, c, d])" e.g. a list/tuple)
ln
log (also base e, same as ln)
max
min
mod
rad (converts degrees to radians)
re (get real part of a number)
root (2-argument, where root(a, 2) is equivalent to sqrt(a))
sqrt
sign (returns -1 if negative, 0 if zero, 1 if positive)
Trigonometric functions: acos, acosh, acot, acoth, asin, asinh, atan, atan2 (2 -argument arctangent), atanh,
cos, cosh, cot, coth, sin, sinh, tan, tanh
Other functions: erf, binomial
There are also a few built-in constants, some of which are capitalized:
Functions
Sunday, June 28, 2015
4:05 PM
One of the main goals of this class is to start you along the path to understanding the behavior of the
Python code that you will write. In particular, we are interested in understanding how long your
program takes to run in terms of the size of the input provide to the program. The key mathematical
Principles of Computing Page 4
program takes to run in terms of the size of the input provide to the program. The key mathematical
concept that we will use to model the running time of a program is the function. As our first Practice
Activity, we will review some basic definitions and properties of functions that you should have learned
in high school Algebra.
Mathematical functions
A mathematical function is a mapping from a set of inputs to a set of outputs with the property that
each input corresponds to exactly one output. The standard mathematical definition of a function has
the form
f(p1,p2,...,pn)=body
where f is the name of the function, p1,p2,...,pn is a sequence of parameters for the function, and body is
an expression involving the parameters p1,p2,...,pn. Supplying values v1,v2,...,vn for the
parameters p1,p2,...,pn, we can call the function via an expression of the form f(v1,v2,...,vn). To evaluate
this expression, we substitute the values vi for the variables pi in expression body and then compute the
value of the resulting expression.
For example, consider the function that takes a number and returns the square of the number.
Mathematically, this function would have the form square(num)=num2. The function
call square(5) would substitute 5 for num and return the value 52=25.
Python functions
One nice feature of Python is that function definitions and calls have a form that is very similar to the
mathematical form described above. If we temporarily ignore our style guidelines, the square function
defined above would be expressed in Python as
def square(num):
return num ** 2
A function call in Python is almost identical to a function call in mathematical form. To compute the
square of 5 in Python, we would simply use the expression square(5). You should already be comfortable
writing simple function definitions in Python if you intend to take this class.
Polynomial functions
The most important type of functions that we will consider in the class are polynomial functions.
A polynomial is an expression consisting of variables and coefficients, that involves only the operations
of addition, subtraction, multiplication, and non-negative integer exponents. A function is a polynomial
function if the body of the function is an polynomial whose variables corresponds to the parameters of
the function. For example, the function
f(x,y)=xyxy+1
is a polynomial function in two variables x and y. A polynomial in one variable is referred to as
a univariate polynomial. A univariate polynomial in the variable xcan be written in the form
cnxn+cn1xn1+...+c0
where the coefficients c0,c1,...,cn are numbers. In this form, the integer n is the degree of the polynomial. A
function of one parameter x is a linear function in x if its body is a univariate polynomial of degree at most
one in x. Likewise, such a function is a quadratic function in x if the body of the function is a univariate
polynomial of degree at most two in x. As an example, note that function square defined above is a
quadratic function in num. Similar terminology involving cubic, quartic, quintic, etc. applies is the degree of
the degree of polynomial corresponding to the body of the function is 3,4,5..., respectively.
f(x)=x21+x
is a rational function in x since its body is the ratio of the polynomials x2 and 1+x. Another common class of
functions is the exponential functions of the form f(x)=cx where c is a number. A related class of function is
the logarithmic functions. The logarithm of a number is the exponent to which another fixed value, the base,
must be raised to produce that number. Logarithmic functions are typically written in the
form g(y)=logc(y) where c is the base of the logarithm. For example, log2(32) is 5 since 25=32.
If the notion of the logarithm is new to you, a simple method for understanding the behavior of
the log function is to note that it is the inverse of a corresponding exponential function. Two
functions f and g are inverses if they satisfy the equation g(f(x))=x. For exponentials and logarithms, these
functions satisfy logc(cx)=x. We will discuss exponentials and logarithms more later in the class.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=functions>
Grid Representations
Sunday, June 28, 2015
4:06 PM
Mathematically, a grid is a partition of a 2D region into a disjoint collection of cells. Typically, these cells
are all a single simple shape such as a square, triangle or hexagon. Several mini-projects, including 2048,
Zombie Apocalypse, and the Fifteen puzzle, involve rectangular grids of squares. Grids are useful in
many computational applications because they provide a convenient way to partition a geometric
region in a way that can be easily modeled as a 2D data structure.
Indexing rectangular grids
For now, we focus on rectangular grids that are composed entirely of squares. Mathematically, such a grid
has a height grid_height and a width grid_width, measured in terms of individual squares. The standard
terminology when referring to the size of such a grid is to specify height first, followed by width. For example,
a three-by-four grid is three squares high and four squares wide.
When working with such grids, we will index individual squares in the grid in the same manner that entries in
a matrix are indexed, top to bottom then left to right. In particular, a square is indexed by its row i and its
column j in the grid where the row index i lies in the range 0,1,...,height1 and the column index j lies in
the range 0,1,...,width1. This program produces a diagram in CodeSkulptor that illustrates this indexing
scheme.
When compared to canvas coordinates, this matrix-based indexing scheme transposes the horizontal and
vertical dimensions. For example, note that the coordinates given to draw_polygon in the diagram-plotting
program linked above order the column index first and the row index second when generating vertices of
each square drawn in the grid. For now, you don't need to worry about this issue since the GUIs that we
provide for each mini-project handle this transposition without any effort on your part.
Modeling rectangular grids in Python
Given a square, we can store the index associated with a square as the tuple (row,col) in Python. Then, we
can represent some relevant property of that square as the entry cells[row][col] in the 2D list cells. Note the
expression cells[row] returns a 1D list corresponding to a row of the grid. We can initialize this 2D list via the
code fragment:
cells = [ [... for col in range(grid_width)] for row in range(grid_height)]
Note that if row or col are not used in the expression ..., Pylint will warn that these variables are unused.
To avoid this warning, you can rename these variables to dummy_row and dummy_col to alert Pylint that
To avoid this warning, you can rename these variables to dummy_row and dummy_col to alert Pylint that
these variables are intentionally unused. This renaming will suppress the warning.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=grids>
Basic Probability
Sunday, June 28, 2015
4:06 PM
Probability is a branch of mathematics associated with the analysis of random phenomena. In Computer
Science, probability can arise in several ways: as part of the mathematics involved in analyzing a random
process or as part of a computational approach to solving a particular problem. For this class, our main
application of probability will be in analyzing and building programs associated with simple games.
However, don't view this application as limiting. Probabilistic methods arise in applications like scientific
computation, cryptography, and robotics.
Since many of you may have had limited exposure to probability, we review some basic terminology
associated with probability theory to begin. A trial (or an experiment) is any procedure that can be infinitely
repeated and has a well-defined set of possible outcomes, known as the sample space. If the sample space is
finite, each outcome can be assigned a number between zero and one that corresponds to the likelihood of
that particular outcome occurring. This number is the probability associated with the outcome. Since every
trial always results in exactly one outcome from the sample space, the sum of the probabilities associated
with the outcomes is always exactly one.
A simple example of a trial is a single roll of a fair six-sided die. The outcomes of this trial are the values on six
sides of the die {1,2,3,4,5,6}. Since the die is fair, the probabilities associated with these six outcomes are
all equal so the probability of each outcome is exactly 16. More generally, the probabilities associated with
outcomes of a trial are said to be uniformly distributed if these probabilities all have equal value.
An event is a set of outcomes of a trial (a subset of the sample space). For a single six-sided die, a simple
example of an event would be that the resulting roll is even. The probability of an event is the sum of the
probabilities associated with its set of outcomes. For example, rolling an even number with a six-sided die
corresponds to an event with three outcomes {2,4,6}, each with probability 1/6. Therefore, the probability of
that event is 1/6+1/6+1/6=12.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=probability>
Expected Value
Sunday, June 28, 2015
4:07 PM
In some computer science departments, one third of the students in a department have a GPA of 2.0,
one third have a GPA of 3.0, and one third have a GPA of 4.0. Suppose that we choose a student at
random from this department. What do you expect the students GPA to be? The answer is 3.0, since the
mean, or average, GPA is (2.0 + 3.0 + 4.0)/3 = 3.0. This value (the mean) is also called the expected value
(that is, we say that the expected GPA of a student in this CS department is 3.0).
At the same university, but in the biology department, half of the students have a GPA of 3.0 and the other
half have a GPA of 4.0. What is the expected GPA of a biology student in this university? The answer is (3.0+
4.0)/2=3.5. In other words, if we choose a biology student at random from this university, we expect the
student's GPA to be 3.5. Notice that the expected value in this case does not make sense as we understand
the term "expect," since no student in our case has a GPA of 3.5. The interpretation of the expected value
here is the mean, or average, GPA.
Let's now turn back to an example involving dice. What is the expected outcome of a single roll of a fair sixsided die? The answer is (1+2+3+4+5+6)/6=3.5. Of course, 3.5 has a probability of 0 being the outcome of
this trial. But, again, the interpretation of the expected value here is that 3.5 is the average of the values we
get if we had rolled this die an infinite number of times.
Notice that in the three examples above we divided by 3, 2, and 6, respectively. The reason for this is in these
three cases, the values 13, 12, and 16 are the probabilities of the relevant outcomes, respectively. That is, the
probability of each possible outcome in the fair die trial is 16. So, we can rewrite the formula for the expected
value as 161+162+163+164+165+166=3.5.
More generally, if the possible outcomes of a trial have value x1,x2,,xk and their probabilities
are p1,p2,,pk, respectively, then the expected value of this trial is ki=1pixi. As an example, consider the
case where we roll two fair six-sided dice and consider their sum as possible outcomes of the trial. In this
case, the set of possible outcomes is {2,3,4,5,6,7,8,9,10,11,12}. To compute the expect value of this sum,
we need to determine the probability of each of these outcomes.
In this case, there are 36 possible rolls if the values of the pair of dice are treated as an ordered tuple. There
is one possible tuple (1,1) that yields a sum of two so p2=136. Likewise, there are two possible
tuples (1,2) and (2,1) that yield a sum of three so p3=236=118. Continuing this analysis, pi=136(6abs(7
i)). Applying our formula for expected value, we arrive at the expression:
1362+2363+3364+4365+5366+6367+5368+4369+33610+23611+13612=7.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=expected_value>
Enumeration
Sunday, June 28, 2015
4:11 PM
mmm...m=mn.
This program computes the set of all possible sequences of outcomes of a specified length using the
function gen_all_sequences. (The program also includes a function gen_sorted_sequences which we will discuss
later.) Note that these functions represent sequences as tuples since the members of a set must be
immutable.
Applications to probability
In many applications in probability, we are interested in enumerating the sequences of outcomes
associated with a sequence of trials. For this class, we restrict our attention to the situation in which
each trial is independent; that is the outcome of the trial does not affect the probabilities associated with
the outcomes of other trials. For a sequence of independent trials, the probability of a particular
sequence of outcomes is the product of the probabilities associated with each individual outcome.
A simple example of an independent sequence of trials would be rolling a pair of dice. In this case, the roll of
the first die would have six outcomes {1,2,3,4,5,6} and the roll of the second die would have six
outcomes {1,2,3,4,5,6}. Joining an outcome from the first roll with an outcome from the second roll yields
a set of all 36 possible sequences of outcomes,
{(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(2,1),...,(6,3),(6,4),(6,5),(6,6)}
Since we considered all sequences (not just sorted sequences), the probability associated with each sequence
of outcomes is the same (136).
In this setting, we can now discuss events that correspond to a subset of this set of sequences. For the case of
two dice, a typical question might be: what is the probability that sum of the dice is exactly 7? Since each of
the 36 possible sequences of outcomes has a probability of 136 and six of these
outcomes {(1,6),(2,5),(3,4),(4,3),(5,2),(6,1)} correspond to an event where the sum is 7, the probability
that the sum of two dice is 7 is exactly 636=16. Note the sequences (2,5) and (5,2) must be treated as
distinct sequences for this analysis.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=enumeration>
4:14 PM
In some cases where a sequence of trials is conducted, we would like to preclude having the same
outcome occur twice. For example, consider the case of a lottery in which ping-pong balls are drawn one
at a time from a lottery machine. Once the first ball is drawn, it is set aside and that ball cannot be
redrawn later in the drawing process. In cases like this one, we are often interested in the number of
possible sequences associated with this process.
This question is a well-studied one and two mathematical tools are available to help in the analysis. Both of
these tools rely on a mathematical function that you may be familiar with. The factorial of a non-negative
integer m (denoted m!) is the product of the numbers 123...(m1)m. For example, 4!=1234
=24. To simplify various formula involving factorials, 0! is defined to be 1. The factorial function can be
accessed in Python using themath module. For example,
import math
print math.factorial(6)
Permutations
Given a set of outcomes, a sequence of outcomes of length n with no repetition is a permutation of
size n of this set. For our lottery example, if the set of outcomes is {1,2,3,...,59}, the ordered
sequence (34,12,27,56,58) is a permutation of length five. Observe that the
sequence (23,11,23,3,47) would not be a permutation since the outcome 23 is repeated. Also, note
that the permutation (34,12,27,56,58) is distinct from the permutation (56,12,27,34,58)since the
ordering of the elements in the permutation matters.
Principles of Computing Page 13
m(m1)...(mn+1)
possible permutations. This product can be conveniently written as m!(mn)! since all of the terms in products
in the numerator and denominator that are less than mn cancel out leaving the desired product.
Combinations
As was the case when repetition was allowed, the order of the resulting sequence may not matter in
some applications. The standard technique for handling this situation is to group all sequences that
correspond to the same set of outcomes in a single cluster. (Note we can use a set here instead of a
sorted sequence since repetition is not allowed.) The sets of outcomes associated with each cluster is
a combination of this set. For example, most lotteries require only that your set of numbers match those
drawn during the lottery to win. The order in which the numbers are drawn is irrelevant. In this case, the
sets {34,12,27,56,58}and {56,12,27,34,58} represent the same combination of lottery numbers.
The number of combinations of size n associated with a set of outcomes of size m also has a simple formula
in terms of factorials. As noted previously, there are m!(mn)! permutations of length n. These permutations
can be grouped into clusters where all of the permutations in a single cluster involve the same outcomes, but
in different orders. Note that in this model, each cluster corresponds to a combination. Since there
are n! possible ordered sequences of outcomes in each cluster, the total number of possible combinations
is m!(mn)!n! which is often written mathematically as (mn).
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=permutations>
Arithmetic Sums
Sunday, June 28, 2015
4:16 PM
In counting the number of steps executed during the evaluation of loops or nested sequence of loops,
various arithmetic sums will sometimes arise. Here is a quick overview of the notation for arithmetic
sums and closed form solutions for some common sums.
Notation
An arithmetic sum is the operation of adding a sequence of numbers. If we index the numbers in the
sequence by the subscript i, the arithmetic sum can be expressed mathematically in the form
i=0nai=a0+a1+a2+an.
Note that, as opposed to Python, both the lower bound (zero) and the upper bound (n) are also included in
the sum.
Common arithmetic sums and their solutions
Closed form expressions for almost all of the various arithmetic sums that you will encounter during this class
are listed below. It's not particularly important to memorize these expressions, just be aware that they exists
so you know that you can look them up when necessary.
i=0n1=1+1+...+1=n+1
The sum of a constant expression is a linear polynomial in n.
i=0nn=n+n+n+...+n=(n+1)n
The sum of a linear expression in n is a quadratic polynomial in n.
i=0ni=0+1+2+...+n=12(n+1)n
This sum is known as a triangular sum. The sum of a linear expression in i is also a quadratic polynomial in n.
i=0n2i=20+21+22+...+2n=2n+11
This sum is known as a geometric sum. In most cases, the sum of a sequence of exponential expressions is
Principles of Computing Page 15
This sum is known as a geometric sum. In most cases, the sum of a sequence of exponential expressions is
again exponential.
i=0ni=0+1+2+...+n=n+111
Note that this relation holds as long as 1. If 0<<1and the sum is infinite, i.e; n=, the sum reduces
to 11.
i=1n1i=1+12+13+...+1nlog(n)+
This sum is called a harmonic sum and has only an approximate solution (indicated by the symbol ).
Here, is a small constant
See this page for more information on logarithms (log(n)) and exponentials (exp(n)).
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=arithmetic_sums>
4:17 PM
During this class, we will use two mathematical functions with which you should be familiar. The first
function is the natural exponential exp(n)=en where e isEuler's constant 2.71828... The second
function log(n) takes the natural logarithm of n with respect to the base e. These two functions
are inverses of each other in the following sense:
If exp(n)=m, then log(m)=n. Conversely, if log(m)=n, then exp(n)=m.
In some situations, we may wish to work with different base such as base 2 or base 10. In this case, the base
of the logarithm is typically indicated as a subscript to the log function. For example, the
functions 2n and log2(n) are the examples of the exponential and logarithm function taken base 2.
When working with exponentials and logarithms, we will often make use of two properties. The product of
two exponentials is an exponential of the sum of the exponents while the logarithm of a product is the sum
of logarithms of the product's multiplicands.
exp(n+m)=exp(n)exp(m)
log(n m)=log(n)+log(m)
Log/Log plotting
To illustrate the usefulness of logarithms, let us consider of the problem of determining whether a set of
data points (xi,yi) lies on some polynomial function y=axn. This problem will sometimes crop up when
we are trying to estimate the running time of a code fragment where each value of the xi is the size of
the input to the code fragment and each value of the yi is an estimate of the running time of the code
(such as the number of statements executed).
Simply plotting the data points doesn't always help resolve this question since the constants a and n are
unknown. Moreover, the range and scale of the plot can easily influence how "curved" the plot is. However, if
we take the logarithm of both sides of this equation, the polynomial equation reduces to a linear equation
in log(x) and log(y).
Principles of Computing Page 17
log(y)=log(axn)
log(y)=log(a)+nlog(x)
If the data points (xi,yi) lie on y=axn, then they must satisfy the equation
log(yi)=log(a)+nlog(xi)
where log(a) and n are constants. This observation suggests a strategy for determining whether the data
points lie close to a polynomial function. Plot the data points (log(xi),log(yi)) and check whether these data
points lie near a straight line. If they do, the original data points (xi,yi) lie near a polynomial function.
Moreover, the degree of this polynomial is simply the slope of this line.
Many plotting packages support this kind of analysis by offering a log/log plotting option. Under this option,
the axes are labelled with the various values of the xand y. However, these labels and the plotted data are
positioned at the locations log(x) and log(y). For example, plots with axes labeled 1,10,100,1000,...are
usually log/log plots.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=log_and_exp>
4:18 PM
As part of this class, we will model the growth rates of certain quantities associated with a program,
such as the number of statements in its execution trace, its running time, or the size of its computed
output. In these cases, our goal will be to determine a function f(n) that models the growth of this
quantity as a function of the input size n to the program. As part of the analysis, we will often wish to
compare the growth rate of this function to various known functions to better understand the behavior
of the program.
Given two function f(n) and g(n), these functions grow at the same rate if the ratio f(n)g(n) approaches some
fixed constant as n grows large. If this ratio approaches zero as n grows large, f(n) grows more
slowly than g(n). On the other hand, if this ratio approaches infinity, f(n) grows faster than g(n). For this
class, we won't focus too much effort on doing a formal mathematical analysis of growth rates. Instead, we
will learn a few simple mathematical rules for comparing the growth rates of various functions and rely on
techniques such as plotting when these rules aren't sufficient for our analysis.
Note that in our comparison of functions, we consider functions that are constant multiples of each other to
be "equivalent". This choice reflects the fact that we are more concerned with the growth in the size of a
quantity than the actual value of the quantity. For example, the running time of a program may depend on
many factors such as the power of computer's processor, the speed of its operating system, and the
performance of any environment that runs the computation (like a web browser). However, if the running
time of a program grows at an exponential rate, the processing power of even the fastest computers will be
quickly overwhelmed.
The function log(n) grows faster than the constant function 1 and slower than the linear function n. The
function nlog(n) grows faster than n and slower than n2.
Any exponential function n with >1 grows faster than any polynomial function. The factorial
function n! grows faster than n and, consequently, faster than any polynomial function.
One simple visual technique for comparing the growth rates of pairs of functions is to plot f(n)g(n) for a
reasonable range of values for n. Examining the resulting plots usually provides some insight into the relative
growth rates of the functions being compared. For example, the three plots created by this program illustrate
the situation when f(n) is 0.1n3+20n while g(n) are the functions n3, 20n2, and 0.1n4, respectively. Note
that the leftmost plot tends toward a positive constant value (a horizontal line), the middle plot increases
continuously and has no upper bound, and the right plot converges towards zero. These plots reflect the fact
that two cubics grow at the same rate, a cubic grows faster than a quadratic, and a cubic grows slower than a
quartic.
One method for accelerating this physics update is to divide the canvas into a grid whose cells are roughly the
size of the balls. Before computing ball/ball collisions during a physics update, each ball is assigned to the cell
that contains the center of the ball. Since the size of the grid cells are the diameter of the ball, a maximum of
four balls can be assigned to any one cell. Then, during the collision phase, a ball is tested against only those
balls in its own cell and its eight spatially-adjacent neighbors. This limits the total number of balls that needs
to be tested for collision to be less than or equal to 49=36 balls. Overall, a maximum of 36n total collision
tests are done during each update.
This CodeSkulptor program implements this alternative algorithm for performing physics updates. The left
plot below shows the time per update plotted as a function of the number of balls. Observe that the running
time for each update appears to grow linearly as a function of the number of balls. The right plot shows the
ratio of the running times and the function n. Observe that the plot is trending towards a positive constant
which confirms our analysis that the running time for this update method is growing linearly.
This example illustrates the importance of algorithms and our analysis of their efficiency. At first glance, our
original method seemed simple and efficient. However, we note that the added complexity of our improved
collision method is well worth the effort since the enhanced speed of the update method allows us to add
many more balls to our simulation.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=fun_growth>
Coding Notes
Sunday, June 28, 2015
4:22 PM
This page contains like to a collection of class pages relating to coding issues for the class. Please spend
a few minutes browsing these links so you are aware of this information when necessary.
Python pages:
Guidelines for coding style (IMPORTANT)
Python development environments
A guide to Pylint errors
A guide to Python errors
Python knowledge required for the class
Building tests for your Python programs
Importing custom modules in Python
Using default arguments in Python
Mini-project descriptions and OwlTests:
Week 1 - 2048 (merge) - OwlTest
Week 2 - 2048 (full) - OwlTest
Week 3 - Tic-Tac-Toe (Monte Carlo) - Owltest
Week 4 - Yahtzee - Owltest
Week 5 - Cookie Clicker - OwlTest
From <https://class.coursera.org/principlescomputing1-003/wiki/helpful_pages>
4:22 PM
In this class, we will expect you to follow our coding style conventions. These conventions will largely be
enforced by the use of Pylint. Pylint is a source code bug and quality checker for the Python programming
language. The machine-graders for this class will use a customized version of Pylint to check the style of your
code. Pylint errors that violate of the style guidelines will result in deductions from the score of your miniproject. An explanation of common Pylint errors can be found here.
Here are some of the style guidelines that we will follow in this class. As you interact with Pylint, you will get
more exposure to these guidelines.
Documentation
Documentation strings ("docstrings") are an integral part of the Python language. They need to be in the
following places:
Comments
Comments should describe how a section of code is accomplishing something. You should not comment
obvious code. Instead, you should document complex code and/or design decisions. Comments and
docstrings are not interchangeable. Comments start with the "#" character. While you will see some Python
programmers do this, you should not comment your code by putting a multi-line string in the middle of your
program. That is not actually a comment, rather it is just a string in the middle of your program!
A good example:
# This is a block comment
# that spans multiple lines
# explaining the following code.
val = some complicated expression
A bad example:
"""
Somebody told me that a multiline
string is a block comment.
It's not.
"""
val = some complicated expression
Note that docstrings are multi-line strings, but they do not violate this convention because docstrings and
comments are different and serve different purposes in a program.
Global variables
Global variables should never be used in this class. Avoiding their use is good programming practice in any
language. While programmers will sometimes break this rule, you should not break this rule in this class.
There is one exception to this rule: you may have global constants. Because the Python language does not
actually support constants, by convention, Python programmers use global variables with names that are in
all capital letters for constants. When you see a variable with a name in all capital letters, you should always
assume that it is a constant and you should never change it. Again, such global constants are the only global
variables that will be allowed in this class.
Indentation
Each indentation level should be indented by 4 spaces. As Python requires indentation to be consistent,
it is important not to mix tabs and spaces. You should never use tabs for indentation. Instead, all
indentation levels should be 4 spaces. Note that CodeSkulptor automatically converts all tab indents into
4 spaces.
Names
All variable, function, class, and method names must be at least 3 characters. The first character of a name
should follow these conventions:
Variable names should always start with a lower case letter. (Except for variables that represent constants,
which should use all upper case letters.)
Function and method names should always start with a lower case letter.
Class names should always start with an upper case letter.
Further, we will follow the common Python convention that variable, function, and method names should
not have any capital letters in them. You can separate words in a name with an underscore character, as
follows: some_variable_name. Similarly, class names should not contain underscores, and instead use
capitalization to separate words, as follows: SomeClassName.
As previously noted, constants should be in all capital letters, such as: THIS_IS_A_CONSTANT. Note that this
means that your class names must have at least one lower case letter in them, to distinguish them from
constants.
By convention in Python, you can "violate" the above rules and start a name with an underscore, _, to
indicate that the name is private and should not be accessed outside of the context in which it is defined. In
this case, the rest of the name after the underscore should follow the rules given above. This will arise mainly
when you define instance fields in classes, as these style guidelines insist that such fields be private
(discussed next).
Scope
You should not use names that knowingly duplicate other names in an outer scope. This would make the
name in the outer scope impossible to access. In particular, you should never use names that are the same as
existing Python built-in functions. For example, if you were to name one of your local variablesmax inside of a
function, you would then not be able to call max() from within that function.
In this case, you should name the variable with the dummy_ prefix. This indicates clearly to you, others, and
Pylint that the variable is intentionally unused.
Principles of Computing Page 27
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=style_guidelines>
4:26 PM
In this class, the instructors will consistently use the CodeSkulptor Python environment. All of the examples,
exercises, and assignments will use CodeSkulptor. If you already took our previous course, An Introduction to
Interactive Programming in Python (IIPP), you should be familiar with this tool. If not, you can watch these
introductory videos from that class to learn more about it:
CodeSkulptor
Saving in CodeSkulptor
CodeSkulptor will work for all of the assignments in this class. We strongly advocate that you use
CodeSkulptor throughout the class, as that ensures that you are working in the same environment as the
instructors and everyone else. All of the assignments and exercises were developed and tested within
CodeSkulptor. However, it is not a strict requirement that you use CodeSkulptor for this class. The class uses
Python 2 (most importantly, the machine grader runs Python 2), so whatever environment you choose must
support Python 2. The following video from IIPP briefly discusses moving beyond CodeSkulptor:
Beyond CodeSkulptor
If you want to explore other Python development environments, we suggest you post in the Python
subforum and discuss alternatives with your classmates.
Note: There are some caveats with using alternate environments:
1. Due to the high volume of help requests, if you choose to use the Code Clinic, the staff will only be able to
help you with code configured to run in CodeSkulptor and submitted as a CodeSkulptor URL. This restriction
is critical since it allows us to reliably and efficiently access your code when helping you.
2. You will need to download any files that are provided with each assignment to your computer and figure out
where to locate them so that your development environment can find them (more below).
where to locate them so that your development environment can find them (more below).
3. The machine grader only supports a limited subset of Python modules. You will need to restrict yourself to
those modules in order to work with the grader. The grader supports all modules that CodeSkulptor supports.
In many of the template files, we will import some provided code, i.e., import poc_provided. To access this code,
you simply need to go to the corresponding CodeSkulptor URL (by adding a hash tag, the imported file name,
and the ".py" extension): http://www.codeskulptor.org/#poc_provided.py (note that this is just an example
of how to construct the URL and that file does not exist). Once you have copied all of the provided files onto
your machine (with the same names that we gave them), then you should be able to develop your code on
your local machine. However, you will need to make sure you locate those files where your environment can
find them.
Note:The machine grader currently has two restrictions. First, the machine grader only supports the upload
of a single file. So, even though most development environments make it easy to break your program up into
multiple files, you must keep all of the code you write for an assignment in one file for this class. While this is
not necessarily the best programming practice, it is necessary for us to deal with the complexities of a large
online class like this. Second, the machine grader only supports the following Python
libraries: random, time, math, re, collections.defaultdict, and collections.Counter. Again, this has to do with the
complexities of providing a machine grader for a large online class like this. These modules are sufficient to
complete all of the assignments in this class and CodeSkulptor also supports all of these modules.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=pythonides>
4:27 PM
Pylint is a source code bug and quality checker for the Python programming language. The machinegraders for this class will use a customized version of Pylint to check the style of your code. Pylint errors
due to violations of the style guidelines will result in deductions from the final score for your miniproject.
If you would like to experiment with Pylint, you are welcome to use this Owltest page to submit programs
directly to Pylint for style checking. Here are explanations of some common warning message that Pylint will
display.
Missing docstring for program: Pylint warns you if your program does not begin with a docstring (which
violate the style guidelines). This programgenerates the warning "[line 1] Missing docstring". Adding a docstring
at the top of the program will remedy this error.
Non-compliant variables names: Pylint warns you if your variable names do not conform to the style
guidelines. In particular, all variable names should consist of three or more lower case letters or underscores.
For example, this program will generate the warning "Invalid name "n" (should match [a-z_][a-z0-9_]{2,30}$)" which
signals that the parameter name n does not meet the style guidelines. Renaming n to number in
the program avoids the warning.
Use of global variables: Pylint warns you if you are using global variables (which violate the style guidelines).
Since global constants are allowed, Pylint will warn you that they should be named using all capital letters.
For example, this program generates the warning " Invalid name "canvas_width" (should match (([A-Z_][A-Z0-9
For example, this program generates the warning " Invalid name "canvas_width" (should match (([A-Z_][A-Z0-9
_]*)|(__.*__))$)". Capitalizing the names of the two global constants yields a program free of warnings.
Missing docstring for a function or class definition: Pylint will warn you if your function or class definition
does not contain a docstring (which violate the style guidelines). For example, this program generates the
warning "[line 5] Missing docstring". Adding a docstring to the function definition yields aprogram that avoids
this warning.
Code refactoring warnings: Pylint analyzes your code and check for long, complex blocks of code. If the
complexity of these blocks exceeds Pylint's built-in limits, Pylint will issue a warning asking you to refactor
(rewrite) your code in smaller pieces using several functions or methods. For example, thisprogram generates
the warning "Too many return statements (10/6)". In this case, rewriting this program to use the remainder
operator avoids the warning.
Redefining built-in function names: Pylint warns you if you attempt to redefine the name of a built-in Python
function. For example, this program will generate the warning "Redefining built-in 'format'" that signals that you
are trying to redefine the built-in format function in Python. Renaming formatto template in the program avoids
the warning. (Yes, we did this in the template for Stopwatch for IIPP. We also write bad code sometimes.)
Unused variables: Pylint warns you if a variable in your code is unused (which may indicate a problem in your
code). A common situation where this issues arises is when using list comprehensions to create lists with
constant values. This example will cause Pylint to report the error "[line 10] Unused variable 'index'". Renaming
the variable with the prefix dummy_... will inform Pylint that this variable is intentionally being used as a
dummy variable. This programwill pass Pylint's style check.
Access to a protected member: Pylint warns you if you attempt to access a class field outside the class
definition. This example will cause Pylint to report the error "[line 16] Access to a protected member _name of a
client class". (Pylint also gives a refactoring warning about having no public methods for the class.) Adding the
method get_name (and a second public method) yields this program that will pass Pylint's style check.
Invalid name for class field: Pylint warns you if you fail to use a leading underscore on class fields to indicate
that they are private. This example will cause Pylint to report the error "[line 12] Invalid name "name" (should
match _[a-z0-9_]{3,30}$) function "Widget.__init__", line 12" . Adding a leading underscore to the field name yields
this program that will pass Pylint's style check.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=pylint_errors>
4:29 PM
This is an attempt to translate Python errors into English created by Emily Wachtel. It is by no means
complete or comprehensive, but we've added it here as a resource.
So what do all these errors mean?
Principles of Computing Page 34
SyntaxError: "I don't recognize what you just wrote as Python code."
'Syntax' refers to the rules that dictate how you're allowed to write down a coding language. For example,
the rule that states that youmay not begin a variable name with a digit is part of the syntax of Python. A
SyntaxError will pop up if you violate any of Python's syntax rules. This could be forgetting to close a
parenthesis or quote, mistakes in indentation, forgetting colons after function headers, etc. Note that syntax
errors can be tricky - sometimes the real error is actually before or after the line that the error is reported on.
When you go hunting for syntax errors, try looking at the entire block of code that surrounds the line where
the error appears.
Example 1: Syntax Error: bad input ('
') - http://www.codeskulptor.org/#user29_RBAM7aLLFF_10.py
Example 2: Syntax Error: bad token('"') - http://www.codeskulptor.org/#user29_9vki2pLzHk_1.py
Example 3a: Syntax Error: bad input('print') - http://www.codeskulptor.org/#user29_p7riICJqyf_1.py
Example 3b: Syntax Error: 'return' outside function - http://www.codeskulptor.org/#user29_UWijfk8YnI_0.py
Example 4: Syntax Error: can't assign to literal - http://www.codeskulptor.org/#user29_GAQb6gQq0Y_2.py
Example 5: Indendation Error: unindent does not match any outer
indentation - http://www.codeskulptor.org/#user29_DM85TuO1tN5P1fJ.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------NameError: "What in the world is X?"
A NameError is triggered when Codeskulptor doesn't recognize the variable, function name, etc. that you're
referring to. A NameError is Codeskulptor's way of saying "I've never heard of that before!" Common causes
of this are misspellings or forgetting to declare variables entirely.
Example 1: NameError: name 'some_variable_name' is not defined - http://www.codeskulptor.org/#user29
_rvErPx9lFA_7.py
Example 2: NameError: name 'some_function_name' is not defined - http://www.codeskulptor.org/#user29
_DSrwc3QXrb_1.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------TypeError: "You're trying to use some of those things in a way that wasn't intended."
This error can come up when you're trying to do perform an operation on something, but the operation and
the thing just don't go together. One example is trying to multiply a dictionary and an integer - it just won't
work. A helpful tool in debugging type errors is the Python type() function. Adding print statements like "print
type(my_variable)" will help you figure out what's going wrong.
Example 1: TypeError: cannot concatenate 'str' and 'int' objects (or any other data
type): http://www.codeskulptor.org/#user29_O8c065gLl1_11.py
Example 2: TypeError: function_name() takes exactly x arguments (y given) - http://www.codeskulptor.org/
#user29_Xd5fyxBt6K_0.py
Example 3: TypeError: 'int' object is not iterable (could be a different data
type) - http://www.codeskulptor.org/#user29_Vd3ft6yTVH_0.py
Example 4: TypeError: 'int' object is not callable (could be a different data
type) - http://www.codeskulptor.org/#user29_BRRaiVlwpD_0.py
Example 5: TypeError: handler must be a function - http://www.codeskulptor.org/#user29_5JQUSZ4lDP_1.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------AttributeError: "That object doesn't know how do to what you asked it to do"
In OOP, objects have "attributes" - things that they're aware of, and/or know how to do. In terms of Python,
attributes are an objects properties and the methods defined by its class. An AttributeError will be thrown
when you ask an object to do something or access something that isn't in its class definition.
Example 1: Attribute Error: '[Object X] has no attribute [attribute Y] - http://www.codeskulptor.org/#user29
_JWjKm5ZQV4_6.py
Example 2: Same as Example 1, but with an explicit class definition - http://www.codeskulptor.org/#user29
_Qvjnv5BNTg_0.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------IndexError: "That list/dictionary/tuple (etc.) doesn't have that many items in it."
An IndexError happens when you try to access an index that doesn't actually exist. It's like telling someone to
take 13 eggs out of a 12-egg carton - it won't work, because there are only 12 spaces. Printing out your index
values, along with len(the_list_in_question) will help you in debugging these errors. Important to note:
negative indices *are* possible in Python! See the video lecture on lists for more information.
negative indices *are* possible in Python! See the video lecture on lists for more information.
Example 1: IndexError: list index out of range - http://www.codeskulptor.org/#user29_eget014sAQ_9.py
-------------------------------------------------------------------------------------------------------------------------------------------------------------------TokenError: "You probably forgot to close a bracket." *
Very simply, tokens are things that stand for other things - sort of like variables, except they're used at a
more structural level. Some examples of tokens are EOF (End Of File) and EOL (End Of Line). These are the
two most common ones you will come across in Python, but they are used everywhere in programming. The
TokenErrors that you will see in this course are usually solved by remembering to close your brackets. See the
example for a more in-depth explanation of why this is.
Example 1: TokenError: EOF in multi-line statement - http://www.codeskulptor.org/#user29_TwsBlWnsiG_
3.py
*Not actually what it means - but a more detailed explanation is more appropriate for other courses, and this
is the most common cause of TokenErrors in this class.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------ValueError: "There's something wrong with the value of one of those arguments (but the type is ok)."
A ValueError is raised when a function receives an argument that looks ok on the surface (e.g., it receives a
character, and it was looking for a character), but the value of that argument is unexpected (e.g., the function
was only built to handle digits, and it received a letter 'a'). This type of error can be solved by checking the
documentation for whatever function you're trying to use,
and making sure that whatever you put inside the parentheses, the function was built to handle it.
Example 1: ValueError: invalid literal for int() with base 10: ' ' - http://www.codeskulptor.org/#user29
_v7yqnKyAPa_2.py
IndentationError: "Your code blocks aren't all indented to the proper levels."
This is a type of Syntax Error. See Syntax Errors, example # 5.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------Miscellaneous section - these errors are either self-explanatory or not common in the level of programming
done in IIPP
OverflowError - caused by trying to store, for example, a long inside an int. A long has too many bytes to fit
inside the int data type
ZeroDivisionError - you guessed it - you're trying to divide by zero somewhere
ImportError - caused by trying to import a module that doesn't exist. Check your spelling.
JavaScript section - these are not Python errors. They are related to your browser, not your code.
HierarchyError - Internet Explorer is not supported by CodeSkulptor. Use Chrome or Firefox.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=python_errors>
4:33 PM
In this class, we will assume a basic knowledge of Python consistent with having taken our previous
course, In Introduction to Interactive Programming in Python. Although we'll be using Python 2, starting
with a knowledge of Python 3 is fine. The only two differences from Python 3 that you will probably
notice in Python 2 are printing (print "Hello world" instead of print("Hello world")) and integer division (11 /
4 is 2 instead of 2.75).
4:34 PM
An example
Using poc_simpletest, it's possible to create fairly complete test suites for your programs. This test suite is
designed to test this format function for the stopwatch project. Note that the test suite is imported into the
solution file in line 5 and run in line 21. Inside the test suite, the test code is encapsulated inside a single test
function run_suite() that includes the function being tested as a parameter. This design allows us to import the
test suite using a single importstatement and then run the test suite using a single call to run_suite(). One can
turn off testing by simply commenting out the call to run_suite(). (For information on how importing works,
turn off testing by simply commenting out the call to run_suite(). (For information on how importing works,
please this page.)
4:35 PM
In this class, we will store provided code, test suites, and GUI code in separate files (which are referred
to as modules in Python) to keep the size of your programs tractable. You have already seen examples of
built-in modules such as math and random whose implementations are hidden from you. In this page, we
will show you how you can create and import Python modules of your own creation. Storing various
parts of your code in separate modules is a simple way to organize the components of your program.
parts of your code in separate modules is a simple way to organize the components of your program.
In Python, the import statement allows you to reference and execute code stored in a separate module.
Import statements have the syntax
import my_code as important_module
On the desktop, Python looks for the file "my_code.py" in the directory where your program is saved
and loads that file. At that point, the user can reference variables, functions, and classes defined in the
file by adding the prefix important_module. to the names of the variables/functions/classes defined in the
module. (Note that if you omit the "as important_module" part of the import statement, you should use
the prefix "my_code" when referencing entities defined in the module.)
Note the name used in the import statement matches the part of the CodeSkulptor URL after the "#" for
the file above. (Remember to omit the ".py" extension just as is done in desktop Python.) This
program imports the file above and prints out a message generated by the imported code by
callingimportant_module.print_something().
where the name "poc_helper_stuff" corresponds to the file with the URL "http://www.codeskulptor.org/
#poc_helper_stuff.py" that we have manually created on Google Storage. (Note that this particular file
doesn't exist.)
To import test suite code into your mini-project for testing. These imports will typically consist of two
statements: one that imports the module containing your test suite and a second that runs your test suite.
For example, you can import and run the test suite for Solitaire Mancala via the code
import poc_mancala_testsuite
poc_mancala_testsuite.run_suite(SolitaireMancala)
4:36 PM
The way Python handles default arguments is not intuitive and is often confusing to students. This issue
because especially important when others (say a machine grader) are calling functions with default
arguments that you have written. The key thing to understand is that the default argument is evaluated
onlyonce, when the function is defined. The same object is then used whenever the default argument is
needed.
Consider for example, the following program:
def mystery(item, sequence=[1, 2, 3]):
sequence.append(item)
return sequence
print mystery(4)
print mystery(5)
Mini Projects
Sunday, June 28, 2015
5:51 PM
2048 (Merge)
Sunday, June 28, 2015
5:51 PM
Overview
2048 is a simple grid-based numbers game. The rules of the game are described here.
In the first two assignments, we will implement a version of the 2048 game. Although the original game is
played on a 44 grid, your version should be able to have an arbitrary height and width. In this first
assignment, we will focus on only one aspect of the game: merging tiles.
We have provided the following template that contains the basic code that you will need to implement the
merge function. The signature (name and parameters) of the functions in this file must remain unchanged,
but you may add any additional functions or other code that you need to.
Coding Style
In this class, you will be asked to strictly follow a set of coding style guidelines. Good programmers not only
get their code to work, but they also write it in a way that enables others to easily read and understand their
code. Please read the style guidelines carefully and get into the habit of following them right from the start.
When you are ready to submit your code to be graded formally, submit your code to the CourseraTest page
for this mini-project that is linked on the main assignment page. Note that the CourseraTest page looks
similar to the OwlTest page, but they are not the same! The CourseraTest page has a whitebackground and
does submit your grade to Coursera.
Merge
For this assignment, you will implement a function merge(line) that models the process of merging all of the
tile values in a single row or column. This function takes the list line as a parameter and returns a new list with
the tile values from line slid towards the front of the list and merged. Note that you should return a new list
and you should not modify the input list. This is one of the more challenging parts of implementing the game.
In this function, you are always sliding the values in the list towards the front of the list (the list position with
index 0). You will make sure you order the entries in line appropriately when you call this function later in the
next assignment. Empty grid squares with no displayed value will be assigned a value of zero in our
representation.
For example, if a row of the board started as follows:
And you slide the tiles left, the row would become:
Note that the two leftmost tiles merged to become a 4 and the third 2 just slides over next to the 4.
A given tile can only merge once on any given turn, although many pairs of tiles could merge on a single turn.
For the above example, the input to the merge function would be the list [2, 0, 2, 2]. The function should then
produce the output [4, 2, 0, 0]. We suggest you begin to implement this function as follows:
1. Start with a result list that contains the same number of 0's as the length of the line argument.
2. Iterate over the line input looking for non-zero entries. For each non-zero entry, put the value into the next
available entry of the result list (starting at position 0).
Notice if you only follow this process, you would end up with the result [2, 2, 2, 0].
Now you should think through what you should add to your function in order to merge tiles. Keep in mind,
however, that any tile should only be merged once and that these merges should happen in order from
lowest index to highest index. For instance, on the input [2, 0, 2, 4], the result should be [4, 4, 0, 0],not [8, 0, 0, 0].
Note that there are many ways to implement the merge function. The objective of this project is for you to
use what you've learned in our previous classes to implement a complex function. You have already learned
all of the Python required to implement merge, so the challenge is to think carefully about what the function
does and how to best accomplish that.
Here is one basic strategy to implement the merge function:
3. Iterate over the input and create an output list that has all of the non-zero tiles slid over to the beginning of
the list with the appropriate number of zeroes at the end of the list.
4. Iterate over the list created in the previous step and create another new list in which pairs of tiles in the first
list are replaced with a tile of twice the value and a zero tile.
5. Repeat step one using the list created in step two to slide the tiles to the beginning of the list again.
This is not the most efficient way of implementing merge. While it is fine to implement it in this way, we
challenge you to think of other ways of doing it that do not require creating so many lists. Ultimately, how
you approach the problem is up to you.
As you work on your merge function, here are some simple tests you should try:
These tests are by no means exhaustive and are just meant to get you started.
From <https://class.coursera.org/principlescomputing1-003/wiki/view?page=2048_(Merge)>