1 //
2 // This file is part of Gambit
3 // Copyright (c) 1994-2016, The Gambit Project (http://www.gambit-project.org)
4 // Albert Xin Jiang <albertjiang@gmail.com>
5 //
6 // FILE: src/libagg/agg.cc
7 // Implementation of Action Graph Game representation
8 //
9 // This program is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 //
23
24
25 #include <iostream>
26 #include <fstream>
27 #include <sstream>
28 #include <cassert>
29 #include <algorithm>
30 #include "gambit/agg/gray.h"
31 #include "gambit/agg/agg.h"
32
33 using namespace std;
34
35 namespace Gambit {
36
37 namespace agg {
38
select2nd(const pair<int,int> & x)39 inline int select2nd(const pair <int,int> &x) { return x.second; }
40
AGG(int numPlayers,int * _actions,int numANodes,int _numPNodes,vector<vector<int>> & _actionSets,vector<vector<int>> & neighb,vector<projtype> & projTypes,vector<vector<aggdistrib>> & projS,vector<vector<vector<config>>> & proj,vector<vector<proj_func * >> & projF,vector<vector<vector<int>>> & Po,vector<aggdistrib> & P,vector<aggpayoff> & _payoffs)41 AGG::AGG(int numPlayers,int* _actions, int numANodes, int _numPNodes,
42 vector<vector<int> >& _actionSets, vector<vector<int> >& neighb,
43 vector<projtype>& projTypes,
44 vector<vector<aggdistrib > >& projS,
45 vector<vector<vector<config> > >& proj,
46 vector<vector<proj_func*> > & projF,
47 vector<vector<vector<int> > >& Po,
48 vector<aggdistrib> &P,
49 vector<aggpayoff>& _payoffs) :
50 numPlayers(numPlayers),
51 numActionNodes(numANodes),
52 numPNodes(_numPNodes),
53 actionSets(_actionSets),
54 neighbors(neighb),
55 projectionTypes(projTypes),
56 payoffs(_payoffs),
57 projection(proj),
58 projectedStrat(projS),
59 fullProjectedStrat(projS),
60 projFunctions(projF),
61 Porder(Po),
62 Pr(P),
63 isPure(numANodes,true),
64 node2Action(numANodes,vector<int>(numPlayers)),
65 cache(numPlayers+1),
66 player2Class(numPlayers),
67 kSymStrategyOffset(1,0)
68 {
69
70 //actions
71 actions=new int[numPlayers];
72 strategyOffset= new int[numPlayers+1];
73 strategyOffset[0]=0;
74 maxActions=0;
75 totalActions=0;
76
77 for (int i=0;i<numPlayers;i++){
78 actions[i]=_actions[i];
79 totalActions+=actions[i];
80 strategyOffset[i+1]=strategyOffset[i]+actions[i];
81 if(actions[i]>maxActions) maxActions=actions[i];
82 }
83
84
85
86 //construct uniqueActionSets,playerClasses and player2Class
87 vector<pair<vector<int> ,int> >t;
88 vector<vector<int> > sortedActionSets (actionSets);
89 //sort the actions in each action set in ascending order
90 for (int i=0;i<numPlayers;i++){
91 sort(sortedActionSets[i].begin(),sortedActionSets[i].end());
92 if (sortedActionSets[i] != actionSets[i]){
93 cerr<< "WARNING: action set for player "<<i<<" is not in ascending order:"<<endl;
94 copy(actionSets[i].begin(),actionSets[i].end(), ostream_iterator<int>(cerr," "));
95 cerr<<endl<<"This potentially affects computations with symmetric (or k-symmetric) strategies"<<endl;
96 }
97 t.push_back(make_pair(sortedActionSets[i],i));
98 }
99 sort(t.begin(),t.end());
100 //vector<pair<vector<int>,int> >::iterator new_end = unique(t.begin(),t.end());
101 vector<pair<vector<int>,int> >::iterator p=t.begin();
102 uniqueActionSets.push_back(p->first);
103 playerClasses.push_back(vector<int> (1,p->second));
104 player2Class[p->second]=0;
105 numKSymActions=p->first.size();
106 kSymStrategyOffset.push_back(numKSymActions);
107
108 while(++p!=t.end()){
109 if(p->first == uniqueActionSets.at(uniqueActionSets.size()-1)){
110 playerClasses[playerClasses.size()-1].push_back(p->second);
111 }
112 else{
113 uniqueActionSets.push_back(p->first);
114 playerClasses.push_back(vector<int> (1, p->second));
115 numKSymActions += p->first.size();
116 kSymStrategyOffset.push_back(numKSymActions);
117 }
118 player2Class[p->second]=playerClasses.size()-1;
119 }
120
121
122 //set isPure
123 for (int i=0; i<numANodes; i++)if (neighb.at(i).size()>0){
124 int maxNode=*( max_element(neighb.at(i).begin(),neighb.at(i).end()));
125 isPure[i]=(maxNode <numANodes );
126 }
127
128 //set node2Action
129 for (int i=0;i<numANodes;i++)
130 for(int j=0;j<numPlayers;j++)
131 node2Action[i][j]=-1;
132 for(int i=0;i<numPlayers;i++)
133 for(int j=0;j<actions[i];j++)
134 node2Action[actionSets[i][j]][i]=j;
135
136 }
137
138 /*
139 AGG::AGG(const agg& other, bool completeGraph)
140 :
141 numPlayers(other.numPlayers)
142 //numActionNodes(other.numActionNodes),
143 //numPNodes(other.numPNodes)
144 //actionSets(actionSets),
145 //neighbors(neighb),
146 //projectionTypes(projTypes),
147 //payoffs(_payoffs),
148 //projection(proj),
149 //projectedStrat(projS),
150 //fullProjectedStrat(projS),
151 //projFunctions(projF),
152 //Porder(Po),
153 //Pr(P),
154 //isPure(numANodes,true),
155 //node2Action(numANodes,vector<int>(numPlayers)),
156 //cache(numPlayers+1),
157 //player2Class(numPlayers)
158 {
159 //actions
160 actions=new int[numPlayers];
161 strategyOffset= new int[numPlayers+1];
162 strategyOffset[0]=0;
163 maxActions=0;
164 totalActions=0;
165
166 for (int i=0;i<numPlayers;i++){
167 actions[i]=other.actions[i];
168 totalActions+=actions[i];
169 strategyOffset[i+1]=strategyOffset[i]+actions[i];
170 if(actions[i]>maxActions) maxActions=actions[i];
171 }
172
173 if (completeGraph){
174
175 numActionNodes=totalActions;
176 numPNodes=0;
177 for (int i=0;i<numPlayers;i++){
178 for (int j=0;j<actions[i];j++)
179 actionSets[i][j] = firstAction(i)+j;
180 }
181 }
182 else{
183 b numActionNodes=other.numActionNodes;
184
185 numPNodes=other.numPNodes;
186 actionSets=other.actionSets;
187 neighbors=other.neighbors;
188 projectionTypes=other.projectionTypes;
189 payoffs=other.payoffs;
190 projection=other.projection;
191 projectedStrat=other.projectedStrat;
192 fullProjectedStrat=other.fullProjectedStrat;
193 //projFunctions=other.projFunctions;
194 Porder=other.Porder;
195 Pr=other.Pr;
196 isPure=other.isPure;
197 node2Action=other.node2Action;
198 cache=other.cache;
199 uniqueActionSets=other.uniqueActionSets;
200 playerClasses=other.playerClasses;
201 player2Class=other.player2Class;
202
203 projFunctions=vector<vector<proj_func*> > (numActionNodes);
204 for (int i=0;i<numActionNodes;i++){
205 int neighb_size=neighbors[i].size();
206 for(int j=0;j<neighb_size; j++){
207 projtype t=(neighbors[i][j]<numActionNodes)?P_SUM:projectionTypes[neighbors[i][j]-numActionNodes];
208 projFunctions[i].push_back(make_proj_func(t, numActionNodes+numPNodes) );
209 }
210 }
211
212 }
213 }
214 */
215
stripComment(istream & in)216 void AGG::stripComment(istream& in){
217 in>>ws;
218 char c =in.peek();
219 stringbuf discard(ios_base::out);
220 if(c== AGG::COMMENT_CHAR){
221 in.get (discard);
222 #ifdef AGGDEBUG
223 cerr<<discard.str()<<endl;
224 #endif
225 stripComment(in);
226 }
227 }
228
229
makeAGG(char * filename)230 AGG *AGG::makeAGG(char* filename){
231 ifstream in(filename);
232 return AGG::makeAGG(in);
233 }
makeAGG(istream & in)234 AGG *AGG::makeAGG(istream &in){
235 int i,j,n,S,P;
236 int neighb_size;
237
238 if(in.good() && !in.eof()) {
239 stripComment(in);
240 in>>n;
241 if(!in.good()) {
242 cout<<"Error reading the number of players"<<endl;
243 return 0;
244 }
245 stripComment(in);
246 in>>S;
247 if(!in.good()) {
248 cout<<"Error reading the number of action nodes"<<endl;
249 return 0;
250 }
251 stripComment(in);
252 in>>P;
253 if(!in.good()) {
254 cout<<"Error reading the number of function nodes"<<endl;
255 return 0;
256 }
257 stripComment(in);
258
259 //enter sizes of action sets:
260 int* size = new int[n];
261 for (i=0;i<n;i++){
262 in >> size[i];
263 if(in.eof()||in.fail()) {
264 cout << "Error in game file while trying to read the size of action set of player "<<i<<".\n";
265 return 0;
266 }
267 //sumActionSets+=size[i];
268 }
269
270 stripComment(in);
271 vector<vector<int> > ASets(n); //action sets
272 for (i=0;i<n;i++){
273 stripComment(in);
274 for (j=0;j<size[i];j++){
275 int aindex;
276 in>>aindex;
277 if(in.eof()||in.fail()) {
278 cout<< "Error in game file while trying to read the node index of action "<<j<< " of player "
279 <<i<<".\n";
280 return 0;
281 }
282 ASets[i].push_back(aindex);
283 }
284 }
285
286 stripComment(in);
287 vector<vector<int> > neighb(S+P); //neighbor lists
288 for(i=0;i<S+P;i++){
289
290 stripComment(in);
291 in>>neighb_size;
292 if(in.eof()||in.fail()) {
293 cout << "Error in game file while trying to read the size of the neighbor list of node "<<i<<".\n";
294 return 0;
295 }
296 for(j=0;j<neighb_size;j++){
297 int nindex;
298 in>>nindex;
299 if(!in.good()){
300 cout<<"Error while reading neighor #"<<j<<" of node "<<i<<".\n";
301 return 0;
302 }
303 neighb[i].push_back(nindex);
304 }
305 }
306
307 stripComment(in);
308 //enter the projection types:
309 vector<projtype> projTypes(P);
310 for (i=0;i<P;++i) {
311 int pt;
312 stripComment(in);
313 in >> pt;
314 if (in.eof()||in.fail()){
315 cout<<"Error in game file: expected integer for type of function node #"<<i<<endl;
316 return 0;
317 }
318 projTypes[i] = make_proj_func((TypeEnum)pt,in,S,P);
319 }
320
321 vector<vector<aggdistrib > > projS;
322 vector<vector<vector<config> > > proj;
323 setProjections(projS,proj,n,S,P, ASets, neighb,projTypes);
324
325 vector<vector<proj_func*> > projF(S);
326 for (i=0;i<S;i++){
327 neighb_size=neighb[i].size();
328 for(j=0;j<neighb_size; j++){
329 projtype t=(neighb[i][j]<S)?(new proj_func_SUM):projTypes[neighb[i][j]-S];
330 projF[i].push_back(t );
331 }
332 }
333
334 vector<vector<vector<int> > > Po(n);
335 vector<aggdistrib> Pr(n);
336 vector<aggpayoff> pays(S); //payoffs
337
338
339 set<vector<int> > doneASets;
340 for (i=0;i<n;i++){
341 for(j=0;j<size[i] ; j++){
342 Po[i].push_back(vector<int>(n) );
343 initPorder (Po[i][j], i,n,projS[ASets[i][j]]);
344 }
345 vector<int> as = ASets[i];
346 sort(as.begin(),as.end());
347 if (doneASets.count(as)==0){
348 for(j=0;j<size[i];j++){
349 // apply i's strategy j
350 Pr[0].reset();
351 Pr[0].insert (make_pair(proj[ASets[i][j]][i][j], 1));
352
353 // apply the rest of players strats
354 for (int k=1; k<n;k++){
355 Pr[k].multiply (Pr[k-1], projS[ASets[i][j]][Po[i][j][k]],proj[ASets[i][j]][i][j].size() ,projF[ASets[i][j]] );
356 }
357 pays[ASets[i][j]].insert(Pr[n-1].begin(), Pr[n-1].end());
358 }
359 doneASets.insert(as);
360 }
361 }
362
363 stripComment(in);
364 //read in payoffs
365 for(i=0;i<S;i++){
366 if(in.eof()||in.bad()) {
367 cout << "Error in game file: not enough payoffs.\n";
368 return 0;
369 }
370 stripComment(in);
371 int t;
372 in>>t;
373 if(!in.good()){
374 cout<< "Error reading the integer type of the utility function for action node "<<i<<endl;
375 return 0;
376 }
377 switch (t){
378 case COMPLETE:
379 AGG::makeCOMPLETEpayoff(in,pays[i]);
380 break;
381 case MAPPING:
382 AGG::makeMAPPINGpayoff(in,pays[i],neighb[i].size());
383 break;
384 case ADDITIVE:
385 default:
386 cerr<<"Unknown payoff type "<<t
387 <<endl;
388 exit(1);
389 }
390
391 }
392 AGG *r=NULL;
393 r=new AGG(n,size,S,P,ASets,neighb,projTypes,projS,proj,projF,Po,Pr,pays);
394 if (!r)cout<<"Failed to allocate memory for new AGG";
395 delete [] size;
396 return r;
397 } else {
398 cout << "Bad game file.\n";
399 exit(1);
400 }
401 }
402
403
makeRandomAGG(int n,int * actions,int S,int P,vector<vector<int>> & ASets,vector<vector<int>> & neighb,vector<projtype> & projTypes,int seed,bool int_payoffs,int int_factor)404 AGG *AGG::makeRandomAGG(int n, int* actions, int S, int P,
405 vector<vector<int> >& ASets, vector<vector<int> >& neighb,
406 vector<projtype>& projTypes, int seed, bool int_payoffs, int int_factor){
407 int i,j;
408 #if HAVE_SRAND48
409 srand48(seed);
410 #else
411 srand(seed);
412 #endif // HAVE_SRAND48
413 vector<vector<aggdistrib > > projS;
414 vector<vector<vector<config> > > proj;
415 setProjections(projS,proj,n,S,P, ASets, neighb,projTypes);
416
417 vector<vector<proj_func*> > projF(S);
418 for (i=0;i<S;i++){
419 int neighb_size=neighb[i].size();
420 for(j=0;j<neighb_size; j++){
421 projtype t=(neighb[i][j]<S)?(new proj_func_SUM):projTypes[neighb[i][j]-S];
422 projF[i].push_back(t );
423 }
424 }
425
426 vector<vector<vector<int> > > Po(n);
427 vector<aggdistrib> Pr(n);
428 vector<aggpayoff> pays(S); //payoffs
429
430
431
432 set<vector<int> > doneASets;
433 for (i=0;i<n;i++){
434 for(j=0;j<actions[i]; j++){
435 Po[i].push_back(vector<int>(n) );
436 initPorder (Po[i][j], i,n,projS[ASets[i][j]]);
437 }
438 vector<int> as = ASets[i];
439 sort(as.begin(),as.end());
440 if (doneASets.count(as)==0){
441 for(j=0;j<actions[i];j++){
442 // apply i's strategy j
443 Pr[0].reset();
444 Pr[0].insert (make_pair(proj[ASets[i][j]][i][j], 1));
445
446 // apply the rest of players strats
447 for (int k=1; k<n;k++){
448 Pr[k].multiply (Pr[k-1], projS[ASets[i][j]][Po[i][j][k]],proj[ASets[i][j]][i][j].size() ,projF[ASets[i][j]] );
449 }
450 pays[ASets[i][j]].insert(Pr[n-1].begin(), Pr[n-1].end());
451 }
452 doneASets.insert(as);
453 }
454 }
455
456
457 //read in payoffs
458 int numPayoffs=0;
459 for(i=0;i<S;i++){
460 pays[i].in_order( inputRand(int_payoffs,int_factor) );
461 numPayoffs += pays[i].size();
462 }
463 cout << "Creating an AGG with "<<numPayoffs <<" payoff values"<<endl;
464 AGG *r= new AGG(n,actions,S,P,ASets,neighb,projTypes,projS,proj,projF,Po,Pr,pays);
465
466 return r;
467
468 }
469
470
471
472 void
setProjections(vector<vector<aggdistrib>> & projS,vector<vector<vector<config>>> & proj,int N,int S,int P,vector<vector<int>> & AS,vector<vector<int>> & neighb,vector<projtype> & projTypes)473 AGG::setProjections(vector<vector<aggdistrib > >& projS,
474 vector<vector<vector<config> > >& proj, int N,int S,int P,
475 vector<vector<int> >& AS, vector<vector<int> >& neighb, vector<projtype>& projTypes)
476 {
477
478 int Node, i,j,k,numNei,actions;
479
480 vector<multiset<int> > an(P); //set of ancestors for P nodes
481 vector<int> path;
482 for (i=0;i<P;i++){
483 path.clear();
484 getAn(an[i],neighb,projTypes,S,S+i,path);
485 }
486
487
488 projS.clear();
489 proj.clear();
490
491 for (Node=0;Node<S;++Node){//for each action node
492 projS.push_back(vector<aggdistrib >(N));
493 proj.push_back(vector<vector<config> >(N));
494 numNei=neighb[Node].size();
495
496 for (i=0;i<N;i++){//for each player
497
498 actions =AS[i].size();
499 for (j=0;j<actions;j++){ // for each action in S_i
500 proj[Node][i].push_back( config(numNei) );
501 for(k=0;k<numNei;k++){ //foreach neighbor of Node
502 //get i's action j's contribution to the count of node k
503 proj[Node][i][j][k]=0;
504 if (AS[i][j]==neighb[Node][k]){
505 proj[Node][i][j][k]=1;
506 //break;
507 }
508 else if (neighb[Node][k]>=S ){
509 proj_func *f=projTypes[neighb[Node][k]-S];
510 assert(f);
511 pair<multiset<int>::iterator,multiset<int>::iterator> \
512 p=an[neighb[Node][k]-S].equal_range(AS[i][j]);
513 multiset<int> blah(p.first, p.second);
514 proj[Node][i][j][k] = (*f) (blah);
515
516 }
517 } //end for(k..
518
519 //insert player i's action j's contribution to projS
520 projS[Node][i].insert(make_pair(proj[Node][i][j], 1));
521 }//end for(j..
522 }//end for(i..
523 }//end for(Node..
524 }
525
526 void
getAn(multiset<int> & dest,vector<vector<int>> & neighb,vector<projtype> & projTypes,int S,int Node,vector<int> & path)527 AGG::getAn(multiset<int>& dest, vector<vector<int> >& neighb, vector<projtype>& projTypes,
528 int S,int Node, vector<int>& path)
529 {
530 //get ancestors
531 if (Node<S) {
532 dest.insert(Node);
533 return;
534 }
535 //cycle check
536 for (vector<int>::iterator p=path.begin();p!=path.end();++p){
537 if (Node == (*p)) {
538 cout<<"ERROR: cycle of projected nodes at "<<Node <<endl;
539 cout <<"Path: (Size "<<path.size() <<")"<<endl;
540 copy(path.begin(),path.end(),ostream_iterator<int>(cout, " "));
541 cout<<endl;
542 exit(1);
543 }
544 }
545
546 int numNei=neighb[Node].size();
547 path.push_back(Node);
548 for (int i=0; i<numNei;++i){
549 //check consistency of proj. signatures
550 if(neighb[Node][i]>=S && *(projTypes[neighb[Node][i]-S])!= *(projTypes[Node-S])){
551 cout<<"ERROR: projection type mismatch: Node "<< Node
552 <<" and its neighbor "<<neighb[Node][i]<<endl;
553 exit(1);
554 }
555 getAn(dest, neighb,projTypes, S, neighb[Node][i],path);
556 }
557 path.pop_back();
558
559 }
560
561 void
initPorder(vector<int> & Po,int i,int N,vector<aggdistrib> & projS)562 AGG::initPorder(vector<int>& Po,
563 //vector<aggdistrib>& P,
564 int i, int N, vector<aggdistrib>& projS)
565 //config & proj,
566 //vector<proj_func*>& projF
567 {
568 vector<pair<int,int> > order;
569 int k;
570 for (k=0;k<N;k++) if (k!=i){
571 order.push_back (make_pair( projS[k].size() , k) );
572 }
573
574 sort (order.begin(),order.end() );
575 vector<int>::iterator p = Po.begin();
576 (*p) = i;
577 ++p;
578 transform(order.begin(),order.end(), p, select2nd );
579
580 }
581
582
583
584 //compute the induced distribution
585 void
computeP(int player,int act,int player2,int act2)586 AGG::computeP(int player, int act, int player2,int act2)
587 {
588 //apply player's strat
589 Pr[0].reset();
590 Pr[0].insert(make_pair(projection[actionSets[player][act]][player][act], 1.0) );
591
592 int numNei = neighbors[actionSets[player][act]].size();
593 //apply others' strat
594 for (int k=1; k<numPlayers;k++){
595 Pr[k].reset();
596 if (Porder[player][act][k]==player2){
597 if (act2==-1){
598 //Pr[k].swap(Pr[k-1]);
599 Pr[k]=Pr[k-1];
600 } else {
601 //apply player2's pure strat
602 aggdistrib temp;
603 temp.insert(make_pair(projection[actionSets[player][act]][player2][act2],1.0));
604 Pr[k].multiply(Pr[k-1],temp ,numNei, projFunctions[actionSets[player][act]]);
605 }
606 } else {
607 Pr[k].multiply (Pr[k-1],
608 projectedStrat[actionSets[player][act]][Porder[player][act][k]],
609 numNei ,projFunctions[actionSets[player][act]] );
610 }
611 }
612
613 }
614
doProjection(int Node,AggNumber * s)615 void AGG:: doProjection(int Node, AggNumber* s)
616 {
617 for (int i=0;i<numPlayers;i++){
618 doProjection(Node,i, &(s[firstAction(i)]));
619 }
620 }
621
doProjection(int Node,int i,AggNumber * s)622 inline void AGG:: doProjection(int Node, int i, AggNumber* s)
623 {
624 projectedStrat[Node][i].reset();
625 for (int j=0;j<actions[i];j++)if(s[j]>(AggNumber)0.0){
626 projectedStrat[Node][i]+= make_pair(projection[Node][i][j],
627 s[j]);
628 }
629 }
getPurePayoff(int player,int * s)630 AggNumber AGG::getPurePayoff(int player, int *s){
631 assert(player>=0 && player < numPlayers);
632 int Node = actionSets[player][s[player]];
633 int keylen = neighbors[Node].size();
634 config pureprofile (projection[Node][0][s[0]]);
635 for (int i=1; i<numPlayers; i++){
636 for (int j=0; j<keylen; j++){
637 pureprofile[j]=
638 (*projFunctions[Node][j]) (pureprofile[j],projection[Node][i][s[i]][j] );
639 }
640 }
641 aggpayoff::iterator p= payoffs[Node].find(pureprofile);
642 if ( p == payoffs[Node].end() ){
643 cout<<"AGG::getPurePayoff ERROR: unable to find the following configuration"
644 <<endl;
645 cout <<"[";
646 copy(pureprofile.begin(),pureprofile.end(),ostream_iterator<int>(cout, " "));
647 cout<<"]" <<endl;
648 cout<< "\tin payoffs of action node #"<<Node<<endl;
649 exit(1);
650 }
651 return p->second;
652 }
653
getMixedPayoff(int player,StrategyProfile & s)654 AggNumber AGG::getMixedPayoff(int player, StrategyProfile &s){
655 AggNumber result=0.0;
656 assert(player>=0 && player < numPlayers);
657 for (int act=0;act <actions[player];++act)if (s[act+firstAction(player)]>(AggNumber)0.0){
658 result+= s[act+firstAction(player)]* getV(player, act, s);
659 }
660 return result;
661 }
662
getPayoffVector(AggNumberVector & dest,int player,const StrategyProfile & s)663 void AGG::getPayoffVector(AggNumberVector &dest, int player,const StrategyProfile &s){
664 assert(player>=0 && player < numPlayers);
665 for (int act=0;act<actions[player]; ++act){
666 dest[act]=getV(player,act,s);
667 }
668 }
669
getV(int player,int act,const StrategyProfile & s)670 AggNumber AGG::getV(int player, int act,const StrategyProfile &s){
671 //project s to the projectedStrat
672 doProjection(actionSets.at(player).at(act), s);
673 computeP(player, act);
674 return Pr[numPlayers-1].inner_prod(payoffs[actionSets[player][act]]);
675 }
676
getJ(int player1,int act1,int player2,int act2,StrategyProfile & s)677 AggNumber AGG::getJ(int player1, int act1, int player2,int act2,StrategyProfile &s)
678 {
679 doProjection(actionSets[player1][act1],s);
680 computeP(player1,act1,player2,act2);
681 return Pr[numPlayers-1].inner_prod(payoffs[actionSets[player1][act1]]);
682 }
683
684 //getSymMixedPayoff: compute expected payoff under a symmetric mixed strat,
685 // for a symmetric game.
686 // parameter: s is the mixed strategy of one player. It is a vector of
687 // probabilities, indexed by the action node.
688
getSymMixedPayoff(StrategyProfile & s)689 AggNumber AGG::getSymMixedPayoff( StrategyProfile &s){
690 AggNumber result=0;
691 if (! isSymmetric() ) {
692 cerr<< "AGG::getSymMixedPayoff: the game is not symmetric!"<<endl;
693 exit(1);
694 }
695
696
697 for (int node=0; node<numActionNodes; ++node)if(s[node]>(AggNumber)0.0){
698 result+= s[node]* getSymMixedPayoff(node,s);
699 }
700 return result;
701 }
getSymPayoffVector(AggNumberVector & dest,StrategyProfile & s)702 void AGG::getSymPayoffVector(AggNumberVector& dest, StrategyProfile &s){
703 if (! isSymmetric() ) {
704 cerr<< "AGG::getSymMixedPayoff: the game is not symmetric!"<<endl;
705 exit(1);
706 }
707
708 //check the pureness
709 //bool pure=true;
710 //for (int i=0;i<numActionNodes;++i){
711 // if(!(s[ i ] == (AggNumber)0.0 || isPure[i])){
712 // pure=false;
713 // break;
714 // }
715 //}
716 //if(!pure){
717 // StrategyProfile fulls(getNumActions());
718 // for(int i=0;i<getNumPlayers();++i){
719 // for(int j=0;j<numActionNodes;++j)
720 // fulls[j+firstAction(i)]=s[j];
721 // }
722 // getPayoffVector(dest, 0, fulls);
723 // return;
724 //}
725 for (int act=0;act<numActionNodes; ++act){
726 dest[act]=getSymMixedPayoff(act,s);
727 }
728 }
getSymMixedPayoff(int node,StrategyProfile & s)729 AggNumber AGG::getSymMixedPayoff(int node, StrategyProfile &s)
730 {
731 int numNei = neighbors[node].size();
732
733 if(!isPure[node]){ // then compute EU using trie_map::power()
734 doProjection(node,0,s);
735 assert(numPlayers>1);
736 //aggdistrib *dest;
737 //projectedStrat[node][0].power(numPlayers-1, dest, Pr, numNei,projFunctions[node]);
738 aggdistrib &dest = Pr[numPlayers-1];
739 projectedStrat[node][0].power(numPlayers-1, dest, Pr[numPlayers-2],numNei,projFunctions[node]);
740 return dest.inner_prod(projection[node][0][node], numNei, projFunctions[node], payoffs[node]);
741 }
742
743 AggNumber V = 0.0;
744 vector<int> support;
745 AggNumber null_prob=1;
746 //do projection & get support
747 int self = -1;
748 for (int i=0; i<numNei; ++i){
749 if (neighbors[node][i] == node) self=i;
750 if (s[neighbors[node][i]]>(AggNumber)0) {
751 support.push_back(i);
752 null_prob -= s[neighbors[node][i]];
753 }
754 }
755 if (numNei < numActionNodes && null_prob>(AggNumber)0)
756 support.push_back(-1);
757
758
759 //gray code
760 GrayComposition gc (numPlayers-1, support.size() );
761
762 AggNumber prob = pow((support.at(0)>=0)?s[neighbors[node][support[0]]]:null_prob,
763 numPlayers-1);
764
765 while (1){
766 const vector<int>& comp = gc.get();
767 config c(numNei, 0);
768 for (size_t j=0;j<support.size(); ++j) {
769 if(support[j]!=-1)
770 c[support[j]] = comp[j];
771 }
772 //add current player's action
773 if (self!=-1) c[self]++;
774 V+= prob * payoffs[node].find(c)->second ;
775
776 //get next composition
777 gc.incr();
778 if (gc.eof() ) break;
779 //update prob
780 AggNumber i_prob = (support.at(gc.i)!=-1)?s[neighbors[node][support[gc.i]]]:null_prob;
781 AggNumber d_prob =(support.at(gc.d)!=-1)?s[neighbors[node][support[gc.d]]]:null_prob;
782 assert(i_prob>(AggNumber)0 && d_prob>(AggNumber)0 );
783 prob *= ((AggNumber)(gc.get().at(gc.d)+1)) * i_prob /(AggNumber)(gc.get().at(gc.i)) /d_prob;
784
785 }//end while
786
787 return V;
788 }
789
790 //get the prob distribution over configurations of neighbourhood of node.
791 //plClass: the index for the player class
792 //s: mixed strat for that player class
793
getSymConfigProb(int plClass,StrategyProfile & s,int ownPlClass,int act,aggdistrib & dest,int plClass2,int act2)794 void AGG::getSymConfigProb(int plClass, StrategyProfile &s, int ownPlClass, int act, aggdistrib &dest,int plClass2,int act2){
795 int node = uniqueActionSets.at(ownPlClass).at(act);
796 int numPl = playerClasses.at(plClass).size();
797 assert(numPl>0);
798 //int numA = uniqueActionSets[plClass].size();
799
800
801 if (plClass==ownPlClass) numPl--;
802 if (plClass==plClass2) numPl--;
803 dest.reset();
804 int numNei = neighbors.at(node).size();
805
806
807 if(!isPure[node]){
808 int player = playerClasses[plClass].at(0);
809 projectedStrat[node][player].reset();
810 if(numPl>0){
811 for (int j=0;j<actions[player];j++)if(s[j]>(AggNumber)0.0){
812 projectedStrat[node][player]+= make_pair(projection[node][player][j], s[j]);
813 }
814 projectedStrat[node][player].power(numPl, dest,Pr[0],numNei, projFunctions[node]);
815 }
816 if(plClass==ownPlClass){
817 aggdistrib temp;
818 temp.insert(make_pair(projection[node][player].at(act),1.0));
819 if(dest.size()>0){
820 dest.multiply(temp, numNei, projFunctions[node]);
821 }else{
822 //dest.swap(temp);
823 dest=temp;
824 }
825 }
826 if(plClass==plClass2){
827 aggdistrib temp;
828 temp.insert(make_pair(projection[node][player].at(act2),1.0));
829 if(dest.size()>0){
830 dest.multiply(temp, numNei, projFunctions[node]);
831 }else{
832 //dest.swap(temp);
833 dest=temp;
834 }
835 }
836 return;
837 }
838
839
840
841
842
843 //AggNumber V = 0.0;
844 vector<int> support;
845 AggNumber null_prob=1;
846 //do projection & get support
847 int self = -1; //index of self in the neighbor list
848 int ind2=-1; //index of act2 in the neighbor list
849 int p=playerClasses[plClass][0];
850 for (int i=0; i<numNei; ++i){
851 if (neighbors[node][i] == node) self=i;
852 if (plClass2>=0 && neighbors[node][i] == uniqueActionSets.at(plClass2).at(act2)) ind2=i;
853
854 int a=node2Action.at(neighbors[node][i]).at(p);
855 if (a>=0&&s[a]>(AggNumber)0) {
856 support.push_back(i);
857 null_prob -= s[a];
858 }
859 }
860 if (null_prob>(AggNumber)0)
861 support.push_back(-1);
862
863
864 //gray code
865 GrayComposition gc (numPl, support.size() );
866
867 AggNumber prob0=(support.at(0)>=0)?s[node2Action[neighbors[node].at(support[0])][p]]:null_prob;
868 AggNumber prob = pow(prob0,numPl);
869
870 while (1){
871 const vector<int>& comp = gc.get();
872 config c(numNei, 0);
873 for (size_t j=0;j<support.size(); ++j) {
874 if(support[j]!=-1)
875 c[support[j]] = comp[j];
876 }
877 //add current player's action
878 if (plClass == ownPlClass && self!=-1) c[self]++;
879
880 if(plClass==plClass2 && ind2!=-1)c[ind2]++;
881
882 //V+= prob * payoffs[node].find(c)->second ;
883 dest.insert(make_pair(c, prob));
884
885 //get next composition
886 gc.incr();
887 if (gc.eof() ) break;
888 //update prob
889 AggNumber i_prob = (support.at(gc.i)!=-1)?s[node2Action[neighbors[node][support[gc.i]]][p]]:null_prob;
890 AggNumber d_prob =(support.at(gc.d)!=-1)?s[node2Action[neighbors[node][support[gc.d]]][p]]:null_prob;
891 assert(i_prob>(AggNumber)0 && d_prob>(AggNumber)0 );
892 prob *= ((AggNumber)(gc.get().at(gc.d)+1)) * i_prob /(AggNumber)(gc.get().at(gc.i)) /d_prob;
893
894 }//end while
895
896
897 }
898
getKSymMixedPayoff(int playerClass,vector<StrategyProfile> & s)899 AggNumber AGG::getKSymMixedPayoff( int playerClass,vector<StrategyProfile> &s){
900 AggNumber result=0.0;
901
902 for(int act=0;act<(int)uniqueActionSets[playerClass].size();act++)if(s[playerClass][act]>(AggNumber)0.0){
903
904 result += s[playerClass][act] *getKSymMixedPayoff(playerClass, act,s);
905 }
906 return result;
907 }
getKSymMixedPayoff(int playerClass,StrategyProfile & s)908 AggNumber AGG::getKSymMixedPayoff( int playerClass,StrategyProfile &s){
909 AggNumber result=0.0;
910
911 for(int act=0;act<(int)uniqueActionSets[playerClass].size();act++)if(s[firstKSymAction(playerClass)+act]>(AggNumber)0.0){
912
913 result += s[firstKSymAction(playerClass)+act] *getKSymMixedPayoff(s,playerClass, act);
914 }
915 return result;
916 }
getKSymPayoffVector(AggNumberVector & dest,int playerClass,StrategyProfile & s)917 void AGG::getKSymPayoffVector(AggNumberVector& dest,int playerClass, StrategyProfile &s){
918 for (size_t act=0;act<uniqueActionSets[playerClass].size();++act){
919 dest[act]=getKSymMixedPayoff(s,playerClass,act);
920 }
921 }
getKSymMixedPayoff(int playerClass,int act,vector<StrategyProfile> & s)922 AggNumber AGG::getKSymMixedPayoff(int playerClass, int act, vector<StrategyProfile> &s){
923
924 int numPC = playerClasses.size();
925
926 int numNei = neighbors[uniqueActionSets[playerClass][act]].size();
927
928 static aggdistrib d,temp;
929 d.reset();
930 temp.reset();
931 getSymConfigProb(0, s[0], playerClass, act, d);
932 for(int pc=1;pc<numPC;pc++){
933 getSymConfigProb(pc, s[pc], playerClass, act, temp);
934 d.multiply(temp, numNei, projFunctions[uniqueActionSets[playerClass][act]]);
935 }
936 return d.inner_prod(payoffs[uniqueActionSets[playerClass][act]]);
937 }
938
getKSymMixedPayoff(const StrategyProfile & s,int pClass1,int act1,int pClass2,int act2)939 AggNumber AGG::getKSymMixedPayoff(const StrategyProfile &s,int pClass1,int act1,int pClass2,int act2){
940 int numPC=playerClasses.size();
941 int numNei=neighbors[uniqueActionSets[pClass1][act1]].size();
942 static aggdistrib d,temp;
943 if (pClass2>=0 && pClass1==pClass2 && playerClasses.at(pClass1).size()<=1){
944 return 0;
945 }
946 d.reset();
947 temp.reset();
948 StrategyProfile s0(getNumKSymActions(0), 0.0);
949 //if (0==pClass2) s0[act2]=1;
950 //else
951 for (int a=firstKSymAction(0);a<lastKSymAction(0);++a)s0[a]=s[a];
952 getSymConfigProb(0,s0,pClass1,act1,d,pClass2,act2);
953 for (int pc=1;pc<numPC;pc++){
954 StrategyProfile ss(getNumKSymActions(pc), 0.0);
955 //if (pc==pClass2)ss[act2]=1;
956 //else
957 for (int a=0;a<getNumKSymActions(pc);++a)ss[a]=s[a+firstKSymAction(pc)];
958 getSymConfigProb(pc,ss,pClass1,act1,temp,pClass2,act2);
959 d.multiply(temp,numNei,projFunctions[uniqueActionSets[pClass1][act1]]);
960 }
961 return d.inner_prod(payoffs[uniqueActionSets[pClass1][act1]]);
962 }
963
964
965
makeMAPPINGpayoff(std::istream & in,aggpayoff & pay,int numNei)966 void AGG::makeMAPPINGpayoff(std::istream& in, aggpayoff& pay, int numNei){
967 int num;
968 char c;
969 AggNumber u;
970 aggpayoff temp;
971 //temp.swap(pay);
972 temp=pay;
973 pay.clear();
974
975 stripComment(in);
976 in>>num;
977 if(!in.good()){
978 cerr<<"Error reading the integer number of configuration-value pairs"<<endl;
979 exit(1);
980 }
981
982 while (num--){
983 in>>ws;
984 if(in.eof()||in.bad()){
985 cerr<<"ERROR: bad input"<<endl;
986 exit(1);
987 }
988
989 c = in.get();
990 assert(in.good());
991 if (c != AGG::LBRACKET){
992 cerr<< "ERROR: "<<AGG::LBRACKET <<" expected. Instead, got "<<c <<endl;
993 cerr<<"The rest of the line is: ";
994 stringbuf discard(ios_base::out);
995 in.get(discard);
996 cerr<<discard.str()<<endl;
997 exit(1);
998 }
999 vector<int> key;
1000
1001 for(int j=0;j<numNei; ++j){
1002 int cnt;
1003 in>>cnt;
1004 if(!in.good()){
1005 cerr<<"ERROR trying to read element #"<<j<<" of the configuraiton"<<endl;
1006 exit(1);
1007 }
1008 key.push_back(cnt);
1009 }
1010
1011
1012 in>>ws;
1013 c=in.get(); //get right bracket
1014 assert (in.good());
1015
1016 if (c!=AGG::RBRACKET){
1017 cerr<< "ERROR: "<<AGG::RBRACKET <<" expected. Instead, got "<<c<<endl;
1018 cerr<< "current configuration: ";
1019 copy(key.begin(),key.end(), ostream_iterator<int>(cerr, " "));
1020 cerr<<endl;
1021 exit(1);
1022 }
1023
1024 in>>u; //get payoff
1025 if(!in.good()){
1026 cerr<<"Error trying to read the utility value for configuration ";
1027 copy(key.begin(),key.end(), ostream_iterator<int>(cerr, " "));
1028 cerr<<endl;
1029 exit(1);
1030 }
1031
1032
1033 //insert
1034 pair<trie_map<AggNumber>::iterator, bool> r = pay.insert(make_pair(key,u));
1035 if (!r.second){
1036 cerr<<"WARNING: overwriting utility at [";
1037 copy(key.begin(),key.end(), ostream_iterator<int>(cerr, " "));
1038 cerr<<"]"<<endl;
1039 cerr<<"previous value: "<<r.first->second<<" new value: "<<u<<endl;
1040
1041 r.first->second = u;
1042 }
1043
1044 }
1045 //check
1046 for(trie_map<AggNumber>::iterator it = temp.begin(); it!=temp.end(); ++it){
1047
1048 //pair<trie_map<AggNumber>::iterator,bool> res = pay.insert( *it);
1049
1050 if (pay.count(it->first)==0){
1051 cerr<<"ERROR: utility at [";
1052 copy(it->first.begin(),it->first.end(), ostream_iterator<int>(cerr, " "));
1053 cerr<<"] not specified."<<endl;
1054 cerr<<"The set of configurations (requiring utility to be specified) are: "<<endl;
1055 cerr<<temp;
1056 cerr<<endl;
1057 cerr<<"The set of configurations to which utility has been specified are: "<<endl;
1058 cerr<<pay;
1059 cerr<<endl;
1060 exit(1);
1061 }
1062 }
1063
1064
1065 }
1066
getMaxPayoff()1067 AggNumber AGG::getMaxPayoff(){
1068 static bool done=false;
1069 static AggNumber result=0;
1070 if (done)return result;
1071 assert(numActionNodes>0);
1072 result=payoffs[0].begin()->second;
1073 for (int i=1;i<numActionNodes;i++)
1074 for (aggpayoff::iterator it=payoffs[i].begin();it!=payoffs[i].end();++it)
1075 result=max(result, it->second);
1076
1077 done=true;
1078 return result;
1079 }
getMinPayoff()1080 AggNumber AGG::getMinPayoff(){
1081 static bool done=false;
1082 static AggNumber result=0;
1083 if (done)return result;
1084 assert(numActionNodes>0);
1085 result=payoffs[0].begin()->second;
1086 for (int i=1;i<numActionNodes;i++)
1087 for (aggpayoff::iterator it=payoffs[i].begin();it!=payoffs[i].end();++it)
1088 result=min(result, it->second);
1089 done=true;
1090 return result;
1091 }
1092
1093
1094 } // end namespace Gambit::agg
1095
1096 } // end namespace Gambit
1097