spot/src/ltlast/unop.cc
Alexandre Duret-Lutz 8d947a8782 ltl: get rid of ltl::ref_formula
Instead, manage all reference counting from ltl::formula.
It ridance of virtual calls to clone() and destroy() easily compensate
the extra test in destroy() to not delete constant nodes.

* src/ltlast/refformula.cc, src/ltlast/refformula.hh: Delete.
* src/ltlast/Makefile.am, wrap/python/spot.i: Adjust.
* src/ltlast/atomic_prop.cc, src/ltlast/atomic_prop.hh,
src/ltlast/binop.cc, src/ltlast/binop.hh, src/ltlast/bunop.cc,
src/ltlast/bunop.hh, src/ltlast/formula.cc, src/ltlast/formula.hh,
src/ltlast/multop.cc, src/ltlast/multop.hh, src/ltlast/unop.cc,
src/ltlast/unop.hh: Ajust the reference counting code.
2014-10-25 17:06:45 +02:00

336 lines
8.1 KiB
C++

// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie.
//
// 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/>.
#include "config.h"
#include "unop.hh"
#include "visitor.hh"
#include <cassert>
#include <cstddef>
#include <iostream>
#include "constant.hh"
#include "atomic_prop.hh"
#include "bunop.hh"
namespace spot
{
namespace ltl
{
unop::unop(type op, const formula* child)
: formula(UnOp), op_(op), child_(child)
{
props = child->get_props();
switch (op)
{
case Not:
is.not_marked = true;
is.eventual = child->is_universal();
is.universal = child->is_eventual();
is.in_nenoform = (child->kind() == AtomicProp);
is.sere_formula = is.boolean;
is.syntactic_safety = child->is_syntactic_guarantee();
is.syntactic_guarantee = child->is_syntactic_safety();
// is.syntactic_obligation inherited from child
is.syntactic_recurrence = child->is_syntactic_persistence();
is.syntactic_persistence = child->is_syntactic_recurrence();
is.accepting_eword = false;
break;
case X:
is.not_marked = true;
is.boolean = false;
is.X_free = false;
is.eltl_formula = false;
is.sere_formula = false;
// is.syntactic_safety inherited
// is.syntactic_guarantee inherited
// is.syntactic_obligation inherited
// is.syntactic_recurrence inherited
// is.syntactic_persistence inherited
is.accepting_eword = false;
break;
case F:
is.not_marked = true;
is.boolean = false;
is.eltl_formula = false;
is.sere_formula = false;
is.finite = false;
is.sugar_free_ltl = false;
is.eventual = true;
is.syntactic_safety = false;
// is.syntactic_guarantee inherited
is.syntactic_obligation = is.syntactic_guarantee;
is.syntactic_recurrence = is.syntactic_guarantee;
// is.syntactic_persistence inherited
is.accepting_eword = false;
break;
case G:
is.not_marked = true;
is.boolean = false;
is.eltl_formula = false;
is.sere_formula = false;
is.finite = false;
is.sugar_free_ltl = false;
is.universal = true;
// is.syntactic_safety inherited
is.syntactic_guarantee = false;
is.syntactic_obligation = is.syntactic_safety;
// is.syntactic_recurrence inherited
is.syntactic_persistence = is.syntactic_safety;
is.accepting_eword = false;
break;
case Finish:
is.not_marked = true;
is.boolean = false;
is.ltl_formula = false;
is.psl_formula = false;
is.sere_formula = false;
is.finite = false;
is.syntactic_safety = false;
is.syntactic_guarantee = false;
is.syntactic_obligation = false;
is.syntactic_recurrence = false;
is.syntactic_persistence = false;
is.accepting_eword = false;
break;
case NegClosure:
case NegClosureMarked:
is.not_marked = (op == NegClosure);
is.boolean = false;
is.ltl_formula = false;
is.eltl_formula = false;
is.psl_formula = true;
is.sere_formula = false;
is.syntactic_safety = is.finite;
is.syntactic_guarantee = true;
is.syntactic_obligation = true;
is.syntactic_recurrence = true;
is.syntactic_persistence = true;
is.accepting_eword = false;
break;
case Closure:
is.not_marked = true;
is.boolean = false;
is.ltl_formula = false;
is.eltl_formula = false;
is.psl_formula = true;
is.sere_formula = false;
is.syntactic_safety = true;
is.syntactic_guarantee = is.finite;
is.syntactic_obligation = true;
is.syntactic_recurrence = true;
is.syntactic_persistence = true;
is.accepting_eword = false;
assert(child->is_sere_formula());
break;
}
}
unop::~unop()
{
// Get this instance out of the instance map.
size_t c = instances.erase(key(op(), child()));
assert(c == 1);
(void) c; // For the NDEBUG case.
// Dereference child.
child()->destroy();
}
std::string
unop::dump() const
{
return std::string("unop(") + op_name() + ", " + child()->dump() + ")";
}
void
unop::accept(visitor& v) const
{
v.visit(this);
}
const char*
unop::op_name() const
{
switch (op_)
{
case Not:
return "Not";
case X:
return "X";
case F:
return "F";
case G:
return "G";
case Finish:
return "Finish";
case Closure:
return "Closure";
case NegClosure:
return "NegClosure";
case NegClosureMarked:
return "NegClosureMarked";
}
SPOT_UNREACHABLE();
}
unop::map unop::instances;
const formula*
unop::instance(type op, const formula* child)
{
// Some trivial simplifications.
switch (op)
{
case F:
case G:
{
if (const unop* u = is_unop(child))
{
// F and G are idempotent.
if (u->op() == op)
return u;
}
// F(0) = G(0) = 0
// F(1) = G(1) = 1
if (child == constant::false_instance()
|| child == constant::true_instance())
return child;
assert(child != constant::empty_word_instance());
}
break;
case Not:
{
// !1 = 0
if (child == constant::true_instance())
return constant::false_instance();
// !0 = 1
if (child == constant::false_instance())
return constant::true_instance();
// ![*0] = 1[+]
if (child == constant::empty_word_instance())
return bunop::instance(bunop::Star,
constant::true_instance(), 1);
if (const unop* u = is_unop(child))
{
// "Not" is an involution.
if (u->op() == op)
{
const formula* c = u->child()->clone();
u->destroy();
return c;
}
// !Closure(Exp) = NegClosure(Exp)
if (u->op() == Closure)
{
const formula* c = unop::instance(NegClosure,
u->child()->clone());
u->destroy();
return c;
}
// !NegClosure(Exp) = Closure(Exp)
if (u->op() == NegClosure)
{
const formula* c = unop::instance(Closure,
u->child()->clone());
u->destroy();
return c;
}
}
break;
}
case X:
// X(1) = 1, X(0) = 0
if (child == constant::true_instance()
|| child == constant::false_instance())
return child;
assert(child != constant::empty_word_instance());
break;
case Finish:
// No simplifications for Finish.
break;
case Closure:
// {0} = 0, {1} = 1, {b} = b
if (child->is_boolean())
return child;
// {[*0]} = 0
if (child == constant::empty_word_instance())
return constant::false_instance();
break;
case NegClosure:
case NegClosureMarked:
// {1} = 0
if (child == constant::true_instance())
return constant::false_instance();
// {0} = 1, {[*0]} = 1
if (child == constant::false_instance()
|| child == constant::empty_word_instance())
return constant::true_instance();
// {b} = !b
if (child->is_boolean())
return unop::instance(Not, child);
break;
}
const formula* res;
auto ires = instances.emplace(key(op, child), nullptr);
if (!ires.second)
{
// This instance already exists.
child->destroy();
res = ires.first->second->clone();
}
else
{
res = ires.first->second = new unop(op, child);
}
return res;
}
unsigned
unop::instance_count()
{
return instances.size();
}
std::ostream&
unop::dump_instances(std::ostream& os)
{
for (const auto& i: instances)
os << i.second << " = "
<< 1 + i.second->refs_ << " * "
<< i.second->dump()
<< '\n';
return os;
}
}
}