ファジイ推論

  以下,複数のファイル構成になっています.ファイル間の区切りを「---・・・」で示します.makefile の部分は,make コマンドを使用してコンパイルする場合に必要となる makefile の例です.make を使用しない場合は必要ありません.

------------------------makefile------------------
#
#     リンク
#
CFLAGS = -c -Wall -O2
OBJECT = fz.o cons.o dest.o Cross.o Height.o Inf.o Result.o
pgm: $(OBJECT)
	g++ $(OBJECT) -o fz -lm
#
#     コンパイル
#
fz.o: fuzzy.h fz.cpp
	g++ $(CFLAGS) fz.cpp
cons.o: fuzzy.h cons.cpp
	g++ $(CFLAGS) cons.cpp
dest.o: fuzzy.h dest.cpp
	g++ $(CFLAGS) dest.cpp
Cross.o: fuzzy.h Cross.cpp
	g++ $(CFLAGS) Cross.cpp
Height.o: fuzzy.h Height.cpp
	g++ $(CFLAGS) Height.cpp
Inf.o: fuzzy.h Inf.cpp
	g++ $(CFLAGS) Inf.cpp
Result.o: fuzzy.h Result.cpp
	g++ $(CFLAGS) Result.cpp

------------------------規則ファイル--------------
推論方法 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

------------------------fuzzy.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 *);
};

------------------------constructor---------------
/************************************/
/* コンストラクタ                   */
/*      name : 入力データファイル名 */
/************************************/
#include <stdio.h>
#include "fuzzy.h"

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);
}

------------------------destructor----------------
/****************/
/* デストラクタ */
/****************/
#include "fuzzy.h"

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;
}

------------------------Cross.cpp----------------
/*******************************************/
/* 交点の計算                              */
/*      x : x                              */
/*      c : 中心                           */
/*      h : 幅                             */
/*      r : <0 : 左辺のメンバーシップ関数  */
/*          >=0 : 右辺(ω)                 */
/*      return : 交点                      */
/*******************************************/
#include "fuzzy.h"

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;
}

------------------------Height.cpp----------------
/**********************************************/
/* 右辺の計算                                 */
/*      x : 値                                */
/*      om[i] : <0 : i番目の規則を使用しない */
/*              >=0 : ωの値                  */
/*      return : xにおける右辺の値           */
/**********************************************/
#include "fuzzy.h"

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;
}

------------------------Inf.cpp-------------------
/**************************/
/* 推論の実行             */
/*      x[i] : 各変数の値 */
/*      return : 推論値   */
/**************************/
#include "fuzzy.h"

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;
}

------------------------Result.cpp----------------
/**********************************************/
/* 右辺による推論                             */
/*      om[i] : <0 : i番目の規則を使用しない */
/*              >=0 : ωの値                  */
/*      return : 推論値                       */
/**********************************************/
#include <stdio.h>
#include <math.h>
#include "fuzzy.h"

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----------------------
/****************************/
/* ファジイ推論             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>
#include <stdlib.h>
#include "fuzzy.h"

/****************/
/* 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;
}