実装とは必ずしも異るが、アイデアとしての外作用モデルを、その要素ごとに提示していく。
ある市場に売り手と買い手が情報を出す。売り手の価格を超える 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 は外作用のステップの半ばで呼ばれることになる。
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 での実装は、とりあえず、シミュレーションが動作するところまでしかできておらず、入出力もコマンドラインを通じてするものしかない。
もちろん、細かい実装については説明しきれないが、まず、注意すべき点から。
シミュレーションで同じ結果を得るために、生成される乱数を固定するときは、オプションに --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 の総量が変化しないことに気づいた。
そもそもの動機は
ペニーオークションが無尽講ではないかという疑問に対し、何らかのモデルを作って確かめるべきだと考えたところにある。ミクロな取引の「外側」というのを、簡単でいいかから何か表現する手段が欲しかった。昔も経済モデルを作ろうとしては何度も頓挫していたが、久しぶりにそもそも今の私ならどう経済モデルを作るだろうという関心をもって、作ってみたのが本稿のモデルである。
今回は動くところまでは持ってきたが、昔、何度も頓挫しただけあって、これ以上ないくらい簡単にしたつもりのわりには、解析にまで手を回すのは、かなり難しそうな印象がある。正直、まだ、ほとんど解析できておらず、上のプログラムが「意図」したとおり動いているかどうかも確かめられていない。
ただ、いつものごとくここで「頓挫」としておいて次を期すほどの「野心」のようなものはすでに私にはないと言ってよく、中途半端であることは重々承知しつつも、まずは公開するのを急いだ。
よって、課題だらけと言っていいが、ちょっとした解析とそれに基づくブラッシュアップはすぐにでもしたい。そして最初の目標であったペニーオークションのモデル化については、ゆっくり考えていくつもりである。
経済学は大学の教養課程と独学でちょっとかじっただけと言え、最近は経済プロパーなブログをチェックしているわけではない。特に参考文献とした経済学の文献がないのは申し訳ないかぎりである。
|
● |
|
● |
『 歴史は「べき乗則」で動く』(マーク・ブキャナン 著, 水谷 淳 訳, ハヤカワ文庫)。内作用と外作用の臨界が一致するモデルというのは、この本の第9章にある。
|
● |
|
● |
|
● |
《 「日銀カード(仮称)」構想》。ずっと以前に私が書いた経済に関する考察。金利と経済の関わりなども書いている。国家、特に税に力点を置いたのは、消費税還付論を援護するためでもあった。
|
● |
《 集合論雑記 - かがみのホームページ》。数理論理学では、集合論の強制法など、「外側」を作って、そこから「内側」のモデルを作っていくことがある。そういったところからもインスピレーションは得ている。
|
● |
|
● |
《 Perl でオブジェクト指向 C++風》。今回、Perl で実装するに際し、かねてからの懸案だった問題をやっと解決した。これが、コーディングスピードの上昇をもたらし、ひいてはすばやい公開につながったのだと思う。
|
● |
|
● |
《 資産市場の簡易シミュレーション》。simple_market_a1_*.py。この記事に対する更新のようなもの。が、多くのアイデアが失われているのも事実。 (2019年5月31日追記。)
|
|
コメント
更新:リンクをいくつか足した。本文は何もかえてない。…関心は似ていても抱いている思いは違う。しかし、コンピュータの時代に数学を修めたあと、彼らは働き、遊んでいるのは私だ。ただ、いいたいこともわからないではないから、似たところに辿り着いたのは「小人さん」達のせいばかりではないだろう…とかチラと思う。まぁ、ただの妄想。
投稿: 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)