<?php /****************************/ /* ファジイ推論 */ /* coded by Y.Suganuma */ /****************************/ /*********************/ /* クラスFuzzyの定義 */ /*********************/ class Fuzzy { private $left; // [i][j][0] : 中心 // [1] : 幅 private $right; // [i][0] : 中心 // [1] : 幅 private $omega; // ωの値 private $bun; // 積分の分割数 private $method; // 推論方法 // =0 : and,or // =1 : *,or // =2 : *,+ private $n_rule; // 規則の数 private $n_val; // 変数の数 private $rule; // [i][j] =0 : i番目の規則はj番目の変数を使用しない // =1 : i番目の規則はj番目の変数を使用する /************************************/ /* コンストラクタ */ /* name : 入力データファイル名 */ /************************************/ function Fuzzy($name) { $in = fopen($name, "r"); /* 基本データの入力 */ fscanf($in, "%*s %d %*s %d %*s %d %*s %d", $this->method, $this->n_rule, $this->n_val, $this->bun); /* 領域の確保 */ $this->left = array($this->n_rule); $this->right = array($this->n_rule); $this->omega = array($this->n_rule); $this->rule = array($this->n_rule); for ($i1 = 0; $i1 < $this->n_rule; $i1++) { $this->left[$i1] = array($this->n_val); $this->right[$i1] = array(2); $this->rule[$i1] = array($this->n_val); for ($i2 = 0; $i2 < $this->n_val; $i2++) $this->left[$i1][$i2] = array(2); } /* 規則データの入力 */ for ($i1 = 0; $i1 < $this->n_rule; $i1++) { fgets($in); // 左辺 for ($i2 = 0; $i2 < $this->n_val; $i2++) { $str = trim(fgets($in)); strtok($str, " "); $this->rule[$i1][$i2] = intval(strtok(" ")); if ($this->rule[$i1][$i2] > 0) { strtok(" "); $this->left[$i1][$i2][0] = floatval(strtok(" ")); $this->left[$i1][$i2][1] = floatval(strtok(" ")); } } // 右辺 fscanf($in, "%*s %lf %lf", $this->right[$i1][0], $this->right[$i1][1]); } fclose($in); } /*******************************************/ /* 交点の計算 */ /* x : x */ /* c : 中心 */ /* h : 幅 */ /* r : <0 : 左辺のメンバーシップ関数 */ /* >=0 : 右辺(ω) */ /* return : 交点 */ /*******************************************/ function Cross($x, $c, $h, $r) { if ($x < $c) { $x1 = $c - $h; $x2 = $c; $y1 = 0.0; $y2 = ($r < 0.0 || ($r >= 0.0 && $this->method == 0)) ? 1.0 : $r; } else { $x1 = $c; $x2 = $c + $h; $y1 = ($r < 0.0 || ($r >= 0.0 && $this->method == 0)) ? 1.0 : $r; $y2 = 0.0; } $y = $y1 + ($y2 - $y1) * ($x - $x1) / ($x2 - $x1); if ($y < 0.0) $y = 0.0; else { if ($r >= 0.0 && $this->method == 0 && $y > $r) $y = $r; } return $y; } /**********************************************/ /* 右辺の計算 */ /* x : 値 */ /* om[i] : <0 : i番目の規則を使用しない */ /* >=0 : ωの値 */ /* return : xにおける右辺の値 */ /**********************************************/ function Height($x, $om) { $y = 0.0; $sw = 0; for ($i1 = 0; $i1 < $this->n_rule; $i1++) { if ($om[$i1] >= 0.0) { $y1 = $this->Cross($x, $this->right[$i1][0], $this->right[$i1][1], $om[$i1]); if ($sw == 0) { $y = $y1; $sw = 1; } else { if ($this->method < 2) { if ($y1 > $y) $y = $y1; } else $y += $y1; } } } return $y; } /**************************/ /* 推論の実行 */ /* x[i] : 各変数の値 */ /* return : 推論値 */ /**************************/ function Inf($x) { /* ωの計算 */ for ($i1 = 0; $i1 < $this->n_rule; $i1++) { $this->omega[$i1] = -1.0; for ($i2 = 0; $i2 < $this->n_val; $i2++) { if ($this->rule[$i1][$i2] > 0) { if ($x[$i2] > $this->left[$i1][$i2][0]-$this->left[$i1][$i2][1] && $x[$i2] < $this->left[$i1][$i2][0]+$this->left[$i1][$i2][1]) $x1 = $this->Cross($x[$i2], $this->left[$i1][$i2][0], $this->left[$i1][$i2][1], -1.0); else $x1 = 0.0; if ($this->omega[$i1] < 0.0) $this->omega[$i1] = $x1; else { if ($this->method == 0) { if ($x1 < $this->omega[$i1]) $this->omega[$i1] = $x1; } else $this->omega[$i1] *= $x1; } } } } /* 右辺の計算 */ $y = $this->Result($this->omega); return $y; } /**********************************************/ /* 右辺による推論 */ /* om[i] : <0 : i番目の規則を使用しない */ /* >=0 : ωの値 */ /* return : 推論値 */ /**********************************************/ function Result($om) { $max = 0.0; $min = 0.0; $y = 0.0; $sw = 0; /* 積分範囲と積分幅の計算 */ for ($i1 = 0; $i1 < $this->n_rule; $i1++) { if ($om[$i1] >= 0.0) { $x1 = $this->right[$i1][0] - $this->right[$i1][1]; $x2 = $this->right[$i1][0] + $this->right[$i1][1]; if ($sw == 0) { $min = $x1; $max = $x2; $sw = 1; } else { if ($x1 < $min) $min = $x1; if ($x2 > $max) $max = $x2; } } } $h = ($max - $min) / $this->bun; if ($h < 1.0e-15) exit("***error invalid data (h = 0) ***\n"); /* 積分(重心の計算,台形則) */ $z1 = $this->Height($min, $om); $z2 = $this->Height($max, $om); $y1 = 0.5 * ($min * $z1 + $max * $z2); $y2 = 0.5 * ($z1 + $z2); $x1 = $min; for ($i1 = 0; $i1 < $this->bun-1; $i1++) { $x1 += $h; $z1 = $this->Height($x1, $om); $y1 += $x1 * $z1; $y2 += $z1; } $y1 *= $h; $y2 *= $h; if (abs($y2) > 1.0e-10) $y = $y1 / $y2; else exit("***error invalid data (y2 = 0) ***\n"); return $y; } } /****************/ /* main program */ /****************/ if (count($argv) == 4) { // オブジェクトの生成 $fz = new Fuzzy($argv[1]); // 推論データの読み込み $in = fopen($argv[2], "rb"); fscanf($in, "%*s %d %*s %d", $n_val, $n_d); $x = array($n_val); $xx = array($n_val); for ($i1 = 0; $i1 < $n_val; $i1++) { $xx[$i1] = array($n_d); $str = trim(fgets($in)); strtok($str, " "); for ($i2 = 0; $i2 < $n_d; $i2++) $xx[$i1][$i2] = floatval(strtok(" ")); } fclose($in); // 推論とその結果の出力 $out = fopen($argv[3], "w"); for ($i1 = 0; $i1 < $n_d; $i1++) { $str = ""; for ($i2 = 0; $i2 < $n_val; $i2++) { $x[$i2] = $xx[$i2][$i1]; $str = $str.$x[$i2]." "; } $y = $fz->Inf($x); // 推論 $str = $str."res ".$y."\n"; fwrite($out, $str); } fclose($out); } else exit("***error 入力データファイル名を指定して下さい\n"); /* ------------------------規則ファイル-------------- 推論方法 0 規則の数 3 変数の数 1 積分の分割数 100 規則1 変数1 1 中心と幅 1.0 1.0 右辺(中心と幅) 1.0 15.0 規則2 変数1 1 中心と幅 2.0 1.0 右辺(中心と幅) 11.0 15.0 規則3 変数1 1 中心と幅 3.0 1.0 右辺(中心と幅) 21.0 15.0 ------------------------推論ファイル-------------- 変数の数 1 データ数 21 変数1 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 */ ?>