遺伝的アルゴリズム( TSP )

<?php

/***********************************/
/* 遺伝的アルゴリズムによるTSPの解 */
/*      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;
}
	
/*******************/
/* クラスTSPの定義 */
/*******************/

class TSP extends Species {

	private $max_gen;   // 最大世代交代数
	private $kosa_m;   // 交叉方法
                       //   =-1 : 交叉を使用しない
                       //   =0 : 親のコピー
                       //   =1 : 循環交叉
                       //   =2 : 部分的交叉
                       //   =3 : 順序交叉
                       //   =4 : 一様順序交叉
                       //   =5 : 一様位置交叉
                       //   =6 : エッジ組み替え交叉
                       //   =7 : サブツアー交叉
	private $kosa;   // 交叉確率
	private $k_point;   // 交差点の数(負の時は,1から-k_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 : 転座
	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;   // 出力ファイル名
	private $city;   //都市の位置データ
	private $n_city;   // 都市の数
	private $rg;   // 都市間の距離
	private $kinbo;   // 近傍探索(0:行わない,1:行う)
	private $neib;   // 近傍(2 or 3)
	private $sel;   // エッジの選択方法
                    //   =0 : 最良のものを選択
                    //   =1 : 最初のものを選択
    
	/***************************************/
	/* コンストラクタ                      */
	/*      name1 : Species定義ファイル名  */
	/*      name2 : TSP定義ファイル名      */
	/*      seed : 乱数の初期値            */
	/***************************************/
	function TSP ($name1, $name2, $seed)
	{
		parent::Species($name1, $seed);
						// 基本データの入力
		$in = fopen($name2, "r");
	
		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_stds);
    	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 %*s %d", $this->n_city, $this->max_gen);
		fscanf($in, "%*s %d %*s %d", $this->kinbo, $this->neib);
		fscanf($in, "%*s %d", $this->sel);
	
		if ($this->kinbo > 0 && $this->neib != 2 && $this->neib != 3)
			exit("***error  近傍の値が不適当 \n");
    
		if ($this->n_city != $this->max_len)
			exit("***error  都市数が不適当 \n");
						// 都市の位置データ
		$this->city = array($this->n_city);
		for ($i1 = 0; $i1 < $this->n_city; $i1++) {
			$this->city[$i1] = array(2);
			fscanf($in, "%d %d", $this->city[$i1][0], $this->city[$i1][1]);
		}
						// 距離テーブル
		$this->rg = array($this->n_city);
	
		for ($i1 = 0; $i1 < $this->n_city; $i1++) {
    		$this->rg[$i1] = array($this->n_city);
    		for ($i2 = $i1+1; $i2 < $this->n_city; $i2++) {
				$x = $this->city[$i2][0] - $this->city[$i1][0];
    			$y = $this->city[$i2][1] - $this->city[$i1][1];
    			$this->rg[$i1][$i2] = round(sqrt($x * $x + $y * $y));
			}
		}
	
		for ($i1 = 1; $i1 < $this->n_city; $i1++) {
			for ($i2 = 0; $i2 < $i1; $i2++)
				$this->rg[$i1][$i2] = $this->rg[$i2][$i1];
		}
    
