Newer
Older
RDLProofSystem / src / main / java / inference / InferenceRule.java
@Sakoda2269 Sakoda2269 13 days ago 8 KB 公理見直し中
package inference;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import exceptions.SubstituteFailedException;
import lombok.Getter;
import models.formulas.DependencyFormula;
import models.formulas.EquationFormula;
import models.formulas.Formula;
import models.formulas.meta.MetaEquationFormula;
import models.formulas.meta.MetaFormula;
import models.terms.DependencyTerm;
import models.terms.EvaluatableTerm;
import models.terms.RDLTerm;
import models.terms.Resource;
import models.terms.meta.MatchConstraint;
import models.terms.meta.MetaVariable;
import utils.Product;

public class InferenceRule {

	@Getter
	protected String name;
	
	@Getter
	protected List<MetaFormula> assumptions = new ArrayList<>();
	@Getter
	protected MetaFormula conclusion;
	protected InferenceOrderConstraint defaultOrderConstraint;
	
	protected List<MetaVariable> missingVariables;
	
	protected InferenceRule(String name) {
		this.name = name;
	}
	
	public InferenceRule(String name, List<MetaFormula> assumptions, MetaFormula conclusion, InferenceOrderConstraint constraint) {
		this.name = name;
		this.assumptions = assumptions;
		this.conclusion = conclusion;
		this.defaultOrderConstraint = constraint;
		Set<MetaVariable> missingVariables = conclusion.getAllVariables();
		for (MetaFormula assumption: assumptions) {
			missingVariables.removeAll(assumption.getAllVariables());
		}
		this.missingVariables = new ArrayList<>(missingVariables);
	}
	
	public InferenceRule(String name, List<MetaFormula> assumptions, MetaFormula conclusion) {
		this(name, assumptions, conclusion, null);
	}
	
	public Set<Formula> apply(Set<Formula> formulas, Set<RDLTerm> existTerms) {
		List<List<Formula>> matchFormulas = new ArrayList<>();
		List<List<RDLTerm>> matchTerms = new ArrayList<>();
		Set<Formula> result = new HashSet<>();
		for (int i = 0; i < assumptions.size(); i++) {
			matchFormulas.add(new ArrayList<>());
			for (Formula formula: formulas) {
				if (! assumptions.get(i).isMatchedBy(formula).isEmpty()) {
					matchFormulas.get(i).add(formula);
				}
			}
			if (matchFormulas.get(i).isEmpty()) { 
				return new HashSet<>();
			}
		}
		for (int i = 0; i < missingVariables.size(); i++) {
			matchTerms.add(new ArrayList<>());
			for (RDLTerm term : existTerms) {
				if (! missingVariables.get(i).isMatchedBy(term).isEmpty()) {
					matchTerms.get(i).add(term);
				}
			}
			if (matchTerms.get(i).isEmpty()) {
				return new HashSet<>();
			}
		}
		if (matchFormulas.size() == 0) {
			for (List<RDLTerm> terms : Product.product(matchTerms)) {
				MatchConstraint constraint = MatchConstraint.createDefault();
				for (int i = 0; i < terms.size(); i++) {
					MetaVariable variable = missingVariables.get(i);
					RDLTerm term = terms.get(i);
					constraint.setBinding(variable.getVariableName(), term);
					Formula conclusion = this.conclusion.substitution(constraint.getBinding(), constraint.getContext());
					if (conclusionCheck(conclusion, constraint, formulas)) {
						result.add(conclusion);
					}
				}
			}
		}
		for (List<Formula> assumptions: Product.product(matchFormulas)) {
			Set<MatchConstraint> matchResult = matchCheck(assumptions);
			if (matchResult.isEmpty()) {
				continue;
			}
			for (MatchConstraint constraint: matchResult) {
				if (missingVariables.size() == 0) {
					try {
						Formula conclusion = this.conclusion.substitution(constraint.getBinding(), constraint.getContext());
						if (conclusionCheck(conclusion, constraint, formulas)) {
							result.add(conclusion);
						}
					} catch (SubstituteFailedException e) {
						continue;
					}
				}
				for (List<RDLTerm> terms : Product.product(matchTerms)) {
					for (int i = 0; i < terms.size(); i++) {
						MetaVariable variable = missingVariables.get(i);
						RDLTerm term = terms.get(i);
						constraint.setBinding(variable.getVariableName(), term);
						try {
							Formula conclusion = this.conclusion.substitution(constraint.getBinding(), constraint.getContext());
							if (conclusionCheck(conclusion, constraint, formulas)) {
								result.add(conclusion);
							}
						} catch (SubstituteFailedException e) {
							continue;
						}
						
					}
				}
			}
		}
		return result;
	}
	
