遺伝的アルゴリズム(関数の最大値)

<?php

/********************************************************************/
/* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */
/*      coded by Y.Suganuma                                         */
/********************************************************************/

/***********************/
/* クラスSpeciesの定義 */
/***********************/

class Species {

	protected $max;   // 最大適応度
	protected $mean;   // 平均適応度
	protected $pi;   // 適応度
	protected $ro;   // ルーレット板
	protected $allele_u;   // 対立遺伝子上限
	protected $allele_l;   // 対立遺伝子下限
	protected $size;   // 個体総数
	protected $max_ch;   // 子供の数の最大値
	protected $max_len;   // 最大遺伝子長
	protected $min_len;   // 最小遺伝子長(負の時は,最大遺伝子長で固定)
	protected $max_n;   // 最大適応度の個体番号
	protected $dup_a;   // 遺伝子の重複
                        //   =0 : 重複を許さない
                        //   =1 : 重複を許す
	protected $dup_s;   // 個体の重複(同じ染色体の個体)
                        //   =0 : 重複を許さない
                        //   =1 : 重複を許す
	protected $ind;   // 集団(個体の集まり)
	protected $len;   // 各個体の遺伝子長
	protected $kou1;   // 交叉・突然変異用作業場所1
	protected $kou2;   // 交叉・突然変異用作業場所2
	protected $s_w;   // 淘汰用指標(選択された回数)
	protected $edge;   // エッジ組み替え交叉用ワークエリア
	protected $pi_w;   // 適応度計算指標
                       //   =0 : 未使用
                       //   =1 : 適応度計算前(突然変異はこの個体だけに適用)
                       //   =2 : 適応度計算済み(交叉時に親とみなす)

	/****************************/
	/* コンストラクタ           */
	/*      name : ファイル名   */
	/*      seed : 乱数の初期値 */
	/****************************/
	function Species($name, $seed)
	{
	/*
	     データの入力
	*/
		$in = fopen($name, "rb");
	
		fscanf($in, "%*s %d %*s %d", $this->allele_u, $this->allele_l);
		fscanf($in, "%*s %d %*s %d", $this->max_len, $this->min_len);
    	fscanf($in, "%*s %d %*s %d", $this->dup_a, $this->dup_s);
    	fscanf($in, "%*s %d %*s %d", $this->size, $this->max_ch);
	/*
         データのチェック
    */
		if ($this->size <= 0)
			exit("***error  個体総数≦0 (Constructor)\n");
	
		if ($this->max_ch < 0)
			exit("***error  子供の数<0 (Constructor)\n");
    
		if ($this->max_len <= 0 || $this->min_len == 0)
			exit("***error  遺伝子長≦0 (Constructor)\n");
	
		if ($this->max_len < $this->min_len)
			exit("***error  最大遺伝子長<最小遺伝子長 (Constructor)\n");
	
		if ($this->allele_u <= $this->allele_l)
			exit("***error  対立遺伝子上限≦対立遺伝子下限 (Constructor)\n");
    
    	$kind = $this->allele_u - $this->allele_l + 1;
		if ($this->dup_a == 0 && $this->max_len > $kind)
    		exit("***error  遺伝子の重複を防ぐことはできない (Constructor)\n");
	/*
	     領域の確保
	*/
		$num = $this->size + $this->max_ch;
	
		$this->ind = array($num);
    	for ($i1 = 0; $i1 < $num; $i1++)
    		$this->ind[$i1] = array($this->max_len);
    
		$this->edge = array($this->max_len);
		for ($i1 = 0; $i1 < $this->max_len; $i1++)
			$this->edge[$i1] = array(5);
	
		$this->pi   = array($num);
		$this->ro   = array($num);
		$this->len  = array($num);
		$this->kou1 = array($this->max_len);
		$this->kou2 = array($this->max_len);
		$this->s_w  = array($num);
		$this->pi_w = array($num);
	/*
	     乱数の初期設定
	*/
    	mt_srand($seed);
    }
	
