CIS 194: Homework 7. Due Wednesday, 25 March. Preliminaries. Finger exercises

Similar documents
CS 137 Part 8. Merge Sort, Quick Sort, Binary Search. November 20th, 2017

Part 20. Sorting and Selection

CS125 : Introduction to Computer Science. Lecture Notes #38 and #39 Quicksort. c 2005, 2003, 2002, 2000 Jason Zych

Sorting. CSE 143 Java. Insert for a Sorted List. Insertion Sort. Insertion Sort As A Card Game Operation. CSE143 Au

Sorting. CSC 143 Java. Insert for a Sorted List. Insertion Sort. Insertion Sort As A Card Game Operation CSC Picture

COSC 311: ALGORITHMS HW1: SORTING

Randomized Algorithms: Selection

CIS 194: Homework 6. Due Wednesday, 4 March. Fibonacci numbers. It s all about being lazy.

Mergesort again. 1. Split the list into two equal parts

Mergesort again. 1. Split the list into two equal parts

CS240 Fall Mike Lam, Professor. Quick Sort

CSE373: Data Structure & Algorithms Lecture 21: More Comparison Sorting. Aaron Bauer Winter 2014

According to Larry Wall (designer of PERL): a language by geniuses! for geniuses. Lecture 7: Haskell. Haskell 98. Haskell (cont) - Type-safe!

7. Arrays, More Java Looping

Sorting. Task Description. Selection Sort. Should we worry about speed?

COMP2012H Spring 2014 Dekai Wu. Sorting. (more on sorting algorithms: mergesort, quicksort, heapsort)

CIS 194: Homework 11. Due Thursday, April 5. Risk. The Rand StdGen monad

CIS 194: Homework 5. Due Wednesday, 25 February, Preface. Setup. JSON files. String theory

COSC242 Lecture 7 Mergesort and Quicksort

Overview of Sorting Algorithms

CSE 332: Data Structures & Parallelism Lecture 12: Comparison Sorting. Ruth Anderson Winter 2019

Table ADT and Sorting. Algorithm topics continuing (or reviewing?) CS 24 curriculum

QuickSort

Solution sheet 1. Introduction. Exercise 1 - Types of values. Exercise 2 - Constructors

CIS 194: Homework 6. Due Friday, October 17, Preface. Setup. Generics. No template file is provided for this homework.

CS61BL. Lecture 5: Graphs Sorting

Object-oriented programming. and data-structures CS/ENGRD 2110 SUMMER 2018

CS1 Lecture 30 Apr. 2, 2018

Sorting is a problem for which we can prove a non-trivial lower bound.

Quicksort (Weiss chapter 8.6)

CSCI 204 Introduction to Computer Science II

Sorting. Riley Porter. CSE373: Data Structures & Algorithms 1

Algorithmic Analysis and Sorting, Part Two

SAMPLE OF THE STUDY MATERIAL PART OF CHAPTER 6. Sorting Algorithms

Technical Interviews Kenny Yu

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Sorting lower bound and Linear-time sorting Date: 9/19/17

Scan and Quicksort. 1 Scan. 1.1 Contraction CSE341T 09/20/2017. Lecture 7

Better sorting algorithms (Weiss chapter )

DO NOT. UNIVERSITY OF CALIFORNIA Department of Electrical Engineering and Computer Sciences Computer Science Division. P. N.

Lecture 6: Sequential Sorting

Lecture 2: Divide&Conquer Paradigm, Merge sort and Quicksort

9. The Disorganized Handyman

Deterministic and Randomized Quicksort. Andreas Klappenecker

COMP Data Structures

Key question: how do we pick a good pivot (and what makes a good pivot in the first place)?

Real-world sorting (not on exam)

Quicksort (CLRS 7) We saw the divide-and-conquer technique at work resulting in Mergesort. Mergesort summary:

CS102 Sorting - Part 2

Data structures. More sorting. Dr. Alex Gerdes DIT961 - VT 2018

CS 360: Programming Languages Lecture 12: More Haskell

811312A Data Structures and Algorithms, , Exercise 3 Solutions

CSE373: Data Structure & Algorithms Lecture 18: Comparison Sorting. Dan Grossman Fall 2013

Introduction to Algorithms and Data Structures. Lecture 12: Sorting (3) Quick sort, complexity of sort algorithms, and counting sort

Haskell Refresher Informatics 2D

Lecture 7 Quicksort : Principles of Imperative Computation (Spring 2018) Frank Pfenning

CSE 373 MAY 24 TH ANALYSIS AND NON- COMPARISON SORTING

