Santos-Pacheco-Lenaerts model

/* 繋ぎ変えメカニズムをもつジレンマモデル
   Santos-Pacheco-Lenaerts model */
/* 描画ライブラリとして plplotが必要 */

#include "plConfig.h"
#include "plplot.h"
#include "plevent.h"
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define AGENT_NUM 100
#define LINK_NUM 500

#define XMAX 4.0  /* glplotのウィンドウサイズ */
#define YMAX 4.0
#define BGCOLOR "FFFFFF"  /* glplotの背景色 */
#define TAU_A 1.0
#define TAU_E 1.0

typedef struct agent_type{
  int attri;
  double payoff;
  int linkto[AGENT_NUM];
  int c_max;

  double c;
} AGENT;
double x[AGENT_NUM][1],y[AGENT_NUM][1];


int main(){
  double te,ta,y,w,z,c,M,K,O,T,S,P,R,Z,Q,pl,p,r; /* 変数定義としては悪い見本! まねしないように*/
  int i=0,n,m,k,j,o,l,q,f,v,B,L,h,mk,b,x,lm,d,e,V,C,F,D,ok,ck,ak,cd;
  int myIDX_in_partner_linkto, partnerIDX_in_my_linkto,IDX_new_in_partner_linkto;
  AGENT a[AGENT_NUM];
  int iteration,checkFlag, me, partner, both_unsatisfied=0;
  double param_w, prob_choose_strategy;  /* W */

  srand((unsigned) time(NULL));
  /* T: Temptation, P: punishiment, S: sucker's, R: Reward for mutual coop. */

  param_w = TAU_E/TAU_A;
  printf("W= %f\n", param_w);

  prob_choose_strategy = 1.0 / (1+ param_w);
  R=1;P=0; /* ペアの利得定数 */

  T=0.0;
  while(T < 2.0){
    T+=0.2;
    printf("\n利得G(T):%.2f\n",T);

    S=-1.0;
    while(S <1.0){
      S+=0.2;
      printf("利得S:%.2f  ",S);


      for(i=0; i<AGENT_NUM;i++){
        a[i].c_max=-1;
      }
      for (i=0;i<AGENT_NUM;i++){
        a[i].attri =(int)(0.5 + (double)random()/RAND_MAX); // CかDか

        do {  // 各ノードについて最初のリンク1本をつくる リンクが重複しないように
          checkFlag=0;
          n = (int) random()%AGENT_NUM;
          for(j=0;j<=a[i].c_max;j++) if(a[i].linkto[j]==n) checkFlag++;
        } while(checkFlag!=0);
        a[i].c_max++;
        a[i].linkto[a[i].c_max] = n;
        a[n].c_max++;
        a[n].linkto[a[n].c_max] = i;
        if (1.0<=a[i].attri){e++;}

      }

      for(i=0;i<LINK_NUM-AGENT_NUM;i++){
        n = random()%AGENT_NUM;
        m = n;

        do {
          checkFlag = 0;
          m = random()%AGENT_NUM;
          for(j=0;j<=a[n].c_max;j++) if(a[n].linkto[j]==m) checkFlag++;
          for(j=0;j<=a[m].c_max;j++) if(a[m].linkto[j]==n) checkFlag++;
        } while(checkFlag!=0);

        a[n].c_max++;
        a[n].linkto[a[n].c_max]=m;
        a[m].c_max++;
        a[m].linkto[a[m].c_max]=n;
      }
      /* 以上、初期のランダムグラフ作成 */
      /*for(ck=0;ck<=AGENT_NUM;ck++){printf("つながりの数:%d;%d\n",ck,a[ck].c_max);}
       */
      //      printf("SGAP %f,%f,%f,%f\n",S,G,A,P);

      /* 初期状態の描画 */
      //                        drawInit();
      //                        drawAll(a);
      /*******************/

      /* 時間発展の繰り返し */
      for(iteration=0;iteration<1000000;iteration++) {/*printf("%d回目\n",i+1);*/
        /* ひとつのノードをランダムに選び出す*/
        k = rand()%AGENT_NUM;

        if(a[k].c_max==0) continue; /* リンクが1本になったらゲームはしない */

        /* それとつながった相手をランダムに選ぶ */
        partnerIDX_in_my_linkto  = rand() % a[k].c_max;
        f = a[k].linkto[partnerIDX_in_my_linkto];

        /*  printf("Aの戦略:%d  ", a[k].attri );*/

        /* attri=1: cooperator,  attri=0: defector */
        a[k].payoff=0;
        for(j=0;j<=a[k].c_max;j++){
          if(a[k].attri == 1 &&  a[a[k].linkto[j]].attri == 0)
            { a[k].payoff+=S;}
          else if(a[k].attri == 0 && a[a[k].linkto[j]].attri==1)
            { a[k].payoff+=T;}
          else if(a[k].attri==0 &&  a[a[k].linkto[j]].attri==0)
            { a[k].payoff+=P;}
          else if(a[k].attri==1 &&  a[a[k].linkto[j]].attri==1)
            { a[k].payoff+=R;
            } else {
            printf("error %d %d %d %d %d\n",k,j,a[j].c_max,a[k].attri,a[j].attri);
          }
        }
        r=a[k].payoff;
        /* printf("Aの総利得:%.001f\n",a[k].payoff);*/

        /* printf("Bの戦略:%d  ", a[f].attri );*/

        a[f].payoff=0;
        for(v=0;v<=a[f].c_max;v++){
          if(a[f].attri == 1 &&  a[a[f].linkto[v]].attri ==0)
            { a[f].payoff+=S;}
          else if(a[f].attri ==0 && a[a[f].linkto[v]].attri==1)
            { a[f].payoff+=T;}
          else if(a[f].attri==0 &&  a[a[f].linkto[v]].attri==0)
            { a[f].payoff+=P;}
          else if(a[f].attri==1 &&  a[a[f].linkto[v]].attri==1)
            { a[f].payoff+=R;
            } else {
            printf("error %d %d %d %d %d\n",f,v,a[f].c_max,a[f].attri,a[v].attri);
          }
        }
        p=a[f].payoff;
        /* printf("Bの総利得%.001f\n",a[f].payoff);*/

        y=-0.005*(p-r);
        if(abs(y)>100.0)        y=100.0;
        w=1.0/(1.0+exp(y));  /* w = 1.0/(1 + exp(-\beta * (Pi(B) - Pi(A)) */



        if((double)random()/(double)RAND_MAX < prob_choose_strategy) {
          /****** 戦略の変更を選択  *******/
          if((double)random()/(double)RAND_MAX < w) {
            a[k].attri = a[f].attri;  /* attri=0なら1に,1なら0に */
          }

        } else if(a[f].c_max!=0) {
          /***** つなぎ替えを選択 *******/
          both_unsatisfied =0;
          if(a[k].attri ==1 ) { /*自分がCooperatior */
            if( a[f].attri == 1) continue; /* 相手がCooperatorなら何もしない.両方満足 */
            else {
              /* 相手がDefectorなら,自分のつなぎ替えを試みる */
              me = k; partner = f;
            }
          } else { /* 自分がDefectorの場合 */
            if(a[f].attri == 1) continue; /* 相手がCooperatorなら何もしない */
            else {
              /* どちらもDefector(不満)の場合は,どちらかが確率的につなぎ替え */
              both_unsatisfied = 1;
              if((double)random()/(double)RAND_MAX < w) {
                me = k; partner = f;
              } else {
                me = f; partner = k; /* partnerの方を入れ替えるため,meとpartnerを交代 */
                for(b=0; b <= a[me].c_max; b++) {
                  if(a[me].linkto[b]==partner) {
                    partnerIDX_in_my_linkto = b;
                    break;
                  }
                }
                if(b>a[me].c_max) {printf("見つからない!!%d, %d",b,a[me].c_max);
                  exit(0);}
              }
            }
          }
          /* 以降,つなぎ替えを試みる方をme,切られる相手をpartnerと記す */
          v = 0; cd=0;
          /* 新しい友達探し */
          while(v < a[partner].c_max*2) {  /* 無限ループにおちいらいないために c_maxの2倍繰り返したらやめる */
            IDX_new_in_partner_linkto = rand() % a[partner].c_max;
            B = a[partner].linkto[IDX_new_in_partner_linkto];
            if(B!=me) { /* 再び自分が選ばれることを避ける */
              for (b=0; b<=a[me].c_max; b++){ /* すでに自分の友達かどうかチェック.リンクの重複を避ける */
                if(B == a[me].linkto[b]) cd++;
              }
              if(cd==0) break; /* 避けられた -> 新しい友達候補がみつかったらループから抜ける */
            }
            v++;
          }

          if(v < a[partner].c_max*2) { /* 新たな友達候補が見つかったときだけ */

            if(both_unsatisfied==1 || (double)random()/(double)RAND_MAX < w){ /* 確率的につなぎ替え */

              for(b=0; b<=a[partner].c_max;b++) {
                if(a[partner].linkto[b] == me) {
                  myIDX_in_partner_linkto = b;
                  break;
                }
              }
              /* test 出力 */
              /* printf("\nme=%d, f=%d,B=%d\n", me, partner,B);
                 for(j=0;j<=a[me].c_max;j++) printf("%d, ",a[me].linkto[j]);
                 printf("\n");
                 for(j=0;j<=a[partner].c_max;j++) printf("%d, ",a[partner].linkto[j]);
              */

              if(b>a[partner].c_max) {
                printf("相手のlinktoに自分の登録が見つかりませんでした.me=%d\n",me);
                //                                                              for(j=0;j<=a[partner].c_max;j++) printf("%d, ",a[partner].linkto[j]);
                exit(0);
              }
              /*相手のlinktoから自分の登録を抹消 */
              L = myIDX_in_partner_linkto;
              while(L<a[partner].c_max) {
                a[partner].linkto[L]=a[partner].linkto[L+1];
                L++;
              }
              a[partner].c_max--;

              /* 自分のlinktoに新しい友達を登録 (上書きにより既存の相手を抹消) */
              a[me].linkto[partnerIDX_in_my_linkto] = B;

              /* 新しい友達のlinktoへ自分を登録 */
              a[B].linkto[a[B].c_max+1]=me;
              a[B].c_max++;
            }
            //                                                  f = B; /** ???? これは何? */
          }
          /*BににつながったCをランダムに選ぶ*/
        } /* つなぎ替えの終わり */
        if(i%100==0) { /* 描画 */
          //                                    printf("i=%d\n",i);
          //                                    drawAll(a);
        }
      } /* 1回の試行(r <= p) の終わり */

      /*printf("%d\n",e);*/ /*for(ak=0;ak<=AGENT_NUM;ak++){printf("数%d;%d\n",ak,a[ak].c_max);}*/
      for (b=0;b<AGENT_NUM;b++){if( a[b].attri==1){Z++;}}

      printf("%.5f \n",(double)Z/AGENT_NUM);
      Z=0;
    }
  }

  plend();
  exit(0);
}