    /**************************************************/
    /* 場所を探す                                     */
	/*      n : >=0 : n番目の親を捜す                 */
	/*          -1 : 空いている場所を探す             */
	/*      return : 親の場所,または,空いている場所 */
	/*               (存在しないときは負の値)       */
	/**************************************************/
	function Position($n)
	{
    	$k  = -1;
    	$sw = 0;
    /*
	     空いている場所を探す
	*/
		if ($n < 0) {
			for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < 0; $i1++) {
				if ($this->pi_w[$i1] == 0)
					$k = $i1;
			}
			if ($k < 0)
				exit("***error  空いている場所がない --Position--\n");
		}
	/*
	     n番目の親($this->pi_w[i]=2)を捜す
    */
    	else {
			for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) {
    			if ($this->pi_w[$i1] == 2) {
    				$k++;
					if ($k == $n) {
						$sw = 1;
						$k  = $i1;
					}
				}
			}
		}
    
    	return $k;
    }
	
	/*******************************************************************/
	/* 個体の選択                                                      */
	/*      method : 選択方法                                          */
	/*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      bias : α,または,method=2の場合は初期値(default=0)       */
	/*      step : β(default=1)                                       */
	/*      return : 個体番号                                          */
	/*******************************************************************/
	function Select($method = -1, $bias = 0.0, $step = 1.0)
	{
    	$sum = 0.0;
    					// ルーレット板の用意
		switch ($method) {
    						// ランダム
    		case -1:
				$n = 0;
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1)
						$n++;
				}
				$sum = 1.0 / $n;
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    				if ($this->pi_w[$i1] > 1)
    					$this->ro[$i1] = $sum;
    			}
				break;
							// 評価値をそのまま利用
			case 0:
				$n = 0;
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1) {
						$sum += $this->pi[$i1];
						$n++;
					}
				}
				if (abs($sum) > 1.0e-10) {
					$sum = 1.0 / abs($sum);
					for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
						if ($this->pi_w[$i1] > 1)
    						$this->ro[$i1] = $this->pi[$i1] * $sum;
    				}
				}
    			else {
    				$sum = 1.0 / $n;
					for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
						if ($this->pi_w[$i1] > 1)
							$this->ro[$i1] = $sum;
					}
				}
				break;
							// 最小値からの差
    		case 1:
    			$min = -1;
    			$n   = 0;
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1) {
						$n++;
						if ($min < 0 || $this->pi[$i1] < $this->pi[$min])
							$min = $i1;
					}
				}
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1) {
						$this->ro[$i1] = $this->pi[$i1] - $this->pi[$min];
						if ($this->ro[$i1] < $bias)
							$this->ro[$i1] = $bias;
						$sum += $this->ro[$i1];
					}
    			}
    			if ($sum > 1.0e-10) {
					$sum = 1.0 / $sum;
    				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    					if ($this->pi_w[$i1] > 1)
							$this->ro[$i1] *= $sum;
					}
				}
				else {
					$sum = 1.0 / $n;
					for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
						if ($this->pi_w[$i1] > 1)
    						$this->ro[$i1] = $sum;
    				}
    			}
				break;
							// 線形化
			case 2:
				$n = 0;
				for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1) {
						$this->ro[$i1] = -1.0;
						$n++;
					}
					else
						$this->ro[$i1] = 1.0;
				}
				$sw  = 0;
				$sum = $bias;
    			while ($sw == 0) {
    				$min = -1;
					for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    					if ($this->ro[$i1] < 0.0 && ($min < 0 || $this->pi[$i1] < $this->pi[$min]))
    						$min = $i1;
					}
					if ($min < 0)
						$sw = 1;
					else {
						$this->ro[$min]  = $sum;
						$sum     += $step;
					}
    			}
    			$sum = 1.0 / (0.5 * (2.0 * $bias + $step * ($n - 1)) * $n);
    			for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
					if ($this->pi_w[$i1] > 1)
						$this->ro[$i1] *= $sum;
				}
				break;
		}
	
		$sum = 0.0;
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
			if ($this->pi_w[$i1] > 1) {
				$sum           += $this->ro[$i1];
				$this->ro[$i1]  = $sum;
			}
		}
						// 選択
    	$x  = uniform();
    	$sw = 0;
		$k  = 0;
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) {
    		if ($this->pi_w[$i1] > 1) {
				if ($x <= $this->ro[$i1]) {
					$sw = 1;
					$k  = $i1;
				}
			}
		}
	
    	return $k;
    }
    
	/********************/
	/* 標準的な初期設定 */
	/********************/
	function Init_std()
	{
	/*
	     初期設定
	*/
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
			if ($i1 < $this->size)
				$this->pi_w[$i1] = 1;   // 適応度の計算前
			else
				$this->pi_w[$i1] = 0;   // 未使用
		}
    /*
         遺伝子の決定
	*/
    	for ($i1 = 0; $i1 < $this->size; $i1++) {
    
			$sw1 = 0;
	
			while ($sw1 == 0) {
						// 遺伝子長の決定
				if ($this->min_len < 0)
					$length = $this->max_len;
				else {
    				$length = intval(uniform() * ($this->max_len - $this->min_len + 1) + $this->min_len);
    				if ($length > $this->max_len)
    					$length = $this->max_len;
				}
				$this->len[$i1] = $length;
						// 遺伝子の決定
				for ($i2 = 0; $i2 < $length; $i2++) {
					$sw2 = 0;
					while ($sw2 == 0) {
						$lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l);
						if ($lid > $this->allele_u)
							$lid = $this->allele_u;
						$this->ind[$i1][$i2] = $lid;
							// 重複遺伝子のチェック
						$sw2 = 1;
						if ($this->dup_a == 0) {
							for ($i3 = 0; $i3 < $i2 && $sw2 > 0; $i3++) {
    							if ($lid == $this->ind[$i1][$i3])
    								$sw2 = 0;
							}
    					}
    				}
				}
						// 重複個体のチェック
				$sw1 = 1;
				if ($this->dup_s == 0) {
					for ($i2 = 0; $i2 < $i1 && $sw1 > 0; $i2++) {
						if ($this->len[$i1] == $this->len[$i2]) {
							$sw2 = 0;
    						for ($i3 = 0; $i3 < $this->len[$i1] && $sw2 == 0; $i3++) {
    							if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3])
    								$sw2 = 1;
							}
							if ($sw2 == 0)
								$sw1 = 0;
						}
					}
				}
			}
		}
	}
	
	/****************************************************/
	/* 標準的な出力                                     */
	/*      sw : 出力レベル                             */
	/*             =0 : 最終出力だけ                    */
    /*             n>0 : n世代毎に出力(負はファイル) */
    /*      out_m : 出力方法                            */
	/*                =0 : すべての個体を出力           */
    /*                =1 : 最大適応度の個体だけを出力   */
    /*      gen : 現在の世代番号                        */
	/*      name : 出力ファイル名                       */
	/****************************************************/
	function Out_std($sw, $out_m, $gen, $name)
	{
		$k = 0;
	
		if ($sw >= 0) {
    		printf("   出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ");
    		fscanf(STDIN, "%d", $pr);
    	}
		else
			$pr = -1;
	
		if ($pr != 0) {
						// 出力先の決定と評価値の出力
			if ($pr > 0) {
				$out = STDOUT;
				fgets(STDIN);
			}
			else {
				$x   = getdate();
				$now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒";
				$out = fopen($name, "ab");
				fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n");
    		}
						// 詳細出力
    		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    			if (($this->pi_w[$i1] > 1) && ($out_m == 0 || $out_m == 1 && $i1 == $this->max_n)) {
					$str = $i1." allele";
					for ($i2 = 0; $i2 < $this->len[$i1]; $i2++)
						$str += " ".$this->ind[$i1][$i2];
					$str += " value ".$this->pi[$i1];
					fwrite($out, $str."\n");
					if ($pr > 0) {
						$k++;
						if ($k == $pr) {
    						fgets(STDIN);
    						$k = 0;
    					}
					}
				}
			}
	
			if ($pr < 0)
				fclose($out);
		}
	}
	
	/*******************************************************************/
	/* 交叉(親のコピー)                                              */
	/*      method : =2 : 有性(2つの親から2つの子供)(default)      */
	/*               =1 : 1つの親から1つの子供                       */
	/*      pair : method=2 の時は親のペア数(default=max_ch/2)         */
    /*             method=1 の時は親の数(=子供の数)                 */
    /*      k_method : 選択方法                                        */
	/*                 =-1 : ランダム(default)                         */
    /*                 =0 : 適応度をそのまま使用                       */
    /*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_copy($method = 2, $pair = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
	/*
         初期設定とデータチェック
    */
    	if ($method != 1)
			$method = 2;
	
		if ($pair <= 0)
			$pair = ($method==2) ? intval($this->max_ch/2) : $this->max_ch;
		else {
			if ($method == 2 && 2*$pair > $this->max_ch || $method == 1 && $pair > $this->max_ch)
				exit("***error  子供が多すぎる (C_copy)\n");
		}
	/*
	     実行
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
    					// 親の選択
    		$p1 = $this->Select($k_method, $k_bias, $k_step);
			$sw = 0;
    
    		while ($sw == 0) {
				$p2 = $this->Select($k_method, $k_bias, $k_step);
				if ($p1 != $p2)
					$sw = 1;
			}
						// コピー
			for ($i2 = 0; $i2 < $method; $i2++) {
				$p       = ($i2 == 0) ? $p1 : $p2;
    			$k       = $this->Position(-1);
    			$this->len[$k]  = $this->len[$p];
    			$this->pi_w[$k] = 1;
				for ($i3 = 0; $i3 < $this->len[$k]; $i3++)
					$this->ind[$k][$i3] = $this->ind[$p][$i3];
			}
		}
	}
	
	/*******************************************************************/
	/* 交叉(多点交叉)                                                */
	/*      kosa : 交叉確率                                            */
	/*      k_point : 交叉点の数(default=1)                            */
	/*                (負の時は,1から-k_point間のランダム)          */
	/*      k_vr : =0 : 両親とも同じ位置で交叉(default)                */
	/*             =1 : 両親が異なる位置で交叉(遺伝子長は可変)       */
	/*      k_method : 選択方法                                        */
    /*                 =-1 : ランダム(default)                         */
    /*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
    /*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
    /*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_point($kosa, $k_point = 1, $k_vr = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
		$mn = 0;
	/*
	     初期設定とデータのチェック
    */
    	$pair = $this->max_ch / 2;
    
		if ($this->dup_a == 0)
			exit("***error  交叉方法が不適当 (C_point)\n");
	
		$abs_p = abs($k_point);
		if ($abs_p == 0 || $abs_p > $this->max_len-1 || $this->min_len > 0 && $abs_p > $this->min_len-1)
			exit("***error  交叉点の数が不適当 (C_point)\n");
	
		if ($k_vr > 0 && $this->min_len < 0)
			exit("***error  遺伝子長は可変でなければならない (C_point)\n");
    /*
	     交叉
    */
    	$num = $k_point;
	
		for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(2, 1);
						// 交叉する場合
			else {
    						// 親の選択
    			$p1 = $this->Select($k_method, $k_bias, $k_step);
    			$sw = 0;
				while ($sw == 0) {
					$p2 = $this->Select($k_method, $k_bias, $k_step);
					if ($p1 != $p2)
						$sw = 1;
				}
							// 交叉位置の数の決定
				if ($k_point < 0) {
					$num = intval(uniform() * $abs_p + 1);
					if ($num > $abs_p)
						$num = $abs_p;
				}
							// 交叉位置の決定(点の後ろで交叉)
				for ($i2 = 0; $i2 < $num; $i2++) {
								// 親1の交叉位置
    				$sw = 0;
    				while ($sw == 0) {
						$sw              = 1;
    					$this->kou1[$i2] = intval(uniform() * ($this->len[$p1] - 1));
    					if ($this->kou1[$i2] > $this->len[$p1]-2)
							$this->kou1[$i2] = $this->len[$p1] - 2;
						if ($k_vr == 0 && $this->kou1[$i2] > $this->len[$p2]-2)
							$this->kou1[$i2] = $this->len[$p2] - 2;
						for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) {
							if ($this->kou1[$i3] == $this->kou1[$i2])
								$sw = 0;
						}
    				}
    							// 親2の交叉位置
    				if ($k_vr > 0) {
						$sw = 0;
						while ($sw == 0) {
							$sw              = 1;
							$this->kou2[$i2] = intval(uniform() * ($this->len[$p2] - 1));
							if ($this->kou2[$i2] > $this->len[$p2]-2)
								$this->kou2[$i2] = $this->len[$p2] - 2;
							for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) {
								if ($this->kou2[$i3] == $this->kou2[$i2])
									$sw = 0;
							}
						}
					}
				}
							// 交叉の実行
    						//   親1のt11からt12を子1のc1へコピー
    						//   親2のt21からt22を子2のc2へコピー
							//     次は,
    						//   親1のt11からt12を子2のc2へコピー
    						//   親2のt21からt22を子1のc1へコピー
							//     ・・・・・
				$c1  = 0;
				$c2  = 0;
				$t11 = 0;
				$t21 = 0;
								// 遺伝子長
				$k1              = $this->Position(-1);
    			$this->pi_w[$k1] = 1;
    			$this->len[$k1]  = $this->len[$p1];
    			$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
	
				for ($i2 = 0; $i2 < $num+1; $i2++ ) {
								// 次の交叉位置を求める
					if ($i2 == $num) {            // 最後
						$t12 = $this->len[$p1];
						$t22 = $this->len[$p2];
					}
					else {
									// 親1
						$t12 = $this->max_len;
						for ($i3 = 0; $i3 < $num; $i3++) {
							if ($this->kou1[$i3] >= 0 && $this->kou1[$i3] <= $t12) {
    							$t12 = $this->kou1[$i3];
    							$mn  = $i3;
							}
    					}
    					$this->kou1[$mn] = -1;
						$t12++;
									// 親2
						if ($k_vr == 0)
							$t22 = $t12;
						else {
							$t22 = $this->max_len;
							for ($i3 = 0; $i3 < $num; $i3++) {
    							if ($this->kou2[$i3] >= 0 && $this->kou2[$i3] <= $t22) {
    								$t22 = $this->kou2[$i3];
    								$mn  = $i3;
								}
							}
							$this->kou2[$mn] = -1;
							$t22++;
						}
					}
								// 指定箇所のコピー
					for ($i3 = $t11; $i3 < $t12; $i3++) {
						if ($i2%2 == 0) {
							if ($c1 < $this->max_len) {
								$this->ind[$k1][$c1] = $this->ind[$p1][$i3];
								$c1++;
							}
						}
    					else {
    						if ($c2 < $this->max_len) {
								$this->ind[$k2][$c2] = $this->ind[$p1][$i3];
    							$c2++;
    						}
						}
					}
	
					for ($i3 = $t21; $i3 < $t22; $i3++) {
						if ($i2%2 == 0) {
							if ($c2 < $this->max_len) {
								$this->ind[$k2][$c2] = $this->ind[$p2][$i3];
    							$c2++;
    						}
    					}
						else {
							if ($c1 < $this->max_len) {
								$this->ind[$k1][$c1] = $this->ind[$p2][$i3];
								$c1++;
							}
						}
					}
								// 交叉位置の移動
					$t11 = $t12;
					$t21 = $t22;
				}
			}
		}
	}
    
    /*******************************************************************/
	/* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば,            */
    /*       親1,0であれば親2の遺伝子を子1が受け継ぐ)             */
    /*      kosa : 交叉確率                                            */
	/*      k_method : 選択方法                                        */
	/*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
    /*******************************************************************/
    function C_uniform($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
    {
	/*
	     初期設定とデータのチェック
	*/
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a == 0)
			exit("***error  交叉方法が不適当 (C_uniform)\n");
	
		if ($this->min_len > 0)
			exit("***error  遺伝子長は固定長でなければならない (C_uniform)\n");
    /*
         交叉
	*/
    	for ($i1 = 0; $i1 < $pair; $i1++) {
    					// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(2, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
    			while ($sw == 0) {
    				$p2 = $this->Select($k_method, $k_bias, $k_step);
    				if ($p1 != $p2)
						$sw = 1;
				}
							// 遺伝子長
				$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
				$this->len[$k1]  = $this->len[$p1];
				$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
							// 交叉
				for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					if (uniform() > 0.5) {
						$this->ind[$k1][$i2] = $this->ind[$p1][$i2];
						$this->ind[$k2][$i2] = $this->ind[$p2][$i2];
    				}
    				else {
						$this->ind[$k1][$i2] = $this->ind[$p2][$i2];
    					$this->ind[$k2][$i2] = $this->ind[$p1][$i2];
    				}
				}
			}
		}
	}
	
	/*******************************************************************/
	/* 交叉(平均化交叉.2つの親の平均値を受け継ぐ)                  */
    /*      kosa : 交叉確率                                            */
    /*      k_method : 選択方法                                        */
    /*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_mean($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
	/*
	     初期設定とデータのチェック
	*/
		if ($this->min_len > 0)
			exit("***error  遺伝子長は固定長でなければならない (C_mean)\n");
    /*
	     交叉
    */
    	for ($i1 = 0; $i1 < $this->max_ch; $i1++) {
						// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(1, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
    			$sw = 0;
    			while ($sw == 0) {
    				$p2 = $this->Select($k_method, $k_bias, $k_step);
					if ($p1 != $p2)
						$sw = 1;
				}
							// 遺伝子長
				$k             = $this->Position(-1);
				$this->len[$k]  = $this->len[$p1];
				$this->pi_w[$k] = 1;
							// 交叉
				for ($i2 = 0; $i2 < $this->len[$k]; $i2++)
					$this->ind[$k][$i2] = ($this->ind[$p1][$i2] + $this->ind[$p2][$i2]) / 2;
			}
		}
	}
	
    /*******************************************************************/
    /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を  */
	/*       そのまま各子供が選択する.その位置にある親2(1)の遺伝  */
    /*       子を,その遺伝子の親1(2)の場所に,子1(2)が受け継  */
    /*       ぐ(ただし,doubleの場合は,この手続きをのぞく).この手  */
	/*       続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り  */
	/*       返し,残りの遺伝子については,子1(2)は,親2(1)の  */
	/*       遺伝子をその順番通りに受け継ぐ)                          */
	/*         2 4 1 3 6 5    + + 1 + + 5    3 2 1 4 6 5               */
	/*             *       →             →                           */
	/*         3 2 5 4 1 6    + + 5 + 1 +    2 4 5 3 1 6               */
	/*      kosa : 交叉確率                                            */
    /*      k_method : 選択方法                                        */
    /*                 =-1 : ランダム(default)                         */
    /*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_cycle($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
	/*
	     初期設定とデータのチェック
	*/
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a != 0)
			exit("***error  交叉方法が不適当 (C_cycle)\n");
	
    	if ($this->min_len > 0)
    		exit("***error  遺伝子長は固定長でなければならない (C_cycle)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
    		if (uniform() > $kosa)
    			$this->C_copy(2, 1);
    					// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
				while ($sw == 0) {
					$p2 = $this->Select($k_method, $k_bias, $k_step);
					if ($p1 != $p2)
						$sw = 1;
				}
							// 初期設定
				for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					$this->kou1[$i2] = 0;
					$this->kou2[$i2] = 0;
				}
    						// 遺伝子長
    			$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
    			$this->len[$k1]  = $this->len[$p1];
    			$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
							// 交叉
				$sw = 0;
	
				while ($sw == 0) {
					$sw = 1;
    				$p  = intval(uniform() * $this->len[$p1]);
    				if ($p >= $this->len[$p1])
    					$p = $this->len[$p1] - 1;
					if ($this->kou1[$p] == 0 && $this->kou2[$p] == 0) {
						$this->kou1[$p]     = 1;
						$this->kou2[$p]     = 1;
						$this->ind[$k1][$p] = $this->ind[$p1][$p];
						$this->ind[$k2][$p] = $this->ind[$p2][$p];
						for ($i2 = 0; $i2 < $this->len[$p1] && $sw > 0; $i2++) {
							if ($this->ind[$p2][$p] == $this->ind[$p1][$i2]) {
								$this->ind[$k1][$i2] = $this->ind[$p1][$i2];
								$this->kou1[$i2]     = 1;
								$sw                  = 0;
							}
						}
						$sw = 1;
						for ($i2 = 0; $i2 < $this->len[$p2] && $sw > 0; $i2++) {
    						if ($this->ind[$p1][$p] == $this->ind[$p2][$i2]) {
    							$this->ind[$k2][$i2] = $this->ind[$p2][$i2];
								$this->kou2[$i2]     = 1;
    							$sw                  = 0;
    						}
						}
					}
				}
	
				$sw = 0;
				$i2 = 0;
				$i3 = 0;
    			while ($sw == 0) {
    				while ($sw == 0 && $i2 < $this->len[$p1]) {
    					if ($this->kou1[$i2] == 0)
							$sw = 1;
						else
							$i2++;
					}
					$sw = 0;
					while ($sw == 0 && $i3 < $this->len[$p2]) {
						if ($this->kou2[$i3] == 0)
							$sw = 1;
						else
							$i3++;
					}
					if ($i2 < $this->len[$p1] && $i3 < $this->len[$p2]) {
						$this->ind[$k1][$i2] = $this->ind[$p2][$i3];
						$this->ind[$k2][$i3] = $this->ind[$p1][$i2];
    					$sw                  = 0;
    					$i2++;
						$i3++;
    				}
    				else
						$sw = 1;
				}
			}
		}
	}
	
	/*******************************************************************/
    /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と  */
    /*       親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ  */
    /*       の2つの遺伝子の位置を交換する.この操作を,選択した点よ  */
	/*       り右にあるすべての遺伝子に対して実施する                  */
	/*         2 4 1 3 6 5    2 4 5 3 6 1                              */
	/*             *       →             → ・・・・・                     */
	/*         3 2 5 4 1 6    3 2 1 4 5 6                              */
	/*      kosa : 交叉確率                                            */
	/*      k_method : 選択方法                                        */
	/*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_part($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
    {
	/*
         初期設定とデータのチェック
    */
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a != 0)
			exit("***error  交叉方法が不適当 (C_part)\n");
	
    	if ($this->min_len > 0)
    		exit("***error  遺伝子長は固定長でなければならない (C_part)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(2, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
				while ($sw == 0) {
    				$p2 = $this->Select($k_method, $k_bias, $k_step);
    				if ($p1 != $p2)
						$sw = 1;
    			}
    						// 遺伝子長
				$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
				$this->len[$k1]  = $this->len[$p1];
				$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
							// 交叉
    			$p = intval(uniform() * $this->len[$p1]);
    			if ($p >= $this->len[$p1])
    				$p = $this->len[$p1] - 1;
	
				for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					$this->ind[$k1][$i2] = $this->ind[$p1][$i2];
					$this->ind[$k2][$i2] = $this->ind[$p2][$i2];
				}
	
				for ($i2 = $p; $i2 < $this->len[$p1]; $i2++) {
					$sw = 0;
					$lv = $this->ind[$k1][$i2];
					for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
						if ($this->ind[$k2][$i2] == $this->ind[$k1][$i3]) {
							$this->ind[$k1][$i2] = $this->ind[$k1][$i3];
							$this->ind[$k1][$i3] = $lv;
							$sw                  = 1;
    					}
    				}
					$sw = 0;
    				for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
    					if ($lv == $this->ind[$k2][$i3]) {
							$this->ind[$k2][$i3] = $this->ind[$k2][$i2];
							$this->ind[$k2][$i2] = $lv;
							$sw                  = 1;
						}
					}
				}
			}
    	}
    }
    
	/*******************************************************************/
	/* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の  */
	/*       左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1  */
	/*       の遺伝子を親2の遺伝子の出現順序に並べ替える.            */
	/*         2 4 1 3 6 5    2 4 1 3 5 6                              */
	/*             *       →                                          */
	/*         3 2 5 4 1 6    3 2 5 4 1 6                              */
	/*      kosa : 交叉確率                                            */
	/*      k_method : 選択方法                                        */
	/*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
    /*      k_step : β(default=1)                                     */
    /*******************************************************************/
	function C_seq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
    {
    /*
	     初期設定とデータのチェック
	*/
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a != 0)
			exit("***error  交叉方法が不適当 (C_seq)\n");
    
    	if ($this->min_len > 0)
			exit("***error  遺伝子長は固定長でなければならない (C_seq)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(2, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
    			$sw = 0;
    			while ($sw == 0) {
					$p2 = $this->Select($k_method, $k_bias, $k_step);
    				if ($p1 != $p2)
    					$sw = 1;
				}
							// 遺伝子長
				$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
				$this->len[$k1]  = $this->len[$p1];
				$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
    			$this->len[$k2]  = $this->len[$p2];
    						// 交叉
    			$p = intval(uniform() * ($this->len[$p1] - 1));
				if ($p >= $this->len[$p1]-1)
					$p = $this->len[$p1] - 2;
	
				for ($i2 = 0; $i2 <= $p; $i2++) {
					$this->ind[$k1][$i2] = $this->ind[$p1][$i2];
					$this->ind[$k2][$i2] = $this->ind[$p2][$i2];
				}
	
				$pp = 0;
				for ($i2 = $p+1; $i2 < $this->len[$p1]; $i2++) {
					$sw = 0;
					for ($i3 = $pp; $i3 < $this->len[$p2] && $sw == 0; $i3++) {
						for ($i4 = $p+1; $i4 < $this->len[$p1] && $sw == 0; $i4++) {
							if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4]) {
    							$sw                  = 1;
    							$pp                  = $i3 + 1;
								$this->ind[$k1][$i2] = $this->ind[$p1][$i4];
    						}
    					}
					}
				}
				$pp = 0;
				for ($i2 = $p+1; $i2 < $this->len[$p2]; $i2++) {
					$sw = 0;
					for ($i3 = $pp; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
						for ($i4 = $p+1; $i4 < $this->len[$p2] && $sw == 0; $i4++) {
    						if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4]) {
    							$sw                  = 1;
    							$pp                  = $i3 + 1;
								$this->ind[$k2][$i2] = $this->ind[$p2][$i4];
							}
						}
					}
				}
			}
		}
	}
	
	/*******************************************************************/
	/* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選  */
	/*       択された位置における遺伝子の順序に従って,他の親の遺伝子  */
	/*       を並べ替える                                              */
	/*         2 4 1 3 6 5    2 4 1 3 6 5                              */
    /*           *   *     →                                          */
    /*         3 2 5 4 1 6    4 2 5 3 1 6                              */
	/*      kosa : 交叉確率                                            */
    /*      k_method : 選択方法                                        */
    /*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_useq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
    {
    /*
         初期設定とデータのチェック
	*/
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a != 0)
			exit("***error  交叉方法が不適当 (C_useq)\n");
	
		if ($this->min_len > 0)
			exit("***error  遺伝子長は固定長でなければならない (C_useq)\n");
	/*
	     交叉
    */
    	for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
    		if (uniform() > $kosa)
    			$this->C_copy(2, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
				while ($sw == 0) {
					$p2 = $this->Select($k_method, $k_bias, $k_step);
    				if ($p1 != $p2)
    					$sw = 1;
    			}
							// 遺伝子長
				$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
				$this->len[$k1]  = $this->len[$p1];
				$k2              = $this->Position(-1);
				$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
							// 交叉
				for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					$this->ind[$k1][$i2] = $this->ind[$p1][$i2];
					$this->ind[$k2][$i2] = $this->ind[$p2][$i2];
					$this->kou1[$i2]     = (uniform() < 0.5) ? 0 : 1;
				}
	
    			$p = 0;
    			for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					if ($this->kou1[$i2] > 0) {
    					$sw = 0;
    					for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) {
							for ($i4 = 0; $i4 < $this->len[$p1] && $sw == 0; $i4++) {
								if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4] && $this->kou1[$i4] > 0) {
									$sw                  = 1;
									$p                   = $i3 + 1;
									$this->ind[$k1][$i2] = $this->ind[$p1][$i4];
								}
							}
    					}
    				}
    			}
				$p = 0;
				for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) {
					if ($this->kou1[$i2] > 0) {
						$sw = 0;
						for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
							for ($i4 = 0; $i4 < $this->len[$p2] && $sw == 0; $i4++) {
								if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4] && $this->kou1[$i4] > 0) {
									$sw                  = 1;
									$p                   = $i3 + 1;
									$this->ind[$k2][$i2] = $this->ind[$p2][$i4];
								}
							}
						}
					}
    			}
    		}
		}
    }
    
	/*******************************************************************/
	/* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選  */
	/*       択された位置における遺伝子の位置に,他の親の同じ遺伝子を  */
	/*       配置する.残りの遺伝子は,親と同じ順序に配置する.        */
	/*         2 4 1 3 6 5    + + 5 + 1 +    2 4 5 3 1 6               */
	/*             *   *   →             →                           */
	/*         3 2 5 4 1 6    + + 1 + 6 +    3 2 1 5 6 4               */
    /*      kosa : 交叉確率                                            */
    /*      k_method : 選択方法                                        */
    /*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_upos($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
	/*
	     初期設定とデータのチェック
	*/
		$pair = $this->max_ch / 2;
	
		if ($this->dup_a != 0)
    		exit("***error  交叉方法が不適当 (C_upos)\n");
    
    	if ($this->min_len > 0)
			exit("***error  遺伝子長は固定長でなければならない (C_upos)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
    					// 交叉しない場合
    		if (uniform() > $kosa)
    			$this->C_copy(2, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
				while ($sw == 0) {
					$p2 = $this->Select($k_method, $k_bias, $k_step);
					if ($p1 != $p2)
						$sw = 1;
				}
							// 遺伝子長
				$k1              = $this->Position(-1);
				$this->pi_w[$k1] = 1;
				$this->len[$k1]  = $this->len[$p1];
    			$k2              = $this->Position(-1);
    			$this->pi_w[$k2] = 1;
				$this->len[$k2]  = $this->len[$p2];
    						// 交叉
    			for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
					$this->kou1[$i2] = (uniform() < 0.5) ? 0 : 1;
					if ($this->kou1[$i2] > 0) {
						$this->ind[$k1][$i2] = $this->ind[$p2][$i2];
						$this->ind[$k2][$i2] = $this->ind[$p1][$i2];
					}
				}
	
    			$p = 0;
    			for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) {
    				$sw = 0;
					for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
						if ($this->kou1[$i3] > 0 && $this->ind[$p1][$i2] == $this->ind[$k1][$i3])
							$sw = 1;
					}
					if ($sw == 0) {
						for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) {
							if ($this->kou1[$i3] == 0) {
								$this->ind[$k1][$i3] = $this->ind[$p1][$i2];
								$p                   = $i3 + 1;
								$sw                  = 1;
							}
						}
					}
				}
    			$p = 0;
    			for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) {
					$sw = 0;
    				for ($i3 = 0; $i3 < $this->len[$p2] && $sw == 0; $i3++) {
    					if ($this->kou1[$i3] > 0 && $this->ind[$p2][$i2] == $this->ind[$k2][$i3])
							$sw = 1;
					}
					if ($sw == 0) {
						for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) {
							if ($this->kou1[$i3] == 0) {
								$this->ind[$k2][$i3] = $this->ind[$p2][$i2];
								$p                   = $i3 + 1;
    							$sw                  = 1;
    						}
    					}
					}
				}
			}
		}
	}
	
	/*******************************************************************/
	/* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は  */
	/*       0~(max_len-1)である必要がある)                          */
	/*         (0) エッジマップを作成する.エッジマップとは,2つの親  */
	/*             を見て,ノードがどこに接続されているのかを表すもの  */
	/*             であり,例えば,2つの親が,                        */
	/*                 [A B C D E F]                                   */
	/*                 [B D C A E F]                                   */
    /*             である場合は,                                      */
    /*                 A : B F C E                                     */
	/*                 B : A C D F                                     */
    /*                 C : B D A                                       */
    /*                 D : C E B                                       */
	/*                 E : D F A                                       */
	/*                 F : A E B                                       */
	/*             となる.                                            */
	/*         (1) 両親の2つの出発点の内1つで初期化する.ランダムま  */
	/*             たはステップ(4)の基準に従って選ぶ(現在のノード)   */
	/*         (2) エッジマップから,現在のノードを除く                */
	/*         (3) 現在のノードが接続先のノードを持っていたら,(4)に   */
    /*             進む.さもなければ,(5)に進む                       */
    /*         (4) 現在のノードが持っている接続先ノードの内,最も少な  */
    /*             い接続先ノードを持ったノードを選択し(同じ条件の場  */
	/*             合は,ランダム),それを現在のノードとし,(2)に進む */
	/*         (5) 未接続のノードが残っていればランダムに選択し,(2)に */
	/*             戻る.さもなければ,終了する                        */
	/*      kosa : 交叉確率                                            */
	/*      k_method : 選択方法                                        */
	/*                 =-1 : ランダム(default)                         */
	/*                 =0 : 適応度をそのまま使用                       */
	/*                 =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                 =2 : 評価値に順位をつけ,減少率βで線形化       */
	/*      k_bias : α,または,method=2の場合は初期値(default=0)     */
	/*      k_step : β(default=1)                                     */
	/*******************************************************************/
	function C_edge($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0)
	{
    	$e  = array(2);
    	$k0 = 0;
	/*
         初期設定とデータのチェック
    */
		$pair = $this->max_ch;
	
		if ($this->dup_a != 0)
			exit("***error  交叉方法が不適当 (C_edge)\n");
	
    	if ($this->min_len > 0)
    		exit("***error  遺伝子長は固定長でなければならない (C_edge)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $pair; $i1++) {
						// 交叉しない場合
			if (uniform() > $kosa)
				$this->C_copy(1, 1);
						// 交叉する場合
			else {
							// 親の選択
				$p1 = $this->Select($k_method, $k_bias, $k_step);
				$sw = 0;
				while ($sw == 0) {
    				$p2 = $this->Select($k_method, $k_bias, $k_step);
    				if ($p1 != $p2)
						$sw = 1;
    			}
    						// 遺伝子長
				$k              = $this->Position(-1);
				$this->pi_w[$k] = 1;
				$this->len[$k]  = $this->len[$p1];
							// エッジマップの初期化
				for ($i2 = 0; $i2 < $this->len[$k]; $i2++) {
					$this->edge[$i2][0] = 0;
					for ($i3 = 1; $i3 <= 4; $i3++)
    					$this->edge[$i2][$i3] = -1;
    			}
    						// 交叉
								// エッジマップの作成
				for ($i2 = 0; $i2 < $this->len[$k]; $i2++) {
	
					$sw = 0;
					for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) {
						if ($i2 == $this->ind[$p1][$i3]) {
							$sw = 1;
							if ($i3 == 0) {
								$e[0] = $this->ind[$p1][$this->len[$k]-1];
								$e[1] = $this->ind[$p1][1];
							}
							else {
								if ($i3 == $this->len[$k]-1) {
									$e[0] = $this->ind[$p1][$i3-1];
    								$e[1] = $this->ind[$p1][0];
    							}
								else {
    								$e[0] = $this->ind[$p1][$i3-1];
    								$e[1] = $this->ind[$p1][$i3+1];
								}
							}
							for ($i4 = 0; $i4 < 2; $i4++) {
								$this->edge[$i2][0]++;
								$this->edge[$i2][$this->edge[$i2][0]] = $e[$i4];
							}
						}
    				}
    
    				$sw = 0;
					for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) {
						if ($i2 == $this->ind[$p2][$i3]) {
							$sw = 1;
							if ($i3 == 0) {
								$e[0] = $this->ind[$p2][$this->len[$k]-1];
								$e[1] = $this->ind[$p2][1];
							}
							else {
								if ($i3 == $this->len[$k]-1) {
									$e[0] = $this->ind[$p2][$i3-1];
									$e[1] = $this->ind[$p2][0];
								}
								else {
									$e[0] = $this->ind[$p2][$i3-1];
    								$e[1] = $this->ind[$p2][$i3+1];
    							}
							}
    						for ($i4 = 0; $i4 < 2; $i4++) {
    							$sw = 1;
								for ($i5 = 1; $i5 <= $this->edge[$i2][0] && $sw == 1; $i5++) {
									if ($this->edge[$i2][$i5] == $e[$i4])
										$sw = 2;
								}
								if ($sw == 1) {
									$this->edge[$i2][0]++;
									$this->edge[$i2][$this->edge[$i2][0]] = $e[$i4];
    							}
    						}
    					}
					}
				}
								// 交叉の実行
									// 出発点の決定
				$k1 = $this->ind[$p1][0];
				$k2 = $this->ind[$p2][0];
				if ($this->edge[$k1][0] == $this->edge[$k2][0])
					$kk = (uniform() > 0.5) ? $k2 : $k1;
				else
					$kk = ($this->edge[$k1][0] < $this->edge[$k2][0]) ? $k1 : $k2;
				$this->ind[$k][0] = $kk;
				$p                = 1;
	
				while ($p < $this->len[$k]) {
    								// ノードの除去
    				for ($i2 = 0; $i2 < $this->len[$k]; $i2++) {
						$sw = 0;
    					if ($this->edge[$i2][0] > 0) {
    						for ($i3 = 1; $i3 <= 4 && $sw == 0; $i3++) {
								if ($this->edge[$i2][$i3] == $kk) {
									$sw                   = 1;
									$this->edge[$i2][$i3] = -1;
									$this->edge[$i2][0]--;
								}
							}
						}
    				}
    								// 次の現在ノードの選択
    				$min = 10;
					$num = 0;
					for ($i2 = 1; $i2 <= 4; $i2++) {
						if ($this->edge[$kk][$i2] >= 0) {
							$k1 = $this->edge[$kk][$i2];
							if ($this->edge[$k1][0] >= 0 && $this->edge[$k1][0] < $min) {
								$num = 1;
								$min = $this->edge[$k1][0];
								$k0  = $k1;
							}
							else {
								if ($this->edge[$k1][0] == $min)
									$num++;
							}
						}
    				}
    				if ($num > 1) {
						$k1 = intval(uniform() * $num) + 1;
    					if ($k1 > $num)
    						$k1 = $num;
						$k2 = 0;
						$k0 = -1;
						for ($i2 = 1; $i2 <= 4 && $k0 < 0; $i2++) {
							if ($this->edge[$kk][$i2] >= 0) {
								if ($this->edge[$this->edge[$kk][$i2]][0] == $min) {
									$k2++;
									if ($k1 == $k2)
    									$k0 = $this->edge[$kk][$i2];
    							}
    						}
						}
					}
					else {
						if ($num <= 0) {
							$num = 0;
							for ($i2 = 0; $i2 < $this->len[$k]; $i2++) {
								if ($i2 != $kk && $this->edge[$i2][0] >= 0)
									$num++;
							}
							if ($num <= 0)
								exit("***error  invalid data (C_edge)\n");
							else {
    							$k1 = intval(uniform() * $num) + 1;
    							if ($k1 > $num)
									$k1 = $num;
    							$k2 = 0;
    							$k0 = -1;
								for ($i2 = 0; $i2 < $this->len[$k] && $k0 < 0; $i2++) {
									if ($i2 != $kk && $this->edge[$i2][0] >= 0) {
										$k2++;
										if ($k1 == $k2)
											$k0 = $i2;
									}
								}
    						}
    					}
    				}
					$this->edge[$kk][0] = -1;
					$this->ind[$k][$p]  = $k0;
					$kk                 = $k0;
					$p++;
				}
			}
		}
	}
	
	/*************************************************************/
	/* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/
	/*       同じ遺伝子のグループがない限り実行されない.たとえば*/
	/*         ***abcd**                                         */
	/*         *cdab****                                         */
    /*       のような両親の時実行され,以下の4つの子供が生成され*/
    /*       る)                                                */
	/*         ***cdab**                                         */
    /*         *abcd****                                         */
    /*         ***badc**                                         */
	/*         *dcba****                                         */
	/*       最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */
	/*       供が生成される可能性があるので,子供の数としてこの値*/
	/*       以上のデータを入力しておく必要がある.              */
	/*      kosa : 交叉確率                                      */
	/*      count : 1つのペアーに対する交差回数(default=10)     */
	/*************************************************************/
    function C_sub($kosa, $count = 10)
    {
    	$t22 = 0;
	/*
	     初期設定とデータのチェック
	*/
		if ((4*$count*$this->size*($this->size-1)) > $this->max_ch)
			exit("***error  子供が多すぎる (C_sub)\n");
	/*
	     交叉
	*/
		for ($i1 = 0; $i1 < $this->size-1; $i1++) {
						// 親1
			$p1 = $this->Position($i1);
	
    		if ($p1 >= 0) {
    
				for ($i2 = $i1; $i2 < $this->size; $i2++) {
    					// 親2
    				$p2 = $this->Position($i2);
	
					if ($p2 >= 0) {
						// 交叉しない場合
						if (uniform() > $kosa)
							$this->C_copy(2, 1);
						// 交叉する場合
						else {
    						// 交叉回数の制御
    						for ($i3 = 0; $i3 < $count; $i3++) {
    							// 交叉位置の決定(点の後ろで交叉)
									// 親1の交叉位置
								$t11 = intval(uniform() * $this->len[$p1]);
								if ($t11 > ($this->len[$p1]-1))
									$t11 = $this->len[$p1] - 1;
								$sw = 0;
								while ($sw == 0) {
									$t12 = intval(uniform() * $this->len[$p1]);
									if ($t12 > ($this->len[$p1]-1))
										$t12 = $this->len[$p1] - 1;
									if ($t12 != $t11)
										$sw = 1;
								}
								if ($t11 > $t12) {
									$k1  = $t11;
    								$t11 = $t12;
    								$t12 = $k1;
								}
    								// 親2の交叉位置
    							$sw  = 0;
								$t21 = -1;
								for ($i4 = 0; $i4 < $this->len[$p2] && $t21 < 0; $i4++) {
									for ($i5 = $t11; $i5 <= $t12 && $t21 < 0; $i5++) {
										if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5])
											$t21 = $i4;
									}
								}
    							if ($t21 >= 0) {
    								$t22 = $t21 + $t12 - $t11;
    								if ($t22 < $this->len[$p2]) {
										$sw = 1;
										for ($i4 = $t21+1; $i4 <= $t22 && $sw > 0; $i4++) {
											$sw = 0;
											for ($i5 = $t11; $i5 <= $t12 && $sw == 0; $i5++) {
												if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5])
													$sw = 1;
											}
										}
									}
								}
									// 交叉の実行
								if ($sw > 0) {
	
									$k1              = $this->Position(-1);
    								$this->pi_w[$k1] = 1;
    								$this->len[$k1]  = $this->len[$p1];
									$k2              = $this->Position(-1);
    								$this->pi_w[$k2] = 1;
    								$this->len[$k2]  = $this->len[$p1];
									$k3              = $this->Position(-1);
									$this->pi_w[$k3] = 1;
									$this->len[$k3]  = $this->len[$p2];
									$k4              = $this->Position(-1);
									$this->pi_w[$k4] = 1;
									$this->len[$k4]  = $this->len[$p2];
	
    								for ($i4 = 0; $i4 < $t11; $i4++) {
    									$this->ind[$k1][$i4] = $this->ind[$p1][$i4];
    									$this->ind[$k2][$i4] = $this->ind[$p1][$i4];
									}
									for ($i4 = $t11; $i4 <= $t12; $i4++) {
										$this->ind[$k1][$i4] = $this->ind[$p2][$t21+$i4-$t11];
										$this->ind[$k2][$i4] = $this->ind[$p2][$t22-$i4+$t11];
									}
									for ($i4 = $t12+1; $i4 < $this->len[$p1]; $i4++) {
										$this->ind[$k1][$i4] = $this->ind[$p1][$i4];
										$this->ind[$k2][$i4] = $this->ind[$p1][$i4];
									}
									for ($i4 = 0; $i4 < $t21; $i4++) {
										$this->ind[$k3][$i4] = $this->ind[$p2][$i4];
										$this->ind[$k4][$i4] = $this->ind[$p2][$i4];
									}
									for ($i4 = $t21; $i4 <= $t22; $i4++) {
    									$this->ind[$k3][$i4] = $this->ind[$p1][$t11+$i4-$t21];
    									$this->ind[$k4][$i4] = $this->ind[$p1][$t12-$i4+$t21];
									}
    								for ($i4 = $t22+1; $i4 < $this->len[$p2]; $i4++) {
    									$this->ind[$k3][$i4] = $this->ind[$p2][$i4];
										$this->ind[$k4][$i4] = $this->ind[$p2][$i4];
									}
								}
							}
						}
					}
				}
    		}
    	}
    }
	
	/**************************************/
	/* 突然変異(対立遺伝子との置き換え) */
	/*      pr : 突然変異率               */
	/**************************************/
	function M_alle($pr)
	{
	/*
	     データのチェックと初期設定
	*/
		if ($this->dup_a == 0)
			exit("***error  突然変異方法が不適当 (M_alle)\n");
    /*
         実行
	*/
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    		if ($this->pi_w[$i1] == 1) {
				for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) {
					if (uniform() <= $pr) {
						$lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l);
						if ($lid > $this->allele_u)
							$lid = $this->allele_u;
						if ($lid != $this->ind[$i1][$i2])
							$this->ind[$i1][$i2] = $lid;
    				}
    			}
    		}
		}
	}
	
	/**********************************************************************/
	/* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */
	/*           移動する)                                               */
	/*      pr : 突然変異率                                               */
	/**********************************************************************/
	function M_move($pr)
	{
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
	/*
         位置の決定
    */
						// p1
    			$p1 = intval(uniform() * $this->len[$i1]);
    			if ($p1 >= $this->len[$i1])
					$p1 = $this->len[$i1] - 1;
						// p2
				$sw = 0;
				while ($sw == 0) {
					$p2 = intval(uniform() * $this->len[$i1]);
					if ($p2 >= $this->len[$i1])
						$p2 = $this->len[$i1] - 1;
    				if ($p2 != $p1)
    					$sw = 1;
    			}
	/*
	     実行
	*/
				if ($p2 > $p1) {
					$ld = $this->ind[$i1][$p2];
					for ($i2 = $p2; $i2 > $p1; $i2--)
						$this->ind[$i1][$i2] = $this->ind[$i1][$i2-1];
					$this->ind[$i1][$p1] = $ld;
				}
				else {
					$ld = $this->ind[$i1][$p2];
					for ($i2 = $p2; $i2 < $p1-1; $i2++)
						$this->ind[$i1][$i2] = $this->ind[$i1][$i2+1];
					$this->ind[$i1][$p1-1] = $ld;
    			}
    		}
		}
    }
    
	/********************************************************/
	/* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */
	/*      pr : 突然変異率                                 */
	/*      wd : >0 : 幅を固定                              */
	/*           =0 : 幅をランダム(default)                 */
	/********************************************************/
	function M_inv($pr, $wd = 0)
    {
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
	/*
	     区間の決定
	*/
				if ($wd == 0) {
					$p1 = intval(uniform() * $this->len[$i1]);
					if ($p1 >= $this->len[$i1])
						$p1 = $this->len[$i1] - 1;
					$sw = 0;
					while ($sw == 0) {
						$p2 = intval(uniform() * $this->len[$i1]);
						if ($p2 >= $this->len[$i1])
    						$p2 = $this->len[$i1] - 1;
    					if ($p2 != $p1)
							$sw = 1;
    				}
    				if ($p1 > $p2) {
						$p  = $p1;
						$p1 = $p2;
						$p2 = $p;
					}
				}
	
				else {
    				$p1 = $this->len[$i1];
    				while ($p1 > $this->len[$i1]-2)
    					$p1 = intval(uniform() * $this->len[$i1]);
					$p2 = $p1 + $wd - 1;
					if ($p2 >= $this->len[$i1])
						$p2 = $this->len[$i1] - 1;
				}
	/*
	     実行
	*/
				$sw = 0;
				while ($sw == 0) {
					$lid         = $this->ind[$i1][$p1];
					$this->ind[$i1][$p1] = $this->ind[$i1][$p2];
					$this->ind[$i1][$p2] = $lid;
					$p1++;
					$p2--;
    				if ($p1 >= $p2)
    					$sw = 1;
				}
    		}
    	}
	}
	
	/**********************************************************************/
	/* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */
	/*      pr : 突然変異率                                               */
	/*      wd : >0 : 幅を固定                                            */
	/*           =0 : 幅をランダム(default)                               */
    /**********************************************************************/
    function M_scram($pr, $wd = 0)
    {
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
	/*
	     区間の決定
	*/
				if ($wd == 0) {
					$p1 = intval(uniform() * $this->len[$i1]);
					if ($p1 >= $this->len[$i1])
						$p1 = $this->len[$i1] - 1;
					$sw = 0;
					while ($sw == 0) {
						$p2 = intval(uniform() * $this->len[$i1]);
						if ($p2 >= $this->len[$i1])
    						$p2 = $this->len[$i1] - 1;
    					if ($p2 != $p1)
							$sw = 1;
    				}
    				if ($p1 > $p2) {
						$p  = $p1;
						$p1 = $p2;
						$p2 = $p;
					}
				}
	
				else {
    				$p1 = $this->len[$i1];
    				while ($p1 > $this->len[$i1]-2)
    					$p1 = intval(uniform() * $this->len[$i1]);
					$p2 = $p1 + $wd - 1;
					if ($p2 >= $this->len[$i1])
						$p2 = $this->len[$i1] - 1;
				}
	/*
	     実行
	*/
				for ($i2 = $p1; $i2 <= $p2; $i2++) {
					$p = intval(uniform() * ($p2 - $p1 + 1) + $p1);
					if ($p > $p2)
						$p = $p2;
					$ld                  = $this->ind[$i1][$i2];
					$this->ind[$i1][$i2] = $this->ind[$i1][$p];
					$this->ind[$i1][$p]  = $ld;
    			}
    		}
		}
    }
    
	/**********************************************************************/
	/* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */
	/*           重複部分はそのままとする)                               */
	/*      pr : 突然変異率                                               */
	/*      wd : >0 : 幅を固定                                            */
	/*           =0 : 幅をランダム(default)                               */
	/**********************************************************************/
    function M_chg($pr, $wd = 0)
    {
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
	/*
	     区間等の決定([p1,p2]と[p3,p4]の入れ替え)
	*/
						// p1
				$p1 = intval(uniform() * $this->len[$i1]);
				if ($p1 >= $this->len[$i1])
					$p1 = $this->len[$i1] - 1;
						// p3
				$sw = 0;
				while ($sw == 0) {
					$p3 = intval(uniform() * $this->len[$i1]);
					if ($p3 >= $this->len[$i1])
    					$p3 = $this->len[$i1] - 1;
    				if ($p3 != $p1)
						$sw = 1;
    			}
    					// 小さい方をp1,p2にする
				if ($p1 > $p3) {
					$p  = $p1;
					$p1 = $p3;
					$p3 = $p;
				}
						// p4, p2
				$p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p1 + $wd - 1;
    			if ($p4 >= $this->len[$i1])
    				$p4 = $this->len[$i1] - 1;
				$p2 = $p1 + ($p4 - $p3);
						// 重複部分のチェック
				if ($p2 >= $p3) {
					$p  = $p3 - 1;
					$p3 = $p2 + 1;
					$p2 = $p;
					$p4 = $p3 + ($p2 - $p1);
				}
	/*
	     実行
	*/
				$p = $p3;
				for ($i2 = $p1; $i2 <= $p2; $i2++) {
					$ld                  = $this->ind[$i1][$i2];
    				$this->ind[$i1][$i2] = $this->ind[$i1][$p];
    				$this->ind[$i1][$p]  = $ld;
					$p++;
    			}
    		}
		}
	}
	
	/**********************************************************************/
	/* 突然変異(重複.2点間の遺伝子を他の位置にコピーする               */
	/*      pr : 突然変異率                                               */
	/*      wd : >0 : 幅を固定                                            */
    /*           =0 : 幅をランダム(deafult)                               */
    /**********************************************************************/
    function M_dup($pr, $wd = 0)
	{
	/*
	     データのチェック
	*/
		if ($this->dup_a == 0)
			exit("***error  突然変異方法が不適当 (M_dup)\n");
	/*
	     実行
	*/
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
    					// 区間の決定([p1,p2]を[p3,p4]にコピー)
    						// p1
				$p1 = intval(uniform() * $this->len[$i1]);
    			if ($p1 >= $this->len[$i1])
    				$p1 = $this->len[$i1] - 1;
							// p3
				$sw = 0;
				while ($sw == 0) {
					$p3 = intval(uniform() * $this->len[$i1]);
					if ($p3 >= $this->len[$i1])
						$p3 = $this->len[$i1] - 1;
					if ($p3 != $p1)
    					$sw = 1;
    			}
    						// 区間を決める
				if ($p3 > $p1) {
					$p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p3 + $wd - 1;
					if ($p4 >= $this->len[$i1])
						$p4 = $this->len[$i1] - 1;
					$p2 = $p1 + ($p4 - $p3);
				}
				else {
					$p2 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p1)) + $p1 :$p1 + $wd - 1;
					if ($p2 >= $this->len[$i1])
						$p2 = $this->len[$i1] - 1;
					$p4 = $p3 + ($p2 - $p1);
				}
    					// 実行
    			$p = $p4;
				for ($i2 = $p2; $i2 >= $p1; $i2--) {
    				$this->ind[$i1][$p] = $this->ind[$i1][$i2];
    				$p--;
				}
			}
		}
	}
	
	/******************************************************/
	/* 突然変異(摂動.値をある量だけ変化させる)         */
    /*      pr : 突然変異率                               */
    /*      method : =0 : 正規分布(default)               */
    /*               =1 : 一様分布                        */
	/*      m : 平均または一様分布の下限(default=0.0)     */
	/*      s : 標準偏差または一様分布の上限(default=1.0) */
	/******************************************************/
	function M_per($pr, $method = 0, $m = 0.0, $s = 1.0)
	{
		$wd = 0.0;
	/*
	     データのチェックと初期設定
	*/
		if ($this->dup_a == 0)
			exit("***error  突然変異方法が不適当 (M_per)\n");
	
    	if ($method > 0)
    		$wd = $s - $m;
	/*
         実行
    */
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
			if ($this->pi_w[$i1] == 1) {
				for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) {
					if (uniform() <= $pr) {
						if ($method == 0)
							$w = norm_d($m, $s);
						else {
    						$w = uniform() * $wd;
    						if (uniform() < 0.5)
    							$w = -$w;
						}
						$x1 = (double)$this->ind[$i1][$i2] + $w;
						if ($x1 > $this->allele_u)
							$x1 = $this->allele_u;
						else {
							if ($x1 < $this->allele_l)
								$x1 = $this->allele_l;
						}
						$this->ind[$i1][$i2] = intval($x1);
					}
				}
			}
		}
	}
    
    /**********************************************************************/
	/* 突然変異(挿入.ある長さの遺伝子を挿入する)                       */
    /*      pr : 突然変異率                                               */
    /*      wd : >0 : 幅を固定                                            */
	/*           =0 : 幅をランダム(default)                               */
	/**********************************************************************/
	function M_ins($pr, $wd = 0)
	{
	/*
	     データのチェック
	*/
    	if ($this->dup_a == 0 || $this->min_len < 0)
    		exit("***error  突然変異方法が不適当 (M_ins)\n");
	/*
	     実行
	*/
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
	
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
						// 挿入位置の決定
				$p = intval(uniform() * ($this->len[$i1]+1));
				if ($p > $this->len[$i1])
					$p = $this->len[$i1];
						// 挿入する遺伝子長の決定
				$l = ($wd == 0) ? intval(uniform() * ($this->max_len - $this->len[$i1] + 1)) : $wd;
				if ($l > $this->max_len-$this->len[$i1])
    				$l = $this->max_len - $this->len[$i1];
    			else {
					if ($l <= 0)
    					$l = 1;
    			}
						// 実行
							// 挿入場所の確保
				if ($p < $this->len[$i1]) {
					for ($i2 = $this->len[$i1]+$l-1; $i2 >= $p; $i2--)
						$this->ind[$i1][$i2] = $this->ind[$i1][$i2-$l];
				}
							// 挿入場所の遺伝子の決定
    			for ($i2 = $p; $i2 < $p+$l; $i2++) {
    				$ld = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l);
    				if ($ld > $this->allele_u)
						$ld = $this->allele_u;
					$this->ind[$i1][$i2] = $ld;
				}
	
				$this->len[$i1]  += $l;
			}
		}
	}
	
	/**********************************************************************/
	/* 突然変異(削除.ある長さの遺伝子を削除する)                       */
	/*      pr : 突然変異率                                               */
	/*      wd : >0 : 幅を固定                                            */
	/*           =0 : 幅をランダム(default)                               */
    /**********************************************************************/
    function M_del($pr, $wd = 0)
	{
    /*
         データのチェック
	*/
		if ($this->dup_a == 0 || $this->min_len < 0)
			exit("***error  突然変異方法が不適当 (M_del)\n");
			exit(1);
	/*
	     実行
    */
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    
			if ($this->pi_w[$i1] == 1 && uniform() <= $pr) {
						// 削除位置の決定
				$p = intval(uniform() * $this->len[$i1]);
				if ($p >= $this->len[$i1])
					$p = $this->len[$i1] - 1;
						// 削除する遺伝子長の決定
				$max = ($this->len[$i1]-$this->min_len < $this->len[$i1]-$p) ? $this->len[$i1] - $this->min_len : $this->len[$i1] - $p;
				$l   = ($wd == 0) ? intval(uniform() * $max + 1) : $wd;
				if ($l > $max)
					$l = $max;
						// 実行
				for ($i2 = 0; $i2 < $this->len[$i1]-$p-$l; $i2++)
					$this->ind[$i1][$p+$i2] = $this->ind[$i1][$p+$i2+$l];
	
    			$this->len[$i1] -= $l;
    		}
		}
    }
    
	/*********************************************************************/
	/* 淘汰(エリート・ルーレット選択)                                  */
	/*      elite : エリートで残す個体数(default=0)                      */
	/*      s_method : ルーレット板の作成方法(default=1)                 */
	/*                   =0 : 適応度をそのまま使用                       */
	/*                   =1 : 最小値からの差(ただし,α以下の場合はα) */
	/*                   =2 : 評価値に順位をつけ,減少率βで線形化       */
    /*      s_bias : α,または,method=2の場合は初期値(default=0)       */
    /*      s_step : β(default=1)                                       */
    /*********************************************************************/
	function S_roul($elite = 0, $s_method = 1, $s_bias = 0.0, $s_step = 1.0)
	{
		$count = 0;
		$k     = 0;
		$n     = 0;
	/*
	     値のチェックと初期設定
	*/
		if ($s_method != 0 && $s_method != 2)
			$s_method = 1;
	
		if ($elite > $this->size)
			exit("***error  エリートで残す数が多すぎる (S_roul)\n");
    
		if ($s_method == 2 && $s_step <= 0.0)
    		$s_step = 1.0;
    
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++)
			$this->s_w[$i1] = 0;
	/*
	     重複個体を削除
	*/
		if ($this->dup_s == 0) {
			for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    			if ($this->pi_w[$i1] > 0) {
    				for ($i2 = $i1+1; $i2 < $this->size+$this->max_ch; $i2++) {
    					if ($this->pi_w[$i2] > 0 && $this->len[$i1] == $this->len[$i2]) {
							$sw = 0;
							for ($i3 = 0; $i3 < $this->len[$i1] && $sw == 0; $i3++) {
								if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3])
									$sw = 1;
							}
							if ($sw == 0)
								$this->pi_w[$i2] = 0;
						}
					}
				}
			}
		}
	
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    		if ($this->pi_w[$i1] > 1)
    			$n++;
		}
    
    	if ($n < 0 || $this->dup_s == 0 && $n < $this->size)
			exit("***error  残す個体がない (S_roul)\n");
	/*
	     淘汰して残す個体を選ぶ
	*/
						// エリートの選択
    	$sw = 0;
    
    	while ($k < $elite && $k < $n && $sw == 0) {
			$max = -1;
			for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
				if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) {
					if ($max < 0 || $this->pi[$i1] > $this->pi[$max])
						$max = $i1;
				}
			}
			if ($max < 0)
				$sw = 1;
			else {
				$this->s_w[$max] = 1;
				$k++;
			}
		}
    					// ルーレット選択
    	while ($count < $this->size+$this->max_ch && $k < $this->size) {
			$p = $this->Select($s_method, $s_bias, $s_step);
    		if ($this->dup_s == 0 && $this->s_w[$p] > 0)
    			$count++;
			else {
				$count = 0;
				$this->s_w[$p]++;
				$k++;
			}
		}
							// 選択に失敗した場合の処理
    	if ($this->dup_s == 0 && $k < $this->size) {
    		for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < $this->size; $i1++) {
    			if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) {
					$this->s_w[$i1] = 1;
					$k++;
				}
			}
		}
							// 複数回選択されたものの処理
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
			if ($this->s_w[$i1] == 0)
				$this->pi_w[$i1] = 0;
		}
	
		for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
			if ($this->s_w[$i1] > 0) {
				if ($this->s_w[$i1] > 1) {
    				for ($i2 = 2; $i2 <= $this->s_w[$i1]; $i2++) {
    					$k              = $this->Position(-1);
						$this->len[$k]  = $this->len[$i1];
    					$this->pi_w[$k] = 2;
    					$this->pi[$k]   = $this->pi[$i1];
						for ($i3 = 0; $i3 < $this->len[$i1]; $i3++)
							$this->ind[$k][$i3] = $this->ind[$i1][$i3];
					}
				}
			}
		}
	}
}
    
