#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.h2database', name:'h2'
|
||||
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: '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.activation.General;
|
||||
import com.fuzzylite.defuzzifier.Centroid;
|
||||
import com.fuzzylite.defuzzifier.WeightedAverage;
|
||||
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 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.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@ -31,65 +31,52 @@ public class FuzzyInferenceService {
|
||||
+ " is %s";
|
||||
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() {
|
||||
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, "возраст", "молодой", "доход", "небольшой", "небольшой")
|
||||
);
|
||||
}
|
||||
|
||||
private List<InputVariable> getInputVariables() {
|
||||
return List.of(getInputVariable("возраст", inputFuzzyTerms.get("возраст")),
|
||||
getInputVariable("доход", inputFuzzyTerms.get("доход")));
|
||||
}
|
||||
|
||||
private InputVariable getInputVariable(String name, List<Entry<String, Integer>> terms) {
|
||||
private InputVariable getInputVariable(Variable variable) {
|
||||
final InputVariable input = new InputVariable();
|
||||
input.setName(name);
|
||||
input.setName(variable.getName());
|
||||
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.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());
|
||||
for (int i = 0; i < variable.getValues().size(); i++) {
|
||||
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();
|
||||
input.addTerm(term);
|
||||
}
|
||||
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();
|
||||
output.setName(name);
|
||||
output.setName(variable.getName());
|
||||
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.setAggregation(new Maximum());
|
||||
output.setDefuzzifier(new Centroid(terms.get(terms.size() - 1).getValue()));
|
||||
output.setDefuzzifier(new WeightedAverage());
|
||||
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());
|
||||
for (int i = 0; i < variable.getValues().size(); i++) {
|
||||
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();
|
||||
output.addTerm(term);
|
||||
}
|
||||
@ -97,9 +84,11 @@ public class FuzzyInferenceService {
|
||||
}
|
||||
|
||||
private RuleBlock getRuleBlock(Engine engine,
|
||||
List<String> rules) {
|
||||
getInputVariables().forEach(engine::addInputVariable);
|
||||
engine.addOutputVariable(getOutputVariable("кредит", outputFuzzyTerms.get("кредит")));
|
||||
List<String> rules,
|
||||
List<Variable> inputVariables,
|
||||
Variable outputVariable) {
|
||||
inputVariables.stream().map(this::getInputVariable).forEach(engine::addInputVariable);
|
||||
engine.addOutputVariable(getOutputVariable(outputVariable));
|
||||
|
||||
RuleBlock mamdani = new RuleBlock();
|
||||
mamdani.setName("mamdani");
|
||||
@ -119,7 +108,7 @@ public class FuzzyInferenceService {
|
||||
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);
|
||||
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
|
||||
InputVariable inputVariable = engine.getInputVariable(variableValue.getKey());
|
||||
@ -130,14 +119,40 @@ public class FuzzyInferenceService {
|
||||
LOG.info("Output: {}", outputVariable.getValue());
|
||||
}
|
||||
return Double.isNaN(outputVariable.getValue())
|
||||
? Map.of(NO_RESULT, 0.0)
|
||||
: outputVariable.fuzzyOutput().getTerms().stream().collect(Collectors.toMap(t -> t.getTerm().getName(), Activated::getDegree));
|
||||
? List.of(new OutputValue(NO_RESULT, 0.0))
|
||||
: 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.addRuleBlock(getRuleBlock(engine, getDemoRules()));
|
||||
return getConsequent(engine, Map.of("возраст", 20.0, "доход", 250000.0));
|
||||
engine.addRuleBlock(getRuleBlock(engine, rules, inputVariables, outputVariable));
|
||||
return getConsequent(engine, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,4 +17,6 @@ spring.datasource.password=password
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
spring.h2.console.enabled=true
|
||||
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