    	fclose($in);
    }
	
	/**************/
	/* 全体の制御 */
	/**************/
	function Control()
	{
		$gen = 1;
						// 初期集団の発生
		$this->Init_std();
						// 評価
		if ($this->kinbo > 0)
			$this->Kinbo();
		else
			$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_cycle($this->kosa);   // 循環交叉
					break;
				case 2:
					$this->C_part($this->kosa);   // 部分的交叉
					break;
				case 3:
					$this->C_seq($this->kosa);   // 順序交叉
					break;
				case 4:
					$this->C_useq($this->kosa);   // 一様順序交叉
					break;
				case 5:
					$this->C_upos($this->kosa);   // 一様位置交叉
    				break;
    			case 6:
					$this->C_edge($this->kosa);   // エッジ組み替え交叉
    				break;
    			case 7:
					$this->C_sub($this->kosa, $this->k_point);   // サブツアー交叉
					break;
				default:
					break;
			}
							// 突然変異
			switch ($this->mute_m) {
    			case -1:
    				break;
    			case 0:
					$this->M_move($this->mute);   // 移動
					break;
				case 1:
					$this->M_inv($this->mute);   // 逆位
					break;
				case 2:
					$this->M_scram($this->mute);   // スクランブル
					break;
				case 3:
					$this->M_chg($this->mute);   // 転座
					break;
				default:
					break;
			}
    						// 適応度
    		if ($this->kinbo > 0)
				$this->Kinbo();
    		else
    			$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;
	}
	
	/*********************************/
	/* 距離の計算                    */
    /*      n_c : 都市の数           */
    /*      p : 都市番号             */
	/*      return : 距離(負)      */
    /*********************************/
    function Kyori($n_c, $p)
	{
		$range = 0;
		$n1    = $p[0];
	
		for ($i1 = 1; $i1 < $n_c; $i1++) {
			$n2     = $p[$i1];
    		$range -= $this->rg[$n1][$n2];
    		$n1     = $n2;
    	}
	
		$n2     = $p[0];
		$range -= $this->rg[$n1][$n2];
	
		return $range;
	}
	
	/****************/
	/* 適応度の計算 */
	/****************/
	function Adap()
	{
		$k           = 0;
		$this->mean  = 0.0;
    	$this->max   = 0.0;
    	$this->max_n = -1;
	
    	for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) {
    		if ($this->pi_w[$i1] == 1) {
				$this->pi_w[$i1] = 2;
				$this->pi[$i1]   = $this->Kyori($this->len[$i1], $this->ind[$i1]);
			}
			if ($this->pi_w[$i1] > 0) {
				$k++;
				$this->mean += $this->pi[$i1];
				if ($this->max_n < 0 || $this->pi[$i1] > $this->max) {
    				$this->max   = $this->pi[$i1];
    				$this->max_n = $i1;
    			}
			}
		}
	
		if ($k > 0)
			$this->mean /= $k;
	}
	
	/**************************************/
	/* エッジの入れ替え                   */
	/*      n_city : 都市の数             */
	/*      seq : 訪問する順番            */
	/*      r_m : 距離の負値              */
	/*      return : =0 : 改善がなかった  */
	/*               =1 : 改善があった    */
    /**************************************/
    function Change($n_city, &$seq, &$r_m)
	{
    	$ch  = 0;
    	$sw  = 0;
		$max = $r_m;
	
		$n3  = intval(uniform() * ($n_city - 2));
		if ($n3 > $n_city-3)
			$n3 = $n_city - 3;
	                         // 2近傍
		for ($i1 = 0; $i1 <= $n_city-3 && $ch == 0; $i1++) {
    
    		if ($n3 == 0)
    			$n1 = $n_city - 2;
			else
				$n1 = $n_city - 1;
	
			for ($i2 = $n3+2; $i2 <= $n1 && $ch == 0; $i2++) {
	                              // 枝の場所((n3,n3+1), (k1,k2))
				$k1 = $i2;
				if ($i2 == $n_city-1)
					$k2 = 0;
				else
					$k2 = $i2 + 1;
	                              // 枝の入れ替え
				$this->kou1[0] = $seq[$n3];
				$k             = 1;
				for ($i3 = $k1; $i3 >= $n3+1; $i3--) {
    				$this->kou1[$k] = $seq[$i3];
    				$k++;
				}
    
    			$nn = $k2;
				while ($nn != $n3) {
					$this->kou1[$k] = $seq[$nn];
					$k++;
					$nn++;
					if ($nn > $n_city-1)
						$nn = 0;
				}
                                  // 評価
    			$r = $this->Kyori($n_city, $this->kou1);
    
				if ($r > $max) {
					$max = $r;
					$sw  = 1;
					for ($i3 = 0; $i3 < $n_city; $i3++)
						$this->kou2[$i3] = $this->kou1[$i3];
					if ($this->sel > 0)
						$ch = 1;
				}
			}
	
			$n3++;
			if ($n3 > $n_city-3)
				$n3 = 0;
		}
                             // 3近傍
    	if ($this->neib == 3 && $ch == 0) {
	
    		for ($i1 = 0; $i1 <= $n_city-3 && $ch == 0; $i1++) {
    
				$n1 = $n_city - 2;
				$n2 = $n_city - 1;
	
				for ($i2 = $n3+1; $i2 <= $n1 && $ch == 0; $i2++) {
	
					for ($i3 = $i2+1; $i3 <= $n2 && $ch == 0; $i3++) {
	                              // 枝の場所((n3,n3+1), ($i2,$i2+1), (k1,k2))
    					$k1 = $i3;
    					if ($i3 == $n_city-1)
    						$k2 = 0;
						else
							$k2 = $i3 + 1;
	                              // 枝の入れ替えと評価
	                                   // 入れ替え(その1)
						$this->kou1[0] = $seq[$n3];
						$k             = 1;
						for ($i4 = $i2; $i4 >= $n3+1; $i4--) {
							$this->kou1[$k] = $seq[$i4];
							$k++;
						}
	
						for ($i4 = $k1; $i4 >= $i2+1; $i4--) {
							$this->kou1[$k] = $seq[$i4];
							$k++;
    					}
    
						$nn = $k2;
    					while ($nn != $n3) {
    						$this->kou1[$k] = $seq[$nn];
							$k++;
							$nn++;
							if ($nn > $n_city-1)
								$nn = 0;
						}
	                                   // 評価(その1)
						$r = $this->Kyori($n_city, $this->kou1);
    
    					if ($r > $max) {
    						$max = $r;
							$sw  = 1;
							for ($i3 = 0; $i3 < $n_city; $i3++)
								$this->kou2[$i3] = $this->kou1[$i3];
							if ($this->sel > 0)
								$ch = 1;
						}
	                                   // 入れ替え(その2)
						$this->kou1[0] = $seq[$n3];
						$k             = 1;
						for ($i4 = $k1; $i4 >= $i2+1; $i4--) {
							$this->kou1[$k] = $seq[$i4];
							$k++;
						}
	
    					for ($i4 = $n3+1; $i4 <= $i2; $i4++) {
    						$this->kou1[$k] = $seq[$i4];
							$k++;
    					}
    
						$nn = $k2;
						while ($nn != $n3) {
							$this->kou1[$k] = $seq[$nn];
							$k++;
							$nn++;
							if ($nn > $n_city-1)
								$nn = 0;
    					}
                                       // 評価(その2)
    					$r = $this->Kyori($n_city, $this->kou1);
	
						if ($r > $max) {
							$max = $r;
							$sw  = 1;
							for ($i3 = 0; $i3 < $n_city; $i3++)
								$this->kou2[$i3] = $this->kou1[$i3];
							if ($this->sel > 0)
								$ch = 1;
						}
	                                   // 入れ替え(その3)
						$this->kou1[0] = $seq[$n3];
						$k             = 1;
						for ($i4 = $i2+1; $i4 <= $k1; $i4++) {
							$this->kou1[$k] = $seq[$i4];
    						$k++;
    					}
	
    					for ($i4 = $i2; $i4 >= $n3+1; $i4--) {
    						$this->kou1[$k] = $seq[$i4];
							$k++;
						}
	
						$nn = $k2;
						while ($nn != $n3) {
							$this->kou1[$k] = $seq[$nn];
							$k++;
    						$nn++;
    						if ($nn > $n_city-1)
    							$nn = 0;
						}
	                                   // 評価(その3)
						$r = $this->Kyori($n_city, $this->kou1);
	
						if ($r > $max) {
							$max = $r;
							$sw  = 1;
							for ($i3 = 0; $i3 < $n_city; $i3++)
								$this->kou2[$i3] = $this->kou1[$i3];
							if ($this->sel > 0)
								$ch = 1;
						}
	                                   // 入れ替え(その4)
						$this->kou1[0] = $seq[$n3];
    					$k             = 1;
    					for ($i4 = $i2+1; $i4 <= $k1; $i4++) {
							$this->kou1[$k] = $seq[$i4];
    						$k++;
    					}
	
						for ($i4 = $n3+1; $i4 <= $i2; $i4++) {
							$this->kou1[$k] = $seq[$i4];
							$k++;
						}
	
						$nn = $k2;
    					while ($nn != $n3) {
    						$this->kou1[$k] = $seq[$nn];
    						$k++;
							$nn++;
							if ($nn > $n_city-1)
								$nn = 0;
						}
	                                   // 評価(その4)
						$r = $this->Kyori($n_city, $this->kou1);
	
						if ($r > $max) {
							$max = $r;
							$sw  = 1;
							for ($i3 = 0; $i3 < $n_city; $i3++)
								$this->kou2[$i3] = $this->kou1[$i3];
							if ($this->sel > 0)
								$ch = 1;
    					}
    				}
				}
    
    			$n3++;
				if ($n3 > $n_city-3)
					$n3 = 0;
			}
		}
	                         // 設定
		if ($sw > 0) {
			$r_m = $max;
    		for ($i1 = 0; $i1 < $n_city; $i1++)
    			$seq[$i1] = $this->kou2[$i1];
    	}
	
		return $sw;
	}
	
	/**************/
	/* 近傍の探索 */
	/**************/
	function Kinbo()
	{
		$k           = 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) {
				$this->pi_w[$i1] = 2;
    			$sw              = 1;
    			$r               = $this->Kyori($this->len[$i1], $this->ind[$i1]);
				while ($sw > 0)
					$sw = $this->Change($this->len[$i1], $this->ind[$i1], $r);
				$this->pi[$i1] = $r;
			}
			if ($this->pi_w[$i1] > 0) {
				$k++;
				$this->mean += $this->pi[$i1];
    			if ($this->max_n < 0 || $this->pi[$i1] > $this->max) {
    				$this->max   = $this->pi[$i1];
    				$this->max_n = $i1;
				}
			}
		}
	
		if ($k > 0)
			$this->mean /= $k;
	}
	
	/*****************************/
	/* 結果の出力                */
	/*      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");
			}
					// 巡回順序の出力
			if ($this->out_m == 0) {
				for ($i1 = 0; $i1 < $this->len[$this->max_n]; $i1++) {
					$n = $this->ind[$this->max_n][$i1];
					fwrite($out, $n." ".$this->city[$n][0]." ".$this->city[$n][1]."\n");
					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);

			$tsp = new TSP($i_file1[$i1], $i_file2[$i1], $seed[$i1]);

			$tsp->Control();
		}
	}

//----------------ケーススタディデータ(data_ct.txt)------
/*
3
data1_t.txt data2_t.txt
data1_t.txt data2_t.txt
data1_t.txt data2_t.txt
*/

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

//---------------TSP記述データ(data2_t.txt)--------
/*
出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0
出力ファイル名 out1.txt 表示間隔 10
交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1
突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0
エリート 2 方法 1 バイアス 0 ステップ 1
都市数 10 最大世代交代数 2000
近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2
選択方法(0:最良,1:最初) 1
-58 37
55 -19
6 -79
27 -30
44 -94
33 -58
-94 87
-9 3
33 69
43 -57
*/

?>