/*
* An adapter class for ptolemy.domains.fsm.kernel.FSMActor.
*
* Copyright (c) 2006-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.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import ptolemy.actor.IOPort;
import ptolemy.data.expr.ASTPtRootNode;
import ptolemy.data.properties.PropertyHelper;
import ptolemy.data.properties.lattice.PropertyConstraintSolver.ConstraintType;
import ptolemy.domains.fsm.kernel.AbstractActionsAttribute;
import ptolemy.domains.fsm.kernel.CommitActionsAttribute;
import ptolemy.domains.fsm.kernel.FSMActor;
import ptolemy.domains.fsm.kernel.OutputActionsAttribute;
import ptolemy.domains.fsm.kernel.State;
import ptolemy.domains.fsm.kernel.Transition;
import ptolemy.kernel.util.Attribute;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NamedObj;
//////////////////////////////////////////////////////////////////////////
//// FSMActor
/**
* An adapter class for ptolemy.domains.fsm.kernel.FSMActor.
*
* @author Man-Kit Leung, Thomas Mandl
* @version $Id: PropertyConstraintFSMHelper.java 54803 2009-06-29 22:33:45Z
* mankit $
* @since Ptolemy II 7.1
* @Pt.ProposedRating Red (mankit)
* @Pt.AcceptedRating Red (mankit)
*/
public class PropertyConstraintFSMHelper extends
PropertyConstraintCompositeHelper {
/**
* Construct an adapter for the given FSMActor. This is the base adapter class
* for any FSMActor that does not have a specific defined adapter class.
* Default actor constraints are set for this adapter.
* @param solver The given solver.
* @param actor The given ActomicActor.
* @exception IllegalActionException Thrown if super class throws it.
*/
public PropertyConstraintFSMHelper(PropertyConstraintSolver solver,
ptolemy.domains.fsm.kernel.FSMActor actor)
throws IllegalActionException {
super(solver, actor);
}
///////////////////////////////////////////////////////////////////
//// public methods ////
/**
* Return the list of property constraints. Return the constraints for the
* setAction and outputAction expressions associated with transitions of
* each contained states. For example, if there is a setAction for assigning
* the value of the variable V, this creates constraints between the
* properties of V and the assigned expression.
* @return The list of property constraints.
* @exception IllegalActionException Thrown if any error occurs when
* creating the constraints.
*/
public List<Inequality> constraintList() throws IllegalActionException {
// FIMXE: cannot call super here, because PropertyConstraintCompositeHelper
// recursively call constraintList() of its children.
//super.constraintList();
ptolemy.domains.fsm.kernel.FSMActor actor = (ptolemy.domains.fsm.kernel.FSMActor) getComponent();
HashMap<NamedObj, List<ASTPtRootNode>> outputActionMap = new HashMap<NamedObj, List<ASTPtRootNode>>();
HashMap<NamedObj, List<ASTPtRootNode>> setActionMap = new HashMap<NamedObj, List<ASTPtRootNode>>();
for (State state : (List<State>) actor.entityList(State.class)) {
List<Transition> transitions = state.outgoingPort
.linkedRelationList();
for (Transition transition : transitions) {
for (Object propertyable : getPropertyables()) {
if (propertyable instanceof NamedObj) {
NamedObj namedObj = (NamedObj) propertyable;
OutputActionsAttribute outputActions = transition.outputActions;
if (outputActions.getDestinationNameList().contains(
namedObj.getName())) {
// do not consider multiple assigenments to same output from one action since
// only the last assignment in the expression is actually effective
ASTPtRootNode parseTree = outputActions
.getParseTree(namedObj.getName());
if (!outputActionMap.containsKey(namedObj)) {
outputActionMap.put(namedObj,
new ArrayList<ASTPtRootNode>());
}
outputActionMap.get(namedObj).add(parseTree);
}
CommitActionsAttribute setActions = transition.setActions;
if (setActions.getDestinationNameList().contains(
namedObj.getName())) {
// do not consider multiple assigenments to same output from one action since
// only the last assignment in the expression is actually effective
ASTPtRootNode parseTree = setActions
.getParseTree(namedObj.getName());
if (!setActionMap.containsKey(namedObj)) {
setActionMap.put(namedObj,
new ArrayList<ASTPtRootNode>());
}
setActionMap.get(namedObj).add(parseTree);
}
}
}
}
}
boolean constraintSource = interconnectConstraintType == ConstraintType.SRC_EQUALS_MEET
|| interconnectConstraintType == ConstraintType.SRC_EQUALS_GREATER;
for (Entry entry : outputActionMap.entrySet()) {
Object destination = entry.getKey();
List<ASTPtRootNode> expressions = (List<ASTPtRootNode>) entry
.getValue();
if (constraintSource) {
for (ASTPtRootNode root : expressions) {
List<Object> sinkAsList = new ArrayList<Object>();
sinkAsList.add(destination);
_constraintObject(interconnectConstraintType, root,
sinkAsList);
}
} else {
_constraintObject(interconnectConstraintType, destination,
expressions);
}
}
for (Entry entry : setActionMap.entrySet()) {
Object destination = entry.getKey();
List<ASTPtRootNode> expressions = (List<ASTPtRootNode>) entry
.getValue();
if (constraintSource) {
for (ASTPtRootNode root : expressions) {
List<Object> sinkAsList = new ArrayList<Object>();
sinkAsList.add(destination);
_constraintObject(interconnectConstraintType, root,
sinkAsList);
}
} else {
_constraintObject(interconnectConstraintType, destination,
expressions);
}
}
_checkIneffectiveOutputPorts(actor, outputActionMap.keySet(),
setActionMap.keySet());
return _union(_ownConstraints, _subHelperConstraints);
}
/**
* Return the list of parsed expression trees for the specified State. This
* traverses the outgoing transitions of the State. The outputActions and
* setActions attributes are parsed for each of these transitions and
* included into the return list.
* @param state The specified State.
* @return the list of parse trees for the specified State.
*/
public List<ASTPtRootNode> getParseTrees(State state) {
List<ASTPtRootNode> result = new LinkedList<ASTPtRootNode>();
Iterator transitions = state.outgoingPort.linkedRelationList()
.iterator();
while (transitions.hasNext()) {
Transition transition = (Transition) transitions.next();
result.addAll(_getParseTrees(transition.outputActions));
result.addAll(_getParseTrees(transition.setActions));
}
return result;
}
/**
* Constrain the first specified term to be at least the second term (e.g.
* term1 >= term2). If neither of the terms is null, increment the
* statistics for default constraints set up.
*/
public void setAtLeastByDefault(Object term1, Object term2) {
setAtLeast(term1, term2);
if (term1 != null && term2 != null) {
_solver.incrementStats("# of default constraints", 1);
_solver.incrementStats("# of composite default constraints", 1);
}
}
/**
* Constrain the two specified terms same as each other. If neither of the
* terms is null, increment the statistics for default constraints set up.
*/
public void setSameAsByDefault(Object term1, Object term2) {
setSameAs(term1, term2);
if (term1 != null && term2 != null) {
_solver.incrementStats("# of default constraints", 2);
_solver.incrementStats("# of composite default constraints", 2);
}
}
///////////////////////////////////////////////////////////////////
//// protected methods ////
/**
* Return a list of root nodes for the parse trees of attribute expressions.
* This also considers the attribute expressions of all the States contained
* in this FSM.
* @return A list of ASTPtRootNodes.
* @exception IllegalActionException If the super method throws it.
*/
protected List<ASTPtRootNode> _getAttributeParseTrees()
throws IllegalActionException {
List<ASTPtRootNode> result = super._getAttributeParseTrees();
ptolemy.domains.fsm.kernel.FSMActor actor = (ptolemy.domains.fsm.kernel.FSMActor) getComponent();
Iterator states = actor.entityList(State.class).iterator();
while (states.hasNext()) {
State state = (State) states.next();
result.addAll(getParseTrees(state));
}
return result;
}
/**
* Get the list of propertyable attributes for this adapter. In this base
* adapter class for FSM, it considers all guard expressions as propertyable
* attributes.
* @return The list of propertyable attributes.
*/
protected List<Attribute> _getPropertyableAttributes() {
List<Attribute> result = super._getPropertyableAttributes();
ptolemy.domains.fsm.kernel.FSMActor actor = (ptolemy.domains.fsm.kernel.FSMActor) getComponent();
Iterator states = actor.entityList(State.class).iterator();
while (states.hasNext()) {
State state = (State) states.next();
Iterator transitions = state.outgoingPort.linkedRelationList()
.iterator();
while (transitions.hasNext()) {
Transition transition = (Transition) transitions.next();
result.add(transition.guardExpression);
}
}
return result;
}
/**
* Return the list of sub-adapters. In this base class, it returns the list
* of ASTNode adapters that are associated with the expressions of the
* propertyable attributes.
* @return The list of sub-adapters.
* @exception IllegalActionException Not thrown in this base class.
*/
protected List<PropertyHelper> _getSubHelpers()
throws IllegalActionException {
return _getASTNodeHelpers();
}
///////////////////////////////////////////////////////////////////
//// private methods ////
private void _checkIneffectiveOutputPorts(FSMActor actor,
Set<NamedObj> setDestinations1, Set<NamedObj> setDestinations2) {
Iterator outputs = actor.outputPortList().iterator();
while (outputs.hasNext()) {
IOPort output = (IOPort) outputs.next();
if (!setDestinations1.isEmpty() && !setDestinations2.isEmpty()) {
if (!setDestinations1.contains(output)
&& !setDestinations2.contains(output)) {
getPropertyTerm(output).setEffective(false);
}
} else if (setDestinations1.isEmpty()) {
if (!setDestinations2.contains(output)) {
getPropertyTerm(output).setEffective(false);
}
} else if (setDestinations2.isEmpty()) {
if (!setDestinations1.contains(output)) {
getPropertyTerm(output).setEffective(false);
}
}
}
}
/** Return the parse trees for a given action.
* @param actions The given action.
* @return The parse trees.
*/
private List<ASTPtRootNode> _getParseTrees(AbstractActionsAttribute actions) {
List<ASTPtRootNode> parseTrees = actions.getParseTreeList();
Iterator iterator = parseTrees.iterator();
while (iterator.hasNext()) {
putAttribute((ASTPtRootNode) iterator.next(), actions);
}
return parseTrees;
}
}