CS 15-122: Principles of Imperative Computation
(Fall 2021)


Course Information  [  Logistics  |  Calendar of Classes  |  Coursework Calendar  |  Office Hours  ]




(Your comments will be sent anonymously to the instructors)

Logistics

Labs: M,  between 8:00am and 6:35pm ET  (varies by section)
Lectures: TR,  08:35-9:55am ET (MI MELLON)
or  TR,  10:10-11:30 ET  (MI MELLON)
Recitations: F,  between 8:00am and 6:35pm ET  (varies by section)
Class web page: https://cs.cmu.edu/~15122
Course syllabus

Calendar of Classes [iCal format]

Click on a class day to go to that particular lecture or recitation. Due dates for homeworks are set in bold. The due date of the next homework blinks.

August 2021
UMTWRFS
1234567
891011121314
15161718192021
22232425262728
293031    
       
September 2021
UMTWRFS
   1234
567891011
12131415161718
19202122232425
2627282930  
       
October 2021
UMTWRFS
     12
3456789
10111213141516
17181920212223
24252627282930
31      
November 2021
UMTWRFS
 123456
78910111213
14151617181920
21222324252627
282930    
       
December 2021
UMTWRFS
   1234
567891011
12131415161718
19202122232425
262728293031 
       

Coursework Calendar

Test
Percentage
learn. obj
Wr1
1.7%
1-3,11
Pg1
2.5%
1,12
Wr2
1.7%
1-3
Pg2
2.5%
12,15,16
Wr3
1.7%
1,2,4,12
Pg3
2.5%
1,12-16
Wr4
1.7%
1-4,21,27
Pg4
2.5%
1,18,17
Wr5
1.1%
6-10,15-17
Midterm1
12.5%
1-8
Wr6
1.7%
6-8,12,17
Pg5
2.5%
5,12,27
Wr7
1.7%
9,17,24,27
Pg6
2.5%
10
Posted30 Aug2 Sep6 Sep9 Sep13 Sep16 Sep20 Sep23 Sep27 SepThu
7 Oct
4 Oct7 Oct11 Oct14 Oct
Due
(9pm)
Mon
6 Sep
Thu
9 Sep
Mon
13 Sep
Thu
16 Sep
Mon
20 Sep
Thu
23 Sep
Mon
27 Sep
Thu
30 Sep
Mon
4 Oct
Mon
11 Oct
Fri
15 Oct
Mon
18 Oct
Thu
21 Oct
Corrected7 Sep11 Sep14 Sep18 Sep21 Sep25 Sep28 Sep2 Oct5 Oct11 Oct12 Oct16 Oct19 Oct23 Oct
Test
Percentage
learn. obj
Wr8
1.7%
12,24,27
Pg7
2.5%
8,10-18
Wr9
1.1%
9,10,25-27
Midterm2
12.5%
1-8
Pg8
2.5%
9,12-18
Wr10
1.7%
2,13,25,27
Pg9
2.5%
10,15-20
Wr11
1.7%
18-20
Pg10
2.5%
5,15-20
Wr12
1.7%
19,20
Pg11
2.5%
5,15-20
Final
25%
1-27
Posted18 Oct21 Oct25 OctThu
4 Nov
1 Nov4 Nov8 Nov11 Nov15 Nov18 Nov15 NovMon
6 Dec
(8:30-11:30)
Due
(9pm)
Mon
25 Oct
Thu
28 Oct
Mon
1 Nov
Mon
8 Nov
Thu
11 Nov
Mon
15 Nov
Thu
18 Nov
Mon
22 Nov
Mon
29 Nov
Thu
2 Dec
Corrected26 Oct30 Oct2 Nov8 Nov13 Nov12 Nov17 Nov19 Nov24 Nov30 Nov4 Dec13 Dec

Office Hours [iCal format]

Office hour rules:

About this course  [  Description  |  How to Do Well  |  Resources  |  Grading  |  Academic Integrity  |  Policies  |  Help  |  Learning Objectives  ]

Description[–]

This course teaches imperative programming in a C-like language and methods for ensuring the correctness of imperative programs. It is intended for students who are familiar with elementary programming concepts such as variables, expressions, loops, arrays, and functions. Given these building blocks, students will learn the process and techniques needed to go from high-level descriptions of algorithms to correct imperative implementations, with specific applications to basic data structures and algorithms. Much of the course will be conducted in a subset of C amenable to verification, with a transition to full C near the end. This will be accomplished along three dimensions: After completing 15-122, you will be able to take 15-213 (Introduction to Computer Systems), 15-210 (Parallel and Sequential Data Structures and Algorithms) and 15-214 (Principles of Software System Construction). Other prerequisites or restrictions may apply.

Prerequisites

You must have gotten a 5 on the AP Computer Science A exam or passed 15-112 (Fundamentals of Programming) or equivalent. You may also get permission from an advisor if you performed very high on the CS Assessment on Canvas.
It is strongly advised that you either have taken or take at the same time either 21-127 (Concepts of Mathematics) or 15-151 (Mathematical Foundations of Computer Science): historically, students who did not do so ended up learning less, spending considerably more time on the course and earning one letter grade lower than their peers who did, on average.

