summaryrefslogtreecommitdiffstats
path: root/src/uscxml/transform/ChartToFSM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/transform/ChartToFSM.cpp')
-rw-r--r--src/uscxml/transform/ChartToFSM.cpp1106
1 files changed, 435 insertions, 671 deletions
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp
index 2c5aacd..8eda0a5 100644
--- a/src/uscxml/transform/ChartToFSM.cpp
+++ b/src/uscxml/transform/ChartToFSM.cpp
@@ -33,6 +33,26 @@
#undef max
#include <limits>
+#define DUMP_STATS(nrTrans) \
+uint64_t now = tthread::chrono::system_clock::now(); \
+if (now - _lastTimeStamp > 1000) { \
+ std::cerr << "T: " << _perfTransTotal << " [" << _perfTransProcessed << "/sec]"; \
+ if (nrTrans > 0) { \
+ std::cerr << " - 2**" << nrTrans << " = " << pow(2.0, static_cast<double>(nrTrans)); \
+ } \
+ std::cerr << std::endl; \
+ std::cerr << "S: " << _globalConf.size() << " [" << _perfStatesProcessed << "/sec]" << std::endl; \
+ std::cerr << "C: " << _perfStatesCachedTotal << " [" << _perfStatesCachedProcessed << "/sec]" << std::endl; \
+ std::cerr << "X: " << _perfStatesSkippedTotal << " [" << _perfStatesSkippedProcessed << "/sec]" << std::endl; \
+ std::cerr << std::endl; \
+ _perfTransProcessed = 0; \
+ _perfStatesProcessed = 0; \
+ _perfStatesCachedProcessed = 0; \
+ _perfStatesSkippedProcessed = 0; \
+ _lastTimeStamp = now; \
+}
+
+
#define DUMP_TRANSSET(where) \
{\
std::cout << std::endl;\
@@ -41,26 +61,13 @@ std::cout << "** " << transitions.size() << " ** " << where << std::endl;\
std::cout << transitions[m] << std::endl;\
}\
}
+
namespace uscxml {
using namespace Arabica::DOM;
using namespace Arabica::XPath;
-#define CREATE_TRANSIENT_STATE_WITH_CHILDS(stateId) \
-if (childs.size() > 0) { \
- Element<std::string> transientState = _flatDoc.createElementNS(_nsInfo.nsURL, "state"); \
- _nsInfo.setPrefix(transientState);\
- transientState.setAttribute("transient", "true"); \
- if (stateId.length() > 0) \
- transientState.setAttribute("id", stateId); \
- for (int i = 0; i < childs.size(); i++) { \
- Node<std::string> imported = _flatDoc.importNode(childs[i], true); \
- transientState.appendChild(imported); \
- } \
- transientStateChain.push_back(transientState); \
-} \
-childs = NodeSet<std::string>();
#define DETAIL_EXEC_CONTENT(field, actPtr) \
std::cerr << " " << #field << " / " << TAGNAME_CAST(actPtr->field) << " ("; \
@@ -71,19 +78,7 @@ for (int i = 0; i < contents.size(); i++) { \
std::cerr << ")";
-Interpreter ChartToFSM::flatten(const Interpreter& other) {
-
- // instantiate a new InterpreterImpl to do the flattening
- boost::shared_ptr<InterpreterImpl> flattener = boost::shared_ptr<InterpreterImpl>(new FlatteningInterpreter(other.getDocument()));
- flattener->setNameSpaceInfo(other.getNameSpaceInfo());
- flattener->interpret();
-
- // clone the flattener implementation to a new interpreter
- Interpreter flat = Interpreter::fromClone(flattener);
- return flat;
-}
-
-uint64_t ChartToFSM::stateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
+uint64_t Complexity::stateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
Complexity complexity = calculateStateMachineComplexity(root);
uint64_t value = complexity.value;
for (std::list<uint64_t>::const_iterator histIter = complexity.history.begin(); histIter != complexity.history.end(); histIter++) {
@@ -93,7 +88,7 @@ uint64_t ChartToFSM::stateMachineComplexity(const Arabica::DOM::Element<std::str
return value;
}
-ChartToFSM::Complexity ChartToFSM::calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
+Complexity Complexity::calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
Complexity complexity;
bool hasFlatHistory = false;
@@ -144,56 +139,66 @@ ChartToFSM::Complexity ChartToFSM::calculateStateMachineComplexity(const Arabica
}
-FlatteningInterpreter::FlatteningInterpreter(const Document<std::string>& doc) {
+ChartToFSM::ChartToFSM(const Interpreter& other) {
- _perfProcessed = 0;
- _perfTotal = 0;
+ cloneFrom(other.getImpl());
+
_lastTimeStamp = tthread::chrono::system_clock::now();
+ _perfTransProcessed = 0;
+ _perfTransTotal = 0;
+ _perfStatesProcessed = 0;
+ _perfStatesSkippedProcessed = 0;
+ _perfStatesSkippedTotal = 0;
+ _perfStatesCachedProcessed = 0;
+ _perfStatesCachedTotal = 0;
+
+ _start = NULL;
_currGlobalTransition = NULL;
_lastTransientStateId = 0;
- // just copy given doc into _document an create _flatDoc for the FSM
+ _lastStateIndex = 0;
+ _lastTransIndex = 0;
+
+ // create a _flatDoc for the FSM
DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
- _document = domFactory.createDocument(doc.getNamespaceURI(), "", 0);
- _flatDoc = domFactory.createDocument(doc.getNamespaceURI(), "", 0);
-
- Node<std::string> child = doc.getFirstChild();
- while (child) {
- Node<std::string> newNode = _document.importNode(child, true);
- _document.appendChild(newNode);
- child = child.getNextSibling();
- }
+ _flatDoc = domFactory.createDocument(other.getDocument().getNamespaceURI(), "", 0);
addMonitor(this);
}
-FlatteningInterpreter::~FlatteningInterpreter() {
+ChartToFSM::~ChartToFSM() {
std::map<std::string, GlobalState*>::iterator confIter = _globalConf.begin();
while(confIter != _globalConf.end()) {
- std::map<std::string, GlobalTransition*>::iterator transIter = confIter->second->outgoing.begin();
- while (transIter != confIter->second->outgoing.end()) {
- delete transIter->second;
+ std::list<GlobalTransition*>::iterator transIter = confIter->second->sortedOutgoing.begin();
+ while (transIter != confIter->second->sortedOutgoing.end()) {
+ delete *transIter;
transIter++;
}
delete confIter->second;
confIter++;
}
+
+ // tear down caches
+ Arabica::XPath::NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true);
+ for (int i = 0; i < allTransitions.size(); i++) {
+ _transParents.erase(allTransitions[i]);
+ }
}
-Document<std::string> FlatteningInterpreter::getDocument() const {
+Document<std::string> ChartToFSM::getDocument() const {
// std::cerr << "######################" << std::endl;
// std::cerr << _flatDoc << std::endl;
// std::cerr << "######################" << std::endl;
return _flatDoc;
}
-InterpreterState FlatteningInterpreter::interpret() {
+InterpreterState ChartToFSM::interpret() {
init();
setupIOProcessors();
- uint64_t complexity = ChartToFSM::stateMachineComplexity(_scxml) + 1;
+ uint64_t complexity = Complexity::stateMachineComplexity(_scxml) + 1;
std::cerr << "Approximate Complexity: " << complexity << std::endl;
// initialize the datamodel
@@ -216,6 +221,16 @@ InterpreterState FlatteningInterpreter::interpret() {
LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
}
+ // setup caches
+ {
+ Arabica::XPath::NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true);
+ indexedTransitions.reserve(allTransitions.size());
+ for (int i = 0; i < allTransitions.size(); i++) {
+ _transParents[allTransitions[i]] = InterpreterImpl::getParentState(allTransitions[i]);
+ }
+ }
+
+
_binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
// set invokeid for all invokers to parent state if none given
@@ -229,10 +244,9 @@ InterpreterState FlatteningInterpreter::interpret() {
_currGlobalTransition = NULL;
// very first state
- GlobalState::gIndex = 0;
- _start = new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix);
+ _start = new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this);
_globalConf[_start->stateId] = _start;
- _globalConf[_start->stateId]->index = toStr(GlobalState::gIndex++);
+ _globalConf[_start->stateId]->index = _lastStateIndex++;
NodeSet<std::string> initialTransitions;
@@ -255,14 +269,47 @@ InterpreterState FlatteningInterpreter::interpret() {
// weightTransitions();
indexTransitions(_scxml);
+ // reverse indices for most prior to be in front
+ std::reverse(indexedTransitions.begin(), indexedTransitions.end());
+
+ // add initial transitions as least prior
+ for (int i = 0; i < initialTransitions.size() ; i++) {
+ indexedTransitions.push_back(Element<std::string>(initialTransitions[i]));
+ }
+
+ // set index attribute for transitions
+ for (int i = 0; i < indexedTransitions.size(); i++) {
+ indexedTransitions[i].setAttribute("index", toStr(i));
+ }
+
+// int lastTransIndex = indexedTransitions.size();
+// for (int i = 0; i < initialTransitions.size() ; i++, lastTransIndex++) {
+// indexedTransitions[i].setAttribute("index", toStr(indexedTransitions.size() - 1 - i));
+// }
+
+ // gather and set index attribute o states
+ NodeSet<std::string> allStates = getAllStates();
+ allStates.to_document_order();
+
+ indexedStates.resize(allStates.size());
+ for (int i = 0; i < allStates.size(); i++) {
+ Element<std::string> state = Element<std::string>(allStates[i]);
+ state.setAttribute("index", toStr(i));
+ indexedStates[i] = state;
+ }
+
// std::cerr << _scxml << std::endl;
GlobalTransition* globalTransition = new GlobalTransition(initialTransitions, _dataModel, this);
- _start->outgoing[globalTransition->transitionId] = globalTransition;
+ globalTransition->index = _lastTransIndex++;
+
+ _start->sortedOutgoing.push_back(globalTransition);
globalTransition->source = _start->stateId;
_currGlobalTransition = globalTransition;
enterStates(initialTransitions);
+ globalTransition->destination = FlatStateIdentifier::toStateId(_configuration);
+
explode();
#if 0
@@ -275,9 +322,6 @@ InterpreterState FlatteningInterpreter::interpret() {
std::cerr << _globalConf.size() << std::endl;
#endif
- createDocument();
-
-// std::cout << _scxml << std::endl;
NodeSet<std::string> elements = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, _scxml, true);
uint64_t nrStates = 0;
@@ -294,14 +338,14 @@ InterpreterState FlatteningInterpreter::interpret() {
return _state;
}
-void FlatteningInterpreter::executeContent(const Arabica::DOM::Element<std::string>& content, bool rethrow) {
+void ChartToFSM::executeContent(const Arabica::DOM::Element<std::string>& content, bool rethrow) {
// std::cerr << content << std::endl;
// std::cerr << TAGNAME(content) << std::endl;
GlobalTransition::Action action;
if (false) {
- } else if (TAGNAME(content) == "transition") {
+ } else if (TAGNAME(content) == "transition" && content.hasChildNodes()) {
action.transition = content;
} else if (TAGNAME(content) == "onexit") {
action.onExit = content;
@@ -313,23 +357,24 @@ void FlatteningInterpreter::executeContent(const Arabica::DOM::Element<std::stri
return;
}
_currGlobalTransition->actions.push_back(action);
+ _currGlobalTransition->hasExecutableContent = true;
}
-void FlatteningInterpreter::invoke(const Arabica::DOM::Element<std::string>& element) {
+void ChartToFSM::invoke(const Arabica::DOM::Element<std::string>& element) {
GlobalTransition::Action action;
action.invoke = element;
_currGlobalTransition->actions.push_back(action);
- _currGlobalTransition->invoke.push_back(element);
+ _currGlobalTransition->hasExecutableContent = true;
}
-void FlatteningInterpreter::cancelInvoke(const Arabica::DOM::Element<std::string>& element) {
+void ChartToFSM::cancelInvoke(const Arabica::DOM::Element<std::string>& element) {
GlobalTransition::Action action;
action.uninvoke = element;
_currGlobalTransition->actions.push_back(action);
- _currGlobalTransition->uninvoke.push_back(element);
+ _currGlobalTransition->hasExecutableContent = true;
}
-void FlatteningInterpreter::internalDoneSend(const Arabica::DOM::Element<std::string>& state) {
+void ChartToFSM::internalDoneSend(const Arabica::DOM::Element<std::string>& state) {
Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
if (parentIsScxmlState(state))
@@ -367,34 +412,38 @@ void FlatteningInterpreter::internalDoneSend(const Arabica::DOM::Element<std::st
action.onEntry = onentry;
_currGlobalTransition->actions.push_back(action);
+ _currGlobalTransition->hasExecutableContent = true;
}
static bool isSuperset(const GlobalTransition* t1, const GlobalTransition* t2) {
bool isSuperset = true;
- if (t1->transitions.size() >= t2->transitions.size())
+ if (t1->transitionRefs.size() >= t2->transitionRefs.size())
return false;
- for (int i = 0; i < t1->transitions.size(); i++) {
- if (!InterpreterImpl::isMember(t1->transitions[i], t2->transitions)) {
+ NodeSet<std::string> t1Trans = t1->getTransitions();
+ NodeSet<std::string> t2Trans = t2->getTransitions();
+
+ for (int i = 0; i < t1Trans.size(); i++) {
+ if (!InterpreterImpl::isMember(t1Trans[i], t2Trans)) {
isSuperset = false;
}
}
return isSuperset;
}
-static bool filterSameState(const NodeSet<std::string>& transitions) {
- NodeSet<std::string> filteredTransitions;
+// return false if two transitions have the same source
+std::map<Arabica::DOM::Node<std::string>, Arabica::DOM::Node<std::string> > ChartToFSM::_transParents;
+bool ChartToFSM::filterSameState(const NodeSet<std::string>& transitions) {
+
for (unsigned int i = 0; i < transitions.size(); i++) {
- Node<std::string> t1 = transitions[i];
- Node<std::string> p1 = InterpreterImpl::getParentState(t1);
+ Node<std::string> p1 = _transParents[transitions[i]];
- for (unsigned int j = 0; j < transitions.size(); j++) {
- if (i == j)
- continue;
- Node<std::string> t2 = transitions[j];
- Node<std::string> p2 = InterpreterImpl::getParentState(t2);
+ for (unsigned int j = i + 1; j < transitions.size(); j++) {
+// if (i == j)
+// continue;
+ Node<std::string> p2 = _transParents[transitions[j]];
if (p1 == p2)
return false;
@@ -433,7 +482,7 @@ static bool filterChildEnabled(const NodeSet<std::string>& transitions) {
}
-void FlatteningInterpreter::indexTransitions(const Arabica::DOM::Element<std::string>& root) {
+void ChartToFSM::indexTransitions(const Arabica::DOM::Element<std::string>& root) {
// breadth first traversal of transitions
Arabica::XPath::NodeSet<std::string> levelTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", root);
for (int i = levelTransitions.size() - 1; i >= 0; i--) {
@@ -450,187 +499,163 @@ void FlatteningInterpreter::indexTransitions(const Arabica::DOM::Element<std::st
}
bool GlobalTransition::operator< (const GlobalTransition& other) const {
- const std::list<Arabica::DOM::Element<std::string> >& indexedTransitions = interpreter->indexedTransitions;
- for (std::list<Element<std::string> >::const_reverse_iterator transIter = indexedTransitions.rbegin(); transIter != indexedTransitions.rend(); transIter++) {
+ const std::vector<Arabica::DOM::Element<std::string> >& indexedTransitions = interpreter->indexedTransitions;
+ NodeSet<std::string> transitions = getTransitions();
+
+ for (std::vector<Element<std::string> >::const_iterator transIter = indexedTransitions.begin(); transIter != indexedTransitions.end(); transIter++) {
const Element<std::string>& refTrans = *transIter;
+ NodeSet<std::string> otherTransitions = other.getTransitions();
- if (InterpreterImpl::isMember(refTrans, transitions) && !InterpreterImpl::isMember(refTrans, other.transitions)) {
+ if (InterpreterImpl::isMember(refTrans, transitions) && !InterpreterImpl::isMember(refTrans, otherTransitions)) {
return true;
}
- if (!InterpreterImpl::isMember(refTrans, transitions) && InterpreterImpl::isMember(refTrans, other.transitions)) {
+ if (!InterpreterImpl::isMember(refTrans, transitions) && InterpreterImpl::isMember(refTrans, otherTransitions)) {
return false;
}
}
return true; // actually, they are equal
}
+template <typename T> bool PtrComp(const T * const & a, const T * const & b) {
+ return *a < *b;
+}
-void FlatteningInterpreter::explode() {
-
- // save global configuration elements to restore after recursive explode
- Arabica::XPath::NodeSet<std::string> configuration = _configuration;
- Arabica::XPath::NodeSet<std::string> alreadyEntered = _alreadyEntered;
- std::map<std::string, Arabica::XPath::NodeSet<std::string> > historyValue = _historyValue;
-
- // create current state from global configuration
- GlobalState* globalState = new GlobalState(configuration, alreadyEntered, historyValue, _nsInfo.xmlNSPrefix);
- // remember that the last transition lead here
- if (_currGlobalTransition) {
- _currGlobalTransition->destination = globalState->stateId;
- globalState->incoming[_currGlobalTransition->transitionId] = _currGlobalTransition;
+/**
+ * subset only removes transitions without cond -> superset will always be enabled
+ */
+bool hasUnconditionalSuperset (GlobalTransition* first, GlobalTransition* second) {
-// if (!_currGlobalTransition->isEventless) {
- // if it was an eventful transition, add all invokers
- for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
- NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
- for (unsigned int j = 0; j < invokes.size(); j++) {
- invoke(Element<std::string>(invokes[j]));
+ NodeSet<std::string> firstTransitions = first->getTransitions();
+ NodeSet<std::string> secondTransitions = first->getTransitions();
+
+ if (isSuperset(second, first)) {
+ for (int i = 0; i < firstTransitions.size(); i++) {
+ if (!InterpreterImpl::isMember(firstTransitions[i], secondTransitions)) {
+ if (HAS_ATTR_CAST(firstTransitions[i], "cond")) {
+ return false; // second can't be removed
+ }
}
}
- _statesToInvoke = NodeSet<std::string>();
-// }
+ return true; // remove second
}
+ return false; //second can't be removed
+}
- if (_globalConf.find(globalState->stateId) != _globalConf.end()) {
- delete globalState;
- return; // we have already been here
+bool hasEarlierUnconditionalMatch(GlobalTransition* first, GlobalTransition* second) {
+ if (first->eventDesc == second->eventDesc) {
+ if (first->condition.size() == 0)
+ return true;
}
+ return false;
+}
- _globalConf[globalState->stateId] = globalState;
- _globalConf[globalState->stateId]->index = toStr(GlobalState::gIndex++);
-// assert(isLegalConfiguration(configuration));
-
- if(_globalConf[globalState->stateId]->isFinal)
- return; // done in this branch
+// for some reason, unique is not quite up to the task
+std::list<GlobalTransition*> reapplyUniquePredicates(std::list<GlobalTransition*> list) {
+
+ for (std::list<GlobalTransition*>::iterator outerIter = list.begin();
+ outerIter != list.end();
+ outerIter++) {
+ for (std::list<GlobalTransition*>::iterator innerIter = outerIter;
+ innerIter != list.end();
+ innerIter++) {
+
+ if (innerIter == outerIter)
+ continue;
+
+ GlobalTransition* t1 = *outerIter;
+ GlobalTransition* t2 = *innerIter;
+
+ if (hasUnconditionalSuperset(t1, t2)) {
+ list.erase(outerIter++);
+ continue;
+ } else if (hasUnconditionalSuperset(t2, t1)) {
+ list.erase(innerIter++);
+ continue;
+ }
+ if (hasEarlierUnconditionalMatch(t1, t2)) {
+ list.erase(innerIter++);
+ continue;
+ }
+ }
+ }
+
+ return list;
+}
+void ChartToFSM::getPotentialTransitionsForConf(const Arabica::XPath::NodeSet<std::string>& conf, std::map<std::string, GlobalTransition*>& outMap) {
// get all transition elements from states in the current configuration
- NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", configuration);
-
- /**
- * From http://www.w3.org/TR/scxml/#SelectingTransitions
- *
- * A transition T is enabled by named event E in atomic state S if
- * a) T's source state is S or an ancestor of S
- * b) T matches E's name
- * c) T lacks a 'cond' attribute or its 'cond' attribute evaluates to "true"
- *
- * A transition is enabled by NULL in atomic state S if
- * a) T lacks an 'event' attribute
- * b) T's source state is S or an ancestor of S
- * c) T lacks an 'cond' attribute or its 'cond' attribute evaluates to "true"
- *
- * The _source state_ of a transition is the <state> or <parallel> element that it occurs in.
- * The _target state(s)_ of the transition is the state or set of states specified by its 'target' attribute.
- * The _complete target_ set of a transition consists of all the states that will be active after the transition is taken.
- *
- * A transition T is optimally enabled by event E in atomic state S if
- * a) T is enabled by E in S
- * b) no transition that precedes T in document order in T's source state is enabled by E in S
- * c) no transition is enabled by E in S in any descendant of T's source state.
- *
- * Two transitions T1 and T2 conflict in state configuration C if their exit sets in C have a non-null intersection.
- * let transitions T1 and T2 conflict:
- * T1 is optimally enabled in atomic state S1
- * T2 is optimally enabled in atomic state S2
- * S1 and S2 are both active
- * T1 has a higher priority than T2 if:
- * a) T1's source state is a descendant of T2's source state, or
- * b) S1 precedes S2 in document order
- *
- * The _optimal transition set_ enabled by event E in state configuration C is
- * the largest set of transitions such that:
- * a) each transition in the set is optimally enabled by E in an atomic state in C
- * b) no transition conflicts with another transition in the set
- * c) there is no optimally enabled transition outside the set that has a higher priority than some member of the set
- *
- * A _microstep_ consists of the execution of the transitions in an optimal enabled transition set
- *
- * A _macrostep_ is a series of one or more microsteps ending in a configuration
- * where the internal event queue is empty and no transitions are enabled by NULL
- */
-
-
+ NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", conf);
+
if (allTransitions.size() == 0)
return; // no transitions
-
+
int nrElements = allTransitions.size();
int k = 0;
int* stack = (int*)malloc((nrElements + 1) * sizeof(int));
memset(stack, 0, (nrElements + 1) * sizeof(int));
-
- // subset of powerset we already processed
- std::map<std::string, GlobalTransition*> transitionSets;
-
+
while(1) {
// create the power set of all potential transitions - this is expensive!
// see: http://www.programminglogic.com/powerset-algorithm-in-c/
-
+
if (stack[k] < nrElements) {
stack[k+1] = stack[k] + 1;
k++;
}
-
+
else {
stack[k-1]++;
k--;
}
-
+
if (k==0)
break;
-
+
NodeSet<std::string> transitions;
-// std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl;
+ // std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl;
for (int i = 1; i <= k; i++) {
-// std::cerr << stack[i] - 1 << ", ";
+ // std::cerr << stack[i] - 1 << ", ";
transitions.push_back(allTransitions[stack[i] - 1]);
}
-// std::cerr << std::endl;
-
-// transitions.push_back(allTransitions[0]);
-// transitions.push_back(allTransitions[4]);
-// transitions.push_back(allTransitions[5]);
-// transitions.push_back(allTransitions[7]);
-
+ // std::cerr << std::endl;
+
+ // transitions.push_back(allTransitions[0]);
+ // transitions.push_back(allTransitions[4]);
+ // transitions.push_back(allTransitions[5]);
+ // transitions.push_back(allTransitions[7]);
+
bool dump = false;
-
-// if (k == 4 && stack[1] == 1 && stack[2] == 5 && stack[3] == 6 && stack[4] == 8) {
-// dump = true;
-// }
-
+
+ // if (k == 4 && stack[1] == 1 && stack[2] == 5 && stack[3] == 6 && stack[4] == 8) {
+ // dump = true;
+ // }
+
if (dump) DUMP_TRANSSET("at start");
-
- _perfTotal++;
- _perfProcessed++;
-
- if (tthread::chrono::system_clock::now() - _lastTimeStamp > 1000) {
- _lastTimeStamp = tthread::chrono::system_clock::now();
-// std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl;
- std::cerr << "States: " << _globalConf.size() << " - ";
- std::cerr << "Tested: " << _perfTotal << " [" << _perfProcessed << "/sec] - ";
- std::cerr << "Current Complexity: 2**" << nrElements << " = " << pow(2.0, static_cast<double>(nrElements));
- std::cerr << std::endl;
- _perfProcessed = 0;
- }
-
+
+ _perfTransTotal++;
+ _perfTransProcessed++;
+
+ DUMP_STATS(nrElements);
+
// remove transitions in the same state
if(!filterSameState(transitions))
continue;
if (dump) DUMP_TRANSSET("after same state filtered");
-
+
// remove those transitions with a child transition
if(!filterChildEnabled(transitions))
continue;
if (dump) DUMP_TRANSSET("after child enabled filtered");
-
+
// reduce to conflict-free subset
// transitions.to_document_order();
transitions = removeConflictingTransitions(transitions);
if (dump) DUMP_TRANSSET("after conflicting filtered");
-
+
// algorithm can never reduce to empty set
assert(transitions.size() > 0);
-
+
// create a GlobalTransition object from the set
GlobalTransition* transition = new GlobalTransition(transitions, _dataModel, this);
if (!transition->isValid) {
@@ -638,447 +663,152 @@ void FlatteningInterpreter::explode() {
delete transition;
continue;
}
+ transition->index = _lastTransIndex++;
// two combinations might have projected onto the same conflict-free set
- if (transitionSets.find(transition->transitionId) != transitionSets.end()) {
-// std::cerr << "skipping as projected onto existing conflict-free subset" << std::endl;
+ if (outMap.find(transition->transitionId) != outMap.end()) {
+ // std::cerr << "skipping as projected onto existing conflict-free subset" << std::endl;
delete transition;
continue;
}
-
+
// remember this conflict-free set
-// std::cerr << "New conflict-free subset: " << transition->transitionId << ":" << transition->eventDesc << std::endl;
- transitionSets[transition->transitionId] = transition;
+ // std::cerr << "New conflict-free subset: " << transition->transitionId << ":" << transition->eventDesc << std::endl;
+ outMap[transition->transitionId] = transition;
}
-
- // TODO: reduce and sort transition sets
- std::list<GlobalTransition*> transitionList;
- for(std::map<std::string, GlobalTransition*>::iterator transSetIter = transitionSets.begin();
- transSetIter != transitionSets.end();
- transSetIter++) {
- transitionList.push_back(transSetIter->second);
- }
-
- for(std::list<GlobalTransition*>::iterator transListIter = transitionList.begin();
- transListIter != transitionList.end();
- transListIter++) {
-
- // add transition set to current global state
- globalState->outgoing[(*transListIter)->transitionId] = *transListIter;
- (*transListIter)->source = globalState->stateId;
-
- _currGlobalTransition = *transListIter;
- microstep((*transListIter)->transitions);
-// if (!isLegalConfiguration(_configuration)) {
-// FlatStateIdentifier fromState(configuration, alreadyEntered, historyValue);
-// FlatStateIdentifier toState(_configuration, _alreadyEntered, _historyValue);
-// std::cerr << "invalid configuration after transition " << std::endl
-// << "from \t" << fromState.getStateId() << std::endl
-// << "to \t" << toState.getStateId() << std::endl
-// << "via ------" << std::endl;
-// for (int i = 0; i < (*transListIter)->transitions.size(); i++) {
-// std::cerr << (*transListIter)->transitions[i] << std::endl;
-// }
-// std::cerr << "----------" << std::endl;
-// assert(false);
-// }
- explode();
-
- // reset state for next transition set
- _configuration = configuration;
- _alreadyEntered = alreadyEntered;
- _historyValue = historyValue;
-
- }
-}
-
-static bool sortStatesByIndex(const std::pair<std::string,GlobalState*>& s1, const std::pair<std::string,GlobalState*>& s2) {
- return s1.second->index < s2.second->index;
+ return;
}
-
-void FlatteningInterpreter::createDocument() {
- Element<std::string> _origSCXML = _scxml;
-
- _scxml = _flatDoc.createElementNS(_nsInfo.nsURL, "scxml");
- _nsInfo.setPrefix(_scxml);
-
- _scxml.setAttribute("flat", "true");
- _flatDoc.appendChild(_scxml);
-
- if (HAS_ATTR(_origSCXML, "datamodel")) {
- _scxml.setAttribute("datamodel", ATTR(_origSCXML, "datamodel"));
- }
-
- if (HAS_ATTR(_origSCXML, "name")) {
- _scxml.setAttribute("name", ATTR(_origSCXML, "name"));
- }
-
- if (HAS_ATTR(_origSCXML, "binding")) {
- _scxml.setAttribute("binding", ATTR(_origSCXML, "binding"));
- }
-
- _scxml.setAttribute("initial", _start->stateId);
-
- NodeSet<std::string> datas;
- if (_binding == InterpreterImpl::LATE) {
- // with late binding, just copy direct datamodel childs
- datas = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _origSCXML);
- } else {
- // with early binding, copy all datamodel elements into scxml element
- datas = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "datamodel", _origSCXML).asNodeSet();
- }
- for (int i = 0; i < datas.size(); i++) {
- if (isInEmbeddedDocument(datas[i]))
- continue; // nested document
- Node<std::string> imported = _flatDoc.importNode(datas[i], true);
- _scxml.appendChild(imported);
- }
-
-
- NodeSet<std::string> scripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", _origSCXML);
- for (int i = 0; i < scripts.size(); i++) {
- Node<std::string> imported = _flatDoc.importNode(scripts[i], true);
- _scxml.appendChild(imported);
- }
-
- NodeSet<std::string> comments = filterChildType(Node_base::COMMENT_NODE, _origSCXML);
- for (int i = 0; i < comments.size(); i++) {
- Node<std::string> imported = _flatDoc.importNode(comments[i], true);
- _scxml.appendChild(imported);
- }
-
- std::vector<std::pair<std::string,GlobalState*> > sortedStates;
- sortedStates.insert(sortedStates.begin(), _globalConf.begin(), _globalConf.end());
- std::sort(sortedStates.begin(), sortedStates.end(), sortStatesByIndex);
-
- int index = 0;
- for (std::list<Element<std::string> >::reverse_iterator transIter = indexedTransitions.rbegin(); transIter != indexedTransitions.rend(); transIter++) {
- const Element<std::string>& refTrans = *transIter;
- std::cerr << index++ << ": " << refTrans << std::endl;
- }
- std::cerr << std::endl;
-
- for (std::vector<std::pair<std::string,GlobalState*> >::iterator confIter = sortedStates.begin();
- confIter != sortedStates.end();
- confIter++) {
- appendGlobalStateNode(confIter->second);
- }
-// exit(0);
-
-}
-
-
-template <typename T> bool PtrComp(const T * const & a, const T * const & b) {
- return *a < *b;
-}
-
-
-/**
- * subset only removes transitions without cond -> superset will always be enabled
- */
-bool hasUnconditionalSuperset (GlobalTransition* first, GlobalTransition* second) {
- if (isSuperset(second, first)) {
- for (int i = 0; i < first->transitions.size(); i++) {
- if (!InterpreterImpl::isMember(first->transitions[i], second->transitions)) {
- if (HAS_ATTR_CAST(first->transitions[i], "cond")) {
- return false; // second can't be removed
- }
- }
- }
- return true; // remove second
- }
- return false; //second can't be removed
-}
-
-bool hasEarlierUnconditionalMatch(GlobalTransition* first, GlobalTransition* second) {
- if (first->eventDesc == second->eventDesc) {
- if (first->condition.size() == 0)
- return true;
- }
- return false;
-}
-
-// for some reason, unique is not quite up to the task
-std::list<GlobalTransition*> reapplyUniquePredicates(std::list<GlobalTransition*> list) {
-
- for (std::list<GlobalTransition*>::iterator outerIter = list.begin();
- outerIter != list.end();
- outerIter++) {
- for (std::list<GlobalTransition*>::iterator innerIter = outerIter;
- innerIter != list.end();
- innerIter++) {
-
- if (innerIter == outerIter)
- continue;
-
- GlobalTransition* t1 = *outerIter;
- GlobalTransition* t2 = *innerIter;
-
- if (hasUnconditionalSuperset(t1, t2)) {
- list.erase(outerIter++);
- continue;
- } else if (hasUnconditionalSuperset(t2, t1)) {
- list.erase(innerIter++);
- continue;
- }
- if (hasEarlierUnconditionalMatch(t1, t2)) {
- list.erase(innerIter++);
- continue;
- }
+
+void ChartToFSM::explode() {
+
+ std::list<GlobalState*> statesRemaining;
+ statesRemaining.push_back(new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this));
+
+ // add all invokers for initial transition
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ invoke(Element<std::string>(invokes[j]));
}
}
+ _statesToInvoke = NodeSet<std::string>();
- return list;
-}
-
-void FlatteningInterpreter::appendGlobalStateNode(GlobalState* globalState) {
- Element<std::string> state = _flatDoc.createElementNS(_nsInfo.nsURL, "state");
- _nsInfo.setPrefix(state);
-
- state.setAttribute("ref", globalState->index);
- state.setAttribute("id", globalState->stateId);
-
- if (globalState->isFinal)
- state.setAttribute("final", "true");
-
- std::list<GlobalTransition*> transitionList;
- for (std::map<std::string, GlobalTransition*>::iterator outIter = globalState->outgoing.begin();
- outIter != globalState->outgoing.end();
- outIter++) {
- transitionList.push_back(outIter->second);
- }
-
-// transitionList = sortTransitions(transitionList);
- transitionList.sort(PtrComp<GlobalTransition>);
- transitionList.unique(hasUnconditionalSuperset);
- transitionList.unique(hasEarlierUnconditionalMatch);
- // unique is not quite like what we need, but it was a start
- transitionList = reapplyUniquePredicates(transitionList);
-
- // apend here, for transient state chains to trail the state
- _scxml.appendChild(state);
-
- size_t index = 0;
- for (std::list<GlobalTransition*>::iterator outIter = transitionList.begin();
- outIter != transitionList.end();
- outIter++) {
- (*outIter)->index = globalState->index + ":" + toStr(index);
- state.appendChild(globalTransitionToNode(*outIter));
- index++;
- }
-}
-
-/**
- * Creates transient states for executable content as a side-effect
- */
-Node<std::string> FlatteningInterpreter::globalTransitionToNode(GlobalTransition* globalTransition) {
- Element<std::string> transition = _flatDoc.createElementNS(_nsInfo.nsURL, "transition");
- _nsInfo.setPrefix(transition);
-
-// transition.setAttribute("ref", globalTransition->index);
-
-#if 1
- transition.setAttribute("members", globalTransition->members);
-#endif
- // transition.setAttribute("priority", toStr(globalTransition->priority));
-
- if (!globalTransition->isEventless) {
- transition.setAttribute("event", globalTransition->eventDesc);
- }
-
- if (globalTransition->condition.size() > 0) {
- transition.setAttribute("cond", globalTransition->condition);
- }
-
- if (globalTransition->destination.size() > 0) {
- transition.setAttribute("final-target", globalTransition->destination);
- }
-
- NodeSet<std::string> transientStateChain;
-
- // current active state set
- FlatStateIdentifier flatId(globalTransition->source);
- std::list<std::string> currActiveStates = flatId.getActive();
-
-// std::cerr << "From " << globalTransition->source << " to " << globalTransition->destination << ":" << std::endl;
-
- // gather content for new transient state
- NodeSet<std::string> childs;
- // iterate all actions taken during the transition
- for (std::list<GlobalTransition::Action>::iterator actionIter = globalTransition->actions.begin();
- actionIter != globalTransition->actions.end();
- actionIter++) {
-
- if (actionIter->transition) {
-// DETAIL_EXEC_CONTENT(transition, actionIter);
-
- Element<std::string> onexit = _flatDoc.createElementNS(_nsInfo.nsURL, "onexit");
- _nsInfo.setPrefix(onexit);
- Node<std::string> child = actionIter->transition.getFirstChild();
- while(child) {
- Node<std::string> imported = _flatDoc.importNode(child, true);
- onexit.appendChild(imported);
- child = child.getNextSibling();
- }
- // only append if there is something done
- if (onexit.hasChildNodes())
- childs.push_back(onexit);
-
- continue;
- }
-
- if (actionIter->onExit) {
-// DETAIL_EXEC_CONTENT(onExit, actionIter);
-
- childs.push_back(actionIter->onExit);
- continue;
- }
-
- if (actionIter->onEntry) {
-// DETAIL_EXEC_CONTENT(onEntry, actionIter);
-
- childs.push_back(actionIter->onEntry);
- continue;
- }
-
- if (actionIter->invoke) {
-// DETAIL_EXEC_CONTENT(invoke, actionIter);
- if (!globalTransition->isTargetless) {
-// CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates));
- }
- Element<std::string> invokeElem = Element<std::string>(actionIter->invoke);
- invokeElem.setAttribute("persist", "true");
- childs.push_back(invokeElem);
- continue;
+ /**
+ We need this to be a recursion in order not to exhaust the stack
+ */
+
+ // append new global states and pop from front
+ while(statesRemaining.size() > 0) {
+ DUMP_STATS(0);
+
+ GlobalState* globalState = statesRemaining.front();
+ statesRemaining.pop_front();
+
+ // used to be conditionalized, we will just assum
+ assert(_currGlobalTransition);
+
+ if (_globalConf.find(globalState->stateId) != _globalConf.end()) {
+ delete globalState;
+ _perfStatesSkippedTotal++;
+ _perfStatesSkippedProcessed++;
+ continue; // we have already been here
}
- if (actionIter->uninvoke) {
-// DETAIL_EXEC_CONTENT(uninvoke, actionIter);
- Element<std::string> uninvokeElem = _flatDoc.createElementNS(_nsInfo.nsURL, "uninvoke");
- _nsInfo.setPrefix(uninvokeElem);
-
- if (HAS_ATTR(actionIter->uninvoke, "type")) {
- uninvokeElem.setAttribute("type", ATTR(actionIter->uninvoke, "type"));
- }
- if (HAS_ATTR(actionIter->uninvoke, "typeexpr")) {
- uninvokeElem.setAttribute("typeexpr", ATTR(actionIter->uninvoke, "typeexpr"));
- }
- if (HAS_ATTR(actionIter->uninvoke, "id")) {
- uninvokeElem.setAttribute("id", ATTR(actionIter->uninvoke, "id"));
+ _perfStatesProcessed++;
+
+ _configuration = globalState->getActiveStates();
+ _alreadyEntered = globalState->getAlreadyEnteredStates();
+ _historyValue = globalState->getHistoryStates();
+
+ // remember as global configuration
+ _globalConf[globalState->stateId] = globalState;
+ _globalConf[globalState->stateId]->index = _lastStateIndex++;
+
+ if(_globalConf[globalState->stateId]->isFinal)
+ continue; // done in this branch
+
+ if (_transPerActiveConf.find(globalState->activeId) != _transPerActiveConf.end()) {
+ // we already know these transition sets, just copy over
+ std::list<GlobalTransition*>::iterator sortTransIter = _transPerActiveConf[globalState->activeId]->sortedOutgoing.begin();
+ while(sortTransIter != _transPerActiveConf[globalState->activeId]->sortedOutgoing.end()) {
+ globalState->sortedOutgoing.push_back(new GlobalTransition(**sortTransIter)); // copy constructor
+ globalState->sortedOutgoing.back()->index = _lastTransIndex++;
+ sortTransIter++;
}
- if (HAS_ATTR(actionIter->uninvoke, "idlocation")) {
- uninvokeElem.setAttribute("idlocation", ATTR(actionIter->uninvoke, "idlocation"));
- }
- childs.push_back(uninvokeElem);
- continue;
- }
+ _perfStatesCachedTotal++;
+ _perfStatesCachedProcessed++;
- if (actionIter->exited) {
-// std::cerr << " exited(" << ATTR_CAST(actionIter->exited, "id") << ")";
- currActiveStates.remove(ATTR_CAST(actionIter->exited, "id"));
- if (childs.size() > 0) {
- CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates)); // create a new transient state to update its id
+ } else {
+ // we need to calculate the potential optimal transition sets
+ std::map<std::string, GlobalTransition*> transitionSets;
+ getPotentialTransitionsForConf(refsToStates(globalState->activeStatesRefs), transitionSets);
+
+ // TODO: reduce and sort transition sets
+ for(std::map<std::string, GlobalTransition*>::iterator transSetIter = transitionSets.begin();
+ transSetIter != transitionSets.end();
+ transSetIter++) {
+ globalState->sortedOutgoing.push_back(transSetIter->second);
}
+
+ globalState->sortedOutgoing.sort(PtrComp<GlobalTransition>);
+ globalState->sortedOutgoing.unique(hasUnconditionalSuperset);
+ globalState->sortedOutgoing.unique(hasEarlierUnconditionalMatch);
+ // unique is not quite like what we need, but it was a start
+ globalState->sortedOutgoing = reapplyUniquePredicates(globalState->sortedOutgoing);
+
+ _transPerActiveConf[globalState->activeId] = globalState;
}
-
- if (actionIter->entered) {
-// std::cerr << " entered(" << ATTR_CAST(actionIter->entered, "id") << ")";
- if (childs.size() > 0)
- CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates)); // create a new transient state to update its id
- currActiveStates.push_back(ATTR_CAST(actionIter->entered, "id"));
-
- // we entered a new child - check if it has a datamodel and we entered for the first time
- if (_binding == InterpreterImpl::LATE) {
- NodeSet<std::string> datamodel = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", actionIter->entered);
- if (datamodel.size() > 0 && !isMember(actionIter->entered, _globalConf[globalTransition->source]->alreadyEnteredStates)) {
- childs.push_back(datamodel);
+
+ // append resulting new states
+ for(std::list<GlobalTransition*>::iterator transListIter = globalState->sortedOutgoing.begin();
+ transListIter != globalState->sortedOutgoing.end();
+ transListIter++) {
+
+ (*transListIter)->source = globalState->stateId;
+ _currGlobalTransition = *transListIter;
+
+ microstep(refsToTransitions((*transListIter)->transitionRefs));
+ statesRemaining.push_back(new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this));
+
+ // add all invokers
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ invoke(Element<std::string>(invokes[j]));
}
}
- }
- if (!globalTransition->isTargetless) {
-// CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates))
- }
- }
-
-// std::cerr << std::endl;
-
-// if (globalTransition->isTargetless) {
-// for (int i = 0; i < childs.size(); i++) {
-// Node<std::string> imported = _flatDoc.importNode(childs[i], true);
-// transition.appendChild(imported);
-// // CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates))
-// }
-// return transition;
-// }
-
- CREATE_TRANSIENT_STATE_WITH_CHILDS(FlatStateIdentifier::toStateId(currActiveStates))
-
- if (transientStateChain.size() > 0) {
- Element<std::string> prevExitTransitionElem;
-
- for (int i = 0; i < transientStateChain.size(); i++) {
- Element<std::string> transientStateElem = Element<std::string>(transientStateChain[i]);
- transientStateElem.setAttribute("id", transientStateElem.getAttribute("id") + "-via-" + toStr(_lastTransientStateId++));
-
- Element<std::string> exitTransition = _flatDoc.createElementNS(_nsInfo.nsURL, "transition");
- _nsInfo.setPrefix(exitTransition);
-
- if (prevExitTransitionElem) {
- // point previous to this one
- prevExitTransitionElem.setAttribute("target", transientStateElem.getAttribute("id"));
- } else {
- // update globalTransition->source target
- }
+ _statesToInvoke = NodeSet<std::string>();
- transientStateElem.appendChild(exitTransition);
- prevExitTransitionElem = exitTransition;
+ // remember that the last transition lead here
+ (*transListIter)->destination = statesRemaining.back()->stateId;
- if (i == 0)
- transition.setAttribute("target", transientStateElem.getAttribute("id"));
-
- _scxml.appendChild(transientStateElem);
+ // reset state for next transition set
+ _configuration = globalState->getActiveStates();
+ _alreadyEntered = globalState->getAlreadyEnteredStates();
+ _historyValue = globalState->getHistoryStates();
}
-
- // last one points to actual target
- assert(prevExitTransitionElem);
- prevExitTransitionElem.setAttribute("target", globalTransition->destination);
-
- } else {
- transition.setAttribute("target", globalTransition->destination);
}
- assert(HAS_ATTR_CAST(transition, "target"));
- return transition;
}
-#if 0
-void FlatteningInterpreter::weightTransitions() {
- maxDepth = 0;
- maxOrder = 0;
-
- int depth = 0;
- Arabica::XPath::NodeSet<std::string> states = getChildStates(_scxml);
- while(states.size() > 0) {
- NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states);
- NodeSet<std::string> initials = filterChildElements(_nsInfo.xmlNSPrefix + "initial", states);
- transitions.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "transition", initials));
+Arabica::XPath::NodeSet<std::string> ChartToFSM::refsToStates(const std::set<int>& stateRefs) {
+ NodeSet<std::string> states;
+ for (std::set<int>::const_iterator stateIter = stateRefs.begin(); stateIter != stateRefs.end(); stateIter++) {
+ states.push_back(indexedStates[*stateIter]);
+ }
+ return states;
+}
- for (int j = 0; j < transitions.size(); j++) {
- if (depth > maxDepth)
- maxDepth = depth;
- if (j > maxOrder)
- maxOrder = j;
- Element<std::string> transition = Element<std::string>(transitions[j]);
- transition.setAttribute("depth", toStr(depth));
- transition.setAttribute("order", toStr(j));
- }
- depth++;
- states = getChildStates(states);
+Arabica::XPath::NodeSet<std::string> ChartToFSM::refsToTransitions(const std::set<int>& transRefs) {
+ NodeSet<std::string> transitions;
+ for (std::set<int>::const_iterator transIter = transRefs.begin(); transIter != transRefs.end(); transIter++) {
+ transitions.push_back(indexedTransitions[*transIter]);
}
+ return transitions;
}
-#endif
-void FlatteningInterpreter::labelTransitions() {
+
+void ChartToFSM::labelTransitions() {
// put a unique id on each transition
Arabica::XPath::NodeSet<std::string> states = getAllStates();
states.push_back(_scxml);
@@ -1096,39 +826,50 @@ void FlatteningInterpreter::labelTransitions() {
}
}
-void FlatteningInterpreter::beforeMicroStep(Interpreter interpreter) {
+void ChartToFSM::beforeMicroStep(Interpreter interpreter) {
}
-void FlatteningInterpreter::onStableConfiguration(Interpreter interpreter) {
+void ChartToFSM::onStableConfiguration(Interpreter interpreter) {
}
-void FlatteningInterpreter::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
+void ChartToFSM::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
GlobalTransition::Action action;
action.exited = state;
_currGlobalTransition->actions.push_back(action);
- _currGlobalTransition->exited.push_back(state);
}
-void FlatteningInterpreter::beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
+void ChartToFSM::beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
GlobalTransition::Action action;
action.entered = state;
_currGlobalTransition->actions.push_back(action);
- _currGlobalTransition->entered.push_back(state);
}
-void FlatteningInterpreter::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) {
+void ChartToFSM::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) {
}
-int GlobalState::gIndex = 0;
GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeStates_,
const Arabica::XPath::NodeSet<std::string>& alreadyEnteredStates_, // we need to remember for binding=late
const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates_,
- const std::string& xmlNSPrefix) {
+ const std::string& xmlNSPrefix,
+ ChartToFSM* flattener) {
+ interpreter = flattener;
+
+ // take references
+ for (int i = 0; i < activeStates_.size(); i++) {
+ activeStatesRefs.insert(strTo<int>(ATTR_CAST(activeStates_[i], "index")));
+ }
+
+ for (int i = 0; i < alreadyEnteredStates_.size(); i++) {
+ alreadyEnteredStatesRefs.insert(strTo<int>(ATTR_CAST(alreadyEnteredStates_[i], "index")));
+ }
+
+ for (std::map<std::string, Arabica::XPath::NodeSet<std::string> >::const_iterator histIter = historyStates_.begin(); histIter != historyStates_.end(); histIter++) {
+ for (int i = 0; i < histIter->second.size(); i++) {
+ historyStatesRefs[histIter->first].insert(strTo<int>(ATTR_CAST(histIter->second[i], "index")));
+ }
+ }
- // make copies and sort
- activeStates = activeStates_;
- alreadyEnteredStates = alreadyEnteredStates_;
- historyStates = historyStates_;
isFinal = false;
- for(int i = 0; i < activeStates.size(); i++) {
- Arabica::DOM::Element<std::string> state = Arabica::DOM::Element<std::string>(activeStates[i]);
+ // is state this final?
+ for(int i = 0; i < activeStates_.size(); i++) {
+ Arabica::DOM::Element<std::string> state = Arabica::DOM::Element<std::string>(activeStates_[i]);
Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode();
if(InterpreterImpl::isFinal(state) && iequals(parentElem.getTagName(), xmlNSPrefix + "scxml")) {
isFinal = true;
@@ -1136,25 +877,30 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeState
}
}
- // sort configuration
- activeStates.to_document_order();
- alreadyEnteredStates.to_document_order();
- for(std::map<std::string, Arabica::XPath::NodeSet<std::string> >::iterator historyIter = historyStates.begin();
- historyIter != historyStates.end();
- historyIter++) {
- historyIter->second.to_document_order();
- }
-
- FlatStateIdentifier flatStateId(activeStates, alreadyEnteredStates, historyStates);
+ FlatStateIdentifier flatStateId(getActiveStates(), getAlreadyEnteredStates(), getHistoryStates());
stateId = flatStateId.getStateId();
+ activeId = flatStateId.getFlatActive();
}
-GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& transitionSet, DataModel dataModel, FlatteningInterpreter* flattener) {
+GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& transitionSet, DataModel dataModel, ChartToFSM* flattener) {
interpreter = flattener;
- transitions = transitionSet;
+
+ for (int i = 0; i < transitionSet.size(); i++) {
+ transitionRefs.insert(strTo<int>(ATTR_CAST(transitionSet[i], "index")));
+ }
+
+ std::ostringstream setId; // also build id for subset
+ std::string seperator = "";
+ for (std::set<int>::iterator transIter = transitionRefs.begin(); transIter != transitionRefs.end(); transIter++) {
+ setId << seperator << *transIter;
+ seperator = "-";
+ }
+ transitionId = setId.str();
+
+ hasExecutableContent = false;
isValid = true;
isEventless = true;
-
+
#if 0
std::cerr << "################" << std::endl;
for (int i = 0; i < transitions.size(); i++) {
@@ -1163,39 +909,7 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
std::cerr << "################" << std::endl;
#endif
- std::list<std::string> conditions;
- std::ostringstream setId; // also build id for subset
- for (int i = 0; i < transitions.size(); i++) {
- Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitions[i]);
- // get a unique string for the transition - we assume it is sorted
- assert(HAS_ATTR(transElem, "id"));
- setId << ATTR(transElem, "id") << "-";
-
- // gather conditions while we are iterating anyway
- if (HAS_ATTR(transElem, "cond")) {
- conditions.push_back(ATTR(transElem, "cond"));
- }
- }
- transitionId = setId.str();
-
- int index = 0;
- std::string seperator;
- for (std::list<Element<std::string> >::iterator transIter = interpreter->indexedTransitions.begin(); transIter != interpreter->indexedTransitions.end(); transIter++) {
- const Element<std::string>& refTrans = *transIter;
- if (InterpreterImpl::isMember(refTrans, transitions)) {
- members += seperator + toStr(index);
- } else {
- members += seperator;
- for (int i = 0; i < toStr(index).size(); i++) {
- members += " ";
- }
- }
- seperator = " ";
- index++;
- }
-
-// if (members == " 4 6 7 ")
-// std::cout << "asdfadf";
+ // first establish whether this is a valid set
/**
* Can these events event occur together? They can't if:
@@ -1209,8 +923,8 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
bool foundWithTarget = false;
bool foundTargetLess = false;
- for (int i = 0; i < transitions.size(); i++) {
- Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitions[i]);
+ for (int i = 0; i < transitionSet.size(); i++) {
+ Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitionSet[i]);
if (HAS_ATTR(transElem, "eventexpr")) {
ERROR_EXECUTION_THROW("Cannot flatten document with eventexpr attributes");
}
@@ -1253,7 +967,7 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
// is there a set of event names that would enable this conflict-free transition set?
if (foundWithEvent) {
// get the set of longest event descriptors that will enable this transition set
- eventNames = getCommonEvents(transitions);
+ eventNames = getCommonEvents(transitionSet);
if (eventNames.size() == 0) {
// LOG(INFO) << "No event will activate this conflict-free subset" << std::endl;
isValid = false;
@@ -1271,6 +985,35 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
eventDesc = "*";
}
+ // extract conditions
+ std::list<std::string> conditions;
+ for (int i = 0; i < transitionSet.size(); i++) {
+ Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitionSet[i]);
+ // gather conditions while we are iterating anyway
+ if (HAS_ATTR(transElem, "cond")) {
+ conditions.push_back(ATTR(transElem, "cond"));
+ }
+ }
+
+ int index = 0;
+ seperator = "";
+ for (std::vector<Element<std::string> >::iterator transIter = interpreter->indexedTransitions.begin(); transIter != interpreter->indexedTransitions.end(); transIter++) {
+ const Element<std::string>& refTrans = *transIter;
+ if (InterpreterImpl::isMember(refTrans, transitionSet)) {
+ members += seperator + toStr(index);
+ } else {
+ members += seperator;
+ for (int i = 0; i < toStr(index).size(); i++) {
+ members += " ";
+ }
+ }
+ seperator = " ";
+ index++;
+ }
+
+ // if (members == " 4 6 7 ")
+ // std::cout << "asdfadf";
+
if (conditions.size() > 1) {
condition = dataModel.andExpressions(conditions);
if (condition.size() == 0) {
@@ -1281,6 +1024,27 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
}
}
+Arabica::XPath::NodeSet<std::string> GlobalState::getActiveStates() {
+ return interpreter->refsToStates(activeStatesRefs);
+}
+
+Arabica::XPath::NodeSet<std::string> GlobalState::getAlreadyEnteredStates() {
+ return interpreter->refsToStates(alreadyEnteredStatesRefs);
+}
+
+std::map<std::string, Arabica::XPath::NodeSet<std::string> > GlobalState::getHistoryStates() {
+ std::map<std::string, Arabica::XPath::NodeSet<std::string> > historyValue;
+ for (std::map<std::string, std::set<int> >::iterator histIter = historyStatesRefs.begin(); histIter != historyStatesRefs.end(); histIter++) {
+ historyValue[histIter->first] = interpreter->refsToStates(histIter->second);
+ }
+ return historyValue;
+}
+
+
+Arabica::XPath::NodeSet<std::string> GlobalTransition::getTransitions() const {
+ return interpreter->refsToTransitions(transitionRefs);
+}
+
std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::string>& transitions) {
std::list<std::string> prefixes;
std::list<std::string> longestPrefixes;