« 時効延長絶対反対 | トップページ | 海外ダウンロード購入にまつわる私のトラブルに関する法的検討 »

2011年1月 9日 (日)

外作用的簡易経済シミュレーションのアイデアと Perl による実装

抽象化された確率モデルにおいて、内的作用(内作用)により作られたモデルと外的作用(外作用)から作られたモデルが同じ臨界をもたらすことがある。経済に関するモデルを作るとき、ミクロな部分でなしたことがマクロに影響するということがいいたいことがあるが、マクロの大きな数と複雑な動きを表すにはコンピュータを用いても限界がある。確率モデルのようなアイデアをもってすれば、コンピュータシミュレーションなどで解析できるほど少ない数でも、しかし、それが外作用的にミクロな内作用と関わるというモデルが作れるのではないかと考えた。

私は本稿の実験および考察を通じ、外作用をとても簡易で厳格なモデルにするが、内作用については外作用との関わりはごく限るかわりにその表現を自由にすることで、いろいろな問題についてある種の見通しを出すことができるかもしれないという感触を得た。
外作用モデル


実装とは必ずしも異るが、アイデアとしての外作用モデルを、その要素ごとに提示していく。

嗜好品需要


ある市場に売り手と買い手が情報を出す。売り手の価格を超える desire を持つ買い手のうち、もっとも高い desire を持つものが、二番目に高い desire の価格または seller の価格で購入を行う。

ここは外作用といいながら、内作用的に細かいすりあわせが行われる。ここが商売の譲れない基本ということかもしれない。


必需品需要


greed のもっとも低い売り手から順に買い入れられて必要量消費される。その平均額がその品の売り手から均等にわけ与えられる。その総額が大きいと、 desire の総量が大きくなる。

最後は、すなわち、所得ルールである。消費量一定でも消費総額が多いと気が大きくなって、desire も大きくなるとする。

desire と greed は別のもので、単純に消費欲と生産欲というわけでもない。もちろん、現実の経済では、ある物が嗜好品か必需品かというのは定かではないが、むしろ、desire を持ってしまうのが嗜好品であり、greed を持ってしまうのが必需品で、現実にある定かでない物というのは、それらが一つの view をもって見えているに過ぎない……といったようにこのモデルでは考えるのである。


一般需要ルール


その期の収穫が少なく liability が大きいと greed が大きくなる。asset が大きいと desire の振輻が大きくなる。

借金が大きいと値段をふっかけようとし、資産が大きいと高い物でも買えるが、欲しくないものはまったく欲しくないというような「わがままさ」を持つといったところか。


嗜好品供給


各 player に毎期一定の確率でできる。その価格は asset が大きいほど、大きくなる。

つまり、このモデルで asset というのは文化資本であって、嗜好品は文化的蓄積からのみ価値の高いものができる…とでもいえよう。


必需品供給


総産出量がある程度決まっており、毎期、必要量以上はある。総 liability が大きいほど、産出量が大きくなる。ランダムに持分権と権利期間が割り振られ、権利期間が終るまで持続する。持分権にランダム変動をかけた割合で分割して生産したことになる。

「産出量が大きくなる」という部分については、今回の実装ではそれほど気にしていない。

持分権をある期間持つ possession は、耕作地の所有権のようなイメージだが、それがいきなり与えられいきなり取り上げられるのは、まさに「外作用」的簡易さの現れている部分である。これも内作用的な view で嗜好品消費と結びつけることができるだろうから、観方によっては、必需品の possession のはずなのに desire の有効期間として機能することもできるだろうという直感がある。


収支のルール


嗜好品の購入は、資産と負債が同時に増える。必需品の購入は、負債だけが増える。嗜好品・必需品の売却は、負債が減るか、(現金)資産が増える。

なお、「(現金)資産」とは単にマイナスの負債のことである。つまり、このシミュレーション世界では、現金とは「マイナスの負債」すなわち、負債の相手方が誰かいるということの標章に過ぎない。

もちろん、内作用の view においては、 現金らしい動きをするものも作れるかもしれず、それは排除しない。


資産減耗


減耗はなくてもよい。減耗する場合は、定率にするか、ランダムにばらすか試してみるべきだろう。

なお、資産価格の上昇は、asset に関して desire や供給価格が変化することに捉えられているとする。

今回の実装には、資産減耗は入れてない。


内作用の戦術


内作用は tactics と呼ばれ、tactics は外作用のステップの半ばで呼ばれることになる。

View


player の view に関して統計をとる。

この統計が simulation そのものの実験者への view とも言える。

なお、今回の実験では view の統計をとり、問題にするところまでには致っていない。


戦術


外作用に view を反映させる方法、すなわちこのゲームの「コマ」は二種しかない。一つは、必需品を「廃棄」すること、もう一つは嗜好品を「価格低下」させること。量をいじれるのは commodity (嗜好品か必需品)だけで、 asset や liability, possession もいじることはできない。

必需品の「廃棄」により、必要需要量を下回ってもよい。これは単に、ある者の必需品売却に対する受益権の放棄を意味するに近い。

嗜好品を自分の desire よりも安い価格とすることで、それを自分の asset にもできる。ただし、自分の desire がどれぐらいかが明らかであるとは限らない。(その期、買い手のいない嗜好品は廃棄される。)