Past Offerings

2021 2020 2019 2018 2017 2016 2015 2014 2013 2012 2011 2010
Fall F'21 F'20 F'19 F'18 F'17 F'16 F'15 F'14 F'13 F'12 F'11 F'10
Summer N'21 N'20 N'19 N'18 N'17 N'16 M'15 M'14 M'13 M'12 S'11
Spring S'21 S'20 S'19 S'18 S'17 S'16 S'15 S'14 S'13 S'12 S'11

How to do Well in this Course[–]

Our goals are for you to succeed in this course and to teach you skills and concepts that will contribute to your success in life. To this end, we are providing you with lots of resources and the knowledge that comes from years of experience. Talking to some of the thousands of students who took this course before you, here's some advice that they found particularly useful:

Feedback

It is our goal to make this course successful, stimulating and enjoyable. If at any time you feel that the course is not meeting your expectations or you want to provide feedback on how the course is progressing for you, please contact us. If we are not aware about a problem, we won't know to fix it. If you would like to provide anonymous comments, please use the feedback form on the course home page or slide a note under our doors.

Resources[–]

Course Material

There is no textbook for this course. Lecture notes and other resources are provided through the Schedule tab of this page and on Diderot. We do not require students to read lecture notes before lecture, but those who are interested in reading ahead can certainly do so.

The C0 Language

In the first nine weeks, the course uses C0, a safe subset of C augmented with contracts. This language has been specifically designed to support the learning objectives in this course. It provides garbage collection (freeing students from dealing with low-level details of explicit memory management), fixed range modular integer arithmetic (avoiding complexities of floating point arithmetic and multiple data sizes), an unambiguous language definition (guarding against undefined behavior), and contracts (making code expectations explicit and localizing reasoning).

The C Language

In the last four weeks, the course transitions to C in preparation for subsequent systems courses. Emphasis is on transferring positive habits developed with the use of C0, and on practical advice for avoiding the pitfalls and understanding the idiosyncrasies of C. We use the valgrind tool to test proper memory management.

Programming Environments

You are welcome to use any programming environment that suits you to write your programming assignments. However, all programming homework will be graded by running them on a Unix system using Autolab — you may want to make sure they work on Andrew Unix. Popular environment choices include emacs, vim, VSCode, and sublime, but you should use what works for you: an environment that allows you to write code quickly and efficiently. Here are some useful links:
UnixEmacsVim

Grading[–]

This is a 10 unit course.

Tasks and Percentages

We are aiming to have homework and exams graded within two days of submission.

Accessing and Monitoring your Grades

Posted grades are accessible by clicking on the Grades tab of this page. After authenticating, you will be able to see your current grades and a projection of where you are headed given your past performance in the class. Use this application to take action if the trajectory does not lead to the grade you are hoping for.

Evaluation Criteria

Your assignments and exams are evaluated on the basis of:

Late Policy

This is a fast-paced course. The late policy has the purpose to help students from falling behind. Aside from this, there will be no extensions on assignments in general. If you think you really really need an extension on a particular assignment, contact the instructors as soon as possible and before the deadline. Please be aware that extensions are entirely discretionary and will be granted only in exceptional circumstances outside of your control (e.g., due to severe illness or major personal/family emergencies, but not for competitions, club-related events or interviews). The instructors will require confirmation from University Health Services or your academic advisor, as appropriate.

Nearly all situations that make you run late on an assignment homework can be avoided with proper planning — often just starting early. Here are some examples:

Grade Appeals

We make mistakes too!
After each exam and homework assignment is graded, you will be able to access your score by clicking on the Grades tab of this page. We will make the utmost effort to be fair and consistent in our grading. If you notice any grading mistakes, proceed as follows: Email requests to the course staff will not be accepted. Please do not make regrade requests on Diderot.

All regrade requests must be received within 5 days of the work being handed back on Gradescope or Autolab, which we will announce in a Diderot post.

Final Grades

This class is not curved. However, to ensure consistency across semesters, we set our grading standards in such a way as to compensate for the relative difficulty of exams.

What follows is a rough guide to how course grades will be established, not a precise formula — we will fine-tune cutoffs and other details as we see fit after the end of the course. This is meant to help you set expectations and take action if your trajectory in the class does not take you to the grade you are hoping for (see also the Grades tab on this page). So, here's a rough, very rough heuristics about the correlation between final grades and total scores:

This assumes that the makeup of a student’s grade is not wildly anomalous: exceptionally low overall scores on exams, programming assignments, or written assignments will be treated on a case-by-case basis. In particular, students who are unable to demonstrate a basic proficiency with the C language in the last few programming assignments will receive a D in the class (this is because 15-122 is a prerequisite to 15-213, a very C-intensive course). For reference, almost a quarter of the students who received a B in Fall 2014 had a 90-100% average on programming assignments, an 80-90% average on written homeworks, and a 70-80% average on exams.

Precise grade cutoffs will not be discussed at any point during or after the semester. For students very close to grade boundaries, instructors may, at their discretion, consider participation in lecture and recitation, exam performance and overall grade trends when assigning the final grade.

Academic Integrity[–]

