# Chapter 2. Linear Systems

There’s definitely, definitely, definitely no logic

To human behaviour— “Human Behaviour” by Björk

**
In this chapter, you will try your hand at abstract painting.**

I’m as excited as you are about making a meteor fly, so let’s take the complexity of our systems up a notch. We’ll set multiple objects in motion in this section and see what we can learn about their behavior.

# 2.1 Systems of Equations

## Testing Solutions

In the last chapter, you applied linear equations as a mathematical model for the path of a meteor. As the meteor’s \(x\)-coordinate increased, its \(y\)-coordinate increased, and we related the two using an equation like the one below.

\(y = 0.5x + 100\)

If you substituted \(10\) for \(x\), you could evaluate the right-hand side to find, or ** solve for**, \(y\).

\(y = 0.5 \cdot 10 + 100\)

\(y = 105\)

You could use the same approach to find every coordinate pair along the meteor’s path. Substituting the coordinate pair \((10,105)\) into the equation \(y=0.5x+100\) makes both sides equal, so we call it a ** solution** to the equation.

How about the coordinate pair \((10,110)\)?

\(110=0.5 \cdot 10 + 100\)

\(110 \ne 105\)

No luck. The symbol \(\ne\) means “does not equal.” \((10,110)\) is not a solution to this equation.

OK, so we can map out all the points along an object’s path. But what if there were multiple objects moving along multiple paths?

## Solving Equations

In the film *Gravity*, a Space Shuttle is destroyed by a barrage of space debris, forcing the survivors to find another way home to Earth before the debris completes another orbit and threatens them again. Let’s try to help out the astronauts by constructing a simulation of the Shuttle-debris system.

**
A Space Shuttle and debris in Earth’s orbit.**

**\(\mapsto\)**
Outer space is an empty, infinite, two-dimensional surface. The Space Shuttle is a point moving along the straight path described by the equation \(y=0.5x+100\). The debris is also a point moving along a straight path, this one described by the equation \(y= -0.5x+300\).

**
The coordinates of both objects are ordered pairs of floating point numbers. The Space Shuttle’s initial position is \((0,300)\). The debris’ initial position is \((0,100)\).**

**
First, paint the sky. Next, select a pencil color & weight. Then, update the position of each object. Finally, draw a point at each object’s position.**