他者の価格推移がわかったり desire がわかったりすると考えるかどうか、それによりどのように「廃棄」を決定するか…といったことが戦術となる。 desire や greed のやりとりもできないが、「自分」が知っているそのデータを根拠に「廃棄」や「ディスカウント」する「契約」は結べる。liability や asset の増減は直接できなくとも、それに関して廃棄させるようなことはできる。


二つの基本戦術


「廃棄」や「価格低下」のような「マイナス」の操作だけでは、経済的に意味がないと思うかもしれないが、そうではない。

まず、廃棄されるはずだった嗜好品の価格を自分の desire にまで下落させることができれば、相手には収入が入るし、自分の asset は大きくなる。だから、価格下落の権利は未実現資産として view されることになる。

また、greed の低い者の必需品を廃棄させることができれば、必需品の価格はたいてい上がることになり、それは liability の減少、ひいては、greed の減少につながり、「好順還」をもたらすかもしれない。特に、誰でもいいから廃棄させられるといったものは「現金」として view できるようになるかもしれない。

ただし、asset が大きいことも liability が大きくなることも「良いこととする」かどうかは決まっていない。とりあえずは、総 liability が小さい中で、嗜好品の一期の売買総額が大きくなることを目標にしようかと思う。

最初に作る tacitics として、上の二つを直接つなげるように考えた。売れ残った嗜好品を 10% 下げれば買える者がいるとき、その者は任意の期の必需品の 10% を廃棄する権利を渡すことで、ディスカウントが実現するとする。そして、その者の必需品が売れる状態ならば、必ず 10% 廃棄の権利が使われるとする。そして、view としては、必需品廃棄の権利がどれぐらい大きくなるかも調べたい。その内作用により、どう外作用的経済の統計が変わるか、その内作用的 view を最大にする外作用とはどのようなものか考えたい。

このような戦術の導入により、asset があり liability がなくても貧乏と view されるものが出てくるだろう。それによって、外作用モデルの結果も変わる。しかし、それでも外作用のルールが変更されるわけではない。

何かを最大にする外作用を考えたとしても、その実現は、それを可能とする別の内作用を見つけることが理想である。ただし、その内作用どうしの相互作用が意図しない結果を生むことも十分考えられる。

場面の設定と、場面の変分により作用の本質的パラメータを特定するようなことも、将来的には行いたい。


集団の埋め込み


将来的には、複数の player を統合して、一人の player と見なす「埋め込み」は可能か、どういう条件が必要か……といたことを解析したい。


Perl での実装


Perl での実装は、とりあえず、シミュレーションが動作するところまでしかできておらず、入出力もコマンドラインを通じてするものしかない。

もちろん、細かい実装については説明しきれないが、まず、注意すべき点から。

シミュレーションで同じ結果を得るために、生成される乱数を固定するときは、オプションに --srand=0 などと指定する必要がある。もちろん、ソース の最初で srand をしてもよい。その場合は下記のコメントアウトした部分をコードに戻せばよい。

:
:
# BEGIN { srand(0); }

use strict;
use warnings;
:
:



何かによって desire が大きくなる…などといったことにどういう関数を割り当てるかが問題だが、次のようにしている。

{
  package Main::_LuxuryCommodity; ## 嗜好品
  use base qw(Main::_Commodity);
  :
  :
  sub random_produce {
    my $self = shift;
    my ($asset) = @_;
    return 0 if rand(1) < $self->{difficulty};
    my $v = variance_for_mean_of_pnr(log(1 + $asset), $Pow);
    return powered_normal_rand(0, $v, $Pow);
  }

  sub random_desire {
    my $self = shift;
    my ($asset, $init_price, $tendency) = @_;

    return normal_rand($tendency * $init_price, sqrt($asset));
  }
  :
  :
}
:
:
{
  package Main::_EssentialCommodity; ## 必需品
  use base qw(Main::_Commodity);
  :
  :
  sub random_produce {
    my $self = shift;
    my ($quota) = @_;

    if ($USE_PPNR) {
      return pseudo_powered_normal_rand($quota, $Pow);
    } else {
      my $v = variance_for_mean_of_pnr($quota, $Pow);
      return powered_normal_rand(0, $v, $Pow);
    }
  }

  sub random_attach {
    my $self = shift;
    my ($newquata, $players) = @_;
  :
  :
  }
}
:
:
{
  package Main::_Market;
  use base qw(Main::_Simple);
  :
  :
          ## greed の計算式 $prod はプレイヤー $p の今期の生産。
          my $mag = exp(1 - pow($prod / $quota, 1/$Pow));
          $greed = $mag
            * sqrt(($p->{liability} > 100)? $p->{liability}
                   : log(1 + exp($p->{liability})));
  :
  :
}  
:
:
{
  package Math::Aux;
  :
  :
  sub variance_for_mean_of_pnr {
    my ($mean, $pow) = @_;

    return pow($mean * sqrt(pi) / gamma(($pow + 1) / 2), 1/$pow)/sqrt(2);
  }
  :
  :
}  


