技術とか戦略とか

証券レガシーシステムを8年いじってから転職した普通の文系SEによるブログ。技術のみではなく趣味の戦略考察についても。

ファジィ推論をjavaでやってみた

ファジィ推論」とは、「高い」「重い」「暑い」等の数値では表せない感覚的なものを数値として表すことでコンピュータ制御を行うAI技術です。
現在は、洗濯機・エアコンといったの家電や、地下鉄の自動運転等に応用されています。
 
今回は、こちらのページで解説されているファジィ推論javaで実装してみました。
 
静岡理工科大学情報学部コンピュータシステム学科・知能インタラクション研究室 - ファジイ推論
http://www.sist.ac.jp/~kanakubo/research/reasoning_kr/fuzzy.html
 
実装に際しては、下記ページを参考にしています。
 
SoftComputing lab. - ファジィ推論
http://ix9.jp/softcomputing/fuzzy-rcpg.shtml
 
稚拙な実装となっていることを始めにお断りしておきます。
ただ、ごく簡単な実装でもファジィ推論は実現できるという意味で、参考になるかもしれません。
 
ソースコード
・FussyMain.java
public class FussyMain {
    public static void main(String[] args){

        // 実行時の引数から気温と湿度を取得
        double temperature = Float.parseFloat(args[0]);
        double humidity = Float.parseFloat(args[1]);

        // 適合度の変数定義
        // (「あまり暑くない」「かなり暑い」「湿度が低い」「湿度が高い」)
        FussyMember fussyMember = FussyMember.getInstance();
        double notHotDegree = 0;
        double tooHotDegree = 0;
        double lowHumidityDegree = 0;
        double highHumidityDegree = 0;

        // 適合度計算
        notHotDegree = fussyMember.notHotCalc(temperature);
        tooHotDegree = fussyMember.tooHotCalc(temperature);
        lowHumidityDegree = fussyMember.lowHumidityCalc(humidity);
        highHumidityDegree = fussyMember.highHumidityCalc(humidity);
        System.out.println("■適合度計算");
        System.out.println("・あまり暑くない:"+notHotDegree);
        System.out.println("・かなり暑い:"+tooHotDegree);
        System.out.println("・湿度が低い:"+lowHumidityDegree);
        System.out.println("・湿度が高い:"+highHumidityDegree);

        // 非ファジィ化の変数定義
        // ルール① もし、かなり暑くて、湿度が高ければ、室温を下げる
        // ルール② もし、あまり暑くなくて、湿度が高ければ、室温はそのまま
        // ルール③ もし、かなり暑くて、湿度が低ければ、室温はそのまま
        // ルール④ もし、あまり暑くなくて、湿度が低ければ、室温を上げる
        UnFussyLogic unFussyLogic = UnFussyLogic.getInstance();
        double rule1Degree = 0;
        double rule2Degree = 0;
        double rule3Degree = 0;
        double rule4Degree = 0;
        double toLowDegree = 0;
        double toMiddleDegree = 0;
        double toHighDegree = 0;
        double temperatureCentor = 0;

        // 各ルールの前件部の計算
        rule1Degree = unFussyLogic.andCalc(tooHotDegree, highHumidityDegree);
        rule2Degree = unFussyLogic.andCalc(notHotDegree, highHumidityDegree);
        rule3Degree = unFussyLogic.andCalc(tooHotDegree, lowHumidityDegree);
        rule4Degree = unFussyLogic.andCalc(notHotDegree, lowHumidityDegree);
        System.out.println("■前件部計算");
        System.out.println("・ルール①:"+rule1Degree);
        System.out.println("・ルール②:"+rule2Degree);
        System.out.println("・ルール③:"+rule3Degree);
        System.out.println("・ルール④:"+rule4Degree);

        // 各ルールの後件部の計算
        toLowDegree = rule1Degree;
        toMiddleDegree = unFussyLogic.orCalc(rule2Degree, rule3Degree);
        toHighDegree = rule4Degree;
        temperatureCentor =
            unFussyLogic.centerCalc(toLowDegree,toMiddleDegree,toHighDegree);
        System.out.println("■後件部計算");
        System.out.println("・室温を下げるグレード:"+toLowDegree);
        System.out.println("・室温はそのままグレード:"+toMiddleDegree);
        System.out.println("・室温を上げるグレード:"+toHighDegree);
        System.out.println("・室温の変化値:"+temperatureCentor);

    }
}

・FussyMember.java
public class FussyMember {

    // 適合度計算用クラス。Singletonとする。
    private static FussyMember fussyMember = new FussyMember();
    public static FussyMember getInstance(){
        return fussyMember;
    }

    public double notHotCalc (double temperature) {
        double degree = 0;
        double lowLimit = 12;
        double highLimit = 30;

        // 温度が12度以下の場合は「あまり暑くない」の適合度=1
        if (temperature <= lowLimit) {
            degree = 1;
        // 温度が12度~30度の場合は「あまり暑くない」の適合度は0~1
        } else if(temperature > lowLimit && temperature < highLimit) {
            degree = 1 - ((temperature - lowLimit)/(highLimit - lowLimit));
        // 温度が30度以上の場合は「あまり暑くない」の適合度=0
        } else {
            degree = 0;
        }

        return degree;
    }

    public double tooHotCalc (double temperature) {
        double degree = 0;
        double lowLimit = 20;
        double highLimit = 39;

        // 温度が20度以下の場合は「かなり暑い」の適合度=0
        if (temperature <= lowLimit) {
            degree = 0;
        // 温度が20度~39度の場合は「かなり暑い」の適合度は0~1
        } else if(temperature > lowLimit && temperature < highLimit) {
            degree = 0 + ((temperature - lowLimit)/(highLimit - lowLimit));
        // 温度が39度以上の場合は「かなり暑い」の適合度=1
        } else {
            degree = 1;
        }

        return degree;
    }

    public double lowHumidityCalc (double humidity) {
        double degree = 0;
        double lowLimit = 0;
        double highLimit = 40;

        // 湿度が0%以下の場合は「湿度が低い」の適合度=1
        if (humidity <= lowLimit) {
            degree = 1;
        // 湿度が0%~40%の場合は「湿度が低い」の適合度は0~1
        } else if(humidity > lowLimit && humidity < highLimit) {
            degree = 1 - ((humidity - lowLimit)/(highLimit - lowLimit));
        // 湿度が40%以上の場合は「湿度が低い」の適合度=0
        } else {
            degree = 0;
        }

        return degree;
    }

    public double highHumidityCalc (double humidity) {
        double degree = 0;
        double lowLimit = 60;
        double highLimit = 100;

        // 湿度が60%以下の場合は「湿度が高い」の適合度=0
        if (humidity <= lowLimit) {
            degree = 0;
        // 湿度が60%~100%の場合は「湿度が高い」の適合度は0~1
        } else if(humidity > lowLimit && humidity < highLimit) {
            degree = 0 + ((humidity - lowLimit)/(highLimit - lowLimit));
        // 湿度が100%以上の場合は「湿度が高い」の適合度=1
        } else {
            degree = 1;
        }

        return degree;
    }
}

・UnFussyLogic.java
public class UnFussyLogic {

    // 非ファジィ化用クラス。Singletonとする。
    private static UnFussyLogic unFussyLogic = new UnFussyLogic();
    public static UnFussyLogic getInstance(){
        return unFussyLogic;
    }

    // AND/OR演算メソッド
    public double andCalc (double a,double b) {
        if (a > b) {
            a = b;
        }
        return (a);
    }
    public double orCalc (double a,double b) {
        if (a < b) {
            a = b;
        }
        return (a);
    }

    // 重心算出メソッド
    public double centerCalc
    (double toLowDegree,double toMiddleDegree,double toHighDegree) {

        // 0.25単位(49段階)で離散化
        double[] temperatureList = {-6,-5.75,-5.5,-5.25,  -5,-4.75,-4.5,-4.25,  -4,-3.75,-3.5,-3.25,-3,-2.75,-2.5,-2.25,  -2,-1.75,-1.5,-1.25,  -1,-0.75, 0.5,-0.25,0,0.25, 0.5,0.75,   1,1.25, 1.5,1.75,   2,2.25, 2.5,2.75,3,3.25, 3.5,3.75,   4,4.25,4.5,4.75,   5,5.25, 5.5,5.75,6};
        double[] toLowList       = { 0, 0.08,0.17, 0.25,0.33, 0.42, 0.5, 0.58,0.67, 0.75,0.83, 0.92, 1, 0.92,0.83, 0.75,0.67, 0.58, 0.5, 0.42,0.33, 0.25,0.17, 0.08,0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,0,   0,   0,   0,   0,   0,  0,   0,   0,   0,   0,   0,0};
        double[
] toMiddleList    = { 0,    0,   0,    0,   0,    0,   0,    0,   0,    0,   0,    0, 0,    0,   0,    0,   0, 0.13,0.25, 0.38, 0.5, 0.63,0.75, 0.88,1,0.88,0.75,0.63, 0.5,0.38,0.25,0.13,   0,   0,   0,   0,0,   0,   0,   0,   0,   0,  0,   0,   0,   0,   0,   0,0};
        double[] toHighList      = { 0,    0,   0,    0,   0,    0,   0,    0,   0,    0,   0,    0, 0,    0,   0,    0,   0,    0,   0,    0,   0,    0,   0,    0,0,0.08,0.17,0.25,0.33,0.42, 0.5,0.58,0.67,0.75,0.83,0.92,1,0.92,0.83,0.75,0.67,0.58,0.5,0.42,0.33,0.25,0.17,0.08,0};

        // ファジィ集合の定義
        double toLowSet = 0;
        double toMiddleSet = 0;
        double toHighSet = 0;
        double toSynthesisSet = 0;

        // 重心の計算で使用する変数の定義
        int stepNum = 49;
        double sum = 0;
        double den = 0;
        double centor = 0;

        // 重心の計算
        for (int i = 0;i < stepNum;i++) {

            // 頭切り
            toLowSet = andCalc(toLowDegree,toLowList[i]);
            toMiddleSet = andCalc(toMiddleDegree,toMiddleList[i]);
            toHighSet = andCalc(toHighDegree,toHighList[i]);

            // ファジィ集合の合成
            toSynthesisSet = orCalc(orCalc(toLowSet,toMiddleSet),toHighSet);

            // 重心の途中計算
            sum = sum + (toSynthesisSet * temperatureList[i]);
            den = den + toSynthesisSet;

        }

        centor = sum / den;
        return centor;
    }
}
 
【実行結果】 ※気温(第1引数)が28、湿度(第2引数)が70の場合
■適合度計算
・あまり暑くない:0.11111111111111116
・かなり暑い:0.42105263157894735
・湿度が低い:0.0
・湿度が高い:0.25
■前件部計算
・ルール①:0.25
・ルール②:0.11111111111111116
・ルール③:0.0
・ルール④:0.0
■後件部計算
・室温を下げるグレード:0.25
・室温はそのままグレード:0.11111111111111116
・室温を上げるグレード:0.0
・室温の変化値:-2.400324149108591