package uk.ac.manchester.cs.jfact.split;
/* This file is part of the JFact DL reasoner
Copyright 2011-2013 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import uk.ac.manchester.cs.jfact.dep.DepSet;
import uk.ac.manchester.cs.jfact.helpers.Helper;
import uk.ac.manchester.cs.jfact.kernel.DLDag;
import uk.ac.manchester.cs.jfact.kernel.NamedEntry;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptName;
import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomConceptInclusion;
import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomEquivalentConcepts;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.AxiomInterface;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.ConceptExpression;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.NamedEntity;
import uk.ac.manchester.cs.jfact.kernel.options.JFactReasonerConfiguration;
import conformance.Original;
import conformance.PortedFrom;
/** all split rules: vector of rules with init and access methods */
@PortedFrom(file = "tSplitExpansionRules.h", name = "TSplitRules")
public class TSplitRules implements Serializable {
private static final long serialVersionUID = 11000L;
/** class to check whether there is a need to unsplit splitted var */
public class TSplitRule implements Serializable {
private static final long serialVersionUID = 11000L;
/** signature of equivalent part of the split */
private final Set<NamedEntity> eqSig;
/** signature of subsumption part of the split */
private final Set<NamedEntity> impSig;
/** pointer to split vertex to activate */
private final int bpSplit;
/**
* init c'tor
*
* @param es
* es
* @param is
* is
* @param p
* p
*/
TSplitRule(Set<NamedEntity> es, Set<NamedEntity> is, int p) {
eqSig = new HashSet<NamedEntity>(es);
impSig = new HashSet<NamedEntity>(is);
bpSplit = p;
}
/**
* copy c'tor
*
* @param copy
* copy
*/
TSplitRule(TSplitRule copy) {
this(copy.eqSig, copy.impSig, copy.bpSplit);
}
// access methods
/** @return bipolar pointer of the rule */
public int bp() {
return bpSplit;
}
/**
* @param CurrentSig
* CurrentSig
* @return check whether signatures of a rule are related to current
* signature in such a way that allows rule to fire
*/
public boolean canFire(Set<NamedEntity> CurrentSig) {
return CurrentSig.containsAll(eqSig)
&& Helper.intersectsWith(impSig, CurrentSig);
}
/**
* calculates dep-set for a rule that can fire, write it to DEP.
*
* @param CurrentSig
* CurrentSig
* @param SigDep
* SigDep
* @return updated dep set
*/
public DepSet fireDep(Set<NamedEntity> CurrentSig,
Map<NamedEntity, DepSet> SigDep) {
DepSet dep = DepSet.create();
// eqSig is contained in current, so need all
for (NamedEntity p : eqSig) {
dep = DepSet.plus(dep, SigDep.get(p));
}
// impSig has partial intersect with current; 1st common entity is
// fine
for (NamedEntity p : impSig) {
if (CurrentSig.contains(p)) {
dep = DepSet.plus(dep, SigDep.get(p));
break;
}
}
return dep;
}
}
/** all known rules */
@PortedFrom(file = "tSplitExpansionRules.h", name = "Base")
private final List<TSplitRule> Base = new ArrayList<TSplitRule>();
/** all entities that appears in all the splits in a set */
@PortedFrom(file = "tSplitExpansionRules.h", name = "PossibleSignature")
private final Set<NamedEntity> PossibleSignature = new HashSet<NamedEntity>();
/** map between BP and TNamedEntities */
@PortedFrom(file = "tSplitExpansionRules.h", name = "EntityMap")
private final List<NamedEntity> EntityMap = new ArrayList<NamedEntity>();
@Original
private final JFactReasonerConfiguration config;
/**
* @param options
* options
*/
public TSplitRules(JFactReasonerConfiguration options) {
config = options;
}
/** @return split rules */
@PortedFrom(file = "tSplitExpansionRules.h", name = "begin")
public List<TSplitRule> getRules() {
return Base;
}
/**
* add new split rule
*
* @param eqSig
* eqSig
* @param impSig
* impSig
* @param bp
* bp
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "addSplitRule")
private void addSplitRule(Set<NamedEntity> eqSig, Set<NamedEntity> impSig,
int bp) {
Base.add(new TSplitRule(eqSig, impSig, bp));
}
/**
* @return single entity based on a named entry ENTRY and possible signature
* @param entry
* entry
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "getSingleEntity")
private NamedEntity getSingleEntity(NamedEntry entry) {
if (entry == null) {
return null;
}
NamedEntity ret = entry.getEntity();
// now keep only known signature concepts
return PossibleSignature.contains(ret) ? ret : null;
}
/**
* create all the split rules by given split set SPLITS
*
* @param Splits
* Splits
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "createSplitRules")
public void createSplitRules(TSplitVars Splits) {
for (TSplitVar p : Splits.getEntries()) {
initSplit(p);
}
}
/**
* ensure that Map has the same size as DAG, so there would be no access
* violation
*
* @param dagSize
* dagSize
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "ensureDagSize")
public void ensureDagSize(int dagSize) {
Helper.resize(EntityMap, dagSize);
}
/**
* @param bp
* bp
* @return named entity corresponding to a given bp
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "getEntity")
public NamedEntity getEntity(int bp) {
return EntityMap.get(bp > 0 ? bp : -bp);
}
/**
* init entity map using given DAG. note that this should be done AFTER rule
* splits are created!
*
* @param Dag
* Dag
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "initEntityMap")
public void initEntityMap(DLDag Dag) {
int size = Dag.size();
Helper.resize(EntityMap, size);
EntityMap.set(0, null);
EntityMap.set(1, null);
for (int i = 2; i < size - 1; ++i) {
EntityMap.set(i, getSingleEntity(Dag.get(i).getConcept()));
}
}
/**
* @return a set out of signature SIG w/o given ENTITY
* @param sig
* sig
* @param entity
* entity
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "buildSet")
private Set<NamedEntity> buildSet(TSignature sig, NamedEntity entity) {
Set<NamedEntity> set = new HashSet<NamedEntity>();
for (NamedEntity p : sig.begin()) {
if (!p.equals(entity) && p instanceof ConceptName) {
set.add(p);
}
}
// register all elements in the set in PossibleSignature
PossibleSignature.addAll(set);
return set;
}
/**
* init split as a set-of-sets
*
* @param split
* split
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "initSplit")
private void initSplit(TSplitVar split) {
SplitVarEntry p = split.getEntries().get(0);
Set<NamedEntity> impSet = buildSet(p.sig, p.name);
int bp = split.getC().getpBody() + 1;
// choose-rule stays next to a split-definition of C
for (int i = 1; i < split.getEntries().size(); i++) {
p = split.getEntries().get(i);
if (p.Module.size() == 1) {
addSplitRule(buildSet(p.sig, p.name), impSet, bp);
} else {
// make set of all the seed signatures of for p.Module
Set<TSignature> Out = new HashSet<TSignature>();
// prepare vector of available entities
List<NamedEntity> Allowed = new ArrayList<NamedEntity>();
List<AxiomInterface> Module = new ArrayList<AxiomInterface>(
p.Module);
// prepare signature for the process
TSignature sig = p.sig;
prepareStartSig(Module, sig, Allowed);
// build all the seed sigs for p.sig
BuildAllSeedSigs(Allowed, sig, Module, Out);
for (TSignature q : Out) {
addSplitRule(buildSet(q, p.name), impSet, bp);
}
}
}
}
/**
* prepare start signature
*
* @param Module
* Module
* @param sig
* sig
* @param Allowed
* Allowed
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "prepareStartSig")
private void prepareStartSig(List<AxiomInterface> Module, TSignature sig,
List<NamedEntity> Allowed) {
// remove all defined concepts from signature
for (AxiomInterface p : Module) {
if (p instanceof AxiomEquivalentConcepts) {
// we don't need class names here
for (ConceptExpression q : ((AxiomEquivalentConcepts) p)
.getArguments()) {
// FIXME!! check for the case A=B for named classes
if (q instanceof ConceptName) {
sig.remove((ConceptName) q);
}
}
} else {
if (!(p instanceof AxiomConceptInclusion)) {
continue;
}
// don't need the left-hand part either if it is a name
ConceptExpression c = ((AxiomConceptInclusion) p)
.getSubConcept();
if (c instanceof ConceptName) {
sig.remove((ConceptName) c);
}
}
}
// now put every concept name into Allowed
for (NamedEntity r : sig.begin()) {
if (r instanceof ConceptName) {
// concept name
Allowed.add(r);
}
}
}
/**
* build all the seed signatures
*
* @param Allowed
* Allowed
* @param StartSig
* StartSig
* @param Module
* Module
* @param Out
* Out
*/
@PortedFrom(file = "tSplitExpansionRules.h", name = "BuildAllSeedSigs")
private void BuildAllSeedSigs(List<NamedEntity> Allowed,
TSignature StartSig, List<AxiomInterface> Module,
Set<TSignature> Out) {
// copy the signature
TSignature sig = StartSig;
// create a set of allowed entities for the next round
List<NamedEntity> RecAllowed = new ArrayList<NamedEntity>();
List<NamedEntity> Keepers = new ArrayList<NamedEntity>();
// Set<AxiomInterface> outModule = new HashSet<AxiomInterface>();
TModularizer mod = new TModularizer(config,
new SyntacticLocalityChecker());
for (NamedEntity p : Allowed) {
if (sig.containsNamedEntity(p)) {
sig.remove(p);
// outModule.addAll(
mod.extractModule(Module, sig, ModuleType.M_STAR);
if (mod.getModule().size() == Module.size()) {
// possible to remove one
RecAllowed.add(p);
} else {
Keepers.add(p);
}
sig.add(p);
}
}
if (RecAllowed.isEmpty()) {
// minimal seed signature
Out.add(StartSig);
return;
}
if (!Keepers.isEmpty()) {
for (NamedEntity p : RecAllowed) {
sig.remove(p);
}
// outModule.addAll(
mod.extractModule(Module, sig, ModuleType.M_STAR);
if (mod.getModule().size() == Module.size()) {
Out.add(sig);
return;
}
}
// need to try smaller sigs
sig = StartSig;
for (NamedEntity p : RecAllowed) {
sig.remove(p);
BuildAllSeedSigs(RecAllowed, sig, Module, Out);
sig.add(p);
}
}
}