int drawInit(AGENT a[]){
  int i,j;
  plsdev("xwin");
  plsetopt("geometry","700x700");
  plsetopt("bg",BGCOLOR);
  //  plinit();
  plstar(1,1);

  for(i=0;i<AGENT_NUM; i++){
    x[i][0] = (double) random()/RAND_MAX*XMAX;  /* AGENT_NUM個のノード位置 */
    y[i][0] = (double) random()/RAND_MAX*YMAX;
  }

}

int drawAll(AGENT a[], int new_page) {

  int i,j;
  int col[2] = {1,9}; /* マークの色 */

  plenv(0,XMAX,0,YMAX,1,-2);

  plcol0(1);
  plssym(0.,2.0);

  for(i=0;i<AGENT_NUM; i++){
    plcol0(col[a[i].attri]);
    plpoin(1,x[i],y[i],a[i].attri+16);
  }

  plcol0(5);
  for(i=0;i<AGENT_NUM;i++){
    j=0;
    while(j<=a[i].c_max){
      pljoin(x[i][0],y[i][0],x[a[i].linkto[j]][0],y[a[i].linkto[j]][0]);
      j++;
    }
  }
  /*  plend(); */
  return(0);
}

/* 変化するノードを目立つように大きくし,前の注目ノードを元に戻す */
int drawChangeNode(int n, int attri, int prev_n, int prev_attri) {
  int col[2] = {1,9}; /* マークの色 */

  plssym(0,2.0); /* 一回り大きく */

  plcol0(col[attri]);
  plpoin(1,x[n],y[n],attri+16);

  plcol0(15);  /* 15は白 */
  plpoin(1,x[prev_n],y[prev_n],prev_attri+16); /* 前のを普通の大きさに戻す */

  plcol0(col[prev_attri]);
  plpoin(1,x[prev_n],y[prev_n],prev_attri+16);

}

/* リンク線を消す */
int plotDelLink(int m, int del_n) {/*2つのAGENT番号を受け取って消す */
  int col[2] = {1,9}; /* マークの色 */
  plcol0(15);
  pljoin(x[m][0],y[m][0],x[del_n][0],y[del_n][0]);
}

/* 新たにリンク線を張る */
int plotNewLink(int m, int new_n) { /*  */
  int col[2] = {1,9}; /* マークの色 */
  plcol0(5);
  pljoin(x[m][0],y[m][0],x[new_n][0],y[new_n][0]);
}