2.5 Reasoning about Programs: Assertions and Loop Invariants

Slides:



Advertisements
Similar presentations
College of Information Technology & Design
Advertisements

 O: order of magnitude  Look at the loops and to see whether the loops are nested. ◦ One single loop: O(n) ◦ A nested loop: O(n 2 ) ◦ A nested loop.
Algorithm Analysis.
Lecture: Algorithmic complexity
Algorithm Complexity Analysis: Big-O Notation (Chapter 10.4)
1 Chapter 24 Developing Efficient Algorithms. 2 Executing Time Suppose two algorithms perform the same task such as search (linear search vs. binary search)
1 Recursion Algorithm Analysis Standard Algorithms Chapter 7.
Data Structures and Algorithms Lecture 5 and 6 Instructor: Quratulain Date: 15 th and 18 th September, 2009 Faculty of Computer Science, IBA.
Analysis of Algorithms These slides are a modified version of the slides used by Prof. Eltabakh in his offering of CS2223 in D term 2013.
Program Efficiency & Complexity Analysis. Algorithm Review An algorithm is a definite procedure for solving a problem in finite number of steps Algorithm.
Data Structure Introduction.
C++ How to Program, 7/e © by Pearson Education, Inc. All Rights Reserved.
1 Chapter 2 Algorithm Analysis Reading: Chapter 2.
Algorithm Complexity Analysis (Chapter 10.4) Dr. Yingwu Zhu.
Data Structures I (CPCS-204) Week # 2: Algorithm Analysis tools Dr. Omar Batarfi Dr. Yahya Dahab Dr. Imtiaz Khan.
Algorithm Analysis 1.
C++ Lesson 1.
19 Searching and Sorting.
Introduction to Algorithms
Repetitive Structures
Applied Discrete Mathematics Week 2: Functions and Sequences
Introduction to Analysis of Algorithms
Chapter 6 CS 3370 – C++ Functions.
Chapter 1.2 Introduction to C++ Programming
Analysis of Algorithms
Analysis of Algorithms
Introduction to Algorithms
Lecture – 2 on Data structures
COMP 53 – Week Seven Big O Sorting.
Introduction to Algorithms
DATA STRUCTURES Introduction: Basic Concepts and Notations
Control Structures Combine individual statements into a single logical unit with one entry point and one exit point. Used to regulate the flow of execution.
Teach A level Computing: Algorithms and Data Structures
Enough Mathematical Appetizers!
Computation.
C++ Templates L03 - Iterator 10 – Iterator.
10 – Iterators C++ Templates 4.6 The Iterator pgs
Control Structures Combine individual statements into a single logical unit with one entry point and one exit point. Used to regulate the flow of execution.
While loops The while loop executes the statement over and over as long as the boolean expression is true. The expression is evaluated first, so the statement.
Efficiency (Chapter 2).
Building Java Programs
5.1 The Stack Abstract Data Type
Lab 03 - Iterator.
Algorithm An algorithm is a finite set of steps required to solve a problem. An algorithm must have following properties: Input: An algorithm must have.
Programming Funamental slides
15 – Sequential Containers
Introduction to Algorithms Analysis
14 – Sequential Containers
Algorithm Efficiency, Big O Notation, and Javadoc
CS 201 Fundamental Structures of Computer Science
Applied Discrete Mathematics Week 6: Computation
Analysis of Algorithms
CSE 2010: Algorithms and Data Structures Algorithms
Introduction to Algorithms
Analysis of Algorithms
C++ Templates L03 - Iterator 10 – Iterator.
Engineering Problem Solving with C++ An Object Based Approach
Engineering Problem Solving with C++ An Object Based Approach
C++ Templates L03 - Iterator 10 – Iterator.
Analysis of Algorithms
Sum this up for me Let’s write a method to calculate the sum from 1 to some n public static int sum1(int n) { int sum = 0; for (int i = 1; i
Algorithmic complexity
Complexity Analysis (Part II)
Analysis of Algorithms
2.6, pgs Efficiency of Algorithms Big-O Notation
Analysis of Algorithms
16 – Sequential Containers
Algorithms and data structures: basic definitions
Algorithm Analysis How can we demonstrate that one algorithm is superior to another without being misled by any of the following problems: Special cases.
Presentation transcript:

2.5 Reasoning about Programs: Assertions and Loop Invariants 2.6 Efficiency of Algorithms 13 – Program Correctness

Attendance Quiz #10 Program Correctness

Tip #13: '\n' Confusion Program Correctness Internally all applications use '\n' to indicate line termination. But the line termination sequence is platform specific. Windows (DOS) uses CR and LF. Unix (Linux) uses LF. Mac (OSX) CR. 2 additional formats: Unicode Line Separator (LS) and Unicode Paragraph Separator (PS).

Tip #13: Newline Confusion Iterators The problem with platform specific line termination is The '\n' character is transformed into a platform specific sequence of character(s) when you write it to a file. The platform specific sequence is converted back to '\n' when the file is read. The problem becomes a problem you write files on one platform and read them on another. For example, after running "filename >> amount;", the newline is still in the buffer. This normally isn't a problem when using only ">>" as it ignores newlines. But when you mix getline and ">>" you need to ignore the newlines that ">>" leaves behind. Bad getline(cin, line, '\n'); cout << "hello\n"; filename >> amount; getline(filename, line); Good getline(cin, line); cout << "hello" << endl; filename >> amount >> std::ws;

Lab 03 Iterator MyArray Iterator Program Correctness #include <iostream> #include <string> using namespace std; #define MAX_ARRAY_SIZE 1000 template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(const size_t array_size) : size_(0) array_ = (T*)malloc(array_size * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } }; int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); return 0; } MyArray<int>::Iterator iter = numbers.begin(); for (int i = 0; i < 4; ++i) cout << iter[i] << ' '; cout << endl << endl; MyArray Iterator class Iterator { private: size_t index_; T* array_; public: Iterator(T* a) : array_(a), index_(0) {} T& operator[](int i) const { return array_[index_ + i]; } }; Iterator begin() { return MyArray<T>::Iterator(array_); }

2.5 Reasoning about Programs: Assertions and Loop Invariants The C++ assert Macro 2.5, pgs. 166-168

Assertions Program Correctness Assertions are logical statements about a program that are "asserted" to be true. A pre-condition is an assertion about the state of the input data (generally the input parameters) before the function is executed. For example, a pre-condition for method double divide(double dividend, double divisor) might be divisor != 0. A post-condition is an assertion about the state of the output data when the function returns. For example, a post-condition for method int search (int x[], int x_length, int target) would be all elements were tested and target not found. An invariant is a particular pre-condition of a procedure is the same after the procedure is completed. For example a valid invariant for a procedure boolean search(int term, int array[]) might say that the state of array before the call is the same as it is after the call.

The C++ assert Macro Program Correctness Assertions written as comments are valuable for understanding a program, but are only verified by the programmer. C++ provides an assert macro (defined in <cassert>) that calls an internally defined function to print an error message and terminate the program if the asserted condition is not true. int search (int x[], int x_length, int target) { //assert: x_length is a valid array index assert(x_length >= 0 && "Length can't possibly be negative!"); int i; for (int i = 0; i < x_length; i++) if (x[i] == target) return i; } //assert: all elements were tested and target not found assert(i == x_length && "Didn't check all values!"); return -1;

Loop Invariant Program Correctness A loop invariant condition is about the relationship between the variables of a program which are true immediately before and immediately after each iteration of the loop. int max = INT_MIN; int a[] = { 7, 5, 3, 10, 2, 6 }; for (int i = 0; i < 6; i++) { if (a[i] > max) max = a[i]; } For example, in the above procedure, loop invariants include: "The array a doesn't change." "The variable max is always the max value of the first i elements of array a." Ideally in OO, you would isolate what varies as much as possible, so that each object/procedure is mostly invariant. Enforcing invariants on loops reduces side effects that lead to nasty situations where two identical calls to the same procedure (with the same input) might yield different outputs.

Describe a loop invariant for the following loop (i. e Describe a loop invariant for the following loop (i.e. what is true for every iteration): string a = "aibohphobia"; int i, j; for (i = 0, j = 10; i < 11; i++, j++) { // loop invariant before loop begins if (a[i] != a[j]) break; // holds true at end of loop } if (i == 11) cout << "Palidrome"; The first ith elements of array are a palindrome. (i + j) == 10 (i >= 0) and (i <= 11)

2.6, pgs. 170-179 2.6 Efficiency of Algorithms Big-O Notation Comparing Performance Algorithms with Exponential and Factorial Growth Rates 2.6, pgs. 170-179

Efficiency of Algorithms Program Correctness Getting a precise measure of the performance of an algorithm is difficult. We can try to approximate the effect of a change in the number of data items, n, that an algorithm processes. In this way we can see how an algorithm's execution time increases with respect to n, so we can compare two algorithms by examining their growth rate. For many problems there are algorithms that are relatively obvious but inefficient. Even though computers are getting faster, with larger memories, algorithm growth rates can be so large that no computer can solve the problem above a certain size.

1. Array Search Program Correctness int search(int x[], int x_length, int target) { for (int i = 0; i < x_length; i++) if (x[i] == target) return i; } return -1; // target not found x[] ---- 1 2 3 4 If the target is not present in the array, then the for loop will execute x_length times. If the target is present, the for loop will execute (on average) x_length/2 times. Therefore, the total execution time is directly proportional to x_length . If we double the size of the array, we expect the time to double.

2. Different Arrays x[] ---- 1 2 3 4 y[] ---- 4 3 2 1 Program Correctness bool are_different(int x[], int x_length, int y[], int y_length) { for (int i = 0; i < x_length; i++) if (search(y, y_length, x[i]) != -1) return false; } return true; x[] ---- 1 2 3 4 y[] ---- 4 3 2 1 The for loop will execute x_length times. But it will call search, which will execute y_length times. The total execution time is proportional to (x_length * y_length).

3. Unique Arrays Program Correctness bool are_unique(int x[], int x_length) { for (int i = 0; i < x_length; i++) for (int j = 0; j < x_length; j++) if (i != j && x[i] == x[j]) return false; } return true; x[] ---- 1 2 3 4 If all values are unique, the for loop with i as index will execute x_length times. Inside this loop, the for loop with j as index will execute x_length times. The total number of times the loop body of the innermost loop will execute is ( x.length2 ).

4. Better Unique Arrays x[] ---- 1 2 3 4 Program Correctness bool are_unique2(int x[], int x_length) { for (int i = 0; i < x_length; i++) for (int j = i + 1; j < x_length; j++) if (x[i] == x[j]) return false; } return true; x[] ---- 1 2 3 4 This loop will execute x_length - 1 times the first time. The second time it will execute x_length - 2 times, and so on. The last time it will execute once.

Big-O Notation Program Correctness Understanding how the execution time (and memory requirements) of an algorithm grows as a function of increasing input size gives programmers a tool for comparing various algorithms and determining how they will perform. If the execution time stays the same regardless of the number of inputs, then the growth rate is of order 1. If the execution time approximately doubles when the number of inputs, n, doubles, then the algorithm grows at a linear rate or a growth rate of order n. If the execution time is approximately quadrupled when the number of inputs is doubled, then the algorithm grows at a quadratic rate or at a growth rate of order of n2.

Big-O Notation Program Correctness Consider the following functions with respect to execution: n times for (int i = 0; i < n; i++) { // Statement(s) }

Big-O Notation Program Correctness Consider the following functions with respect to execution: n times for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) // Statement(s) } (n  m) times

Big-O Notation Program Correctness Consider the following functions with respect to execution: n times (n  m) times for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) // Statement(s) } (n2) times

Big-O Notation Program Correctness Consider the following functions with respect to execution: n times (n  m) times (n2) times for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) // Statement(s) } (n log n) times

Big-O Notation Program Correctness Consider the following functions with respect to execution: n times (n  m) times (n2) times (n log n) times. Computer scientists use the notation O(n) to represent the first case O(n  m) to represent the second O(n2) to represent the third O(n log n) to represent the fourth The symbol O can be thought of as an abbreviation for “order of magnitude” and is called big-O notation.

Big-O Notation Program Correctness A simple way to determine the big-O of an algorithm or program is to look at any loops and to see whether the loops are nested. Assuming that the loop body consists only of simple statements, a single loop is O(n) a nested loop is O(n2) a nested loop in a nested loop is O(n3), and so on The growth rate of f(n) will be determined by the fastest growing term, which is the one with the largest exponent. In general, it is safe to ignore all constants and to drop the lower-order terms when determining the order of magnitude.

Big-O Example T(n) = n2 + 3n + 9 void T(int n) { Program Correctness void T(int n) { for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) // Simple Statement; } // Simple Statement 1; // Simple Statement 2; // Simple Statement 3; // ... // Simple Statement 8; // Simple Statement 9; The outer loop will execute n times. The inner loop will execute n times for each outer loop iteration. We can conclude that the relationship between processing time and n (the number of Simple Statements processed) is: T(n) = n2 + 3n + 9 The growth rate of f(n) will be determined by the fastest growing term, which is the one with the largest exponent. In the example, an algorithm of O(n2 + 3n + 9) is more simply expressed as O(n2). The loop will execute 3 Simple Statements n times Finally, 9 Simple Statements are executed.