**Example 2.1 A collision**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
global x
x += 1
shuttleY = 0.5 * x + 100
debrisY = -0.5 * x + 300
point(x, shuttleY)
point(x, debrisY)
```

At the beginning of the film, Mission Control warns the astronauts that danger is coming. In real life, the United States Space Surveillance Network tracks objects in Earth’s orbit using a variety of sensing equipment. The team records the types of objects, when they were launched, their orbits, and their sizes. NASA uses this data to construct models that predict collisions like the one in *Gravity*.

While we don’t have a giant network of sensors and computers, we do have all the tools we need to figure out where the paths of our simulated Shuttle and debris cross. Let’s combine the equations describing each object’s path into a *system of equations*.

\(y = 0.5x + 100\)

\(y = -0.5x + 300\)

A system of equations is a set of related equations. There are infinitely many possible \((x,y)\) coordinate pairs, but only one that solves both of these equations. For example, the point \((100,150)\) solves the equation for the Shuttle’s path.

\(150 = 0.5 \cdot 100 + 100\)

\(150 = 50 + 100\)

\(150 = 150\)

But does it also solve the equation for the debris’ path?

\(150 = -0.5 \cdot 100 + 100\)

\(150 = -50 + 100\)

\(150 \ne 150\)

No luck. We could try guessing and checking other coordinate pairs, but we might be at it for a while. There are many good techniques for solving systems of linear equations and we need a few additional ideas to apply them. Let’s start with a simpler case.

Math that uses letters as placeholders for numbers is known as ** algebra**. Those placeholders, or variables, can show up anywhere we establish a relationship. Take the equation below as an example.

\(2 + 3 = 5\)

What if I wrote the following equation instead?

\(x + 3 = 5\)

We’ll use this example as a starting point for finding “unknown” values like \(x\), also called solving an equation. Given \(x+3 =5\), I want to come up with an algorithm that solves for \(x\). Let’s simplify again.

We know the following equation relates \(2\), \(3\), and \(5\).

\(2 + 3 = 5\)

**Figure 2.1 Three hops to the right**

You could express the same relationship another way by rearranging the equation a bit.

\(2 = 5 - 3\)

**Figure 2.2 Three hops to the left**

At this point you might think, “OK, the numbers \(2\) and \(5\) are \(3\) units apart. But what does that have to do with finding unknowns?” Everything, as it turns out.

We can think of the original equation \(2+3=5\) as running “forward” from the starting point \(2\). In this view, the second equation \(2=5-3\) runs “backward”. Running an operation backward is known as ** inverting** the operation. And something interesting happens when we apply an operation and its inverse together.

\(2 + 3 - 3 = 2\)

**Figure 2.3 Hopping back and forth**

We’re right back where we started! Operations and their inverses undo each other; it’s like nothing happened at all. This fact is key to solving equations.

In math, the \(=\) symbol is an ironclad statement of equality. The left-hand side must equal the right-hand side, now and always. If you make a change to the left, you’d better do the same to the right. Let’s take the original equation one more time and invert the \(+3\) operation.

\(2 + 3 - 3 = 5 - 3\)

Or simplified:

\(2 = 2\)

Now, let’s apply identical reasoning to the equation with the variable \(x\).

\(x + 3 = 5\)

\(x + 3 - 3 = 5 - 3\)

\(x = 2\)

OK, let’s see that process one more time with a different example.

\(x - 2 = 10\)

\(x - 2 + 2 = 10 + 2\)

\(x = 12\)

** Exercise 2.1**
Given the equation \(x-5=10\), solve for \(x\). Then, describe the algorithm you used to solve for \(x\) in plain English.

**Operator Precedence**

Inverting addition and subtraction seems to work just fine, but what happens when you include other operations? Let’s take the path of our Shuttle.

\(y = 0.5x + 100\)

How would you determine the Shuttle’s \(x\)-coordinate when its \(y\)-coordinate is \(300\)?

\(300 = 0.5x + 100\)

It seems like we could invert this equation to solve for \(x\), but I’m not certain of how to proceed now that multiplication is in the mix. Figuring this out requires a brief interlude to discuss the order, or ** precedence**, of mathematical operations.

If you come across an expression like \(2 \cdot 3 + 4\), the mathematical community has agreed that you should multiply before adding. You can compute the value produced in this example as follows.

\(2 \cdot 3 + 4\)

\(6 + 4\)

\(10\)

We’ve seen the computation run forward, so let’s go backward. The last operation applied was \(+4\), so let’s invert that first.

\(10 = 2 \cdot 3 + 4\)

\(10 - 4 = 2 \cdot 3 + 4 - 4\)

\(6 = 2 \cdot 3\)

You can view the multiplication as \(2\) multiplying \(3\) or as \(3\) multiplying \(2\). I’ll go with the former and undo multiplication by \(2\).

\(\frac{6}{2} = \frac{2 \cdot 3}{2}\)

\(3 = 3\)

How about we substitute one of the operands for a variable and solve for it?

\(10 = 2x + 4\)

\(10 - 4 = 2x + 4 - 4\)

\(6 = 2x\)

\(\frac{6}{2} = \frac{2x}{2}\)

\(3 = x\)

It’s been quite a journey, but I think we’re ready to plot a course for our Shuttle.

\(300 = 0.5x +100\)

\(300 - 100 = 0.5x + 100 - 100\)

\(200 = 0.5x\)

\(\frac{200}{0.5} = \frac{0.5x}{0.5}\)

\(400 = x\)

** Exercise 2.2**
Find the \(x\)-coordinate of the Shuttle when its \(y\)-coordinate is \(100\). Then, describe the algorithm you used to solve for \(x\) in plain English.

The order of mathematical operations is bundled up nice and neat in the acronym PEMDAS.

**P**arentheses

**E**xponents

**M**ultiplication

**D**ivision

**A**ddition

**S**ubtraction

Let’s focus on MDAS for now as they are key to linear relationships. Multiplication and division have the same precedence. Consider the example below.

\(3 \cdot 10 \div 5\)

You could compute \(3 \cdot 10 = 30\), then divide \(30 \div 5\) to produce \(6\). Or you could start by dividing \(10 \div 5 = 2\) before multiplying \(3 \cdot 2\) to produce \(6\). There are multiple pathways to the correct answer!

There is a similar story for addition and subtraction.

\(3 + 10 - 5\)

You could compute \(3 + 10 = 13\), then subtract \(13 - 5\) to produce \(8\). Or you could start by subtracting \(10 - 5 = 5\) and add \(3 + 5 = 8\). Once again, multiple pathways!

** Exercise 2.3**
Evaluate the expression \(10 \cdot 5 \div 2 + 5\).

** Exercise 2.4**
Evaluate the expression \(10 ÷ 5 - 2 \cdot 5\).

## Solving Systems

We’re on a tight schedule to be of any help to NASA. Let’s figure out the coordinates \((x,y)\) where the paths of the Shuttle and debris intersect. Recall the system of equations describing the scenario.

\(y = 0.5x + 100\)

\(y = -0.5x + 300\)

There are infinitely many points along each object’s path, and the variables \(x\) and \(y\) are placeholders for all of them. The Shuttle and debris were moving before they collided, and they continued moving afterward. Those variables \(x\) and \(y\) that solved one equation at a time must now solve both equations simultaneously.

**Substitution**

Algebraic techniques help us solve systems of equations because we really do mean that the \(y\) in the first equation is the very same \(y\) in the second equation. Consider the following simplified case for a moment.

\(a = 5\)

\(b = 5\)

\(a = b\)

The same ** transitive property of equality** applies to systems of equations.

\(y = 0.5x + 100\)

\(y = -0.5x + 300\)

\(0.5x + 100 = -0.5x + 300\)

Now we have one equation with one unknown. Let’s solve it for \(x\)!

\(0.5x + 100 = -0.5x + 300\)

\(0.5x + 0.5x + 100 = -0.5x + 0.5x + 300\)

\(x + 100 = 300\)

\(x + 100 - 100 = 300 - 100\)

\(x = 200\)

And now that we’ve found \(x\), we can substitute the value back into one of the original equations to find \(y\).

\(y = 0.5 \cdot 200 + 100\)

\(y = 100 + 100\)

\(y = 200\)

We also could have gone with the other equation.

\(y = -0.5 \cdot 200 + 300\)

\(y = -100 + 300\)

\(y = 200\)

**Example 2.2 Predicting collision**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
global x
x += 1
shuttleY = 0.5 * x + 100
debrisY = -0.5 * x + 300
point(x, shuttleY)
point(x, debrisY)
# Predicted collision
stroke('red')
point(200, 200)
```

