Logo
  • Home
  • Classes
  • Conveying Computing
  • Exams
  • Fractal Gallery
  • Guides
  • Problem Sets
  • Syllabus

Problem Set 5: Wahoo! Auctions

Turn-in Checklist:
  1. Bring in to a stapled turn-in containing your written answers to all questions and all of your code by 11:01am Friday, 21 October. (There is no automatic adjudication for this problem set.)
  2. If you work with a partner, your team should submit a single writeup with both of your names and UVa IDs on it.

Collaboration Policy - Read Very Carefully

You may work on this assignment alone or with one partner of your choice so long as it is not someone with whom you have partnered on two or more previous problem sets. Regardless of whether you work alone or with a partner, you are encouraged to discuss this assignment with other students in the class and ask and provide help in useful ways.

Remember to follow the pledge you read and signed at the beginning of the semester. For this assignment, you may consult any outside resources, including books, papers, web sites and people, you wish except for materials from previous cs1120, cs150, and cs200 courses. If you use resources other than the class materials, lectures and course staff, explain what you used in your turn-in.

Purpose

  • Gain understanding of the asymptotic operators and how to use them to describe the costs of executing procedures.
  • Learn to program using state and mutation.
  • Learn how mutation changes the Scheme evaluation rules.
  • Learn about databases and SQL commands.
  • Save the University from further cuts to "non-essential" services.
Reading: Course book through the end of Chapter 9.
Download: Download ps5.zip to your machine and unzip it into your cs1120 directory. This file contains:
  • ps5.rkt — A template for your answers. You should do the problem set by editing this file.
  • auction.rkt — Partial code for setting up an auction.
  • database.rkt — Partial implementation of a database.
  • book-code.rkt — Some useful procedures from the book (Chapter 5 and Chapter 9)

Background

Once upon a time, in a faraway fictional town known as Charlottansville, East Virginia, there was a highly regarded public university where funding cuts led to a budget crisis. The wise and noble University administration tried cutting "non-essential" services such as heat and cleaning for student housing, libraries, printing and professors and have attempted some more creative solutions including hosting rock concerts, building a fancy new basketball arena, increasing student tuition, adding extra digits to course numbers, replacing an adequate student information system with a dysfunctional one, and opening physicist shops, but somehow the budget is still not balanced and the University is expecting further extractions from the Commonbroke government.

Fortunately, the University was able to get "Chapter 11" status from the Commonwealth, which gives it more power to control its own destiny by raising tuition and selling bagels. The Board of Transients has decided the time for drastic measures has arrived, and they will conduct an auction to raise money. To avoid paying fees to a commercial auction service, they have decided to exploit free labor from cs1120 students to develop an auction service for them.

Before they hire you for this important task, however, you need to show that you have a good understanding of how to measure cost asymptotically.

Measuring Cost

For each of the following subquestions, you will be given two functions, g and f that take a single parameter n (which must be a non-negative integer) and asked to determine which of O (f(n)), Ω (f(n)), and Θ(f(n)) contain g. It is possible that more than one of the sets contain g.

In addition to identifying the properties that hold, you should justify your answer by:

  • For each property that is true, select c and n0 values and show why the necessary inequality holds for all n >n0.
  • For each property that is false, explain why no such c and n0 values exists. One way to do this is to show how for any selected c value, you can find infinitely many n values that fail to satisfy the necessary property.
For example, if g is n2 and f is n3 you would argue:
  • n2 is in O (n3) since if we pick c = 1 and n0 = 1 then n2 ≤ cn3 for all n > 1.
  • n2 is not in Ω(n3) since for any c value we know n2 is not ≥ c n3 for all n > 1/c. This is the case since we can simplify the inequality to 1 ≥ cn which is not true if we choose n > 1/c.
  • n2 is not in Θ(n3) since n2 is not in Ω(n3).
