You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
14 KiB
473 lines
14 KiB
/*
|
|
* This file is part of the program ltl2dstar (http://www.ltl2dstar.de/).
|
|
* Copyright (C) 2005-2007 Joachim Klein <j.klein@ltl2dstar.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
|
|
#ifndef DAUNIONALGORITHM_H
|
|
#define DAUNIONALGORITHM_H
|
|
|
|
#include "NBA2DA.hpp"
|
|
#include "StutteredNBA2DA.hpp"
|
|
|
|
#include <memory>
|
|
|
|
/** @file
|
|
* Provides DAUnionAlgorithm for calculating the union of two DA.
|
|
*/
|
|
|
|
|
|
// TODO: trueloop again
|
|
|
|
|
|
/**
|
|
* Generic dummy UnionAcceptanceCalculator functor.
|
|
* Any specialization should provide (see RabinAcceptance for example):
|
|
* <ul>
|
|
* <li>Constructor taking the acceptance for the two DA</li>
|
|
* <li>prepareAcceptance(&acceptance): prepare the acceptance condition in the result DA</li>
|
|
* <li>calculateAcceptance: calculating the resulting acceptance signature for two states</li>
|
|
* </ul>
|
|
*/
|
|
template <typename Acceptance>
|
|
struct UnionAcceptanceCalculator {
|
|
};
|
|
|
|
|
|
/**
|
|
* Specialized UnionAcceptanceCalculator for RabinAcceptance, for calculating the acceptance in the union automaton.
|
|
* This approach merges the acceptance signatures of the two states in the union tuple, the union is provided by
|
|
* the semantics of the Rabin acceptance condition (There <i>exists</i> an acceptance pair ....)
|
|
*/
|
|
template <>
|
|
struct UnionAcceptanceCalculator<RabinAcceptance> {
|
|
/** RabinAcceptance signature type. */
|
|
typedef RabinAcceptance::signature_type signature_t;
|
|
/** shared_ptr of signature type. */
|
|
typedef std::shared_ptr<signature_t> signature_ptr;
|
|
|
|
/**
|
|
* Constructor.
|
|
* @param acc_1 The RabinAcceptance condition from automaton 1
|
|
* @param acc_2 The RabinAcceptance condition from automaton 2
|
|
*/
|
|
UnionAcceptanceCalculator(RabinAcceptance& acc_1,
|
|
RabinAcceptance& acc_2) :
|
|
_acc_1(acc_1), _acc_2(acc_2) {
|
|
_acc_size_1=_acc_1.size();
|
|
_acc_size_2=_acc_2.size();
|
|
}
|
|
|
|
/**
|
|
* Prepares the acceptance condition in the result union automaton. If the two automata have k1 and k2
|
|
* acceptance pairs, this function allocates k1+k2 acceptance pairs in the result automaton.
|
|
* @param acceptance_result The acceptance condition in the result automaton.
|
|
*/
|
|
void prepareAcceptance(RabinAcceptance& acceptance_result) {
|
|
acceptance_result.newAcceptancePairs(_acc_size_1+_acc_size_2);
|
|
}
|
|
|
|
|
|
/**
|
|
* Calculate the acceptance signature for the union of two states.
|
|
* @param da_state_1 index of the state in the first automaton
|
|
* @param da_state_2 index of the state in the second automaton
|
|
* @return A shared_ptr Rabin acceptance signature
|
|
*/
|
|
signature_ptr calculateAcceptance(unsigned int da_state_1,
|
|
unsigned int da_state_2) {
|
|
signature_ptr signature_p=signature_ptr(new signature_t(_acc_size_1+
|
|
_acc_size_2));
|
|
signature_t& signature=*signature_p;
|
|
|
|
for (unsigned int i=0;
|
|
i<_acc_size_1;
|
|
i++) {
|
|
if (_acc_1.isStateInAcceptance_L(i, da_state_1)) {
|
|
signature.setL(i, true);
|
|
}
|
|
if (_acc_1.isStateInAcceptance_U(i, da_state_1)) {
|
|
signature.setU(i, true);
|
|
}
|
|
}
|
|
|
|
for (unsigned int j=0;
|
|
j<_acc_size_2;
|
|
j++) {
|
|
if (_acc_2.isStateInAcceptance_L(j, da_state_2)) {
|
|
signature.setL(j + _acc_size_1, true);
|
|
}
|
|
if (_acc_2.isStateInAcceptance_U(j, da_state_2)) {
|
|
signature.setU(j + _acc_size_1, true);
|
|
}
|
|
}
|
|
|
|
return signature_p;
|
|
}
|
|
|
|
/** The acceptance condition of the first automaton. */
|
|
RabinAcceptance& _acc_1;
|
|
/** The acceptance condition of the second automaton. */
|
|
RabinAcceptance& _acc_2;
|
|
|
|
/** The size of the acceptance condition in the original automaton. */
|
|
unsigned int _acc_size_1, _acc_size_2;
|
|
};
|
|
|
|
|
|
/**
|
|
* An algorithm calculating the union of two DA. Requires the existance of a UnionAcceptanceCalculator for the
|
|
* AcceptanceCondition.
|
|
* @param DA_t the Deterministic Automaton class.
|
|
*/
|
|
template <typename DA_t>
|
|
class DAUnionAlgorithm {
|
|
public:
|
|
/** shared_ptr for DA_t type*/
|
|
typedef typename std::shared_ptr<DA_t> DA_ptr;
|
|
/** state_type from DA_t */
|
|
typedef typename DA_t::state_type da_state_t;
|
|
/** acceptance condition type from DA_t */
|
|
typedef typename DA_t::acceptance_condition_type da_acceptance_t;
|
|
/** acceptance signature type from DA_t */
|
|
typedef typename da_acceptance_t::signature_type da_signature_t;
|
|
|
|
/** A state representing a union state from two DA. */
|
|
struct UnionState {
|
|
/** Index of the state from the first automaton */
|
|
unsigned int da_state_1;
|
|
/** Index of the state from the second automaton */
|
|
unsigned int da_state_2;
|
|
/** A shared_ptr with the acceptance signature of this state */
|
|
std::shared_ptr<da_signature_t> signature;
|
|
/** A shared_ptr to a string containing a detailed description of this state */
|
|
std::shared_ptr<std::string> description;
|
|
|
|
/** Constructor.
|
|
* @param da_state_1_ index of the state in the first automaton
|
|
* @param da_state_2_ index of the state in the second automaton
|
|
* @param acceptance_calculator UnionAcceptanceCalculator
|
|
*/
|
|
template <typename AcceptanceCalc>
|
|
UnionState(unsigned int da_state_1_,
|
|
unsigned int da_state_2_,
|
|
AcceptanceCalc& acceptance_calculator) :
|
|
da_state_1(da_state_1_), da_state_2(da_state_2_) {
|
|
signature=acceptance_calculator.calculateAcceptance(da_state_1,
|
|
da_state_2);
|
|
}
|
|
|
|
/** Compare this state to another for equality.
|
|
* @param other the other UnionState
|
|
* @returns true iff the two states are equal
|
|
*/
|
|
bool operator==(const UnionState& other) const{
|
|
return (da_state_1==other.da_state_1 &&
|
|
da_state_2==other.da_state_2);
|
|
// we don't have to check the signature as there is a
|
|
// 1-on-1 mapping between <da_state_1, da_state_2> -> signature
|
|
}
|
|
|
|
|
|
/** Compare this state to another for less-than-relationship. Uses the natural order on
|
|
* the two indizes (da_state_1, da_state_2)
|
|
* @param other the other UnionState
|
|
* @returns true iff this state is 'smaller' than the other
|
|
*/
|
|
bool operator<(const UnionState& other) const {
|
|
if (da_state_1<other.da_state_1)
|
|
return true;
|
|
|
|
if (da_state_1==other.da_state_1) {
|
|
return (da_state_2<other.da_state_2);
|
|
// we don't have to check the signature as there is a
|
|
// 1-on-1 mapping between <da_state_1, da_state_2> -> signature
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/** Copy acceptance signature for this state
|
|
* @param acceptance (<b>out</b>) AcceptanceForState for the state in the result automaton
|
|
*/
|
|
void generateAcceptance(typename da_acceptance_t::AcceptanceForState acceptance) const {
|
|
acceptance.setSignature(*signature);
|
|
}
|
|
|
|
/** Copy acceptance signature for this state
|
|
* @param acceptance (<b>out</b>) acceptance signature for the state in the result automaton
|
|
*/
|
|
void generateAcceptance(da_signature_t& acceptance) const {
|
|
acceptance=*signature;
|
|
}
|
|
|
|
/** Return the acceptance acceptance signature for this state
|
|
* @return the acceptance signature for this state
|
|
*/
|
|
const RabinAcceptance::RabinSignature& generateAcceptance() const {
|
|
return *signature;
|
|
}
|
|
|
|
/**
|
|
* Set the detailed description for this state
|
|
* @param description_ the description
|
|
*/
|
|
void setDescription(const std::string& description_) {
|
|
description=std::shared_ptr<std::string>(new std::string(description_));
|
|
}
|
|
|
|
/** Generate a simple representation of this state
|
|
* @return a string with the representation
|
|
*/
|
|
std::string toString() const {
|
|
return "("+boost::lexical_cast<std::string>(da_state_1)+","+boost::lexical_cast<std::string>(da_state_1)+")";
|
|
}
|
|
|
|
/** Return the detailed description
|
|
* @return the detailed description
|
|
*/
|
|
const std::string& toHTML() const {
|
|
if (!description) {
|
|
THROW_EXCEPTION(Exception, "No description");
|
|
} else {
|
|
return *description;
|
|
}
|
|
}
|
|
|
|
/** Calculates the hash for the union state.
|
|
* @param hash the HashFunction functor used for the calculation
|
|
*/
|
|
template <class HashFunction>
|
|
void hashCode(HashFunction& hash) {
|
|
hash.hash(da_state_1);
|
|
hash.hash(da_state_2);
|
|
// we don't have to consider the signature as there is a
|
|
// 1-on-1 mapping between <da_state_1, da_state_2> -> signature
|
|
}
|
|
|
|
};
|
|
/** shared_ptr of UnionState */
|
|
typedef std::shared_ptr<UnionState> UnionState_ptr;
|
|
|
|
/** A simple wrapper for UnionState_Result to accomodate the plugging in with fuzzy matching */
|
|
struct UnionState_Result {
|
|
UnionState_ptr state;
|
|
|
|
UnionState_Result(UnionState_ptr state_) : state(state_) {}
|
|
|
|
UnionState_ptr getState() {
|
|
return state;
|
|
}
|
|
};
|
|
/** shared_ptr for UnionState_Result */
|
|
typedef std::shared_ptr<UnionState_Result> UnionState_Result_ptr;
|
|
|
|
typedef UnionState_Result_ptr result_t;
|
|
typedef UnionState_ptr state_t;
|
|
|
|
|
|
/** Constructor.
|
|
* @param da_1 The first DA
|
|
* @param da_2 the second DA
|
|
* @param trueloop_check Check for trueloops?
|
|
* @param detailed_states Generate detailed descriptions of the states? */
|
|
DAUnionAlgorithm(DA_t& da_1, DA_t& da_2,
|
|
bool trueloop_check=true,
|
|
bool detailed_states=false) :
|
|
_da_1(da_1), _da_2(da_2),
|
|
_acceptance_calculator(da_1.acceptance(), da_2.acceptance()),
|
|
_trueloop_check(trueloop_check),
|
|
_detailed_states(detailed_states) {
|
|
|
|
if (! (_da_1.getAPSet() == _da_2.getAPSet()) ) {
|
|
THROW_EXCEPTION(IllegalArgumentException, "Can't create union of DAs: APSets don't match");
|
|
}
|
|
|
|
APSet_cp combined_ap=da_1.getAPSet_cp();
|
|
|
|
if (!_da_1.isCompact() || !_da_2.isCompact()) {
|
|
THROW_EXCEPTION(IllegalArgumentException, "Can't create union of DAs: Not compact");
|
|
}
|
|
|
|
_result_da=DA_ptr((DA_t*)da_1.createInstance(combined_ap));
|
|
}
|
|
|
|
/** Destructor */
|
|
~DAUnionAlgorithm() {}
|
|
|
|
/** Get the resulting DA
|
|
* @return a shared_ptr to the resulting union DA.
|
|
*/
|
|
DA_ptr getResultDA() {
|
|
return _result_da;
|
|
}
|
|
|
|
/** Calculate the successor state.
|
|
* @param from_state The from state
|
|
* @param elem The edge label
|
|
* @return result_t the shared_ptr of the successor state
|
|
*/
|
|
result_t delta(state_t from_state, APElement elem) {
|
|
da_state_t* state1_to=_da_1[from_state->da_state_1]->edges().get(elem);
|
|
da_state_t* state2_to=_da_2[from_state->da_state_2]->edges().get(elem);
|
|
|
|
UnionState_ptr to=createState(state1_to->getName(),
|
|
state2_to->getName());
|
|
return UnionState_Result_ptr(new UnionState_Result(to));
|
|
}
|
|
|
|
|
|
/** Get the start state.
|
|
* @return a shared_ptr to the start state
|
|
*/
|
|
state_t getStartState() {
|
|
if (_da_1.getStartState()==0 ||
|
|
_da_2.getStartState()==0) {
|
|
THROW_EXCEPTION(IllegalArgumentException, "DA has no start state!");
|
|
}
|
|
|
|
return createState(_da_1.getStartState()->getName(),
|
|
_da_2.getStartState()->getName());
|
|
}
|
|
|
|
/** Prepare the acceptance condition
|
|
* @param acceptance the acceptance condition in the result DA
|
|
*/
|
|
void prepareAcceptance(da_acceptance_t& acceptance) {
|
|
_acceptance_calculator.prepareAcceptance(acceptance);
|
|
}
|
|
|
|
/** Check if the automaton is a-priori empty */
|
|
bool checkEmpty() {
|
|
return false;
|
|
}
|
|
|
|
/** Calculate the union of two DA. If the DAs are not compact, they are made compact.
|
|
* @param da_1 The first DA
|
|
* @param da_2 the second DA
|
|
* @param trueloop_check Check for trueloops?
|
|
* @param detailed_states Generate detailed descriptions of the states?
|
|
* @return shared_ptr to result DA
|
|
*/
|
|
static
|
|
DA_ptr calculateUnion(DA_t& da_1,
|
|
DA_t& da_2,
|
|
bool trueloop_check=true,
|
|
bool detailed_states=false) {
|
|
if (!da_1.isCompact()) {
|
|
da_1.makeCompact();
|
|
}
|
|
|
|
if (!da_2.isCompact()) {
|
|
da_2.makeCompact();
|
|
}
|
|
|
|
typedef DAUnionAlgorithm<DA_t> algo_t;
|
|
algo_t dua(da_1, da_2, trueloop_check, detailed_states);
|
|
|
|
NBA2DA<algo_t, DA_t> generator(detailed_states);
|
|
generator.convert(dua, *dua.getResultDA(), 0);
|
|
|
|
return dua.getResultDA();
|
|
}
|
|
|
|
|
|
/** Calculate the union of two DA, using stuttering if possible. If the DAs are not compact, they are made compact.
|
|
* @param da_1 The first DA
|
|
* @param da_2 the second DA
|
|
* @param stutter_information information about the symbols where stuttering is allowed
|
|
* @param trueloop_check Check for trueloops?
|
|
* @param detailed_states Generate detailed descriptions of the states? */
|
|
static
|
|
DA_ptr calculateUnionStuttered(DA_t& da_1,
|
|
DA_t& da_2,
|
|
StutterSensitivenessInformation::ptr stutter_information,
|
|
bool trueloop_check=true,
|
|
bool detailed_states=false) {
|
|
if (!da_1.isCompact()) {
|
|
da_1.makeCompact();
|
|
}
|
|
|
|
if (!da_2.isCompact()) {
|
|
da_2.makeCompact();
|
|
}
|
|
|
|
typedef DAUnionAlgorithm<DA_t> algo_t;
|
|
algo_t dua(da_1, da_2, trueloop_check, detailed_states);
|
|
|
|
StutteredNBA2DA<algo_t, DA_t> generator(detailed_states, stutter_information);
|
|
generator.convert(dua, *dua.getResultDA(), 0);
|
|
|
|
return dua.getResultDA();
|
|
}
|
|
|
|
private:
|
|
/** The first DA */
|
|
DA_t& _da_1;
|
|
/** The second DA */
|
|
DA_t& _da_2;
|
|
/** The result DA */
|
|
DA_ptr _result_da;
|
|
|
|
/** The acceptance calculator */
|
|
UnionAcceptanceCalculator<da_acceptance_t> _acceptance_calculator;
|
|
|
|
/** Perform trueloop check? */
|
|
bool _trueloop_check;
|
|
/** Generate detailed descriptions? */
|
|
bool _detailed_states;
|
|
|
|
|
|
/** Create a UnionState
|
|
* @param da_state_1
|
|
* @param da_state_2
|
|
* @return the corresponding UnionState
|
|
*/
|
|
UnionState_ptr createState(unsigned int da_state_1,
|
|
unsigned int da_state_2) {
|
|
UnionState_ptr state(new UnionState(da_state_1, da_state_2, _acceptance_calculator));
|
|
|
|
// Generate detailed description
|
|
if (_detailed_states) {
|
|
std::ostringstream s;
|
|
|
|
s << "<TABLE BORDER=\"1\" CELLBORDER=\"0\"><TR><TD>";
|
|
|
|
if (_da_1[da_state_1]->hasDescription()) {
|
|
s << _da_1[da_state_1]->getDescription();
|
|
} else {
|
|
s << da_state_1;
|
|
}
|
|
|
|
s << "</TD><TD>U</TD><TD>";
|
|
|
|
if (_da_2[da_state_2]->hasDescription()) {
|
|
s << _da_2[da_state_2]->getDescription();
|
|
} else {
|
|
s << da_state_2;
|
|
}
|
|
|
|
s << "</TD></TR></TABLE>";
|
|
|
|
state->setDescription(s.str());
|
|
}
|
|
|
|
return state;
|
|
}
|
|
};
|
|
|
|
|
|
#endif
|