ここで powered_normal_rand は N を正規乱数とすると √|N| を返すような関数($Pow は 0.5 にほぼ固定。)である。「下限のみが定義され最大頻度を持つ乱数」で、もっとも簡単に表現できるものを選んだ。密度関数を求めることも簡単だが、自然界に正規分布したものの冪乗根を取るような操作があるのかと問われると苦しい。

その平均となるところは正規乱数の分散に関連するがそのものではない。シミュレーションでは、欲しい平均に対応する分散を variance_for_mean_of_pnr の計算式で求めている。gamma はΓ関数である。

なお、$tendency は今期の必需品総消費額を前期の必需品総消費額で割ったものに arctan (tan の逆関数)を適用したものをとりあえず用いている。 $init_price は、その期のある嗜好品 $c の生産者希望価格の平均に $c->{simplicity} (現在 0.7 に固定)をかけたものにしている。$quota は持分権である。

毎期、割り当てられた期間の過ぎた possession が出てくるため、それをランダムに割り当てる必要があるが、それをするのが random_attach である。当然、二重に割り当てられることがでてくるが、その場合は、従来の持分権を $quota として $newterm = $term + ($newterm / (1 + $quota)) として期間延長により対応している。そのため、期間が過ぎるときは徐々に持分権が少なくなるということはなく、一気になくなってしまう。

powered_normal_rand の替わりに pseudo_powered_normal_rand が使えるようにしている。両者は似た形で、「下限のみが定義され最大頻度を持つ乱数」だが、後者だと、$greed の解析時に $mag の部分の密度関数が a x + b の一次式になる。これはいずれどちらを使うか、著者である私が決定すべきだろう。

これらの計算式は、解析がしやすいように選択している面が大きく、観測結果等に基づいてはいないという点で、根拠は薄い。


需要と供給のすりあわせのアルゴリズムは次のようになっている。

{
  package Main::_Market;
  use base qw(Main::_Simple);
  :
  :
  sub match_greed {
    my $market = shift;
    my ($cid, $prodmap) = @_;

    my @producer = keys %{$prodmap};
    @producer = sort {$market->{player}->{$a}->{greed}->{$cid}
                        <=> $market->{player}->{$b}->{greed}->{$cid}}
      @producer;
    my $total_prod = 0;
    foreach my $pid (@producer) {
      $total_prod += $prodmap->{$pid};
    }
    my $total = 0;
    my $need = $market->{essential}->{$cid}->{need};
    my $i = 0;
    while ($need > 0 && $i < @producer) {
      my $pid = $producer[$i++];
      my $greed = $market->{player}->{$pid}->{greed}->{$cid};
      my $prod = $prodmap->{$pid};
      if ($need < $prod) {
        $total += $greed * $need;
        $need = 0;
      } else {
        $total += $greed * $prod;
        $need -= $prod;
      }
    }

    my $buyer_price = $total / scalar(keys %{$market->{player}});
    my $seller_price = {};

    foreach my $pid (@producer) {
      my $prod = $prodmap->{$pid};
      my $price = $prod * $total / $total_prod;
      $seller_price->{$pid} = $price;
    }

    return ($buyer_price, $seller_price);
  }
  :
  :
  sub match_desire {
    my $market = shift;
    my ($cid, $pricemap) = @_;

    my @producer = keys %{$pricemap};
    @producer = sort {$pricemap->{$a} <=> $pricemap->{$b}} @producer;

    my @desire;
    foreach my $pid (keys %{$market->{player}}) {
      push(@desire, $pid) 
        if exists $market->{player}->{$pid}->{desire}->{$cid};
    }
    @desire = sort {$market->{player}->{$b}->{desire}->{$cid}
                      <=> $market->{player}->{$a}->{desire}->{$cid}}
      @desire;

    my @match;
    while (@producer && @desire) {
      my $p = $producer[0];
      my $d = shift(@desire);
      my $price = $pricemap->{$p};
      last if $market->{player}->{$d}->{desire}->{$cid} < $price;
      if (@desire) {
        my $rival = $desire[0];
        $price = $market->{player}->{$rival}->{desire}->{$cid}
          if $market->{player}->{$rival}->{desire}->{$cid} > $price;
      }
      @producer = grep {$pricemap->{$_} <= $price} @producer;
      unshift(@match, [$price, $d, @producer]);
      pop(@producer) if @producer;
    }

    my $sold = 0;
    my $prev_price = 0;
    foreach my $m (@match) {
      my ($price, $d, @rest) = @$m;
      my $p = $rest[$sold++];
      my $seller_price = $pricemap->{$p};
      if (@rest > $sold) {
        $price = ($seller_price > $prev_price)?
          $seller_price : $prev_price;
      }
      @$m = ($price, $d, $p);
      $prev_price = $price;
    }
    return @match;
  }
  :
  :
}


必需品に関しては、$need が満ちるまで集めるのが価格決定には重要で、あとは総計をとって、持分に応じ分割しているだけである。

嗜好品に関しては、かなり複雑なことになっているが、オークション的に価格をすりあわせている。アルゴリズムがこれで良いのかはっきりいって自信はない。


戦術、tactics の実装についても説明しておこう。tactics は「クラス」として実装され、その期の途中で割り込みを行いたい部分にのみメソッドを書いておくということになる。ソースでは上の「二つの基本戦術」のところで書いたものを実装しているが、長いのでその説明はせず、どのようにメインループから tactics が呼び出されるかの部分だけここに転載しておこう。

{
  package Main::_Market;
  use base qw(Main::_Simple);
  :
  :
  sub main_loop {
    my $market = shift;
    my ($while) = @_;
    :
    :
    for (my $term = 0; $term < $while; $term++) {
      :
      :
      if ($DEBUG) {
        map {$_->[1]->preconsume_essential($market)} @{$market->{tactics}};
      } else {
        map {
          my $m2 = $market->clone();
          my ($tid, $tactics) = @$_;
          $tactics->preconsume_essential($m2);
          $market->change_after_tactics($tid, $m2,
                                        discountable_essential => 1
                                       );
        } @{$market->{tactics}};
      }
      $market->annual_consume_essential();
      :
      :
      $market->annual_cleanup();
    }
    :
    :
  }
}


デバッグモードでないとき、tacitics に渡すのは $market そのものではなく $market をコピーしたものである。そして、その返ってきたコピーの内容は、ちゃんと上の戦術の条件として示した「廃棄」と「価格低下」のみ(あとはその tactics 用のデータ)に制限して $market に反映する。

こうすることで、他者が tactics として書いたものをコピー&ペーストして自分の環境で実行するのがかなり安全になる……少なくともプレッシャーを与えることができるだろうと考えている。


実行はいくつかオプションを指定する必要がある。--term で総期間を --player でその数を、--luxury で嗜好品の種類数を、--essential で必需品の種類数を指定できる。また、--initial-asset と --initial-liability で player が持つ asset と liability の初期値が指定できるが、これを別々に設定したいなら、ソースをいじる必要がある。(なお、デフォルトでは --term=10 --player=5 --luxury=2 --essential=3 --initial-asset=5 --initial-liability=10 になっている。)

出力は今のところ、$market のプログラム内での構造をそのままダンプ(吐き出す)だけとなっているが、それも一つの tactics として実装されており、ダンプをするなら --tactics-dumper を指定しなければならない。

「二つの基本戦術」を使う場合は --tactics-desire-greed-convert を指定する。

デバッグモードは -d で指定するが、配布するものは最初からそうなっているので、デバッグモードでなくするためには -d0 を指定する必要がある。乱数固定のため srand をするときは --srand=0 が必要である。必需品の生産に関し、 powered_normal_rand の替わりに pseudo_powered_normal_rand を使うときは --ppnr を指定する。

次のコマンドを実行し、結果を log にとる。

$ perl simple_market_0.pl -d0 --srand=0 --term=100 --player=5 --luxury=2 --essential=3 --tactics-dumper > simple_market_0_without_convert.log
TERM001:
TERM002:
  :
  :
TERM100:


最終期の log は次のようになっている。

TERM100:
$market = bless( {
  current_essential => {
    C003 => {
      P001 => "1.38585848705482",
      P004 => "1.35418264860133",
      P005 => "0.764173024821585"
    },
    C004 => {
      P001 => "1.39482895434153",
      P003 => "1.22323239642829"
    },
    C005 => {
      P001 => "1.11098402290041",
      P003 => "1.33341620305035",
      P005 => "1.42270552055381"
    }
  },
  current_gross_essential_consumption => "10.9979581450734",
  current_luxury => {
    C002 => {
      P004 => "7.34410057579468"
    }
  },
  essential => {
    C003 => bless( {
      id => "C003",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' ),
    C004 => bless( {
      id => "C004",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' ),
    C005 => bless( {
      id => "C005",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' )
  },
  luxury => {
    C001 => bless( {
      difficulty => "0.8",
      id => "C001",
      simplicity => "0.7",
      type => "luxury"
    }, 'Main::_LuxuryCommodity' ),
    C002 => bless( {
      difficulty => "0.8",
      id => "C002",
      simplicity => "0.7",
      type => "luxury"
    }, 'Main::_LuxuryCommodity' )
  },
  player => {
    P001 => bless( {
      asset => "292.526322259257",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {
        C002 => "21.8707742235897"
      },
      current_income_essential => {
        C003 => "4.41026399711994",
        C004 => "6.26294205353971",
        C005 => "3.15961253315821"
      },
      current_income_luxury => {},
      desire => {
        C002 => "29.3189043379945"
      },
      greed => {
        C003 => "3.6528380880111",
        C004 => "3.5628484740355",
        C005 => "7.25595615938614"
      },
      id => "P001",
      liability => "98.9365858742281",
      possession => {
        C003 => {
          quota => 1,
          term => "7.27451057789084"
        },
        C004 => {
          quota => 1,
          term => "9.24261590725239"
        },
        C005 => {
          quota => 1,
          term => "10.712607419061"
        }
      }
    }, 'Main::_Player' ),
    P002 => bless( {
      asset => "185.207825577778",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {},
      current_income_luxury => {},
      desire => {
        C002 => "-18.1103647838689"
      },
      greed => {},
      id => "P002",
      liability => "3.85679939366609",
      possession => {}
    }, 'Main::_Player' ),
    P003 => bless( {
      asset => "257.042434291185",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C004 => "5.4924538187978",
        C005 => "3.7922044423962"
      },
      current_income_luxury => {},
      desire => {
        C002 => "6.81648344618042"
      },
      greed => {
        C004 => "5.54745907697928",
        C005 => "4.20004644522383"
      },
      id => "P003",
      liability => "3.30105390426006",
      possession => {
        C004 => {
          quota => 3,
          term => "6.25529138245987"
        },
        C005 => {
          quota => 3,
          term => "15.3199029030476"
        }
      }
    }, 'Main::_Player' ),
    P004 => bless( {
      asset => "201.865083277347",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C003 => "4.30946091281162"
      },
      current_income_luxury => {
        C002 => "21.8707742235897"
      },
      desire => {
        C002 => "2.90340762051466"
      },
      greed => {
        C003 => "4.51066952551896"
      },
      id => "P004",
      liability => "88.4260684697607",
      possession => {
        C003 => {
          quota => 1,
          term => "7.42209534715529"
        }
      }
    }, 'Main::_Player' ),
    P005 => bless( {
      asset => "135.33376898518",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C003 => "2.43185347596573",
        C005 => "4.04614116951901"
      },
      current_income_luxury => {},
      desire => {
        C002 => "21.8707742235897"
      },
      greed => {
        C003 => 0,
        C005 => 0
      },
      id => "P005",
      liability => "-144.520507641915",
      possession => {
        C003 => {
          quota => 2,
          term => "7.35749096965106"
        }
      }
    }, 'Main::_Player' )
  },
  previous_gross_essential_consumption => "18.4612245946956",
  tactics => [
    [
      "T001",
      bless( {
        id => "T001",
        type => "dumper"
      }, 'Main::_DumperTactics' )
    ]
  ],
  tactics_data => {},
  term => 100,
  term_rest => 1
}, 'Main::_Market' )



次は「二つの基本戦術」をありにしてみよう。

$ perl simple_market_0.pl -d0 --srand=0 --term=100 --player=5 --luxury=2 --essential=3 --tactics-desire-greed-convert --tactics-dumper > simple_market_0_with_convert.log
TERM001:
TERM002:
  :
  :
TERM100:


このときの最終期は次のようになっている。ただし、「取引」はほとんど起こらなかったようだ。

TERM100:
$market = bless( {
  current_essential => {
    C003 => {
      P001 => "1.38585848705482",
      P004 => "1.35418264860133",
      P005 => "0.764173024821585"
    },
    C004 => {
      P001 => "1.39482895434153",
      P003 => "1.22323239642829"
    },
    C005 => {
      P001 => "1.11098402290041",
      P003 => "1.33341620305035",
      P005 => "1.42270552055381"
    }
  },
  current_gross_essential_consumption => "10.9979581450734",
  current_luxury => {
    C002 => {
      P004 => "7.34410057579468"
    }
  },
  essential => {
    C003 => bless( {
      id => "C003",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' ),
    C004 => bless( {
      id => "C004",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' ),
    C005 => bless( {
      id => "C005",
      need => "3.5",
      type => "essential"
    }, 'Main::_EssentialCommodity' )
  },
  luxury => {
    C001 => bless( {
      difficulty => "0.8",
      id => "C001",
      simplicity => "0.7",
      type => "luxury"
    }, 'Main::_LuxuryCommodity' ),
    C002 => bless( {
      difficulty => "0.8",
      id => "C002",
      simplicity => "0.7",
      type => "luxury"
    }, 'Main::_LuxuryCommodity' )
  },
  player => {
    P001 => bless( {
      asset => "292.526322259257",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {
        C002 => "21.8707742235897"
      },
      current_income_essential => {
        C003 => "4.41026399711994",
        C004 => "6.26294205353971",
        C005 => "3.15961253315821"
      },
      current_income_luxury => {},
      desire => {
        C002 => "29.3189043379945"
      },
      greed => {
        C003 => "3.6528380880111",
        C004 => "3.5628484740355",
        C005 => "7.25595615938614"
      },
      id => "P001",
      liability => "98.9365858742281",
      possession => {
        C003 => {
          quota => 1,
          term => "7.27451057789084"
        },
        C004 => {
          quota => 1,
          term => "9.24261590725239"
        },
        C005 => {
          quota => 1,
          term => "10.712607419061"
        }
      }
    }, 'Main::_Player' ),
    P002 => bless( {
      asset => "185.207825577778",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {},
      current_income_luxury => {},
      desire => {
        C002 => "-18.1103647838689"
      },
      greed => {},
      id => "P002",
      liability => "3.85679939366609",
      possession => {}
    }, 'Main::_Player' ),
    P003 => bless( {
      asset => "257.042434291185",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C004 => "5.4924538187978",
        C005 => "3.7922044423962"
      },
      current_income_luxury => {},
      desire => {
        C002 => "6.81648344618042"
      },
      greed => {
        C004 => "5.54745907697928",
        C005 => "4.20004644522383"
      },
      id => "P003",
      liability => "3.30105390426006",
      possession => {
        C004 => {
          quota => 3,
          term => "6.25529138245987"
        },
        C005 => {
          quota => 3,
          term => "15.3199029030476"
        }
      }
    }, 'Main::_Player' ),
    P004 => bless( {
      asset => "201.865083277347",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C003 => "4.30946091281162"
      },
      current_income_luxury => {
        C002 => "21.8707742235897"
      },
      desire => {
        C002 => "2.90340762051466"
      },
      greed => {
        C003 => "4.51066952551896"
      },
      id => "P004",
      liability => "88.4260684697607",
      possession => {
        C003 => {
          quota => 1,
          term => "7.42209534715529"
        }
      }
    }, 'Main::_Player' ),
    P005 => bless( {
      asset => "135.33376898518",
      current_consumption_essential => {
        C003 => "2.23031567717946",
        C004 => "2.3510791744675",
        C005 => "2.19959162901469"
      },
      current_consumption_luxury => {},
      current_income_essential => {
        C003 => "2.43185347596573",
        C005 => "4.04614116951901"
      },
      current_income_luxury => {},
      desire => {
        C002 => "21.8707742235897"
      },
      greed => {
        C003 => 0,
        C005 => 0
      },
      id => "P005",
      liability => "-144.520507641915",
      possession => {
        C003 => {
          quota => 2,
          term => "7.35749096965106"
        }
      }
    }, 'Main::_Player' )
  },
  previous_gross_essential_consumption => "18.4612245946956",
  tactics => [
    [
      "T001",
      bless( {
        essential_convert_unit => "0.1",
        id => "T001",
        type => "desire_greed_convert"
      }, 'Main::_DesireGreedConvertTactics' )
    ],
    [
      "T002",
      bless( {
        id => "T002",
        type => "dumper"
      }, 'Main::_DumperTactics' )
    ]
  ],
  tactics_data => {
    T001 => {
      name => "desire_greed_convert",
      owe => {}
    }
  },
  term => 100,
  term_rest => 1
}, 'Main::_Market' )


実は、これを公開するときにも出力を読んではじめてバグを見つけて修正したりした。以上が意図通り動いているか自信がないが、とりあえずこのシミュレーションでは asset はどんどん膨らむが、liability の総量は変化しない。以前のバージョンでは liability も膨らんでいたが、必需品の買い手の価格の計算でおかしなところを直したことで、恥ずかしながら、やっと、このモデルでは liability の総量が変化しないことに気づいた。


課題


そもそもの動機はペニーオークションが無尽講ではないかという疑問に対し、何らかのモデルを作って確かめるべきだと考えたところにある。ミクロな取引の「外側」というのを、簡単でいいかから何か表現する手段が欲しかった。昔も経済モデルを作ろうとしては何度も頓挫していたが、久しぶりにそもそも今の私ならどう経済モデルを作るだろうという関心をもって、作ってみたのが本稿のモデルである。

今回は動くところまでは持ってきたが、昔、何度も頓挫しただけあって、これ以上ないくらい簡単にしたつもりのわりには、解析にまで手を回すのは、かなり難しそうな印象がある。正直、まだ、ほとんど解析できておらず、上のプログラムが「意図」したとおり動いているかどうかも確かめられていない。

ただ、いつものごとくここで「頓挫」としておいて次を期すほどの「野心」のようなものはすでに私にはないと言ってよく、中途半端であることは重々承知しつつも、まずは公開するのを急いだ。

よって、課題だらけと言っていいが、ちょっとした解析とそれに基づくブラッシュアップはすぐにでもしたい。そして最初の目標であったペニーオークションのモデル化については、ゆっくり考えていくつもりである。


参考文献


経済学は大学の教養課程と独学でちょっとかじっただけと言え、最近は経済プロパーなブログをチェックしているわけではない。特に参考文献とした経済学の文献がないのは申し訳ないかぎりである。

simple_market_0.tar.gz。Perl 実装のソースと実行ログをアーカイブしたもの。(「tar xvzf ファイル名」や、他のアーカイバソフトでも展開可能。tgz 形式と書かれているやつかもしれない。)

歴史は「べき乗則」で動く』(マーク・ブキャナン 著, 水谷 淳 訳, ハヤカワ文庫)。内作用と外作用の臨界が一致するモデルというのは、この本の第9章にある。

経済がわからない - 悪魔の妄想》。最近、私の別の記事から見つけた関心領域の重なりを感じる関連記事。

古風な経済学の講義から脱出するために - hiroyukikojimaの日記》。数学書も書いてる経済学者の記事。経済プロパーでないため、どこにトラックバックすれば良いかも私はわからないのだが、ガロア理論の本を読んだことがあるよしみで、関連研究者としてリンクした。たまたまオークションに関する本に関して書いてあった最近の記事にリンクしている。

「日銀カード(仮称)」構想》。ずっと以前に私が書いた経済に関する考察。金利と経済の関わりなども書いている。国家、特に税に力点を置いたのは、消費税還付論を援護するためでもあった。

集合論雑記 - かがみのホームページ》。数理論理学では、集合論の強制法など、「外側」を作って、そこから「内側」のモデルを作っていくことがある。そういったところからもインスピレーションは得ている。

参考文献:確率論》。私には、確率モデルに関しては、論理学との「アマルガム」を作りたいという思いもあって、本稿は《コンピュータ定理証明における弁証法 − 私が作りたいシステム》とはまた違う方向から、そこにアプローチしていると言えるかもしれない。宗教哲学的側面からは《シミュレーション・アーギュメントを論駁する》という記事も書いている。

Perl でオブジェクト指向 C++風》。今回、Perl で実装するに際し、かねてからの懸案だった問題をやっと解決した。これが、コーディングスピードの上昇をもたらし、ひいてはすばやい公開につながったのだと思う。

ミクロ経済学の我流シミュレーション》。micro_economy_*.py。最適化を大胆に用いた商品市場モデル。(2019年5月31日追記。)

資産市場の簡易シミュレーション》。simple_market_a1_*.py。この記事に対する更新のようなもの。が、多くのアイデアが失われているのも事実。 (2019年5月31日追記。)
更新: 2011-01-08,2011-02-02,2011-03-15,2012-12-25
初公開: 2011年01月09日 00:18:55
最新版: 2019年05月31日 20:02:17

2011-01-09 00:18:52 (JST) in 経済学 | | コメント (6) | トラックバック (4)

批評や挨拶のためのネットコミュニティ

  • はてなブックマーク(って何?) このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク
  • Twitter (って何?)

トラックバック


トラックバックのポリシー

他サイトなどからこの記事に自薦された関連記事(トラックバック)の一覧です。
» JRF の私見:税・経済・法:外作用的簡易経済シミュレーションのアイデアと Perl による実装 (この記事)

» 時間泥棒の夕べ from JRF の私見:雑記

「量子」という考え方を御存知あろう。その特徴として、複数の排他的状態が「可能性」として現実に並存し、観測によってその状態が確定する解釈が有名である。喩[たと]えれば、先に書いた七芒星の埋め込みの記事で、平面への展開図が発散する方向は確定していないが、空間への埋め込みにおいては、グラフの作画者はスピンの巻き方を左(InLeft)か右(InRight)に決定せざるをえないようなものだ。 この図のグラフ... 続きを読む

受信: 2011-01-20 20:01:24 (JST)

2011年3月1日に、匿名で(ポイント授受としては)高額のはてなポイントを受け取りました。(どなたか存じませんが、ありがとうございます。)それまでにいただいたポイントの累計額は、分配するには少なかったので、「送られたポイントは別枠で一切使わないようにする」という方針をとってきましたが、高額のポイントを受け取った以上、これを役立てる必要があると考え、それを分配することにしました。 分配方法を決めるに... 続きを読む

受信: 2011-03-03 02:23:16 (JST)

概要 このゲームは、タロットカードを使ったソリティアの一種ということになるだろう。 タロットカードの大アルカナ 22 枚(-2枚)をシャッフルして6 枚を引き、それを並べて盤面とし、プレイヤーのトークンを置く。シャッフルした小アルカナ 56 枚( 大アルカナ一枚)を一枚づつ引いてそれ従ってトークンを移動させる。ゲーム終了時のトークンの位置で勝敗が決まるゲーム。 易とタロットカードの意味を参考にして... 続きを読む

受信: 2011-11-09 07:06:55 (JST)

» ミクロ経済学の我流シミュレーション from JRF の私見:税・経済・法

ミクロ経済学に基づき、経済シミュレーションまたはゲームを作った。モデル自体は簡単なものなのだが、「動く」までにするのが一苦労であった。コンピュータでシミュレーションができるようになるまでには、いろいろ決め難いことを決めねばならない。あいまいにしたいことがあれば、どうやってあいまいにするのか、乱数を使うならどのような乱数を使うのかを決めなければならない。企業が赤字の場合どうするか、パラメータが 0 ... 続きを読む

受信: 2018-03-19 17:28:50 (JST)

コメント

更新:リンクをいくつか足した。本文は何もかえてない。…関心は似ていても抱いている思いは違う。しかし、コンピュータの時代に数学を修めたあと、彼らは働き、遊んでいるのは私だ。ただ、いいたいこともわからないではないから、似たところに辿り着いたのは「小人さん」達のせいばかりではないだろう…とかチラと思う。まぁ、ただの妄想。

投稿: JRF | 2011-01-09 19:25:09 (JST)

更新:バージョンを1.01 にした。DesireGreedConvertTactics が「greed の低い者」に廃棄という条件を使ってなかったので、そこを修正、他ちょこちょこといじっている。これにより、上の出力結果の数値が変わるが、まだ変更は反映していない。上の tar.gz を新しいバージョンのものに差しかえているが、変更前のアーカイブは simple_market_0-20110109.tar.gz で、今回のアーカイブは simple_market_0-20110111.tar.gz でもダウンロードできる。

投稿: JRF | 2011-01-11 16:10:43 (JST)

更新:「greed の低い者」に廃棄させるというのが、そうなってなかったことを発見し、fix。急遽、バージョンを 1.02 にする。今回のアーカイブは simple_market_0-20110111_2.tar.gz。ついでなので出力結果も記事に反映しておいた。このバージョンアップの間、誰もこの記事を読んだ形跡がないのがトホホな感じ。orz しばらくはこんな感じで不安定な状態が続きそう。orz

投稿: JRF | 2011-01-11 19:55:07 (JST)

更新:少し解析をしていて、その成果を反映し「ブラッシュアップ」した。…といっても、powered_normal_rand まわりの解析をしただけだが。

ここまでで、greed に関してはこれ以上の解析は私には困難であることがわかった。ソートの分布が多項式になる…というところまではできるが、その先に冪乗根の和の条件を付して重積分を行う必要がありそうで、そこで私はお手上げである。

一方、desire に関しては基礎的なところ以外はどこから手を付けるべきかもわかりにくい。また、アイデアとしてbalance_mail_redirect のアルゴリズムを嗜好品の生産か需要かどちらかに使うのがおもしろそうだなどという考えが浮かんでいる。

解析というよりは統計的手法を用いた「分析」が必要だろうと考えている。このシミュレーションの特殊な状態として、必需品は必ずすべて「廃棄」させ、嗜好品は必ずすべて 0 まで価格低下させると、ほとんどシステムが動かない「ゲームオーバー」の状態になる。ここから逆に廃棄や価格低下を一部やめることで「変分」を見るような分析ができるだろう。この変分と、同じ頻度なのに、より効果的な「内作用」を見つけるといったことが、おもしろい結果となるかもしれない。……などと夢想している。

ただ、そういう「計画」はあるものの、ちょっと手詰まり感があり、少し間を置いて、ほかのことに時間を使いたいと思っている。しばらく、本格的なプログラムの更新がないだろうということで、これまでのところの「スナップショット」を公開しておこう…というのが今回の記事の更新の動機である。

今回は、バージョン 1.03 でアーカイブは simple_market_0-20110202.tar.gz。オプション周りでは、srand をオプションとして指定するようになったところが注意すべき変更である。

投稿: JRF | 2011-02-02 17:38:13 (JST)

更新:メインのところに変更はないが、DesireGreedConvertTactics を、自分が生産者のときは自分より低い greed の者に廃棄させ、自分が非生産者のときは、need よりも生産が少ないかギリギリのとき、greed の高い生産者から廃棄させるようにした。当然、自己への owe が解消されなくなったが…。また、owe の解消は、必ず 10% ではなく 0.1 ずつの累積を認め、100% 廃棄にも対応した。

ただ、上の更新自体は前回の更新のあとすぐに行っており、今回、バージョンアップという形を取ったのは、ポイントがらみのモデルを造っていて、simple_market との絡みも少し考えようかと思っていたが、大震災のため、そうする精神的余祐がないと認めてしまいたかったというのが一つ。また、同じく大震災前に考えていたモデルがらみのことを吐き出してしまっておきたかったというのが一つ。

で、考えていたことだが、一つは、「資産減耗遷移(または資産減耗埋め込み)」…上の記事では資産減耗を定率で行うことなどを考えていたが、そうではなく、「定常状態」にあるときなどに、埋め込まれたシステムに遷移することで、catastrophic に資産減耗を実現するということを考えていた。埋め込まれた先では、埋め込まれる元の経済が埋め込まれているかもしれない。また、複数ある「子」経済のうちの一つに遷移するかもしれない。

また、一つは、アバウトミーに書いたことだが、すなわち、「実数」で乱数を作るとき、値の重なりは普通無視して良いが、「意志」により、ある乱数の値まで「価格低下」することを認めるなら、値が重なる者の「評価の順序」がシステムに与える影響を無視できないということ。これに対していずれ解決策を出す必要がある。それに付随して、「公共財遷移」…文化的 possession などを公共財として説明したくなることへの牽制として、possesion や asset に「ふさわしくない」生産があると、それを公共財からの付与として負担を要求する戦術を考えていた。

さらに、一つは、liability の総量が変わらない「不自然さ」に気づき、乱数の「平等」を気にするなら、逆に、「平等」をわざと崩して特定のものにマイナスの liability を集中する「中央銀行モデル」…「最強」のプレイヤーが存在し、その者の liability がどんどん減っていく tactics があればいいのではないかと考えていた。その「強さ」がどれぐらい弱くても「中央銀行」として成り立つかに興味がある。

こういったちょっと誇大妄想的なアイデアは、実現の難しさには差がある(「中央銀行モデル」は簡単かな?)が、かなりモデルの様相を変えるものであるので、実装する気になかなかなれなかった。それが大震災で、もうそちらには私は手が出せないような気がしてきたので、アイデアだけ公開しておいた。

今回は、バージョン 1.04 でアーカイブは simple_market_0-20110315.tar.gz

投稿: JRF | 2011-03-15 20:46:38 (JST)

更新:simple_market_0-20121225.tar.gz。バージョン 1.05。

必需品の random_produce のミスを修正。上の記事のソース部分を読んでて間違いに気付いた。記事の該当部分と計算結果を更新した。

投稿: JRF | 2012-12-25 19:57:09 (JST)

コメントを書く



(メールアドレス形式)


※匿名投稿を許可しています。ゆるめのコメント管理のポリシーを持っています。この記事にまったく関係のないコメントはこのリンク先で受け付けています。
※暗号化パスワードを設定すれば、後に「削除」、すなわち JavaScript で非表示に設定できます。暗号解読者を気にしないならメールアドレスでもかまいません。この設定は平文のメールで管理者に届きます。
※コメントを書くために漢字[かんじ]でルビが、[google: キーワード] で検索指定が使えます。


ランダムことわざ: 七転び八起き。