Newer
Older
RDLProofSystem / src / main / java / inference / InferenceRule.java
package inference;

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

import exceptions.SubstituteFailedException;
import lombok.Getter;
import models.formulas.Formula;
import models.formulas.meta.MetaDependencyFormula;
import models.formulas.meta.MetaFormula;
import models.terms.DependencyTerm;
import models.terms.EvaluatableTerm;
import models.terms.Resource;
import models.terms.meta.MatchConstraint;
import models.terms.meta.MetaRDLTerm;
import models.terms.meta.MetaVariable;
import utils.Permutation;

public class InferenceRule {

	@Getter
	protected String name;
	
	@Getter
	protected List<MetaFormula> assumptions = new ArrayList<>();
	@Getter
	protected MetaFormula conclusion;
	protected InferenceOrderConstraint defaultOrderConstraint;
	
	protected List<MetaFormula> repetitionAssumptions = new ArrayList<>();
	protected ConclusionSizeCalculator conclusionMaxIndexCalculator;
	protected ConclusionSizeCalculator conclusionMaxDepthCalculator;
	protected AssumptionSizeCalculator assumptionRepetitionSizeCalculator;
	
	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;
	}
	
	public InferenceRule(
			String name,
			List<MetaFormula> assumptions, 
			List<MetaFormula> repetitionAssumptions, 
			MetaFormula conclusion, 
			InferenceOrderConstraint constraint,
			ConclusionSizeCalculator conclusionMaxIndexCalculator,
			ConclusionSizeCalculator conclusionMaxDepthCalculator,
			AssumptionSizeCalculator assumptionSizeCalculator
	) {
		this.name = name;
		this.assumptions = assumptions;
		this.repetitionAssumptions = repetitionAssumptions;
		this.conclusion = conclusion;
		this.defaultOrderConstraint = constraint;
		this.conclusionMaxIndexCalculator = conclusionMaxIndexCalculator;
		this.conclusionMaxDepthCalculator = conclusionMaxDepthCalculator;
		this.assumptionRepetitionSizeCalculator = assumptionSizeCalculator;
	}
	
	public InferenceRule( List<MetaFormula> assumptions, MetaFormula conclusion, InferenceOrderConstraint constraint) {
		this("undefined", assumptions, conclusion, constraint);
	}
	
	public InferenceRule(String name, List<MetaFormula> assumptions, MetaFormula conclusion) {
		this(name, assumptions, conclusion, null);
	}
	
	public InferenceRule(List<MetaFormula> assumptions, MetaFormula conclusion) {
		this("undefined", assumptions, conclusion, null);
	}
	
	
	public Set<Formula> apply(Formula ...assumptions) {
		return apply(Set.of(assumptions));
	}
	
	public Set<Formula> apply(Set<Formula> assumptions) {
		if (assumptions.size() < getAssumptionSize()) {
			return new HashSet<>();
		}
		Set<Formula> result = new HashSet<>();
		for (List<Formula> assumptionList : Permutation.permutation(assumptions, assumptions.size())) {
			result.addAll(apply(assumptionList));
		}
		return result;
	}
	
	protected Set<Formula> apply(List<Formula> assumptions) {
		return apply(assumptions, MatchConstraint.createDefault());
	}
	
	protected Set<Formula> apply(List<Formula> assumptions, MatchConstraint constraint) {
		if (assumptions.size() < getAssumptionSize()) {
			return new HashSet<>();
		}
		
		Set<MatchConstraint> result = new HashSet<>();
		result.add(constraint);
		for (int i = 0; i < getAssumptionSize(); i++) {
			result = this.assumptions.get(i).isMatchedBy(assumptions.get(i), result);
			if (result.isEmpty()) {
				return new HashSet<>();
			}
		}
		if (this.repetitionAssumptions.size() != 0 && (assumptions.size() - this.assumptions.size()) % this.repetitionAssumptions.size() != 0) {
			return new HashSet<>();
		}
		if (this.repetitionAssumptions.size() != 0) {
			for (int i = 0; i < (assumptions.size() - this.assumptions.size()) / this.repetitionAssumptions.size(); i++) {
				List<MetaFormula> metaAssumptions = repetitionAssumptionGenerate(i);
				for (int j = 0; j < this.repetitionAssumptions.size(); j++) {
					Formula assumption = assumptions.get(this.assumptions.size() + i * this.repetitionAssumptions.size() + j);
					MetaFormula metaAssumption = metaAssumptions.get(j);
					result = metaAssumption.isMatchedBy(assumption, result);
					if (result.isEmpty()) {
						return new HashSet<>();
					}
				}
			}
		}
		Set<Formula> subRes = new HashSet<>();
		for (MatchConstraint con: result) {
			try {
				int maxIndex = conclusionMaxIndexCalculator != null ? conclusionMaxIndexCalculator.calculate(assumptions) : 0;
				int maxDepth = conclusionMaxDepthCalculator != null ? conclusionMaxDepthCalculator.calculate(assumptions) : 1;
				con.getContext().put("maxIndex", maxIndex);
				con.getContext().put("maxDepth", maxDepth);
				subRes.add(conclusion.substitution(con.getBinding(), con.getContext()));
			} catch (SubstituteFailedException e) {
				continue;
			}
		}
		return subRes;
	}
	
	private static Set<MetaFormula> requiredAssumptions(EvaluatableTerm term) {
		if (term instanceof Resource) {
			return new HashSet<>();
		}
		DependencyTerm depTerm = (DependencyTerm) term;
		Set<MetaFormula> result = new HashSet<>();
		EvaluatableTerm dependingTerm = depTerm.getDependingTerm();
		List<EvaluatableTerm> dependedTerms = depTerm.getDependedTerms();
		List<EvaluatableTerm> argumentTerms = depTerm.getArgumentTerms();
		if (dependingTerm instanceof Resource) {
			result.add(new MetaDependencyFormula(dependingTerm, dependedTerms));
			for (int i = 0; i < dependedTerms.size(); i++) {
				EvaluatableTerm dependedTerm = dependedTerms.get(i);
				EvaluatableTerm argTerm = argumentTerms.get(i);
				In in = new In(dependedTerm, argTerm);
			}
		}
		
		return result;
	}
	
	
	public int getAssumptionSize() {
		return this.assumptions.size();
	}
	
	protected List<MetaFormula> repetitionAssumptionGenerate(int i) {
//		if (i == 0) {
//			return new ArrayList<>(this.repetitionAssumptions);
//		}
		List<MetaFormula> result = new ArrayList<>();
		for (MetaFormula metaFormula : this.repetitionAssumptions) {
			Map<MetaVariable, MetaRDLTerm> mapping = new HashMap<>();
			for (MetaVariable variable : metaFormula.getAllVariables()) {
				mapping.put(variable, variable.cloneWithName(variable.getVariableName().getName() + i));
			}
			result.add(metaFormula.replace(mapping));
		}
		return result;
	}
	
	
	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();
	}
	
}