/***********************************/
/* [0, 1] 区間の一様分布変量の発生 */
/***********************************/
function uniform()
{
	return mt_rand() / mt_getrandmax();
}

/***********************************/
/* 正規分布変量の発生              */
/*      m : 平均                   */
/*      s : 標準偏差               */
/*           return : 正規分布変量 */
/***********************************/
function norm_d($m, $s)
{
  	$x = 0.0;

   	for ($i1 = 0; $i1 < 12; $i1++)
   		$x += uniform();

	$x = $s * ($x - 6.0) + $m;

	return $x;
}
	
/************************/
/* クラスFunctionの定義 */
/************************/
class Func extends Species {

	private $cv;   // 2進数を10進数の変換する係数
	private $max_gen;   // 最大世代交代数
	private $kosa_m;   // 交叉方法
                       //   =-1 : 交叉を使用しない
                       //   =0 : 親のコピー
                       //   =1 : 多点交叉
                       //   =2 : 一様交叉
                       //   =3 : 平均化交叉
	private $kosa;   // 交叉確率
	private $k_point;   // 交差点の数(負の時は,1から-point間のランダム)
	private $k_vr;   // =0 : 両親とも同じ位置で交叉
                     // =1 : 両親が異なる位置で交叉(遺伝子長は可変)
	private $k_method;   // 交叉の時の親の選択方法
                         //   =-1 : ランダム
                         //   =0 : 適応度をそのまま使用
                         //   =1 : 最小値からの差(ただし,α以下の場合はα)
                         //   =2 : 評価値に順位をつけ,減少率βで線形化
	private $k_bias;   // α,または,method=2の場合は初期値
	private $k_step;   // β
	private $mute_m;   // 突然変異方法
                       //   =-1 : 突然変異を使用しない
                       //   =0 : 対立遺伝子への置換
                       //   =1 : 移動
                       //   =2 : 逆位
                       //   =3 : スクランブル
                       //   =4 : 転座
                       //   =5 : 重複
                       //   =6 : 摂動
	private $mute;   // 突然変異率
	private $wd;   // 突然変異に使用する部分遺伝子長
	private $m_mean;   // 摂動の平均値
	private $m_std;   // 摂動の標準偏差
	private $elite;   // エリート選択で残す数
	private $s_method;   // ルーレット板の作成方法
                         //   =0 : 適応度をそのまま使用
                         //   =1 : 最小値からの差(ただし,α以下の場合はα)
                         //   =2 : 評価値に順位をつけ,減少率βで線形化
	private $s_bias;   // α,または,s_method=2の場合は初期値
	private $s_step;   // β
	private $out_d;   // 表示間隔
	private $out_lvl;   // 出力レベル
                        //   =0 : 最終出力だけ
                        //   n>0 : n世代毎に出力(負の時はファイル)
	private $out_m;   // 出力方法
                      //   =0 : すべてを出力
                      //   =1 : 最大適応度の個体だけを出力
	private $o_file;   // 出力ファイル名

