From ab9a60cdd2fe991c053052bdeda156f3a3255238 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Thu, 7 Sep 2023 16:06:37 +0400 Subject: [PATCH] #8 -- Add some fuzzy --- .../controller/InferenceMvcController.java | 8 +- .../rule/service/FuzzyInferenceService.java | 191 ++++++++++-------- 2 files changed, 117 insertions(+), 82 deletions(-) diff --git a/src/main/java/ru/ulstu/fc/rule/controller/InferenceMvcController.java b/src/main/java/ru/ulstu/fc/rule/controller/InferenceMvcController.java index 1a9d616..1875bc8 100644 --- a/src/main/java/ru/ulstu/fc/rule/controller/InferenceMvcController.java +++ b/src/main/java/ru/ulstu/fc/rule/controller/InferenceMvcController.java @@ -8,12 +8,18 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import ru.ulstu.fc.rule.model.Antecedent; import ru.ulstu.fc.rule.model.InferenceForm; +import ru.ulstu.fc.rule.service.FuzzyInferenceService; import java.util.Arrays; import java.util.List; @Controller public class InferenceMvcController { + private final FuzzyInferenceService fuzzyInferenceService; + + public InferenceMvcController(FuzzyInferenceService fuzzyInferenceService) { + this.fuzzyInferenceService = fuzzyInferenceService; + } @GetMapping("/") public String initInference(Model model) { @@ -28,7 +34,7 @@ public class InferenceMvcController { model.addAttribute("ageAntecedents", getAgeAntecedents()); model.addAttribute("incomeAntecedents", getIncomeAntecedents()); model.addAttribute("inferenceForm", inferenceForm); - model.addAttribute("response", "123"); + model.addAttribute("response", fuzzyInferenceService.getFuzzyInference().get(0)); return "index"; } diff --git a/src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java b/src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java index 70a9746..0c16b4c 100644 --- a/src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java +++ b/src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java @@ -1,84 +1,115 @@ package ru.ulstu.fc.rule.service; import com.fuzzylite.Engine; +import com.fuzzylite.activation.General; +import com.fuzzylite.defuzzifier.Centroid; +import com.fuzzylite.norm.s.Maximum; +import com.fuzzylite.norm.t.AlgebraicProduct; +import com.fuzzylite.norm.t.Minimum; +import com.fuzzylite.rule.Rule; +import com.fuzzylite.rule.RuleBlock; import com.fuzzylite.term.Activated; +import com.fuzzylite.term.Triangle; import com.fuzzylite.variable.InputVariable; import com.fuzzylite.variable.OutputVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.stream.Collectors; @Service public class FuzzyInferenceService { private final static Logger LOG = LoggerFactory.getLogger(FuzzyInferenceService.class); - private final static String OUTPUT_VARIABLE_NAME = "state"; + private final static String OUTPUT_VARIABLE_NAME = "кредит"; private final static String RULE_TEMPLATE = "if %s is %s and %s is %s then " + OUTPUT_VARIABLE_NAME + " is %s"; private final static String NO_RESULT = "Нет результата"; -// private List mapRulesToString(List dbRules) { -// return dbRules.stream().map(this::getFuzzyRule).collect(Collectors.toList()); -// } + private Map>> inputFuzzyTerms = Map.of( + "возраст", + List.of( + new AbstractMap.SimpleEntry("молодой", 35), + new AbstractMap.SimpleEntry("средний", 60), + new AbstractMap.SimpleEntry("старый", 100)), + "доход", + List.of( + new AbstractMap.SimpleEntry("небольшой", 35000), + new AbstractMap.SimpleEntry("средний", 100000), + new AbstractMap.SimpleEntry("высокий", 500000))); -// private String getFuzzyRule(DbRule dbRule) { -// return format(RULE_TEMPLATE, -// dbRule.getFirstAntecedent().name(), -// dbRule.getFirstAntecedentValue().getAntecedentValue(), -// dbRule.getSecondAntecedent().name(), -// dbRule.getSecondAntecedentValue().getAntecedentValue(), -// dbRule.getId()); -// } + private Map>> outputFuzzyTerms = Map.of( + "кредит", List.of(new AbstractMap.SimpleEntry("небольшой", 200000), + new AbstractMap.SimpleEntry("средний", 100000), + new AbstractMap.SimpleEntry("большой", 1000000))); -// private RuleBlock getRuleBlock(Engine engine, -// List dbRules, -// Map variableValues, -// List antecedentValues, -// List consequentValues) { -// variableValues.forEach((key, value) -> { -// InputVariable input = new InputVariable(); -// input.setName(key); -// input.setDescription(""); -// input.setEnabled(true); -// input.setRange(-1, 1); -// input.setLockValueInRange(false); -// input.addTerm(new Triangle("спад", -1, 0)); -// input.addTerm(new Triangle("стабильно", -0.1, 0.1)); -// input.addTerm(new Triangle("рост", 0, 1)); -// engine.addInputVariable(input); -// }); -// -// OutputVariable output = new OutputVariable(); -// output.setName(OUTPUT_VARIABLE_NAME); -// output.setDescription(""); -// output.setEnabled(true); -// output.setRange(0, consequentValues.size() + 0.1); -// output.setAggregation(new Maximum()); -// output.setDefuzzifier(new Centroid(10)); -// output.setDefaultValue(Double.NaN); -// output.setLockValueInRange(false); -// for (int i = 0; i < consequentValues.size(); i++) { -// output.addTerm(new Triangle(consequentValues.get(i).toString(), i, i + 1)); -// } -// engine.addOutputVariable(output); -// -// RuleBlock mamdani = new RuleBlock(); -// mamdani.setName("mamdani"); -// mamdani.setDescription(""); -// mamdani.setEnabled(true); -// mamdani.setConjunction(new Minimum()); -// //mamdani.setDisjunction(null); -// mamdani.setImplication(new AlgebraicProduct()); -// mamdani.setActivation(new General()); -// mapRulesToString(dbRules).forEach(r -> { -// LOG.info(r); -// mamdani.addRule(Rule.parse(r, engine)); -// }); -// return mamdani; -// } + private List getDemoRules() { + return List.of( + String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "высокий", "большой"), + String.format(RULE_TEMPLATE, "возраст", "средний", "доход", "высокий", "средний"), + String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "высокий", "средний") + ); + } + + private List getInputVariables() { + return List.of(getInputVariable("возраст", inputFuzzyTerms.get("возраст")), + getInputVariable("доход", inputFuzzyTerms.get("доход"))); + } + + private InputVariable getInputVariable(String name, List> terms) { + final InputVariable input = new InputVariable(); + input.setName(name); + input.setDescription(""); + input.setEnabled(true); + input.setLockValueInRange(false); + double prev = 0; + for (int i = 0; i < terms.size(); i++) { + Triangle term = new Triangle(terms.get(i).getKey(), prev, terms.get(i).getValue()); + prev = term.getVertexB(); + input.addTerm(term); + } + return input; + } + + private > OutputVariable getOutputVariable(String name, List> terms) { + final OutputVariable output = new OutputVariable(); + output.setName(name); + output.setDescription(""); + output.setEnabled(true); + output.setAggregation(new Maximum()); + output.setDefuzzifier(new Centroid(10)); + output.setDefaultValue(Double.NaN); + output.setLockValueInRange(false); + double prev = 0; + for (int i = 0; i < terms.size(); i++) { + Triangle term = new Triangle(terms.get(i).getKey(), prev, terms.get(i).getValue()); + prev = term.getVertexB(); + output.addTerm(term); + } + return output; + } + + private RuleBlock getRuleBlock(Engine engine, + List rules) { + getInputVariables().forEach(engine::addInputVariable); + engine.addOutputVariable(getOutputVariable("кредит", outputFuzzyTerms.get("кредит"))); + + RuleBlock mamdani = new RuleBlock(); + mamdani.setName("mamdani"); + mamdani.setDescription(""); + mamdani.setEnabled(true); + mamdani.setConjunction(new Minimum()); + mamdani.setImplication(new AlgebraicProduct()); + mamdani.setActivation(new General()); + rules.forEach(r -> mamdani.addRule(Rule.parse(r, engine))); + return mamdani; + } private Engine getFuzzyEngine() { Engine engine = new Engine(); @@ -87,29 +118,6 @@ public class FuzzyInferenceService { return engine; } -// public List getFuzzyInference(List dbRules, -// List antecedentValues, -// Map variableValues) { -// validateVariables(variableValues, dbRules); -// variableValues.entrySet().forEach(e -> System.out.println(e.getKey() + " " + e.getValue())); -// Engine engine = getFuzzyEngine(); -// List consequentValues = dbRules.stream().map(DbRule::getId).collect(Collectors.toList()); -// engine.addRuleBlock(getRuleBlock(engine, dbRules, variableValues, antecedentValues, consequentValues)); -// Map consequents = getConsequent(engine, variableValues); -// if (consequents.containsKey(NO_RESULT)) { -// return new ArrayList<>(); -// } -// List assessments = new ArrayList<>(); -// for (Map.Entry consequent : consequents.entrySet()) { -// for (DbRule dbRule : dbRules) { -// if (dbRule.getId().equals(Integer.valueOf(consequent.getKey()))) { -// assessments.add(new Assessment(dbRule, consequent.getValue())); -// } -// } -// } -// return assessments; -// } - private Map getConsequent(Engine engine, Map variableValues) { OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME); for (Map.Entry variableValue : variableValues.entrySet()) { @@ -124,4 +132,25 @@ public class FuzzyInferenceService { ? Map.of(NO_RESULT, 0.0) : outputVariable.fuzzyOutput().getTerms().stream().collect(Collectors.toMap(t -> t.getTerm().getName(), Activated::getDegree)); } + + public List getFuzzyInference() { + //variableValues.entrySet().forEach(e -> System.out.println(e.getKey() + " " + e.getValue())); + Engine engine = getFuzzyEngine(); + //List consequentValues = dbRules.stream().map(DbRule::getId).collect(Collectors.toList()); + engine.addRuleBlock(getRuleBlock(engine, getDemoRules())); + Map consequents = getConsequent(engine, Map.of("возраст", 20.0, "доход", 250000.0)); + if (consequents.containsKey(NO_RESULT)) { + return new ArrayList<>(); + } + /*List assessments = new ArrayList<>(); + for (Map.Entry consequent : consequents.entrySet()) { + for (DbRule dbRule : dbRules) { + if (dbRule.getId().equals(Integer.valueOf(consequent.getKey()))) { + assessments.add(new Assessment(dbRule, consequent.getValue())); + } + } + }*/ + return List.of(0.0); + } + }