Algorithms Intro2CS week 5 1
Computational problems A computational problem specifies an inputoutput relationship What does the input look like? What should the output be for each input? Example: Input: an integer number N Output: Is the number prime? Example: Input: A list of names of people Output: The same list sorted alphabetically
Algorithms An algorithm is an exact specification of how to solve a computational problem An algorithm must specify every step completely, so a computer can implement it without any further understanding An algorithm must work for all possible inputs of the problem. Algorithms must be: Correct: For each input produce an appropriate output Efficient: run as quickly as possible, and use as little memory as possible more about this later There can be many different algorithms for each computational problem.
Describing Algorithms Algorithms can be implemented in any programming language Usually we use pseudo-code to describe algorithms Testing whether input N is prime: For j = 2.. N-1 Math notation: j divides N If j N Output N is composite and halt Output N is prime In this course we will describe algorithms in Python
Greatest Common Divisor מחלק משותף מקסימאלי Definition: The GCD of two natural numbers x, y is the largest integer j that divides both (without remainder). I.e. j x, j y and j is the largest integer with this property. The GCD Problem: Input: natural numbers x, y Output: GCD(x,y) their GCD
Simple GCD algorithm 6
Proof of Correctness משפט: לכל שני מספרים טבעיים,x y אלגוריתם זה מחזיר את.gcd(x,y) הוכחה: שום מספר גדול מ (x,y) min לא יכול לחלק את שניהם ולכן ה- gcd חייב להיות מספר שלם בין 1 ל-( x,y ) min )כולל(, וזהו התחום שהלולאה עוברת עליו. הפונקציה מחזירה את המחלק המשותף )כלומר ה- i כך ש i x וגם ) i y האחרון שמצאה, ומכיוון שהיא עוברת על הערכים מקטן לגדול, זהו גם המחלק המשותף הגדול ביותר. 7
Need for speed Conclusion: On my PC, the loop in the gcd function runs about 10 Million times per second. Conclusion: gcd(123456789123456789, 456789123456789123) will require about 10 10 seconds > 300 years 8
Euclid s Algorithm Considered first algorithm Invented. Idea: Assume x >> y: gcd(x,y) = gcd(x-y, y) = = gcd(x-2y, y) = = = gcd(x%y, y) 9
Euclid s algorithm in python Example run: gcd(250, 72) x y 250 72 72 34 34 4 4 2 2 0 10
Proof of Correctness משפט: לכל שני מספרים טבעיים,x y אלגוריתם זה מחזיר את.gcd(x,y) הוכחה: נראה )בשקף הבא( שלאורך כל התוכנית, הערכים של,x y שומרים על אותו gcd כמו של ה,x y המקוריים. נראה )אחר כך( שהפונקציה תמיד מסיימת את הלולאה זה קורה כאשר 0=y וברור ש gcd(x,0) הינו באמת x )שכן x x וגם 0 x וברור ששום מספר גדול יותר לא מחלק את x( וזה מה שאנו מחזירים. מכיון שה- gcd לא השתנה זה גם ה- gcd של ה-,x y המקוריים. 11
Proof of Loop invariant סימון: x i, y i יסמנו את הערכים של המשתנים,x y לאחר i פעמים שהלולאה רצה. בפרט x 0, y 0 הינם הערכים המקוריים של,x y gcd(x i, y i )=gcd(x 0, y 0 ) לכל למה: 0 i מתקיים ש: הוכחה: באינדוקציה על i. עבור 0=i זה טריוויאלית נכון. נניח לגבי i נוכיח לגבי 1+i:, y i לפי קוד התוכנית 1+i = x הבאה מתקיים ש: ו- i+1.)x i % y i (= y ולכן לפי הלמה המתמטית gcd(x i+1, y i+1 ) = gcd(y i, x i %y i ) = gcd(x i %y i, y i ) = gcd(x i, y i ) = gcd(x 0, y 0 ) gcd(a,b) = gcd(a%b, b) למה מתמטית: לכל שני שלמים a,b מתקיים ש 12
Proof of Mathematical Lemma למה מתמטית: a,b מתקיים (b gcd(a,b)=gcd(a%b, לכל ולכן הוכחה: מספיק להראות ש ) i b וגם i (a%b) ( אםם ) i b וגם i a ( מכיון ש i b קיים שלם m כך ש.b=mi תהי n המנה השלמה בחלוקת a לb אזי.a%b = a-nb = a-nmi ) ( i a משמעותו שקיים k כך ש ki=a ולכן: i (a%b) ולכן a%b = a-nmi = ki-nmi = (k-nm)i a%b=a-nmi=li כך ש l משמעותו שקיים i (a%b) ) ( i a ולכן a = li+nmi = (l+nm)i 13
Proof of Termination משפט: לכל שני מספרים אי-שליליים,x y הפונקציה מסיימת את הריצה. הוכחה: לפי קוד התוכנית, כל עוד לא סיימנו אנו מעדכנים i+1 )x i % y i (= y ולכן. y i+1 >y i כלומר הערך של המשתנה השלם y קטן ממש כל סבב של הלולאה ולכן מספר הסבבים הוא לכל היותר הערך המקורי של y. 14
How fast does it run? 15
Square Roots The problem we want to address is to compute the square root of a real number. When working with real numbers, we can not have complete precision. The inputs will be given in finite precision The outputs should only be computed approximately The square root problem: Input: a positive real number x, and a precision requirement Output: a real number r such that r- x
Binary Search Algorithm idea The square root of x is somewhere between L=0 and H=max(1,x). If we take a middle point M=(L+H)/2 we can tell whether it is too high or too low by testing whether M 2 > x or M 2 < x, after that we can continue searching in the correct half. 17
Square Root via Binary Search in Python round 1 2 3 4 5 6 7 l 0 1 1 1.25 1.375 1.375 1.40625 h 2 2 1.5 1.5 1.5 1.4375 1.4375 m 1 1.5 1.25 1.375 1.4375 1.40625 18
Proof of correctness משפט: לכל קלט אי-שלילי x ערך r כך ש:. r- x וערך >0 התוכנית מחזירה למה: לאורך כל ריצת התוכנית מתקיימת האינווריאנטה ש:.l x h )הוכחה בשקף הבא( l הוכחת המשפט: לפי הקוד, הערך של h-l קטן פי 2 כל סבב של הלולאה, והלולאה מסתיימת כאשר ערך זה קטן מ- ולכן הלולאה עוצרת אחרי מספר סופי של צעדים )כי תמיד יש k כך ש.)(h-l)/2 k < אז מתקיים ש: xוכמו - l h-l כן 0 l, x - ולכן החזרת הערך כמו שעושה הקוד מקיימת את הנדרש. 19
Proof of Invariant למה: לאורך כל ריצת התוכנית מתקיימת האינווריאנטה ש:.l x h הוכחה: רצה. באינדוקציה על מספר הפעמים i שהלולאה בסיס האינדוקציה: h=max(1,x) l=0 x )כי עבור <1(. x מתקיים x<1 עבור ואילו x x 1 xמתקיים צעד האינדוקציה: אנו משנים את הערך של h להיות m רק אם באמת m 2 x< ולכן (הערך החדש של ; x > h) אנו משנים את הערך של l להיות m רק אם m 2 x ולכן (הערך החדש של. x l) 20
In General This type of binary search can be used to find the roots of any continuous function f. Mean Value Theorem: if f(low)<0 and f(high)>0 then for some low<x<high, f(x)=0. In our case, to find 2, 2 we solved f ( x) x 2 0
Run time Analysis 22
How fast will your program run? The running time of your program will depend upon: The algorithm The input Your implementation of the algorithm in a programming language The compiler/interpreter you use The OS on your computer Your computer hardware Maybe other things: temperature outside; other programs on your computer; Our Motivation: analyze the running time of an algorithm as a function of only simple parameters of the input.
Some timings on my old office PC 24
Comparing with old timings in Java System Empty loop Float division PII, 333MHz, Interpreted (1998) PIII, 500MHz, compiled (2000) River, compiled (2011) ~2010 PC, Python, interpreted (2015) 196 400 10 77 1.16 10 81 88
Basic idea: counting operations Each algorithm performs a sequence of basic operations: Arithmetic: (low + high)/2 Comparison: if x > 0: Assignment: temp = x Branching: while y>0: Idea: count the number of basic operations performed on the input. Difficulties: Which operations are basic? Not all operations take the same amount of time. Operations take different times with different hardware or compilers
Difficulties do not matter so much Operation counts are only problematic in terms of constant factors. The general form of the function describing the running time is invariant over hardware, languages or compilers! for i in range(n): for j in range(n): x = x + i*j Running time is about n 2. We use Big-O notation, and say that the running time is O(n 2 )
Asymptotic behavior of functions
Mathematical Formalization Definition: Let f and g be functions from the natural numbers to the natural numbers. We write f=o(g) if there exists a constant c such that for all n: f(n) cg(n). f=o(g) c n: f(n) cg(n) This is a mathematically formal way of ignoring constant factors, and looking only at the shape of the function. f=o(g) should be considered as saying that f is at most g, up to constant factors. We usually will have f be the running time of an algorithm and g a nicely written function. E.g. The running time of the previous algorithm was O(n 2 ).
Asymptotic analysis of algorithms We usually embark on an asymptotic worst case analysis of the running time of the algorithm. Asymptotic: Formal, exact, depends only on the algorithm Ignores constants Applicable mostly for large input sizes Worst Case: Bounds on running time must hold for all inputs. Thus the analysis considers the worst-case input. Sometimes the average performance can be much better Real-life inputs are rarely average in any formal sense
Let s time some functions 31
??-- time 32
Linear O(n) -- time 33
??- time 34
Quadratic O(n 2 ) - time 35
?? - time 36
Logarithmic - O(log n) - time 37
Exponential O(2 n ) running time 38
Running time of simple GCD algorithm Theorem: The simple GCD algorithm runs in time O(min(x,y)) 39
Running time of Euclid s GCD Algorithm How fast does Euclid s algorithm terminate? From the first iteration onward we have that x > y. In an iteration where x 2y then x%y < y x/2. In an iteration where x < 2y then x%y = x-y < x/2. Thus, the value of xy decreases by a factor of at least 2 each iteration (except, maybe, the first one).
Run time analysis of Euclid s Algorithm Theorem: Euclid s GCD algorithm runs in time O(log2x + log2y) Proof: As we have seen, in every iteration of the loop (except maybe the first) the value of xy decreases by a factor of at least 2. Thus after k+1 iterations the value of xy is at most 2 -k times the original value. Since the algorithm terminates when xy=0 and since it is an integer, the algorithm must terminate at the latest when k satisfies: 2 -k xy < 1 (for the original values of x, y). Thus the algorithm runs for at most 1+log 2 (xy) iterations. Each iteration has only a constant number of operations, thus the total running time is O(log 2 (xy)) = O(log x + log y).
Run time comparison Simple GCD Euclid GCD asymptotic O(min(x,y)) O(log(x)+log(y)) 2 digit numbers 100 Fraction of a second 9 digit numbers 10 9 1000000000 a minute 18 digit numbers 10 18 1000000000000000000 Hundreds of years log 2 (100) 7 Fraction of a second log 2 (10 9 ) 30 Fraction of a second log 2 (10 18 ) 60 Fraction of a second Actual run times assume that python does around 10,000,000 simple loops per second 42
Binary search Square root algorithm h-l goes down by a factor of 2 each iteration. Starts at max(1, x), finishes when reaching Run time is O(log 2 (x/ )) = O(log x + log (1/ ))
Algorithms on Arrays 44
Array access operations O(1) 45
Random Access Memory 57 58 59 60 61 62 63 64 a a[3] To access a[i], take start location of a, and add i to it to get the address in RAM 46
Array Append O(1) Implementation Logic: If (out of space) Then (copy to a new place that has twice the space) 47
Array Search O(n) 48
Dictionary Access and Search O(1) 49
Hash Tables key value hagar 123 david 456 noah 789 hash( hagar ) = 7 hash( david ) = 2 hash( noah ) = 4 456 789 123 0 1 2 3 4 5 6 7 50
Input: An array The sorting problem Output: The same array, with the elements reordered from smallest to largest. [53, 12, 77, 23, 50] [12, 23, 50, 53, 77] [ yossi, david, anat, gila ] [ anat, david, gila, yossi ] 51
Comparison in Python 52
Selection Sort 53
Selection Sort i 5 3 2 1 4 0 1 3 2 5 4 1 1 2 3 5 4 2 1 2 3 5 4 3 1 2 3 4 5 4 1 2 3 4 5 54
Proof of Correctness: Argmin Theorem: argmin returns the index of the smallest element in a[start:] Invariant: When the iteration with value i ends, index holds the location of the smallest element in a[start:i+1] 55
Proof of Correctness: sort Theorem: When sort terminates, the array a holds the original elements, but in sorted order. Invariants: a always holds the same multi-set of elements After the i th iteration, a[:i+1] holds the smallest i+1 elements of a in sorted order 56
Selection Sort O(n 2 ) Runtime O(n) O(n) times argmin 57
Binary Search Sample Run [10,20,30,40,50] Find(20) l h m 0 5 2 0 2 1 58
Binary Search Sample Run [10,20,30,40,50] Find(25) l h m 0 5 2 0 2 1 2 2 59
Binary Search O(log n) Runtime Invariant: a[l-1] < x < a[h] (where we consider a[-1]=-, a[len(a)]= 60