/* A solver for lattice-based ontologies.
*
* Copyright (c) 2007-2014 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.lattice;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import ptolemy.data.ArrayToken;
import ptolemy.data.RecordToken;
import ptolemy.data.StringToken;
import ptolemy.data.Token;
import ptolemy.data.expr.ASTPtRootNode;
import ptolemy.data.expr.Parameter;
import ptolemy.data.expr.StringParameter;
import ptolemy.data.ontologies.Concept;
import ptolemy.data.ontologies.OntologyAdapter;
import ptolemy.data.ontologies.OntologyResolutionException;
import ptolemy.data.ontologies.OntologySolver;
import ptolemy.data.ontologies.OntologySolverBase;
import ptolemy.data.ontologies.OntologySolverModel;
import ptolemy.data.ontologies.gui.OntologySolverGUIFactory;
import ptolemy.data.type.ArrayType;
import ptolemy.data.type.BaseType;
import ptolemy.data.type.RecordType;
import ptolemy.data.type.Type;
import ptolemy.domains.modal.kernel.FSMActor;
import ptolemy.graph.CPO;
import ptolemy.graph.Inequality;
import ptolemy.graph.InequalityTerm;
import ptolemy.kernel.ComponentEntity;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.NamedObj;
import ptolemy.kernel.util.Settable;
import ptolemy.kernel.util.Workspace;
///////////////////////////////////////////////////////////////////
//// LatticeOntologySolver
/**
* An instance of this solver contains an ontology , which itself
* contains a {@linkplain ptolemy.data.ontologies.ConceptGraph ConceptGraph}
* and default constraints. The LatticeOntologySolver
* contains an {@linkplain ptolemy.data.ontologies.Ontology Ontology} whose
* ConceptGraph must be a lattice. It uses the
* Rehof-Mogensen algorithm to resolve which {@linkplain ptolemy.data.ontologies.FiniteConcept Concepts}
* are assigned to model components.
*
* This class is based on the PropertyConstraintSolver in the properties package
* by Man-Kit Leung.
*
* @author Man-Kit Leung, Edward A. Lee, Charles Shelton, Ben Lickly, Dai Bui, Beth Latronico
* @version $Id: LatticeOntologySolver.java 70402 2014-10-23 00:52:20Z cxh $
* @since Ptolemy II 10.0
* @Pt.ProposedRating Red (mankit)
* @Pt.AcceptedRating Red (mankit)
*/
public class LatticeOntologySolver extends OntologySolver {
/** Constructor for the OntologySolver.
* @param container The model that contains the OntologySolver
* @param name The name of the OntologySolver
* @exception IllegalActionException If there is any problem creating the
* OntologySolver object.
* @exception NameDuplicationException If there is already a component
* in the container with the same name
*/
public LatticeOntologySolver(NamedObj container, String name)
throws IllegalActionException, NameDuplicationException {
super(container, name);
// Provide a default model so that this is never empty.
_model = new OntologySolverModel(this, workspace());
// Provide a single parameter to set the others, plus a "custom" option
// However, for the other parameters, still call setExpression here
// in case the solverStrategy was set to custom (for example in
// a saved model) and in case no parameter values were specified.
// The "custom" option makes no changes to the other parameters.
solverStrategy = new StringParameter(this, "solverStrategy");
solverStrategy.setExpression("forward");
solvingFixedPoint = new StringParameter(this, "solvingFixedPoint");
solvingFixedPoint.setExpression("least");
_trainedConceptRecordArray = new Parameter(this,
"_trainedConceptRecordArray");
_trainedConceptRecordArray.setVisibility(Settable.NONE);
_trainedConceptRecordArray.setPersistent(true);
_setTrainedConceptsParameterType();
_addChoices();
_attachText("_iconDescription", "\n"
+ " " + ""
+ "Double click to\nApply Ontology ");
new OntologySolverGUIFactory(this, "_LatticeOntologySolverGUIFactory");
}
///////////////////////////////////////////////////////////////////
//// ports and parameters ////
/**
* Indicate whether to compute the least or greatest fixed point solution.
*
* "least" Solve for least fixed point
* "greatest" Solve for greatest fixed point
*
*/
public StringParameter solvingFixedPoint;
/**
* A single parameter for quickly selecting common solving strategies,
* plus a "custom" option to allow a user-defined strategy.
*/
public StringParameter solverStrategy;
/** The string name of the attribute that defines the arithmetic add
* concept function for this ontology solver.
*/
public static final String ADD_FUNCTION_NAME = "addFunction";
/** The string name of the attribute that defines the arithmetic subtract
* concept function for this ontology solver.
*/
public static final String SUBTRACT_FUNCTION_NAME = "subtractFunction";
/** The string name of the attribute that defines the arithmetic multiply
* concept function for this ontology solver.
*/
public static final String MULTIPLY_FUNCTION_NAME = "multiplyFunction";
/** The string name of the attribute that defines the arithmetic divide
* concept function for this ontology solver.
*/
public static final String DIVIDE_FUNCTION_NAME = "divideFunction";
/** The string name of the attribute that defines the arithmetic negation
* concept function for this ontology solver.
*/
public static final String NEGATE_FUNCTION_NAME = "negateFunction";
/** The string name of the attribute that defines the arithmetic negation
* concept function for this ontology solver.
*/
public static final String RECIPROCAL_FUNCTION_NAME = "reciprocalFunction";
/** The string name of the attribute that defines the logical not
* concept function for this ontology solver.
*/
public static final String NOT_FUNCTION_NAME = "notFunction";
/** The string name of the attribute that defines the logical and
* concept function for this ontology solver.
*/
public static final String AND_FUNCTION_NAME = "andFunction";
/** The string name of the attribute that defines the logical or
* concept function for this ontology solver.
*/
public static final String OR_FUNCTION_NAME = "orFunction";
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Clone the object into the specified workspace. The new object is
* not added to the directory of that workspace (you must do this
* yourself if you want it there).
* The result is an object with no container.
* @param workspace The workspace for the cloned object.
* @exception CloneNotSupportedException Not thrown in this base class
* @return The new object.
*/
@Override
public Object clone(Workspace workspace) throws CloneNotSupportedException {
LatticeOntologySolver newObject = (LatticeOntologySolver) super
.clone(workspace);
newObject._annotatedObjects = new HashSet();
newObject._constraintManager = new ConstraintManager(newObject);
newObject._trainedConceptRecordArray = (Parameter) newObject
.getAttribute("_trainedConceptRecordArray");
return newObject;
}
/**
* Get the list of affected InequalityTerms from the OntologySolver's
* ConceptTermManager.
* FIXME: 01/28/10 Charles Shelton - Not really sure what this method is used for. The call to
* _conceptTermManager.getAffectedTerms() appears to always return
* an empty ArrayList.
*
* @param updateTerm This parameter doesn't appear to be used
* @return The list of inequality terms that are affected by the OntologySolver
* @exception IllegalActionException If an exception is thrown
*/
public List getAffectedTerms(
ptolemy.graph.InequalityTerm updateTerm)
throws IllegalActionException {
return _conceptTermManager.getAffectedTerms(updateTerm);
}
/**
* Get the ConstraintManager that collects and maintains all the inequality
* constraints for the OntologySolver.
*
* @return the constraintManager
*/
public ConstraintManager getConstraintManager() {
return _constraintManager;
}
/** Initialize the solver and get the initial statistics for the
* Lattice OntologySolver. This will return information about
* the number of constraints and concept terms generated before
* the solver executes its algorithm.
*
* @return A hash table containing string representations of the
* solver statistics and constraints information, separated by
* tabs.
* @exception IllegalActionException If an exception occurs when
* collecting the constraints.
*/
public Hashtable getInitialSolverInformation()
throws IllegalActionException {
initialize();
String initialSolverConstraints = _getConstraintsAsString(_initialConstraintList);
Hashtable initialSolverInfo = new Hashtable();
initialSolverInfo.put("initialSolverConstraints",
initialSolverConstraints);
return initialSolverInfo;
}
/** Get the statistics for the Lattice OntologySolver after the
* model has been resolved. This will return information about
* the number of constraints and concept terms generated after
* the solver executes its algorithm.
*
* @return A hash table containing string representations of the
* solver statistics and constraints information, separated by
* tabs.
* @exception IllegalActionException If an exception occurs when
* collecting the constraints.
*/
public Hashtable getResolvedSolverInformation()
throws IllegalActionException {
if (_resolvedConstraintList == null) {
invokeSolver(false);
}
String resolvedSolverConstraints = _getConstraintsAsString(_resolvedConstraintList);
Hashtable resolvedSolverInfo = new Hashtable();
resolvedSolverInfo.put("resolvedSolverConstraints",
resolvedSolverConstraints);
// Reset the resolved constraint list for the next time it is tested.
_resolvedConstraintList = null;
return resolvedSolverInfo;
}
/**
* Returns the adapter that contains concept information for the given AST
* node.
* @param node The given ASTPtRootNode.
* @return The associated concept constraint adapter.
* @exception IllegalActionException If an exception is thrown in the private
* _getAdapter method
*/
public LatticeOntologyASTNodeAdapter getAdapter(ASTPtRootNode node)
throws IllegalActionException {
return (LatticeOntologyASTNodeAdapter) _getAdapter(node);
}
/**
* Returns the adapter that contains concept information for the given
* component.
* @param component The given component
* @return The associated concept constraint adapter.
* @exception IllegalActionException If an exception is thrown in the private
* _getAdapter method
*/
public OntologyAdapter getAdapter(NamedObj component)
throws IllegalActionException {
return _getAdapter(component);
}
/**
* Return the concept constraint adapter associated with the given object.
* @param object The given object.
* @return The associated concept constraint adapter.
* @exception IllegalActionException If an exception is thrown in the private
* _getAdapter method
*/
@Override
public OntologyAdapter getAdapter(Object object)
throws IllegalActionException {
return _getAdapter(object);
}
/**
* Return the concept value associated with the specified object.
* @param object The specified object.
* @return The concept of the specified object.
*/
/*
public Concept getConcept(Object object) {
try {
return (Concept) getConceptTerm(object).getValue();
} catch (IllegalActionException ex) {
return null;
}
}
*/
/**
* Return the concept term from the given object.
* @param object The given object.
* @return The concept term of the given object.
*/
public ptolemy.graph.InequalityTerm getConceptTerm(Object object) {
return getConceptTermManager().getConceptTerm(object);
}
/**
* Return the concept term manager that collects and maintains a hash map
* that maps all model objects to their the inequality terms for the OntologySolver.
*
* @return The concept term manager for the OntologySolver
*/
public ConceptTermFactory getConceptTermManager() {
if (_conceptTermManager == null) {
_conceptTermManager = _getConceptTermManager();
}
return _conceptTermManager;
}
/** Returns true if one or more terms resolved to unacceptable concepts,
* false otherwise (if the solver has not run, or if all terms have
* acceptable resolved concepts.
*
* @return True if one or more terms resolved to unacceptable concepts,
* false otherwise.
*/
public boolean hasUnacceptableTerms() {
if (_resolvedUnacceptableList != null
&& !_resolvedUnacceptableList.isEmpty()) {
return true;
}
return false;
}
/**
* Initialize the solver: Reset the solver (superclass) and then collect
* all of the initial constraints from the model.
* @exception IllegalActionException If an exception occurs when
* collecting the constraints.
*/
@Override
public void initialize() throws IllegalActionException {
super.initialize();
NamedObj toplevel = _toplevel();
LatticeOntologyAdapter toplevelAdapter = (LatticeOntologyAdapter) getAdapter(toplevel);
// FIXME: The code from here to constraintList() doesn't really
// belong here. The constraintList() method of the Adapter should
// ensure that the constraint list it returns is valid.
toplevelAdapter.reinitialize();
// FIXME: have to generate the connection every time
// because the model structure can changed.
// (i.e. adding or removing connections.)
toplevelAdapter._setConnectionConstraintType(_getConstraintType());
toplevelAdapter._addDefaultConstraints(_getConstraintType());
_initialConstraintList = toplevelAdapter.constraintList();
}
/**
* Return true if the given model object has been annotated with a
* manual annotation constraint.
*
* @param object The model object to be checked to see if it is annotated
* @return true if the model object is annotated, false otherwise
*/
public boolean isAnnotatedTerm(Object object) {
return _annotatedObjects.contains(object);
}
/** Return true if the solver is finding a least fixed point, and
* false if the solver is finding a greatest fixed point.
*
* @return True, if solver is solving a least fixed point,
* false, if it is solving a greatest fixed point.
* @exception IllegalActionException If the solvingFixedPoint parameter
* contains an invalid value.
*/
public boolean isLeastFixedPoint() throws IllegalActionException {
if (solvingFixedPoint.stringValue().equals("least")) {
return true;
} else if (solvingFixedPoint.stringValue().equals("greatest")) {
return false;
} else {
throw new IllegalActionException("Invalid fixed point type.\n"
+ "Must be one of 'least' or 'greatest'.");
}
}
/**
* Reset the solver. This removes the internal states of the
* solver (e.g. previously recorded properties, statistics,
* etc.). Also resets the {@linkplain ConceptTermManager} to null
* and clears the trained constraints.
*/
@Override
public void reset() {
super.reset();
_clearLists();
_conceptTermManager = null;
}
/** Resolve the concept values for the toplevel entity that contains this
* solver, given the model analyzer that invokes this.
* @exception IllegalActionException If there is an exception thrown during the OntologySolver
* resolution.
*/
@Override
public void resolveConcepts() throws IllegalActionException {
NamedObj toplevel = _toplevel();
_resolveConcepts(toplevel, _initialConstraintList);
}
/** Run concept inference and check the values match those trained.
*
* This simply looks through the conceptable objects and
* checks that their resolved concepts match the values
* contained in the __trainedConceptRecordArray attribute.
*
* @exception IllegalActionException If inference fails or the test
* resolves to the wrong values.
*/
@Override
public void test() throws IllegalActionException {
try {
workspace().getWriteAccess();
invokeSolver();
} finally {
workspace().doneWriting();
}
ArrayToken trainedConceptsArrayToken = (ArrayToken) _trainedConceptRecordArray
.getToken();
if (trainedConceptsArrayToken == null) {
throw new IllegalActionException("The " + getName()
+ " ontology solver has not been trained for ontology "
+ "concept resolution, so its analysis cannot be tested.");
} else {
Token[] trainedConceptRecordsArray = trainedConceptsArrayToken
.arrayValue();
Set allNamedObjs = getAllConceptableNamedObjs();
for (Token trainedConceptToken : trainedConceptRecordsArray) {
RecordToken conceptRecord = (RecordToken) trainedConceptToken;
String conceptableFullName = ((StringToken) conceptRecord
.get(_namedObjLabel)).stringValue();
NamedObj conceptable = _getConceptableFromFullName(
conceptableFullName, allNamedObjs);
if (conceptable == null) {
throw new IllegalActionException(this, "The full name "
+ conceptableFullName
+ " does not refer to a valid model object that "
+ "can be resolved to an ontology concept.");
}
String trainedConceptString = ((StringToken) conceptRecord
.get(_conceptLabel)).stringValue();
Concept inferredConcept = getConcept(conceptable);
if (inferredConcept == null) {
if (trainedConceptString != null
&& !trainedConceptString.equals("")) {
throw new IllegalActionException(conceptable,
"Testing failure at " + conceptable.toString()
+ '\n' + "Expected '"
+ trainedConceptString
+ "' but did not infer anything.");
}
} else if (!inferredConcept.toString().equals(
trainedConceptString)) {
throw new IllegalActionException(conceptable,
"Testing failure at " + conceptable.toString()
+ '\n' + "Expected '"
+ trainedConceptString + "' but got '"
+ inferredConcept.toString() + "' instead.");
}
}
if (!allNamedObjs.isEmpty()) {
throw new IllegalActionException(this, "Some of the "
+ "conceptable model elements do not have "
+ "trained concept values. They are: " + allNamedObjs);
}
}
}
/** Run concept inference and save the inferred concept values.
*
* For all conceptable model elements, an array of records that maps the
* full name of the Ptolemy element to the name of the concept to which it
* was resolved is generated and stored as a parameter of the ontology
* solver.
*
* @exception IllegalActionException If inference fails..
*/
@Override
public void train() throws IllegalActionException {
try {
workspace().getWriteAccess();
invokeSolver();
Set allNamedObjs = getAllConceptableNamedObjs();
RecordToken[] trainedConcepts = new RecordToken[allNamedObjs.size()];
int index = 0;
for (NamedObj conceptable : allNamedObjs) {
Concept inferredConcept = getConcept(conceptable);
Token[] recordArray = new Token[2];
recordArray[0] = new StringToken(conceptable.getFullName());
if (inferredConcept == null) {
recordArray[1] = new StringToken(null);
} else {
recordArray[1] = new StringToken(inferredConcept.toString());
}
RecordToken conceptRecord = new RecordToken(
_trainedConceptRecordLabels, recordArray);
trainedConcepts[index++] = conceptRecord;
}
_trainedConceptRecordArray
.setToken(new ArrayToken(trainedConcepts));
} finally {
workspace().doneWriting();
}
}
///////////////////////////////////////////////////////////////////
//// public inner classes ////
/**
* An enumeration type to represent the types of constraints for
* default constraint settings for actor inputs and outputs, connections
* and finite state machine transitions.
*/
public static enum ConstraintType {
/** Represents that the two sides must be equal. */
EQUALS,
/** Represents that there is no constraint between the two sides. */
NONE,
/** Represents that the sink must be ≥ the source. */
SINK_GE_SOURCE,
/** Represents that the source must be ≥ the sink. */
SOURCE_GE_SINK
}
///////////////////////////////////////////////////////////////////
//// protected methods ////
/** Return a string representing the list of terms that resolved to
* unacceptable concepts. Returns an empty string if the solver has not
* been run, or if all terms were acceptable.
*
* See {@linkplain ptolemy.data.ontologies.lattice.ConceptTermManager ConceptTermManager}
* for a definition of acceptable.
*
* @return A string representing the list of terms that resolved to
* unacceptable concepts. Can be the empty string.
* @exception IllegalActionException If the string cannot be formed from the
* list of inequality terms
*/
protected String getUnacceptableTermsAsString()
throws IllegalActionException {
StringBuffer output = new StringBuffer();
if (_resolvedUnacceptableList != null
&& !_resolvedUnacceptableList.isEmpty()) {
for (InequalityTerm term : _resolvedUnacceptableList) {
output.append(term.toString() + _eol);
}
}
return output.toString();
}
/** Return the list of inequality terms that resolved to unacceptable
* concepts. Returns null if the solver has not been run first, or if all
* terms were acceptable.
* See {@linkplain ptolemy.data.ontologies.lattice.ConceptTermManager ConceptTermManager}
* for a definition of acceptable.
*
* @return The list of inequality terms that resolved to unacceptable
* concepts. Can be null.
*/
protected List getUnacceptableTerms() {
return _resolvedUnacceptableList;
}
/**
* Set the resolved constraint list and the list of unacceptable
* inequality terms to null. Implemented as a protected method so that
* subclasses may call it.
*/
protected void _clearLists() {
_initialConstraintList = null;
_resolvedConstraintList = null;
_resolvedUnacceptableList = new ArrayList();
}
// Illegal action exception thrown from getOntology()
// Collect all information related to whether or not terms are unacceptable
// For each term, check if its concept is acceptable for that term
// The notion of acceptable can currently be defined at three levels:
// Per-lattice: The concept is not acceptable for any term that uses that lattice
// Per-container: The concept is not acceptable for any term in the specified
// container. The container can be a whole model.
// Per-term: The concept is not acceptable for the specified term
// (acceptance criteria translate to one or more of these)
// Return a list/table of terms, true/false?
// Allow checking of an individual term?
// Per-lattice
// Per-container. Not implemented currently.
// Per-term
// collectUnacceptableConcepts(Ontology?)
// A concept is deemed acceptable unless explicitly specified otherwise
// DO this way, or should ontology provide a list? Perhaps ontology should provide a list?
// collectUnacceptableConcepts(Container?)
// collectUnacceptableConcepts(Term?)
// call lattice - getUnacceptableConcepts() - for per-lattice - save list
// make it a sorted set for easy access
// nothing implemented per-container yet
// collect all acceptance criteria constraints and determine list for these
/**
* Return the LatticeOntologyAdapter for the specified
* component. This instantiates a new OntologyAdapter if it does
* not already exist for the specified component. This returns
* specific LatticeOntologyAdapters for the LatticeOntologySolver.
*
* @param component The specified component.
* @return The LatticeOntologyAdapter for the specified component.
* @exception IllegalActionException Thrown if the LatticeOntologyAdapter
* cannot be instantiated.
*/
protected OntologyAdapter _getAdapter(Object component)
throws IllegalActionException {
OntologyAdapter adapter = null;
// First see if the adapter has already been cached
// Must check the adapter store first because additional state
// is stored in the adapter that will be lost if we generate a new adapter from
// a model defined adapter definition after it was already instantiated before.
// This fixes the bug where backwards and bidirectional ontology solvers
// were not working because the adapter's interconnectConstraintType member variable
// would be reset to null because a new adapter object was created from the model
// definition.
if (_adapterStore.containsKey(component)) {
return _adapterStore.get(component);
} else {
// Next look for the adapter in the LatticeOntologySolver model.
List modelDefinedAdapters = ((OntologySolverModel) _model)
.attributeList(ActorConstraintsDefinitionAttribute.class);
for (ActorConstraintsDefinitionAttribute adapterDefinitionAttribute : modelDefinedAdapters) {
if (((StringToken) adapterDefinitionAttribute.actorClassName
.getToken()).stringValue().equals(
component.getClass().getName())) {
adapter = adapterDefinitionAttribute.createAdapter(
(ComponentEntity) component, this);
break;
}
}
}
if (adapter == null) {
try {
adapter = OntologySolverBase._getAdapter(component, this);
} catch (IllegalActionException ex) {
}
}
if (adapter == null) {
if (component instanceof FSMActor) {
adapter = new LatticeOntologyModalFSMAdapter(this,
(FSMActor) component);
} else if (component instanceof CompositeEntity) {
adapter = new LatticeOntologyCompositeAdapter(this,
(CompositeEntity) component);
} else if (component instanceof ASTPtRootNode) {
adapter = new LatticeOntologyASTNodeAdapter(this,
(ASTPtRootNode) component);
} else {
adapter = new LatticeOntologyAdapter(this, component);
}
}
_adapterStore.put(component, adapter);
return adapter;
}
/**
* Return a new concept term manager. Subclass can implements a its own
* manager and override this method to instantiate a instance of the new
* class.
* @return A concept term manager.
*/
protected ConceptTermManager _getConceptTermManager() {
// FIXME: doesn't work for other use-cases!
// return new StaticDynamicTermManager(this);
return new ConceptTermManager(this);
}
/** Resolve the concepts for the given top-level container,
* subject to the given constraint list.
* @param toplevel The top-level container
* @param constraintList The constraint list that we are solving
* @exception OntologyResolutionException If constraints are unsatisfiable
*/
protected void _resolveConcepts(NamedObj toplevel,
List constraintList) throws OntologyResolutionException {
List conflicts = new ArrayList();
try {
// 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 = null;
// Added by Charles Shelton 12/17/09
// Check to see if the ontology is a lattice
// and throw an exception if it isn't.
if (getOntology().isLattice()) {
lattice = getOntology().getConceptGraph();
} else {
throw new IllegalActionException(
this,
"This Ontology is not a lattice, "
+ "and therefore we cannot resolve the model using the least fixed point algorithm.");
}
// 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());
_constraintManager.setConstraints(constraintList);
// Find the greatest solution (most general type)
if (solvingFixedPoint.stringValue().equals("greatest")) {
solver.solveGreatest();
} else {
solver.solveLeast();
}
_resolvedConstraintList = constraintList;
// 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
// concept conflicts.
for (Inequality inequality : constraintList) {
if (!inequality.isSatisfied(lattice)) {
conflicts.add(inequality);
} else {
// Check if there exist an unacceptable term value.
InequalityTerm[] lesserVariables = inequality
.getLesserTerm().getVariables();
InequalityTerm[] greaterVariables = inequality
.getGreaterTerm().getVariables();
// Collect all unacceptable terms from the inequalities
for (InequalityTerm variable : lesserVariables) {
if (!variable.isValueAcceptable()) {
_resolvedUnacceptableList.add(variable);
}
}
// Continue checking for unacceptable terms.
for (InequalityTerm variable : greaterVariables) {
if (!variable.isValueAcceptable()) {
_resolvedUnacceptableList.add(variable);
}
}
}
}
}
// Check for solution correctness.
if (conflicts.size() > 0) {
throw new OntologyResolutionException(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 OntologyResolutionException(this, toplevel, ex,
"Concept resolution failed because of an error "
+ "during concept inference");
}
}
/** Return the constraint type based on the solver strategy and the
* type of the fixed point.
* Least fixed points with forward inference give constraints
* that the sinks be greater that the sources, bidirectional
* inference requires sources and sinks to be equal, etc.
*
* @return The enumeration from ConstraintType corresponding to the
* given solver strategy.
* @exception IllegalActionException If solver strategy or fixed point
* type cannot be understood.
*/
protected ConstraintType _getConstraintType() throws IllegalActionException {
String strategy = solverStrategy.stringValue();
String fixedPoint = solvingFixedPoint.stringValue();
if (strategy.equals("forward") && fixedPoint.equals("least")
|| strategy.equals("backward") && fixedPoint.equals("greatest")) {
return ConstraintType.SINK_GE_SOURCE;
} else if (strategy.equals("backward") && fixedPoint.equals("least")
|| strategy.equals("forward") && fixedPoint.equals("greatest")) {
return ConstraintType.SOURCE_GE_SINK;
} else if (strategy.equals("bidirectional")) {
return ConstraintType.EQUALS;
} else if (strategy.equals("none")) {
return ConstraintType.NONE;
} else {
throw new IllegalActionException(
"Cannot understand solver strategy.\n" + "Strategy: \""
+ strategy + "\"\n" + "Fixed Point: \""
+ fixedPoint + '"');
}
}
///////////////////////////////////////////////////////////////////
//// protected variables ////
/** The list of constraints collected from the model, before resolution. */
protected List _initialConstraintList;
/** The list of constraints after the ontology resolution algorithm has executed. */
protected List _resolvedConstraintList;
/** The list of InequalityTerms that have resolved to an unacceptable concept value.
* See {@linkplain ptolemy.data.ontologies.lattice.ConceptTermManager ConceptTermManager}
* for a definition of unacceptable. */
protected List _resolvedUnacceptableList;
///////////////////////////////////////////////////////////////////
//// private methods ////
/**
* Add choices to the parameters.
* @exception IllegalActionException If there is a problem accessing files
* or parameters.
*/
private void _addChoices() throws IllegalActionException {
solverStrategy.addChoice("forward");
solverStrategy.addChoice("backward");
solverStrategy.addChoice("bidirectional");
solverStrategy.addChoice("none");
solvingFixedPoint.addChoice("least");
solvingFixedPoint.addChoice("greatest");
}
/** Return the conceptable model element NamedObj that has the given
* full name string. Also remove that NamedObj from the given set of
* all conceptable NamedObj elements.
* @param fullName The full name of the model element.
* @param allConceptableNamedObjs The set of all conceptable NamedObj
* elements in the model.
* @return The NamedObj element in the set with the given full name, or
* null if it does not exist.
*/
private NamedObj _getConceptableFromFullName(String fullName,
Set allConceptableNamedObjs) {
for (NamedObj modelElement : allConceptableNamedObjs) {
if (modelElement.getFullName().equals(fullName)) {
allConceptableNamedObjs.remove(modelElement);
return modelElement;
}
}
return null;
}
/** Return a string representing the list of inequality constraints specified
* that can be written to a log file.
*
* @param constraintList The list of inequality constraints to be parsed into a string.
* @return A string representing the list of inequality constraints that can be written to a log file.
* @exception IllegalActionException If the string cannot be formed from the list of inequality constraints.
*/
private String _getConstraintsAsString(List constraintList)
throws IllegalActionException {
StringBuffer output = new StringBuffer();
for (Inequality inequality : constraintList) {
output.append(inequality.toString() + _eol);
}
return output.toString();
}
/** Set the type constraint for the _trainedConceptRecordArray parameter.
* @exception IllegalActionException Thrown if there is a problem setting
* the type constraint.
*/
private void _setTrainedConceptsParameterType()
throws IllegalActionException {
Type[] typeArray = new Type[2];
typeArray[0] = BaseType.STRING;
typeArray[1] = BaseType.STRING;
RecordType conceptRecordType = new RecordType(
_trainedConceptRecordLabels, typeArray);
ArrayType conceptRecordArrayType = new ArrayType(conceptRecordType);
_trainedConceptRecordArray.setTypeEquals(conceptRecordArrayType);
}
///////////////////////////////////////////////////////////////////
//// private variables ////
/** The set of Objects that have been manually annotated. */
private/*final*/HashSet _annotatedObjects = new HashSet();
/** The constraint manager that keeps track of all the constraints in the model for the LatticeOntologySolver. */
private/*final*/ConstraintManager _constraintManager = new ConstraintManager(
this);
/** The concept term manager that keeps track of all the concept terms in the model for the LatticeOntologySolver. */
private ConceptTermManager _conceptTermManager;
/** The parameter that contains the array of trained concept values for
* the model that contains this solver.
*/
private Parameter _trainedConceptRecordArray;
/** Label for the NamedObj field of the trained concept record tokens. */
private static final String _namedObjLabel = "NamedObj";
/** Label for the Concept field of the trained concept record tokens. */
private static final String _conceptLabel = "Concept";
/** The array of labels for the trained concept records. */
private static final String[] _trainedConceptRecordLabels = new String[] {
_namedObjLabel, _conceptLabel };
}