Programming Assignment 3: Divide-and-Conquer

Sorting: Given a list A with n elements possessing a total order, return a list with the same elements in non-decreasing order.

CSCI-1200 Data Structures Spring 2017 Lecture 15 Problem Solving Techniques, Continued

Cpt S 122 Data Structures. Sorting

17/05/2018. Outline. Outline. Divide and Conquer. Control Abstraction for Divide &Conquer. Outline. Module 2: Divide and Conquer

BM267 - Introduction to Data Structures

Transformation and Analysis of Haskell Source Code

DATA STRUCTURES AND ALGORITHMS

Randomized Algorithms, Quicksort and Randomized Selection

SORTING, SETS, AND SELECTION

Cosc 241 Programming and Problem Solving Lecture 17 (30/4/18) Quicksort

Introduction to Programming: Lecture 6

ECE 2574: Data Structures and Algorithms - Basic Sorting Algorithms. C. L. Wyatt

Unit-2 Divide and conquer 2016

CSE 373: Data Structures and Algorithms

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

100 points total. CSE 3353 Homework 2 Spring 2013

Scribe: Sam Keller (2015), Seth Hildick-Smith (2016), G. Valiant (2017) Date: January 25, 2017

April 2 to April 4, 2018

Unit 6 Chapter 15 EXAMPLES OF COMPLEXITY CALCULATION

DIVIDE AND CONQUER ALGORITHMS ANALYSIS WITH RECURRENCE EQUATIONS

SORTING AND SELECTION

CIS 121 Data Structures and Algorithms with Java Spring Code Snippets and Recurrences Monday, January 29/Tuesday, January 30

Haskell: From Basic to Advanced. Part 2 Type Classes, Laziness, IO, Modules

// walk through array stepping by step amount, moving elements down for (i = unsorted; i >= step && item < a[i-step]; i-=step) { a[i] = a[i-step];

( ) time in the worst case, but it is

Lecture 8: Mergesort / Quicksort Steven Skiena

Assignment 4: Question 1b omitted. Assignment 5: Question 1b clarification

L14 Quicksort and Performance Optimization

Quicksort. Alternative Strategies for Dividing Lists. Fundamentals of Computer Science I (CS F)

Introduction to Algorithms

COMP 250 Fall recurrences 2 Oct. 13, 2017

Today s Topics. Percentile ranks and percentiles. Standardized scores. Using standardized scores to estimate percentiles

Data Structures and Algorithms

Sorting Algorithms. + Analysis of the Sorting Algorithms

Exercises on ML. Programming Languages. Chanseok Oh

Information Coding / Computer Graphics, ISY, LiTH

Analysis of Algorithms - Quicksort -

CIS 194: Homework 3. Due Wednesday, February 11, Interpreters. Meet SImPL

Principles of Algorithm Design

Sorting. Weiss chapter , 8.6

CS61B Lectures # Purposes of Sorting. Some Definitions. Classifications. Sorting supports searching Binary search standard example

Intro. Scheme Basics. scm> 5 5. scm>

COMP26120 Academic Session: Lab Exercise 6: Recursive Sorting and Searching

Transcription:

CIS 194: Homework 7 Due Wednesday, 25 March Figure 1: The Haskell logo is modelled after the bind function (>>=) in the Monad type class Preliminaries Just as Haskell Strings are not as efficient as ByteStrings, lists are not as efficient as Vectors. Before you begin this homework you should make sure that you have the vector package installed by typing cabal install vector in your terminal. The Data.Vector module is designed to be similar to Data.List so you should see all of your favorite functions defined there! In order to avoid naming collisions, we import qualified Data.Vector as V. This means that you need to prefix all function calls with V. For example, V.fromList [1..10] constructs a Vector from the list [1..10]. We have also imported the Vector a type as well as a few functions non-qualified. These functions are cons, (!), (!?), and (//). You can look these up on Hoogle to figure out what they do. Later in the assignment, we will also use the Control.Monad.Random module which comes from the MonadRandom package. You will probably need to install this package by typing cabal install MonadRandom. Finger exercises The next few exercises are an opportunity to show off what you ve learned about Monads! They are focused on using Vectors and the Maybe monad. Exercise 1 Write the liftm function. This function lifts a regular function into a monad and applies it to an argument in that monad. liftm :: Monad m => (a -> b) -> m a -> m b Example: liftm (+1) (Just 5) == Just 6

cis 194: homework 7 2 The Control.Monad module defines many more lifting operations (ie, liftm2, liftm3,...). Use one of these functions to implement the function swapv :: Int -> Int -> Vector a -> Maybe (Vector a) that takes in two indices and swaps the elements at those indices in some Vector. This function should use the safe indexing operation (!?) and not the unsafe one (!). If either of the indices are out of bounds (ie (!?) returns Nothing), then the result should be Nothing. You will probably find the (//) function useful. Example: swapv 0 2 (V.fromList [1, 2, 3]) == Just (V.fromList [3, 2, 1]) Example: swapv 0 2 (V.fromList [1, 2]) == Nothing Exercise 2 Implement the function mapm that maps a monadic function across a list: mapm :: Monad m => (a -> m b) -> [a] -> m [b] Example: mapm Just [1..10] == Just [1..10] Now, use mapm to define a function that takes in a list of indices and a Vector and returns a list of the elements at those indices in the Maybe monad. If any of the indices don t exist, the function should return Nothing. Again, use the safe indexing operator (!?). getelts :: [Int] -> Vector a -> Maybe [a] Example: getelts [1,3] (V.fromList [0..9]) == Just [1, 3]

cis 194: homework 7 3 Randomized Algorithms Randomization is an extremely powerful tool in the field of algorithms. Using randomization, computationally intractable problems can be accurately approximated and slow algorithms can be made faster. In this section, we will focus on Las Vegas algorithms. A Las Vegas algorithm is an algorithm that always returns the correct result and uses randomization to improve the expected runtime. In other words, it gambles with computing resources, not with the correctness of the output. The problem with randomization is that it is impure; a randomized function may return a different result each time it is called. Does this mean we can t use randomization in Haskell? Of course not! To get around this impurity, we will use the randomness (Rnd) monad. In the same way that IO actions are not actual computations, but rather descriptions of computations, functions in the Rnd monad are descriptions of randomized computations. To evaluate a randomized function, we can use: evalrandio :: Rnd a -> IO a This makes a lot of sense; a value of type Rnd a is pure, but running it produces a value in the IO monad (which, as we know, is the only way to get an impure value in Haskell). To get a random value, use of the following functions: getrandom :: Random a => Rnd a getrandomr :: Random a => (a, a) -> Rnd a The only difference between these two functions is that getrandomr produces a random value between the two values supplied in the tuple and getrandom produces any value of type a where a is a member of the Random type class.

cis 194: homework 7 4 Exercise 3 Use the randomness monad to produce a random element of a Vector. This function should only return Nothing if the Vector has length 0. randomelt :: Vector a -> Rnd (Maybe a) Exercise 4 Now define the following two functions: randomvec :: Random a => Int -> Rnd (Vector a) randomvecr :: Random a => Int -> (a, a) -> Rnd (Vector a) These functions should produce vectors of the specified length that are populated with random elements. The elements of randomvec n can have any value of type a whereas the ones from randomvecr n (lo, hi) should all be within the specified range. Try to make use of functions from the Control.Monad module. Exercise 5 In this exercise you will implement a function that shuffles a Vector. The Fisher-Yates algorithm shuffles the elements of an array such that each element is equally likely to end up in each position. The algorithm is defined as follows: for i = n 1 down to 1, choose a random j {0, 1,..., i} and swap the elements at positions i and j. In order to save yourself some hassle, you can use the unsafe indexing operator (!), but only use it if you are sure that it won t fail! shuffle :: Vector a -> Rnd (Vector a) Quicksort The Quicksort algorithm is a very efficient sorting algorithm that was invented by Tony Hoare in 1960. The algorithm itself is very simple. You first choose a pivot, then partition the array into elements that are less than and greater than the pivot, and finally recurse on the two resulting sublists. The efficiency of the algorithm depends highly on the choice of pivot. More on this shortly! Figure 2: Sorting is hard when you don t use the right algorithms! Exercise 6 Before you implement Quicksort, you should implement a helper function that partitions a Vector around the element at a given index. partitionat :: Ord a => Vector a -> Int -> (Vector a, a, Vector a) The first argument is the Vector to be partitioned and the second argument is the index of the pivot. The output is a 3-tuple containing

cis 194: homework 7 5 a Vector of the elements less than the value of the pivot, the value of the pivot itself, and a Vector of the elements greater than or equal to the pivot in that order. Example: partitionat (V.fromList [5, 2, 8, 3, 6, 1]) 3 == (V.fromList [2, 1], 3, V.fromList [5, 8, 6]) Example: partitionat (V.fromList [1, 6, 4, 7, 2, 4]) 2 == (V.fromList [1, 2], 4, V.fromList [6, 7, 4]) Exercise 7 A naïve Quicksort implementation picks the first element in the array to be the pivot every time. In the worst case, this causes the array to be partitioned into a segment of size 0 and a segment of size Θ(n) causing the runtime to be O(n 2 ). An implementation of Quicksort that uses the first element as the pivot to sort lists is provided for you. Your job is to implement the same algorithm for Vectors instead of lists. qsort :: Ord a => Vector a -> Vector a Note that Vector is a monad! That means that you can use Monad Comprehensions to construct a Vector in the same way they are used for lists! Exercise 8 We can improve the expected runtime of Quicksort from O(n 2 ) to O(n log n) by making one simple modification. Instead of choosing the first element as the pivot each time, we will choose a random element to be the pivot. Intuitively, the reason why this is so effective is because there is a 50% chance that a random element has rank greater than n 4 and less than 3n 4, therefore with good probability the array will be split into roughly even segments. Implement randomized Quicksort: qsortr :: Ord a => Vector a -> Rnd (Vector a) Remember that you implemented the partitionat function! This function should be useful here. We know that randomized Quicksort is theoretically faster than deterministic Quicksort, but is it really faster in practice? Try sorting V.fromList (reverse [1..10000]), the integers from 1 to 10,000 in reverse order, using both implementations:

cis 194: homework 7 6 > let v = V.fromList $ reverse [1..10000] > qsort v > evalrandio $ qsortr v Did you notice a difference? On my machine, the deterministic algorithm took over a minute and the randomized one was instantaneous! Exercise 9 There is a randomized algorithm for selection that is very closely related to Quicksort. The purpose of this algorithm is to select the element with rank i in an unsorted array. For example, select 0 v selects the minimum element, select (n - 1) v selects the maximum element, and select (n div 2) v selects the median. The naïve implementation of this algorithm would simply sort the array and then return the element at position i. However, sorting is overkill here since all we care about is a single element. A better version uses the same divide and conquer approach that Quicksort uses and runs in expected linear time. First, you choose a random pivot p and partition the array around it. This gives you left and right sub-arrays L and R. If i < L, then you know that the element you are looking for is in L, so you should recurse on L. If i = L, then p must have rank i. Finally, if i > L, the element must be in R, so you should recurse on R searching for rank i L 1. Implement the function: select :: Ord a => Int -> Vector a -> Rnd (Maybe a) This function selects the element of rank i by the algorithm described above. Notice that this function returns an Rnd (Maybe a). This is because the rank that is asked for may be outside the bounds of the Vector. In this case, you should return Nothing. Playing Cards The Cards.hs module defines several data types to represent playing cards. The code in this module is mostly boilerplate, but you should familiarize yourself with the Deck and Card types before you start the next few exercises. Exercise 10 It would be useful to be able to get a deck that contains all of the cards grouped by suit (Spade, Heart, Club, Diamond), and arranged from Two to Ace. Implement: allcards :: Deck

cis 194: homework 7 7 which is simply a Vector of Cards arranged in the order stated above (don t worry, this is much easier than allcodes from HW02). You should implement allcards as a Monad Conprehension. You will probably find suits and labels in the Cards module useful. Now that you have allcards, write: newdeck :: Rnd Deck This should return a new Deck that contains all of the cards from allcards, but in a random order. Remember that you already implemented shuffle! Exercise 11 We also need some sort of uncons ing operation for Decks. That is, a function that takes in a Deck and gives you the head and tail (since we can t pattern match on Vector like we can with lists). Implement the function: nextcard :: Deck -> Maybe (Card, Deck) This function takes in a Deck and returns the head and tail of the Deck in the Maybe monad. If the Deck is empty, it should return Nothing. Exercise 12 In many card games, we need to draw multiple cards at once from a deck. Implement the function: getcards :: Int -> Deck -> Maybe ([Card], Deck) This function should draw n cards from the given Deck where n is the first input to the function. Try to make use of nextcard and the Maybe monad in order to avoid pattern matching on Maybe. If the Deck has fewer than n Cards remaining then this function should return Nothing. Exercise 13 Relax! This isn t a real exercise. Now that you have implemented some operations on the Deck type, you can have some fun. Compile this file with GHC by typing GHC HW07.hs -main-is HW07 and then run the resulting executable. In the spirit of the Las Vegas algorithms you implemented earlier, this is a text-based War game with betting. Each round, you place a bet and then you and the computer both draw a card from the deck. Whoever has a higher card wins. If there is a tie, then each player draws 3 more cards and the last card that each player draws is compared. The game ends when you either run out of money, the deck is empty, or you choose to leave. Have fun, and gamble responsibly! Figure 3: Don t put all your eggs in one basket!