#8 -- Fix fuzzy conclusions
This commit is contained in:
parent
f3710b6680
commit
e885a78bff
@ -59,7 +59,6 @@ dependencies {
|
|||||||
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
|
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
|
||||||
implementation group: 'com.h2database', name:'h2'
|
implementation group: 'com.h2database', name:'h2'
|
||||||
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
|
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||||
implementation group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0'
|
|
||||||
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
|
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
|
||||||
|
|
||||||
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
|
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package ru.ulstu.fc.rule.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.ulstu.fc.rule.model.InferenceData;
|
||||||
|
import ru.ulstu.fc.rule.model.OutputValue;
|
||||||
|
import ru.ulstu.fc.rule.service.FuzzyInferenceService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("rest")
|
||||||
|
public class InferenceRestController {
|
||||||
|
private final FuzzyInferenceService fuzzyInferenceService;
|
||||||
|
|
||||||
|
public InferenceRestController(FuzzyInferenceService fuzzyInferenceService) {
|
||||||
|
this.fuzzyInferenceService = fuzzyInferenceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "get-inference", method = RequestMethod.POST)
|
||||||
|
public List<OutputValue> getInference(@RequestBody InferenceData inferenceData) {
|
||||||
|
return fuzzyInferenceService.getFuzzyInference(inferenceData.getRules(),
|
||||||
|
inferenceData.getValues(),
|
||||||
|
inferenceData.getInputVariables(),
|
||||||
|
inferenceData.getOutputVariable());
|
||||||
|
}
|
||||||
|
}
|
43
src/main/java/ru/ulstu/fc/rule/model/InferenceData.java
Normal file
43
src/main/java/ru/ulstu/fc/rule/model/InferenceData.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class InferenceData {
|
||||||
|
private List<String> rules;
|
||||||
|
private Map<String, Double> values;
|
||||||
|
private List<Variable> inputVariables;
|
||||||
|
private Variable outputVariable;
|
||||||
|
|
||||||
|
public List<String> getRules() {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRules(List<String> rules) {
|
||||||
|
this.rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Double> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValues(Map<String, Double> values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Variable> getInputVariables() {
|
||||||
|
return inputVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputVariables(List<Variable> inputVariables) {
|
||||||
|
this.inputVariables = inputVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable getOutputVariable() {
|
||||||
|
return outputVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputVariable(Variable outputVariable) {
|
||||||
|
this.outputVariable = outputVariable;
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/ru/ulstu/fc/rule/model/OutputValue.java
Normal file
27
src/main/java/ru/ulstu/fc/rule/model/OutputValue.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
public class OutputValue {
|
||||||
|
private String fuzzyTerm;
|
||||||
|
private Double degree;
|
||||||
|
|
||||||
|
public OutputValue(String fuzzyTerm, Double degree) {
|
||||||
|
this.fuzzyTerm = fuzzyTerm;
|
||||||
|
this.degree = degree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFuzzyTerm() {
|
||||||
|
return fuzzyTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFuzzyTerm(String fuzzyTerm) {
|
||||||
|
this.fuzzyTerm = fuzzyTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getDegree() {
|
||||||
|
return degree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDegree(Double degree) {
|
||||||
|
this.degree = degree;
|
||||||
|
}
|
||||||
|
}
|
24
src/main/java/ru/ulstu/fc/rule/model/Variable.java
Normal file
24
src/main/java/ru/ulstu/fc/rule/model/Variable.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Variable {
|
||||||
|
private String name;
|
||||||
|
private List<VariableValue> values;
|
||||||
|
|
||||||
|
public Variable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable(String name, List<VariableValue> values) {
|
||||||
|
this.name = name;
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VariableValue> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
30
src/main/java/ru/ulstu/fc/rule/model/VariableValue.java
Normal file
30
src/main/java/ru/ulstu/fc/rule/model/VariableValue.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
public class VariableValue {
|
||||||
|
private String fuzzyTerm;
|
||||||
|
private Double value;
|
||||||
|
|
||||||
|
public VariableValue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableValue(String fuzzyTerm, Double value) {
|
||||||
|
this.fuzzyTerm = fuzzyTerm;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFuzzyTerm() {
|
||||||
|
return fuzzyTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFuzzyTerm(String fuzzyTerm) {
|
||||||
|
this.fuzzyTerm = fuzzyTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -2,24 +2,24 @@ package ru.ulstu.fc.rule.service;
|
|||||||
|
|
||||||
import com.fuzzylite.Engine;
|
import com.fuzzylite.Engine;
|
||||||
import com.fuzzylite.activation.General;
|
import com.fuzzylite.activation.General;
|
||||||
import com.fuzzylite.defuzzifier.Centroid;
|
import com.fuzzylite.defuzzifier.WeightedAverage;
|
||||||
import com.fuzzylite.norm.s.Maximum;
|
import com.fuzzylite.norm.s.Maximum;
|
||||||
import com.fuzzylite.norm.t.AlgebraicProduct;
|
import com.fuzzylite.norm.t.AlgebraicProduct;
|
||||||
import com.fuzzylite.norm.t.Minimum;
|
import com.fuzzylite.norm.t.Minimum;
|
||||||
import com.fuzzylite.rule.Rule;
|
import com.fuzzylite.rule.Rule;
|
||||||
import com.fuzzylite.rule.RuleBlock;
|
import com.fuzzylite.rule.RuleBlock;
|
||||||
import com.fuzzylite.term.Activated;
|
|
||||||
import com.fuzzylite.term.Triangle;
|
import com.fuzzylite.term.Triangle;
|
||||||
import com.fuzzylite.variable.InputVariable;
|
import com.fuzzylite.variable.InputVariable;
|
||||||
import com.fuzzylite.variable.OutputVariable;
|
import com.fuzzylite.variable.OutputVariable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.ulstu.fc.rule.model.OutputValue;
|
||||||
|
import ru.ulstu.fc.rule.model.Variable;
|
||||||
|
import ru.ulstu.fc.rule.model.VariableValue;
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -31,65 +31,52 @@ public class FuzzyInferenceService {
|
|||||||
+ " is %s";
|
+ " is %s";
|
||||||
private final static String NO_RESULT = "Нет результата";
|
private final static String NO_RESULT = "Нет результата";
|
||||||
|
|
||||||
private Map<String, List<Entry<String, Integer>>> 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 Map<String, List<Entry<String, Integer>>> outputFuzzyTerms = Map.of(
|
|
||||||
"кредит", List.of(new AbstractMap.SimpleEntry("небольшой", 20000),
|
|
||||||
new AbstractMap.SimpleEntry("средний", 100000),
|
|
||||||
new AbstractMap.SimpleEntry("большой", 1000000)));
|
|
||||||
|
|
||||||
private List<String> getDemoRules() {
|
private List<String> getDemoRules() {
|
||||||
return List.of(
|
return List.of(
|
||||||
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "высокий", "большой"),
|
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "высокий", "большой"),
|
||||||
String.format(RULE_TEMPLATE, "возраст", "средний", "доход", "высокий", "средний"),
|
String.format(RULE_TEMPLATE, "возраст", "средний", "доход", "высокий", "средний"),
|
||||||
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "высокий", "средний")
|
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "высокий", "средний"),
|
||||||
|
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "небольшой", "небольшой"),
|
||||||
|
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "небольшой", "небольшой")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InputVariable> getInputVariables() {
|
private InputVariable getInputVariable(Variable variable) {
|
||||||
return List.of(getInputVariable("возраст", inputFuzzyTerms.get("возраст")),
|
|
||||||
getInputVariable("доход", inputFuzzyTerms.get("доход")));
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputVariable getInputVariable(String name, List<Entry<String, Integer>> terms) {
|
|
||||||
final InputVariable input = new InputVariable();
|
final InputVariable input = new InputVariable();
|
||||||
input.setName(name);
|
input.setName(variable.getName());
|
||||||
input.setDescription("");
|
input.setDescription("");
|
||||||
input.setRange(0, terms.get(terms.size() - 1).getValue());
|
input.setRange(0, variable.getValues().get(variable.getValues().size() - 1).getValue());
|
||||||
input.setEnabled(true);
|
input.setEnabled(true);
|
||||||
input.setLockValueInRange(false);
|
input.setLockValueInRange(false);
|
||||||
double prev = 0;
|
double prev = 0;
|
||||||
for (int i = 0; i < terms.size(); i++) {
|
for (int i = 0; i < variable.getValues().size(); i++) {
|
||||||
Triangle term = new Triangle(terms.get(i).getKey(), prev, terms.get(i).getValue());
|
Triangle term = new Triangle(variable.getValues().get(i).getFuzzyTerm(),
|
||||||
|
prev,
|
||||||
|
variable.getValues().get(i).getValue(),
|
||||||
|
variable.getValues().get(i).getValue() + variable.getValues().get(i).getValue() - prev);
|
||||||
prev = term.getVertexB();
|
prev = term.getVertexB();
|
||||||
input.addTerm(term);
|
input.addTerm(term);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Enum<T>> OutputVariable getOutputVariable(String name, List<Entry<String, Integer>> terms) {
|
private <T extends Enum<T>> OutputVariable getOutputVariable(Variable variable) {
|
||||||
final OutputVariable output = new OutputVariable();
|
final OutputVariable output = new OutputVariable();
|
||||||
output.setName(name);
|
output.setName(variable.getName());
|
||||||
output.setDescription("");
|
output.setDescription("");
|
||||||
output.setRange(0, terms.get(terms.size() - 1).getValue());
|
output.setRange(0, variable.getValues().get(variable.getValues().size() - 1).getValue());
|
||||||
output.setEnabled(true);
|
output.setEnabled(true);
|
||||||
output.setAggregation(new Maximum());
|
output.setAggregation(new Maximum());
|
||||||
output.setDefuzzifier(new Centroid(terms.get(terms.size() - 1).getValue()));
|
output.setDefuzzifier(new WeightedAverage());
|
||||||
output.setDefaultValue(Double.NaN);
|
output.setDefaultValue(Double.NaN);
|
||||||
output.setLockValueInRange(false);
|
output.setLockValueInRange(false);
|
||||||
double prev = 0;
|
double prev = 0;
|
||||||
for (int i = 0; i < terms.size(); i++) {
|
for (int i = 0; i < variable.getValues().size(); i++) {
|
||||||
Triangle term = new Triangle(terms.get(i).getKey(), prev, terms.get(i).getValue());
|
Triangle term = new Triangle(
|
||||||
|
variable.getValues().get(i).getFuzzyTerm(),
|
||||||
|
prev,
|
||||||
|
variable.getValues().get(i).getValue(),
|
||||||
|
variable.getValues().get(i).getValue() + variable.getValues().get(i).getValue() - prev);
|
||||||
prev = term.getVertexB();
|
prev = term.getVertexB();
|
||||||
output.addTerm(term);
|
output.addTerm(term);
|
||||||
}
|
}
|
||||||
@ -97,9 +84,11 @@ public class FuzzyInferenceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RuleBlock getRuleBlock(Engine engine,
|
private RuleBlock getRuleBlock(Engine engine,
|
||||||
List<String> rules) {
|
List<String> rules,
|
||||||
getInputVariables().forEach(engine::addInputVariable);
|
List<Variable> inputVariables,
|
||||||
engine.addOutputVariable(getOutputVariable("кредит", outputFuzzyTerms.get("кредит")));
|
Variable outputVariable) {
|
||||||
|
inputVariables.stream().map(this::getInputVariable).forEach(engine::addInputVariable);
|
||||||
|
engine.addOutputVariable(getOutputVariable(outputVariable));
|
||||||
|
|
||||||
RuleBlock mamdani = new RuleBlock();
|
RuleBlock mamdani = new RuleBlock();
|
||||||
mamdani.setName("mamdani");
|
mamdani.setName("mamdani");
|
||||||
@ -119,7 +108,7 @@ public class FuzzyInferenceService {
|
|||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Double> getConsequent(Engine engine, Map<String, Double> variableValues) {
|
private List<OutputValue> getConsequent(Engine engine, Map<String, Double> variableValues) {
|
||||||
OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME);
|
OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME);
|
||||||
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
|
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
|
||||||
InputVariable inputVariable = engine.getInputVariable(variableValue.getKey());
|
InputVariable inputVariable = engine.getInputVariable(variableValue.getKey());
|
||||||
@ -130,14 +119,40 @@ public class FuzzyInferenceService {
|
|||||||
LOG.info("Output: {}", outputVariable.getValue());
|
LOG.info("Output: {}", outputVariable.getValue());
|
||||||
}
|
}
|
||||||
return Double.isNaN(outputVariable.getValue())
|
return Double.isNaN(outputVariable.getValue())
|
||||||
? Map.of(NO_RESULT, 0.0)
|
? List.of(new OutputValue(NO_RESULT, 0.0))
|
||||||
: outputVariable.fuzzyOutput().getTerms().stream().collect(Collectors.toMap(t -> t.getTerm().getName(), Activated::getDegree));
|
: outputVariable.fuzzyOutput()
|
||||||
|
.getTerms()
|
||||||
|
.stream()
|
||||||
|
.map(t -> new OutputValue(t.getTerm().getName(), t.getDegree()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Double> getFuzzyInference() {
|
public List<OutputValue> getFuzzyInference() {
|
||||||
|
return getFuzzyInference(getDemoRules(), Map.of("возраст", 20.0, "доход", 250000.0),
|
||||||
|
List.of(new Variable("возраст", List.of(
|
||||||
|
new VariableValue("молодой", 35.0),
|
||||||
|
new VariableValue("средний", 60.0),
|
||||||
|
new VariableValue("старый", 100.0))
|
||||||
|
),
|
||||||
|
new Variable("доход", List.of(
|
||||||
|
new VariableValue("небольшой", 35000.0),
|
||||||
|
new VariableValue("средний", 100000.0),
|
||||||
|
new VariableValue("высокий", 500000.0))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
new Variable("кредит", List.of(
|
||||||
|
new VariableValue("небольшой", 20000.0),
|
||||||
|
new VariableValue("средний", 100000.0),
|
||||||
|
new VariableValue("большой", 1000000.0)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OutputValue> getFuzzyInference(List<String> rules,
|
||||||
|
Map<String, Double> values,
|
||||||
|
List<Variable> inputVariables,
|
||||||
|
Variable outputVariable) {
|
||||||
Engine engine = getFuzzyEngine();
|
Engine engine = getFuzzyEngine();
|
||||||
engine.addRuleBlock(getRuleBlock(engine, getDemoRules()));
|
engine.addRuleBlock(getRuleBlock(engine, rules, inputVariables, outputVariable));
|
||||||
return getConsequent(engine, Map.of("возраст", 20.0, "доход", 250000.0));
|
return getConsequent(engine, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,6 @@ spring.datasource.password=password
|
|||||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
# swagger-ui custom path
|
||||||
|
springdoc.swagger-ui.path=/swagger-ui.html
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user