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