/*
* The base class of a property lattice.
*
* 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.
*
* PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY
*
*/
package ptolemy.data.properties.lattice;
import java.util.HashMap;
import ptolemy.data.properties.Property;
import ptolemy.graph.CPO;
import ptolemy.graph.DirectedAcyclicGraph;
import ptolemy.graph.Node;
import ptolemy.kernel.util.IllegalActionException;
////PropertyLattice
/**
* The property lattice base class. There are more than one instances of a
* property lattice. The property lattice is constructed once and then typically
* does not change during execution.
*
* @author Thomas Mandl, Man-Kit Leung, Edward A. Lee
* @version $Id$
* @since Ptolemy II 7.1
* @Pt.ProposedRating Red (mankit)
* @Pt.AcceptedRating Red (mankit)
* @see ptolemy.graph.CPO
*/
public class PropertyLattice extends DirectedAcyclicGraph {
/**
* Construct a new property lattice.
*/
public PropertyLattice() {
}
///////////////////////////////////////////////////////////////////
//// public methods ////
/**
* Add the specified element to this lattice. The element is assumed to be a
* LatticeProperty. Otherwise, a runtime exception would occur.
* @param weight The element.
* @return The constructed graph node in the lattice.
*/
public Node addNodeWeight(Object weight) {
// The weight argument must be Object or else we get test failures
_propertyMap.put(weight.toString().toUpperCase(),
(LatticeProperty) weight);
return super.addNodeWeight(weight);
}
/**
* Add structured properties. The parameter flag is a bit-wise OR union of
* the structured properties desired to add. The class provides a set of
* symbolic constants for these structured property types. For example,
* invoke addStructuredProperties(RECORD) to add the RecordProperty. This
* method should be called after all base elements have been added. The user
* is responsible for ensuring a lattice structure before calling this
* method. The lattice structure should be preserved after calling this
* method, so there is no need to do another check.
* @param structuredPropertiesToAdd The bit-wise OR union of the structured
* properties desired to add.
* @throws IllegalActionException
*/
public void addStructuredProperties(int structuredPropertiesToAdd)
throws IllegalActionException {
if ((structuredPropertiesToAdd & RECORD) != 0) {
Property record = new RecordProperty(this, new String[0],
new LatticeProperty[0]).getRepresentative();
if (!isLattice()) {
throw new IllegalActionException(
"This ontology needs to be a lattice "
+ "before adding structured types.");
}
Object bottom = bottom();
Object top = top();
addNodeWeight(record);
addEdge(bottom, record);
addEdge(record, top);
}
if ((structuredPropertiesToAdd & ARRAY) != 0) {
// FIXME: add Array structure.
}
}
/**
* Compare two properties in the property lattice. The arguments must be
* instances of Property, otherwise an exception will be thrown. This method
* returns one of ptolemy.graph.CPO.LOWER, ptolemy.graph.CPO.SAME,
* ptolemy.graph.CPO.HIGHER, ptolemy.graph.CPO.INCOMPARABLE, indicating the
* first argument is lower than, equal to, higher than, or incomparable with
* the second argument in the property hierarchy, respectively.
* @param t1 an instance of Property.
* @param t2 an instance of Property.
* @return An integer.
* @exception IllegalArgumentException If one or both arguments are not
* instances of Property.
*/
public int compare(Object t1, Object t2) {
synchronized (PropertyLattice.class) {
if (!(t1 instanceof Property) || !(t2 instanceof Property)) {
throw new IllegalArgumentException("PropertyLattice.compare: "
+ "Arguments are not instances of Property: "
+ " property1 = " + t1 + ", property2 = " + t2);
}
Property t1Rep = _toRepresentative((Property) t1);
Property t2Rep = _toRepresentative((Property) t2);
if (t1Rep.equals(t2Rep) && t1Rep instanceof StructuredProperty) {
return ((StructuredProperty) t1)
._compare((StructuredProperty) t2);
}
return super.compare(t1Rep, t2Rep);
}
}
/**
* Throw an exception. This operation is not supported since we don't need
* it.
* @exception UnsupportedOperationException Always thrown.
*/
public Object[] downSet(Object e) {
throw new UnsupportedOperationException(
"PropertyLattice.downSet(): operation not supported for "
+ "the property lattice.");
}
/**
* Return the element associated with the specified name.
* @param elementName The specified name.
* @return The element.
* @throws IllegalActionException Thrown if this lattice does not contain
* the element with the specified name.
*/
public LatticeProperty getElement(String elementName)
throws IllegalActionException {
LatticeProperty property = _propertyMap.get(elementName.toUpperCase());
if (property == null) {
throw new IllegalActionException("No lattice element named \""
+ elementName + "\".");
}
return property;
}
/**
* Return the name of this lattice.
* @return The name of this lattice, which is the name of the package.
*/
public String getName() {
return toString();
}
/**
* Return the greatest property of a set of properties, or null if the
* greatest one does not exist.
* @param subset an array of properties.
* @return A Property or null.
*/
public Object greatestElement(Object[] subset) {
synchronized (PropertyLattice.class) {
// Compare each element with all of the other elements to search
// for the greatest one. This is a simple, brute force algorithm,
// but may be inefficient. A more efficient one is used in
// the graph package, but more complex.
for (Object element : subset) {
boolean isGreatest = true;
for (Object element2 : subset) {
int result = compare(element, element2);
if (result == CPO.LOWER || result == CPO.INCOMPARABLE) {
isGreatest = false;
break;
}
}
if (isGreatest == true) {
return element;
}
}
// FIXME: Shouldn't this return GENERAL?
return null;
}
}
/**
* Return the greatest lower bound of two properties.
* @param t1 an instance of Property.
* @param t2 an instance of Property.
* @return an instance of Property.
* @exception IllegalArgumentException If one or both of the specified
* arguments are not instances of Property.
*/
public Object greatestLowerBound(Object t1, Object t2) {
synchronized (PropertyLattice.class) {
if (t1 == null || t2 == null) {
return null;
}
if (!(t1 instanceof Property) || !(t2 instanceof Property)) {
throw new IllegalArgumentException(
"PropertyLattice.greatestLowerBound: "
+ "Arguments are not instances of Property.");
}
Property t1Rep = _toRepresentative((Property) t1);
Property t2Rep = _toRepresentative((Property) t2);
if (t1Rep.equals(t2Rep) && t1Rep instanceof StructuredProperty) {
return ((StructuredProperty) t1)
._greatestLowerBound((StructuredProperty) t2);
}
if (!super.containsNodeWeight(t1)) {
throw new IllegalArgumentException(
"PropertyLattice does not contain " + t1);
}
if (!super.containsNodeWeight(t2)) {
throw new IllegalArgumentException(
"PropertyLattice does not contain " + t2);
}
int relation = super.compare(t1Rep, t2Rep);
if (relation == SAME) {
return t1;
} else if (relation == LOWER) {
return t1;
} else if (relation == HIGHER) {
return t2;
} else { // INCOMPARABLE
// FIXME: this case shouldn't happen, right?
return super.greatestLowerBound(t1, t2);
}
}
}
/**
* Return the greatest lower bound of a subset.
* @param subset an array of properties.
* @return an instance of Property.
*/
public Object greatestLowerBound(Object[] subset) {
throw new UnsupportedOperationException(
"PropertyLattice.greatestUpperBound(Object[]) :"
+ " operation not supported for the property lattice.");
}
/**
* Return the greatest lower bound of the two given properties.
* @param property1 The first given property.
* @param property2 The second given property.
* @return The greatest lower bound of property1 and property2.
*/
public synchronized Property greatestLowerBound(Property property1,
Property property2) {
return (Property) super.greatestLowerBound(property1, property2);
}
/**
* Return true.
* @return true.
*/
public boolean isLattice() {
return true;
}
/**
* Return the least property of a set of properties, or null if the least
* one does not exist.
* @param subset an array of properties.
* @return A Property or null.
*/
public Object leastElement(Object[] subset) {
synchronized (PropertyLattice.class) {
// Compare each element with all of the other elements to search
// for the least one. This is a simple, brute force algorithm,
// but may be inefficient. A more efficient one is used in
// the graph package, but more complex.
for (Object element : subset) {
boolean isLeast = true;
for (Object element2 : subset) {
int result = compare(element, element2);
if (result == CPO.HIGHER || result == CPO.INCOMPARABLE) {
isLeast = false;
break;
}
}
if (isLeast == true) {
return element;
}
}
// FIXME: Shouldn't this return bottom?
return null;
}
}
/**
* Return the least upper bound of two properties.
* @param t1 an instance of Property.
* @param t2 an instance of Property.
* @return an instance of Property.
*/
public Object leastUpperBound(Object t1, Object t2) {
synchronized (PropertyLattice.class) {
if (t1 == null) {
return t2;
}
if (t2 == null) {
return t1;
}
if (!(t1 instanceof Property) || !(t2 instanceof Property)) {
throw new IllegalArgumentException(
"PropertyLattice.leastUpperBound: "
+ "Arguments are not instances of Property.");
}
Property t1Rep = _toRepresentative((Property) t1);
Property t2Rep = _toRepresentative((Property) t2);
if (t1Rep.equals(t2Rep) && t1Rep instanceof StructuredProperty) {
return ((StructuredProperty) t1)
._leastUpperBound((StructuredProperty) t2);
}
// Both are neither the same structured property, nor an array
// and non-array pair, so their property relation is defined
// by the basic lattice.
int relation = super.compare(t1Rep, t2Rep);
if (relation == SAME) {
return t1;
} else if (relation == LOWER) {
return t2;
} else if (relation == HIGHER) {
return t1;
} else { // INCOMPARABLE
// FIXME: this case shouldn't happen, right?
return super.leastUpperBound(t1, t2);
}
}
}
/**
* Return the least upper bound of a subset.
* @param subset an array of properties.
* @return an instance of Property.
*/
public Object leastUpperBound(Object[] subset) {
throw new UnsupportedOperationException(
"PropertyLattice.leastUpperBound(Object[]) :"
+ " operation not supported for the property lattice.");
}
/**
* Return the least upper bound of the two given properties.
* @param property1 The first given property.
* @param property2 The second given property.
* @return The least upper bound of property1 and property2.
*/
public synchronized Property leastUpperBound(Property property1,
Property property2) {
return (Property) leastUpperBound((Object) property1,
(Object) property2);
}
/**
* Throw an exception. This operation is not supported since the property
* lattice is infinite, this operation is not supported.
* @exception UnsupportedOperationException Always thrown.
*/
public Object[] upSet(Object e) {
throw new UnsupportedOperationException(
"PropertyLattice.upSet(): operation not supported for "
+ "the property lattice.");
}
/**
* Return the property lattice described by the given lattice description
* file. If the lattice was not created already, a new property lattice is
* instantiated.
* @param latticeName The given lattice name.
* @return The property lattice described by the given file.
*/
public static PropertyLattice getPropertyLattice(String latticeName) {
// Check whether the lattice is included in the model.
if (latticeName.startsWith(PropertyConstraintSolver._USER_DEFINED_LATTICE)) {
// In this case, we don't want to look
// in the predefined lattices.
latticeName = latticeName.replace(
PropertyConstraintSolver._USER_DEFINED_LATTICE, "");
return _lattices.get(latticeName);
}
if (!_lattices.containsKey(latticeName)) {
try {
Class latticeClass = Class
.forName("ptolemy.data.properties.lattice."
+ latticeName + ".Lattice");
// Create a new instance of PropertyLattice.
PropertyLattice newLattice = (PropertyLattice) latticeClass
.getConstructor(new Class[0])
.newInstance(new Object[0]);
_lattices.put(latticeName, newLattice);
} catch (Exception e) {
e.printStackTrace();
}
}
PropertyLattice lattice = _lattices.get(latticeName);
return lattice;
}
/**
* Globally reset all lattices in the model. After calling this method,
* future calls to {@link #getPropertyLattice(String)} would have no memory
* of previously created lattices, and thus instantiate new instances.
*/
public static void resetAll() {
_lattices.clear();
}
/**
* Store the specified lattice with the specified name.
* {@link #getPropertyLattice(String)} first searches from the set of stored
* lattices before instantiating a new instant.
*/
public static void storeLattice(PropertyLattice lattice, String name) {
_lattices.put(name, lattice);
}
/** Return the name of the package that contains this class.
* @return the name of the package that contains this class.
*/
public String toString() {
String name = getClass().getPackage().getName();
return name.substring(name.lastIndexOf('.') + 1);
}
///////////////////////////////////////////////////////////////////
//// public fields ////
/**
* Public symbolic constant value for the RecordProperty.
*/
public final int RECORD = 0x1;
/**
* Public symbolic constant value for the ArrayProperty.
*/
public final int ARRAY = 0x10;
///////////////////////////////////////////////////////////////////
//// private methods ////
// If the argument is a structured type, return its representative;
// otherwise, return the argument. In the latter case, the argument
// is either a base type or a user defined type that is not a
// structured type.
private Property _toRepresentative(Property p) {
if (p instanceof StructuredProperty) {
return ((StructuredProperty) p).getRepresentative();
} else {
return p;
}
}
///////////////////////////////////////////////////////////////////
//// private fields ////
private final HashMap<String, LatticeProperty> _propertyMap = new HashMap<String, LatticeProperty>();
/**
* A HashMap that contains all property lattices with unique lattice files
* as keys.
*/
private static HashMap<String, PropertyLattice> _lattices = new HashMap<String, PropertyLattice>();
}