Pull to refresh

Многокритериальный выбор альтернатив с использованием правил нечеткого вывода. Реализация на Java. Часть 3/3: Пример

Reading time6 min
Views7K
Предыдущие части:
  1. Многокритериальный выбор альтернатив с использованием правил нечеткого вывода. Часть 1/3: Теория
  2. Многокритериальный выбор альтернатив с использованием правил нечеткого вывода. Реализация на Java. Часть 2/3: Основной алгоритм


Пример взят из книги: Борисов, Крумберг, Федоров — «Принятие решений на основе нечетких моделей. Примеры использования», 1990. Стр. 94-102

Условие. Руководство института рассматривает кандидатов на замещение вакантной должности на факультете. Задача заключается в том, чтобы, используя описанный выше метод, выявить наилучшеrо из них. Обсуждение среди членов факультета дало следующий результат:
d1: «Если кандидат опытный исследователь, имеет некоторый производственныи стаж и опыт преподавания технических дисциплин, то он удовлетворяющий (отвечающий требованиям)»;

d2: «Если он вдобавок к вышеописанным требованиям может преподавать теорию информационных систем, то он более чем удовлетворяющий»;
d3: «Если он вдобавок к условиям d2 имеет способпость найти заказчика наукоемкой продукции, то он безупречный»;

d4: «Если оп имеет все, oгoвopeннoe в d3, кроме способности преподавать теорию информационных систем, то он очень удовлетворяющий»;
d5: «Если кандидат очень опытный исследователь, имеет способность найти заказчика и хороший преподаватель, но не имеет производственноrо стажа, он все же будет удовлетворяющим»;
d6: «Если он не имеет квалификации исследователя или не имеет проверенной способности к преподаванию, он — неудовлетворяющий».



Анализ шести информационных фраrментов дает пять критериев, используемых в принятии решения:
Х(1) — исследовательские способности;
Х(2) — производственный стаж
X(3) — опыт преподавания технических дисциплин;
Х(4) – опыт преподавания теории информационных систем
X(5) — способность наЙти заказчика.

Будем измерять эти переменные на базовом множестве U кандидатов. Обращансь к шести фрагментам, получаем:
image

Из строк A,B,C,D,E составляется матрица, передаваемая методу makeSkill класса input, реализующему интерфейс Input. Его описание изложено ниже (см. преобразование высказываний).

Нечеткие функции

После этого фрагменты знаний принимают вид:
d(1):“Если X=A, и B, и C, то Y=S”
d(2):”Если X=A, и B, и C, и D, то Y=MS”
d(3):”Если X=A, и B, и C, и D, и E, то Y=P”
d(4):”Если X=A, и B, иC, и E, то Y=VS”
d(5):”Если X — очень A, и не B, и C, и E, то Y=S”
d(6):”Если X= не А или не C, то Y=US”

В соответствии с вышеизложенным содержание функций в реализации:


package Function;

import Support.Function;

public class mMS extends Function { /*более, чем удовлетворяющий*/
    public mMS(){}

    public double getY(double x) {
        return x*Math.sqrt(x);
    }
}



package Function;

import Support.Function;

public class mP extends Function{ /*безупречный*/
    public mP(){}

    public double getY(double x) {
        if (x==1) return 1;
        return 0;
    }
}


package Function;

import Support.Function;

public class mVS extends Function{ /*очень удовлетворяющий*/
    public mVS(){}

    public double getY(double x) {
        return x*x;
    }
}


package Function;

import Support.Function;

public class mS extends Function { /*удовлетворяющий*/
    public mS(){}

    public double getY(double x) {
        return x;
    }
}


package Function;

import Support.Function;

public class mUS extends Function{ /*не удовлетворяющий*/
    public mUS(){}

    public double getY(double x) {
        return 1-x;
    }
}


Преобразование высказываний

Используя правило для преобразования этих высказываний, получаем

image

Класс Input, связывающий правило с требуемыми навыками, имеет вид:


package FLO_Engine;

import Support.Function;
import Support.Input;
import Support.Rule;
import Support.Skill;

public class input extends Input{

    private Skill A,B,C,D,E,A_M5,B_M5,A_M6,C_M6;
    
    public input(){ /* переменные для контроля количества параметров и функций */
        PARAMS_CNT = 5;
        FUNC_CNT   = 6;
    }

    public void initFunc(Function[] func){
        this.func = func;
    }

    private void makeSkill(double[][] arr){ /* подсчет навыков для создания правил; так как их объекты еще не созданы, использовать реализации Function нельзя и удобнее пересчитывать их значения вручную */
            
            rl = new Rule[FUNC_CNT];

            A = new Skill(arr[0]);
            B = new Skill(arr[1]);
            C = new Skill(arr[2]);
            D = new Skill(arr[3]);
            E = new Skill(arr[4]);

            double[][] u=arr;

            double[] a_m5 = (double[]) u[0].clone();
            for (int i=0;i<u[0].length;i++)
                a_m5[i]*=a_m5[i];       /*очень удовлетворяющий*/
            A_M5 = new Skill(a_m5);

            double[] b_m5 = (double[]) u[1].clone();
            for (int i=0;i<u[1].length;i++)
                b_m5[i]= 1 — b_m5[i];  /* не удовлетворяющий */
            B_M5 = new Skill(b_m5);

            double[] a_m6 = (double[]) u[0].clone();
            for (int i=0;i<u[0].length;i++)
                a_m6[i] = 1 — a_m6[i]; /* не удовлетворяющий */
            A_M6 = new Skill(a_m6);

            double[] c_m6 = (double[]) u[2].clone();
            for (int i=0;i<u[2].length;i++)
                c_m6[i] = 1 — c_m6[i]; /* не удовлетворяющий */
            C_M6 = new Skill(c_m6);

    }

    public Rule[] makeRules(double[][] arr) throws Exception{
        makeSkill(arr);
        
        rl[0] = new Rule(new Skill[]{A,B,C}          ,func[0]);  // высказывание d1
        rl[1] = new Rule(new Skill[]{A,B,C,D}        ,func[1]);  // высказывание d2
        rl[2] = new Rule(new Skill[]{A,B,C,D,E}      ,func[2]);  // высказывание d3
        rl[3] = new Rule(new Skill[]{A,B,C,E}        ,func[3]);  // высказывание d4
        rl[4] = new Rule(new Skill[]{A_M5,B_M5,C,E}  ,func[4]);  // высказывание d5
        rl[5] = new Rule(new Skill[]{A_M6,C_M6}      ,func[5]);  // высказывание d6
        
        return rl;
    }
}


Таким образом,
d(1): ”Если X=M(1), то Y=S”
d(2): ”Если X=M(2), то Y=MS”
d(3): ”Если X=M(3), то Y=P”
d(4): ”Если X=M(4), то Y=VS”
d(5): ”Если X=M(5), то Y=S”
d(6): ”Если X=M(6), то Y=US”

image

Вычисления

Используя соответствующее выражение, получаем матрицы D для каждого высказывания:
image
Результат работы кода:
D[1]:
0.5 0.60 0.70 0.80 0.9 1.0 1.0 1.0 1.0 1.0 1.0
0.4 0.50 0.60 0.70 0.8 0.9 1.0 1.0 1.0 1.0 1.0
0.5 0.60 0.70 0.80 0.9 1.0 1.0 1.0 1.0 1.0 1.0
0.9 1.00 1.00 1.00 1.0 1.0 1.0 1.0 1.0 1.0 1.0
0.7 0.79 0.89 1.00 1.0 1.0 1.0 1.0 1.0 1.0 1.0

image
D[2]:
0.5 0.53 0.58 0.66 0.75 0.85 0.96 1.0 1.0 1.0 1.0
0.7 0.73 0.78 0.86 0.95 1.00 1.00 1.0 1.0 1.0 1.0
0.5 0.53 0.58 0.66 0.75 0.85 0.96 1.0 1.0 1.0 1.0
0.9 0.93 0.98 1.00 1.00 1.00 1.00 1.0 1.0 1.0 1.0
0.7 0.73 0.78 0.86 0.95 1.00 1.00 1.0 1.0 1.0 1.0
Вот тут результаты не сходятся, но матлаб и инжереный калькулятор на моей стороне. Скорее всего, это просчет автора.

image
D[3]:
0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1.0
0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 1.0
0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1.0
0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 1.0
0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 1.0
Такая же история, вероятно, одна из функций при расчетах автора была с ошибкой.

image
D[4]:
0.5 0.51 0.54 0.59 0.66 0.75 0.86 0.99 1.0 1.0 1.0
0.5 0.51 0.54 0.59 0.66 0.75 0.86 0.99 1.0 1.0 1.0
0.5 0.51 0.54 0.59 0.66 0.75 0.86 0.99 1.0 1.0 1.0
0.9 0.91 0.94 0.99 1.00 1.00 1.00 1.00 1.0 1.0 1.0
0.9 0.91 0.94 0.99 1.00 1.00 1.00 1.00 1.0 1.0 1.0

image
D[5]:
0.50 0.6 0.7 0.8 0.9 1.0 1.0 1.0 1.0 1.0 1.0
1.00 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.00 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
0.99 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.00 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0

image
D[6]:
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.00 1.00 0.90 0.8
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.00 1.00 1.00 0.9
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.00 1.00 1.00 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.99 0.89 0.79 0.7
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.00 1.00 1.00 1.0

Общее функциональное решение D находится как пересечение нечетких множеств D(i):
image

D:
0.5 0.50 0.50 0.50 0.50 0.5 0.5 0.5 0.50 0.50 0.8
0.4 0.50 0.54 0.59 0.66 0.7 0.7 0.7 0.70 0.70 0.9
0.5 0.50 0.50 0.50 0.50 0.5 0.5 0.5 0.50 0.50 1.0
0.9 0.90 0.90 0.90 0.90 0.9 0.9 0.9 0.89 0.79 0.7
0.7 0.73 0.78 0.86 0.90 0.9 0.9 0.9 0.90 0.90 1.0

Возможная причина несовпадения результатов описана выше, далее сравнение с книгой идет для демонстрации общего хода решения, кто оказался «правильнее» — вопрос. Формулы одинаковые, но в мою пользу говорят эта реализация, матлаб, калькулятор; у автора же учебника на порядок больше опыта, но способ рассчета неизвестен — единственный найденный экземпляр книги датируется 1990м годом и нельзя исключать ту самую ошибку.

Подсчет точечных оценок

image

Мой результат:
Object #1:
E: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.8
X: 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Point estimate :0.6875

image
Object #2:
E: 0.4 0.5 0.54 0.59 0.66 0.7 0.7 0.7 0.7 0.7 0.9
X: 0.0 0.1 0.20 0.30 0.40 0.5 0.6 0.7 0.8 0.9 1.0
Point estimate :0.6561

image
Object #3:
E: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1.0
X: 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Point estimate :0.7500

image
Object #4:
E: 0.7 0.79 0.89 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9
X: 0.0 0.10 0.20 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Point estimate :0.4833

image
Object #5:
E: 0.7 0.73 0.78 0.86 0.9 0.9 0.9 0.9 0.9 0.9 1.0
X: 0.0 0.10 0.20 0.30 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Point estimate :0.5757308868523388

image

Очевидно, лучшей является третья альтернатива (оценка 0.75).
В книге лучшим признан второй кандидат (до округления его оценка была выше, чем у первого).

Исходники (проект из NetBeans 6.9.1): ifolder.ru
pass: habrahabr.ru
На всякий случай: исполняемый .jar лежит в папке \dist\
Tags:
Hubs:
+27
Comments14

Articles

Change theme settings