As you may expect, there’s more than one way to solve this problem. Let’s examine a different algorithm that combines equations to find solutions.

**Elimination and Back Substitution**

First, I’m going to determine the value of \(y\) by eliminating the variable \(x\) from an equation. Unlike the substitution algorithm, which rewrote one variable in terms of another, I’ll eliminate \(x\) by adding the top equation to the bottom equation. As usual, let’s motivate this idea by considering a simpler case. Take the equations below.

\(20 = 4 \cdot 5\)

\(2x = x + x\)

I could add the two left-hand sides to produce \(2x + 20\). On the right-hand side, I would have \(x + x + 4 \cdot 5\). But do these combined expressions equal each other? We’ll follow this one step-by-step.

\(2x + 20 = x + x + 4 \cdot 5\)

\(2x + 20 = x + x + 20\)

\(2x + 20 = 2x + 20\)

Those \(=\) symbols mean that the expressions on the left- and right-hand sides are equal. When we add the same thing to each side of an equation, we maintain equality. You may hear this called the ** additive property of equality** when you’re out at parties. Now, let’s use this property to eliminate the variable \(x\) and solve for \(y\).

\(y = 0.5x + 100\)

\(y = -0.5x + 300\)

\(y + y = -0.5x + 0.5x + 300 + 100\)

\(2y = 400\)

\(\frac{2y}{2} = \frac{400}{2}\)

\(y = 200\)

The \(y\)-value we just found resulted from combining information stored in separate equations. This is the \(y\)-value both equations share. But what about \(x\)? Well, we know that \(y = 200\), so let’s substitute that part of our solution back into the system.

\(200 = 0.5x + 100\)

\(200 - 100 = 0.5x + 100 - 100\)

\(100 = 0.5x\)

\(\frac{100}{0.5} = \frac{0.5x}{0.5}\)

\(200 = x\)

You’ve now seen two of many possible algorithms for solving systems of linear equations. Practice with them a bit before we build up the logical foundations you need to explore systems of linear *inequalities*.

** Exercise 2.5**
Solve the system of equations below using Substitution. Then, solve it using Elimination and Back Substitution. Describe how each algorithm works in plain English.

\(y = 0.25x + 100\)

\(y = -0.75x + 300\)

# 2.2 Logic

In the novel *1984*, the main character is brainwashed into accepting that \(2 + 2 = 5\) is true. The scene depicts the ultimate flex of power by an oppressive government. I have faith that you’re tough enough to always maintain your grasp on the truth. But let’s go ahead and lay some logical foundations anyway, you know, just in case.

## Boolean Algebra

You just tested a few different coordinate pairs \((x,y)\) to determine whether or not they solved an equation. The test could only have gone one of two ways: success or failure, yes or no, `True`

or `False`

. There is an entire branch of algebra called ** Boolean algebra** dedicated to studying these two

**, which we usually write as \(1\) (true) and \(0\) (false). There are not infinitely many truth values like there are numbers; there are only \(1\) and \(0\).**

*truth values*A truth value can correspond to a situation in the real world. For example, I could claim, “The sun is up”. This claim happens to be false in my neck of the woods as I write this sentence. I can express this idea using the variable \(s\) to represent sunniness.

\(s = 0\)

Even though the sun has already set on this particular day, the sky above me is still momentarily deep blue. I can claim “The sky is blue” and express this blueness, \(b\), matter-of-factly.

\(b = 1\)

OK, we have variables with assigned values. But what can we actually do with them?

Let’s begin by combining s and b using our first logical operation: ** conjunction**, also known as AND. The expression s∧b means “\(s\) is true AND \(b\) is true”. The sky above my front porch is blue, but the sun is not up, so the combined statement is false. We could write this concisely as \(s \land b = 0\).

There is a special set of diagrams called ** logic gates** that depict the results of applying logical operations. Each logic gate has a distinctive shape. Below is the diagram for the AND logic gate.

**Figure 2.4 The AND logic gate**

One of the variables \(s\) and \(b\) is true, and we can test for such a condition using the ** disjunction** operation, also known as OR. A disjunction is true if at least one of its operands is true. I could claim “The sun is up OR the sky is blue” and that would be true because \(b = 1\). We could express idea this as \(s \lor b = 1\).

Like AND, OR also has its own logic gate.

**Figure 2.5 The OR logic gate**

The following ** truth table** organizes all of the facts we’ve established about the view of the sky from my front porch.

**Table 2.1 A truth table’s view of my piece of sky**

\(s\) | \(b\) | \(s \land b\) | \(s \lor b\) |
---|---|---|---|

\(0\) | \(1\) | \(0\) | \(1\) |

The final logical operation we’ll discuss is ** negation**, also known as NOT. The NOT operation simply flips a truth value from \(1\) to \(0\) or from \(0\) to \(1\). Let’s take the variable \(s\) and negate it using the NOT operator, \(\lnot\).