	/***************************************/
	/* コンストラクタ                      */
	/*      name1 : Species定義ファイル名  */
    /*      name2 : Func定義ファイル名     */
    /*      seed : 乱数の初期値            */
    /***************************************/
    function Func ($name1, $name2, $seed)
    {
		parent::Species($name1, $seed);
	
		$in = fopen($name2, "rb");
    
		fscanf($in, "%*s %d %*s %d", $this->out_lvl, $this->out_m);
    	fscanf($in, "%*s %s %*s %d", $this->o_file, $this->out_d);
    	fscanf($in, "%*s %d %*s %lf %*s %d %*s %d %*s %d %*s %lf %*s %lf", $this->kosa_m, $this->kosa, $this->k_point, $this->k_vr, $this->k_method, $this->k_bias, $this->k_step);
    	fscanf($in, "%*s %d %*s %lf %*s %d %*s %lf %*s %lf", $this->mute_m, $this->mute, $this->wd, $this->m_mean, $this->m_std);
		fscanf($in, "%*s %d %*s %d %*s %lf %*s %lf", $this->elite, $this->s_method, $this->s_bias, $this->s_step);
    	fscanf($in, "%*s %d", $this->max_gen);
    
    	$this->cv = 1.0 / (pow(2.0, $this->max_len) - 1.0);
    
    	fclose($in);
    }
    
