/* * Ben Sowell * 6-20-06 */ #include #include #include #include #include //for getopt struct Bidder { double budget; double T; }; struct Bidder *bidders; int *subsetArray; int numBidders; /** * Generates the specified number of bidders with budgets * chosen from a uniform random distribution between * minBudget and maxBudget. Also initializes the subestArray, *which will be used to generate a random subset of bidders. * * @param num The number of bidders to generate. * @param minBudget The smallest possible budget. * @param maxBudget The largest possible budget. */ void generateBidders(int num, double minBudget, double maxBudget) { numBidders = num; int i; for(i = 0; i < num; i++) { bidders[i].budget = minBudget + (maxBudget - minBudget) * (double) rand() / (double) (RAND_MAX + 1.0); bidders[i].T = 0; subsetArray[i] = i; } } /** * Randomly generates num bids between min and max and * finds which one maximizes the tradeoff function as specifed * in "AdWords and Generalized On-line Matching" by Mehta et. al. * * @param num The number of bids to generate. * @param min The minimum bid size. * @param max The maximum bid size. * @return The revenue made from this query. */ double getQueryRevenue(int num, double min, double max) { int maxBidderID = 0, swapNum, temp; double bid = 0.0, maxBid = 0.0, bidTest = 0.0, maxBidTest = 0.0; int i; for(i = 0; i < num; i++) { swapNum = (int) (numBidders - i) * (double) rand() / (double) (RAND_MAX + 1.0) + i; temp = subsetArray[i]; subsetArray[i] = subsetArray[swapNum]; subsetArray[swapNum] = temp; bid = (max - min) * (double) rand() / (double) (RAND_MAX + 1.0) + min; bidTest = bid * (1 - exp(bidders[subsetArray[i]].T - 1)); if(bidTest > maxBidTest) { maxBidTest = bidTest; maxBidderID = subsetArray[i]; maxBid = bid; } } bidders[maxBidderID].T += maxBid/bidders[maxBidderID].budget; return maxBid; } /** * Runs AdWords algorithm by using query data from the * specifed file. This file should be in the form: * * n * b1 min1 max1 * b2 min2 max2 * b3 min3 max3 * ... * where n is the total number of queries, bi is the number of * bids for the ith query, and mini and maxi are the are the minimum * and maximum values for each bid. Each bid is randomly chosen * from a uniform random distribution between min and max. * * In order for this method to work properly, generateBidders * must have been called so that the bidders array is properly * instantiated. * * @param fileName The file containing the query data. * @return The revenue from this run. */ double runFromQueryFile(char* fileName) { FILE *f = fopen(fileName, "r"); int numQueries, num; double min, max, revenue = 0.0; fscanf(f, "%d\n", &numQueries); int i; for(i = 0; i < numQueries; i++) { fscanf(f, "%d %lg %lg", &num, &min, &max); revenue += getQueryRevenue(num, min, max); } return revenue; } /** * Runs the AdWords algorithm where all data is specified in a file. * The file should be of the following form: * * numBidders * budget1 * budget2 * ... * numQueries * numBids bidder1 bid1 bidder2 bid2 ... * numBids bidder1 bid1 bidder2 bid2 ... * ... * * @param fileName The file containing the bidder and query data. * @return The revenue generated by this run. */ double runFromFile(char* fileName) { int bidderID, maxBidderID; double maxBid, bid, bidTest, maxBidTest; double revenue = 0.0; FILE *f = fopen(fileName, "r"); int num, numBids; double budget; /*Read the number of bidders and allocate the appropriate amount of memory*/ fscanf(f, "%d\n", &numBidders); bidders = (struct Bidder*) malloc(sizeof(struct Bidder) * numBidders); int i, j; for(i = 0; i < numBidders; i++) { fscanf(f, "%lg\n", &budget); bidders[i].budget = budget; bidders[i].T = 0; } fscanf(f, "%d\n", &num); for(i = 0; i < num; i++) { maxBidTest = 0.0; maxBidderID = 0; maxBid = 0.0; fscanf(f, "%d", &numBids); for(j = 0; j < numBids; j++) { fscanf(f, "%d %lg", &bidderID, &bid); bidTest = bid * (1 - exp(bidders[bidderID].T - 1)); if(bidTest > maxBidTest) { maxBidTest = bidTest; maxBidderID = bidderID; maxBid = bid; } } bidders[maxBidderID].T += maxBid/bidders[maxBidderID].budget; revenue += maxBid; } fclose(f); return revenue; } /** * Runs the AdWords algorithm for numQueries where * each query has a number of bids randomly chosen from * a uniform distribution between 0 and numBidders. Each * bid is between min and max. * * In order for this method to work properly, generateBidders * must have been called so that the bidders array is properly * instantiated. * * @param numQueries The number of queries. * @param min The minimum bid size. * @param max The maximum bid size. */ double runFromRandomQueries(int numQueries, double min, double max) { int num; double revenue = 0.0; int j; for(j = 0; j < numQueries; j++) { //Check that this works num = (int) numBidders * (double) rand() / (double) (RAND_MAX + 1.0); revenue += getQueryRevenue(num, min, max); } return revenue; } int main(int argc, char *argv[]) { srand(time(0)); double revenue; /* * The only parameter is a fileName, so we call * runFromFile. */ if(argc == 2) { fflush(stdout); revenue = runFromFile(argv[1]); free(bidders); printf("revenue: %g\n", revenue); } /* * The user specified, the number of bidders, min and max * budget size, the number of queries, and min and max query * size. We call runFromRandomQueries. */ else if(argc == 7) { int numQueries; double minBudget, maxBudget, minBid, maxBid; sscanf(argv[1], "%d", &numBidders); sscanf(argv[2], "%lg", &minBudget); sscanf(argv[3], "%lg", &maxBudget); sscanf(argv[4], "%d", &numQueries); sscanf(argv[5], "%lg", &minBid); sscanf(argv[6], "%lg", &maxBid); bidders = (struct Bidder*) malloc(sizeof(struct Bidder) * numBidders); subsetArray = (int*) malloc(sizeof(int) * numBidders); generateBidders(numBidders, minBudget, maxBudget); revenue = runFromRandomQueries(numQueries, minBid, maxBid); printf("revenue: %g\n", revenue); free(bidders); free(subsetArray); } /* * The user specifed the number of bids, the min * and max budgets, and a file name, so we call * runFromQueryFile. */ else if(argc == 5) { double minBudget, maxBudget; sscanf(argv[2], "%d", &numBidders); sscanf(argv[3], "%lg", &minBudget); sscanf(argv[4], "%lg", &maxBudget); bidders = (struct Bidder*) malloc(sizeof(struct Bidder) * numBidders); subsetArray = (int*) malloc(sizeof(int) * numBidders); generateBidders(numBidders, minBudget, maxBudget); revenue = runFromQueryFile(argv[1]); printf("revenue: %g\n", revenue); free(bidders); free(subsetArray); } else { printf("Invalid arguments\n"); } return 0; }