\(s = 0\)

\(\lnot s = 1\)

NOT is a ** unary** operation, meaning we only apply it to a single truth value at a time. AND and OR are both

**operations, meaning we have to provide a pair of operands.**

*binary*Not to be left out, NOT also has its own logic gate.

**Figure 2.6 The NOT logic gate**

And that’s all you need to get started with logic! You can compose logical operations just like you do arithmetic operations. For example, let’s figure out how to cross the street safely using logic. I’ll define the variables \(l\) and \(r\) to represent vehicle traffic from the left and traffic from the right, respectively.

If you were trying to cross a busy street, you would want to avoid vehicles. In logical terms, you would check to see that both \(l = 0\) and \(r = 0\). “No vehicles on the left? No vehicles on the right? OK, let’s go!” This condition is easily expressed by combining operations \(\lnot l \land \lnot r = 1\).

** Exercise 2.6**
Complete the following truth table for two boolean variables \(x\) and \(y\).

\(x\) | \(y\) | \(x \land y\) | \(x \lor y\) |
---|---|---|---|

\(0\) | \(0\) | ||

\(0\) | \(1\) | ||

\(1\) | \(0\) | ||

\(1\) | \(1\) |

** Exercise 2.7**
Compute the value of the expression \(\lnot (1 \land 1)\).

** Exercise 2.8**
Compute the value of the expression \((1 \land 0) \lor (1 \lor 0)\).

** Exercise 2.9**
Rewrite the following ** logic circuit** as an equivalent logical expression.

** Exercise 2.10**
Complete the following truth table for two boolean variables \(x\) and \(y\). What do you notice?

\(x\) | \(y\) | \(\lnot (x \land y)\) | \(\lnot x \lor \lnot y\) | \(\lnot (x \lor y)\) | \(\lnot x \land \lnot y\) |
---|---|---|---|---|---|

\(0\) | \(0\) | ||||

\(0\) | \(1\) | ||||

\(1\) | \(0\) | ||||

\(1\) | \(1\) |

## Branching

Logic is a big deal for computation, from the way the machines are physically built to the way we program them. ** Conditional statements** let us test conditions and make decisions while a program executes. For example, let’s revisit the collision scene from

*Gravity*.

**Example 2.3 Collision revisited**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
global x
x += 1
shuttleY = 0.5 * x + 100
debrisY = -0.5 * x + 300
point(x, shuttleY)
point(x, debrisY)
```

The simulation works fine, but it doesn’t really convey the full drama of the situation. Let’s revise our system a bit to account for the additional debris generated upon collision.

**
A Space Shuttle and debris in Earth’s orbit.**

**\(\mapsto\)**
Outer space is an empty, infinite, two-dimensional surface. The Space Shuttle is a point moving along the straight path described by the equation \(y = 0.5x + 100\). The debris is also a point moving along a straight path, this one described by the equation \(y = -0.5x + 300\). *After colliding, each object leaves a trail of smaller debris along its path*.

**
The coordinates of both objects are ordered pairs of floating point numbers. The Space Shuttle’s initial position is \((0,300)\). The debris’ initial position is \((0,100)\).**

**
First, test for collision and set the alpha value for the sky. Then, paint the sky. Next, select a pencil color & weight. After that, update the position of each object. Finally, draw a point at each object’s position.**

Lucky for us, you already solved this system and know that the two objects collide at \((200,200)\). As the sketch continues running, the Shuttle and debris continue moving to the right. We can test for this using an ** if statement**.

```
if condition:
# things to do if condition is true
```

If statements present a logical crossroads in a program. The first line of the if statement is called a ** header**. The header begins with if, defines the condition to test, and ends with a colon :. If the condition is true, Python will execute the set of statements indented beneath the header, also known as the if statement’s

**.**

*body*```
if condition:
thing_one() # this is part of the body
thing_two() # this too!
thing_three() # this is not
```

In the *Gravity* example, we’re testing whether or not the value of the variable `x`

is greater than `200`

. Python has the following relational operators that work as you would expect for numbers.

**Table 2.2 Python’s relational operators**

\(Math\) | `Code` |
English |
---|---|---|

\(=\) | `==` |
Equal to |

\(\ne\) | `!=` |
Not equal to |

\(>\) | `>` |
Greater than |

\(<\) | `<` |
Less than |

\(\ge\) | `>=` |
Greater than or equal to |

\(\le\) | `<=` |
Less than or equal to |

Applying a relational operator produces a boolean value. For example, the expression `2 + 2 == 5`

produces the boolean value `False`

because, well, math. `2 + 2 == 4`

, on the other hand, produces the value `True`

. These sorts of logical expressions are called ** boolean expressions**.

```
if x > 200:
# things to do if x > 200
```

**Example 2.4 A more impactful collision**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
global x
x += 1
shuttleY = 0.5 * x + 100
debrisY = -0.5 * x + 300
alpha = 255
if x > 200:
alpha = 10
background(25, 25, 112, alpha)
stroke('ghostwhite')
strokeWeight(5)
point(x, shuttleY)
point(x, debrisY)
```

** Exercise 2.11**
Duplicate your original collision sketch and add a few effects. How should the visual appearance of the Shuttle and debris change after impact?

