package agg.xt_basis.csp;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2000
* Company:
* @author
* @version 1.0
*/
import java.util.BitSet;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.Dictionary;
import agg.attribute.AttrContext;
import agg.attribute.impl.VarMember;
import agg.attribute.impl.VarTuple;
import agg.attribute.impl.ValueTuple;
import agg.attribute.impl.ValueMember;
import agg.attribute.AttrVariableTuple;
import agg.attribute.impl.CondTuple;
import agg.attribute.impl.CondMember;
import agg.util.csp.SolutionStrategy;
import agg.util.csp.Variable;
import agg.util.Pair;
import agg.xt_basis.Arc;
import agg.xt_basis.BadMappingException;
import agg.xt_basis.Graph;
import agg.xt_basis.GraphKind;
import agg.xt_basis.GraphObject;
import agg.xt_basis.Match;
import agg.xt_basis.MorphCompletionStrategy;
import agg.xt_basis.Morphism;
import agg.xt_basis.NACStarMorphism;
import agg.xt_basis.Node;
import agg.xt_basis.OrdinaryMorphism;
import agg.xt_basis.PACStarMorphism;
import agg.xt_basis.Type;
/**
* An implementation of morphism completion as a Constraint Satisfaction Problem (CSP).
*/
public class Completion_CSP extends MorphCompletionStrategy {
protected static final BitSet itsSupportedProperties = new BitSet(6);
static {
itsSupportedProperties.set(CompletionPropertyBits.INJECTIVE);
itsSupportedProperties.set(CompletionPropertyBits.DANGLING);
itsSupportedProperties.set(CompletionPropertyBits.IDENTIFICATION);
}
protected ALR_CSP itsCSP;
protected Morphism itsMorph;
protected Dictionary<Object, Variable> relatedVarMap;
final protected HashMap<String, String>
inputParameterMap = new HashMap<String, String>(1);
final protected List<VarMember>
disabledInputParameter = new Vector<VarMember>(2);
protected String errorMsg;
public Completion_CSP() {
super(itsSupportedProperties);
this.itsName = "CSP";
}
public Completion_CSP(boolean randomizeDomain) {
super(itsSupportedProperties);
this.randomDomain = randomizeDomain;
this.itsName = "CSP";
}
public void setProperties(MorphCompletionStrategy fromStrategy) {
initialize(itsSupportedProperties,
(BitSet) fromStrategy.getProperties().clone());
}
public void clear() {
if (this.itsCSP != null) {
this.itsCSP.clear();
}
}
public void dispose() {
if (this.itsCSP != null) {
this.itsCSP.resetSolverVariables();
this.itsCSP.clear();
}
this.relatedVarMap = null;
this.itsMorph = null;
}
/**
* Initialize the CSP by the specified morphism. The CSP variables are
* created for each node and edge of the source graph of the given morphism.
* Initialize the CSP variables (partially) according mappings of the given morphism.
*/
public void initialize(OrdinaryMorphism morph)
throws BadMappingException {
this.itsMorph = morph;
AttrContext aContext = initializeAttrContext(morph);
// create CSP
this.itsCSP = new ALR_CSP(
morph.getOriginal(),
aContext,
this.createSolutionStrategy(getProperties().get(CompletionPropertyBits.INJECTIVE)),
this.randomDomain);
if (morph.getImage().getTypeObjectsMap().isEmpty())
morph.getImage().fillTypeObjectsMap();
this.itsCSP.setRequester(morph);
this.itsCSP.setDomain(morph.getImage());
this.inputParameterMap.clear();
this.disabledInputParameter.clear();
this.itsCSP.getSolutionSolver().enableParallelSearch(this.parallel);
this.itsCSP.getSolutionSolver().setStartParallelSearchByFirst(this.startParallelMatchByFirstCSPVar);
// initialize CSP variables (partially) according mappings of the morphism
setPartialMorphism(morph);
}
/**
* Initialize the CSP by the specified morphism. The CSP variables are
* created for nodes and edge of the specified sets of nodes and edges, only.
* Initialize the CSP variables (partially) according mappings of the given morphism.
*/
public void initialize(final OrdinaryMorphism morph,
Collection<Node> nodes,
Collection<Arc> edges)
throws BadMappingException {
this.itsMorph = morph;
AttrContext aContext = initializeAttrContext(morph);
// create CSP
if (nodes != null && edges != null) {
// new : only injective mapping allowed
this.itsCSP = new ALR_CSP(nodes, edges, aContext, true, this.randomDomain);
} else {
this.itsCSP = new ALR_CSP(
morph.getOriginal(),
aContext,
this.createSolutionStrategy(getProperties().get(CompletionPropertyBits.INJECTIVE)),
this.randomDomain);
}
if (morph.getImage().getTypeObjectsMap().isEmpty()) {
morph.getImage().fillTypeObjectsMap();
}
this.itsCSP.setRequester(morph);
this.itsCSP.setDomain(morph.getImage());
this.inputParameterMap.clear();
this.disabledInputParameter.clear();
this.itsCSP.getSolutionSolver().enableParallelSearch(this.parallel);
this.itsCSP.getSolutionSolver().setStartParallelSearchByFirst(this.startParallelMatchByFirstCSPVar);
// represent the mappings of a partial morphism in the CSP:
setPartialMorphism(morph);
}
protected AttrContext initializeAttrContext(OrdinaryMorphism morph) {
if (morph instanceof Match) {
return morph.getAttrManager().newContext(
agg.attribute.AttrMapping.MATCH_MAP,
((Match) morph).getRule().getAttrContext());
} else if (morph instanceof NACStarMorphism) {
((NACStarMorphism) morph).setPartialMorphismCompletion(true);
return morph.getAttrManager().newContext(
agg.attribute.AttrMapping.MATCH_MAP,
((NACStarMorphism) morph).getRelatedMatchContext());
} else if (morph instanceof PACStarMorphism) {
((PACStarMorphism) morph).setPartialMorphismCompletion(true);
return morph.getAttrManager().newContext(
agg.attribute.AttrMapping.MATCH_MAP,
((PACStarMorphism) morph).getRelatedMorphContext());
} else {
return morph.getAttrManager().newContext(
agg.attribute.AttrMapping.PLAIN_MAP);
}
}
/**
* If an image of the source node or edge exists, set it to be instance of
* the appropriate CSP variable.
*/
public void setPartialMorphism(final OrdinaryMorphism morph) {
if (this.itsMorph != null) {
this.itsCSP.enableAllVariables();
final Iterator<Node> anEnum = morph.getOriginal().getNodesSet().iterator();
while (anEnum.hasNext()) {
final Node anObj = anEnum.next();
final GraphObject anImage = morph.getImage(anObj);
if (anImage != null) {
final Variable anObjVar = this.itsCSP.getVariable(anObj);
if (anObjVar != null) {
if (anObjVar.getInstance() != anImage) {
anObjVar.setInstance(anImage);
final Enumeration<?> conflicts = anObjVar.checkConstraints();
if (conflicts.hasMoreElements()) {
anObjVar.setInstance(null);
morph.removeMapping(anObj);
// throw new BadMappingException(
// "Completion_CSP.setPartialMorphism:: "+morph+" There are conflicts for some CSP constraints!");
}
}
}
}
}
final Iterator<Arc> anEnum1 = morph.getOriginal().getArcsSet().iterator();
while (anEnum1.hasNext()) {
final Arc anObj = anEnum1.next();
final GraphObject anImage = morph.getImage(anObj);
if (anImage != null) {
final Variable anObjVar = this.itsCSP.getVariable(anObj);
if (anObjVar != null) {
if (anObjVar.getInstance() != anImage) {
anObjVar.setInstance(anImage);
final Enumeration<?> conflicts = anObjVar.checkConstraints();
if (conflicts.hasMoreElements()) {
anObjVar.setInstance(null);
morph.removeMapping(anObj);
// throw new BadMappingException(
// "Completion_CSP.setPartialMorphism:: "+morph+" There are conflicts for some constraints!");
}
}
}
}
}
}
}
/*
private void unsetUsedVariable(GraphObject go, OrdinaryMorphism morph) {
if (go.getAttribute() != null) {
final Vector<String> attrVars = ((ValueTuple) go.getAttribute())
.getAllVariableNames();
final VarTuple varTup = (VarTuple) morph.getAttrContext().getVariables();
for (int i = 0; i < attrVars.size(); i++) {
final VarMember vm = varTup.getVarMemberAt(attrVars.elementAt(i));
if (vm != null)
vm.setExpr(null);
}
}
}
*/
/**
* Template method to enable creation of CSPs with varying solution
* strategies by subclasses.
*/
protected SolutionStrategy createSolutionStrategy(boolean injective) {
return new agg.util.csp.Solution_Backjump(injective);
// test only
// return new agg.util.csp.Solution_Backtrack(injective);
}
public void resetSolverQuery_Type() {
if (this.itsCSP != null)
this.itsCSP.resetQuery_Type();
}
public void enableParallelSearch(boolean b) {
this.parallel = b;
if (this.itsCSP != null) {
this.itsCSP.getSolutionSolver().enableParallelSearch(b);
}
}
public void setStartParallelSearchByFirst(boolean b) {
this.startParallelMatchByFirstCSPVar = b;
if (this.itsCSP != null) {
this.itsCSP.getSolutionSolver().setStartParallelSearchByFirst(b);
}
}
public AttrContext getAttrContext() {
return (this.itsCSP != null)? this.itsCSP.getAttrContext(): null;
}
public void resetSolver(boolean doUpdateQueries) {
if (this.itsCSP != null)
this.itsCSP.resetSolver(doUpdateQueries);
}
public void reinitializeSolver(boolean doUpdateQueries) {
if (this.itsCSP != null)
this.itsCSP.reinitializeSolver(doUpdateQueries);
}
public void resetSolverVariables() {
if (this.itsCSP != null)
this.itsCSP.resetSolverVariables();
}
public boolean isDomainOfTypeEmpty(Type t) {
return this.itsCSP.isDomainOfTypeEmpty(t);
}
public boolean isDomainOfTypeEmpty(Type t, Type src, Type tar) {
return this.itsCSP.isDomainOfTypeEmpty(t, src, tar);
}
public void setRelatedInstanceVarMap(
Dictionary<Object, Variable> relVarMap) {
this.relatedVarMap = relVarMap;
}
public boolean hasRelatedInstanceVarMap() {
if (this.relatedVarMap != null)
return true;
return false;
}
public Dictionary<Object, Variable> getInstanceVarMap() {
if (this.itsCSP != null)
return this.itsCSP.getInstanceVarMap();
return null;
}
public void removeFromObjectVarMap(GraphObject anObj) {
if (this.itsCSP != null)
this.itsCSP.removeFromObjectVarMap(anObj);
}
public final void reset() {
if (this.itsCSP != null && this.parallel)
this.itsCSP.reset();
}
public void removeFromTypeObjectsMap(GraphObject anObj) {
if (this.itsCSP != null)
this.itsCSP.removeFromTypeObjectsMap(anObj);
}
public void resetTypeMap(Hashtable<String, HashSet<GraphObject>> typeMap) {
if (this.itsCSP != null)
this.itsCSP.resetTypeMap(typeMap);
}
public void resetTypeMap(Graph g) {
if (this.itsCSP != null)
this.itsCSP.resetTypeMap(g);
}
public void resetVariableDomain(boolean initInstanceByNull) {
if (this.itsCSP != null) {
this.itsCSP.resetVariableDomain(initInstanceByNull);
this.inputParameterMap.clear();
this.disabledInputParameter.clear();
}
}
public void resetVariableDomain(final GraphObject go) {
if (this.itsCSP != null)
this.itsCSP.resetVariableDomain(go);
}
protected void unsetAttrContextVariable() {
this.itsCSP.unsetAttrContextVariable();
}
public final boolean next(final OrdinaryMorphism morph) {
// long time0 = System.currentTimeMillis();
if (morph != this.itsMorph) {
try {
initialize(morph);
} catch (BadMappingException ex) {
return false;
}
}
return doNext((OrdinaryMorphism) this.itsMorph);
}
public final boolean next(final OrdinaryMorphism morph,
Collection<Node> varnodes,
Collection<Arc> varedges) {
// long time0 = System.currentTimeMillis();
if (morph != this.itsMorph) {
try {
initialize(morph, varnodes, varedges);
} catch (BadMappingException ex) {
return false;
}
}
return doNext((OrdinaryMorphism) this.itsMorph);
}
private boolean doNext(final OrdinaryMorphism morph) {
this.itsCSP.setRelatedInstanceVarMap(this.relatedVarMap);
boolean flag = false;
this.errorMsg = "";
if (morph.getAttrContext() != null) {
((VarTuple) morph.getAttrContext().getVariables())
.unsetNotInputVariables();
// ((VarTuple) morph.getAttrContext().getVariables()).showVariables();
storeValueOfInputParameter(morph);
}
while (this.itsCSP.nextSolution()) {
flag = true;
this.errorMsg = "";
// add morph. mapping after CSP success
// add node mapping
final Iterator<Node> anNodeIter = morph.getOriginal().getNodesSet().iterator();
while (flag && anNodeIter.hasNext()) {
final GraphObject anOrig = anNodeIter.next();
Variable lhsVariable = this.itsCSP.getVariable(anOrig);
if (lhsVariable != null) {
final GraphObject anImage = (GraphObject) lhsVariable.getInstance();
try {
morph.addMapping(anOrig, anImage);
} catch (BadMappingException ex) {
flag = false;
}
}
}
// add edge mapping
final Iterator<Arc> anArcIter = morph.getOriginal().getArcsSet().iterator();
while (flag && anArcIter.hasNext()) {
final GraphObject anOrig = anArcIter.next();
Variable lhsVariable = this.itsCSP.getVariable(anOrig);
if (lhsVariable != null) {
final GraphObject anImage = (GraphObject) lhsVariable.getInstance();
try {
morph.addMapping(anOrig, anImage);
} catch (BadMappingException ex) {
flag = false;
}
}
}
// do more checks
if (flag) {
if (morph instanceof Match) {
if (!((Match) morph).areTotalIdentDanglAttrGluingSatisfied()
|| !((Match) morph).isParallelArcSatisfied()) {
flag = false;
}
}
}
if (flag && morph.getAttrContext() != null) {
flag = checkInputParameter(morph) && checkObjectsWithSameVariable(morph);
if (flag // check attr-condition of Match only
&& !(morph instanceof NACStarMorphism)
&& !(morph instanceof PACStarMorphism)
&& !checkAttrCondition(morph)) {
flag = false;
}
}
if (flag) {
morph.clearErrorMsg();
restoreValueOfInputParameter(morph);
break;
}
// flag == FALSE, then set error msg, refresh attr context and search again
morph.setErrorMsg(this.errorMsg);
restoreValueOfInputParameter(morph);
if (morph.getAttrContext() != null) {
// ((VarTuple) morph.getAttrContext().getVariables()).showVariables();
((VarTuple) morph.getAttrContext().getVariables()).unsetNotInputVariables();
}
}
return flag;
}
/*
* first save values of attr. context variables which are used as input parameters,
* otherwise its will be overwritten when next() done.
*/
private void storeValueOfInputParameter(OrdinaryMorphism morph) {
final AttrVariableTuple avt = morph.getAttrContext().getVariables();
int num = avt.getSize();
for (int i = 0; i < num; i++) {
final VarMember var = avt.getVarMemberAt(i);
if (var.isInputParameter()) {
if (this.inputParameterMap.get(var.getName()) == null) {
if (var.isSet()) {
this.inputParameterMap.put(var.getName(), var.getExprAsText());
}
else {
this.disabledInputParameter.add(var);
}
}
}
}
}
/*
* restore values of attr-context variables used as input parameters
*/
private void restoreValueOfInputParameter(OrdinaryMorphism morph) {
if (morph.getAttrContext() != null) {
final AttrVariableTuple avt = morph.getAttrContext().getVariables();
if (!this.inputParameterMap.isEmpty()) {
final Iterator<String> iter = this.inputParameterMap.keySet().iterator();
while (iter.hasNext()) {
final String name = iter.next();
final String val = this.inputParameterMap.get(name);
final VarMember var = avt.getVarMemberAt(name);
if (var != null) {
if (!val.equals(var.getExprAsText())) {
var.setExprAsText(val);
}
}
}
}
}
}
private boolean checkInputParameter(OrdinaryMorphism morph) {
// System.out.println("Completion_CSP.checkInputParameter... of "+morph.getName());
final AttrVariableTuple avt = morph.getAttrContext().getVariables();
if (!this.inputParameterMap.isEmpty()) {
final Iterator<String> iter = this.inputParameterMap.keySet().iterator();
while (iter.hasNext()) {
final String IPname = iter.next();
final String IPvalue = this.inputParameterMap.get(IPname);
final VarMember VM = avt.getVarMemberAt(IPname);
if (VM != null && VM.isInputParameter()) {
if (VM.isEnabled()) {
final String VMvalue = VM.getExprAsText();
if (morph instanceof Match) {
if (VMvalue != null) {
if ((VM.getMark() != VarMember.NAC)
&& (VM.getMark() != VarMember.PAC)
&& !IPvalue.equals(VMvalue)) {
this.errorMsg = "Value of the input parameter [ "
+ VM.getName() + " ] not found.";
return false;
}
}
} else if (morph instanceof NACStarMorphism) {
if (VMvalue != null) {
if ((VM.getMark() == VarMember.NAC)
&& !IPvalue.equals(VMvalue)) {
this.errorMsg = "Value of the input parameter [ "
+ VM.getName() + " ] not found.";
return false;
}
}
} else if (morph instanceof PACStarMorphism) {
if (VMvalue != null) {
if ((VM.getMark() == VarMember.PAC)
&& !IPvalue.equals(VMvalue)) {
this.errorMsg = "Value of the input parameter [ "
+ VM.getName() + " ] not found.";
return false;
}
}
} else {
if (VMvalue != null) {
if ((VM.getMark() != VarMember.NAC)
&& (VM.getMark() != VarMember.PAC)
&& !IPvalue.equals(VMvalue)) {
this.errorMsg = "Value of the input parameter [ "
+ VM.getName() + " ] not found.";
return false;
}
}
}
}
}
}
}
if (!this.disabledInputParameter.isEmpty()) {
if (morph instanceof NACStarMorphism) {
final OrdinaryMorphism relatedMatch = ((NACStarMorphism) morph).getRelatedMatch();
final VarTuple varsOfMatch = (VarTuple) relatedMatch.getAttrContext().getVariables();
for (int i=0; i<this.disabledInputParameter.size(); i++) {
final VarMember VM = this.disabledInputParameter.get(i);
if (VM != null) {
VarMember matchVM = varsOfMatch.getVarMemberAt(VM.getName());
if (matchVM != null
&& matchVM.getMark() == VarMember.NAC
&& !matchVM.isEnabled()) {
return false;
}
}
}
} else if (morph instanceof PACStarMorphism) {
final OrdinaryMorphism relatedMatch = ((PACStarMorphism) morph).getRelatedMorph();
final VarTuple varsOfMatch = (VarTuple) relatedMatch.getAttrContext().getVariables();
for (int i=0; i<this.disabledInputParameter.size(); i++) {
VarMember VM = this.disabledInputParameter.get(i);
if (VM != null) {
final VarMember matchVM = varsOfMatch.getVarMemberAt(VM.getName());
if (matchVM != null
&& matchVM.getMark() == VarMember.PAC
&& !matchVM.isEnabled()) {
return false;
}
}
}
}
}
return true;
}
private boolean checkObjectsWithSameVariable(final OrdinaryMorphism morph) {
// System.out.println("Completion_CSP.checkObjectsWithSameVariable : "+morph.getName());
final VarTuple variables = (VarTuple) morph.getAttrContext().getVariables();
for (int i = 0; i < variables.getSize(); i++) {
final VarMember var = variables.getVarMemberAt(i);
final Vector<Pair<GraphObject, String>> v = new Vector<Pair<GraphObject, String>>();
final Iterator<Node> iter = morph.getOriginal().getNodesSet().iterator();
while (iter.hasNext()) {
GraphObject orig = iter.next();
if (orig.getAttribute() != null) {
final ValueTuple origVal = (ValueTuple) orig.getAttribute();
for (int k = 0; k < origVal.getSize(); k++) {
final ValueMember mem = origVal.getValueMemberAt(k);
if (mem.isSet()
&& mem.getExpr().isVariable()
&& mem.getExprAsText().equals(var.getName())
&& mem.getDeclaration().getTypeName().equals(
var.getDeclaration().getTypeName())) {
v.add(new Pair<GraphObject, String>(orig, mem.getName()));
// System.out.println("Variable: "+var.getName()+" at "+mem.getName());
}
}
}
}
final Iterator<Arc> iter1 = morph.getOriginal().getArcsSet().iterator();
while (iter1.hasNext()) {
GraphObject orig = iter1.next();
if (orig.getAttribute() != null) {
final ValueTuple origVal = (ValueTuple) orig.getAttribute();
for (int k = 0; k < origVal.getSize(); k++) {
final ValueMember mem = origVal.getValueMemberAt(k);
if (mem.isSet()
&& mem.getExpr().isVariable()
&& mem.getExprAsText().equals(var.getName())
&& mem.getDeclaration().getTypeName().equals(
var.getDeclaration().getTypeName())) {
v.add(new Pair<GraphObject, String>(orig, mem.getName()));
}
}
}
}
if (v.size() > 1) {
final Pair<GraphObject, String> p = v.elementAt(0);
final GraphObject img = morph.getImage(p.first);
final ValueTuple val = (ValueTuple) img.getAttribute();
final ValueMember mem = val.getValueMemberAt(p.second);
for (int j = 1; j < v.size(); j++) {
final Pair<GraphObject, String> pj = v.elementAt(j);
final GraphObject imgj = morph.getImage(pj.first);
final ValueTuple valj = (ValueTuple) imgj.getAttribute();
final ValueMember memj = valj.getValueMemberAt(pj.second);
if (mem.isSet() && memj.isSet()) {
if (mem.getExpr().isConstant()
&& memj.getExpr().isConstant()) {
if (!mem.getExprAsText().equals(memj.getExprAsText())) {
this.errorMsg = "Attribute check (value is Constant): equal value due to equal variable - failed!";
return false;
}
} else if (mem.getExpr().isVariable()
&& memj.getExpr().isVariable()) {
if (!mem.getExprAsText().equals(memj.getExprAsText())) {
if (morph.getTarget().isCompleteGraph()) {
this.errorMsg = "Attribute check (value is Variable): equal value due to equal variable - failed!";
return false;
}
else if ((mem.isTransient() || memj.isTransient())
// && morph.getOriginal().getKind() == GraphKind.CONCLUSION
&& (morph.getOriginal().getKind() == GraphKind.PREMISE
|| morph.getOriginal().getKind() == GraphKind.CONCLUSION)
) {
this.errorMsg = "Attribute check (value is Variable): equal (transient) variable due to equal variable - failed!";
// System.out.println(this.getClass().getName()+": "+this.errorMsg);
return false;
}
}
} else if (morph.getTarget().isCompleteGraph()) {
this.errorMsg = "Attribute check: equal value due to equal variable - failed!";
System.out.println(this.getClass().getName()+": "+this.errorMsg);
return false;
}
}
}
}
}
return true;
}
private boolean checkAttrCondition(final OrdinaryMorphism morph) {
final CondTuple conds = (CondTuple) morph.getAttrContext().getConditions();
for (int i = 0; i < conds.getSize(); i++) {
final CondMember cond = conds.getCondMemberAt(i);
if (!cond.isEnabled()
|| cond.getMark() != CondMember.LHS) {
continue;
}
if (cond.isDefinite()
&& !cond.isTrue()) {
this.errorMsg = "Attribute condition [ " + cond.getExprAsText()
+ " ] failed.";
((VarTuple) morph.getAttrContext().getVariables()).unsetVariables();
morph.removeAllMappings();
return false;
}
}
return true;
}
/**
* An additional object name constraint will be added for the CSP variable
* of the given GraphObject anObj. This constraint requires equality of the object names.<br>
*/
public void addObjectNameConstraint(GraphObject anObj) {
if (this.itsCSP != null)
this.itsCSP.addObjectNameConstraint(anObj);
}
/**
* Removes the object name constraint for the CSP variable
* of the given GraphObject anObj.
*/
public void removeObjectNameConstraint(GraphObject anObj) {
if (this.itsCSP != null)
this.itsCSP.removeObjectNameConstraint(anObj);
}
}