/* A solver for ontologies. * * Copyright (c) 2007-2009 The Regents of the University of California. All * rights reserved. * * Permission is hereby granted, without written agreement and without license * or royalty fees, to use, copy, modify, and distribute this software and its * documentation for any purpose, provided that the above copyright notice and * the following two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN * "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ package ptolemy.data.ontologies; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.net.URI; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import ptolemy.actor.TypeConflictException; import ptolemy.data.BooleanToken; import ptolemy.data.expr.ASTPtAssignmentNode; import ptolemy.data.expr.ASTPtRootNode; import ptolemy.data.expr.FileParameter; import ptolemy.data.expr.Parameter; import ptolemy.data.expr.StringParameter; import ptolemy.data.ontologies.PropertyConstraintHelper.Inequality; import ptolemy.data.type.BaseType; import ptolemy.data.type.MonotonicFunction; import ptolemy.domains.fsm.kernel.FSMActor; import ptolemy.domains.tester.lib.Testable; import ptolemy.graph.CPO; import ptolemy.graph.InequalityTerm; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.attributes.URIAttribute; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.KernelException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; import ptolemy.util.FileUtilities; ////////////////////////////////////////////////////////////////////////// //// OntologySolver /** * An instance of this solver contains a <i>use case</i>, which itself * contains a lattice and default constraints. * <p> * This class is based on the PropertyConstraintSolver in the properties package * by Man-Kit Leung. * * @author Man-Kit Leung, Edward A. Lee * @version $Id$ * @since Ptolemy II 7.1 * @Pt.ProposedRating Red (mankit) * @Pt.AcceptedRating Red (mankit) */ public class OntologySolver extends PropertySolver implements Testable { /** * @param container The given container. * @param name The given name * @exception IllegalActionException * @exception NameDuplicationException */ public OntologySolver(NamedObj container, String name) throws IllegalActionException, NameDuplicationException { super(container, name); // Provide a default model so that this is never empty. _model = new CompositeEntity(workspace()); solvingFixedPoint = new StringParameter(this, "solvingFixedPoint"); solvingFixedPoint.setExpression("least"); actorConstraintType = new StringParameter(this, "actorConstraintType"); actorConstraintType.setExpression("out >= in"); connectionConstraintType = new StringParameter(this, "connectionConstraintType"); connectionConstraintType.setExpression("sink >= src"); compositeConnectionConstraintType = new StringParameter(this, "compositeConnectionConstraintType"); compositeConnectionConstraintType.setExpression("sink >= src"); fsmConstraintType = new StringParameter(this, "fsmConstraintType"); fsmConstraintType.setExpression("sink >= src"); expressionASTNodeConstraintType = new StringParameter(this, "expressionASTNodeConstraintType"); expressionASTNodeConstraintType.setExpression("parent >= child"); logMode = new Parameter(this, "logMode"); logMode.setTypeEquals(BaseType.BOOLEAN); logMode.setExpression("false"); // Set to path of the model. logDirectory = new FileParameter(this, "Log directory"); // In Windows, this should map to C:\temp\, /home/tmp/ in Linux. logDirectory.setExpression("$HOME/temp/ConstraintFiles"); trainedConstraintDirectory = new FileParameter(this, "Trained constraint directory"); trainedConstraintDirectory .setExpression("$CLASSPATH/trainedConstraints"); _addChoices(); _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-50\" y=\"-20\" width=\"120\" height=\"40\" " + "style=\"fill:blue\"/>" + "<text x=\"-40\" y=\"-5\" " + "style=\"font-size:12; font-family:SansSerif; fill:white\">" + "Double click to\nResolve Properties</text></svg>"); /* Removed to make compile * --Ben on 12/04/2009 new PropertySolverGUIFactory(this, "_propertyConstraintSolverGUIFactory"); */ } /////////////////////////////////////////////////////////////////// //// ports and parameters //// /** * */ public static enum ConstraintType { EQUALS, NONE, NOT_EQUALS, SINK_EQUALS_GREATER, SINK_EQUALS_MEET, SINK_GREATER, SRC_EQUALS_GREATER, SRC_EQUALS_MEET, SRC_GREATER } public void addAnnotated(Object object) { _annotatedObjects.add(object); } /** * React to a change in an attribute. * @param attribute The attribute that changed. * @exception IllegalActionException If the change is not acceptable to this * container (not thrown in this class). */ public void attributeChanged(Attribute attribute) throws IllegalActionException { if (attribute == logMode) { _logMode = logMode.getToken() == BooleanToken.TRUE; } super.attributeChanged(attribute); } public List<ptolemy.graph.InequalityTerm> getAffectedTerms(ptolemy.graph.InequalityTerm updateTerm) throws IllegalActionException { return _propertyTermManager.getAffectedTerms(updateTerm); } /** * @return the constraintManager */ public ConstraintManager getConstraintManager() { return _constraintManager; } /** * Returns the adapter that contains property information for the given AST * node. * @param node The given ASTPtRootNode. * @return The associated property constraint adapter. */ public PropertyConstraintASTNodeHelper getHelper(ASTPtRootNode node) throws IllegalActionException { return (PropertyConstraintASTNodeHelper) _getHelper(node); } /** * Returns the adapter that contains property information for the given * component. * @param component The given component * @return The associated property constraint adapter. */ public PropertyHelper getHelper(NamedObj component) throws IllegalActionException { return _getHelper(component); } /** * Return the property constraint adapter associated with the given object. * @param object The given object. */ public PropertyHelper getHelper(Object object) throws IllegalActionException { return _getHelper(object); } /////////////////////////////////////////////////////////////////// //// public methods //// /** * Return the property value associated with the specified object. * @param object The specified object. * @return The property of the specified object. */ public Concept getProperty(Object object) { try { return (Concept) getPropertyTerm(object).getValue(); } catch (IllegalActionException ex) { return null; } } /** * Return the property term from the given object. * @param object The given object. * @return The property term of the given object. * @exception IllegalActionException */ public ptolemy.graph.InequalityTerm getPropertyTerm(Object object) { return getPropertyTermManager().getPropertyTerm(object); } public PropertyTermFactory getPropertyTermManager() { if (_propertyTermManager == null) { _propertyTermManager = _getPropertyTermManager(); } return _propertyTermManager; } public boolean isAnnotatedTerm(Object object) { return _annotatedObjects.contains(object); } /** * Return true if the solver is in collect constraints mode; otherwise, * return false. * @return True if the solver is in collect constraints mode; otherwise, * return false. */ public boolean isCollectConstraints() { return action.getExpression().equals(COLLECT_CONSTRAINTS); } /** * Return true if the solver is in initialization mode; otherwise, return * false. * @return True if the solver is in initialization mode; otherwise, return * false. */ public boolean isInitializeSolver() { return action.getExpression().equals(INITIALIZE_SOLVER); } public Boolean isLogMode() { return _logMode; } /** * Override the base class method. Return true if the solver is in * initialization mode; otherwise, return the result of the super method * (default). * @return True if the solver is in initialization mode; otherwise, return * the result of the super method (default). */ public boolean isResolve() { return isCollectConstraints() || isInitializeSolver() || super.isResolve(); } /////////////////////////////////////////////////////////////////// //// public methods //// public void reset() { super.reset(); _propertyTermManager = null; _trainedConstraints.clear(); } public void setLogMode(boolean isLogMode) { _logMode = isLogMode; } /** * Prepare for automatic testing. */ public void setOptions(Map options) { super.setOptions(options); // By default, look up the logMode parameter in the model to // see if we need to test the constraints. if (options.containsKey(NONDEEP_TEST_OPTION)) { setLogMode(false); } if (isLogMode()) { System.out.println("doing deep testing."); } else { System.out.println("NOT deep testing: " + options.size()); } } /** Run a test. This invokes the solver in TEST mode. * @throws IllegalActionException If the test fails. */ public void test() throws IllegalActionException { // FIXME: Brute force method here just sets the action to TEST. // However, the TEST and TRAINING modes should be removed. String previousAction = action.getExpression(); try { action.setExpression(TEST); invokeSolver(); resetAll(); } finally { action.setExpression(previousAction); } } /** Train a test. This invokes the solver in TRAINING mode. */ public void train() { // FIXME: Brute force method here just sets the action to TRAINING. // However, the TEST and TRAINING modes should be removed. String previousAction = action.getExpression(); try { workspace().getWriteAccess(); action.setExpression(TRAINING); invokeSolver(); resetAll(); } finally { action.setExpression(previousAction); workspace().doneWriting(); } } /** * Update the property. * @exception IllegalActionException */ public void updateProperties() throws IllegalActionException { super.updateProperties(); // Only need to look at the constraints of the top level adapter. PropertyHelper adapter; adapter = getHelper(_toplevel()); if (isLogMode()) { String constraintFilename = _getTrainedConstraintFilename() + "_resolved.txt"; if (super.isResolve()) { _trainedConstraints.clear(); // Populate the _trainedConstraints list. _logHelperConstraints((PropertyConstraintHelper) adapter); // Write the list to file. _updateConstraintFile(constraintFilename); } else if (isTesting() && isLogMode()) { // Populate the _trainedConstraints list. _readConstraintFile(constraintFilename); // Match and remove from the list. _regressionTestConstraints((PropertyConstraintHelper) adapter); // Check if there are unmatched constraints. _checkMissingConstraints(); } } } protected PropertyHelper _getHelper(Object component) throws IllegalActionException { PropertyHelper adapter = null; try { adapter = super._getHelper(component); } catch (IllegalActionException ex) { } if (adapter == null) { if (component instanceof FSMActor) { /* Removed to make compile * --Ben on 12/04/2009 adapter = new PropertyConstraintFSMHelper(this, (FSMActor) component); } else if (component instanceof ptolemy.domains.modal.kernel.FSMActor) { adapter = new PropertyConstraintModalFSMHelper(this, (ptolemy.domains.modal.kernel.FSMActor) component); } else if (component instanceof CompositeEntity) { adapter = new PropertyConstraintCompositeHelper(this, (CompositeEntity) component); } else if (component instanceof ASTPtRootNode) { adapter = new PropertyConstraintASTNodeHelper(this, (ASTPtRootNode) component); */ } else { adapter = new PropertyConstraintHelper(this, component); } } _adapterStore.put(component, adapter); return adapter; } /** * Return a new property term manager. Subclass can implements a its own * manager and override this method to instantiate a instance of the new * class. * @return A property term manager. */ protected PropertyTermManager _getPropertyTermManager() { // FIXME: doesn't work for other use-cases! // return new StaticDynamicTermManager(this); return new PropertyTermManager(this); } protected void _initializeStatistics() { super._initializeStatistics(); getStats().put("# of default constraints", 0); getStats().put("# of composite default constraints", 0); getStats().put("# of atomic actor default constraints", 0); getStats().put("# of AST default constraints", 0); getStats().put("# of generated constraints", 0); getStats().put("# of trained constraints", 0); } /** * Resolve the property values for the toplevel entity that contains this * solver, given the model analyzer that invokes this. * @param analyzer The given model analyzer. */ protected void _resolveProperties(NamedObj analyzer) throws KernelException { super._resolveProperties(analyzer); NamedObj toplevel = _toplevel(); PropertyConstraintHelper toplevelHelper = (PropertyConstraintHelper) getHelper(toplevel); toplevelHelper.reinitialize(); toplevelHelper ._addDefaultConstraints(_getConstraintType(actorConstraintType .stringValue())); // FIXME: have to generate the connection every time // because the model structure can changed. // (i.e. adding or removing connections.) toplevelHelper._setConnectionConstraintType( _getConstraintType(connectionConstraintType.stringValue()), _getConstraintType(compositeConnectionConstraintType .stringValue()), _getConstraintType(fsmConstraintType .stringValue()), _getConstraintType(expressionASTNodeConstraintType .stringValue())); // Collect and solve type constraints. /* FIXME: Removing chunks of code wholesale now. * --Ben 12/04/2009 List<Inequality> constraintList = toplevelHelper.constraintList(); _resolveProperties(toplevel, toplevelHelper, constraintList); */ } /** Resolve the properties of the given top-level container, * subject to the given constraint list. * * @param toplevel The top-level container * @param toplevelHelper Must be toplevel.getHelper() * @param constraintList The constraint list that we are solving * @throws TypeConflictException If an unacceptable solution is reached * @throws PropertyResolutionException If constraints are unsatisfiable */ protected void _resolveProperties(NamedObj toplevel, PropertyConstraintHelper toplevelHelper, List<Inequality> constraintList) throws TypeConflictException, PropertyResolutionException { Writer writer = null; List<Inequality> conflicts = new LinkedList<Inequality>(); List<Inequality> unacceptable = new LinkedList<Inequality>(); try { // Check declared properties across all connections. //List propertyConflicts = topLevel._checkDeclaredProperties(); //conflicts.addAll(propertyConflicts); /* * // FIXME: this is the iterative approach. List constraintList = * new ArrayList(); Iterator adapters = * _adapterStore.values().iterator(); while (adapters.hasNext()) { * PropertyConstraintHelper adapter = (PropertyConstraintHelper) * adapters.next(); * * constraintList.addAll(adapter.constraintList()); } // */ // NOTE: To view all property constraints, uncomment these. /* * Iterator constraintsIterator = constraintList.iterator(); while * (constraintsIterator.hasNext()) { * System.out.println(constraintsIterator.next().toString()); } */ if (constraintList.size() > 0) { CPO lattice = getLattice(); // Instantiate our own customized version of InequalitySolver. ptolemy.graph.InequalitySolver solver = new ptolemy.graph.InequalitySolver(lattice); //InequalitySolver solver = new InequalitySolver(cpo, this); solver.addInequalities(constraintList.iterator()); /* FIXME: Removing chunks of code wholesale now. * --Ben 12/04/2009 _constraintManager.setConstraints(constraintList); */ // BEGIN CHANGE Thomas, 04/10/2008 // Collect statistics. getStats().put("# of generated constraints", constraintList.size()); getStats().put("# of property terms", _propertyTermManager.terms().size()); // log initial constraints to file File file = null; Date date = new Date(); String timestamp = date.toString().replace(":", "_"); String logFilename = getContainer().getName() + "__" + getName() + "__" + timestamp.replace(" ", "_") + ".txt"; if (super.isResolve() && isLogMode()) { String directoryPath = logDirectory.getExpression(); directoryPath += directoryPath.endsWith("/") || directoryPath.endsWith("\\") ? "" : "/"; if (directoryPath.startsWith("$CLASSPATH")) { URI directory = new File(URIAttribute.getModelURI(this)) .getParentFile().toURI(); file = FileUtilities.nameToFile(directoryPath .substring(11) + logFilename, directory); } else { if (!logDirectory.asFile().exists()) { if (!logDirectory.asFile().mkdirs()) { throw new IllegalActionException(this, "Failed to create \"" + logDirectory.asFile() .getAbsolutePath() + "\" directory."); } } file = FileUtilities.nameToFile(logFilename, logDirectory.asFile().toURI()); } try { if (!file.exists()) { if (!file.getParentFile().exists()) { if (!file.getParentFile().mkdirs()) { throw new IllegalActionException(this, "Failed to create \"" + file.getParentFile() .getAbsolutePath() + "\" directory."); } } if (!file.createNewFile()) { throw new IllegalActionException(this, "Failed to create \"" + file.getAbsolutePath() + "\"."); } } writer = new FileWriter(file); writer.write(_getStatsAsString("\t")); writer.write(_getConstraintsAsLogFileString( constraintList, "I")); } catch (IOException ex) { throw new PropertyResolutionException(this, ex, "Error writing to constraint log file \"" + file.getAbsolutePath() + "\"."); } } // Record the initial constraints. // FIXME: merge comment: Jackies code is "if (super.isResolve() && isLogMode()) {"; why different? // FIXME: Charles Shelton 05/27/09 - We took the change that Jackie made to include the isLogMode() condition. if (super.isResolve() && isLogMode()) { String constraintFilename = _getTrainedConstraintFilename() + "_initial.txt"; // Populate the _trainedConstraints list. _logHelperConstraints(toplevelHelper); // Write the list to file. _updateConstraintFile(constraintFilename); } // END CHANGE Thomas, 04/10/2008 if (!isCollectConstraints()) { // Find the greatest solution (most general type) if (solvingFixedPoint.stringValue().equals("greatest")) { solver.solveGreatest(); } else { solver.solveLeast(); } } // log resolved constraints to file. if (super.isResolve() && isLogMode()) { try { writer.write(_getConstraintsAsLogFileString( constraintList, "R")); writer.close(); } catch (IOException ex) { throw new PropertyResolutionException(this, ex, "Error writing to constraint log file \"" + file.getAbsolutePath() + "\"."); } } // If some inequalities are not satisfied, or type variables // are resolved to unacceptable types, such as // BaseType.UNKNOWN, add the inequalities to the list of // property conflicts. for (Inequality inequality : constraintList) { if (!inequality.isSatisfied(lattice)) { conflicts.add(inequality); } else { // Check if there exist an unacceptable term value. boolean isAcceptable = true; InequalityTerm[] lesserVariables = inequality .getLesserTerm().getVariables(); InequalityTerm[] greaterVariables = inequality .getGreaterTerm().getVariables(); for (InequalityTerm variable : lesserVariables) { if (!variable.isValueAcceptable()) { unacceptable.add(inequality); isAcceptable = false; break; } } if (isAcceptable) { // Continue checking for unacceptable terms. for (InequalityTerm variable : greaterVariables) { if (!variable.isValueAcceptable()) { unacceptable.add(inequality); break; } } } } } } // Check for solution correctness. // In initialize mode, we can skip this. if (!isInitializeSolver() && !isCollectConstraints()) { if (conflicts.size() > 0) { throw new PropertyResolutionException(this, toplevel(), "Properties conflicts occurred in " + toplevel().getFullName() + " on the following inequalities:\n" + conflicts); } if (unacceptable.size() > 0) { throw new TypeConflictException(unacceptable, "Properties resolved to unacceptable types in " + toplevel.getFullName() + " due to the following inequalities:"); } } } catch (IllegalActionException ex) { // This should not happen. The exception means that // _checkDeclaredProperty or constraintList is called on a // transparent actor. throw new PropertyResolutionException(this, toplevel, ex, "Concept resolution failed because of an error " + "during property inference"); } finally { if (writer != null) { try { writer.close(); } catch (IOException ex) { throw new PropertyResolutionException(this, toplevel(), ex, "Failed to close a file"); } } } } /** * Add choices to the parameters. * @exception IllegalActionException If there is a problem accessing files * or parameters. */ private void _addChoices() throws IllegalActionException { solvingFixedPoint.addChoice("least"); solvingFixedPoint.addChoice("greatest"); actorConstraintType.addChoice("in >= out"); actorConstraintType.addChoice("out >= in"); actorConstraintType.addChoice("out == in"); actorConstraintType.addChoice("out == meet(in1, in2, ...)"); actorConstraintType.addChoice("in == meet(out1, out2, ...)"); actorConstraintType.addChoice("NONE"); // actorConstraintType.addChoice("in > out"); // actorConstraintType.addChoice("out > in"); // actorConstraintType.addChoice("out != in"); connectionConstraintType.addChoice("src >= sink"); connectionConstraintType.addChoice("sink >= src"); connectionConstraintType.addChoice("sink == src"); connectionConstraintType.addChoice("src == meet(sink1, sink2, ...)"); connectionConstraintType.addChoice("sink == meet(src1, src2, ...)"); connectionConstraintType.addChoice("NONE"); // connectionConstraintType.addChoice("src > sink"); // connectionConstraintType.addChoice("sink > src"); // connectionConstraintType.addChoice("sink != src"); compositeConnectionConstraintType.addChoice("src >= sink"); compositeConnectionConstraintType.addChoice("sink >= src"); compositeConnectionConstraintType.addChoice("sink == src"); compositeConnectionConstraintType .addChoice("src == meet(sink1, sink2, ...)"); compositeConnectionConstraintType .addChoice("sink == meet(src1, src2, ...)"); compositeConnectionConstraintType.addChoice("NONE"); // compositeConnectionConstraintType.addChoice("src > sink"); // compositeConnectionConstraintType.addChoice("sink > src"); // compositeConnectionConstraintType.addChoice("sink != src"); expressionASTNodeConstraintType.addChoice("child >= parent"); expressionASTNodeConstraintType.addChoice("parent >= child"); expressionASTNodeConstraintType.addChoice("parent == child"); //expressionASTNodeConstraintType.addChoice("child == meet(parent1, parent2, ...)"); expressionASTNodeConstraintType .addChoice("parent == meet(child1, child2, ...)"); expressionASTNodeConstraintType.addChoice("NONE"); // expressionASTNodeConstraintType.addChoice("child > parent"); // expressionASTNodeConstraintType.addChoice("parent > child"); // expressionASTNodeConstraintType.addChoice("parent != child"); fsmConstraintType.addChoice("src >= sink"); fsmConstraintType.addChoice("sink >= src"); fsmConstraintType.addChoice("sink == src"); fsmConstraintType.addChoice("src == meet(sink1, sink2, ...)"); fsmConstraintType.addChoice("sink == meet(src1, src2, ...)"); fsmConstraintType.addChoice("NONE"); // fsmConstraintType.addChoice("src > sink"); // fsmConstraintType.addChoice("sink > src"); // fsmConstraintType.addChoice("sink != src"); action.addChoice(INITIALIZE_SOLVER); action.addChoice(COLLECT_CONSTRAINTS); } private void _checkMissingConstraints() { StringBuffer errorMessage = new StringBuffer(_eol + "Concept \"" + getName() + "\" resolution failed." + _eol); boolean hasError = false; for (String trainedValue : _trainedConstraints) { errorMessage.append(" Missing constraint: \"" + trainedValue + "\"." + _eol); hasError = true; } if (hasError) { getSharedUtilities().addErrors(errorMessage.toString()); } } // /** // * Return the property value associated with the given property lattice // * and the given port. // * @param object The given port. // * @param lattice The given lattice. // * @return The property value of the given port. // * @exception IllegalActionException // */ // public Concept getProperty(Object object) { // ptolemy.graph.InequalityTerm term = (ptolemy.graph.InequalityTerm) getPropertyTerm(object); // return (Concept) term.getValue(); // } /** * Return the Constraints as a log file string. * @param inequality * @param annotation * @return The Constraints. * @exception IllegalActionException */ private List _getConstraintAsLogFileString(Inequality inequality, String annotation) throws IllegalActionException { List<String> logConstraints = new LinkedList<String>(); String output = ""; ptolemy.graph.InequalityTerm lesserTerm = (ptolemy.graph.InequalityTerm) inequality.getLesserTerm(); ptolemy.graph.InequalityTerm greaterTerm = (ptolemy.graph.InequalityTerm) inequality.getGreaterTerm(); output = inequality.getHelper().getClass().getPackage().toString() .replace("package ", "") + "\t" + inequality.getHelper().getClass().getSimpleName() + "\t" + _getReducedFullName(inequality.getHelper().getComponent()) + "\t" + (inequality.isBase() ? "base" : "not base") + "\t" + _getConstraintLogString(lesserTerm, "") + "\t" + "<=" + "\t" + _getConstraintLogString(greaterTerm, ""); logConstraints.add(output); // also write variables of FunctionTerms to log-Files if (lesserTerm instanceof MonotonicFunction) { for (InequalityTerm variable : lesserTerm.getVariables()) { output = inequality.getHelper().getClass().getPackage() .toString().replace("package ", "") + "\t" + inequality.getHelper().getClass().getSimpleName() + "\t" + _getReducedFullName(inequality.getHelper() .getComponent()) + "\t" + (inequality.isBase() ? "base" : "not base") + "\t" + _getConstraintLogString((ptolemy.graph.InequalityTerm) variable, "") + "\t" + "MFV" + "\t" + _getConstraintLogString(lesserTerm, _getReducedFullName(inequality.getHelper() .getComponent())); logConstraints.add(output); } /* FIXME: Removing chunks of code wholesale now. * --Ben 12/04/2009 for (InequalityTerm constant : lesserTerm.getConstants()) { output = inequality.getHelper().getClass().getPackage() .toString().replace("package ", "") + "\t" + inequality.getHelper().getClass().getSimpleName() + "\t" + _getReducedFullName(inequality.getHelper() .getComponent()) + "\t" + (inequality.isBase() ? "base" : "not base") + "\t" + _getConstraintLogString((ptolemy.graph.InequalityTerm) constant, "") + "\t" + "MFC" + "\t" + _getConstraintLogString(lesserTerm, _getReducedFullName(inequality.getHelper() .getComponent())); logConstraints.add(output); } */ } return logConstraints; } private String _getConstraintLogString(ptolemy.graph.InequalityTerm propertyTerm, String actorName) throws IllegalActionException { if (propertyTerm instanceof Concept) { // FIXME: This is bogus unreadable syntax. "eff" means "effective" // (whatever that means). return (true ? "eff" : "ineff") + "\t" + "\t" + propertyTerm.getClass().getSuperclass().getSimpleName() + "\t" + propertyTerm.toString() + "\t" + propertyTerm.getValue(); } else if (propertyTerm instanceof MonotonicFunction) { return (true ? "eff" : "ineff") + "\t" + actorName + "\t" + propertyTerm.getClass().getSuperclass().getSimpleName() + "\t" + propertyTerm.getClass().toString() .substring( propertyTerm.getClass().toString() .lastIndexOf(".")) + "\t" + propertyTerm.getValue(); } else { Object object = propertyTerm.getAssociatedObject(); String containerName = ""; if (object != null) { if (object instanceof ASTPtRootNode) { try { if (((ASTPtRootNode) object).jjtGetParent() != null && !(((ASTPtRootNode) object).jjtGetParent() instanceof ASTPtAssignmentNode)) { containerName = _getReducedFullName(((ASTPtRootNode) object) .jjtGetParent()); } else { containerName = _getReducedFullName(getHelper( object).getContainerEntity( (ASTPtRootNode) object)); } } catch (IllegalActionException e) { assert false; } } // FIXME: effective is not implemented. return (true ? "eff" : "ineff") + "\t" + containerName + "\t" + object.getClass().getSimpleName() + "\t" + _getReducedFullName(object) + "\t" + propertyTerm.getValue(); } else { return "NO" + "\t" + "ASSOCIATED" + "\t" + "OBJECT"; } } } private String _getConstraintsAsLogFileString( List<Inequality> constraintList, String annotation) throws IllegalActionException { StringBuffer output = new StringBuffer(); for (Inequality inequality : constraintList) { output.append(_getConstraintAsLogFileString(inequality, annotation) + _eol); } return output.toString(); } /** * Return the constraint type. * @param typeValue * @return The constraint type. * @exception IllegalActionException */ protected static ConstraintType _getConstraintType(String typeValue) throws IllegalActionException { boolean isEquals = typeValue.contains("=="); boolean isSrc = typeValue.startsWith("src") || typeValue.startsWith("in") || typeValue.startsWith("child"); boolean isNotEquals = typeValue.contains("!="); boolean hasMeet = typeValue.contains("meet"); if (typeValue.equals("NONE")) { return ConstraintType.NONE; } if (hasMeet) { return isSrc ? ConstraintType.SRC_EQUALS_MEET : ConstraintType.SINK_EQUALS_MEET; } else if (isEquals) { return ConstraintType.EQUALS; } else if (isNotEquals) { return ConstraintType.NOT_EQUALS; } else { return isSrc ? ConstraintType.SRC_EQUALS_GREATER : ConstraintType.SINK_EQUALS_GREATER; } } private String _getReducedFullName(Object object) { if (object instanceof NamedObj) { String name = ((NamedObj) object).getFullName(); if (name.indexOf(".", 2) > 0) { name = name.substring(name.indexOf(".", 2)); } else { name = "topLevelComposite"; } return name; } else { return object.toString(); } } /** * Return the trained constraint filename. * @return The trained constraint filename. * @exception IllegalActionException If there is a problem getting the name * of the top level or the value of the <i>trainedConstraintDirectory</i> * parameter. */ private String _getTrainedConstraintFilename() throws IllegalActionException { // Make an unique file name from the toplevel container. // FIXME: don't use __, they make the filenames too long. String constraintFilename = _toplevel().getName() + "__" + getName(); String directoryPath = trainedConstraintDirectory.getExpression(); directoryPath = directoryPath.replace("\\", "/"); directoryPath += directoryPath.endsWith("/") || directoryPath.endsWith("\\") ? "" : "/"; File constraintFile; if (directoryPath.startsWith("$CLASSPATH")) { // FIXME: for a cloned URIAttribute, the URI is not set. URI directory = new File(URIAttribute.getModelURI(this)) .getParentFile().toURI(); constraintFile = FileUtilities.nameToFile(directoryPath .substring(11) + constraintFilename, directory); } else { if (!trainedConstraintDirectory.asFile().exists()) { if (!trainedConstraintDirectory.asFile().mkdirs()) { throw new IllegalActionException(this, "Failed to create \"" + trainedConstraintDirectory.asFile() .getAbsolutePath() + "\" directory."); } } constraintFile = FileUtilities.nameToFile(constraintFilename, trainedConstraintDirectory.asFile().toURI()); } return constraintFile.getAbsolutePath().replace("\\", "/").replaceAll( "%5c", "/"); } /** * * @param adapter * @exception IllegalActionException */ private void _logHelperConstraints(PropertyConstraintHelper adapter) throws IllegalActionException { List<Inequality>[] constraintSet = new List[2]; /* FIXME: Removing chunks of code wholesale now. * --Ben 12/04/2009 constraintSet[0] = adapter._ownConstraints; constraintSet[1] = adapter._subHelperConstraints; for (int i = 0; i < 2; i++) { //String whichSet = (i == 0) ? " own " : " subHelper's "; for (Inequality constraint : constraintSet[i]) { Iterator logConstraints = _getConstraintAsLogFileString( constraint, "").iterator(); while (logConstraints.hasNext()) { _trainedConstraints.add((String) logConstraints.next()); } } } */ } private void _readConstraintFile(String filename){ File file = new File(filename); try { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); String line = reader.readLine(); while (line != null) { _trainedConstraints.add(line); line = reader.readLine(); } getStats().put("# of trained constraints", _trainedConstraints.size()); } finally { if (reader != null) { reader.close(); } } } catch (IOException ex) { /* FIXME: Removed to make compile * --Ben 12/04/2009 throw new PropertyFailedRegressionTestException(this, "Failed to open or read the constraint file \"" + filename + "\"."); */ } } private void _regressionTestConstraints(PropertyConstraintHelper adapter) throws IllegalActionException { Object object = adapter.getComponent(); if (!(object instanceof NamedObj)) { return; } NamedObj namedObj = (NamedObj) object; StringBuffer errorMessage = new StringBuffer(_eol + "Concept \"" + getName() + "\" resolution failed for " + namedObj.getFullName() + "'s adapter." + _eol); List<Inequality>[] constraintSet = new List[2]; /* FIXME: Removing chunks of code wholesale now. * --Ben 12/04/2009 constraintSet[0] = adapter._ownConstraints; constraintSet[1] = adapter._subHelperConstraints; boolean hasError = false; for (int i = 0; i < 2; i++) { String whichSet = i == 0 ? " own " : " subHelper's "; for (Inequality constraint : constraintSet[i]) { Iterator logConstraints = _getConstraintAsLogFileString( constraint, "").iterator(); while (logConstraints.hasNext()) { String constraintString = (String) logConstraints.next(); // Remove from the trained set so we can test for duplicates. if (!_trainedConstraints.remove(constraintString)) { errorMessage.append(" Extra" + whichSet + "constraint generated: \"" + constraintString + "\"." + _eol); hasError = true; } } } } if (hasError) { getSharedUtilities().addErrors(errorMessage.toString()); } */ } /** * Log the trained constraints in a subdirectory under the specified * logDirectory. The contraint file has an unique name consist of the name * of toplevel container and this solver. If the constraint file already * exists, an overwrite warning message is sent to the user. * @param filename * @exception PropertyResolutionException Thrown if there is a problem * opening, writing, or closing the constraint file. */ private void _updateConstraintFile(String filename) throws IllegalActionException { if (!super.isResolve() || !isLogMode()) { return; } try { File constraintFile = new File(filename); if (constraintFile.exists()) { if (_analyzer != null && ((Parameter) _analyzer .getAttribute("overwriteConstraint")) .getExpression().equals("false")) { return; } // Ask user for a decision. if (_analyzer == null && !isLogMode()) { /* * !MessageHandler.yesNoQuestion( "The constraint file \"" + * filename + "\"" + " exists. OK to overwrite?")) { */ // Don't overwrite, do nothing and return. return; } } else { if (!constraintFile.getParentFile().exists()) { if (!constraintFile.getParentFile().mkdirs()) { throw new IllegalActionException(this, "Failed to create \"" + constraintFile.getParentFile() .getAbsolutePath() + "\" directory."); } } if (!constraintFile.createNewFile()) { throw new IllegalActionException(this, "Failed to create \"" + constraintFile.getAbsolutePath() + "\"."); } } Writer writer = null; try { writer = new FileWriter(filename); for (String constraint : _trainedConstraints) { writer.write(constraint + _eol); } } finally { writer.close(); } } catch (IOException ex) { throw new PropertyResolutionException(this, ex, "Failed to train the constraint log file \"" + filename + "\"."); } } public StringParameter actorConstraintType; public StringParameter compositeConnectionConstraintType; public StringParameter connectionConstraintType; public StringParameter expressionASTNodeConstraintType; public StringParameter fsmConstraintType; public FileParameter logDirectory; /////////////////////////////////////////////////////////////////// //// private methods //// public Parameter logMode; /** * Indicate whether to compute the least or greatest fixed point solution. */ public StringParameter solvingFixedPoint; public FileParameter trainedConstraintDirectory; /** * The set of Object that has been manually annotated. */ private final HashSet<Object> _annotatedObjects = new HashSet<Object>(); private final ConstraintManager _constraintManager = new ConstraintManager( this); /////////////////////////////////////////////////////////////////// //// private variables //// private boolean _logMode; private PropertyTermManager _propertyTermManager; /** * The set of trained constraints. This set is populated from parsing the * constraint file when training mode is off. */ private final List<String> _trainedConstraints = new LinkedList<String>(); protected static final String _USER_DEFINED_LATTICE = "Attribute::"; protected static final String COLLECT_CONSTRAINTS = "COLLECT_CONSTRAINTS"; protected static final String INITIALIZE_SOLVER = "INITIALIZE_SOLVER"; }