forq: fix Buchi acceptance test
* spot/twa/twa.cc: Here. * spot/twaalgos/forq_contains.cc: And there. Also simplify the handling code by simply throwing the exception when the error is detected.
This commit is contained in:
parent
28a6471efb
commit
3861c04581
2 changed files with 28 additions and 138 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2011, 2014-2019, 2021, 2022 Laboratoire de Recherche et
|
// Copyright (C) 2011, 2014-2019, 2021, 2022, 2023 Laboratoire de Recherche et
|
||||||
// Developpement de l'EPITA (LRDE).
|
// Developpement de l'EPITA (LRDE).
|
||||||
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
|
@ -229,12 +229,6 @@ namespace spot
|
||||||
return b->intersecting_run(complement(ensure_graph(a)));
|
return b->intersecting_run(complement(ensure_graph(a)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
is_buchi_automata(const_twa_graph_ptr const& aut)
|
|
||||||
{
|
|
||||||
return spot::acc_cond::acc_code::buchi() == aut->get_acceptance();
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_word_ptr
|
twa_word_ptr
|
||||||
twa::exclusive_word(const_twa_ptr other) const
|
twa::exclusive_word(const_twa_ptr other) const
|
||||||
{
|
{
|
||||||
|
|
@ -256,19 +250,18 @@ namespace spot
|
||||||
}();
|
}();
|
||||||
|
|
||||||
// We have to find a word in A\B or in B\A. When possible, let's
|
// We have to find a word in A\B or in B\A. When possible, let's
|
||||||
// make sure the first automaton we complement is deterministic.
|
// make sure the first automaton we complement, i.e., b, is deterministic.
|
||||||
auto a_twa_as_graph = std::dynamic_pointer_cast<const twa_graph>(a);
|
auto a_twa_as_graph = std::dynamic_pointer_cast<const twa_graph>(a);
|
||||||
auto b_twa_as_graph = std::dynamic_pointer_cast<const twa_graph>(a);
|
auto b_twa_as_graph = std::dynamic_pointer_cast<const twa_graph>(b);
|
||||||
if (a_twa_as_graph)
|
if (a_twa_as_graph)
|
||||||
if (is_deterministic(a_twa_as_graph))
|
if (is_deterministic(a_twa_as_graph))
|
||||||
std::swap(a, b);
|
std::swap(a, b);
|
||||||
|
|
||||||
bool uses_buchi = is_buchi_automata(a_twa_as_graph)
|
|
||||||
&& is_buchi_automata(b_twa_as_graph);
|
|
||||||
if (containment == containment_type::FORQ
|
if (containment == containment_type::FORQ
|
||||||
&& uses_buchi
|
|
||||||
&& a_twa_as_graph
|
&& a_twa_as_graph
|
||||||
&& b_twa_as_graph)
|
&& b_twa_as_graph
|
||||||
|
&& a_twa_as_graph->acc().is_buchi()
|
||||||
|
&& b_twa_as_graph->acc().is_buchi())
|
||||||
{
|
{
|
||||||
if (auto word = difference_word_forq(a_twa_as_graph, b_twa_as_graph))
|
if (auto word = difference_word_forq(a_twa_as_graph, b_twa_as_graph))
|
||||||
return word;
|
return word;
|
||||||
|
|
|
||||||
|
|
@ -19,25 +19,19 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <spot/twaalgos/split.hh>
|
#include <spot/twaalgos/split.hh>
|
||||||
#include "forq_contains.hh"
|
#include <spot/twaalgos/forq_contains.hh>
|
||||||
|
|
||||||
#include <spot/twaalgos/complement.hh>
|
|
||||||
#include <spot/twaalgos/contains.hh>
|
#include <spot/twaalgos/contains.hh>
|
||||||
#include <spot/twaalgos/contains.hh>
|
|
||||||
#include <spot/twaalgos/product.hh>
|
|
||||||
#include <spot/twaalgos/product.hh>
|
#include <spot/twaalgos/product.hh>
|
||||||
#include <spot/twaalgos/word.hh>
|
#include <spot/twaalgos/word.hh>
|
||||||
#include <spot/twaalgos/hoa.hh>
|
|
||||||
#include <spot/misc/bddlt.hh>
|
#include <spot/misc/bddlt.hh>
|
||||||
#include <spot/twa/twagraph.hh>
|
#include <spot/twa/twagraph.hh>
|
||||||
#include <spot/twa/bddprint.hh>
|
|
||||||
#include <spot/twa/bdddict.hh>
|
#include <spot/twa/bdddict.hh>
|
||||||
#include <spot/misc/bddlt.hh>
|
#include <spot/misc/bddlt.hh>
|
||||||
#include <spot/twa/twa.hh>
|
#include <spot/twa/twa.hh>
|
||||||
#include <spot/twa/acc.hh>
|
#include <spot/twa/acc.hh>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <type_traits>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -522,96 +516,6 @@ namespace spot::forq
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class forq_status
|
|
||||||
{
|
|
||||||
FORQ_OKAY, // The forq works as expected
|
|
||||||
FORQ_INVALID_AC_COND, // The automata passed do not
|
|
||||||
// use buchi acceptance conditions
|
|
||||||
FORQ_INCOMPATIBLE_DICTS, // The two automata are using
|
|
||||||
// different bdd_dict objects
|
|
||||||
FORQ_INCOMPATIBLE_AP, // The two automata are using
|
|
||||||
// different atomic propositions
|
|
||||||
FORQ_INVALID_INPUT_BA, // The two automata passed are
|
|
||||||
// nullptrs and are invalid
|
|
||||||
FORQ_INVALID_RESULT_PTR // The pointer forq_result, that
|
|
||||||
// was passed into function
|
|
||||||
// contains_forq, cannot be nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
struct forq_result
|
|
||||||
{
|
|
||||||
// Whether language of graph A is included in B
|
|
||||||
bool included;
|
|
||||||
// If the language of graph A is not included in B,
|
|
||||||
// a counter example is provided
|
|
||||||
spot::twa_word_ptr counter_example;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns a human-readable string given a forq_status,
|
|
||||||
// which can be aquired through a call to contains_forq
|
|
||||||
static const char* forq_status_message(forq_status status)
|
|
||||||
{
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case forq_status::FORQ_OKAY:
|
|
||||||
return "Forq was able to properly run on the two buchi automata.";
|
|
||||||
case forq_status::FORQ_INVALID_AC_COND:
|
|
||||||
return "Forq only operates on automata with buchi "
|
|
||||||
"acceptance conditions.";
|
|
||||||
case forq_status::FORQ_INCOMPATIBLE_DICTS:
|
|
||||||
return "The two input graphs must utilize the same twa_dict.";
|
|
||||||
case forq_status::FORQ_INCOMPATIBLE_AP:
|
|
||||||
return "The two input graphs must utilize the same set of atomic"
|
|
||||||
"propositions defined in their shared twa_dict.";
|
|
||||||
case forq_status::FORQ_INVALID_INPUT_BA:
|
|
||||||
return "One of the two buchi automata passed in was a nullptr.";
|
|
||||||
case forq_status::FORQ_INVALID_RESULT_PTR:
|
|
||||||
return "The result pointer passed in was a nullptr.";
|
|
||||||
default:
|
|
||||||
return "Unknown Forq Status Code.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static forq_status valid_automata(const_graph const& A,
|
|
||||||
const_graph const& B,
|
|
||||||
forq_result* result)
|
|
||||||
{
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
return forq_status::FORQ_INVALID_RESULT_PTR;
|
|
||||||
}
|
|
||||||
if (!A || !B)
|
|
||||||
{
|
|
||||||
return forq_status::FORQ_INVALID_INPUT_BA;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto buchi_acceptance = spot::acc_cond::acc_code::buchi();
|
|
||||||
auto accept_A = A->get_acceptance();
|
|
||||||
auto accept_B = B->get_acceptance();
|
|
||||||
|
|
||||||
if (accept_A != buchi_acceptance || accept_B != buchi_acceptance)
|
|
||||||
{
|
|
||||||
return forq_status::FORQ_INVALID_AC_COND;
|
|
||||||
}
|
|
||||||
if (A->get_dict() != B->get_dict())
|
|
||||||
{
|
|
||||||
return forq_status::FORQ_INCOMPATIBLE_DICTS;
|
|
||||||
}
|
|
||||||
if (A->ap() != B->ap())
|
|
||||||
{
|
|
||||||
return forq_status::FORQ_INCOMPATIBLE_AP;
|
|
||||||
}
|
|
||||||
return forq_status::FORQ_OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
static forq_status create_result(forq_result* result,
|
|
||||||
spot::twa_word_ptr counter_example = nullptr)
|
|
||||||
{
|
|
||||||
result->included = static_cast<bool>(counter_example);
|
|
||||||
result->counter_example = std::move(counter_example);
|
|
||||||
return forq_status::FORQ_OKAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct forq_setup
|
struct forq_setup
|
||||||
{
|
{
|
||||||
forq::forq_context context;
|
forq::forq_context context;
|
||||||
|
|
@ -707,32 +611,11 @@ namespace spot::forq
|
||||||
word_of_v,
|
word_of_v,
|
||||||
setup);
|
setup);
|
||||||
if (counter_example)
|
if (counter_example)
|
||||||
{
|
|
||||||
return final_state_result::failure(std::move(counter_example));
|
return final_state_result::failure(std::move(counter_example));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return final_state_result::success();
|
return final_state_result::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
static forq_status forq_impl(const_graph const& A,
|
|
||||||
const_graph const& B, forq_result* result)
|
|
||||||
{
|
|
||||||
if (auto rc = valid_automata(A, B, result); rc != forq_status::FORQ_OKAY)
|
|
||||||
{
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
forq_setup setup = create_forq_setup(A, B);
|
|
||||||
|
|
||||||
for (auto src : util::get_final_states(A))
|
|
||||||
{
|
|
||||||
auto final_state_result = run_from_final_state(src, setup);
|
|
||||||
if (!final_state_result.should_continue()){
|
|
||||||
return create_result(result, final_state_result.get_counter_example());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return create_result(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
|
|
@ -740,13 +623,27 @@ namespace spot
|
||||||
twa_word_ptr difference_word_forq(forq::const_graph lhs,
|
twa_word_ptr difference_word_forq(forq::const_graph lhs,
|
||||||
forq::const_graph rhs)
|
forq::const_graph rhs)
|
||||||
{
|
{
|
||||||
forq::forq_result result;
|
if (!lhs || !rhs)
|
||||||
auto rc = forq::forq_impl(lhs, rhs, &result);
|
throw std::runtime_error("One of the two automata passed was a nullptr.");
|
||||||
if (rc != forq::forq_status::FORQ_OKAY)
|
if (!lhs->acc().is_buchi() || !rhs->acc().is_buchi())
|
||||||
|
throw std::runtime_error("Forq only operates on automata with Büchi "
|
||||||
|
"acceptance conditions.");
|
||||||
|
if (lhs->get_dict() != rhs->get_dict())
|
||||||
|
throw std::runtime_error
|
||||||
|
("The two input graphs must utilize the same twa_dict.");
|
||||||
|
if (lhs->ap() != rhs->ap())
|
||||||
|
throw std::runtime_error("The two input graphs must use the same set "
|
||||||
|
"of APs");
|
||||||
|
|
||||||
|
forq::forq_setup setup = forq::create_forq_setup(lhs, rhs);
|
||||||
|
|
||||||
|
for (auto src: forq::util::get_final_states(lhs))
|
||||||
{
|
{
|
||||||
throw std::runtime_error(forq::forq_status_message(rc));
|
auto final_state_result = forq::run_from_final_state(src, setup);
|
||||||
|
if (!final_state_result.should_continue())
|
||||||
|
return final_state_result.get_counter_example();
|
||||||
}
|
}
|
||||||
return result.counter_example;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains_forq(forq::const_graph lhs, forq::const_graph rhs)
|
bool contains_forq(forq::const_graph lhs, forq::const_graph rhs)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue