2012年10月12日金曜日

情報の誤伝達5

今回は次のための準備みたいなものです。

伝えたい情報は{0 0 0 0 0 0 0 ..... 0}とします。
そして、今まではどれだけズレても±1か0かどう動くかは等確率1/3でした。

今回は、確率が「復元力」を持つと仮定しましょう。

この仮定は、
「ズレが大きくなく情報にある程度の常識があり、そこから伝達を類推できる。」
という状況を以ていい近似になりうります。

そして、復元力、確率は各々の情報要素で独立に振る舞うとします。
(次に話したいものはこの復元力によって隣の情報要素と相互作用させようというもの)

その復元力をどうするかですが、単純にズレの距離に比例にしてしまうと、
負の確率がでてきてしまうので、少し改変します。
おいおい話しますが、流れを切らないために、式を先に示します。







ここで、dはどういう値かというと、いわゆる「バネの伸びの限界」で、
「xがdになると、P(-1)とP(1)の比がほぼ10倍になる」としています。
つまりdが大きければ大きいほど、復元力は弱いということになります。

参考までに、d=1でのプロットを乗せておきます。青がP(-1),赤がP(+1)です。











これを用いて、Javaでシミュレーションしてみたいと思います。

この前のやつのr部分だけいじりたいと思います。



import java.util.*;

class InfoDest2 {

static double pneg (int x,double d){
return Math.exp(x/d)/3/Math.cosh(x/d);
}

static double ppos (int x,double d){
return Math.exp(-x/d)/3/Math.cosh(x/d);
}

public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int data = sc.nextInt();
int k = sc.nextInt(); //情報数(配列の長さ)
int n = sc.nextInt(); //試行回数
double d = sc.nextDouble(); //バネ限界伸び
while(data>0){ calc(k,n,d); data--;}
}

static void calc(int k,int n,double d) {
int[] a = new int[10];
//最初の値は全部0なのでこのままでいきます。

for(int i=0; i<n; i++){
for(int j=0; j<k; j++){
double rd = Math.random();
int r;
if(rd<=pneg(a[j],d)) r=-1;
else if(rd>=ppos(a[j],d)) r=1;
else r=0;
a[j] = a[j] + r;
}
}

double avr=0; double var=0;
for(int i=0; i<k; i++){
System.out.print(a[i]+", ");
avr += Math.abs(a[i]);
var += a[i]*a[i];
}
System.out.printf("誤り距離平均: %.2f, 誤り分散: %.2f %n",avr/k,Math.sqrt(var));
}


}


ことさら変わったところもないので、ちっちゃくしときます。
入力にバネ限界伸びが追加されました。

5 5 100 1 で出力してみる。

2, 1, 3, 2, 2, 誤り距離平均: 2.00, 誤り分散: 4.69 
3, 3, 2, 0, 0, 誤り距離平均: 1.60, 誤り分散: 4.69 
-1, 3, -1, 0, 0, 誤り距離平均: 1.00, 誤り分散: 3.32 
0, 0, 2, -1, 1, 誤り距離平均: 0.80, 誤り分散: 2.45 
2, 6, 3, 1, 0, 誤り距離平均: 2.40, 誤り分散: 7.07 


ちなみに、復元力なしの場合(5 5 100)

10, 2, 0, 2, 7, 誤り距離平均: 4.20, 誤り分散: 12.53 
-5, -6, -16, 20, 6, 誤り距離平均: 10.60, 誤り分散: 27.44 
0, -5, -13, 8, 1, 誤り距離平均: 5.40, 誤り分散: 16.09 
2, 11, 15, 2, 12, 誤り距離平均: 8.40, 誤り分散: 22.32 
2, -8, -13, -1, 1, 誤り距離平均: 5.00, 誤り分散: 15.46 
となり、明らかに情報が上手く伝わっていますね。

5 5 1000 1としてみると効果が歴然で、
1, 1, 0, -1, -2, 誤り距離平均: 1.00, 誤り分散: 2.65 
-2, 3, 3, 1, -2, 誤り距離平均: 2.20, 誤り分散: 5.20 
0, 1, -2, 0, 2, 誤り距離平均: 1.00, 誤り分散: 3.00 
0, 0, 0, 0, 2, 誤り距離平均: 0.40, 誤り分散: 2.00 
0, 3, 2, 8, 0, 誤り距離平均: 2.60, 誤り分散: 8.77 
4つ目にいたってはほぼ正確に伝わってます。

-------------------------------------------

気になることとしては、バネ限界伸びにどのように依存するか、ですね。
そこで、1 10 100 d として、dを1~10まで出力してみます。









たしかにdが大きくなるほど、誤り距離平均は大きくなっています。

---------------------------------------------

最後に書き残していたP(-1)とP(+1)の求め方について説明しておきます。

まず、非負をとる関数で扱いが容易であるものとして
exp(kx)とexp(-kx)を考えます。
もちろん、
P(-1) ∝ exp(kx)
P(+1) ∝ exp(-kx)
となるだろうと思うわけですが、今回は確率を考えたいので、この両者の割合、







とします。ここでλは定数です。

λを決める。確率は1なのだから、
P(0) + P(+1) + P(-1) = 1
P(+1) + P(-1) = 2/3
で、計算すると、λ = 2/3となります。(まあそりゃそうだ)

最後に、ハイパボリックコサインの定義式:





を代入すれば、上の式に近い値が得られます。
最終的にkをバネ限界伸びdで表すのですが、これは簡単で、
P(+1)/P(-1) = exp(-2) ~ 0.1 として計算すればよいです。
なぜexp(-2)にするかですが、これは式が綺麗になるから以外に理由はないかな…。
ですがまあ大体10倍比であれば、ほぼそれ以上伸びないと思っていいだろう。

「指数関数でいいのか」と思うかもしれないですが、
dを大きくすれば、非常になめらかになるので、
一次関数の近似として十分扱えるんじゃないでしょうか。

0 件のコメント:

コメントを投稿