Question 1: For each g and f pair below, argue convincingly whether or not g is (1) in O(f), (2) in Ω(f), and (3) in Θ(f) as explained above. For all questions, assume n is a non-negative integer.
  1. g: n + 3, f: n
  2. g: n2 + n, f: n2
  3. g: 2n, f: 3n
  4. g: 2n, f: nn
  5. g: the federal debt n years from today, f: the US population n years from today (this one requires a more informal argument)

Databases

The auction service will be built using a database. A database is just a way of storing and manipulating structured data. For this problem set, you will implement a database and use it to implement an auction service. Our database is controlled using Scheme procedures that are similar to the SQL commands used to control nearly all commercial databases.

Data in a database is stored in tables. The fields of a table describe the data and are not mutable. The entries of a table are the data, and can be changed.

We represent a table using a mutable mcons pair where the mcar is a list of the table fields and the mcdr is a list of the table entries. Note that we use a mutable pair to represent the table so can mutate the fields and entries associated with a table.

These definitions are found in database.rkt:

(define (make-table fieldlist entries) 
  (make-tlist 'table (mcons fieldlist entries)))

(define (make-new-table fieldlist) 
  (make-table fieldlist null))

(define (table-fields t) (mcar (tlist-get-data 'table t)))
(define (table-entries t) (mcdr (tlist-get-data 'table t)))
They use a tagged list to make an abstract datatype (as in Section 5.6).

For the Wahoo! Auctions service, we will need several different tables to keep track of the bidders, the items for sale, and the bids on those items. We use quoted symbols to describe the fields in a table. Those tables are defined in auction.rkt:

     (define bidders (make-new-table (list 'name 'email)))
     (define items (make-new-table (list 'item-name 'description)))
     (define bids (make-new-table (list 'bidder-name 'item-name 'amount)))
Question 2:

a. Draw the global environment after the following expressions are evaluated:

   (define t1 (mcons 'name 'email))
   (set-mcar! t1 'nom)
   (set-mcdr! t1 'courriel)
   (set-mcdr! t1 t1)
b. Suppose we then evaluate (mlist-length t1) where mlist-length is defined as in Section 9.3. Explain why the evaluation of (mlist-length t1) never terminates.

Try evaluating the expressions in Question 2 in DrScheme. Also evaluate t1 and see if you can figure out what the printed value means.

Inserting Entries

We want to define more abstract procedures for manipulating data tables.

The table-insert! procedure inserts an entry into a table. We follow the Scheme (and Yahoo!?) convention of using an ! at the end of the names of procedures that mutate state. You should follow this convention also.

You shouldn't need to change the definition of table-insert!, but you should be able to understand it (defined in database.rkt):

(define (table-insert! table entry)
  ;;; The entry must have the right number of values --- one for each
  field in the table
  (assert (= (length entry) (length (table-fields table))))
  (if (null? (table-entries table))
      (set-mcdr! (tlist-get-data 'table table) (mlist entry))
      (mlist-append! (table-entries table) (mlist entry)))
  (void)) ;;; don't evaluate to a value

The expression (assert (= (length entry) (length (table-fields table)))) checks that the entry we are adding to the table has the right number of elements — there must be one element in the entry corresponding to each field in the table. Note that we use length here instead of mlength because we are making the entries themselves immutable. This means we can change the entries in the table (since the entries is a mutable list), but we cannot change the value of an entry itself.

The assert procedure will produce an error if the passed parameter is false. It is defined (in book-code.rkt):

(define (assert pred)
  (if (not pred) (error "Assertion failed!")))

Next, it uses an if expression that tests if (table-entries table) is null. The consequent expression uses set-mcdr! to replace the cdr part of the table data with a new mutable list containing a single element, the inserted entry. The alternate expression uses mlist-append! (from Example 9.4 in the course book) to mutate the table entries by adding the input entry to the list. Note that mlist-append! does not work when the input list is null since there is no way to mutate null (it is not a mutable cons pair, but it is a mutable list). This is why we needed the if expression with the consequent expression for handling the case where the entries are empty.

We use (void) at the end of the procedure body to prevent an application of table-insert! from evaluating to a value. The procedure void takes no parameters, and produces no value.

Our auction service will need procedures for adding bidders, posting items for sale and bidding on items. We have provided a definition of add-bidder! in ps5.ss:

(define (add-bidder! name email)
  (table-insert! bidders (list name email)))
It takes two parameters (name and email) and adds an entry in the bidders table. Understanding it should give you a good idea how to define some additional procedures.

We have defined a table-display procedure in database.rkt for printing out a table. (You don't need to understand the details of how table-display works.)

You should obtain the following interactions:

> (table-display bidders)

name                       email                      
-------------------------  -------------------------  

> (add-bidder! "Tim Koogle" "tk@yahoo.com")

> (add-bidder! "Katie Couric" "katie@cbs.com")

> (add-bidder! "Dave Matthews" "dave@dmb.com")

> (add-bidder! "Paul Rice" "paul.rice@mac.com")

> (table-display bidders)

name                       email                     
-------------------------  ------------------------- 
Tim Koogle                 tk@yahoo.com              
Katie Couric               katie@cbs.com
Dave Matthews              dave@dmb.com              
Paul Rice                  paul.rice@mac.com	

Question 3:

a. Define post-item! as a procedure that takes two parameters (name, description) and adds an entry with the given name and description to the items table.

b. Describe the running time of your post-item! procedure. Your answer should use Θ notation, clearly explain what all variables you use mean, and include a convincing explanation of why your answer is correct.

Question 4:

a. Define insert-bid! as a procedure that takes three parameters (bidder, item and amount) and adds a corresponding entry to the bids table.

b. Describe the running time of your insert-bid! procedure. Your answer should use Θ notation, clearly explain what all variables you use mean, and include a convincing explanation of why your answer is correct.

Develop tests for your post-item! and insert-bid! procedures similar to the add-bidder! examples above, and make sure they also work correctly.

Selecting Entries

Inserting entries in tables is only useful if we can also get the entries we are interested in out of the table. The table-select procedure takes a table, a field and a procedure. It evaluates to a table that has the same fields as the input table, and has entries that are all entries in the table for which the procedure applied to the value of the field for that entry is true.

For example,

(table-select bids 'item-name (lambda (pitem) (string=? pitem "CLAS")))
should produce a table with the same fields as the bids table, (bidder-name item-name amount), but only containing those entries whose item-name matches the string "CLAS".

So, to define table-select, you will first need to find the index of the selected field (e.g., 'item-name in the example). We have provided (in book-code.ss) the list-find-element procedure that may be helpful for this. It takes as input a list and a value, and outputs a number that indicates what is the first element of the input list that matches the input value. Elements are numbered starting from 1. If none of the elements match, the output is 0.

(define (list-find-element p el) ; evaluates to the index of element el
  (define (list-find-element-helper p el n)
    (if (null? p)
        0 ; element not found
        (if (eq? (car p) el)
            n
            (list-find-element-helper (cdr p) el (+ n 1)))))
  (list-find-element-helper p el 1))
Using list-find-element, we have defined table-field-number, a procedure that takes a table and a field and outputs the index of that field in the table's field list:
(define (table-field-number table field)
  (list-find-element (table-fields table) field))
The fields are indexed starting from 1; if the field is not in the table, table-field-number outputs 0.

Hence, you could start to define table-select as:

(define (table-select table field predicate)
  (let ((fieldno (table-field-number table field)))
    (if (= fieldno 0) 
	    (error "No matching field: ~a" field)
        ...

Another procedure you may find helpful in finishing the definition of table-select is the mlist-filter procedure (defined in book-code.rkt:

(define (mlist-filter test p)
  (if (null? p) null
      (if (test (mcar p))
          (mcons (mcar p) (mlist-filter test (mcdr p)))
          (mlist-filter test (mcdr p)))))
Note that this procedure is very different from mlist-filter! from Example 9.3. It does not mutate the input list (hence the lack of a ! in its name), but instead creates a new mutable list that contains only those elements in the input list for which the test function evaluates to true.

Question 5:

a. Define the table-select procedure.

b. Describe the asymptotic running time of your table-select procedure using Θ notation. Be careful to specify carefully what any variables you use in your answer mean.

If your table-select is working correctly, you should see interactions similar to these:

Remember our University is completely fictional. The bid amounts should not be construed to have anything to do with the actual value of any aspects of any real Universities with which you might be familiar or with the generosity of actual University alumni who might have similar names.

> (insert-bid! "Tim Koogle" "SEAS" 10000000)

> (insert-bid! "Dave Matthews" "CLAS" 2000000)

> (insert-bid! "Katie Couric" "CLAS" 37000000)

> (table-select bids 'item-name (lambda (pitem) (string=? pitem "CLAS")))

(table . {(bidder-name item-name amount) ("Dave Matthews" "CLAS" 2000000) ("Katie Couric" "CLAS" 37000000)})

> (table-display (table-select bids 'item-name (lambda (pitem) (string=? pitem "CLAS"))))

bidder-name                item-name                  amount
-------------------------  -------------------------  -------------------------
Dave Matthews              CLAS                       2000000
Katie Couric               CLAS                       37000000

> (table-entries (table-select bids 'item-name (lambda (pitem) (string=? pitem "SEAS"))))

{("Tim Koogle" "SEAS" 10000000)}

> (table-entries (table-select bids 'item-name (lambda (pitem) (string=? pitem "Rotunda"))))

()

> (table-entries (table-select bids 'amount (lambda (pamount) (> pamount 10000000))))

{("Katie Couric" "CLAS" 37000000)}

> (table-entries
    (table-select
      (table-select bids 'amount (lambda (pamount) (<= pamount 10000000)))
      'bidder-name
      (lambda (pbidder) (string=? pbidder "Katie Couric"))))

Selects can be nested since they produce tables as output. Here we use (table-select bids 'amount (lambda (pamount) (<= pamount 10000000))) to produce the table of all bids over 10000000, and then use another table-select to select the bids from that table where the bidder name is "Katie Couric". To make sure you understand table-select, produce a different expression that will evaluate to the same table by selecting the name first and then the amount.

()

In auction.rkt we define define some procedures for making it easier to do table selects:

  (define (make-string-selector match) (lambda (fval) (string=? fval match)))

  (define (get-bids item)
    (table-entries (table-select bids 'item-name (make-string-selector item))))

The get-bids procedure evaluates to a list of bid entries that are the entries in the bids table whose item-name field matches the parameter item. If you're not sure how this works, try evaluating some expressions using make-string-selector by themselves.

Highest Bids

In any auction, it is important to know who currently has the highest bid.
Question 6:

a. Define a get-highest-bid procedure that takes an item name as a parameter and evaluates to the bid entry that is the highest bid on that item. If there is no bid, return null. You shouldn't assume that the last entry that is a bid on this item is the highest bid for that item.

b. Describe the asymptotic running time of your get-highest-bid procedure using Θ notation. Be careful to specify carefully what any variables you use in your answer mean.

Your get-highest-bid procedure should work like this:

> (setup-tables)

> (get-highest-bid "SEAS")

("Tim Koogle" "SEAS" 10000000)

> (get-highest-bid "Rotunda")

()

Placing Bids

To conduct fair auctions, we can't just allow any bid to be inserted into the bids table. Instead, bids will be placed using a place-bid! procedure. It should:

  • Only allow bids by a bidder who is in the bidders table. If a bid is made by someone who is not in the bidders table, place-bid! should report an error and not modify the bids table.
  • Only allow bids on items that are up for sale. If a bid is made for an item that does not match the name of an item in the items table (or that matches multiple items), the place-bid! procedure should report an error and not modify the bids table.
  • Only allow a new bid on an item if the amount of the bid exceeds the amount of the highest earlier bid for the item. If a bid is made that is equal to or less than that amount, place-bid! should report an error and not modify the bids table.
  • Otherwise modify the bids table and return true to indicate success if the bid can be successfully placed.

To report an error, use the error procedure. It take a list of values and prints them as an error message, terminating the execution. For example: (error bidder "is not an authorized bidder!"). The exact prose of your error message doesn't matter — only that it clearly indicates what the problem is. So be as creative as you like with your error messages.

Question 7: Define a place-bid! procedure that satisfies the description above. Don't attempt to do everything at once! Start by satisfying one of the properties first and testing your procedure before trying to satisfy the other property.

Hint: place-bid! may be a relatively long procedure: 25 to 30 lines is reasonable. Don't worry if yours is longer or shorter, as long as you understand what is going on and you are getting the right answers.

You should get interactions similar to these:

> (setup-tables)

> (place-bid! "Tim Koogle" "SEAS" 20000000)

#t

> (place-bid! "Katie Couric" "SEAS" 18000000)

Bid amount does not exceed previous highest bid: {"Tim Koogle" "SEAS" 20000000}

> (place-bid! "Katie Couric" "SEAS" 22000000)

#t

> (place-bid! "Dave Matthews" "The Rotunda" 1000000)

The Rotunda is not for sale!

> (place-bid! "David Evans" "Rice Hall" 10000000000)

David Evans is not a legitimate bidder!

Ending the Auction

When the auction is over, all items are sold to the highest bidders and the University collects the high bid amounts. If there are no bids for an item, it cannot be sold.

Question 8:

a. Define a procedure end-auction! that reports the final auction results. You may assume that the auction has been conducted fairly (i.e., using place-bid! and not by randomly mutating the tables). For each item in the auction, your procedure should print out a message indicating who won the item and for what price, or that there were no bits on the item.

b. Describe the running time of your end-auction! procedure. (You answer should use Θ notation, should clearly define the meaning of all variables you use in your answer, and should include a convincing explanation of why it is correct.)

For better than gold-star level performance, your end-auction! should evaluate to a number representing the total amount of money the University makes from the auction. It is acceptable for a gold-star level solution to produce no output.)

Here's an example:

> (setup-tables)

> (end-auction!)

Congratulations Tina Fey!  You have won the CLAS for $37000000.
Congratulations Tim Koogle!  You have won the SEAS for $10000000.
Congratulations D'Brickashaw Ferguson!  You have won the CS1120 for $1120000.
No bids on Olsson Hall.
Congratulations Paul Rice!  You have won the Rice Hall for $10000000.
Congratulations Dave Matthews!  You have won the SIS for $2.

58120002

Try some sample auctions to demonstrate your program. See if you can make enough money to save the University without further tuition increases, but be careful not to sell off too many important assets — we will revisit the University in Charlottansville in Problem Set 6.



Credits: This problem set was created for CS200 Spring 2003 by Katie Winstanley, Rachel Dada, Spencer Stockdale and David Evans, and revised for subsequent semesters by Sarah Bergkuist and Wes Weimer.
Print Friendly Print Get a PDF version of this webpage PDF

4 Responses to “Problem Set 5: Wahoo! Auctions”

  1. Guy says:
    19 October 2011 at 5:45 am

    Not sure if this has affected anyone but the ‘mlist-length’ procedure defined in “book-code.rkt” needs a space between the + and the 1 or it will cause your program to crash if you use the method

    Log in to Reply
    • David Evans says:
      19 October 2011 at 6:05 am

      Opps, sorry about that! You do need the space after the +, since otherwise +1 is interpreted as just the number +1, so the expression (+1 (mlist-length (cdr p))) would be interpreted as a bad application expression since the first subexpression is a number, not a procedure.

      Log in to Reply
  2. Kevin Liu says:
    23 October 2011 at 5:21 am

    Is the set-up tables function supposed to be predefined?

    Log in to Reply
    • David Evans says:
      23 October 2011 at 8:22 am

      setup-tables is defined in auction.rkt

      Log in to Reply

Leave a Reply Cancel reply

You must be logged in to post a comment.

cs1120 | RSS | Comments RSS | Book | Using These Materials | Login | Admin | Powered by Wordpress