Merge branch 'master' into 3-parse-rule
# Conflicts: # src/main/java/ru/ulstu/fc/rule/model/Variable.java # src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java # src/main/resources/templates/default.html
This commit is contained in:
commit
24a59f204d
@ -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'
|
||||
|
@ -14,6 +14,9 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
@Configuration
|
||||
public class MvcConfiguration implements WebMvcConfigurer {
|
||||
@ -41,6 +44,14 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
||||
return localeInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Docket api() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.basePackage("ru.ulstu"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeInterceptor());
|
||||
|
@ -9,11 +9,14 @@ 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 springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@ApiIgnore
|
||||
public class InferenceMvcController {
|
||||
private final FuzzyInferenceService fuzzyInferenceService;
|
||||
|
||||
@ -34,21 +37,24 @@ public class InferenceMvcController {
|
||||
model.addAttribute("ageAntecedents", getAgeAntecedents());
|
||||
model.addAttribute("incomeAntecedents", getIncomeAntecedents());
|
||||
model.addAttribute("inferenceForm", inferenceForm);
|
||||
model.addAttribute("response", fuzzyInferenceService.getFuzzyInference());
|
||||
model.addAttribute("response", fuzzyInferenceService.getFuzzyInference(
|
||||
Map.of("возраст", Double.valueOf(inferenceForm.getAgeAntecedent()),
|
||||
"доход", Double.valueOf(inferenceForm.getIncomeAntecedent())
|
||||
)));
|
||||
return "index";
|
||||
}
|
||||
|
||||
private List<Antecedent> getAgeAntecedents() {
|
||||
return Arrays.asList(
|
||||
new Antecedent("молодой", "young"),
|
||||
new Antecedent("средний", "average"),
|
||||
new Antecedent("старый", "old"));
|
||||
new Antecedent("молодой", "30"),
|
||||
new Antecedent("средний", "45"),
|
||||
new Antecedent("старый", "60"));
|
||||
}
|
||||
|
||||
private List<Antecedent> getIncomeAntecedents() {
|
||||
return Arrays.asList(
|
||||
new Antecedent("малый", "small"),
|
||||
new Antecedent("средний", "average"),
|
||||
new Antecedent("высокий", "high"));
|
||||
new Antecedent("небольшой", "20000"),
|
||||
new Antecedent("средний", "90000"),
|
||||
new Antecedent("высокий", "200000"));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
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
|
||||
@ -32,69 +32,52 @@ public class FuzzyInferenceService {
|
||||
private final static String NO_RESULT = "Нет результата";
|
||||
private final Engine fuzzyEngine;
|
||||
|
||||
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)));
|
||||
|
||||
public FuzzyInferenceService(Engine fuzzyEngine) {
|
||||
this.fuzzyEngine = fuzzyEngine;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -102,9 +85,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");
|
||||
@ -117,7 +102,7 @@ public class FuzzyInferenceService {
|
||||
return mamdani;
|
||||
}
|
||||
|
||||
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());
|
||||
@ -128,14 +113,39 @@ 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(Map<String, Double> vals) {
|
||||
return getFuzzyInference(getDemoRules(), vals,
|
||||
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) {
|
||||
fuzzyEngine.getRuleBlocks().clear();
|
||||
fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, getDemoRules()));
|
||||
return getConsequent(fuzzyEngine, Map.of("возраст", 20.0, "доход", 250000.0));
|
||||
fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, getDemoRules())); return getConsequent(engine, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,4 +18,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
|
||||
|
||||
|
@ -30,6 +30,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/listRules">Правила</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/swagger-ui/index.html">API</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -50,7 +50,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" class="btn btn-outline-success m-2" value="Получить результат вывода"/>
|
||||
<div class="row" th:text="${response}"></div>
|
||||
<div class="row" th:each="out : ${response}">
|
||||
<div class="col-md-2"> Размер кредита:</div>
|
||||
<div class="col-md-4" th:text="${out.fuzzyTerm}"></div>
|
||||
<div class="col-md-3"> Степень принадлежности:</div>
|
||||
<div class="col-md-1" th:text="${out.degree}"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user