You can also test multiple conditions together. Thinking back to the meteor sketch, how about we make the meteor glow red as it passes over the middle half of the canvas? In other words, when \(x \ge 100\) AND \(x \le 300\).

```
if x >= 100 and x <= 300:
stroke('tomato')
```

`and`

is one of Python’s boolean operators along with `or`

and `not`

. These Python operators function identically to the logical operators you just studied.

Recall our earlier \(2 + 2\) example from the novel *1984*. Notice you can test for the same condition using different boolean operators.

```
if not 2 + 2 == 4:
backup_plan()
```

**Example 2.5 A colorful meteor**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background(25, 25, 112, 15)
stroke('ghostwhite')
strokeWeight(5)
global x
x += 1
y = 0.5 * x + 50
if x >= 100 and x <= 300:
stroke('tomato')
point(x, y)
```

Reading through this code, it isn’t immediately clear that `ghostwhite`

is meant to be the default stroke color. You could make this more explicit by adding an ** else clause** to your conditional statement. Here is an example of the syntax.

```
if condition:
# things to do if condition is true
else:
# things to do if condition is false
```

The conditional statement now has two distinct pathways, or ** branches**, that may be followed depending on the truth value of the condition.

**Figure 2.7 Flow of execution with two branches**

You could reorganize your sketch to reflect this structure like so.

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background(25, 25, 112, 15)
global x
x += 1
y = 0.5 * x + 50
if x >= 100 and x <= 300:
stroke('tomato')
else:
stroke('ghostwhite')
strokeWeight(5)
point(x, y)
```

At this point, you might say, “Branches seem useful, but what if I want more than two in my program?” Say no more! You can ** chain** conditionals together using an

`elif`

statement (a combination of “else” and “if”). In a **, conditions are tested in the order they are written, and only the first branch whose condition is**

*chained conditional*`True`

will execute.```
if condition1:
thing_one()
elif condition2:
thing_two()
else:
thing_three()
```

**Example 2.6 A multicolor meteor**

```
x = 0
def setup():
createCanvas(400, 400)
def draw():
background(25, 25, 112, 15)
global x
x += 1
y = 0.5 * x + 50
if x < 100:
stroke('ghostwhite')
elif x < 300:
stroke('tomato')
else:
stroke('crimson')
strokeWeight(5)
point(x, y)
```

** Exercise 2.12**
Change the previous example so that the following conditions are tested in this order. Can you explain what happened?

```
if x >= 100:
stroke('tomato')
elif x >= 300:
stroke('crimson')
else:
stroke('ghostwhite')
```

** Exercise 2.13**
Duplicate one of your previous sketches and modify its behavior using conditional statements. Use at least one other relational and one other boolean operator.

# 2.3 Iteration

The logical building blocks you assembled in the last two sections let you create branches and make decisions in your programs. In this section, we’ll use many of the same building blocks to form another type of control flow: repetition.

`while`

statements

In Exercise 1.18, you drew a constellation by calling the `point()`

function repeatedly with different arguments. Let’s revisit this exercise using the constellation Orion as a starting point. We’ll focus on Orion’s Belt, which consists of the stars Alnitak, Alnilam, and Mintaka.

**
Orion’s Belt**

**\(\mapsto\)**
Outer space is an empty, infinite, two-dimensional surface. Stars are points of light within this plane.

**
Star coordinates are ordered pairs of floating point numbers.**

**Table 2.3 The “Orion’s Belt” data set**

Star Name | \(x\) | \(y\) |
---|---|---|

Alnitak | 50 | 200 |

Alnilam | 200 | 200 |

Mintaka | 350 | 200 |

**
First, paint the night sky. Then, select a pencil color & weight. Finally, draw a point at each star’s position.**

**Example 2.7 Orion’s Belt**

```
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
point(50, 200) # Alnitak
point(200, 200) # Alnilam
point(350, 200) # Mintaka
```

The stars Alnitak and Mintaka are actually star systems; each system is made up of multiple stars orbiting one another. I’ll use this fact as my creative license to adjust Orion’s Belt a little. For starters, how about we draw Orion’s Belt with all of the major stars in each system? Let’s keep things simple by assuming all of the stars are the same size and are aligned horizontally in the sky.

**Table 2.4 Expanded “Orion’s Belt” data set**

Star Name | \(x\) | \(y\) |
---|---|---|

Alnitak Aa | 50 | 200 |

Alnitak Ab | 100 | 200 |

Alnitak B | 150 | 200 |

Alnilam | 200 | 200 |

δ Ori Aa1 | 250 | 200 |

δ Ori Aa2 | 300 | 200 |

δ Ori Ab | 350 | 200 |

**Example 2.8 Adjusting Orion’s Belt**

```
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
point(50, 200) # Alnitak Aa
point(100, 200) # Alnitak Ab
point(150, 200) # Alnitak B
point(200, 200) # Alnilam
point(250, 200) # δ Ori Aa1 (in the Mintaka star system)
point(300, 200) # δ Ori Aa2 (in the Mintaka star system)
point(350, 200) # δ Ori Aab (in the Mintaka star system)
```

