package agg.xt_basis.csp;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Vector;
import agg.attribute.AttrContext;
import agg.attribute.impl.AttrTupleManager;
import agg.attribute.impl.ValueTuple;
import agg.attribute.impl.VarMember;
import agg.attribute.impl.VarTuple;
import agg.util.csp.BinaryConstraint;
import agg.util.csp.CSP;
import agg.util.csp.Query;
import agg.util.csp.SolutionStrategy;
import agg.util.csp.Variable;
import agg.xt_basis.Arc;
import agg.xt_basis.Graph;
import agg.xt_basis.GraphObject;
import agg.xt_basis.Node;
import agg.xt_basis.Type;
/**
* A CSP whose solutions represent morphisms between two graphs.
*
* @see agg.util.csp.CSP
*/
public class ALR_CSP extends CSP {
private AttrContext itsAttrContext;
private boolean randomizedDomain;
private boolean directed = true;
// private boolean withNTI;
/**
* A 1:1 mapping of the objects of <code>itsVariableGraph</code> to the
* variables of the CSP. Keys are of type <code>GraphObject</code>,
* values of type <code>Variable</code>.
*/
final private Dictionary<GraphObject, Variable>
itsObjVarMap = new Hashtable<GraphObject, Variable>();
/**
* A mapping of every <code>Type.convertToKey()</code> of the variable
* graph to the set of graph objects of this type in the domain graph.
* <p>
* Keys are of type <code>String</code>, values of type
* <code>Vector</code> of <code>GraphObject</code>.
*
* @see agg.xt_basis.Type
* @see agg.xt_basis.GraphObject
* @see java.util.Vector
*/
final private Dictionary<String, HashSet<GraphObject>> itsTypeMap
= new Hashtable<String, HashSet<GraphObject>>();
/**
* @deprecated
*/
public ALR_CSP(final Graph vargraph,
final AttrContext ac,
boolean injective) {
super(new agg.util.csp.Solution_Backjump(injective));
this.itsAttrContext = ac;
// this.withNTI = vargraph.getTypeSet().hasInheritance();
this.directed = vargraph.getTypeSet().isArcDirected();
buildConstraintGraph(vargraph);
}
/**
* @deprecated
*/
public ALR_CSP(final Graph vargraph,
final AttrContext ac,
final SolutionStrategy st) {
super(st);
this.itsAttrContext = ac;
// this.withNTI = vargraph.getTypeSet().hasInheritance();
this.directed = vargraph.getTypeSet().isArcDirected();
buildConstraintGraph(vargraph);
}
/**
* Construct myself to be a CSP where every GraphObject of the specified Graph
* <code>vargraph</code> corresponds to exactly one of my variables.<br>
* <b>Pre:</b> <code>vargraph.isGraph()</code>.<br>
* <b>Post:</b> <code>getDomain() == null</code>.<br>
*
* @param vargraph
* The graph whose elements correspond to the variables of the
* CSP.
* @param ac
* The attribute context to map attributes in.
* @see agg.attribute.AttrMapping
* @param injective
* If <code>true</code>, then only injective solutions will
* be considered.
* @param randomizeDomainOfVariable
* If <code>true</code>, then do randomize the object domain of each CSP variable
*/
public ALR_CSP(final Graph vargraph,
final AttrContext ac,
boolean injective,
boolean randomizeDomainOfVariable) {
super(new agg.util.csp.Solution_Backjump(injective));
this.itsAttrContext = ac;
this.randomizedDomain = randomizeDomainOfVariable;
// this.withNTI = vargraph.getTypeSet().hasInheritance();
this.directed = vargraph.getTypeSet().isArcDirected();
buildConstraintGraph(vargraph);
}
/**
* Construct myself to be a CSP where every GraphObject of the specified Graph
* <code>vargraph</code> corresponds to exactly one of my variables.<br>
* <b>Pre:</b> <code>vargraph.isGraph()</code>.<br>
* <b>Post:</b> <code>getDomain() == null</code>.<br>
*
* @param vargraph
* The graph whose elements correspond to the variables of the
* CSP.
* @param ac
* The attribute context to map attributes in.
* @see agg.attribute.AttrMapping
* @param st
* The search solution strategy
* @param randomizeDomainOfVariable
* If <code>true</code>, then do randomize the object domain of each CSP variable
*/
public ALR_CSP(final Graph vargraph,
final AttrContext ac,
final SolutionStrategy st,
boolean randomizeDomainOfVariable) {
super(st);
this.itsAttrContext = ac;
this.randomizedDomain = randomizeDomainOfVariable;
// this.withNTI = vargraph.getTypeSet().hasInheritance();
this.directed = vargraph.getTypeSet().isArcDirected();
buildConstraintGraph(vargraph);
}
/**
* Construct myself to be a CSP. The CSP variables correspond to
* nodes and edge of the specified sets.
*/
public ALR_CSP(
final Collection<Node> varnodes,
final Collection<Arc> varedges,
final AttrContext ac,
boolean injective,
boolean randomizeDomainOfVariable) {
super(new agg.util.csp.Solution_Backjump(injective));
this.itsAttrContext = ac;
this.randomizedDomain = randomizeDomainOfVariable;
buildConstraintGraph(varnodes, varedges);
}
public void clear() {
this.itsSolver.clear();
((Hashtable<GraphObject, Variable>) this.itsObjVarMap).clear();
}
private synchronized final void buildConstraintGraph(
Collection<Node> varnodes,
Collection<Arc> varedges) {
// Create a value empty TypeMap for all specified nodes and edges.
// Edges without source / target are not taken in account.
// iterate over the nodes and create variables for them
while (varnodes.iterator().hasNext()) {
final Node anObj = varnodes.iterator().next();
final String keystr = anObj.convertToKey();
// create a hashmap entry for the type
if (this.itsTypeMap.get(keystr) == null) {
this.itsTypeMap.put(keystr, new LinkedHashSet<GraphObject>());
}
// create a variable for the current graph object
final Variable anObjVar = new Variable();
// anObjVar.setRandomizedDomain(false);
anObjVar.setKind(0);
anObjVar.setGraphObject(anObj);
this.itsObjVarMap.put(anObj, anObjVar);
}
// iterate over the edges and create variables for them
while (varedges.iterator().hasNext()) {
final Arc anObj = varedges.iterator().next();
final String keystr = anObj.convertToKey();
// create a hashmap entry for the type
if (this.itsTypeMap.get(keystr) == null) {
// check source type
String src_keystr = anObj.getSource().convertToKey();
String tar_keystr = anObj.getTarget().convertToKey();
if (this.itsTypeMap.get(src_keystr) == null
|| this.itsTypeMap.get(tar_keystr) == null)
continue;
// put edge type
this.itsTypeMap.put(keystr, new LinkedHashSet<GraphObject>());
}
// create a variable for the current graph object
final Variable anObjVar = new Variable();
// anObjVar.setRandomizedDomain(false);
anObjVar.setKind(1);
anObjVar.setGraphObject(anObj);
this.itsObjVarMap.put(anObj, anObjVar);
}
buildQueriesAndConstraints(this.itsObjVarMap.keys());
}
// This is the static part of initialization, i.e. it can be compiled
// into a graph rule (or the left graph of a rule).
private synchronized final void buildConstraintGraph(final Graph vargraph) {
// Create a value empty TypeMap for all the GraphObject types of
// the variable graph (LHS of a morphism):
// iterate over all objects in the vargraph
// and create variables for them
final Iterator<Node> nodes = vargraph.getNodesSet().iterator();
while (nodes.hasNext()) {
final GraphObject anObj = nodes.next();
// create a hashmap entry for every node and arc type
final String keystr = anObj.convertToKey();
if (this.itsTypeMap.get(keystr) == null) {
this.itsTypeMap.put(keystr, new LinkedHashSet<GraphObject>());
}
// create a variable for the current graph object
final Variable anObjVar = new Variable();
// anObjVar.setRandomizedDomain(this.randomizedDomain);
anObjVar.setKind(0);
anObjVar.setGraphObject(anObj);
this.itsObjVarMap.put(anObj, anObjVar);
}
final Iterator <Arc> arcs = vargraph.getArcsSet().iterator();
while (arcs.hasNext()) {
final GraphObject anObj = arcs.next();
// System.out.println(anObj.getType().convertToKey());
// create a hashmap entry for every node and arc type
final String keystr = anObj.convertToKey();
if (this.itsTypeMap.get(keystr) == null) {
this.itsTypeMap.put(keystr, new LinkedHashSet<GraphObject>());
}
// create a variable for the current graph object
final Variable anObjVar = new Variable();
// anObjVar.setRandomizedDomain(this.randomizedDomain);
anObjVar.setKind(1);
anObjVar.setGraphObject(anObj);
this.itsObjVarMap.put(anObj, anObjVar);
}
buildQueriesAndConstraints(this.itsObjVarMap.keys());
}
private void buildQueriesAndConstraints(final Enumeration<GraphObject> anEnum) {
GraphObject anObj;
Variable anObjVar, aSrcObjVar, aTarObjVar;
Query query;
BinaryConstraint constraint;
while (anEnum.hasMoreElements()) {
anObj = anEnum.nextElement();
anObjVar = this.itsObjVarMap.get(anObj);
// create queries for the current variable
// query = new Query_Type(itsTypeMap.get(anObj.convertToKey()), anObjVar);
query = new Query_Type(anObjVar);
((Query_Type)query).setRandomizedDomain(this.randomizedDomain);
constraint = new Constraint_Type(anObj, anObjVar);
query.setCorrespondent(constraint);
if (anObj.getType().getAttrType() != null
|| anObj.getType().hasInheritedAttribute())
new Constraint_Attribute(anObj, anObjVar,
this.itsAttrContext,
AttrTupleManager.getDefaultManager());
// additional for node
// if (anObj.isNode()) {
// // in case of node deletion do create a DanglingPoint constraint
// if (this.getRequester() instanceof Match
// && ((Match)this.getRequester()).getRule().getImage(anObj) == null) {
// constraint = new Constraint_DanglingPoint(anObj, anObjVar);
// query.setCorrespondent(constraint);
// }
// }
// else {
// create queries for source and target nodes of an arc
if (anObj.isArc()) {
aSrcObjVar = this.itsObjVarMap.get(((Arc) anObj).getSource());
aTarObjVar = this.itsObjVarMap.get(((Arc) anObj).getTarget());
if (this.directed) {
// constraint_source
constraint = new Constraint_Source(aSrcObjVar, anObjVar);
query = new Query_Outgoing(aSrcObjVar, anObjVar);
query.setCorrespondent(constraint);
query = new Query_Source(anObjVar, aSrcObjVar);
query.setCorrespondent(constraint);
// constraint_target
constraint = new Constraint_Target(aTarObjVar, anObjVar);
query = new Query_Incoming(aTarObjVar, anObjVar);
query.setCorrespondent(constraint);
query = new Query_Target(anObjVar, aTarObjVar);
query.setCorrespondent(constraint);
}
else { // undirected arc
// constraint_source_target
constraint = new Constraint_SourceTarget(aSrcObjVar, anObjVar);
query = new Query_OutgoingIncoming(aSrcObjVar, anObjVar);
query.setCorrespondent(constraint);
query = new Query_SourceTarget(anObjVar, aSrcObjVar);
query.setCorrespondent(constraint);
// constraint_source_target
constraint = new Constraint_TargetSource(aTarObjVar, anObjVar);
query = new Query_IncomingOutgoing(aTarObjVar, anObjVar);
query.setCorrespondent(constraint);
query = new Query_TargetSource(anObjVar, aTarObjVar);
query.setCorrespondent(constraint);
}
}
}
}
protected synchronized final void preprocessDomain(final Object domaingraph) {
// fillTypeMap((Graph) domaingraph);
resetTypeMap((Graph) domaingraph);
}
protected AttrContext getAttrContext() {
return this.itsAttrContext;
}
public final Enumeration<Variable> getVariables() {
return this.itsObjVarMap.elements();
}
public void enableAllVariables() {
Enumeration<GraphObject> keys = this.itsObjVarMap.keys();
while (keys.hasMoreElements()) {
GraphObject obj = keys.nextElement();
Variable var = this.itsObjVarMap.get(obj);
var.setEnabled(true);
}
}
public boolean isDomainOfTypeEmpty(final Type t) {
Enumeration<GraphObject> keys = this.itsObjVarMap.keys();
while (keys.hasMoreElements()) {
GraphObject go = keys.nextElement();
if (go.isArc())
continue;
if (go.getType().compareTo(t)) {
Variable var = this.itsObjVarMap.get(go);
return !var.hasNext();
}
}
return false;
}
public boolean isDomainOfTypeEmpty(final Type t,
final Type src,
final Type tar) {
Enumeration<GraphObject> keys = this.itsObjVarMap.keys();
while (keys.hasMoreElements()) {
GraphObject go = keys.nextElement();
if (go.isNode())
continue;
if (go.getType().compareTo(t)
&& ((Arc) go).getSource().getType().compareTo(src)
&& ((Arc) go).getTarget().getType().compareTo(tar)) {
Variable var = this.itsObjVarMap.get(go);
return !var.hasNext();
}
}
return false;
}
public void setRelatedInstanceVarMap(
final Dictionary<Object, Variable> relatedVarMap) {
this.itsSolver.setRelatedInstanceVarMap(relatedVarMap);
}
public Dictionary<Object, Variable> getInstanceVarMap() {
return this.itsSolver.getInstanceVarMap();
}
public final int getSize() {
return this.itsObjVarMap.size();
}
public final Variable getVariable(final GraphObject obj) {
return this.itsObjVarMap.get(obj);
}
/**
* 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.
*/
public void addObjectNameConstraint(GraphObject anObj) {
Variable anObjVar = this.itsObjVarMap.get(anObj);
if (anObjVar != null)
new Constraint_ObjectName(anObj, anObjVar);
}
/**
* Removes the object name constraint for the CSP variable
* of the given GraphObject anObj.
*/
public void removeObjectNameConstraint(GraphObject anObj) {
Variable anObjVar = this.itsObjVarMap.get(anObj);
if (anObjVar != null) {
Enumeration<?> cons = anObjVar.getConstraints();
while (cons.hasMoreElements()) {
Object c = cons.nextElement();
if (c instanceof Constraint_ObjectName) {
anObjVar.removeConstraint((Constraint_ObjectName) c);
}
}
}
}
// This is dynamic, i.e. can only be done when the domain graph is known.
// Not more in use.
protected void fillTypeMap(final Graph domaingraph) {
// handle nodes
Iterator<?> anEnum = domaingraph.getNodesSet().iterator();
while (anEnum.hasNext()) {
Node anObj = (Node) anEnum.next();
String keystr = anObj.convertToKey();
if (anObj.getType().hasParent()) {
Vector<Type> myParents = anObj.getType().getAllParents();
if (myParents != null) {
for (int i = 0; i < myParents.size(); ++i) {
keystr = myParents.get(i).convertToKey();
if (this.itsTypeMap.get(keystr) != null) {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
anObjVec.add(anObj);
}
}
}
} else if (this.itsTypeMap.get(keystr) != null) {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
anObjVec.add(anObj);
}
}
// handle arcs
anEnum = domaingraph.getArcsSet().iterator();
while (anEnum.hasNext()) {
Arc anObj = (Arc) anEnum.next();
String keystr = anObj.convertToKey();
if (anObj.getSource().getType().hasParent()
|| anObj.getTarget().getType().hasParent()) {
Vector<Type> mySrcParents = anObj.getSource().getType().getAllParents();
Vector<Type> myTarParents = anObj.getTarget().getType().getAllParents();
for (int i = 0; i < mySrcParents.size(); ++i) {
for (int j = 0; j < myTarParents.size(); ++j) {
keystr = mySrcParents.get(i).convertToKey()
+ anObj.getType().convertToKey()
+ myTarParents.get(j).convertToKey();
if (this.itsTypeMap.get(keystr) != null) {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
anObjVec.add(anObj);
}
}
}
} else if (this.itsTypeMap.get(keystr) != null) {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
anObjVec.add(anObj);
}
}
}
public void removeFromObjectVarMap(final GraphObject anObj) {
if (anObj.isNode()) {
Iterator<?> iter = ((Node)anObj).getIncomingArcs();
while (iter.hasNext()) {
removeFromObjectVarMap((Arc)iter.next());
}
iter = ((Node)anObj).getOutgoingArcs();
while (iter.hasNext()) {
removeFromObjectVarMap((Arc)iter.next());
}
}
Variable v = this.itsObjVarMap.get(anObj);
if (v != null) {
v.setInstance(null);
v.clear();
this.itsObjVarMap.remove(anObj);
}
}
protected void removeFromTypeObjectsMap(GraphObject anObj) {
if (anObj.isNode()) {
if (anObj.getType().hasParent()) {
Vector<Type> myParents = anObj.getType().getAllParents();
if (myParents != null) {
for (int i = 0; i < myParents.size(); ++i) {
String keystr = myParents.get(i).convertToKey();
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
if (anObjVec != null) {
anObjVec.remove(anObj);
}
}
}
} else {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(anObj.getType().convertToKey());
if (anObjVec != null) {
anObjVec.remove(anObj);
}
}
} else {
if (((Arc) anObj).getSource().getType().hasParent()
|| ((Arc) anObj).getTarget().getType().hasParent()) {
Vector<Type> mySrcParents = ((Arc) anObj).getSource().getType().getAllParents();
Vector<Type> myTarParents = ((Arc) anObj).getTarget().getType().getAllParents();
for (int i = 0; i < mySrcParents.size(); ++i) {
for (int j = 0; j < myTarParents.size(); ++j) {
String keystr = mySrcParents.get(i).convertToKey()
+ anObj.getType().convertToKey()
+ myTarParents.get(j).convertToKey();
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(keystr);
if (anObjVec != null) {
anObjVec.remove(anObj);
}
}
}
} else {
HashSet<GraphObject> anObjVec = this.itsTypeMap.get(anObj.getType().convertToKey());
if (anObjVec != null) {
anObjVec.remove(anObj);
}
}
}
}
protected void resetTypeMap(final Graph g) {
final Enumeration<GraphObject> lhsObjs = this.itsObjVarMap.keys();
while (lhsObjs.hasMoreElements()) {
final GraphObject obj = lhsObjs.nextElement();
final Variable var = this.itsObjVarMap.get(obj);
final String key = obj.convertToKey();
HashSet<GraphObject> list = g.getTypeObjectsMap().get(key);
if (list == null) {
list = new LinkedHashSet<GraphObject>();
g.getTypeObjectsMap().put(key, list);
}
this.itsTypeMap.put(key, list);
var.getTypeQuery().setObjects(list);
}
}
protected void resetTypeMap(
final Hashtable<String, HashSet<GraphObject>> aTypeMap) {
final Enumeration<GraphObject> lhsObjs = this.itsObjVarMap.keys();
while (lhsObjs.hasMoreElements()) {
final GraphObject obj = lhsObjs.nextElement();
final Variable var = this.itsObjVarMap.get(obj);
final String key = obj.convertToKey();
HashSet<GraphObject> list = aTypeMap.get(key);
if (list == null) {
list = new LinkedHashSet<GraphObject>();
aTypeMap.put(key, list);
}
this.itsTypeMap.put(key, list);
var.getTypeQuery().setObjects(list);
}
}
protected void reinitializeSolver(boolean doUpdateQueries) {
this.itsSolver.reinitialize(doUpdateQueries);
}
protected void resetSolver(boolean doUpdateQueries) {
resetSolverVariables();
this.itsSolver.reinitialize(doUpdateQueries);
}
protected void resetSolverVariables() {
final Enumeration<Variable> cspVars = this.itsObjVarMap.elements();
while (cspVars.hasMoreElements()) {
cspVars.nextElement().setInstance(null);
}
}
protected void resetVariableDomain(boolean resetByNull) {
if (resetByNull) {
final Enumeration<Variable> cspVars = this.itsObjVarMap.elements();
while (cspVars.hasMoreElements()) {
cspVars.nextElement().setInstance(null);
}
}
unsetAttrContextVariable();
}
protected void resetVariableDomain(final GraphObject go) {
final Variable var = this.itsObjVarMap.get(go);
if (var != null) {
this.itsSolver.reinitialize(var);
var.setInstance(null);
unsetAttrContextVariable(go);
}
}
protected void unsetAttrContextVariable() {
if (this.itsSolver.hasQueries()) {
final VarTuple varTuple = (VarTuple) this.itsAttrContext.getVariables();
for (int i = 0; i < varTuple.getSize(); i++) {
final VarMember vm = varTuple.getVarMemberAt(i);
if (vm != null)
vm.setExpr(null);
}
}
}
protected void unsetAttrContextVariable(final GraphObject go) {
if (go.getAttribute() != null
&& this.itsSolver.hasQueries()) {
final Vector<String> attrVars = ((ValueTuple) go.getAttribute())
.getAllVariableNames();
final VarTuple varTup = (VarTuple) this.itsAttrContext.getVariables();
for (int i = 0; i < attrVars.size(); i++) {
final String name = attrVars.elementAt(i);
final VarMember vm = varTup.getVarMemberAt(name);
if (vm != null)
vm.setExpr(null);
}
}
}
}