    /**************/
	/* 全体の制御 */
	/**************/
	function Control()
	{
		$gen = 1;
						// 初期集団の発生
    	$this->Init_std();
    					// 評価
    	$this->Adap();
						// 出力
		printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean);
	
    	if (abs($this->out_lvl) > 0)
    		$this->Output($gen);
						// 世代交代
    	for ($gen = 2; $gen <= $this->max_gen; $gen++) {
    						// 交叉
			switch ($this->kosa_m) {
				case -1:
					break;
				case 0:
    				$this->C_copy();   // 親のコピー
    				break;
    			case 1:
    				$this->C_point($this->kosa, $this->k_point);   // 多点交叉
    				break;
				case 2:
					$this->C_uniform($this->kosa);   // 一様交叉
					break;
    			case 3:
					$this->C_mean($this->kosa);   // 平均化交叉
    				break;
    			default:
    				break;
    		}
							// 突然変異
			switch ($this->mute_m) {
				case -1:
    				break;
    			case 0:
    				$this->M_alle($this->mute);   // 対立遺伝子への置換
    				break;
    			case 1:
    				$this->M_move($this->mute);   // 移動
    				break;
    			case 2:
					$this->M_inv($this->mute, $this->wd);   // 逆位
					break;
				case 3:
					$this->M_scram($this->mute, $this->wd);   // スクランブル
					break;
				case 4:
    				$this->M_chg($this->mute, $this->wd);   // 転座
    				break;
    			case 5:
					$this->M_dup($this->mute, $this->wd);   // 重複
					break;
				case 6:
					$this->M_per($this->mute, $this->wd, $this->m_mean, $this->m_std);   // 摂動
    				break;
    			default:
					break;
    		}
    						// 適応度
			$this->Adap();
							// 淘汰
			$this->S_roul($this->elite);
							// 出力
    		if ($gen%$this->out_d == 0)
    			printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean);
    
    		if (abs($this->out_lvl) > 0) {
				if ($gen%abs($this->out_lvl) == 0)
					$this->Output($gen);
			}
    	}
	
    	$gen--;
    	$k1 = $this->out_m;
    	$this->out_m = 0;
    	printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean);
		$this->Output($gen);
		$this->out_m = $k1;
    }
    
    /****************/
    /* 適応度の計算 */
    /****************/
    function Adap()
    {
		$n           = 0;
		$this->max   = 0.0;
		$this->max_n = -1;
		$this->mean  = 0.0;
	
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    
    		if ($this->pi_w[$i1] == 1) {
				$x = 0.0;
				$y = 0.0;
				for ($i2 = $this->len[$i1]-1; $i2 >= 0; $i2--) {
					if ($this->ind[$i1][$i2] > 0)
    					$x += pow(2.0, $y);
    				$y += 1.0;
				}
    			$x               *= $this->cv;
    			$this->pi[$i1]    = sin(3.0*$x) + 0.5 * sin(9.0*$x) + sin(15.0*$x+50.0);
				$this->pi_w[$i1]  = 2;
			}
	
			if ($this->pi_w[$i1] > 0) {
    			$this->mean += $this->pi[$i1];
    			$n++;
    			if ($this->max_n < 0 || $this->pi[$i1] > $this->max) {
    				$this->max   = $this->pi[$i1];
    				$this->max_n = $i1;
				}
			}
		}
    
		$this->mean /= $n;
    }
    
    /*****************************/
    /* 結果の出力                */
	/*      gen : 現在の世代番号 */
	/*****************************/
	function Output($gen)
    {
 		$k = 0;

    	if ($this->out_lvl >= 0) {
			printf("   出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ");
			fscanf(STDIN, "%d", $pr);
		}
		else
			$pr = -1;
	
    	if ($pr != 0) {
    					// 出力先の決定と評価値の出力
    		if ($pr > 0) {
				$out = STDOUT;
				fgets(STDIN);
			}
			else {
 				$x   = getdate();
				$now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒";
				$out = fopen($this->o_file, "ab");
				fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n");
			}
						// 詳細出力
			for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
				if (($this->pi_w[$i1] > 1) && ($this->out_m ==0 || $this->out_m == 1 && $i1 == $this->max_n)) {
    				fprintf($out, "%d allele", $i1);
    				for ($i2 = 0; $i2 < $this->len[$i1]; $i2++)
    					fprintf($out, " %d", $this->ind[$i1][$i2]);
    				$x = 0.0;
    				$y = 0.0;
					for ($i2 = $this->len[$i1]-1; $i2 >= 0; $i2--) {
						if ($this->ind[$i1][$i2] > 0)
							$x += pow(2.0, $y);
    					$y += 1.0;
					}
    				$x *= $this->cv;
    				fprintf($out, " x %f y %f\n", $x, $this->pi[$i1]);
    				if ($pr > 0) {
    					$k++;
						if ($k == $pr) {
							fgets(STDIN);
							$k = 0;
    					}
    				}
    			}
    		}
    
    		if ($pr < 0)
    			fclose($out);
    	}
	}
	
}