You are expected to comply with the University Policy on Academic Integrity (see also The Word and Understanding Academic Integrity). The university policies and procedures on academic integrity will be applied rigorously. All students are required to fill out a form as part of their first assignment indicating that they understand and accept this policy.

The value of your degree depends on the academic integrity of yourself and your peers in each of your classes. It is expected that, unless otherwise instructed, the work you submit as your own is your own work and not someone else’s work or a collaboration between yourself and other(s).

The Policy (Fall'21)

You are allowed to clarify the writeup of homework assignments with other students, but not work on a solution or brainstorm answers with them.

You are welcome to freely discuss course material (lecture notes/slides, practice exams, lab handouts, recitation handouts, blank writtens and programming writeups) as well as to review graded assignments with students taking the course in the current semester. You may give or receive help with computer systems, compilers, debuggers, profilers, or other facilities (as long as answers and/or code are never visible).

You are not allowed to refer to solutions and/or code written by past or present students, or found on the web, not even to "double-check" your own solution. You may not post code from this course publicly (e.g., to Bitbucket or GitHub).

You are not allowed to use any materials from previous iterations of the course, including your own. You may not discuss or receive help on homework assignments with students who have previously taken the course (excluding current TAs).

We will be using the MOSS system to detect software plagiarism. Whenever a programming assignment is similar to a homework from a previous course edition, we will run MOSS on all submissions from that edition as well. All solutions from the Web are also in MOSS - you should assume that if you were able to find it, we have already found them.

If you are uncertain whether your actions will violate this policy, please reach out to a member of course staff to ask beforehand.

Penalties and Specifics

Please read the University Policy on Academic Integrity carefully to understand the penalties associated with academic dishonesty at Carnegie Mellon. In this class, cheating/copying/plagiarism means copying all or part of a program or homework solution from another student or unauthorized source such as the Internet, having someone else do a homework or take an exam for you, knowingly or by negligence giving such information to another student, reusing answers or solutions from previous editions of the course, or giving or receiving unauthorized information during an examination. In general, each solution you submit (written assignment, programming assignment, midterm or final exam) must be your own work. In the event that you use information written by others in your solution, you must cite the source of this information (and receive prior permission if unsure whether this is permitted). It is considered cheating to compare complete or partial answers, copy or adapt others' solutions, or sit near another person who is taking (or has taken) the same course and complete the assignment together. Working on code together, showing code to another student and looking at another student's code are considered cheating. If you need help debugging, go to office hours or make a post on Diderot. It is also considered cheating for a repeating student to reuse one's solutions from a previous semester, or any instructor-provided sample solution. It is a violation of this policy to hand in work for other students.

Your course instructor reserves the right to determine an appropriate penalty based on the violation of academic dishonesty that occurs. Penalties are severe: a typical violation of the university policy results in the student failing this course, but may go all the way to expulsion from Carnegie Mellon University. If you have any questions about this policy and any work you are doing in the course, please feel free to contact the instructors for help.

Repeat Students

If you took this course in full or in part in a past semester, we ask that you delete your previous work so you won't look at it. In particular, copying one's own solutions from an earlier semester is a violation of the academic integrity policy and will be handled as such. Doing so may save time close to a deadline but it will not have the effect of learning the material, which will be a serious handicap in exams.

Other Policies[–]

Class presence and participation

Active participation by you and other students will ensure that everyone has the best learning experience in this class. We may take participation in lecture and recitation into account when setting final grades. Fire safety rules require that we never exceed the stated capacity of a classroom or cluster. For this reason, we require that you attend the lecture, lab, and recitation you are registered for.

Laptops and mobile devices

As research on learning shows, unexpected noises and movement automatically divert and capture people's attention, which means you are affecting everyone's learning experience if your cell phone, pager, laptop, etc, makes noise or is visually distracting during class. Therefore, please silence all mobile devices during class. You may use laptops for note-taking only, but please do so from the back of the classroom. Do not work on assignments for this or any other class while attending lecture or recitation.

Students with disabilities

If you wish to request an accommodation due to a documented disability, please inform your instructor and contact Disability Resources as soon as possible (access@andrew.cmu.edu). Once your accommodation has been approved, you will be able to request extra-time for each exam separately by filling this form a week in advance.

Research to Improve the Course

For this class, your instructor is conducting research on student learning. This research will involve surveys and course work. You will not be asked to do anything above and beyond the normal learning activities and assignments that are part of this course. You are free not to participate in this research, and your participation will have no influence on your grade for this course or your academic career at CMU. If you do not wish to participate, please send an email to Chad Hershock (hershock@cmu.edu). Please include your name and course number. Participants will not receive any compensation. The data collected as part of this research will include student grades. All analyses of data from participants' coursework will be conducted after the course is over and final grades are submitted. The Eberly Center may provide support on this research project regarding data analysis and interpretation. The Eberly Center for Teaching Excellence & Educational Innovation is located on the CMU-Pittsburgh Campus and its mission is to support the professional development of all CMU instructors regarding teaching and learning. To minimize the risk of breach of confidentiality, the Eberly Center will never have access to data from this course containing your personal identifiers. All data will be analyzed in de-identified form and presented in the aggregate, without any personal identifiers. If you have questions pertaining to your rights as a research participant, or to report concerns to this study, please contact Chad Hershock (hershock@cmu.edu).

Getting Help[–]

Personal Health

Take care of yourself.

Do your best to maintain a healthy lifestyle this semester by eating well, exercising, avoiding drugs and alcohol, getting enough sleep and taking some time to relax. This will help you achieve your goals and cope with stress.

All of us benefit from support during times of struggle. You are not alone. There are many helpful resources available on campus and an important part of the college experience is learning how to ask for help. Asking for support sooner rather than later is often helpful.

If you or anyone you know experiences any academic stress, difficult life events, or feelings like anxiety or depression, we strongly encourage you to seek support. Counseling and Psychological Services (CaPS) is here to help: call 412-268-2922 and visit their website. Consider reaching out to a friend, faculty or family member you trust for help getting connected to the support that can help.

If you or someone you know is feeling suicidal or in danger of self-harm, call someone immediately, day or night:

CaPS: 412-268-2922
Re:solve Crisis Network: 888-796-8226
If the situation is life threatening, call the police:
  • On campus (CMU Police): 412-268-2323
  • Off campus: 911
If you have questions about this or your coursework, please let us know.

Communication

For assistance with the written or oral communication assignments in this class, visit the Global Communication Center (GCC). GCC tutors can provide instruction on a range of communication topics and can help you improve your papers and presentations. The GCC is a free service, open to all students, and located in Hunt library. You can make tutoring appointments directly on the GCC website. You may also visit the GCC website to find out about communication workshops offered throughout the academic year.

External Academic Support

The Office of Academic Development is providing various services aimed at helping students master the contents of this course. These optional services are free and voluntary. They are led by trained leaders who have successfully completed the course. Leaders are not members of the course staff. These services are are designed to supplement — not replace — class lectures and recitations. They do not cover homework.
Supplemental Instruction (SI)
is a weekly session in which the leader prepares review material based on the current course content, but adapts the focus of the session based on the attendees' questions and requests.
Peer Tutoring
Students can drop in between 8:30pm and 11:00pm Sundays through Thursdays at select residence halls and other campus locations. No appointment is necessary, just walk-in.
We ask that students do not seek help from upperclassmates who have successfully completed the course. Doing so often leads to violations of the academic integrity policy of the course. In particular, upper-classmates found to violate this policy will be reported and will incur a grade penalty.

Learning Objectives[–]

Computational Thinking

Students who complete this course should be able to explain abstraction and other key computer science concepts, apply these fundamental concepts as problem-solving tools, and wield contracts as a tool for reasoning about the safety and correctness of programs. In particular, we expect students to be able to:
  1. develop contracts (preconditions, postconditions, assertions, and loop invariants) that establish the safety and correctness of imperative programs.
  2. develop and evaluate proofs of the safety and correctness of code with contracts.
  3. develop and evaluate informal termination arguments for programs with loops and recursion.
  4. evaluate claims of both asymptotic complexity and practical efficiency of programs by running tests on different problem sizes.
  5. define the concept of programs as data, and write programs that use the concept.
  6. defend the use of abstractions and interfaces in the presentation of algorithms and data structures.
  7. identify the difference between specification and implementation.
  8. compare different implementations of a given specification and different specifications that can be applied to a single implementation.
  9. explain data structure manipulations using data structure invariants.
  10. identify and evaluate the use of fundamental concepts in computer science as problem-solving tools:
    1. order (sorted or indexed data),
    2. asymptotic worst case, average case, and amortized analysis,
    3. randomness and (pseudo-)random number generation, and
    4. divide-and-conquer strategies.

Programming Skills

Students who complete this course should be able to read and write code for imperative algorithms and data structures. In particular, we expect students to be able to:
  1. trace the operational behavior of small imperative programs.
  2. identify, describe, and effectively use basic features of C0 and C:
    1. integers as signed modular arithmetic,
    2. integers as fixed-length bit vectors,
    3. characters and strings,
    4. Boolean operations with short-circuiting evaluation,
    5. arrays,
    6. loops (while and for),
    7. pointers,
    8. structs,
    9. recursive and mutually recursive functions,
    10. void pointers and casts between pointer types,
    11. generic data structures using void and function pointers,
    12. contracts (in C0), and
    13. casts between different numeric types (in C).
  3. translate between high-level algorithms and correct imperative code.
  4. translate between high-level loop invariants and data structure invariants and correct contracts.
  5. write code using external libraries when given a library interface.
  6. develop, test, rewrite, and refine code that meets a given specification or interface.
  7. develop and refine small interfaces.
  8. document code with comments and contracts.
  9. identify undefined and implementation-defined behaviors in C.
  10. write, compile, and test C programs in a Unix-based environment using make, gcc, and valgrind.

Algorithms and Data Structures

Students who complete this course should be able to describe the implementation of a number of basic algorithms and data structures, effectively employ those algorithms and data structures, and explain and interpret worst-case asymptotic complexity arguments. In particular, we expect students to be able to:
  1. determine the big-O complexity of common code patterns.
  2. compare common complexity classes like O(1), O(log n), O(n), O(n log n), O(n2), and O(2n).
  3. explain the structure of basic amortized analysis proofs that use potential functions.
  4. apply principles of asymptotic analysis and amortized analysis to new algorithms and data structures.
  5. recognize properties of simple self-adjusting data structures.
  6. recognize algorithms and data structures using divide-and-conquer.
  7. describe and employ a number of basic algorithms and data structures:
    1. integer algorithms,
    2. linear search,
    3. binary search,
    4. sub-quadratic complexity sorting (mergesort and quicksort),
    5. stacks and queues,
    6. pseudo-random number generators,
    7. hash tables,
    8. priority queues,
    9. balanced binary search trees,
    10. disjoint-set data structures (union/find), and
    11. simple graph algorithms.

Course Staff

Mascot

Instructors

photo of Iliano CervesatoIliano Cervesato
Office hours:
R 1:30-2:30pm (GHC 6007)
Conceptual OH
F 1:30-2:30pm (Zoom)
By appointment at other times
photo of Dilsun KaynarDilsun Kaynar
Office hours:
M 1:30-2:30pm (GHC 6009)
T 1:30-2:30pm (Zoom)
By appointment at other times

Course Administrative Assistant

photo of Marcie BakerMarcie Baker
GHC 6006

Teaching Assistants

photo of Pranav AddepalliPranav Addepalli
photo of Nikita BasuNikita Basu
photo of Abigail BergerAbigail Berger
photo of Olivia CorrodiOlivia Corrodi
photo of Eric GanEric Gan
photo of Alexandra GiroudAlexandra Giroud
photo of Semawit GebrehiwotSemawit Gebrehiwot
photo of Bhargav HadyaBhargav Hadya
photo of Sean HoughSean Hough
photo of Immanuel HuangImmanuel Huang
photo of Keren HuangKeren Huang
photo of Evelyn KuoEvelyn Kuo
photo of Ben Kwabi-AddoBen Kwabi-Addo
photo of Roger LacsonRoger Lacson
photo of Mei LengMei Leng
photo of Austin LeungAustin Leung
photo of Amanda LiAmanda Li
photo of Mingkang LiMingkang Li
photo of Kevin LinKevin Lin
photo of Robbie MonesRobbie Mones
photo of Daniel NgDaniel Ng
photo of Riya PatelRiya Patel
photo of Cooper PierceCooper Pierce
photo of Shreya RaghuramShreya Raghuram
photo of Ryan SanthoshkumarRyan Santhoshkumar
photo of Mengrou ShouMengrou Shou
photo of Abby ShrackAbby Shrack
photo of Brandon SommerfeldBrandon Sommerfeld
photo of Rohan SonechaRohan Sonecha
photo of Autumn SoukupAutumn Soukup
photo of Rebecca StevensRebecca Stevens
photo of Evan TippingEvan Tipping
photo of Jessica WangJessica Wang
photo of Elizabeth WeiElizabeth Wei
photo of Chu WengChu Weng
photo of Annie WuAnnie Wu
photo of Brent XiaoBrent Xiao
photo of Rachel YuanRachel Yuan
photo of Angela ZhangAngela Zhang
photo of Karen ZhangKaren Zhang
photo of George ZhouGeorge Zhou
photo of Lora ZhouLora Zhou

Schedule of Classes

At a glance ...

Outline[+]


Mon 30 Aug
Lab 1
Setup
This lab practices using Linux and running the C0 interpreter and compiler.
Tue 31 Aug
Lecture 0
Welcome and Course Introduction
We outline the course, its goals, and talk about various administrative issues.

A mysterious function ...
We examine a program we know nothing about, making hypotheses about what it is supposed to do. We notice that this function has no meaningful output for some inputs, which leads us to restricting its valid inputs using preconditions. We use a similar mechanism, postconditions, to describe the value it returns. Along the way, we get acquainted to C0 and its support for checking pre- and post-conditions. We then notice that this function doesn't return the expected outputs even for some valid inputs ...
Concepts:
  • Pre- and post-conditions
  • Testing
  • Contract support in C0
Readings:
Thu 2 Sep
Lecture 1
Contracts
Contracts are program annotations that spell out what the code is supposed to do. They are the key to connecting algorithmic ideas to their implementation as a program. In this lecture, we illustrate the use of contracts by means of a simple C0 program. As we do so, we learn to verify loop invariants — an important type of contract, we see how contracts can help us write correct code, and we get acquainted with C0's automated support to validating contracts.
Concepts:
  • Loop invariants
  • Assertions
  • Using contracts to write correct programs
  • Contract support in C0
Fri 3 Sep
Recitation 1
C0 Basics
This recitation reviews elementary C0 constructs and practices reasoning about code.
Mon 6 Sep
No class (Labor Day)
Tue 7 Sep
Lecture 2
Ints
In this lecture, we explore how number representation interplays with the the ability to write effective contracts. We focus on integers and see how the binary representation called two's complement supports the laws of modular arithmetic, which C0 embraces. We also examine operations that allow exploiting the bit pattern of a binary number to achieve compact representations of other entities of interest, and to manipulate them.
  • Representation of integers
  • Two's complement
  • Modular arithmetic
  • Bit-level operations
Thu 9 Sep
Lecture 3
Arrays
In this lecture, we examine arrays as our first composite data structure, i.e., a data construction designed to hold multiple values, together with operations to access them. Accessing an array element outside of its range is undefined — it is a safety violation — and we see how to use contracts, in particular loop invariants, to ensure the safety of array accesses in a program. Arrays are stored in memory, which means that they are manipulated through an address. This raises the possibility of aliasing, a notorious source of bugs in carelessly written programs.
  • Arrays
  • Memory allocation
  • Safe access
  • Loop invariants for arrays
  • Aliasing
Fri 10 Sep
Recitation 2
A Bit about Bytes
This recitation practices base conversion and writing code that manipulates bits.
Mon 13 Sep
Lab 3
Loopty-Loopty Loop
This lab practices testing and timing running code to estimate its complexity.
Tue 14 Sep
Lecture 4
Searching Arrays
We practice reasoning about arrays by implementing a function that searches whether an array contains a given value — this is the gateway to a whole class of useful operations. We notice that this function returns its result more quickly when the array is sorted. We write a specialized variant that assumes that the array is sorted, and show that it works correctly by reasoning about array bounds. The first (simpler but less efficient) version acts as a specification for the the second (slightly more complex but often faster). Using the specification in the contract for the implementation is a standard technique to help writing correct code.
  • Linear search
  • Reasoning about arrays
  • Sorted arrays
  • Performance as number of operations executed
  • Specification vs. implementation
Thu 16 Sep
Lecture 5
Big-O
We examine big-O notation as a mathematical tool to describe the running time of algorithms, especially for the purpose of comparing two algorithms that solve the same problem. As a case study, we use the problem of sorting an array, and for now a single sorting algorithm, selection sort. As we implement selection sort, we see that starting with contracts gives us high confidence that the resulting code will work correctly. Along the way, we develop a useful library of functions about sorted arrays to be used in contracts.
  • Big-O notation
  • Selection sort
  • Deliberate programming
  • Asymptotic complexity analysis
Fri 17 Sep
Recitation 3
Function Family Reunion
This recitation practices understanding and using big-O notation.
Mon 20 Sep
Lab 4
TA Training
This lab practices testing code.
Tue 21 Sep
Lecture 6
Binary search
When searching for a value in a sorted array, examining the middle element allows us to discard half of the array in the worst case. The resulting algorithm, binary search, has logarithmic complexity which is much better than linear search (which is linear). Achieving a correct imperative implementation can be tricky however, and we use once more contracts as a mechanism to reach this goal.
  • Binary search
  • Divide-and-conquer
  • Deliberate implementation
  • Checking complex loop invariants
Thu 23 Sep
Lecture 7
Quicksort
We use the key idea underlying binary search to implement two sorting algorithms with better complexity than selection sort. We examine one of them, quicksort, in detail, again using contracts to achieve a correct implementation, this time a recursive implementation. We observe that the asymptotic complexity of quicksort depends on the the value of a quantity the algorithm use (the pivot) and discuss ways to reduce the chances of making a bad choice for it. We conclude by examining another sorting algorithm, mergesort, which is immune from this issue.
  • Quicksort
  • Deliberate programming
  • Recursion
  • Best, average, and worst case complexity
  • Randomness
  • Choosing an algorithm for a problem
Fri 24 Sep
Recitation 4
A Strange Sort of Proof
This recitation reviews proving the correctness of functions.
Mon 27 Sep
Lab 5
Fibonacci has Bad Internet
This lab practices working with algorithms with radically different complexity for the same problem.
Tue 28 Sep
Lecture 8
Libraries
Arrays are homogeneous collections, where all components have the same type. structs enable building heterogeneous collections, that allow combining components of different types. They are key to building pervasively used data structures. In C0, a struct resides in allocated memory and is accessed through an address, which brings up a new form of safety violation: the NULL pointer violation. We extend the language of contracts to reason about pointers.
Now that we have a two ways to build complex collections, we start exploring the idea of segregating the definition of a data structure and the operations that manipulate it into a library. Code that uses this data structure only needs to be aware of the type, operations and invariants of the data structure, not the way they are implemented. This is the basis of a form of modular programming called abstract data types, in which client code uses a data structure exclusively through an interface without being aware of the underlying implementation.
  • Pointers
  • Structs
  • Abstract data types
  • Interfaces, client code and library code
  • Data structure invariants
  • Testing
Thu 30 Sep
Lecture 9
Stacks and Queues
In this lecture, we examine the interface of two fundamental data structures, stacks and queues. We practice using the exported functions to write client code that implements operations of stacks and queues that are not provided by the interface. By relying only of the interface functions and their contracts, we can write code that is correct for any implementation of stacks and queues.
  • Interface of stacks and queues
  • Using an interface
Fri 1 Oct
Recitation 5
A queue_t Interface
This recitation practices programming against an interface.
Mon 4 Oct
Lab 6
Misclaculation
This lab practices understanding postfix notation and stack-based machines.
Tue 5 Oct
Lecture 10
Linked Lists
We observe that we can implement array-like collections using a struct that packages each element with a pointer to the next element. This idea underlies linked lists, a data structure pervasively used in computer science. Writing correct code about linked lists is however tricky as we often rely on stricter invariants than natively supported, in particular the absence of cycles. We develop code to be used in contracts to check for common such properties. We then use linked lists to write code that implements the stack interface, and similarly for queues. We could have given an array-based implementation, and we note the advantages and drawbacks of each choice.
  • Linked lists
  • Checking data structure invariants
  • Linked list implementation of stacks and queues
  • Choosing an implementation: trade-offs
Thu 7 Oct
Midterm 1
Midterm 1
Fri 8 Oct
Recitation 6
Link it All Together
This recitation practices working with linked lists.
Mon 11 Oct
Lab 7
List(en) Up!
This lab practices working with linked lists.
Tue 12 Oct
Lecture 11
Unbounded Arrays
When implementing a data structure for a homogeneous collection, using an array has the advantage that each element can be accessed in constant time, but the drawback that we must fix the number of elements a priori. Linked lists can have arbitrary length but access takes linear time. Can we have the best of both worlds? Unbounded arrays rely on an array to store the data, but double it when we run out of place for new elements. The effect is that adding an element can be either very cheap or very expensive depending on how full the array is. However, a series of insertions will appear as if each one of them takes constant time on average. Showing that this is the case requires a technique called amortized analysis, which we explore at length in this lecture.
  • Better trade-offs
  • Amortized analysis
  • Unbounded arrays
Thu 14 Oct
No class (mid-semester break)

But the following material will be needed for next class (it is also quickly covered in recitation and lab)
Hashing
Associative arrays are data structures that allow efficiently retrieving a value on the basis of a key: arrays are the special case where valid indices into the array are the only possible keys. One popular way to implement associative arrays is to use a hash table, which computes an array index out of each key and uses that index to find the associated value. However, multiple keys can map to the same index, something called a collision. We discuss several approaches to dealing with collisions, focusing on one called separate chaining. The cost of access depends on the contents of the hash table. While a worst case analysis is useful, it is not typically representative of normal usage. We compute the average case complexity of an access relative to a few simple parameters of the hash table.
  • Genericity — part I: void pointers
  • Associative arrays AKA dictionaries AKA maps
  • Implementation using hash tables
  • Dealing with collisions
  • Randomness
  • Average case complexity
Fri 15 Oct
Recitation 7
Array Disarray
This recitation practices coding to achieve amortized cost.
Mon 18 Oct
Lab 8
Hash this!
This lab practices understanding collisions in hash functions.
Tue 19 Oct
Lecture 12
Hash Dictionaries
In this lecture, we look at the interface of modular code at greater depth, using hash functions as a case study. In this and many example, it is useful for the client to fill in some parameters used by the library code so that it delivers the functionalities needed by the client. One such parameter is the type of some quantities the library acts upon, keys in our case. It is also often the case that the client wants to provide some of the operations used by the library, here how to hash a key and how to compare elements. This is a first step towards making libraries generic, so that they implement the general functionalities of a data structure but let the client choose specific details.
  • Adaptable libraries
  • Client-supplied operations
Thu 21 Oct
Lecture 13
Generic Data Structures
In large (and not-so-large) systems, it is common to make multiple uses of the same library, each instantiated with different parameters. This is not possible in C0, however. To achieve this goal, we look at a richer language, called C1. C1 provides two new features: generic pointers and function pointers. Generic pointers, void * in C, allow a same library type to be instantiated with different client types at once, which gives us a way to use a hash table library with both integers and strings as keys for example. Function pointers allow a library to be instantiated with different client-supplied operations in the same program.
  • Genericity — part II: function pointers
Fri 22 Oct
Recitation 8
Generically Speaking
This recitation practices working with generic pointers and function pointers.
Mon 25 Oct
Lab 9
Legacy of the void*
This lab practices defining generic libraries.
Tue 26 Oct
Lecture 14
Binary Search Trees
We discuss trees as an approach to representing a collection, and binary search trees as an effective data structure to store and operate on sorted data. In particular, most operations on balanced binary search trees have a logarithm cost on the number of contained data. Binary search trees can however become unbalanced over time.
  • Trees
  • Binary search trees
  • Ordering invariant
  • Exponential speedup
Thu 28 Oct
Lecture 15
AVL trees
Self-balancing trees guarantee the performance advantages of binary search trees by making sure that common operations keep the tree roughly balanced. This assurance comes at the price of more complex code for these operations, which rely on more complex invariants to tame it.
  • AVL trees
  • AVL invariants
  • Rotations
  • Experimental validation
Fri 29 Oct
Recitation 9
Rotating Rotations
This recitation practices restoring height invariants in trees.
Mon 1 Nov
Lab 10
This One's a Treet
This lab practices using dictionaries to avoid recomputing values.
Tue 2 Nov
Lecture 16
Introduction to C
With this lecture, we are moving from the safety of C0 to the more open-ended world of C. We introduce some basic concepts of C, in particular the C preprocessor and how macros written in this language can simulate some of the effects of C0's contracts. We also see how to compile C programs and discuss separate compilation. We conclude with C's primitives to manage memory, in particular the need to free allocated memory to prevent memory leaks.
  • The C preprocessor
  • Macros
  • Contracts in C
  • Compilation of C programs
  • Allocation and deallocation
Thu 4 Nov
Midterm 2
Midterm 2
Fri 5 Nov
Recitation 10
From C1 to Shining C
This recitation practices the main novelties of C.
Mon 8 Nov
Lab 11
Once you C1 you C them all
This lab practices using translating C0 code to C and managing memory leaks.
Tue 9 Nov
Lecture 17
C's Memory Model
C provides a very flexible view of memory, which allows writing potentially dangerous code unless one is fully aware of the consequences of one's decision. This lecture is about building this awareness. We see that, while C overlays an organization on the monolithic block of memory the operating systems assigns to a running program, it also provides primitives that allow violating this organization. We focus on two such primitives, pointer arithmetic and address-of. While some uses are legitimate, others are not. C's approach to many non-legitimate operations is to declare them undefined, which means that what happens when a program engages in them is decided by the specific implementation of the C compiler in use.
  • C's memory layout
  • Pointer arithmetic
  • Undefined behavior
  • The address-of operator
Thu 11 Nov
Lecture 18
Types in C
In this lecture, we examine how C implements basic types, and what we as programmers need to be aware of as we use them. We begin with strings, that in C are just arrays of characters with the null character playing a special role. A variety of number types are available in C, but some of their characteristics are not defined by the language, most notably their size and what happens in case of overflow. As a consequence, different compilers make different choices, which complicates writing code that will work on generic hardware.
  • Strings in C
  • Casting
  • Numbers in C
  • Implementation-defined behavior
Fri 12 Nov
Recitation 11
C-ing is Believing
This recitation practices advanced C constructions.
Mon 15 Nov
Lab 12
All sorts of sorts
This lab practices working with pointers in C.
Tue 16 Nov
Lecture 19
Virtual Machines
Getting a program written in a high-level language to run onto the machine hardware can be achieved in a number of ways, with compilation to machine code and interpretation of the source language as the two extremes. We assess the benefits and drawbacks of each and introduce virtual machines as a modern trade-off. We explore this possibility through the C0VM, a virtual machine for C0. A compilation phase takes C0 code as input and outputs bytecode that can be run by the C0VM. We examine in depth the organization of the C0VM itself, understanding how its instructions are executed through a description called an operational semantics. We also describe some of the data structures needed to implement the C0VM itself.
  • Interpreters vs. compilers
  • Virtual machines
  • Programs as data
  • Transformation to bytecode
  • Operational semantics
  • Bytecode validation
Thu 18 Nov
Lecture 20
Graph Representation
Graphs provide a uniform way to represent many complex problems, for example the moves of a game. We define a minimal interface for working with undirected graphs and discuss two implementation strategies: adjacency matrices and adjacency lists, emphasizing the pros and cons of each. We also notice that not all graph-based problems need — or can — use an explicit representation of the underlying graph.
  • Graphs
  • Implicit vs. explicit graphs
  • Adjacency matrices
  • Adjacency lists
Fri 19 Nov
Recitation 12
Computing on the Edge
This recitation practices working with graphs.
Mon 22 Nov
Lab 13
passwordLab
This lab practices understanding C0VM bytecode.
Tue 23 Nov
Lecture 21
Graph Search
When working with graphs, one basic question is whether a node is reachable from another node by following a path. That destination node is often described by a property of interest — e.g., being a winning board in the graph representing the moves of a game. We examine various approaches to solving the reachability programs, in particular depth-first and breadth-first, each of which has its own advantages. We then discuss various approaches to implementing these strategies.
  • Path between nodes
  • Depth-first search
  • Breadth-first search
  • Implementation strategies
Thu 25 Nov
No class (Thanksgiving)
Fri 26 Nov
No class (Thanksgiving)
Mon 29 Nov
Lab 14
Spend some Cycles Thinking
This lab practices working with graphs.
Tue 30 Nov
Lecture 22
Priority Queues
We discuss priority queues, another classical data structure. Among the possible ways to implement priority queues, we consider min-heaps, a tree-based strategy that provides superior performance. We examine the data structure invariants of min-heaps and observe that we need to violate them during operations such as insertion. To conclude with, we see that min-heaps are amenable to an efficient implementation based on arrays.
  • Priority queues
  • Implementation strategies
  • Heap-based implementation
  • Implementing heaps using arrays
Thu 2 Dec
Lecture 23
Restoring Invariants
In this lecture, we write a library that implements min-heaps using arrays. Of particular interest is how the temporary violation of invariants needed to implement min-heap operations manifests at the level of contracts. Careful pre- and post-conditions are key to writing their code correctly.
  • Temporary violation of invariants
  • Controlling invariant violations using contracts
  • Min-heap library implementation
  • Heapsort
Fri 3 Dec
Recitation 14
Mind your P's and Q's
This lab practices using priority queues.
Mon 6 Dec
(8:30-11:30)
final
Final

2021 Iliano Cervesato iliano@cmu.edu