blob: 6948f4dd682dac5f74de018a139010b6eebb967d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Created on: 16 juil. 2013
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and implementation
******************************************************************************/
#include "StatemachineReachability.h"
#include <fam/coverage/BaseCoverageFilter.h>
#include <fml/executable/AvmTransition.h>
#include <fml/executable/ExecutableForm.h>
#include <fml/executable/ExecutableQuery.h>
#include <fml/executable/ExecutableSystem.h>
#include <fml/infrastructure/BehavioralPart.h>
#include <fml/workflow/WObject.h>
#include <sew/Configuration.h>
namespace sep
{
/**
* Backward Reachability Analysis
*/
bool StatemachineReachability::computeBackwardReachableComponent(
const Configuration & aConfiguration)
{
avm_size_t currentBackwardDepth = 0;
const Machine * aMachine;
AvmTransition * aCompiledTransition;
InstanceOfMachine * aSourceState;
const TableOfExecutableForm & executables =
aConfiguration.getExecutableSystem().getExecutables();
ListOfExecutableForm listOfTreatedStates;
TableOfExecutableForm::const_raw_iterator itExec = executables.begin();
TableOfExecutableForm::const_raw_iterator endExec = executables.end();
if( mBackwardAnalysisLookaheadDepth >= 1 )
{
ExecutableQuery XQuery( aConfiguration );
// Pour tous les états itExec
// on rajoute les transitions immédiatement entrantes dans BackwardReachableTransition
for( ; itExec != endExec ; ++itExec )
{
if( (itExec)->hasPrototypeInstance() )
{
aMachine = (itExec)->getAstMachine();
if( aMachine->hasIncomingTransition() )
{
// Pour l'état itExec on rajoute :
// - les transitions entrantes à la liste des BackwardReachableTransition
// - les états sources des transitions entrantes à la liste des BackwardReachableMachine
//
BehavioralPart::const_transition_iterator itTransition =
aMachine->getBehavior()->incoming_transition_begin();
BehavioralPart::const_transition_iterator endTransition =
aMachine->getBehavior()->incoming_transition_end();
for( ; itTransition != endTransition ; ++itTransition )
{
aCompiledTransition = XQuery.getTransitionByAstElement(
(itTransition) ).to_ptr< AvmTransition >();
(itExec)->addBackwardReachableTransition( aCompiledTransition );
aSourceState = aCompiledTransition->
getExecutableContainer()->getPrototypeInstance();
if( (aSourceState != NULL)
&& ((itExec) != aSourceState->getExecutable())
&& (not (itExec)->getBackwardReachableMachine().
contains( aSourceState )) )
{
(itExec)->addBackwardReachableMachine( aSourceState );
}
}
}
}
}
currentBackwardDepth = 1;
}
if( mBackwardAnalysisLookaheadDepth > currentBackwardDepth )
{
// Pour tous les états itExec, on ajoute par récursivité :
// - les transitions arrières non directement entrantes
// dans BackwardReachableTransition
// - les états sources de toutes les transitions arrières
// non directement entrantes dans BackwardReachableMachine
//
for( itExec = executables.begin() ; itExec != endExec ; ++itExec )
{
if( (itExec)->hasPrototypeInstance() )
{
computeBackwardReachableComponent( aConfiguration,
(itExec), listOfTreatedStates, currentBackwardDepth );
}
}
}
// Pour tous les états itExec :
// élimination de l'état itExec dans la liste BackwardReachableMachine
//
for( itExec = executables.begin() ; itExec != endExec ; ++itExec )
{
if( (itExec)->hasPrototypeInstance() )
{
if( (itExec)->getBackwardReachableMachine().nonempty() )
{
(itExec)->removeBackwardReachableMachine(
(itExec)->getPrototypeInstance() );
}
if( (itExec)->hasTransition()
&& (not (itExec)->getSpecifier().
isPseudostateInitialOrStateStart())
&& (not (itExec)->hasBackwardReachableMachine()) )
{
(itExec)->setReachableState( false );
}
}
}
// Affichage du résultat dans le fichier trace
//
AVM_IF_DEBUG_LEVEL_FLAG2( MEDIUM , PROCESSOR , CONFIGURING )
AVM_OS_TRACE << AVM_TAB1_INDENT;
for( itExec = executables.begin() ; itExec != endExec ; ++itExec )
{
if( (itExec)->hasPrototypeInstance() )
{
AVM_OS_TRACE << "Statemachine Reachability:> "
"compute backward reachable state/transition"
<< std::endl
<< TAB << "state :> "
<< (itExec)->getFullyQualifiedNameID()
<< std::endl
<< "nb backward states :> "
<< (itExec)->getBackwardReachableMachine().size()
<< std::endl
<< "nb backward transitions :> "
<< (itExec)->getBackwardReachableTransition().size()
<< std::endl;
AVM_IF_DEBUG_LEVEL_GTE_HIGH
ListOfInstanceOfMachine::iterator itState =
(itExec)->getBackwardReachableMachine().begin();
ListOfInstanceOfMachine::iterator endState =
(itExec)->getBackwardReachableMachine().end();
for( ; itState != endState ; ++itState )
{
AVM_OS_TRACE << TAB2 << "backward state :> "
<< (* itState)->getFullyQualifiedNameID()
<< std::endl;
}
AVM_ENDIF_DEBUG_LEVEL_GTE_HIGH
AVM_IF_DEBUG_LEVEL_FLAG( HIGH , TRANSITION )
ListOfAvmTransition::iterator itTransition =
(itExec)->getBackwardReachableTransition().begin();
ListOfAvmTransition::iterator endTransition =
(itExec)->getBackwardReachableTransition().end();
for( ; itTransition != endTransition ; ++itTransition )
{
AVM_OS_TRACE << TAB2 << "backward transition :> "
<< (* itTransition)->getFullyQualifiedNameID()
<< std::endl;
}
AVM_ENDIF_DEBUG_LEVEL_FLAG( HIGH , TRANSITION )
}
}
AVM_OS_TRACE << END_INDENT;
AVM_ENDIF_DEBUG_LEVEL_FLAG2( MEDIUM , PROCESSOR , CONFIGURING )
return( true );
}
void StatemachineReachability::computeBackwardReachableComponent(
const Configuration & aConfiguration, ExecutableForm * aState,
ListOfExecutableForm & aListOfTreatedStates,
avm_size_t theCurrentBackwardDepth)
{
//AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
// AVM_OS_TRACE << "\t" << "state :> " << aState->getFullyQualifiedNameID()
// << std::endl;
//AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
AvmTransition * aCompiledTransition;
ExecutableForm * aSourceState;
ExecutableForm * aContainerState;
const Machine * aMachine = aState->getAstMachine();
if( aMachine->hasIncomingTransition() )
{
ExecutableQuery XQuery( aConfiguration );
theCurrentBackwardDepth += 1;
// Pour chaque transition entrante
BehavioralPart::const_transition_iterator itTransition =
aMachine->getBehavior()->incoming_transition_begin();
BehavioralPart::const_transition_iterator endTransition =
aMachine->getBehavior()->incoming_transition_end();
for( ; itTransition != endTransition ; ++itTransition )
{
aCompiledTransition = XQuery.getTransitionByAstElement(
(itTransition) ).to_ptr< AvmTransition >();
aSourceState = aCompiledTransition->getExecutableContainer();
if( aSourceState->getSpecifier().
isPseudostateInitialOrStateStart() )
{
aContainerState = aSourceState->getExecutableContainer();
if( not aListOfTreatedStates.contains( aContainerState ) )
{
aListOfTreatedStates.append( aContainerState );
if( mBackwardAnalysisLookaheadDepth > theCurrentBackwardDepth )
{
computeBackwardReachableComponent(
aConfiguration, aContainerState,
aListOfTreatedStates, theCurrentBackwardDepth );
}
//AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
// AVM_OS_TRACE << "\t" << "aContainerState :> "
// << aContainerState->getFullyQualifiedNameID() << std::endl;
//AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
}
aState->addBackwardReachableTransition(
aContainerState->getBackwardReachableTransition() );
aState->addBackwardReachableMachine(
aContainerState->getBackwardReachableMachine() );
}
else
{
if( not aListOfTreatedStates.contains( aSourceState ) )
{
aListOfTreatedStates.append( aSourceState );
if( mBackwardAnalysisLookaheadDepth > theCurrentBackwardDepth )
{
computeBackwardReachableComponent(
aConfiguration, aSourceState,
aListOfTreatedStates, theCurrentBackwardDepth );
}
//AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
// AVM_OS_TRACE << "\t" << "aSourceState :> "
// << aSourceState->getFullyQualifiedNameID() << std::endl;
//AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , PROCESSOR )
}
aState->addBackwardReachableTransition(
aSourceState->getBackwardReachableTransition() );
aState->addBackwardReachableMachine(
aSourceState->getBackwardReachableMachine() );
}
}
}
}
/**
* Forward Reachability Analysis
*/
bool StatemachineReachability::computeForwardReachableComponent(
const Configuration & aConfiguration)
{
const TableOfExecutableForm & executables =
aConfiguration.getExecutableSystem().getExecutables();
ListOfInstanceOfMachine::iterator itMachine;
ListOfInstanceOfMachine::iterator endMachine;
TableOfExecutableForm::const_raw_iterator itExec = executables.begin();
TableOfExecutableForm::const_raw_iterator endExec = executables.end();
for( ; itExec != endExec ; ++itExec )
{
if( (itExec)->getSpecifier().
isPseudostateInitialOrStateStart() )
{
ListOfExecutableForm aTraceMachine( (itExec) );
computeForwardReachableComponent(
(itExec), aTraceMachine, (itExec));
itMachine = (itExec)->getForwardReachableMachine().begin();
endMachine = (itExec)->getForwardReachableMachine().end();
for( ; itMachine != endMachine ; ++itMachine )
{
if( (*itMachine) != NULL )
{
ListOfExecutableForm newTraceMachine(
(*itMachine)->getExecutable() );
computeForwardReachableComponent(
(*itMachine)->getExecutable(),
newTraceMachine, (*itMachine)->getExecutable());
}
}
}
}
for( itExec = executables.begin() ; itExec != endExec ; ++itExec )
{
if( (itExec)->getForwardReachableMachine().nonempty() &&
(itExec)->hasPrototypeInstance() )
{
(itExec)->removeForwardReachableMachine(
(itExec)->getPrototypeInstance() );
}
}
return( true );
}
void StatemachineReachability::computeForwardReachableComponent(
ExecutableForm * execMachine,
ListOfExecutableForm & aTraceMachine, ExecutableForm * fwdMachine)
{
ListOfAvmTransition listOfOutgoingTransition;
fwdMachine->getOutgoingTransition( listOfOutgoingTransition );
ListOfInstanceOfMachine listOfOutgoingMachine;
fwdMachine->getOutgoingMachine( listOfOutgoingMachine );
execMachine->addForwardReachableMachine(listOfOutgoingMachine);
execMachine->addForwardReachableTransition(listOfOutgoingTransition);
ListOfInstanceOfMachine::iterator itOutgoing = listOfOutgoingMachine.begin();
ListOfInstanceOfMachine::iterator endOutgoing = listOfOutgoingMachine.end();
for( ; itOutgoing != endOutgoing ; ++itOutgoing )
{
if( not aTraceMachine.contains( (*itOutgoing)->getExecutable() ) )
{
ListOfExecutableForm newTraceMachine( aTraceMachine );
newTraceMachine.append( (*itOutgoing)->getExecutable() );
computeForwardReachableComponent(execMachine,
newTraceMachine, (*itOutgoing)->getExecutable());
}
}
}
} /* namespace sep */