| 情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/
/* ファジイ推論 */
/* coded by Y.Suganuma */
/****************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*********************/
/* クラスFuzzyの定義 */
/*********************/
class Fuzzy {
double ***left; // [i][j][0] : 中心
// [1] : 幅
double **right; // [i][0] : 中心
// [1] : 幅
double *omega; // ωの値
int bun; // 積分の分割数
int method; // 推論方法
// =0 : and,or
// =1 : *,or
// =2 : *,+
int n_rule; // 規則の数
int n_val; // 変数の数
int **rule; // [i][j] =0 : i番目の規則はj番目の変数を使用しない
// =1 : i番目の規則はj番目の変数を使用する
public:
Fuzzy(char *); // コンストラクタ
~Fuzzy(); // デストラクタ
double Cross(double, double, double, double);
double Height(double, double *);
double Inf(double *); // 推論の実行
double Result(double *);
};
/************************************/
/* コンストラクタ */
/* name : 入力データファイル名 */
/************************************/
Fuzzy::Fuzzy(char *name)
{
int i1, i2;
FILE *in;
in = fopen(name, "r");
/*
基本データの入力
*/
fscanf(in, "%*s %d %*s %d %*s %d %*s %d",
&method, &n_rule, &n_val, &bun);
/*
領域の確保
*/
left = new double ** [n_rule];
right = new double * [n_rule];
omega = new double [n_rule];
rule = new int * [n_rule];
for (i1 = 0; i1 < n_rule; i1++) {
left[i1] = new double * [n_val];
right[i1] = new double [2];
rule[i1] = new int [n_val];
for (i2 = 0; i2 < n_val; i2++)
left[i1][i2] = new double [2];
}
/*
規則データの入力
*/
for (i1 = 0; i1 < n_rule; i1++) {
fscanf(in, "%*s");
// 左辺
for (i2 = 0; i2 < n_val; i2++) {
fscanf(in, "%*s %d", &(rule[i1][i2]));
if (rule[i1][i2] > 0)
fscanf(in, "%*s %lf %lf", &(left[i1][i2][0]), &(left[i1][i2][1]));
}
// 右辺
fscanf(in, "%*s %lf %lf", &(right[i1][0]), &(right[i1][1]));
}
fclose(in);
}
/****************/
/* デストラクタ */
/****************/
Fuzzy::~Fuzzy()
{
int i1, i2;
for (i1 = 0; i1 < n_rule; i1++) {
for (i2 = 0; i2 < n_val; i2++)
delete [] left[i1][i2];
delete [] left[i1];
delete [] right[i1];
delete [] rule[i1];
}
delete [] left;
delete [] right;
delete [] rule;
}
/*******************************************/
/* 交点の計算 */
/* x : x */
/* c : 中心 */
/* h : 幅 */
/* r : < 0 : 左辺のメンバーシップ関数 */
/* >=0 : 右辺(ω) */
/* return : 交点 */
/*******************************************/
double Fuzzy::Cross(double x, double c, double h, double r)
{
double x1, x2, y, y1, y2;
if (x < c) {
x1 = c - h;
x2 = c;
y1 = 0.0;
y2 = (r < 0.0 || (r >= 0.0 && method == 0)) ? 1.0 : r;
}
else {
x1 = c;
x2 = c + h;
y1 = (r < 0.0 || (r >= 0.0 && 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 && method == 0 && y > r)
y = r;
}
return y;
}
/**********************************************/
/* 右辺の計算 */
/* x : 値 */
/* om[i] : < 0 : i番目の規則を使用しない*/
/* >=0 : ωの値 */
/* return : xにおける右辺の値 */
/**********************************************/
double Fuzzy::Height(double x, double *om)
{
double y = 0.0, y1;
int i1, sw;
sw = 0;
for (i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
y1 = Cross(x, right[i1][0], right[i1][1], om[i1]);
if (sw == 0) {
y = y1;
sw = 1;
}
else {
if (method < 2) {
if (y1 > y)
y = y1;
}
else
y += y1;
}
}
}
return y;
}
/**************************/
/* 推論の実行 */
/* x[i] : 各変数の値 */
/* return : 推論値 */
/**************************/
double Fuzzy::Inf(double *x)
{
double x1, y;
int i1, i2;
/*
ωの計算
*/
for (i1 = 0; i1 < n_rule; i1++) {
omega[i1] = -1.0;
for (i2 = 0; i2 < n_val; i2++) {
if (rule[i1][i2] > 0) {
if (x[i2] > left[i1][i2][0]-left[i1][i2][1] &&
x[i2] < left[i1][i2][0]+left[i1][i2][1])
x1 = Cross(x[i2], left[i1][i2][0], left[i1][i2][1], -1.0);
else
x1 = 0.0;
if (omega[i1] < 0.0)
omega[i1] = x1;
else {
if (method == 0) {
if (x1 < omega[i1])
omega[i1] = x1;
}
else
omega[i1] *= x1;
}
}
}
}
/*
右辺の計算
*/
y = Result(omega);
return y;
}
/**********************************************/
/* 右辺による推論 */
/* om[i] : < 0 : i番目の規則を使用しない*/
/* >=0 : ωの値 */
/* return : 推論値 */
/**********************************************/
double Fuzzy::Result(double *om)
{
double h, max = 0.0, min = 0.0, x1, x2, y = 0.0, y1, y2, z1, z2;
int i1, sw;
/*
積分範囲と積分幅の計算
*/
sw = 0;
for (i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
x1 = right[i1][0] - right[i1][1];
x2 = right[i1][0] + 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) / bun;
if (h < 1.0e-15) {
printf("***error invalid data (h = 0) ***\n");
exit(1);
}
/*
積分(重心の計算,台形則)
*/
z1 = Height(min, om);
z2 = Height(max, om);
y1 = 0.5 * (min * z1 + max * z2);
y2 = 0.5 * (z1 + z2);
x1 = min;
for (i1 = 0; i1 < bun-1; i1++) {
x1 += h;
z1 = Height(x1, om);
y1 += x1 * z1;
y2 += z1;
}
y1 *= h;
y2 *= h;
if (fabs(y2) > 1.0e-10)
y = y1 / y2;
else {
printf("***error invalid data (y2 = 0) ***\n");
exit(1);
}
return y;
}
/****************/
/* main program */
/****************/
int main(int argc, char *argv[])
{
double *x, **xx, y;
int i1, i2, n_d, n_val;
FILE *in, *out;
if (argc == 4) {
// オブジェクトの生成
Fuzzy fz(argv[1]);
// 推論データの読み込み
in = fopen(argv[2], "r");
fscanf(in, "%*s %d %*s %d", &n_val, &n_d);
x = new double [n_val];
xx = new double * [n_val];
for (i1 = 0; i1 < n_val; i1++) {
fscanf(in, "%*s");
xx[i1] = new double [n_d];
for (i2 = 0; i2 < n_d; i2++)
fscanf(in, "%lf", &xx[i1][i2]);
}
fclose(in);
// 推論とその結果の出力
out = fopen(argv[3], "w");
for (i1 = 0; i1 < n_d; i1++) {
for (i2 = 0; i2 < n_val; i2++) {
x[i2] = xx[i2][i1];
fprintf(out, "%f ", x[i2]);
}
y = fz.Inf(x); // 推論
fprintf(out, "%f\n", y);
}
fclose(out);
}
else {
printf("***error 入力データファイル名を指定して下さい\n");
exit(1);
}
return 0;
}
/*
------------------------規則ファイル--------------
推論方法 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
*/
/****************************/
/* ファジイ推論 */
/* coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.StringTokenizer;
public class Test {
/****************/
/* main program */
/****************/
public static void main(String args[]) throws IOException, FileNotFoundException
{
double x[], xx[][], y;
int i1, i2, n_d, n_val;
StringTokenizer str;
// エラー
if (args.length != 3) {
System.out.print("***error 入力データファイル名を指定して下さい\n");
System.exit(1);
}
else {
// オブジェクトの生成
Fuzzy fz = new Fuzzy (args[0]);
// 推論データの読み込み
BufferedReader in = new BufferedReader(new FileReader(args[1]));
str = new StringTokenizer(in.readLine(), " ");
str.nextToken();
n_val = Integer.parseInt(str.nextToken());
str.nextToken();
n_d = Integer.parseInt(str.nextToken());
x = new double [n_val];
xx = new double [n_val][n_d];
for (i1 = 0; i1 < n_val; i1++) {
str = new StringTokenizer(in.readLine(), " ");
str.nextToken();
for (i2 = 0; i2 < n_d; i2++) {
if (!str.hasMoreTokens())
str = new StringTokenizer(in.readLine(), " ");
xx[i1][i2] = Double.parseDouble(str.nextToken());
}
}
in.close();
// 推論とその結果の出力
PrintStream out = new PrintStream(new FileOutputStream(args[2]));
for (i1 = 0; i1 < n_d; i1++) {
for (i2 = 0; i2 < n_val; i2++) {
x[i2] = xx[i2][i1];
out.print(x[i2] + " ");
}
y = fz.Inf(x); // 推論
out.println(y);
}
}
}
}
class Fuzzy {
private double left[][][]; // [i][j][0] : 中心
// [1] : 幅
private double right[][]; // [i][0] : 中心
// [1] : 幅
private double omega[]; // ωの値
private int bun; // 積分の分割数
private int method; // 推論方法
// =0 : and,or
// =1 : *,or
// =2 : *,+
private int n_rule; // 規則の数
private int n_val; // 変数の数
private int rule[][]; // [i][j] =0 : i番目の規則はj番目の変数を使用しない
// =1 : i番目の規則はj番目の変数を使用する
/************************************/
/* コンストラクタ */
/* name : 入力データファイル名 */
/************************************/
Fuzzy (String name) throws IOException, FileNotFoundException
{
int i1, i2;
StringTokenizer str;
BufferedReader in = new BufferedReader(new FileReader(name));
/*
基本データの入力
*/
str = new StringTokenizer(in.readLine(), " ");
str.nextToken();
method = Integer.parseInt(str.nextToken());
str.nextToken();
n_rule = Integer.parseInt(str.nextToken());
str.nextToken();
n_val = Integer.parseInt(str.nextToken());
str.nextToken();
bun = Integer.parseInt(str.nextToken());
/*
領域の確保
*/
left = new double [n_rule][n_val][2];
right = new double [n_rule][2];
omega = new double [n_rule];
rule = new int [n_rule][n_val];
/*
規則データの入力
*/
for (i1 = 0; i1 < n_rule; i1++) {
in.readLine();
// 左辺
for (i2 = 0; i2 < n_val; i2++) {
str = new StringTokenizer(in.readLine(), " ");
str.nextToken();
rule[i1][i2] = Integer.parseInt(str.nextToken());
if (rule[i1][i2] > 0) {
str.nextToken();
left[i1][i2][0] = Double.parseDouble(str.nextToken());
left[i1][i2][1] = Double.parseDouble(str.nextToken());
}
}
// 右辺
str = new StringTokenizer(in.readLine(), " ");
str.nextToken();
right[i1][0] = Double.parseDouble(str.nextToken());
right[i1][1] = Double.parseDouble(str.nextToken());
}
in.close();
}
/*******************************************/
/* 交点の計算 */
/* x : x */
/* c : 中心 */
/* h : 幅 */
/* r : <0 : 左辺のメンバーシップ関数 */
/* >=0 : 右辺(ω) */
/* return : 交点 */
/*******************************************/
double Cross(double x, double c, double h, double r)
{
double x1, x2, y, y1, y2;
if (x < c) {
x1 = c - h;
x2 = c;
y1 = 0.0;
y2 = (r < 0.0 || (r >= 0.0 && method == 0)) ? 1.0 : r;
}
else {
x1 = c;
x2 = c + h;
y1 = (r < 0.0 || (r >= 0.0 && 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 && method == 0 && y > r)
y = r;
}
return y;
}
/**********************************************/
/* 右辺の計算 */
/* x : 値 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : xにおける右辺の値 */
/**********************************************/
double Height(double x, double [] om)
{
double y = 0.0, y1;
int i1, sw;
sw = 0;
for (i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
y1 = Cross(x, right[i1][0], right[i1][1], om[i1]);
if (sw == 0) {
y = y1;
sw = 1;
}
else {
if (method < 2) {
if (y1 > y)
y = y1;
}
else
y += y1;
}
}
}
return y;
}
/**************************/
/* 推論の実行 */
/* x[i] : 各変数の値 */
/* return : 推論値 */
/**************************/
double Inf(double [] x)
{
double x1, y;
int i1, i2;
/*
ωの計算
*/
for (i1 = 0; i1 < n_rule; i1++) {
omega[i1] = -1.0;
for (i2 = 0; i2 < n_val; i2++) {
if (rule[i1][i2] > 0) {
if (x[i2] > left[i1][i2][0]-left[i1][i2][1] &&
x[i2] < left[i1][i2][0]+left[i1][i2][1])
x1 = Cross(x[i2], left[i1][i2][0], left[i1][i2][1], -1.0);
else
x1 = 0.0;
if (omega[i1] < 0.0)
omega[i1] = x1;
else {
if (method == 0) {
if (x1 < omega[i1])
omega[i1] = x1;
}
else
omega[i1] *= x1;
}
}
}
}
/*
右辺の計算
*/
y = Result(omega);
return y;
}
/**********************************************/
/* 右辺による推論 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : 推論値 */
/**********************************************/
double Result(double [] om)
{
double h, max = 0.0, min = 0.0, x1, x2, y = 0.0, y1, y2, z1, z2;
int i1, sw;
/*
積分範囲と積分幅の計算
*/
sw = 0;
for (i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
x1 = right[i1][0] - right[i1][1];
x2 = right[i1][0] + 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) / bun;
if (h < 1.0e-15) {
System.out.print("***error invalid data (h = 0) ***\n");
System.exit(1);
}
/*
積分(重心の計算,台形則)
*/
z1 = Height(min, om);
z2 = Height(max, om);
y1 = 0.5 * (min * z1 + max * z2);
y2 = 0.5 * (z1 + z2);
x1 = min;
for (i1 = 0; i1 < bun-1; i1++) {
x1 += h;
z1 = Height(x1, om);
y1 += x1 * z1;
y2 += z1;
}
y1 *= h;
y2 *= h;
if (Math.abs(y2) > 1.0e-10)
y = y1 / y2;
else {
System.out.print("***error invalid data (y2 = 0) ***\n");
System.exit(1);
}
return y;
}
}
/*
------------------------規則ファイル--------------
推論方法 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
*/
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>ファジー推論</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<SCRIPT TYPE="text/javascript">
res = "";
fz = null;
/****************/
/* main program */
/****************/
function main()
{
// オブジェクトの生成
fz = new Fuzzy();
// 推論データの読み込み
let lines = (document.getElementById("data2").value).split('\n');
let str = lines[0].split(' ').filter(function(e){return e.length > 0;});
let n_val = parseInt(str[1]);
let n_d = parseInt(str[3]);
let x = new Array(n_val);
let xx = new Array(n_val);
for (let i1 = 0; i1 < n_val; i1++) {
xx[i1] = new Array(n_d);
str = lines[i1+1].split(' ').filter(function(e){return e.length > 0;});
for (let i2 = 0; i2 < n_d; i2++)
xx[i1][i2] = parseFloat(str[i2+1]);
}
// 推論とその結果の出力
for (let i1 = 0; i1 < n_d; i1++) {
for (let i2 = 0; i2 < n_val; i2++) {
x[i2] = xx[i2][i1];
res += (x[i2] + " ");
}
let y = fz.Inf(x); // 推論
res += (y + "\n");
}
document.getElementById("result").value = res;
}
/**********************/
/* Fuzzy オブジェクト */
/**********************/
function Fuzzy ()
{
//
// 基本データの入力
//
let lines = (document.getElementById("data1").value).split('\n');
let str = lines[0].split(' ').filter(function(e){return e.length > 0;});
this.method = parseInt(str[1]);
this.n_rule = parseInt(str[3]);
this.n_val = parseInt(str[5]);
this.bun = parseInt(str[7]);
//
// 領域の確保
//
this.omega = new Array(this.n_rule); // ωの値
this.right = new Array(this.n_rule);
// [i][0] : 中心
// [1] : 幅
this.rule = new Array(this.n_rule);
// [i][j] =0 : i番目の規則はj番目の変数を使用しない
// =1 : i番目の規則はj番目の変数を使用する
this.left = new Array(this.n_rule);
// [i][j][0] : 中心
// [1] : 幅
for (let i1 = 0; i1 < this.n_rule; i1++) {
this.right[i1] = new Array(2);
this.rule[i1] = new Array(this.n_val);
this.left[i1] = new Array(this.n_val);
for (let i2 = 0; i2 < this.n_val; i2++)
this.left[i1][i2] = new Array(2);
}
//
// 規則データの入力
//
for (let i1 = 0; i1 < this.n_rule; i1++) {
// 左辺
for (let i2 = 0; i2 < this.n_val; i2++) {
str = lines[(this.n_val+2)*i1+i2+2].split(' ').filter(function(e){return e.length > 0;});
this.rule[i1][i2] = parseInt(str[1]);
if (this.rule[i1][i2] > 0) {
this.left[i1][i2][0] = parseFloat(str[3]);
this.left[i1][i2][1] = parseFloat(str[4]);
}
}
// 右辺
str = lines[(this.n_val+2)*i1+this.n_val+2].split(' ').filter(function(e){return e.length > 0;});
this.right[i1][0] = parseFloat(str[1]);
this.right[i1][1] = parseFloat(str[2]);
}
}
/*******************************************/
/* 交点の計算 */
/* x : x */
/* c : 中心 */
/* h : 幅 */
/* r : <0 : 左辺のメンバーシップ関数 */
/* >=0 : 右辺(ω) */
/* return : 交点 */
/*******************************************/
Fuzzy.prototype.Cross = function(x, c, h, r)
{
let x1, x2, y1, y2;
if (x < c) {
x1 = c - h;
x2 = c;
y1 = 0.0;
y2 = (r < 0.0 || (r >= 0.0 && fz.method == 0)) ? 1.0 : r;
}
else {
x1 = c;
x2 = c + h;
y1 = (r < 0.0 || (r >= 0.0 && fz.method == 0)) ? 1.0 : r;
y2 = 0.0;
}
let y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
if (y < 0.0)
y = 0.0;
else {
if (r >= 0.0 && fz.method == 0 && y > r)
y = r;
}
return y;
}
/**********************************************/
/* 右辺の計算 */
/* x : 値 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : xにおける右辺の値 */
/**********************************************/
Fuzzy.prototype.Height = function(x, om)
{
let y = 0.0;
let sw = 0;
for (let i1 = 0; i1 < fz.n_rule; i1++) {
if (om[i1] >= 0.0) {
let y1 = fz.Cross(x, fz.right[i1][0], fz.right[i1][1], om[i1]);
if (sw == 0) {
y = y1;
sw = 1;
}
else {
if (fz.method < 2) {
if (y1 > y)
y = y1;
}
else
y += y1;
}
}
}
return y;
}
/**************************/
/* 推論の実行 */
/* x[i] : 各変数の値 */
/* return : 推論値 */
/**************************/
Fuzzy.prototype.Inf = function(x)
{
//
// ωの計算
//
for (let i1 = 0; i1 < fz.n_rule; i1++) {
fz.omega[i1] = -1.0;
for (let i2 = 0; i2 < fz.n_val; i2++) {
if (fz.rule[i1][i2] > 0) {
let x1 = 0.0;
if (x[i2] > fz.left[i1][i2][0]-fz.left[i1][i2][1] &&
x[i2] < fz.left[i1][i2][0]+fz.left[i1][i2][1])
x1 = fz.Cross(x[i2], fz.left[i1][i2][0], fz.left[i1][i2][1], -1.0);
else
x1 = 0.0;
if (fz.omega[i1] < 0.0)
fz.omega[i1] = x1;
else {
if (fz.method == 0) {
if (x1 < fz.omega[i1])
fz.omega[i1] = x1;
}
else
fz.omega[i1] *= x1;
}
}
}
}
//
// 右辺の計算
//
let y = fz.Result(fz.omega);
return y;
}
/**********************************************/
/* 右辺による推論 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : 推論値 */
/**********************************************/
Fuzzy.prototype.Result = function(om)
{
//
// 積分範囲と積分幅の計算
//
let max = 0.0, min = 0.0, x1, x2, y = 0.0, y1, y2, z1, z2;
let sw = 0;
for (let i1 = 0; i1 < fz.n_rule; i1++) {
if (om[i1] >= 0.0) {
x1 = fz.right[i1][0] - fz.right[i1][1];
x2 = fz.right[i1][0] + fz.right[i1][1];
if (sw == 0) {
min = x1;
max = x2;
sw = 1;
}
else {
if (x1 < min)
min = x1;
if (x2 > max)
max = x2;
}
}
}
let h = (max - min) / fz.bun;
if (h < 1.0e-15)
alert("***error invalid data (h = 0) ***");
//
// 積分(重心の計算,台形則)
//
z1 = fz.Height(min, om);
z2 = fz.Height(max, om);
y1 = 0.5 * (min * z1 + max * z2);
y2 = 0.5 * (z1 + z2);
x1 = min;
for (let i1 = 0; i1 < fz.bun-1; i1++) {
x1 += h;
z1 = fz.Height(x1, om);
y1 += x1 * z1;
y2 += z1;
}
y1 *= h;
y2 *= h;
if (Math.abs(y2) > 1.0e-10)
y = y1 / y2;
else
alert("***error invalid data (y2 = 0) ***");
return y;
}
</SCRIPT>
</HEAD>
<BODY STYLE="font-size: 130%; text-align:center; background-color: #eeffee;">
<H2><B>ファジー推論</B></H2>
<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="return main()">実行</BUTTON><BR>
<DIV STYLE="width: 800px; margin-right: auto; margin-left: auto">
<DIV STYLE="text-align:center; float: right; width: 400px">
<DIV STYLE="text-align:center">推論ファイル</DIV>
<TEXTAREA ID="data2" COLS="40" ROWS="10" STYLE="font-size: 100%; width: 380px">
変数の数 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
</TEXTAREA>
</DIV>
<DIV STYLE="text-align:center; width: 400px">
<DIV STYLE="text-align:center">規則ファイル</DIV>
<TEXTAREA ID="data1" COLS="40" ROWS="10" STYLE="font-size: 100%; width: 380px">
推論方法 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
</TEXTAREA>
</DIV>
</DIV>
<DIV STYLE="text-align:center">推論結果</DIV>
<TEXTAREA ID="result" COLS="50" ROWS="10" STYLE="font-size: 100%;"></TEXTAREA>
</BODY>
</HTML>
<?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
*/
?>
############################
# ファジイ推論
# coded by Y.Suganuma
############################
############################
# クラスFuzzyの定義
# coded by Y.Suganuma
############################
class Fuzzy
#####################################
# コンストラクタ
# name : 入力データファイル名
#####################################
def initialize(name)
in_f = open(name, "r")
# 基本データの入力
s = in_f.gets().split(" ")
@_method = Integer(s[1]) # 推論方法
# =0 : and,or
# =1 : *,or
# =2 : *,+
@_n_rule = Integer(s[3]) # 規則の数
@_n_val = Integer(s[5]) # 変数の数
@_bun = Integer(s[7]) # 積分の分割数
# 領域の確保
@_omega = Array.new(@_n_rule) # ωの値
@_rule = Array.new(@_n_rule)
# [i][j] =0 : i番目の規則はj番目の変数を使用しない
# =1 : i番目の規則はj番目の変数を使用する
@_right = Array.new(@_n_rule)
# [i][0] : 中心
# [i][1] : 幅
@_left = Array.new(@_n_rule)
# [i][j][0] : 中心
# [i][j][1] : 幅
for i1 in 0 ... @_n_rule
@_rule[i1] = Array.new(@_n_val)
@_right[i1] = Array.new(2)
@_left[i1] = Array.new(@_n_rule)
for i2 in 0 ... @_n_rule
@_left[i1][i2] = Array.new(2)
end
end
# 規則データの入力
for i1 in 0 ... @_n_rule
in_f.gets()
# 左辺
for i2 in 0 ... @_n_val
s = in_f.gets().split(" ")
@_rule[i1][i2] = Integer(s[1])
if @_rule[i1][i2] > 0
@_left[i1][i2][0] = Float(s[3])
@_left[i1][i2][1] = Float(s[4])
end
end
# 右辺
s = in_f.gets().split(" ")
@_right[i1][0] = Float(s[1])
@_right[i1][1] = Float(s[2])
end
in_f.close()
end
###########################################
# 交点の計算
# x : x
# c : 中心
# h : 幅
# r : <0 : 左辺のメンバーシップ関数
# >=0 : 右辺(ω)
# return : 交点
###########################################
def Cross(x, c, h, r)
if x < c
x1 = c - h
x2 = c
y1 = 0.0
if r < 0.0 or (r >= 0.0 and @_method == 0)
y2 = 1.0
else
y2 = r
end
else
x1 = c
x2 = c + h
if r < 0.0 or (r >= 0.0 and @_method == 0)
y1 = 1.0
else
y1 = r
end
y2 = 0.0
end
y = y1 + (y2 - y1) * (x - x1) / (x2 - x1)
if y < 0.0
y = 0.0
else
if r >= 0.0 and @_method == 0 and y > r
y = r
end
end
return y
end
##############################################
# 右辺の計算
# x : 値
# om[i] : <0 : i番目の規則を使用しない
# >=0 : ωの値
# return : xにおける右辺の値
##############################################
def Height(x, om)
y = 0.0
sw = 0
for i1 in 0 ... @_n_rule
if om[i1] >= 0.0
y1 = Cross(x, @_right[i1][0], @_right[i1][1], om[i1])
if sw == 0
y = y1
sw = 1
else
if @_method < 2
if y1 > y
y = y1
end
else
y += y1
end
end
end
end
return y
end
##########################
# 推論の実行
# x[i] : 各変数の値
# return : 推論値
##########################
def Inf(x)
# ωの計算
for i1 in 0 ... @_n_rule
@_omega[i1] = -1.0
for i2 in 0 ... @_n_val
if @_rule[i1][i2] > 0
if x[i2] > @_left[i1][i2][0]-@_left[i1][i2][1] and x[i2] < @_left[i1][i2][0]+@_left[i1][i2][1]
x1 = Cross(x[i2], @_left[i1][i2][0], @_left[i1][i2][1], -1.0)
else
x1 = 0.0
end
if @_omega[i1] < 0.0
@_omega[i1] = x1
else
if @_method == 0
if x1 < @_omega[i1]
@_omega[i1] = x1
end
else
@_omega[i1] *= x1
end
end
end
end
end
# 右辺の計算
y = Result(@_omega)
return y
end
##############################################
# 右辺による推論
# om[i] : <0 : i番目の規則を使用しない
# >=0 : ωの値
# return : 推論値
##############################################
def Result(om)
max = 0.0
min = 0.0
y = 0.0
sw = 0
# 積分範囲と積分幅の計算
for i1 in 0 ... @_n_rule
if om[i1] >= 0.0
x1 = @_right[i1][0] - @_right[i1][1]
x2 = @_right[i1][0] + @_right[i1][1]
if sw == 0
min = x1
max = x2
sw = 1
else
if x1 < min
min = x1
end
if x2 > max
max = x2
end
end
end
end
h = (max - min) / @_bun
if h < 1.0e-15
print("***error invalid data (h = 0) ***\n")
end
# 積分(重心の計算,台形則)
z1 = Height(min, om)
z2 = Height(max, om)
y1 = 0.5 * (min * z1 + max * z2)
y2 = 0.5 * (z1 + z2)
x1 = min
for i1 in 0 ... @_bun-1
x1 += h
z1 = Height(x1, om)
y1 += x1 * z1
y2 += z1
end
y1 *= h
y2 *= h
if y2.abs() > 1.0e-10
y = y1 / y2
else
print("***error invalid data (y2 = 0) ***\n")
end
return y
end
end
if ARGV.length == 3
file1 = ARGV[0]
file2 = ARGV[1]
file3 = ARGV[2]
# オブジェクトの生成
fz = Fuzzy.new(file1)
# 推論データの読み込み
in_f = open(file2, "r")
s = in_f.gets().split(" ")
n_val = Integer(s[1])
n_d = Integer(s[3])
x = Array.new(n_val)
xx = Array.new(n_val)
for i1 in 0 ... n_val
xx[i1] = Array.new(n_d)
s = in_f.gets().split(" ")
for i2 in 0 ... n_d
xx[i1][i2] = Float(s[i2+1])
end
end
in_f.close()
# 推論とその結果の出力
out = open(file3, "w")
for i1 in 0 ... n_d
for i2 in 0 ... n_val
x[i2] = xx[i2][i1]
out.print(String(x[i2]) + " ")
end
y = fz.Inf(x) # 推論
out.print(String(y) + "\n")
end
out.close()
else
print("***error 入力データファイル名を指定して下さい\n")
end
=begin
------------------------規則ファイル--------------
推論方法 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
=end
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
from random import *
############################
# クラスFuzzyの定義
# coded by Y.Suganuma
############################
class Fuzzy :
#####################################
# コンストラクタ
# name : 入力データファイル名
#####################################
def __init__(self, name) :
in_f = open(name, "r")
# 基本データの入力
s = in_f.readline().split()
self.method = int(s[1]) # 推論方法
# =0 : and,or
# =1 : *,or
# =2 : *,+
self.n_rule = int(s[3]) # 規則の数
self.n_val = int(s[5]) # 変数の数
self.bun = int(s[7]) # 積分の分割数
# 領域の確保
self.omega = np.empty(self.n_rule, np.float) # ωの値
self.rule = np.empty((self.n_rule, self.n_val), np.int)
# [i][j] =0 : i番目の規則はj番目の変数を使用しない
# =1 : i番目の規則はj番目の変数を使用する
self.right = np.empty((self.n_rule, 2), np.float)
# [i][0] : 中心
# [i][1] : 幅
self.left = np.empty((self.n_rule, self.n_rule, 2), np.float)
# [i][j][0] : 中心
# [i][j][1] : 幅
# 規則データの入力
for i1 in range(0, self.n_rule) :
in_f.readline()
# 左辺
for i2 in range(0, self.n_val) :
s = in_f.readline().split()
self.rule[i1][i2] = int(s[1])
if self.rule[i1][i2] > 0 :
self.left[i1][i2][0] = float(s[3])
self.left[i1][i2][1] = float(s[4])
# 右辺
s = in_f.readline().split()
self.right[i1][0] = float(s[1])
self.right[i1][1] = float(s[2])
in_f.close()
###########################################
# 交点の計算
# x : x
# c : 中心
# h : 幅
# r : <0 : 左辺のメンバーシップ関数
# >=0 : 右辺(ω)
# return : 交点
###########################################
def Cross(self, x, c, h, r) :
if x < c :
x1 = c - h
x2 = c
y1 = 0.0
if r < 0.0 or (r >= 0.0 and self.method == 0) :
y2 = 1.0
else :
y2 = r
else :
x1 = c
x2 = c + h
if r < 0.0 or (r >= 0.0 and self.method == 0) :
y1 = 1.0
else :
y1 = r
y2 = 0.0
y = y1 + (y2 - y1) * (x - x1) / (x2 - x1)
if y < 0.0 :
y = 0.0
else :
if r >= 0.0 and self.method == 0 and y > r :
y = r
return y
##############################################
# 右辺の計算
# x : 値
# om[i] : <0 : i番目の規則を使用しない
# >=0 : ωの値
# return : xにおける右辺の値
##############################################
def Height(self, x, om) :
y = 0.0
sw = 0
for i1 in range(0, self.n_rule) :
if om[i1] >= 0.0 :
y1 = self.Cross(x, self.right[i1][0], self.right[i1][1], om[i1])
if sw == 0 :
y = y1
sw = 1
else :
if self.method < 2 :
if y1 > y :
y = y1
else :
y += y1
return y
##########################
# 推論の実行
# x[i] : 各変数の値
# return : 推論値
##########################
def Inf(self, x) :
# ωの計算
for i1 in range(0, self.n_rule) :
self.omega[i1] = -1.0
for i2 in range(0, self.n_val) :
if self.rule[i1][i2] > 0 :
if x[i2] > self.left[i1][i2][0]-self.left[i1][i2][1] and x[i2] < self.left[i1][i2][0]+self.left[i1][i2][1] :
x1 = self.Cross(x[i2], self.left[i1][i2][0], self.left[i1][i2][1], -1.0)
else :
x1 = 0.0
if self.omega[i1] < 0.0 :
self.omega[i1] = x1
else :
if self.method == 0 :
if x1 < self.omega[i1] :
self.omega[i1] = x1
else :
self.omega[i1] *= x1
# 右辺の計算
y = self.Result(self.omega)
return y
##############################################
# 右辺による推論
# om[i] : <0 : i番目の規則を使用しない
# >=0 : ωの値
# return : 推論値
##############################################
def Result(self, om) :
max = 0.0
min = 0.0
y = 0.0
sw = 0
# 積分範囲と積分幅の計算
for i1 in range(0, self.n_rule) :
if om[i1] >= 0.0 :
x1 = self.right[i1][0] - self.right[i1][1]
x2 = self.right[i1][0] + self.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) / self.bun
if h < 1.0e-15 :
print("***error invalid data (h = 0) ***")
# 積分(重心の計算,台形則)
z1 = self.Height(min, om)
z2 = self.Height(max, om)
y1 = 0.5 * (min * z1 + max * z2)
y2 = 0.5 * (z1 + z2)
x1 = min
for i1 in range(0, self.bun-1) :
x1 += h
z1 = self.Height(x1, om)
y1 += x1 * z1
y2 += z1
y1 *= h
y2 *= h
if abs(y2) > 1.0e-10 :
y = y1 / y2
else :
print("***error invalid data (y2 = 0) ***")
return y
############################
# ファジイ推論
# coded by Y.Suganuma
############################
if len(sys.argv) == 4 :
# オブジェクトの生成
fz = Fuzzy(sys.argv[1])
# 推論データの読み込み
in_f = open(sys.argv[2], "r")
s = in_f.readline().split()
n_val = int(s[1])
n_d = int(s[3])
x = np.empty(n_val, np.float)
xx = np.empty((n_val, n_d), np.float)
for i1 in range(0, n_val) :
s = in_f.readline().split()
for i2 in range(0, n_d) :
xx[i1][i2] = float(s[i2+1])
in_f.close()
# 推論とその結果の出力
out = open(sys.argv[3], "w")
for i1 in range(0, n_d) :
for i2 in range(0, n_val) :
x[i2] = xx[i2][i1]
out.write(str(x[i2]) + " ")
y = fz.Inf(x) # 推論
out.write(str(y) + "\n")
out.close()
else :
print("***error 入力データファイル名を指定して下さい")
"""
------------------------規則ファイル--------------
推論方法 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
"""
/****************************/
/* ファジイ推論 */
/* coded by Y.Suganuma */
/****************************/
using System;
using System.IO;
class Program
{
/****************/
/* main program */
/****************/
static void Main(String[] args)
{
// エラー
if (args.Length != 3) {
Console.WriteLine("***error 入力データファイル名を指定して下さい");
Environment.Exit(1);
}
else {
// オブジェクトの生成
Fuzzy fz = new Fuzzy (args[0]);
// 推論データの読み込み
char[] charSep = new char[] {' '};
String[] lines = File.ReadAllLines(args[1]);
String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
int n_val = int.Parse(str[1]);
int n_d = int.Parse(str[3]);
double[] x = new double [n_val];
double[][] xx = new double [n_val][];
for (int i1 = 0; i1 < n_val; i1++) {
xx[i1] = new double [n_d];
str = lines[i1+1].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
for (int i2 = 0; i2 < n_d; i2++)
xx[i1][i2] = double.Parse(str[i2+1]);
}
// 推論とその結果の出力
StreamWriter OUT = new StreamWriter(args[2]);
for (int i1 = 0; i1 < n_d; i1++) {
for (int i2 = 0; i2 < n_val; i2++) {
x[i2] = xx[i2][i1];
OUT.Write(x[i2] + " ");
}
double y = fz.Inf(x); // 推論
OUT.WriteLine(y);
}
OUT.Close();
}
}
}
class Fuzzy {
double[][][] left; // [i][j][0] : 中心
// [1] : 幅
double[][] right; // [i][0] : 中心
// [1] : 幅
double[] omega; // ωの値
int bun; // 積分の分割数
int method; // 推論方法
// =0 : and,or
// =1 : *,or
// =2 : *,+
int n_rule; // 規則の数
int n_val; // 変数の数
int[][] rule; // [i][j] =0 : i番目の規則はj番目の変数を使用しない
// =1 : i番目の規則はj番目の変数を使用する
/************************************/
/* コンストラクタ */
/* name : 入力データファイル名 */
/************************************/
public Fuzzy (String name)
{
char[] charSep = new char[] {' '};
String[] lines = File.ReadAllLines(name);
//
// 基本データの入力
//
String[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
method = int.Parse(str[1]);
n_rule = int.Parse(str[3]);
n_val = int.Parse(str[5]);
bun = int.Parse(str[7]);
//
// 領域の確保
//
omega = new double [n_rule];
right = new double [n_rule][];
rule = new int [n_rule][];
left = new double [n_rule][][];
for (int i1 = 0; i1 < n_rule; i1++) {
right[i1] = new double [2];
rule[i1] = new int [n_val];
left[i1] = new double [n_val][];
for (int i2 = 0; i2 < n_val; i2++)
left[i1][i2] = new double [2];
}
//
// 規則データの入力
//
for (int i1 = 0; i1 < n_rule; i1++) {
// 左辺
for (int i2 = 0; i2 < n_val; i2++) {
str = lines[(n_val+2)*i1+i2+2].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
rule[i1][i2] = int.Parse(str[1]);
if (rule[i1][i2] > 0) {
left[i1][i2][0] = double.Parse(str[3]);
left[i1][i2][1] = double.Parse(str[4]);
}
}
// 右辺
str = lines[(n_val+2)*i1+n_val+2].Split(charSep, StringSplitOptions.RemoveEmptyEntries);
right[i1][0] = double.Parse(str[1]);
right[i1][1] = double.Parse(str[2]);
}
}
/*******************************************/
/* 交点の計算 */
/* x : x */
/* c : 中心 */
/* h : 幅 */
/* r : <0 : 左辺のメンバーシップ関数 */
/* >=0 : 右辺(ω) */
/* return : 交点 */
/*******************************************/
double Cross(double x, double c, double h, double r)
{
double x1, x2, y1, y2;
if (x < c) {
x1 = c - h;
x2 = c;
y1 = 0.0;
y2 = (r < 0.0 || (r >= 0.0 && method == 0)) ? 1.0 : r;
}
else {
x1 = c;
x2 = c + h;
y1 = (r < 0.0 || (r >= 0.0 && method == 0)) ? 1.0 : r;
y2 = 0.0;
}
double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
if (y < 0.0)
y = 0.0;
else {
if (r >= 0.0 && method == 0 && y > r)
y = r;
}
return y;
}
/**********************************************/
/* 右辺の計算 */
/* x : 値 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : xにおける右辺の値 */
/**********************************************/
double Height(double x, double [] om)
{
double y = 0.0;
int sw = 0;
for (int i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
double y1 = Cross(x, right[i1][0], right[i1][1], om[i1]);
if (sw == 0) {
y = y1;
sw = 1;
}
else {
if (method < 2) {
if (y1 > y)
y = y1;
}
else
y += y1;
}
}
}
return y;
}
/**************************/
/* 推論の実行 */
/* x[i] : 各変数の値 */
/* return : 推論値 */
/**************************/
public double Inf(double[] x)
{
//
// ωの計算
//
for (int i1 = 0; i1 < n_rule; i1++) {
omega[i1] = -1.0;
for (int i2 = 0; i2 < n_val; i2++) {
if (rule[i1][i2] > 0) {
double x1 = 0.0;
if (x[i2] > left[i1][i2][0]-left[i1][i2][1] &&
x[i2] < left[i1][i2][0]+left[i1][i2][1])
x1 = Cross(x[i2], left[i1][i2][0], left[i1][i2][1], -1.0);
else
x1 = 0.0;
if (omega[i1] < 0.0)
omega[i1] = x1;
else {
if (method == 0) {
if (x1 < omega[i1])
omega[i1] = x1;
}
else
omega[i1] *= x1;
}
}
}
}
//
// 右辺の計算
//
double y = Result(omega);
return y;
}
/**********************************************/
/* 右辺による推論 */
/* om[i] : <0 : i番目の規則を使用しない */
/* >=0 : ωの値 */
/* return : 推論値 */
/**********************************************/
double Result(double [] om)
{
//
// 積分範囲と積分幅の計算
//
double max = 0.0, min = 0.0, x1, x2, y = 0.0, y1, y2, z1, z2;
int sw = 0;
for (int i1 = 0; i1 < n_rule; i1++) {
if (om[i1] >= 0.0) {
x1 = right[i1][0] - right[i1][1];
x2 = right[i1][0] + right[i1][1];
if (sw == 0) {
min = x1;
max = x2;
sw = 1;
}
else {
if (x1 < min)
min = x1;
if (x2 > max)
max = x2;
}
}
}
double h = (max - min) / bun;
if (h < 1.0e-15) {
Console.WriteLine("***error invalid data (h = 0) ***");
Environment.Exit(1);
}
//
// 積分(重心の計算,台形則)
//
z1 = Height(min, om);
z2 = Height(max, om);
y1 = 0.5 * (min * z1 + max * z2);
y2 = 0.5 * (z1 + z2);
x1 = min;
for (int i1 = 0; i1 < bun-1; i1++) {
x1 += h;
z1 = Height(x1, om);
y1 += x1 * z1;
y2 += z1;
}
y1 *= h;
y2 *= h;
if (Math.Abs(y2) > 1.0e-10)
y = y1 / y2;
else {
Console.WriteLine("***error invalid data (y2 = 0) ***");
Environment.Exit(1);
}
return y;
}
}
/*
------------------------規則ファイル--------------
推論方法 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
*/
'**************************'
' ファジイ推論 '
' coded by Y.Suganuma '
'**************************'
Imports System.IO
Imports System.Text.RegularExpressions
Module Test
Sub Main(args() As String)
' エラー
If args.Length <> 3
Console.WriteLine("***error 入力データファイル名を指定して下さい")
Environment.Exit(1)
Else
' オブジェクトの生成
Dim fz As Fuzzy = new Fuzzy (args(0))
' 推論データの読み込み
Dim inp As StreamReader = New StreamReader(args(1))
Dim MS As Regex = New Regex("\s+")
Dim str() As String = MS.Split(inp.ReadLine().Trim())
Dim n_val As Integer = Integer.Parse(str(1))
Dim n_d As Integer = Integer.Parse(str(3))
Dim x(n_val) As Double
Dim xx(n_val,n_d) As Double
For i1 As Integer = 0 To n_val-1
str = MS.Split(inp.ReadLine().Trim())
For i2 As Integer = 0 To n_d-1
xx(i1,i2) = Double.Parse(str(i2+1))
Next
Next
inp.Close()
' 推論とその結果の出力
Dim OUT As StreamWriter = new StreamWriter(args(2))
For i1 As Integer = 0 To n_d-1
For i2 As Integer = 0 To n_val-1
x(i2) = xx(i2,i1)
OUT.Write(x(i2) & " ")
Next
Dim y As Double = fz.Inf(x) ' 推論
OUT.WriteLine(y)
Next
OUT.Close()
End If
End Sub
Class Fuzzy
Private left(,,) As Double ' (i,j,0) : 中心
' (i,j,1) : 幅
Private right(,) As Double ' (i,0) : 中心
' (i,1) : 幅
Private omega() As Double ' ωの値
Private bun As Integer ' 積分の分割数
Private method As Integer ' 推論方法
' =0 : and,or
' =1 : *,or
' =2 : *,+
Private n_rule As Integer ' 規則の数
Private n_val As Integer ' 変数の数
Private rule(,) As Integer ' (i,j) =0 : i番目の規則はj番目の変数を使用しない
' =1 : i番目の規則はj番目の変数を使用する
'**********************************'
' コンストラクタ '
' name : 入力データファイル名 '
'**********************************'
Public Sub New(name As String)
'
' 基本データの入力
'
Dim inp As StreamReader = New StreamReader(name)
Dim MS As Regex = New Regex("\s+")
Dim str() As String = MS.Split(inp.ReadLine().Trim())
method = Integer.Parse(str(1))
n_rule = Integer.Parse(str(3))
n_val = Integer.Parse(str(5))
bun = Integer.Parse(str(7))
'
' 領域の確保
'
ReDim omega(n_rule)
ReDim right(n_rule,2)
ReDim rule(n_rule,n_val)
ReDim left(n_rule,n_val,2)
'
' 規則データの入力
'
For i1 As Integer = 0 To n_rule-1
inp.ReadLine()
' 左辺
For i2 As Integer = 0 To n_val-1
str = MS.Split(inp.ReadLine().Trim())
rule(i1,i2) = Integer.Parse(str(1))
If rule(i1,i2) > 0
left(i1,i2,0) = Double.Parse(str(3))
left(i1,i2,1) = Double.Parse(str(4))
End If
Next
' 右辺
str = MS.Split(inp.ReadLine().Trim())
right(i1,0) = Double.Parse(str(1))
right(i1,1) = Double.Parse(str(2))
Next
inp.Close()
End Sub
'*****************************************'
' 交点の計算 '
' x : x '
' c : 中心 '
' h : 幅 '
' r : <0 : 左辺のメンバーシップ関数 '
' >=0 : 右辺(ω) '
' return : 交点 '
'*****************************************'
Function Cross(x As Double, c As Double, h As Double, r As Double)
Dim x1 As Double
Dim x2 As Double
Dim y1 As Double
Dim y2 As Double
If x < c
x1 = c - h
x2 = c
y1 = 0.0
If r < 0.0 or (r >= 0.0 and method = 0)
y2 = 1.0
Else
y2 = r
End If
Else
x1 = c
x2 = c + h
if r < 0.0 or (r >= 0.0 and method = 0)
y1 = 1.0
Else
y1 = r
End If
y2 = 0.0
End If
Dim y As Double = y1 + (y2 - y1) * (x - x1) / (x2 - x1)
If y < 0.0
y = 0.0
Else
If r >= 0.0 and method = 0 and y > r
y = r
End If
End If
Return y
End Function
'********************************************'
' 右辺の計算 '
' x : 値 '
' om(i) : <0 : i番目の規則を使用しない '
' >=0 : ωの値 '
' return : xにおける右辺の値 '
'********************************************'
Function Height(x As Double, om() As Double)
Dim y As Double = 0.0
Dim sw As Integer = 0
For i1 As Integer = 0 To n_rule-1
If om(i1) >= 0.0
Dim y1 As Double = Cross(x, right(i1,0), right(i1,1), om(i1))
If sw = 0
y = y1
sw = 1
Else
If method < 2
If y1 > y
y = y1
End If
Else
y += y1
End If
End If
End If
Next
Return y
End Function
'************************'
' 推論の実行 '
' x(i) : 各変数の値 '
' return : 推論値 '
'************************'
Function Inf(x() As Double)
'
' ωの計算
'
For i1 As Integer = 0 To n_rule-1
omega(i1) = -1.0
For i2 As Integer = 0 To n_val-1
If rule(i1,i2) > 0
Dim x1 As Double = 0.0
If x(i2) > left(i1,i2,0)-left(i1,i2,1) and x(i2) < left(i1,i2,0)+left(i1,i2,1)
x1 = Cross(x(i2), left(i1,i2,0), left(i1,i2,1), -1.0)
Else
x1 = 0.0
End If
If omega(i1) < 0.0
omega(i1) = x1
Else
If method = 0
If x1 < omega(i1)
omega(i1) = x1
End If
Else
omega(i1) *= x1
End If
End If
End If
Next
Next
'
' 右辺の計算
'
Dim y As Double = Result(omega)
Return y
End Function
'********************************************'
' 右辺による推論 '
' om(i) : <0 : i番目の規則を使用しない '
' >=0 : ωの値 '
' return : 推論値 '
'********************************************'
Function Result(om() As Double)
'
' 積分範囲と積分幅の計算
'
Dim max As Double = 0.0
Dim min As Double = 0.0
Dim x1 As Double
Dim x2 As Double
Dim y As Double = 0.0
Dim y1 As Double
Dim y2 As Double
Dim z1 As Double
Dim z2 As Double
Dim sw As Integer = 0
For i1 As Integer = 0 To n_rule-1
If om(i1) >= 0.0
x1 = right(i1,0) - right(i1,1)
x2 = right(i1,0) + right(i1,1)
If sw = 0
min = x1
max = x2
sw = 1
Else
If x1 < min
min = x1
End If
If x2 > max
max = x2
End If
End If
End If
Next
Dim h As Double = (max - min) / bun
If h < 1.0e-15
Console.WriteLine("***error invalid data (h = 0) ***")
Environment.Exit(1)
End If
'
' 積分(重心の計算,台形則)
'
z1 = Height(min, om)
z2 = Height(max, om)
y1 = 0.5 * (min * z1 + max * z2)
y2 = 0.5 * (z1 + z2)
x1 = min
For i1 As Integer = 0 To bun-2
x1 += h
z1 = Height(x1, om)
y1 += x1 * z1
y2 += z1
Next
y1 *= h
y2 *= h
If Math.Abs(y2) > 1.0e-10
y = y1 / y2
Else
Console.WriteLine("***error invalid data (y2 = 0) ***")
Environment.Exit(1)
End If
Return y
End Function
End Class
End Module
/*
------------------------規則ファイル--------------
推論方法 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
*/
| 情報学部 | 菅沼ホーム | 目次 | 索引 |