/* A concept that represents the monotoncity of an expression.
*
* Copyright (c) 2010-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.adapters.monotonicityAnalysis;
import java.util.Set;
import ptolemy.actor.gui.ColorAttribute;
import ptolemy.data.ontologies.Concept;
import ptolemy.data.ontologies.ConceptGraph;
import ptolemy.data.ontologies.FiniteConcept;
import ptolemy.data.ontologies.FlatTokenInfiniteConcept;
import ptolemy.data.ontologies.MapTypeInfiniteConcept;
import ptolemy.data.ontologies.Ontology;
import ptolemy.graph.CPO;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.InternalErrorException;
import ptolemy.kernel.util.NameDuplicationException;
/** A concept that represents the monotoncity of an expression.
*
* Note that for an arbitrary expression, it will not have a
* monotonicity concept of simply Monotonic, Constant, etc.
* Rather, the expression will have a monotonicity that depends
* on it's free variables. For example, an expression of the form
*
* (x <= Concept1) ? Bottom :
* (y <= Concept2) ? Top :
* Concept1
*
* may have a monotonicity that is monotonic with respect to the
* variable x, but antimonotonic with respect to y (and constant
* with respect to all other variables).
*
* This class represents exactly such concepts, representing them as
* {x = Monotonic, y = Animonotonic}, in a manner and syntax
* similar to records of the Ptolemy II type system. In records,
* however, accessing an undefined tag is an error, whereas in
* expressions, they are simply constant with respect to any
* variables that are not free.
*
* @author Ben Lickly
* @version $Id: MonotonicityConcept.java 70398 2014-10-22 23:44:32Z cxh $
* @since Ptolemy II 10.0
* @Pt.ProposedRating Red (blickly)
* @Pt.AcceptedRating Red (blickly)
*
*/
public class MonotonicityConcept extends MapTypeInfiniteConcept {
///////////////////////////////////////////////////////////////////
//// public constructors/factories ////
/** Create a new monotonicity concept, belonging to the given
* ontology, with an automatically generated name.
*
* @param ontology The finite ontology to which this belongs.
* This should be the 4 element monotonicity lattice if we
* are really going to be doing inference on monotonicity
* of expressions.
* @return The newly created MonotonicityConcept.
*/
public static MonotonicityConcept createMonotonicityConcept(
Ontology ontology) {
try {
return new MonotonicityConcept(ontology);
} catch (NameDuplicationException e) {
throw new InternalErrorException(
"Name conflict with automatically generated infinite"
+ " concept name. This should never happen.\n"
+ "Original exception:" + e.toString());
} catch (IllegalActionException e) {
throw new InternalErrorException(
"There was an error creating a new MonotonicityConcept"
+ "in the " + ontology + "ontology.\n"
+ "Original exception:" + e.toString());
}
}
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Compare this concept with the given concept.
* Returns an int value that corresponds to the ordering between
* the elements as given in the CPO interface.
*
* @param concept The concept with which we are comparing.
* @return CPO.HIGHER if this concept is above the given concept,
* CPO.LOWER if this concept is below the given concept,
* CPO.SAME if both concepts are the same,
* and CPO.INCOMPARABLE if concepts are incomparable.
* @exception IllegalActionException If the specified concept
* does not have the same ontology as this one.
* @see ptolemy.data.ontologies.Concept#isAboveOrEqualTo(ptolemy.data.ontologies.Concept)
*/
@Override
public int compare(Concept concept) throws IllegalActionException {
if (!concept.getOntology().equals(getOntology())) {
throw new IllegalActionException(this,
"Attempt to compare elements from two distinct ontologies");
}
// Original bottom and top remain bottom and top.
if (concept.equals(getOntology().getConceptGraph().bottom())) {
return CPO.HIGHER;
} else if (concept.equals(getOntology().getConceptGraph().top())) {
return CPO.LOWER;
} else if (concept instanceof MonotonicityConcept) {
MonotonicityConcept righthandSide = (MonotonicityConcept) concept;
CPO graph = getOntology().getConceptGraph();
Set keys = this._combinedKeys(righthandSide);
boolean seenHigher = false;
boolean seenLower = false;
boolean seenIncomparable = false;
for (String key : keys) {
int result = graph.compare(getMonotonicity(key),
righthandSide.getMonotonicity(key));
switch (result) {
case CPO.HIGHER:
seenHigher = true;
break;
case CPO.LOWER:
seenLower = true;
break;
case CPO.INCOMPARABLE:
seenIncomparable = true;
break;
case CPO.SAME:
break;
default:
throw new IllegalActionException(
this,
"ConceptGraph compare "
+ "did not return one of the defined CPO values. "
+ "Return value was " + result
+ ". This should " + "never happen.");
}
}
if (!seenHigher && !seenLower && !seenIncomparable) {
return CPO.SAME;
} else if (seenHigher && !seenLower && !seenIncomparable) {
return CPO.HIGHER;
} else if (seenLower && !seenHigher && !seenIncomparable) {
return CPO.LOWER;
} else {
return CPO.INCOMPARABLE;
}
} else {
return CPO.INCOMPARABLE;
}
}
/** Return the correct color for this monotonicity concept by looking
* at the color of the finite monotonicity representative.
*
* @return A ColorAttribute corresponding to the highlight color of
* this monotonicity concept.
* @exception IllegalActionException Thrown if there is an error getting
* the color for the finite monotonicity concept.
*/
@Override
public ColorAttribute getColor() throws IllegalActionException {
return _toFiniteMonotonicity().getColor();
}
/** Get the monotonicity of this concept with respect to a specific
* variable. While the overall monotonicity of an expression
* cannot be represented so simply, the monotonicity with
* respect to a single variable can be represented as one
* of:
*
* - Constant
* - Monotonic
* - Antimonotonic
* - General
* - NonMonotonic_{Counterexamples}
* - NonAntimonotonic_{Counterexamples}
*
* This method returns one these concepts.
* @param variableName The variable whose monotonicity we are querying.
* @return The monotonicity of this concept with respect to the given
* variable; one of Constant, Monotonic, Antimonotonic, or General.
*/
public Concept getMonotonicity(String variableName) {
return getConcept(variableName);
}
/** Compute the greatest lower bound (GLB) of this and another concept.
*
* @param concept The other concept.
* @return The concept that is the GLB of this and the given concept.
*/
// FIXME: GLB method needs to be implemented.
@Override
public Concept greatestLowerBound(Concept concept) {
throw new IllegalArgumentException("greatestLowerBound method not "
+ "implemented.");
}
/** Compute the least upper bound (LUB) of this and another concept.
*
* @param concept The other concept.
* @return The concept that is the LUB of this and the given concept.
*/
@Override
public Concept leastUpperBound(Concept concept) {
Concept top = getOntology().getConceptGraph().top();
if (!(concept instanceof MonotonicityConcept)) {
Concept bottom = getOntology().getConceptGraph().bottom();
if (concept.equals(bottom)) {
return this;
} else if (this.equals(bottom)) {
return concept;
} else {
return top;
}
} else {
// We have two MonotonicityConcepts
return _leastUpperBound((MonotonicityConcept) concept);
}
}
/** Set the monotonicity of this concept with respect to a specific
* variable.
*
* @param variable The variable whose monotonicity we are querying.
* @param monotonicity The monotonicity of this concept with respect
* to the given variable.
* @see MonotonicityConcept#getMonotonicity(String)
*/
public void putMonotonicity(String variable, Concept monotonicity) {
putConcept(variable, monotonicity);
}
///////////////////////////////////////////////////////////////////
//// protected constructors ////
/** Create a new Monotonicity concept, belonging to the given
* ontology.
*
* @param ontology The finite ontology to which this belongs.
* This should be the 4 element monotonicity lattice if we
* are really going to be doing inference on monotonicity
* of expressions.
* @exception NameDuplicationException Should never be thrown.
* @exception IllegalActionException If the base class throws it.
*/
protected MonotonicityConcept(Ontology ontology)
throws IllegalActionException, NameDuplicationException {
super(ontology, ontology.getConceptGraph().bottom());
}
///////////////////////////////////////////////////////////////////
//// private methods ////
/** Compute the least upper bound (LUB) of this and another monotonicity concept.
*
* @param concept The other monotonicity concept
* @return The concept that is the LUB of this and the given concept.
*/
private Concept _leastUpperBound(MonotonicityConcept concept) {
MonotonicityConcept result = createMonotonicityConcept(getOntology());
Set allKeys = this._combinedKeys(concept);
for (String variableName : allKeys) {
CPO graph = this.getOntology().getConceptGraph();
Concept monotonicity = (Concept) graph.leastUpperBound(
this.getMonotonicity(variableName),
concept.getMonotonicity(variableName));
result.putMonotonicity(variableName, monotonicity);
}
return result;
}
/** Return the finite monotonicity concept that best represents the
* overall monotonicity of this infinite concept. Currently, this
* simply takes the least upper bound of the monotonicity of all the
* free variables referenced in this monotonicity concept, with the
* empty monotonicity concept evaluating to constant.
*
* So, for example the finite monotonicity of
* {x = Monotonic, y = Monotonic}
* is Monotonic, of
* {x = Monotonic, y = Antimonotonic}
* is General, of
* {}
* is Constant, etc.
*
* @return The finite monotonicity concept that represents the overall
* behavior of this infinite monotonicity concept.
*/
private FiniteConcept _toFiniteMonotonicity() {
ConceptGraph monotonicityLattice = getOntology().getConceptGraph();
FiniteConcept result = (FiniteConcept) monotonicityLattice.bottom();
for (String var : keySet()) {
Concept c = getMonotonicity(var);
Concept lub = monotonicityLattice.leastUpperBound(result, c);
if (lub instanceof FlatTokenInfiniteConcept) {
result = ((FlatTokenInfiniteConcept) lub).getRepresentative();
} else {
result = (FiniteConcept) lub;
}
}
return result;
}
}