The visual result looks good, but the code worries me a little. Notice that I wrote seven nearly identical copies of the same statement to draw the stars. This approach works fine to get started but imagine writing a program that needs to repeat an instruction dozens of times. Or millions of times. Writing each variant by hand would be tedious and error prone. Python’s ** while statement** makes repetition, or

**, simple.**

*iteration*```
while condition:
# this is the loop body
# statements in here repeat while condition is true
thing_one()
thing_two()
```

`while`

statements are structured similarly to if statements; they have a header with a condition and a body with code that might be executed. Each statement in the body executes in order, from top to bottom, repeatedly, until the condition in the header is false. Iterative control structures like this are commonly known as ** loops**.

**Figure 2.8 Flow of execution in a while loop**

Let’s use a `while`

loop to simplify our sketch of Orion’s Belt. Reviewing the previous example, the only difference between the stars is their \(x\)-coordinates. We know where our \(x\)-coordinates start, where they stop, and how much space is between them. This is all the information we need to simplify our work by using a loop.

**Example 2.9 Orion’s Belt with iteration**

```
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
x = 50 # first x
while x <= 350: # last x
point(x, 200)
x += 50 # spacing
```

Not too shabby! Given an initial value for `x`

, the `while`

statement draws a point, then increments `x`

by `50`

, and repeats this process until `x`

is greater than `350`

.

We could change one line of code from the previous example to pack twice as many stars in the same region of sky.

**Example 2.10 Bedazzling Orion’s Belt**

```
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
x = 50
while x <= 350:
point(x, 200)
x += 25 # less space between stars
```

** Exercise 2.14**
Modify the sketch above to draw a row of stars in a different arrangement. What is the initial value of your loop variable x? What condition do you test to end the loop’s execution? How much do you increment x by during each iteration?

You might say, “OK, but what if I turned my head a little? Could I draw the stars along a vertical line instead?” Sure! In this case, you could keep the value of `x`

constant while varying `y`

.

**Example 2.11 Switching axes from \(x\) to \(y\)**

```
def setup():
createCanvas(400, 400)
def draw():
background('midnightblue')
stroke('ghostwhite')
strokeWeight(5)
y = 50 # vary y instead
while y <= 350:
point(200, y)
y += 25
```

## Infinite Loops

`while`

statements are powerful tools that should be used with care. Consider the example below.

```
while True:
thing_one()
thing_two()
```

`True`

is a keyword in Python that corresponds to a boolean value of, you guessed it, true. If a `while`

statement’s condition is always true, then it will continue looping forever, thus creating an ** infinite loop**. Unintended infinite loops are bad news. Let’s examine a slightly modified version of the loop from the previous sketch.

```
y = 50
while y <= 350:
point(200, y)
y += 25 # oops
```

Notice that I incremented `y`

outside of the indented loop body. This means that `y`

isn’t incremented after each iteration. Instead, the value of `y`

will always be `50`

, which is always less than or equal to `350`

, so the condition `50 <= 350`

is always true. The loop never stops executing! If you ran this code, your web browser might give you a friendly notification to stop the sketch before it grinds your computer to a halt.

** Exercise 2.15**
The code snippet below is meant to draw a horizontal row of points across the canvas. Instead, it creates an infinite loop. Identify the error and fix it. Explain the problem and your solution in plain English.

```
x = 0
y = 200
while x < 400:
point(x, y)
x = 20
```

** Exercise 2.16**
Create a sketch that uses a `while`

statement to draw points along a diagonal line. In the following code snippet, replace the comment beginning with `# >>`

with the appropriate code.

```
x = 0
while x < 400:
# >> compute y here
point(x, y)
x += 20
```

** Exercise 2.17**
In Chapter 1, we defined an algorithm for multiplying two integers \(a \cdot b\) as repeated addition \(b + b + ... + b\). Fill in the missing code below to express the same algorithm in Python using a `while`

statement.

```
a = 5
b = 3
product = 0
i = 0
while i < a:
# >> compute product here
i += 1
```

** Exercise 2.18**
Review the algorithms for integer division and exponentiation, then implement them in Python using a `while`

statement. The *subtraction assignment*`-=`

and *multiplication assignment*`*=`

operators might be helpful.

# 2.4 Systems of Inequalities

We began this chapter by analyzing a single linear equation in slope-intercept form: \(y = mx + b\). You could substitute any real number for \(x\) and compute the corresponding value of \(y\), making the ordered pair \((x,y)\) a solution to the equation. Let’s review a concrete example.

Given the following linear equation

\(y = 0.5x + 200\)

compute the value of \(y\) when \(x = 100\).

\(y = 0.5 \cdot 100 + 200\)

\(y = 50 + 200\)

\(y = 250\)

One solution to this equation is located at \((100,250)\). What if we tried \((100,251)\) instead?

\(251 = 0.5 \cdot 100 + 200\)

\(251 = 50 + 200\)

\(251 \ne 250\)

It turns out \((100,251)\) is not a solution to this particular equation, but there *are* infinitely many other solutions. For example, we could find solutions to the left and right of \((100,250)\) at \(x = 99\) and \(x = 101\).

\(y = 0.5 \cdot 99 + 200\)

\(y = 49.5 + 200\)

\(y = 249.5\)

\(y = 0.5 \cdot 101 + 200\)

\(y = 50.5 + 200\)

\(y = 250.5\)

You could use a `while`

