All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.metacsp.framework.ConstraintNetwork Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
package org.metacsp.framework;

import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;

import javax.swing.JFrame;

import org.apache.commons.collections15.map.HashedMap;
import org.metacsp.framework.meta.MetaConstraintSolver;
import org.metacsp.framework.multi.MultiBinaryConstraint;
import org.metacsp.throwables.NonInstantiatedDomain;
import org.metacsp.utility.UI.Callback;
import org.metacsp.utility.UI.ConstraintNetworkFrame;
import org.metacsp.utility.logging.MetaCSPLogging;

import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.ObservableGraph;


/**
 * This class implements the necessary functionality to maintain networks of {@link Constraint}s.  It is used by all
 * {@link ConstraintSolver}s and provides methods to add and remove {@link Variable}s, {@link Constraint}s, querying the
 * network for constraints, incident edges, etc.  It also provide basic graphical rendering functions.
 * 
 * @author Federico Pecora
 */

public class ConstraintNetwork implements Cloneable, Serializable  {

	//For changelistener
	private List listeners = null;

	public void addConstraintNetworkChangeListener(ConstraintNetworkChangeListener listener) {
		if (listeners == null) listeners = new ArrayList();
		listeners.add(listener);
	}

	private void dispatchEvent(ConstraintNetwork added, ConstraintNetwork removed) {
		final ConstraintNetworkChangeEvent event = new ConstraintNetworkChangeEvent(this, added, removed);
		for (ConstraintNetworkChangeListener l : listeners) {
			dispatchRunnableOnEventQueue(l, event);
		}
	}

