291 lines
7.9 KiB
C++
291 lines
7.9 KiB
C++
/*
|
|
* Copyright (C) 1999, 2000, 2001, 2002
|
|
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
|
|
*
|
|
* This program 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 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef __GNUC__
|
|
#pragma implementation
|
|
#endif /* __GNUC__ */
|
|
|
|
#include <climits>
|
|
#include <config.h>
|
|
#include <map>
|
|
#include "Alloc.h"
|
|
#include "BitArray.h"
|
|
#include "Exception.h"
|
|
#include "StateSpaceRandomizer.h"
|
|
|
|
namespace Graph
|
|
{
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Function definitions for class StateSpaceRandomizer.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
void StateSpaceRandomizer::reset()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: (Re)initializes the StateSpaceRandomizer object with default
|
|
* state space generation parameters.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
min_size = max_size = 20;
|
|
atoms_per_state = 5;
|
|
edge_probability = 0.2;
|
|
truth_probability = 0.5;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
StateSpace* StateSpaceRandomizer::generateGraph() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Generates a random state space with the current graph
|
|
* generation parameters.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A pointer to a newly allocated StateSpace object.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
StateSpace::size_type size = chooseSize();
|
|
|
|
StateSpace* statespace = new StateSpace(atoms_per_state, size);
|
|
|
|
statespace->initialState() = 0;
|
|
|
|
if (size > 0)
|
|
{
|
|
try
|
|
{
|
|
bool has_successor;
|
|
|
|
for (StateSpace::size_type i = 0; i < size; i++)
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
|
|
has_successor = false;
|
|
|
|
for (StateSpace::size_type j = 0; j < size; j++)
|
|
{
|
|
if (DRAND() < edge_probability)
|
|
{
|
|
statespace->connect(i, j);
|
|
has_successor = true;
|
|
}
|
|
}
|
|
|
|
if (!has_successor)
|
|
statespace->connect(i, LRAND(0, size));
|
|
|
|
for (unsigned long int j = 0; j < atoms_per_state; j++)
|
|
{
|
|
if (DRAND() < truth_probability)
|
|
(*statespace)[i].positiveAtoms().setBit(j);
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
delete statespace;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return statespace;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
StateSpace* StateSpaceRandomizer::generateConnectedGraph() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Initializes a random connected state space whose each state
|
|
* is reachable from its initial state 0.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A pointer to a newly allocated StateSpace object.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
StateSpace::size_type size = chooseSize();
|
|
|
|
StateSpace* statespace = new StateSpace(atoms_per_state, size);
|
|
|
|
statespace->initialState() = 0;
|
|
|
|
if (size > 0)
|
|
{
|
|
try
|
|
{
|
|
/* Random graph generation algorithm:
|
|
----------------------------------
|
|
|
|
allocate number_of_states nodes;
|
|
|
|
insert node 0 to the set of `reachable but unprocessed' nodes (nodes
|
|
that are reachable from the root node but whose children have not yet
|
|
been selected)
|
|
|
|
while the set of `reachable but unprocessed' nodes in nonempty
|
|
{
|
|
select a (random) node X from the set;
|
|
|
|
if there exists a node Y that is not yet reachable from root node
|
|
{
|
|
connect X to Y by making X the parent node of Y;
|
|
insert Y to the set of `reachable but unprocessed' nodes;
|
|
}
|
|
|
|
for each node Z (excluding node Y) in the graph
|
|
{
|
|
randomly connect X to Z (making X the parent of Z);
|
|
|
|
if Z was not previously reachable from the root node
|
|
insert Z to the set of `reachable but unprocessed' nodes;
|
|
}
|
|
|
|
remove X from the set of `reachable but unprocessed' nodes;
|
|
}
|
|
|
|
In the following implementation, the random truth value allocation
|
|
for propositions that hold in a state is interleaved with the
|
|
previous algorithm.
|
|
*/
|
|
|
|
StateSpace::size_type first_unreachable_state = 1, random_node;
|
|
|
|
multimap<long int, StateSpace::size_type, less<long int>,
|
|
ALLOC(StateSpace::size_type) >
|
|
reachable_but_unprocessed;
|
|
|
|
reachable_but_unprocessed.insert(make_pair(0, 0));
|
|
|
|
while (!reachable_but_unprocessed.empty())
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
|
|
random_node = (*(reachable_but_unprocessed.begin())).second;
|
|
reachable_but_unprocessed.erase(reachable_but_unprocessed.begin());
|
|
|
|
for (StateSpace::size_type n = 0; n < first_unreachable_state; ++n)
|
|
{
|
|
if (DRAND() < edge_probability)
|
|
statespace->connect(random_node, n);
|
|
}
|
|
|
|
if (first_unreachable_state < size)
|
|
{
|
|
statespace->connect(random_node, first_unreachable_state);
|
|
reachable_but_unprocessed.insert(make_pair(LRAND(0, LONG_MAX),
|
|
first_unreachable_state));
|
|
++first_unreachable_state;
|
|
|
|
for (StateSpace::size_type i = first_unreachable_state; i < size;
|
|
++i)
|
|
{
|
|
if (DRAND() < edge_probability)
|
|
{
|
|
statespace->connect(random_node, first_unreachable_state);
|
|
reachable_but_unprocessed.insert
|
|
(make_pair(LRAND(0, LONG_MAX), first_unreachable_state));
|
|
++first_unreachable_state;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((*statespace)[random_node].edges().empty())
|
|
statespace->connect(random_node, random_node);
|
|
|
|
BitArray& atoms = (*statespace)[random_node].positiveAtoms();
|
|
for (unsigned long int i = 0; i < atoms_per_state; ++i)
|
|
{
|
|
if (DRAND() < truth_probability)
|
|
atoms.setBit(i);
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
delete statespace;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return statespace;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
StateSpace* StateSpaceRandomizer::generatePath() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Generates a random Kripke structure that consists of a finite
|
|
* prefix of states that ends in a loop. The initial state of
|
|
* the generated structure will be at index 0.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A pointer to a newly allocated StateSpace object.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
StateSpace::size_type size = chooseSize();
|
|
|
|
StateSpace* statespace = new StateSpace(atoms_per_state, size);
|
|
|
|
statespace->initialState() = 0;
|
|
|
|
if (size > 0)
|
|
{
|
|
try
|
|
{
|
|
for (StateSpace::size_type i = 0; i + 1 < size; i++)
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
|
|
statespace->connect(i, i + 1);
|
|
for (unsigned long int j = 0; j < atoms_per_state; j++)
|
|
{
|
|
if (DRAND() < truth_probability)
|
|
(*statespace)[i].positiveAtoms().setBit(j);
|
|
}
|
|
}
|
|
|
|
statespace->connect(size - 1, LRAND(0, size));
|
|
}
|
|
catch (...)
|
|
{
|
|
delete statespace;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return statespace;
|
|
}
|
|
|
|
}
|