statement to quickly compute and visualize all of the solutions in the interval \(0 \le x \le 400\).

**Example 2.12 Visualizing solutions to a linear equation**

```
def setup():
createCanvas(400, 400)
def draw():
background('silver')
stroke('black')
x = 0
while x < 400:
y = 0.5 * x + 200
point(x, y)
x += 1
```

## Testing Solutions

OK, the solutions to a linear equation generate a line. I wonder what shapes other linear relationships make. Let’s take the previous example and swap out the \(=\) symbol for a \(>\).

\(y > 0.5x + 200\)

You can test solutions to this ** linear inequality** just as you did with linear equations. For example, let’s see if the coordinate pair \((100,250)\) produces a truth value of 1 when we substitute the values into our inequality.

\(250 > 0.5 \cdot 100 + 200\)

\(250 > 50 + 200\)

\(250 > 250\)

Uh oh. We evaluated the right-hand side of the inequality and produced a value of \(250\). But that resulted in a false statement; \(250\) is not greater than itself. We can conclude that \((100,250)\) isn’t a solution to this inequality. How about we move along the \(y-axis\) a little to \((100,251)\)?

\(251 > 0.5 \cdot 100 + 200\)

\(251 > 50 + 200\)

\(251 > 250\)

Success! Let’s go a little further along the \(y\)-axis to \((100,252)\).

\(252 > 0.5 \cdot 100 + 200\)

\(252 > 50 + 200\)

\(252 > 250\)

Interesting. Let’s try one more coordinate pair \((100,253)\) to see if this pattern holds.

\(253 > 0.5 \cdot 100 + 200\)

\(253 > 50 + 200\)

\(253 > 250\)

When \(x = 100\), we can pair it with any \(y > 250\) to solve the inequality \(y > 0.5x + 200\). You could automate this sort of test with a `while`

statement.

**Example 2.13 Testing solutions to a linear inequality**

```
def setup():
createCanvas(400, 400)
def draw():
background('silver')
x = 100
y = 0
while y < 400:
if y > 0.5 * x + 200:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1
```

The sketch above fixes the value of `x`

at `100`

and tests solutions to the inequality for all `y`

values in the interval \(0 \le y < 400\). Solutions along this column are colored `black`

while other points are colored `ghostwhite`

.

This is the first example we’ve seen of a `while`

statement that includes an `if`

statement in its body. You can put (almost) whatever code you want in the body of a `while`

statement: function calls, arithmetic operations, `if`

statements, and even other `while`

statements. This last option opens up many interesting possibilities.

## Nested Loops

You just tested hundreds of possible solutions to the inequality \(y > 0.5x + 200\) when \(x\) was fixed at \(100\). Let’s fully automate the process of testing solutions by iterating over the canvas’ \(x\)-axis just like we’re doing with its \(y\)-axis.

A quick note about the algorithm we are about to run: it is *very* inefficient and would normally grind your computer to a halt. By default, p5 executes each statement you place in the body of the `draw()`

function in order, from top to bottom, repeatedly, about \(60\) times per second. Behind the scenes, you can imagine that the code you write in `draw()`

is executing in the body of a `while`

statement.

```
setup() # all of your code bundled up
while True:
draw() # all of your code bundled up
```

Testing individual solutions to a linear inequality requires computing once on each \((x,y)\) coordinate pair before drawing a point on the canvas. The algorithm is slow and produces the same results every time, so there is no need to repeat it!

In the next example and those that follow, I will call the `noLoop()`

function once in `setup()`

like so.

```
def setup():
createCanvas(400, 400)
noLoop()
```

By calling `noLoop()`

, you change p5’s behavior so that `draw()`

only executes a single time. You can imagine p5 running the following code instead.

```
setup() # all of your code bundled up
draw() # all of your code bundled up
```

Now, we can compute once on each \((x,y)\) coordinate pair, draw the corresponding point, and produce a single image. This adjustment should keep your computer happy, but it may still take a moment for the result to appear.

**Example 2.14 Visualizing a linear inequality**

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('silver')
x = 0
while x < 400: # == start outer loop ==
y = 0
while y < 400: # ** start inner loop **
if y > 0.5 * x + 200:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1 # ** end inner loop **
x += 1 # == end outer loop ==
```

The control structure you just created is called a ** nested loop**. The

**increments the variable**

*outer loop*`x`

while the **increments the variable**

*inner loop*`y`

and tests for solutions along each column of your canvas. And the result of all that computation? It turns out the set of \((x,y)\) coordinate pairs that solve our inequality, known as the solution set, forms a triangle-shaped region with the edges of the canvas. Neat! Can we make a rectangle?**Example 2.15 The rectangle inequality**

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('silver')
x = 0
while x < 400:
y = 0
while y < 400:
if y > 200:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1
x += 1
```

** Exercise 2.19**
Modify the previous example to draw a new five-sided shape with your solution set. Closed shapes made by connecting three or more straight lines are known as ** polygons**, and a five-sided polygon is known as a

**.**

*pentagon*** Exercise 2.20**
Ellsworth Kelly’s “Austin” is a serene little chapel located on the campus of the University of Texas at Austin. Its walls feature a series of fourteen black and white marble panels that look suspiciously like linear inequalities. Use Kelly’s panels as inspiration for your own series of abstract images. How many images will you include in your series? What colors will you use? What shapes will you create?