	protected Set<MatchConstraint> matchCheck(List<Formula> assumptions) {
		Set<MatchConstraint> matchResult = new HashSet<>();
		matchResult.add(MatchConstraint.createDefault());
		for (int i = 0; i < assumptions.size(); i++) {
			Formula assumption = assumptions.get(i);
			MetaFormula metaAssumption = this.assumptions.get(i);
			matchResult = metaAssumption.isMatchedBy(assumption, matchResult);
			if (matchResult.isEmpty()) {
				return new HashSet<>();
			}
		}
		return matchResult;
	}
	
	private static Set<Formula> requiredAssumptions(EvaluatableTerm term) {
		if (term instanceof Resource) {
			return new HashSet<>();
		}
		DependencyTerm depTerm = (DependencyTerm) term;
		Set<Formula> result = new HashSet<>();
		EvaluatableTerm dependingTerm = depTerm.getDependingTerm();
		List<EvaluatableTerm> dependedTerms = depTerm.getDependedTerms();
		List<EvaluatableTerm> argumentTerms = depTerm.getArgumentTerms();
		for (int i = 0; i < dependedTerms.size(); i++) {
			EvaluatableTerm dependedTerm = dependedTerms.get(i);
			EvaluatableTerm argTerm = argumentTerms.get(i);
			In in = new In(argTerm, dependedTerm);
			result.add(in);
		}
		if (dependingTerm instanceof Resource) {
			result.add(new DependencyFormula(dependingTerm, dependedTerms));
		} else if (dependingTerm instanceof DependencyTerm depending) {
			for (Formula formula : requiredAssumptions(depending)) {
				if (formula instanceof DependencyFormula dependency) {
					DependencyTerm newDependingTerm = new DependencyTerm((EvaluatableTerm) dependency.getDependency().getDependingTerm(), dependedTerms, argumentTerms);
					List<EvaluatableTerm> newDependedTerms = new ArrayList<>();
					for (RDLTerm dependedTerm : dependency.getDependency().getDependedTerms()) {
						newDependedTerms.add(new DependencyTerm((EvaluatableTerm) dependedTerm, dependedTerms, argumentTerms));
					}
					result.add(new DependencyFormula(newDependingTerm, newDependedTerms));
				} else if(formula instanceof In in) {
					result.add(new In(new DependencyTerm(in.getLeftSideHand(), dependedTerms, argumentTerms), new DependencyTerm(in.getRightSideHand(), dependedTerms, argumentTerms)));
				}
			}
		}
		return result;
	}
	
	private static boolean conclusionCheck(Formula conclusion, MatchConstraint constraint, Set<Formula> formulas) {
		if (conclusion instanceof DependencyFormula) return true;
		EquationFormula eq = (EquationFormula) conclusion;
		EvaluatableTerm leftSideHand = eq.getLeftSideHand();
		for (Formula formula: requiredAssumptions(leftSideHand)) {
			if (formula instanceof DependencyFormula dep) {
				if (! formulas.contains(dep)) { 
					return false;
				}
			} else if (formula instanceof In in) {
				boolean flg = false;
				for (MetaEquationFormula metaFormula: in.deriveRule()) {
					for (Formula existFormula: formulas) {
						if (! metaFormula.isMatchedBy(existFormula, constraint).isEmpty()) {
							flg = true;
							break;
						}
					}
					if (flg) break;
				}
				if (!flg) {
					return false;
				}
			}
		}
		return true;
	}
	
	public int getAssumptionSize() {
		return this.assumptions.size();
	}
	
	
	public String toString() {
		StringBuilder sb = new StringBuilder();
		if (defaultOrderConstraint != null) {
			sb.append(defaultOrderConstraint);
			sb.append(", ");
		}
		for (int i = 0; i < assumptions.size(); i++) {
			sb.append(assumptions.get(i).toString());
			if (i != assumptions.size() - 1) {
				sb.append(", ");
			}
		}
		String assumpStr = sb.toString();
		String concluStr = conclusion.toString();
		String line = "-".repeat(Math.max(assumpStr.length(), concluStr.length())) + "  (" + this.name + ")";
		sb = new StringBuilder();
		sb.append(assumpStr);
		sb.append("\n");
		sb.append(line);
		sb.append("\n");
		sb.append(concluStr);
		return sb.toString();
	}
	
	@Override
	public boolean equals(Object another) {
		if (! (another instanceof InferenceRule)) {
			return false;
		}
		InferenceRule anotherRule = (InferenceRule) another;
		return getName().equals(anotherRule.getName());
	}
	
	@Override
	public int hashCode() {
		return getName().hashCode();
	}
	
}