	private void dispatchRunnableOnEventQueue(final ConstraintNetworkChangeListener listener, final ConstraintNetworkChangeEvent event) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				listener.stateChanged(event);
			}
		});
	}
	//end for changelistener
	
	public static HashMap backupForSerialization = new HashMap();
	//This will back up the domain valuechoice functions for serialization
	private HashMap,HashMap> domainValueChoiceFunctions = new HashMap, HashMap>();

	private class FieldOfObject {
		private Field field;
		private int ID;
		private FieldOfObject(Field field) {
			this.ID = getID();
			this.field = field;
		}
		public boolean equals(Object o) {
			FieldOfObject foo = (FieldOfObject)o;
			return (foo.ID == this.ID && foo.field.getName().equals(this.field.getName()));
		}
		public int hashCode() {
			return this.toString().hashCode();
		}
		public String toString() {
			return "FieldOfObject <" + ID + "," + field.getName() + ">";
		}
	}

	protected ConstraintSolver solver;
	protected ObservableGraph graph;
	protected DirectedSparseMultigraph g;
	protected HashMap variables = new HashMap();
	protected HashMap variablesR = new HashMap();
	protected HashMap substitutions = new HashMap();
	protected HashMap substituted = new HashMap();

	protected HashMap hyperEdges = new HashMap();

	public ObservableGraph getGraph() { return graph; }
	
	private transient Logger logger = MetaCSPLogging.getLogger(this.getClass());
	private static final long serialVersionUID = 7526472295622776148L;

	private double weight=-1;

	public transient Object annotation;
	public transient Object specilizedAnnotation;
	public ConstraintNetworkMarking marking; // to mark the ConstraintNetwork in the backtracking process

	public static int IDs = 0;
	public int ID = IDs++;

	public int getID() { return this.ID; }

	public Object getSpecilizedAnnotation() {
		return specilizedAnnotation;
	}

	public void setSpecilizedAnnotation(Object specilizedAnnotation) {
		this.specilizedAnnotation = specilizedAnnotation;
	}

	//This is so that subclasses must invoke 1-arg constructor of ConstraintNetwork (below)
	@SuppressWarnings("unused")
	private ConstraintNetwork() {};

	/**
	 * Convenience method to keep track of correspondences between {@link VariablePrototype}s and {@link Variable}s (useful
	 * when {@link ConstraintNetwork}s are used as meta-values in {@link MetaConstraintSolver}s).
	 * @param vp The {@link VariablePrototype}.
	 * @param v The {@link Variable} that corresponds to the given {@link VariablePrototype}.
	 */
	public void addSubstitution(VariablePrototype vp, Variable v) {
		substitutions.put(vp, v);
		substituted.put(v,vp);
		logger.finest("Added susbstitution " + vp + " <-- " + v);
	}

	/**
	 * Convenience method to keep track of correspondences between {@link VariablePrototype}s and {@link Variable}s (useful
	 * when {@link ConstraintNetwork}s are used as meta-values in {@link MetaConstraintSolver}s).
	 * @param vp2v Mapping between {@link VariablePrototype}s and {@link Variable}s.
	 */	
	public void addSubstitutions(HashedMap vp2v) {

		for(VariablePrototype vp: vp2v.keySet()){
			substitutions.put(vp, vp2v.get(vp));
			substituted.put(vp2v.get(vp),vp);
			logger.finest("Added susbstitution " + vp + " <-- " + vp2v.get(vp));
		}
	}


	/**
	 * Get the {@link Variable} corresponding to a given {@link VariablePrototype} (see addSubstitution() method).
	 * @param vp The {@link VariablePrototype} to look up.
	 * @return The {@link Variable} corresponding to the given {@link VariablePrototype}.
	 */
	public Variable getSubstitution(VariablePrototype vp) {
		return substitutions.get(vp);
	}

	/**
	 * Get the {@link VariablePrototype} corresponding to a given {@link Variable} (see addSubstitution() method).
	 * @param v The {@link Variable} to look up.
	 * @return The {@link VariablePrototype} corresponding to the given {@link Variable}.
	 */
	public VariablePrototype getSubstituted(Variable v) {
		return substituted.get(v);
	}

	/**
	 * Remove the {@link Variable} corresponding to a given {@link VariablePrototype} (see addSubstitution() method).
	 * @param vp The {@link VariablePrototype} to look up.
	 */
	public void removeSubstitution(VariablePrototype vp) {
		Variable v= this.substitutions.get(vp);
		substitutions.remove(vp);
		substituted.remove(v);
	}


	/**
	 * Instantiates a new {@link ConstraintNetwork}.  Note that all implementing classes must call this constructor
	 * (i.e., specifying a {@link ConstraintSolver} is mandatory).
	 * @param sol The {@link ConstraintSolver} which maintains this {@link ConstraintNetwork}.
	 */
	public ConstraintNetwork(ConstraintSolver sol) {
		solver = sol;
		g = new DirectedSparseMultigraph();
		graph = new ObservableGraph(g);
		this.weight=-1;
		this.annotation="NONE";
		this.marking=new ConstraintNetworkMarking();
	}

	/**
	 * Returns the {@link Constraint} between two given {@link Variable}s (if it exists).
	 * If more than one exists, it returns one of them (no guarantees as to which one).
	 * @param from The source variable of the {@link Constraint} to find.
	 * @param to The destination variable of the {@link Constraint} to find.
	 * @return The {@link Constraint} between the two given {@link Variable}s, null if
	 * no such {@link Constraint} exists. 
	 */
	public Constraint getConstraint(Variable from, Variable to) {
		return this.graph.findEdge(from, to);
	}

	/**
	 * Returns all {@link Constraint}s between two given {@link Variable}s.
	 * @param from The source variable of the {@link Constraint}s to find.
	 * @param to The destination variable of the {@link Constraint}s to find.
	 * @return All {@link Constraint}s between the two given {@link Variable}s, null if
	 * no such {@link Constraint} exists.
	 */
	public Constraint[] getConstraints(Variable from, Variable to) {
		Collection edges = this.graph.findEdgeSet(from, to);
		return edges.toArray(new Constraint[edges.size()]);
	}

	/**
	 * Adds a given {@link Variable} to the network.
	 * @param v The {@link Variable} to add to the network.
	 */
	public void addVariable(Variable v) {
		this.graph.addVertex(v);
		this.variables.put(Integer.valueOf(v.getID()), v);
		this.variablesR.put(v, Integer.valueOf(v.getID()));
		logger.finest("Added variable " + v);
		if (listeners != null) {
			ConstraintNetwork added = new ConstraintNetwork(this.solver);
			added.addVariable(v);
			dispatchEvent(added, null);
		}
	}

	/**
	 * Removes a given {@link Variable} from the network.
	 * @param v The {@link Variable} to remove from the network.
	 */
	public void removeVariable(Variable v) {
		this.graph.removeVertex(v);
		this.variables.remove(Integer.valueOf(v.getID()));
		this.variablesR.remove(v);
		logger.finest("Removed variable " + v);
		if (listeners != null) {
			ConstraintNetwork removed = new ConstraintNetwork(this.solver);
			removed.addVariable(v);
			dispatchEvent(null, removed);
		}
	}

	/**
	 * Adds a set of {@link Constraint}s to the network.
	 * @param cons The {@link Constraint}s to add to the network. NOTE: this only works for
	 * {@link BinaryConstraint}s and {@link MultiBinaryConstraint}s in the current implementation. 
	 */
	public void addConstraints(Constraint ... cons) {
		for (Constraint c : cons) this.addConstraint(c);
	}
	
	/**
	 * Adds a {@link Constraint} to the network.
	 * @param c The {@link Constraint} to add to the network. NOTE: this only works for
	 * {@link BinaryConstraint}s and {@link MultiBinaryConstraint}s in the current implementation. 
	 */
	public void addConstraint(Constraint c) {
		if (c instanceof BinaryConstraint || c instanceof MultiBinaryConstraint) {
			this.graph.addEdge(c, c.getScope()[0], c.getScope()[1]);
			logger.finest("Added binary constraint " + c);
			if (listeners != null) {
				ConstraintNetwork added = new ConstraintNetwork(this.solver);
				added.addConstraint(c);
				dispatchEvent(added, null);
			}
		}
		else {
			DummyVariable dv = new DummyVariable(this.solver, c.getEdgeLabel());
			hyperEdges.put(c, dv);
			graph.addVertex(dv);
			for (Variable var : c.getScope()) {
				DummyConstraint dm = new DummyConstraint("");
				dm.setScope(new Variable[] {dv, var});
				this.graph.addEdge(dm, dv, var);
			}
			logger.finest("Added constraint " + c);
			if (listeners != null) {
				ConstraintNetwork added = new ConstraintNetwork(this.solver);
				added.addConstraint(c);
				dispatchEvent(added, null);
			}
		}
	}

	/**
	 * Removes a given {@link Constraint} from the network.
	 * @param c The {@link Constraint} to remove from the network.
	 */
	public void removeConstraint(Constraint c) {
		if (c instanceof BinaryConstraint || c instanceof MultiBinaryConstraint) {
			this.graph.removeEdge(c);
			logger.finest("Removed binary constraint " + c);
			if (listeners != null) {
				ConstraintNetwork removed = new ConstraintNetwork(this.solver);
				removed.addConstraint(c);
				dispatchEvent(null, removed);
			}
		}
		else {
			if (!(c instanceof DummyConstraint)) {
				DummyVariable dv = hyperEdges.get(c);
				Collection incident = graph.getIncidentEdges(dv);
				for (Constraint auxCon : incident) this.graph.removeEdge(auxCon);
				graph.removeVertex(dv);
				hyperEdges.remove(c);
				logger.finest("Removed constraint " + c);
				if (listeners != null) {
					ConstraintNetwork removed = new ConstraintNetwork(this.solver);
					removed.addConstraint(c);
					dispatchEvent(null, removed);
				}
			}
		}
	}

	/**
	 * Gets the source {@link Variable} of a given (binary) {@link Constraint}.
	 * @param c The {@link Constraint} from which to get the source {@link Variable}.
	 * @return The source {@link Variable} of the given {@link Constraint}.
	 */
	public Variable getVariableFrom(Constraint c) {
		return graph.getSource(c);
	}

	/**
	 * Gets the destination {@link Variable} of a given (binary) {@link Constraint}.
	 * @param c The {@link Constraint} from which to get the destination {@link Variable}.
	 * @return The destination {@link Variable} of the given {@link Constraint}.
	 */
	public Variable getVariableTo(Constraint c) {
		return graph.getDest(c);
	}

	/**
	 * Gets a {@link Variable} given its ID.
	 * @param id The ID of the {@link Variable}.
	 * @return The {@link Variable} with the given ID (if it exists).
	 */
	public Variable getVariable(int id) {
		return this.variables.get(id);
	}

	/**
	 * Checks whether the domains of the {@link Variable}s in the {@link ConstraintNetwork} are instantiated.
	 * This is used by the {@link ConstraintSolver} class to assess whether automatic propagation
	 * should occur (in some CSPs, domains of {@link Variable}s cannot be instantiated by the {@link Variable} constructor,
	 * rather an explicit call to a dedicated method is necessary).
	 * @return null if all domains are instantiated; a {@link Variable} whose domain is not instantiated if one exists. 
	 */
	public Variable checkDomainsInstantiated() {
		for (Variable v : this.getVariables())
			if (v.getDomain() == null)
				return v;
		return null;
	}

	/*
	 * draw() is static so you can call this high-level
	 * version to draw an object of a subclass (Java
	 * enforces late-binding)
	 */
	/**
	 * A static method for drawing {@link ConstraintNetwork}s.  This method is static so that
	 * it can be called to draw an object of a subclass (Java enforces late-binding). This method instantiated a {@link JFrame}
	 * containing a rendering of the {@link ConstraintNetwork}.  The rendering is dynamic and attempts to animate transitions
	 * when {@link Constraint} and/or {@link Variable}s are added/removed from the network.
	 * @param cn The {@link ConstraintNetwork} to draw.
	 * @param title The title of the {@link JFrame} containing the rendered {@link ConstraintNetwork}. 
	 */
	public static void draw(ConstraintNetwork cn, String title) {
		Variable v = cn.checkDomainsInstantiated(); 
		if (v == null) new ConstraintNetworkFrame(cn.graph, title, null);
		else throw new NonInstantiatedDomain(v);
	}

	/**
	 * A static method for drawing {@link ConstraintNetwork}s.  This method is static so that
	 * it can be called to draw an object of a subclass (Java enforces late-binding). This method instantiated a {@link JFrame}
	 * containing a rendering of the {@link ConstraintNetwork}.  The rendering is dynamic and attempts to animate transitions
	 * when {@link Constraint} and/or {@link Variable}s are added/removed from the network.
	 * @param cn The {@link ConstraintNetwork} to draw.
	 * @param title The title of the {@link JFrame} containing the rendered {@link ConstraintNetwork}.
	 * @param cb A {@link Callback} object to use when the button is pressed. 
	 */
	public static void draw(ConstraintNetwork cn, String title, Callback cb) {
		Variable v = cn.checkDomainsInstantiated(); 
		if (v == null) new ConstraintNetworkFrame(cn.graph, title, cb);
		else throw new NonInstantiatedDomain(v);
	}

	/**
	 * Same as the static two-argument draw method, using the {@link ConstraintNetwork}'s simple class name as the
	 * title of the {@link JFrame}.
	 * @param cn The {@link ConstraintNetwork} to draw.
	 */
	public static void draw(ConstraintNetwork cn) {
		if (cn.getVariables().length > 0) ConstraintNetwork.draw(cn, cn.getVariables()[0].getConstraintSolver().getClass().getSimpleName(), null);
		else ConstraintNetwork.draw(cn, cn.getClass().getSimpleName(), null);
	}

	/**
	 * Same as the static two-argument draw method, using the {@link ConstraintNetwork}'s simple class name as the
	 * title of the {@link JFrame}.
	 * @param cn The {@link ConstraintNetwork} to draw.
	 * @param cb A {@link Callback} object to use when the button is pressed. 
	 */
	public static void draw(ConstraintNetwork cn, Callback cb) {
		if (cn.getVariables().length > 0) ConstraintNetwork.draw(cn, cn.getVariables()[0].getConstraintSolver().getClass().getSimpleName(), cb);
		else ConstraintNetwork.draw(cn, cn.getClass().getSimpleName(), cb);

	}

	/**
	 * Get all {@link Constraint}s involving a given {@link Variable}. 
	 * @param v The {@link Variable} involved in the {@link Constraint}s.
	 * @return All {@link Constraint}s involving the given {@link Variable}.
	 */
	public Constraint[] getIncidentEdges(Variable v) {
		Collection in = this.graph.getInEdges(v);
		Constraint[] inArray = new Constraint[0];
		if (in != null) inArray = in.toArray(new Constraint[in.size()]);
		Collection out = this.graph.getOutEdges(v);
		Constraint[] outArray = new Constraint[0];
		if (out != null) outArray = out.toArray(new Constraint[out.size()]);
		if (in == null && out == null) return null;
		HashSet retSet = new HashSet();
		for (int i = 0; i < in.size(); i++) retSet.add(inArray[i]);
		for (int i = 0; i < out.size(); i++) retSet.add(outArray[i]);
		Constraint[] ret = retSet.toArray(new Constraint[retSet.size()]);
		//		if(ret.length==0){return null;}
		return ret;
	}
	
	/**
	 * Get all {@link Constraint}s involving a given {@link Variable}, along with all the constraints involving
	 * the dependent variables of this variable (recursively). 
	 * @param v The {@link Variable} involved in the {@link Constraint}s.
	 * @return All {@link Constraint}s involving the given {@link Variable} (including those
	 * involving dependent variables of this variable, recursively).
	 */	
	public Constraint[] getIncidentEdgesIncludingDependentVariables(Variable v) {
		HashSet ret = new HashSet();
		Constraint[] incident = this.getIncidentEdges(v);
		if (incident != null) {
			for (Constraint con : incident) ret.add(con);
		}
		for (Variable var : v.getDependentVariables()) {
			for (Constraint con : var.getConstraintSolver().getConstraintNetwork().getIncidentEdgesIncludingDependentVariables(var)) {
				ret.add(con);
			}
		}
		return ret.toArray(new Constraint[ret.size()]);
	}

	/**
	 * Get all {@link Constraint}s for which a given {@link Variable} is source. 
	 * @param v The {@link Variable} involved in the {@link Constraint}s.
	 * @return All {@link Constraint}s for which a given {@link Variable} is source.
	 */
	public Constraint[] getIngoingEdges(Variable v) {
		Collection in = this.graph.getInEdges(v);
		if (in == null) return null;
		Constraint[] inArray = in.toArray(new Constraint[in.size()]);
		HashSet retSet = new HashSet();
		for (int i = 0; i < in.size(); i++) retSet.add(inArray[i]);
		Constraint[] ret = retSet.toArray(new Constraint[retSet.size()]);
		return ret;
	}


	/**
	 * Get all {@link Constraint}s for which a given {@link Variable} is destination. 
	 * @param v The {@link Variable} involved in the {@link Constraint}s.
	 * @return All {@link Constraint}s for which a given {@link Variable} is destination.
	 */
	public Constraint[] getOutgoingEdges(Variable v) {
		Collection out = this.graph.getOutEdges(v);
		if (out == null) return null;
		Constraint[] outArray = out.toArray(new Constraint[out.size()]);
		HashSet retSet = new HashSet();
		for (int i = 0; i < out.size(); i++) retSet.add(outArray[i]);
		Constraint[] ret = retSet.toArray(new Constraint[retSet.size()]);
		return ret;
	}

	/**
	 * Get all variables in the network.
	 * @return All variables in the network.
	 */
	public Variable[] getVariables() {
		HashSet ret = new HashSet();
		for (Variable v : this.graph.getVertices()) {
			if (!hyperEdges.containsValue(v)) ret.add(v);
		}
		for (Constraint c : hyperEdges.keySet()) {
			for (Variable v : c.getScope()) {
				ret.add(v);
			}
		}
		return ret.toArray(new Variable[ret.size()]);
		//return this.graph.getVertices().toArray(new Variable[this.graph.getVertexCount()]);
	}

	/**
	 * Get all variables in the network with a given component.
	 * @return All variables in the network with a given component.
	 */
	public Variable[] getVariables(String component, Object ... markingsToExclude) {
		if (this.solver != null) {
			return this.solver.getVariables(component, markingsToExclude);
		} else {
			ArrayList ret = new ArrayList();
			for (Variable var : getVariables()) {
				if (var.getComponent() != null && component.equals(var.getComponent())) {
					boolean found = false;
					if (var.getMarking() != null)
						for (Object m : markingsToExclude) {
							if (m.equals(var.getMarking())) {
								found = true;
								break;
							}
						}
					if (!found) ret.add(var);
				}
			}
			return ret.toArray(new Variable[ret.size()]);
		}
	}


	/**
	 * Get all variables in the network with a given component.
	 * @return All variables in the network with a given component.
	 */
	public Variable[] getVariables(String component) {
		if (this.solver != null) {
			return this.solver.getVariables(component);
		} else {
			ArrayList ret = new ArrayList();
			for (Variable var : getVariables()) {
				if (var.getComponent() != null && component.equals(var.getComponent())) {
					ret.add(var);
				}
			}
			return ret.toArray(new Variable[ret.size()]);
		}
	}

	/**
	 * Get all {@link Constraint}s in the network.
	 * @return All the {@link Constraint}s in the network.
	 */
	public Constraint[] getConstraints() {
		Vector ret = new Vector();
		for (Constraint c : this.graph.getEdges()) {
			//if (c.getScope().length == 2) {
			if (c instanceof BinaryConstraint || c instanceof MultiBinaryConstraint) {
				ret.add(c);
			}
		}
		for (Constraint c : hyperEdges.keySet()) ret.add(c);
		return ret.toArray(new Constraint[ret.size()]);
		//return this.graph.getEdges().toArray(new Constraint[this.graph.getEdgeCount()]);
	}


	/**
	 * Query the network for the existence of a given {@link Constraint}. 
	 * @param c The {@link Constraint} for the query. 
	 * @return true iff the network contains the given {@link Constraint} 
	 */
	public boolean containsConstraint(Constraint c) {
		return (this.graph.containsEdge(c) || this.hyperEdges.containsKey(c));
	}

	/**
	 * Query the network for the existence of a given {@link Variable}. 
	 * @param v The {@link Variable} for the query. 
	 * @return true iff the network contains the given {@link Variable} 
	 */
	public boolean containsVariable(Variable v) {
		return this.graph.containsVertex(v);
	}

	/**
	 * Query the network for the existence of a {@link Variable} with a given ID. 
	 * @param ID The ID of the {@link Variable} for the query. 
	 * @return true iff the network contains the {@link Variable} with the given ID.
	 */
	public boolean containsVariable(int ID) {
		Collection vars = this.graph.getVertices();
		for (Variable v : vars) if (v.getID() == ID) return true;
		return false;
	}

	/**
	 * Get a {@link String} representation of this {@link ConstraintNetwork}
	 * (note that {@link MetaConstraintSolver}s use {@link ConstraintNetwork}s as resolvers,
	 * therefore this method is used to draw the edge label in the search tree rendering).
	 * @return A {@link String} representation of this {@link Constraint}.
	 */
	public String getEdgeLabel() {
		String ret = "";
		for (Constraint con : this.getConstraints()) ret += con.toString() + "\n";
		return ret;
	}

	/**
	 * Get a {@link String} representation of this {@link ConstraintNetwork}.
	 * @return A {@link String} representation of this {@link ConstraintNetwork}.
	 */
	public String toString() {
		return "[ConstraintNetwork]: \n\tVertices: " + Arrays.toString(this.getVariables()) + "\n\tConstriants: " + Arrays.toString(this.getConstraints());		
		//		return "[ConstraintNetwork]: marking -> "+ this.getMarking().getState()+"\n\tVertices: " + Arrays.toString(this.getVariables()) + "\n\tConstriants: " + Arrays.toString(this.getConstraints());
	}

	/**
	 * Merges the given {@link ConstraintNetwork} to this.
	 * @param cn The {@link ConstraintNetwork} to merge into this.
	 */
	public void join(ConstraintNetwork cn) {
		for (Variable var : cn.getVariables()) this.addVariable(var);
		for (Constraint con : cn.getConstraints()) this.addConstraint(con);
	}

	/**
	 * Checks if the given {@link ConstraintNetwork} is equal to this.
	 * @return true iff the given {@link ConstraintNetwork} has the same
	 * {@link Variable}s and the same {@link Constraint}s as this.
	 */
	public boolean equals(Object o) {		
		if (!(o instanceof ConstraintNetwork)) return false;
		ConstraintNetwork otherNetwork = (ConstraintNetwork)o;
		for (Variable v : otherNetwork.getVariables()) if (!this.containsVariable(v)) return false;
		for (Constraint c : otherNetwork.getConstraints()) if (!this.containsConstraint(c)) return false;
		for(Variable v: this.getVariables()) if(!otherNetwork.containsVariable(v)) return false;
		for(Constraint c: this.getConstraints()) if (!this.containsConstraint(c))return false;
		return true;
	}

	//	private void writeObject(ObjectOutputStream out) throws IOException {
	//		out.defaultWriteObject();
	//	}
	//
	//	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
	//		in.defaultReadObject();
	//		logger = MetaCSPLogging.getLogger(this.getClass());
	//	}

	/**
	 * Weight associated to the {@link ConstraintNetwork} for some metrics.
	 * @return Weight related to the {@link ConstraintNetwork} 
	 */
	public double getWeight() {
		return weight;
	}

	/**
	 * Weight to associate to the {@link ConstraintNetwork} for some metrics.
	 * @param weight Weight related to the {@link ConstraintNetwork}.
	 */
	public void setWeight(double weight) {
		this.weight = weight;
	}

	/**
	 * Clone this {@link ConstraintNetwork}.
	 * @return A new {@link ConstraintNetwork} of the runtime type of the original.
	 */
	public Object clone() {

		try {
			Constructor c = this.getClass().getConstructor(new Class[] {ConstraintSolver.class});
			ConstraintNetwork ret = (ConstraintNetwork)c.newInstance(new Object[] {this.solver});
			for (Variable v : this.getVariables()) ret.addVariable(v);
			for (Constraint con : this.getConstraints()) ret.addConstraint(con);
			return ret;
		}
		catch (SecurityException e) { e.printStackTrace(); }
		catch (NoSuchMethodException e) { e.printStackTrace(); }
		catch (IllegalArgumentException e) { e.printStackTrace(); }
		catch (InstantiationException e) { e.printStackTrace(); }
		catch (IllegalAccessException e) { e.printStackTrace(); }
		catch (InvocationTargetException e) { e.printStackTrace(); }
		return null;
	}

	/**
	 * Set an annotation for this {@link ConstraintNetwork}.
	 * @param ann An object that should be used to annotate this {@link ConstraintNetwork}.
	 */
	public void setAnnotation(Object ann) { this.annotation = ann; }

	/**
	 * Get the annotation for this {@link ConstraintNetwork}.
	 * @return An object that is used to annotate this {@link ConstraintNetwork}.
	 */
	public Object getAnnotation() { return this.annotation; }

	/**
	 * Get all the substitutions of {@link VariablePrototype}s to {@link Variable}s.
	 * @return All the substitutions of {@link VariablePrototype}s to {@link Variable}s.
	 */
	public HashMap getSubstitutions() {
		return substitutions;
	}

	/**
	 * Get all the inverse substitutions of {@link VariablePrototype}s to {@link Variable}s.
	 * @return All the inverse substitutions of {@link VariablePrototype}s to {@link Variable}s.
	 */
	public HashMap getInverseSubstitutions() {
		return substituted;
	}

	/**
	 * Get the marking of this {@link ConstraintNetwork}.
	 * @return The marking of this {@link ConstraintNetwork}.
	 */
	public ConstraintNetworkMarking getMarking() {
		return marking;
	}
	/**
	 * Set the marking of this {@link ConstraintNetwork}. 
	 * @param marking The marking of this {@link ConstraintNetwork}.
	 */
	public void setMarking(ConstraintNetworkMarking marking) {
		this.marking = marking;
	}

	/**
	 * This method returns the variables which have been created in the network based on {@link VariablePrototype}s (i.e.,
	 * the ones that first were {@link VariablePrototype}s) 
	 * @return The variables which have been created in the network based on {@link VariablePrototype}s. 
	 */
	Variable[] getNativeVariables(){
		return this.substituted.keySet().toArray(new Variable[this.substituted.keySet().size()]);
	}

	private void writeObject(ObjectOutputStream out) throws IOException {
		this.domainValueChoiceFunctions = Domain.valueChoiceFunctions;
		out.defaultWriteObject();
		for (Field f : ConstraintNetwork.class.getDeclaredFields()) {
			if (Modifier.isTransient(f.getModifiers())) {
				try { backupForSerialization.put(new FieldOfObject(f), f.get(this)); }
				catch (IllegalArgumentException e) { e.printStackTrace(); }
				catch (IllegalAccessException e) { e.printStackTrace(); }
			}
		}
	}

	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		for (Field f : ConstraintNetwork.class.getDeclaredFields()) {
			if (Modifier.isTransient(f.getModifiers())) {
				Object foo = backupForSerialization.get(new FieldOfObject(f));
				try { f.set(this, foo); }
				catch (IllegalArgumentException e) { e.printStackTrace(); }
				catch (IllegalAccessException e) { e.printStackTrace(); }
			}
		}
		Domain.valueChoiceFunctions = this.domainValueChoiceFunctions;
		logger = MetaCSPLogging.getLogger(this.getClass());
	}

	/**
	 * Get all {@link Variable}s that are directly connected to a given {@link Variable} through one {@link Constraint}.
	 * @param var The {@link Variable} from which the connected {@link Variable}s are to be computed. 
	 * @return All {@link Variable}s that are directly connected to a given {@link Variable} through one {@link Constraint}.
	 */
	public Variable[] getNeighboringVariables(Variable var) {
		HashSet ret = new HashSet();
		if (var instanceof DummyVariable) return ret.toArray(new Variable[ret.size()]);
		Collection neighbors = this.g.getNeighbors(var);
		for (Variable neighbor : neighbors) {
			if (neighbor instanceof DummyVariable) {
				Collection neighborsOfNeighbor = this.g.getNeighbors(neighbor);
				ret.addAll(neighborsOfNeighbor);
				ret.remove(var);
			}
			else {
				ret.add(neighbor);
			}
		}
		return ret.toArray(new Variable[ret.size()]);
	}


	/**
	 * Masks all {@link Constraint}s in this {@link ConstraintNetwork}.
	 */
	public void maskConstraints() {
		for (Constraint con : this.getConstraints()) con.mask();
	}

	/**
	 * Unmasks all {@link Constraint}s in this {@link ConstraintNetwork}.
	 */
	public void unmaskConstraints() {
		for (Constraint con : this.getConstraints()) con.unmask();
	}

	/**
	 * Masks all given {@link Constraint}s.
	 * @param cons The {@link Constraint}s to mask.
	 */
	public static void maskConstraints(Constraint[] cons) {
		for (Constraint con : cons) con.mask();
	}

	/**
	 * Unmasks all given {@link Constraint}s.
	 * @param cons The {@link Constraint}s to unmask.
	 */
	public static void unmaskConstraints(Constraint[] cons) {
		for (Constraint con : cons) con.unmask();
	}

	/**
	 * Get all {@link Constraint}s that are not masked.
	 * @return All {@link Constraint}s that are not masked.
	 */
	public Constraint[] getUnmaskedConstraints() {
		Vector ret = new Vector();
		for (Constraint con : this.getConstraints()) {
			if (!con.isMasked()) ret.add(con);
		}
		return ret.toArray(new Constraint[ret.size()]);
	}

	/**
	 * Get all {@link Constraint}s that are not masked.
	 * @return All {@link Constraint}s that are not masked.
	 */
	public Constraint[] getMaskedConstraints() {
		Vector ret = new Vector();
		for (Constraint con : this.getConstraints()) {
			if (con.isMasked()) ret.add(con);
		}
		return ret.toArray(new Constraint[ret.size()]);
	}
	
	public static void saveConstraintNetwork(ConstraintNetwork cn, String filename) {
		try {
			FileOutputStream out = new FileOutputStream(filename);
			ObjectOutputStream oos = new ObjectOutputStream(out);
			oos.writeObject(cn);
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		catch (IOException e) { e.printStackTrace(); }		
	}

	public static void saveConstraintNetwork(ConstraintNetwork cn, File file) {
		try {
			FileOutputStream out = new FileOutputStream(file);
			ObjectOutputStream oos = new ObjectOutputStream(out);
			oos.writeObject(cn);
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		catch (IOException e) { e.printStackTrace(); }		
	}

	public static ConstraintNetwork loadConstraintNetwork(String filename) {
		try {
			FileInputStream in = new FileInputStream(filename);
			ObjectInputStream ois = new ObjectInputStream(in);
			ConstraintNetwork con = (ConstraintNetwork)ois.readObject();
			return con;
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		catch (IOException e) { e.printStackTrace(); }
		catch (ClassNotFoundException e) { e.printStackTrace(); }
		return null;
	}

	public static ConstraintNetwork loadConstraintNetwork(File file) {
		try {
			FileInputStream in = new FileInputStream(file);
			ObjectInputStream ois = new ObjectInputStream(in);
			ConstraintNetwork con = (ConstraintNetwork)ois.readObject();
			return con;
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		catch (IOException e) { e.printStackTrace(); }
		catch (ClassNotFoundException e) { e.printStackTrace(); }
		return null;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy