<?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
*/
?>