add ltlsynt executable
For now, ltlsynt only handles LTL realizability. It uses a reduction to parity game followed by Calude et al.'s reduction from parity game to reachability game. * bin/ltlsynt.cc, bin/Makefile.am, bin/man/ltlsynt.x, bin/man/Makefile.am, bin/.gitignore: New binary. * doc/org/arch.tex, doc/Makefile.am, doc/org/tools.org, doc/org/ltlsynt.org: Document it. * spot/misc/game.cc, spot/misc/game.hh, spot/misc/Makefile.am: Parity game wrapper for parity automata + reachability game interface from Calude et al.'s paper.
This commit is contained in:
parent
7a11842613
commit
0821c97eb8
13 changed files with 812 additions and 4 deletions
270
spot/misc/game.hh
Normal file
270
spot/misc/game.hh
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2017 Laboratoire de Recherche et Développement
|
||||
// de l'Epita (LRDE).
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
// Spot is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Spot 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include <bddx.h>
|
||||
#include <spot/twa/twagraph.hh>
|
||||
#include <spot/twaalgos/parity.hh>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
||||
class SPOT_API parity_game
|
||||
{
|
||||
private:
|
||||
const const_twa_graph_ptr dpa_;
|
||||
const std::vector<bool> owner_;
|
||||
|
||||
public:
|
||||
/// \a parity_game provides an interface to manipulate a deterministic parity
|
||||
/// automaton as a parity game, including methods to solve the game.
|
||||
///
|
||||
/// \param dpa the underlying deterministic parity automaton
|
||||
/// \param owner a vector of Booleans indicating the owner of each state,
|
||||
/// with the convention that true represents player 1 and false represents
|
||||
/// player 0.
|
||||
parity_game(const twa_graph_ptr dpa, std::vector<bool> owner)
|
||||
: dpa_(dpa), owner_(owner)
|
||||
{
|
||||
bool max;
|
||||
bool odd;
|
||||
dpa_->acc().is_parity(max, odd, true);
|
||||
SPOT_ASSERT(max && odd);
|
||||
SPOT_ASSERT(owner_.size() == dpa_->num_states());
|
||||
}
|
||||
|
||||
unsigned num_states() const
|
||||
{
|
||||
return dpa_->num_states();
|
||||
}
|
||||
|
||||
unsigned get_init_state_number() const
|
||||
{
|
||||
return dpa_->get_init_state_number();
|
||||
}
|
||||
|
||||
internal::state_out<const twa_graph::graph_t>
|
||||
out(unsigned src) const
|
||||
{
|
||||
return dpa_->out(src);
|
||||
}
|
||||
|
||||
internal::state_out<const twa_graph::graph_t>
|
||||
out(unsigned src)
|
||||
{
|
||||
return dpa_->out(src);
|
||||
}
|
||||
|
||||
bool owner(unsigned src) const
|
||||
{
|
||||
return owner_[src];
|
||||
}
|
||||
|
||||
/// Print the parity game in PGSolver's format.
|
||||
void print(std::ostream& os);
|
||||
|
||||
/// Whether player 1 has a winning strategy from the initial state.
|
||||
/// Implements Calude et al.'s quasipolynomial time algorithm.
|
||||
/** \verbatim
|
||||
@inproceedings{calude.17.stoc,
|
||||
author = {Calude, Cristian S. and Jain, Sanjay and Khoussainov,
|
||||
Bakhadyr and Li, Wei and Stephan, Frank},
|
||||
title = {Deciding Parity Games in Quasipolynomial Time},
|
||||
booktitle = {Proceedings of the 49th Annual ACM SIGACT Symposium on
|
||||
Theory of Computing},
|
||||
series = {STOC 2017},
|
||||
year = {2017},
|
||||
isbn = {978-1-4503-4528-6},
|
||||
location = {Montreal, Canada},
|
||||
pages = {252--263},
|
||||
numpages = {12},
|
||||
url = {http://doi.acm.org/10.1145/3055399.3055409},
|
||||
doi = {10.1145/3055399.3055409},
|
||||
acmid = {3055409},
|
||||
publisher = {ACM},
|
||||
address = {New York, NY, USA},
|
||||
keywords = {Muller Games, Parity Games, Quasipolynomial Time Algorithm},
|
||||
}
|
||||
\endverbatim */
|
||||
bool solve_qp() const;
|
||||
};
|
||||
|
||||
|
||||
class reachability_state: public state
|
||||
{
|
||||
private:
|
||||
unsigned num_;
|
||||
std::vector<unsigned> b_;
|
||||
bool anke_;
|
||||
|
||||
public:
|
||||
reachability_state(unsigned state, const std::vector<unsigned>& b,
|
||||
bool anke)
|
||||
: num_(state), b_(b), anke_(anke)
|
||||
{
|
||||
}
|
||||
|
||||
int compare(const state* other) const override;
|
||||
|
||||
bool operator==(const reachability_state& o) const
|
||||
{
|
||||
return compare(&o) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const reachability_state& o) const
|
||||
{
|
||||
return compare(&o) != 0;
|
||||
}
|
||||
|
||||
bool operator<(const reachability_state& o) const;
|
||||
|
||||
size_t hash() const override
|
||||
{
|
||||
size_t hash = wang32_hash(num_);
|
||||
for (unsigned i = 0; i < b_.size(); ++i)
|
||||
hash ^= wang32_hash(b_[i]) ^ wang32_hash(i);
|
||||
return hash;
|
||||
}
|
||||
|
||||
reachability_state* clone() const override
|
||||
{
|
||||
return new reachability_state(*this);
|
||||
}
|
||||
|
||||
std::vector<unsigned> b() const
|
||||
{
|
||||
return b_;
|
||||
}
|
||||
|
||||
unsigned num() const
|
||||
{
|
||||
return num_;
|
||||
}
|
||||
|
||||
bool anke() const
|
||||
{
|
||||
return anke_;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const reachability_state>
|
||||
const_reachability_state_ptr;
|
||||
|
||||
struct reachability_state_hash
|
||||
{
|
||||
size_t operator()(const reachability_state& state) const
|
||||
{
|
||||
return state.hash();
|
||||
}
|
||||
};
|
||||
|
||||
class reachability_game_succ_iterator final: public twa_succ_iterator
|
||||
{
|
||||
private:
|
||||
const parity_game& pg_;
|
||||
const reachability_state& state_;
|
||||
internal::edge_iterator<const twa_graph::graph_t> it_;
|
||||
|
||||
public:
|
||||
reachability_game_succ_iterator(const parity_game& pg,
|
||||
const reachability_state& s)
|
||||
: pg_(pg), state_(s)
|
||||
{
|
||||
}
|
||||
|
||||
bool first() override
|
||||
{
|
||||
it_ = pg_.out(state_.num()).begin();
|
||||
return it_ != pg_.out(state_.num()).end();
|
||||
}
|
||||
|
||||
bool next() override
|
||||
{
|
||||
++it_;
|
||||
return it_ != pg_.out(state_.num()).end();
|
||||
}
|
||||
|
||||
bool done() const override
|
||||
{
|
||||
return it_ == pg_.out(state_.num()).end();
|
||||
}
|
||||
|
||||
const reachability_state* dst() const override;
|
||||
|
||||
bdd cond() const override
|
||||
{
|
||||
return bddtrue;
|
||||
}
|
||||
|
||||
acc_cond::mark_t acc() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// On-the-fly reachability game interface for a max even parity game such
|
||||
// that a target is reachable iff there is a memoryless winning strategy
|
||||
// in the parity game for player 1.
|
||||
class reachability_game final: public twa
|
||||
{
|
||||
private:
|
||||
typedef std::unordered_map<spot::reachability_state, unsigned,
|
||||
spot::reachability_state_hash> wincount_t;
|
||||
typedef std::unordered_map<spot::reachability_state,
|
||||
std::vector<spot::reachability_state>,
|
||||
spot::reachability_state_hash> parents_t;
|
||||
|
||||
const parity_game& pg_;
|
||||
// number of successors that need to have a winning strategy in order for
|
||||
// a given node to have a winning strategy.
|
||||
wincount_t c_;
|
||||
parents_t parents_;
|
||||
const_reachability_state_ptr init_state_; // cache
|
||||
|
||||
public:
|
||||
|
||||
reachability_game(const parity_game& pg)
|
||||
: twa(std::make_shared<bdd_dict>()),
|
||||
pg_(pg)
|
||||
{
|
||||
init_state_ = std::shared_ptr<const reachability_state>(get_init_state());
|
||||
}
|
||||
|
||||
const reachability_state* get_init_state() const override;
|
||||
|
||||
reachability_game_succ_iterator* succ_iter(const state* s) const override;
|
||||
|
||||
std::string format_state(const state* s) const override;
|
||||
|
||||
bool is_reachable();
|
||||
|
||||
private:
|
||||
bool mark(const spot::reachability_state& s);
|
||||
|
||||
bool is_target(const reachability_state& s);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue