001/* 002Below is the copyright agreement for the Ptolemy II system. 003 004Copyright (c) 1995-2014 The Regents of the University of California. 005All rights reserved. 006 007Permission is hereby granted, without written agreement and without 008license or royalty fees, to use, copy, modify, and distribute this 009software and its documentation for any purpose, provided that the above 010copyright notice and the following two paragraphs appear in all copies 011of this software. 012 013IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 014FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 015ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 016THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 017SUCH DAMAGE. 018 019THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 020INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 021MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 022PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 023CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 024ENHANCEMENTS, OR MODIFICATIONS. 025 026Ptolemy II includes the work of others, to see those copyrights, follow 027the copyright link on the splash page or see copyright.htm. 028 */ 029package ptolemy.actor.util; 030 031import java.util.ArrayList; 032import java.util.HashSet; 033import java.util.LinkedList; 034import java.util.List; 035import java.util.Set; 036 037import ptolemy.actor.IOPort; 038import ptolemy.actor.TypedIOPort; 039import ptolemy.data.type.BaseType; 040import ptolemy.data.type.MonotonicFunction; 041import ptolemy.data.type.Type; 042import ptolemy.data.type.TypeLattice; 043import ptolemy.graph.InequalityTerm; 044import ptolemy.kernel.util.IllegalActionException; 045 046/////////////////////////////////////////////////////////////////// 047//// GLBFunction 048 049/** This class implements a monotonic function that returns the greatest 050 * lower bound (GLB) of its arguments. These arguments are the port type 051 * variables of the destination ports of the TypedIOPort passed to the 052 * constructor. This function is used to define a type constraint asserting 053 * that the type of the output of this port is greater than or equal to the 054 * GLB of its destinations. 055 * <p> 056 * NOTE: It may seem counterintuitive that the constraint is "greater than 057 * or equal to" rather than "less than or equal to". But the latter 058 * constraint is already implied by the connections, since the output port 059 * type is required to be less than or equal to each destination port type. 060 * The combination of these constraints has the effect of setting the type 061 * of the output equal to the GLB of the types of the destination ports. 062 * This resolved type is, in fact, the most specific type that satisfies the 063 * constraints of all the downstream ports. 064 * @author Edward A. Lee, Marten Lohstroh 065 * @version $Id: GLBFunction.java$ 066 * @since Ptolemy II 10.0 067 * @Pt.ProposedRating Red (eal) 068 * @Pt.AcceptedRating Red (cxh) 069 */ 070public class GLBFunction extends MonotonicFunction { 071 072 /** Construct a GLBFunction that finds the greatest lower bound of the 073 * type variable of the destination ports connected to the TypedIOPort 074 * that is given as an argument. If the boolean argument inside is true 075 * then the port is required to be an input port and the arguments for 076 * this <code>GLBFunction</code> will be the inside destination ports. 077 * Otherwise, the port is required to be an output port and the arguments 078 * for this <code>GLBFunction</code> will be the outside destination ports. 079 * 080 * @param sourcePort The port connected to the ports of which their type 081 * variables are used to calculate the greatest lower bound. 082 * 083 */ 084 public GLBFunction(TypedIOPort sourcePort) { 085 _sourcePort = sourcePort; 086 } 087 088 /////////////////////////////////////////////////////////////////// 089 //// public methods //// 090 091 /** Return the current value of this monotonic function. 092 * @return A Type. 093 * @exception IllegalActionException If thrown while getting the 094 * value of the cached terms. 095 */ 096 @Override 097 public Object getValue() throws IllegalActionException { 098 _updateArguments(); 099 100 Set<Type> types = new HashSet<Type>(); 101 types.addAll(_cachedTypes); 102 for (InequalityTerm _cachedTerm : _cachedTerms) { 103 Type type = (Type) _cachedTerm.getValue(); 104 // if (type != BaseType.UNKNOWN) 105 // enabling this will make the function non-monotonic which may 106 // cause type resolution to diverge 107 types.add(type); 108 } 109 // If there are no destination outputs at all, then set 110 // the output type to unknown. 111 if (types.size() == 0) { 112 return BaseType.UNKNOWN; 113 } 114 // If there is only one destination, the GLB is equal to the 115 // type of that port. 116 if (types.size() == 1) { 117 return types.toArray()[0]; 118 } 119 120 return TypeLattice.lattice().greatestLowerBound(types); 121 } 122 123 /** Return the type variables for this function, which are 124 * the type variables for all the destination ports. 125 * @return An array of InequalityTerms. 126 */ 127 @Override 128 public InequalityTerm[] getVariables() { 129 _updateArguments(); 130 return _cachedTerms; 131 } 132 133 /** Return the type constants for this function, which are 134 * the type constant types for all the destination ports. 135 * @return An array of Types. 136 */ 137 public Type[] getConstants() { 138 _updateArguments(); 139 return _cachedTypes.toArray(new Type[_cachedTypes.size()]); 140 } 141 142 /////////////////////////////////////////////////////////////////// 143 //// protected methods //// 144 145 /** Update the arguments used in <code>getValue()</code>, which are the 146 * InequalityTerms and Types of the destination ports. The arguments are 147 * only updated if the workspace version has changed. 148 */ 149 protected void _updateArguments() { 150 List<IOPort> destinations = null; 151 if (_sourcePort.getContainer().workspace() 152 .getVersion() == _previousWorkspaceVersion) { 153 return; 154 } 155 ArrayList<InequalityTerm> portTypeTermList = new ArrayList<InequalityTerm>(); 156 _cachedTypes = new HashSet<Type>(); 157 // Make sure to support ports that are both input and output. 158 if (_sourcePort.isOutput()) { 159 destinations = _sourcePort.sinkPortList(); 160 } 161 if (_sourcePort.isInput()) { 162 if (destinations == null) { 163 destinations = _sourcePort.insideSinkPortList(); 164 } else { 165 destinations = new LinkedList<IOPort>(destinations); 166 destinations.addAll(_sourcePort.insideSinkPortList()); 167 } 168 } 169 170 for (IOPort destination : destinations) { 171 InequalityTerm destinationTypeTerm = ((TypedIOPort) destination) 172 .getTypeTerm(); 173 if (destinationTypeTerm.isSettable()) { 174 portTypeTermList.add(destinationTypeTerm); 175 } else { 176 _cachedTypes.add(((TypedIOPort) destination).getType()); 177 } 178 } 179 _cachedTerms = portTypeTermList 180 .toArray(new InequalityTerm[portTypeTermList.size()]); 181 _previousWorkspaceVersion = _sourcePort.getContainer().workspace() 182 .getVersion(); 183 } 184 185 /** 186 * Provide a more descriptive string representation. 187 * @return A description of this term. 188 */ 189 @Override 190 public String toString() { 191 return "GreatestLowerBound(destinations)"; 192 } 193 194 /////////////////////////////////////////////////////////////////// 195 //// protected variables //// 196 197 /** The constant types found in destination ports. */ 198 protected Set<Type> _cachedTypes; 199 200 /** The types terms found in destination ports. */ 201 protected InequalityTerm[] _cachedTerms; 202 203 /** The workspace version number at time of last update of arguments. */ 204 protected long _previousWorkspaceVersion = -1; 205 206 /** The source port. */ 207 protected TypedIOPort _sourcePort; 208}