Drawing with linear inequalities opens up a dizzying number of creative possibilities. But what if you wanted to draw a rectangle in the middle of your canvas? Meeting this challenge requires expanding our modeling toolkit yet again.

## Solving Systems

When you solved your first system of linear equations, you found the point \((x,y)\) where two lines intersected. In other words, you found the only ordered pair \((x,y)\) that solved both equations simultaneously. We’ll follow a very similar train of thought to solve ** systems of linear inequalities**.

For starters, let’s try consider the system \(y > -x + 300\) and \(y < 150\). We can test possible solutions \((x,y)\) against both inequalities using the `and`

operator.

**Example 2.16 A system of linear inequalities**

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('silver')
x = 0
while x < 400:
y = 0
while y < 400:
if y > -x + 300 and y < 150:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1
x += 1
```

OK, but how would we draw that rectangle in the middle of the canvas? You can think of a rectangle as the set of points between a pair of \(x\)-values and a pair of \(y\)-values. For example, we could take all of the points where \(x > 150\) AND \(x < 250\) AND \(y > 275\) AND \(y < 325\).

**Example 2.17 A more constrained system**

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('gainsboro')
x = 0
while x < 400:
y = 0
while y < 400:
if x > 150 and x < 250 and y > 275 and y < 325:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1
x += 1
```

At this point you might say, “This is great! But how do I draw multiple shapes?” Simple: define multiple systems of inequalities. I’d like to frame this part of the discussion by studying the work of another abstract painter, Piet Mondrian.

**Figure 2.9 “Composition II in Red, Blue, and Yellow” Courtesy Wikimedia Foundation**

**
The painting “Composition II”**

**\(\mapsto\)**
Each colored region is the solution set to a system of linear inequalities.

**
The boundaries for each system of inequalities are either vertical or horizontal lines.**

**Table 2.5 The “Composition II” data set**

Name | Left \(x\) | Right \(x\) | Bottom \(y\) | Top \(y\) |
---|---|---|---|---|

Blue corner | 0 | 70 | 0 | 90 |

Yellow corner | 375 | 400 | 0 | 35 |

Red corner | 80 | 400 | 100 | 400 |

Stripe 1 | 70 | 80 | 0 | 400 |

Stripe 2 | 0 | 70 | 255 | 280 |

Stripe 3 | 0 | 400 | 90 | 100 |

Stripe 4 | 365 | 375 | 0 | 90 |

Stripe 5 | 375 | 400 | 35 | 55 |

**
First, prime the canvas by painting it **`ghostwhite`

. Next, select the paint color by testing whether a point solves a system of inequalities. Finally, paint the point. Repeat for every point on the canvas.

**Example 2.18 “Composition II”**

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('ghostwhite')
x = 0
while x < 400:
y = 0
while y < 400:
if x >= 0 and x < 70 and y >= 0 and y < 90:
stroke('royalblue')
elif x >= 375 and x < 400 and y >= 0 and y < 35:
stroke('yellow')
elif x >= 80 and x < 400 and y >= 100 and y < 400:
stroke('orangered')
elif x >= 70 and x < 80 and y >= 0 and y < 400:
stroke('black')
elif x >= 0 and x < 70 and y >= 255 and y < 280:
stroke('black')
elif x >= 0 and x < 400 and y >= 90 and y < 100:
stroke('black')
elif x >= 365 and x < 375 and y >= 0 and y < 90:
stroke('black')
elif x >= 375 and x < 400 and y >= 35 and y < 55:
stroke('black')
else:
stroke('ghostwhite')
point(x, y)
y += 1
x += 1
```

** Exercise 2.21**
Spend a few minutes exploring WikiArt and find an abstract painting or painter who inspires you. Hilma af Klint and Mark Rothko are personal favorites of mine. Then, create a new sketch that uses systems of inequalities to draw your own abstraction. Is your sketch completely abstract or is it based on an object, place, emotion, etc.? What do you like most about your sketch? What was challenging about creating it?

** Exercise 2.22**
Visualize integer multiplication by building on your solution to Exercise 2.17. Use the starter code below to snap (very tiny) blocks together.

```
def setup():
createCanvas(400, 400)
noLoop()
def draw():
background('darkorchid')
stroke('floralwhite')
# compute and visualize product
a = 30
b = 50
product = 0
i = 0
while i < a:
# >> compute product here
j = 0
while j < b:
# >> draw "blocks" here using point()
# >> watch out for infinite loops!
i += 1
# draw label
noStroke()
fill('floralwhite')
text(product, a, b)
```

The `noStroke()`

function removes edges p5 draws around text; doing so can make it easier to read some fonts. The `fill()`

function sets the interior color of text. Note that the `text()`

function takes three arguments: the text to be displayed, and the \(x\)- and \(y\)-coordinates where the text should appear.

The control structures you just studied make it possible to construct many useful computations. In the next chapter, we’ll raise the level of abstraction by bundling computations into functions you define. We’ll also have fun drawing with the many built-in shapes that p5 provides.

# Reference

*Intermediate Algebra 2e*/ Chapter 3*Precalculus*/ Chapter 9

This book’s text and images are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

This book’s code examples are licensed under the MIT License.