Discussion 3: Loop Invariants
The goal of today’s discussion is to practice writing “loopy” code using the tools from last Thursday’s lecture: array diagrams and loop invariants. Becoming more comfortable with these tools will help you design loops in a more principled way that lets you get the code right on the first try, saving debugging time. In addition, we’ll continue to use the language of loop invariants throughout the course as we discuss more complicated methods. During this discussion, you’ll develop three different “loopy” methods from their specifications.
Learning Outcomes
- Describe the loop invariant of an iterative method involving an array and visualize it using a diagram.
- Use an array diagram to develop an iterative method.
Reminder: Discussion Guidelines
The work that you complete in discussion serves as a formative assessment tool; it offers the opportunity to assess your understanding of the material and for our course staff to get a “pulse” on how things are going, so we can make adjustments in future classes. Your grade in discussion is based on your attendance, active participation, and completion of that day’s activity. More information about the grading and expectations can be found in the syllabus.
Since discussion activities are not graded for correctness, we do not restrict what resources you may use to complete them, which include notes, books, unrestricted conversations with other students, internet searches, and the use of large language models or other generative AI. We advise you to be pragmatic about your use of these resources and think critically about whether they are enhancing your learning. Discussion activities are intended to serve as “strength training” for programming tasks we will expect on assignments and exams (and that you will encounter in future courses and careers), and their main benefit comes from thinking critically to “puzzle” them out.
double[] array of sensor measurements. We expect all of the readings to be non-negative; however, occasionally the sensor will record a spurious negative value. To "clean" the data, we'd like to "clip" these negative values, replacing them with 0. For example, the array
cleanData() to carry out this operation.
|
|
|
|
Throughout the method, we’ll use the loop variable i to keep track of the index of the next array entry that we will inspect. Let’s suppose that we want to carry out the cleaning from right to left.
How should we initialize i?
What should our loop guard be to ensure that we exit the loop immediately after inspecting all of the array entries?
cleanData().
Use your answers from parts (a) and (b) to write the definition of the cleanData() method.
Add a comment above the loop documenting the loop invariant. Then, fill in the loop body.
ints is a mountain if its entries (weakly) increase to the array's maximum value and then (weakly) decrease after this. More concretely, an array int[] nums is a mountain if there is some index i with 0 <= i < nums.length for which nums[..i] is a non-decreasing sequence and nums[i..] is a non-increasing sequence. For example,
i = 3. However,
isMountain() that determines whether a given int[] array is a mountain.
|
|
|
|
In addition to a loop index variable j, what other variables will you need to keep track of our progress as we traverse the array? (Hint: Our solution uses one additional boolean variable).
return conditions: reaching the end of the array and certifying that it is a mountain, versus detecting that the array is not a mountain and returning early.
Using the “Pre” diagram, how should we initialize the loop variables? Briefly explain why your initialization makes the loop invariant true at the start of the loop.
What should be our loop guard? When we exit from the loop, what will our return value be?
Use your answers from parts (c) and (d) to set up your loop in the isMountain() method. Add a comment above the loop documenting the loop invariant. Then, fill in the loop body.
ints into three segments by comparing them to a pivot, another special int value. We'll move all the entries that are less than the pivot to the beginning of the array, followed by all the entries that are equal to the pivot, followed by all the entries that are greater than the pivot. Soon in lecture, we'll see that this type of pivot partitioning forms the basis for the Quicksort sorting algorithm.
|
|
|
|
int loop variables (i, j, and k) and the following loop invariant:
i, j, and k.
Within the while loop of the partition3Way() method, we’ll start by reading the value of nums[i]. For each of the following cases, describe what must be done in the loop body to make progress and restore the loop invariant.
nums[i] < pivot:
nums[i] == pivot:
nums[i] > pivot:
Use your answers from parts (a), (b), and (c) to write the definition of the partition3Way() method. Be sure to document your loop invariant (using proper range notation) in a multi-line comment above the loop declaration.
Submission
At the end of class, your group’s primary author should create a PDF with your written answers to Exercises 1-3 and upload this to the “Discussion 3” Gradescope assignment, tagging all other members of the group onto the submission. If you need any help with this process, be sure to call over the TA. This is the same process that you’ll be using to submit your homework assignments.