/****************/
/* main program */
/****************/
   					// 入力ミス
	if (count($argv) <= 1)
		exit("***error  ファイル名を入力して下さい\n");
					// 入力OK
	else {
						// ファイルのオープン
		$in = fopen($argv[1], "rb");
		if ($in == NULL)
			exit("***error  ファイル名が不適当です\n");
						// 入力データファイル名の入力
		fscanf($in, "%d", $n);   // データの数

		$seed    = array($n);
		$i_file1 = array($n);
		$i_file2 = array($n);

		for ($i1 = 0; $i1 < $n; $i1++) {
			$seed[$i1]    = 1000 * $i1 + 1234567;
			fscanf($in, "%s %s", $i_file1[$i1], $i_file2[$i1]);
		}

		fclose($in);
						// 実行(乱数の初期値を変える)
		for ($i1 = 0; $i1 < $n; $i1++) {

			printf("\n+++++ケース %d+++++\n", $i1+1);

			$fn = new Func ($i_file1[$i1], $i_file2[$i1], $seed[$i1]);

			$fn->Control();
		}
	}

//------------------ケーススタディデータ(data_cf.txt)------
/*
3
data1_f.txt data2_f.txt
data1_f.txt data2_f.txt
data1_f.txt data2_f.txt
*/

//------------------Species記述データ(data1_f.txt)---------
/*
対立遺伝子上限 1 対立遺伝子下限 0
最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1
遺伝子の重複 1 個体の重複(同じ染色体の個体) 0
集団サイズ 20 子供 20
*/

//------------------Func記述データ(data2_f.txt)--------
/*
出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0
出力ファイル名 out1.txt 表示間隔 1
交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1
突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0
エリート 2 方法 1 バイアス 0 ステップ 1
最大世代交代数 200
*/

?>