title:- A=[ '% Second Price Auction : A Vickrey-Clarke-Groves Mechanism ', '% program: spa.pl ', '% created: 28-30 Jun 2004.', '% previous: pivotal.pl(28 Jun 2004)', '% author: Kenyo Indo (Kanto Gakuen University)', '% --------main predicates ---------', '% go/0, pivotal/1, pivotal_data/2. ', '% find_best_response_of/5, nash_equilibrium/1. ', '% truthful/3, truth_telling_profile/1. ', '% explain/0, explain_j/0, reference.', '% allocation/4 (combinatorial auction in Appendix)' ], forall(member(L,A),(nl,write(L))),nl. reference:- A=[ '% reference:', '% [1] Clarke, E. (1971). Multipart pricing of public goods. Public Choice 11: 17-33. ', '% [2] Groves, T. (1973). Incentives in teams. Econometrica 41: 617-31. ', '% [3] Holtzman, R., N. Kfir-Dahav, D. Monderer, and M. Tennenholtz (2004). Bundling equilibrium in combinatorial auctions. Games and Economic Behavior 47: 104-123. ', '% [4] Pekec,A. and M. H. Rothkept (2003). Management Science 49(11):1185-1503.', '% [5] Vickrey, W. (1961). Counterspeculation, auctions, and competitive sealed tenders. Journal of Finance 16: 8-37. ' ], forall(member(L,A),(nl,write(L))). % generalization : Groves mechanism. explain:- forall(explanation(E,F),(nl,write(E),nl, tab(2),write(F))). explanation('******* VCG Mechanism for Auction *********','definitions'). explanation('cost of implementation for the project: ','r.'). explanation('social decision:','x, allocation of goods. x[i] is the i`s aquisition. '). explanation('payment for individual i : ','m[i]. The tuple m is a social transfer.'). explanation('utility function: ','u[i] = U[i,truth](x[i]) - m[i], where U is valuation.'). explanation('strategy space: ','each i reports a real number Ur[x,i]. (direct revelation)'). explanation('profile of reports: ','n-dimensional tuple Ur.'). explanation('social choice rule: ','f(Ur) = ( x(Ur), m(Ur) ).'). explanation('(rule1) ','x(Ur)= argmax sum(Ur(x)). '). explanation('(rule2) ','m[i](Ur) = max sum(Ur[k\=i](x)) - sum(Ur[k\=i](x(Ur)) + h[i](Ur[k\=i]).'). %------------------------------------- % Script for Mechanisms %------------------------------------- :- dynamic pivotal_data/2. clear:- abolish(auction_data/2). go:- clear, go1. go1:- auction(_O), fail. go1:- write(end). %------------------------------------- % Agents and Valuations %------------------------------------- agent(A):-agents(W),member(A,W). % projects object(A):-objects(W),member(A,W). % same as example 1 in model_base/1. agents([a,b,c]). objects([x,y,z]). % true valuation % valuation(Agent,State,Object,Utility). valuation(a,[x],10). valuation(b,[x],2). valuation(c,[x],9). valuation(a,[y],3). valuation(b,[y],10). valuation(c,[y],5). valuation(a,[z],4). valuation(b,[z],6). valuation(c,[z],1). % binary comparison. prefer_to(Agent,O1,O2):- valuation(Agent,O1,U1), valuation(Agent,O2,U2), U1 >= U2. % agent's bid strategy_of(A,B):- agent(A), length(L,11), nth1(K,L,_), B is (K-1). strategy_profile_0([],[]). strategy_profile_0([A|B],[C|D]):- strategy_profile_0(B,D), strategy_of(A,C). strategy_profile(B):- agents(A), strategy_profile_0(A,B). %------------------------------------ % Vickrey's Second Price Auction : A VCG Mechanism %------------------------------------ auction(O):- object(O), agents(I), strategy_profile_0(I,P), % profile of bid %allocation & transfer spa_rule([bids:P,win:W,by:HP,price:SP],allocate:L,prices:T), payoff(O,I,L,T,V), assert( auction_data( [object:O,winner:W,by:HP,price:SP], [agent:I,bid:P,payment:T,payoff:V] ) ). % ranking_of_bids(+P,-Top,-Second) %--------------------------- % The highest bidder wins. % The winner must pay the second highest value in the bids. % It is the price what might have paid if he/she did not win. spa_rule([bids:P,win:Winner,by:TopPrice,price:SecondPrice],allocate:L,prices:T):- agents(I), rank_bidder_value_pairs(agents:I,bids:P,rank:RANK), allocate_rule(agents:I,rank:RANK,allocate:L), payments_rule(agents:I,rank:RANK,prices:T), RANK=[TopPrice-Winner|[SecondPrice-_|_]]. rank_bidder_value_pairs(agents:I,bids:P,rank:RANK):- findall(B-A,(nth1(K,I,A),nth1(K,P,B)),PA), sort(PA,SPA), reverse(SPA,RANK). allocate_rule(agents:I,rank:RANK,allocate:L):- RANK=[_TopPrice-Winner|_], findall(LA, (member(A,I),win_price(Winner-1,A-LA)),L). payments_rule(agents:I,rank:RANK,prices:T):- RANK=[_TopPrice-Winner|[SecondPrice-_|_]], findall(TA, (member(A,I),win_price(Winner-SecondPrice,A-TA)),T). win_price(X,X):-!. win_price(_,_-0). /* ?- spa_rule([bids:[1,3,5],A,B,E],C,D). A = win:c B = by:5 E = price:3 C = rank:[5-c, 3-b, 1-a] D = prices:[0, 0, 3] Yes ?- */ % payoff(+O,+I,+L,+T,-V) %--------------------------- payoff(O,I,L,T,V):- findall(VA, ( nth1(K,I,A), nth1(K,T,TA), nth1(K,L,LA), valuation(A,[O],UA), VA is LA * UA - TA ), V). %--------------------------- % find best response of agent %--------------------------- :- dynamic nash_data/3. find_best_response_of(A,O,PK,VK,Data):- agents(I), agent(A), object(O), nth1(K,I,A), nth1(K,V,VK), nth1(K,P,PK), Data=auction_data( [object:O,winner:_W,by:_HP,price:_SP], [agent:I,bid:P,payment:_T,payoff:V] ), (\+ clause(Data,_) ->go;true), find_best_response_0([O,I,A,K,VK,P],Data). find_best_response_0(X,PD):- clause(nash_data(best,X,PD),_), !. find_best_response_0(X,PD):- clause(nash_data(not_best,X,PD),_), !, fail. find_best_response_0([O,I,A,K,VK,P],AD):- X=[O,I,A,K,VK,P], DD=auction_data( [object:O,winner:_W,by:_HP,price:_SP], [agent:I,bid:P1,payment:_T1,payoff:V1] ), AD, \+ ( DD, forall( nth1(J,P,PJ), (nth1(J,P1,PJ);J=K) ), nth1(K,V1,V1K), V1K >VK, assert(nash_data(not_best,X,AD)), Y=[O,I,A,K,V1K,P1], assert(nash_data(defeat(X),Y,DD)) ), assert(nash_data(best,X,AD)). % (inefficient) find_all_best_responses:- (clause(nash_data(_,_,_),_) -> ( write('Will you abolish all nash_data/3 ? (y/n) '),nl, write('Note: It will take you some minutes. >'), read(y) );true ), abolish(nash_data/3), forall( find_best_response_of(_A,_O,_B,_C,_AD), true ). nash_equilibrium(AD):- (\+ clause(nash_data(_,_,_),_)->find_all_best_responses;true), AD=auction_data( [object:O,winner:_W,by:_HP,price:_SP], [agent:I,bid:P,payment:_T,payoff:_V] ), AD, X=[O,I,A,_K,_VK,P], forall(member(A,I), nash_data(best,X,AD) ). /* ?- find_all_best_responses. Will you abolish all nash_data/3 ? (y/n) >y. end Yes ?- tell_goal('spa_ne.pl',forall,nash_data(_,_,_)). % Save Data to File. Yes */ % optimality of truthfulness %--------------------------- truthful(Y,PD,Z):- Y=[O,I,A,K,VK,P], _X=[[P,I,K],[A,O,PK,VK]], object(O), agents(I), valuation(A,[O],PK), nth1(K,I,A), nth1(K,P,PK), nth1(K,V,VK), PD=auction_data( [object:O,winner:_W,by:_HP,price:_SP], [agent:I,bid:P,payment:_T,payoff:V] ), PD, is_best_response([A,O,PK,VK,PD],Z1), Z=Z1. is_best_response([A,O,PK,VK,PD],best):- find_best_response_of(A,O,PK,VK,PD), !. is_best_response(_,not_best). truth_telling_profile(PD):- PD=auction_data( [object:O,winner:_W,by:_HP,price:_SP], [agent:I,bid:TT,payment:_T,payoff:_V] ), PD, findall(ZK, ( member(A,I), valuation(A,[O],ZK) ), TT). /* ?- truth_telling_profile(A), nash_equilibrium(A). A = auction_data([object:x, winner:a, by:10, price:9], [agent:[a, b, c], bid:[10, 2, 9], payment:[9, 0, 0], payoff:[1, 0, 0]]) ; A = auction_data([object:y, winner:b, by:10, price:5], [agent:[a, b, c], bid:[3, 10, 5], payment:[0, 5, 0], payoff:[0, 5, 0]]) ; A = auction_data([object:z, winner:b, by:6, price:4], [agent:[a, b, c], bid:[4, 6, 1], payment:[0, 4, 0], payoff:[0, 2, 0]]) ; No % proving dominance. %----------------------- ?- truthful(A,B,not_best). No */ %----------------------------------------------------------------- % Appendix. Determining Winner of Combinatorial Auction %----------------------------------------------------------------- % mimicing the example of A. Pekec and M. H. Rothkept (2003). valuation_c(X,[],0):-agents(I),member(X,I). valuation_c(a,[x],1). valuation_c(b,[x],1). valuation_c(c,[x],0). valuation_c(a,[y],3). valuation_c(b,[y],2). valuation_c(c,[y],1). valuation_c(a,[z],1). valuation_c(b,[z],0). valuation_c(c,[z],2). valuation_c(a,[x,y],Z):-A is 1, valuation_c(a,[x],X),valuation_c(a,[y],Y),Z is X+Y+A. valuation_c(b,[x,y],Z):-A is 0, valuation_c(b,[x],X),valuation_c(b,[y],Y),Z is X+Y+A. valuation_c(c,[x,y],Z):-A is 0, valuation_c(c,[x],X),valuation_c(c,[y],Y),Z is X+Y+A. valuation_c(a,[y,z],Z):-A is 0, valuation_c(a,[z],X),valuation_c(a,[y],Y),Z is X+Y+A. valuation_c(b,[y,z],Z):-A is 0, valuation_c(b,[z],X),valuation_c(b,[y],Y),Z is X+Y+A. valuation_c(c,[y,z],Z):-A is 0, valuation_c(c,[z],X),valuation_c(c,[y],Y),Z is X+Y+A. valuation_c(a,[x,z],Z):-A is 0, valuation_c(a,[x],X),valuation_c(a,[z],Y),Z is X+Y+A. valuation_c(b,[x,z],Z):-A is 4, valuation_c(b,[x],X),valuation_c(b,[z],Y),Z is X+Y+A. valuation_c(c,[x,z],Z):-A is 0, valuation_c(c,[x],X),valuation_c(c,[z],Y),Z is X+Y+A. valuation_c(a,[x,y,z],4). valuation_c(b,[x,y,z],5). valuation_c(c,[x,y,z],6). goods_c([x,y,z]). agents_c([a,b,c]). winner_in_subset(E,I,U):- (var(E)->(goods_c(ALL),subset_of(E,_,ALL),E\=[]);true), max(U, ( valuation_c(I,E,U) ) ). /* ?- winner_in_subset(A,B,C),nl,write(A-B-C),fail. [z]-c-2 [y]-a-3 [y, z]-a-4 [x]-a-1 [x]-b-1 [x, z]-b-5 [x, y]-a-5 [x, y, z]-c-6 No ?- */ allocation_0([],[],[],[],0). allocation_0(Goods,[X|Sold],[I|Agents],[U|Values],SUM):- subset_of(X,_,Goods), subtract(Goods,X,Remains), allocation_0(Remains,Sold,Agents,Values,SUM_0), valuation_c(I,X,U), SUM is SUM_0 + U. allocation(G,A,U ,TotalValue):- goods_c(S), agents_c(A), allocation_0(S,G,A,U ,TotalValue). /* ?- allocation(B,C,D,E),nl,write(C:D:E:B),fail. [a, b, c]:[0, 0, 6]:6:[[], [], [x, y, z]] [a, b, c]:[0, 0, 1]:1:[[], [z], [x, y]] [a, b, c]:[0, 2, 2]:4:[[], [y], [x, z]] [a, b, c]:[0, 2, 0]:2:[[], [y, z], [x]] [a, b, c]:[0, 1, 3]:4:[[], [x], [y, z]] [a, b, c]:[0, 5, 1]:6:[[], [x, z], [y]] [a, b, c]:[0, 3, 2]:5:[[], [x, y], [z]] [a, b, c]:[0, 5, 0]:5:[[], [x, y, z], []] [a, b, c]:[1, 0, 1]:2:[[z], [], [x, y]] [a, b, c]:[1, 2, 0]:3:[[z], [y], [x]] [a, b, c]:[1, 1, 1]:3:[[z], [x], [y]] [a, b, c]:[1, 3, 0]:4:[[z], [x, y], []] [a, b, c]:[3, 0, 2]:5:[[y], [], [x, z]] [a, b, c]:[3, 0, 0]:3:[[y], [z], [x]] [a, b, c]:[3, 1, 2]:6:[[y], [x], [z]] [a, b, c]:[3, 5, 0]:8:[[y], [x, z], []] [a, b, c]:[4, 0, 0]:4:[[y, z], [], [x]] [a, b, c]:[4, 1, 0]:5:[[y, z], [x], []] [a, b, c]:[1, 0, 3]:4:[[x], [], [y, z]] [a, b, c]:[1, 0, 1]:2:[[x], [z], [y]] [a, b, c]:[1, 2, 2]:5:[[x], [y], [z]] [a, b, c]:[1, 2, 0]:3:[[x], [y, z], []] [a, b, c]:[2, 0, 1]:3:[[x, z], [], [y]] [a, b, c]:[2, 2, 0]:4:[[x, z], [y], []] [a, b, c]:[5, 0, 2]:7:[[x, y], [], [z]] [a, b, c]:[5, 0, 0]:5:[[x, y], [z], []] [a, b, c]:[4, 0, 0]:4:[[x, y, z], [], []] No ?- max(E,allocation(B,C,D,E)). E = 8 B = [[y], [x, z], []] C = [a, b, c] D = [3, 5, 0] ; No ?- */ %--------------------------- % Common Programs %--------------------------- % sum %--------------------------- sum([],0). sum([X|Members],Sum):- sum(Members,Sum1), Sum is Sum1 + X. % maximal solution for given goal clause : a naive solver %--------------------------------------------------------- max(X,Goal):- % X: the objective variable, % Goal: the objective function and constraints, setof((X,Goal),Goal,Z), member((X,Goal),Z), \+ ( member((Y,_),Z), Y > X ). % a sequence of binary choice for a list: %-------------------------------------------------- list_projection([],[],[]). list_projection([X|Y],[_A|B],C):- X = 0, list_projection(Y,B,C). list_projection([X|Y],[A|B],[A|C]):- X = 1, list_projection(Y,B,C). % % subset_of/3 : subset-enumeration % ----------------------------------------------------------- % subset_of(A,N,As):- length(As,L), length(D,L), list_projection(D,As,B), length(B,N), sort(B,A). % % complementary list projection %-------------------------------------------------- c_list_projection([],[],[]). c_list_projection([X|Y],[_A|B],C):- X = 1, c_list_projection(Y,B,C). c_list_projection([X|Y],[A|B],[A|C]):- X = 0, c_list_projection(Y,B,C). % ----------------------------------------------------------- % % output to file. % ----------------------------------------------------------- % tell_test(Goal):- open('tell.txt',write,S), tell('tell.txt'), Goal, current_stream('tell.txt',write,S), tell(user),wn(end), close(S). % tell_goal(File,G):- (current_stream(File,write,S0)->close(S0);true), open(File,write,S), tell(File), nl, tstamp('% file output start time ',_), nl, write('%---------- start from here ------------%'), nl, G, nl, write('%---------- end of data ------------%'), nl, tstamp('% file output end time ',_), tell(user), close(S), % The following is to cope with the duplicated stream problem. (current_stream(File,write,S1)->close(S1);true). % saving all successful goals to a file. %-------------------------------- tell_goal(File,forall,G):- G0 = (nl,write(G),write('.')), G1 = forall(G,G0), tell_goal(File,G1). % time stamp %-------------------------------- tstamp(no,T):- get_time(U), convert_time(U,A,B,C,D,E,F,_G), T = [date(A/B/C), time(D:E:F)], nl. tstamp(Word,T):- \+ var(Word), Word \= no, get_time(U), convert_time(U,A,B,C,D,E,F,_G), T = [date(A/B/C), time(D:E:F)], % format('~`.t~t~a~30|~`.t~t~70|~n',[Word]), write((Word,T)), nl. :- title. % end