home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tlx501.zip
/
SRC
/
PROPAC6.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-04
|
10KB
|
315 lines
/****************************************************************************
$Id: propac6.cpp 501.0 1995/03/07 12:26:20 RON Exp $
Copyright (c) 1991-95 Tarma Software Research. All rights reserved.
Project: Tarma Library for C++ V5.0
Author: Ron van der Wal
Implementation of the AC-6 constraint propagation algorithm.
$Log: propac6.cpp $
Revision 501.0 1995/03/07 12:26:20 RON
Updated for TLX 5.01
Revision 1.10 1995/02/28 15:13:08 RON
Update for release 012
Added partial support for SunPro C++ compiler
Revision 1.9 1995/01/06 15:58:09 ron
Corrected Revision keyword
Revision 1.8 1995/01/05 15:26:52 ron
Renamed tracing macro
Revision 1.7 1994/11/16 15:41:52 ron
Adapted to group-style tracing
Added module info; rearranged #include directives
Revision 1.6 1994/10/10 16:53:19 ron
Changed to <tlx\solve\ac6.h>
Revision 1.5 1994/10/05 18:41:48 ron
Renamed TLx...() functions to tl...()
Revision 1.4 1994/09/28 14:20:14 ron
Removed Macintosh-style #include references
Revision 1.3 1994/09/27 20:22:43 ron
Changed path separator from / to \
Revision 1.2 1994/09/26 15:44:56 ron
Changed include file references
Revision 1.1 1994/08/16 18:13:07 ron
Initial revision
****************************************************************************/
#include <tlx\501\_build.h>
TLX_MODULE_INFO("$Revision: 501.0 $");
#include <tlx\501\solve\ac6.h>
/*---------------------------------------------------------------------------
Template source code
---------------------------------------------------------------------------*/
#if defined(THINK_CPLUS)
#include "assoc.cpp"
#include "ptrseq.cpp"
#include "queue.cpp"
#pragma template_access public
#pragma template TLAssoc<TLVariableAC6 *, TLDomainElement>
#pragma template TLPtrSeq<TLVariableAC6>
#pragma template TLQueue<TLDomainRemoval>
#elif defined(__BORLANDC__) || defined(__SC__) || defined(__WATCOMC__)
#include <tlx\501\template\assoc.cpp>
#include <tlx\501\template\ptrseq.cpp>
#include <tlx\501\template\queue.cpp>
#elif defined(__SUNPRO_CC)
#include <tlx\501\template\assoc.cpp>
#include <tlx\501\template\ptrseq.cpp>
#include <tlx\501\template\queue.cpp>
#elif defined(__IBMCPP__)
#if __IBMCPP__ < 300
#pragma implementation("tlx\\template\\assoc.cpp")
#pragma implementation("tlx\\template\\ptrseq.cpp")
#pragma implementation("tlx\\template\\queue.cpp")
#else
#include <tlx\501\template\assoc.cpp>
#include <tlx\501\template\ptrseq.cpp>
#include <tlx\501\template\queue.cpp>
#endif
#else
#error Unsupported compiler; contact Tarma Software Research
#endif
/*-------------------------------------------------------------------------*/
TLPropagatorAC6::TLPropagatorAC6()
/* Default constructor.
---------------------------------------------------------------------------*/
: TLPropagator()
{
}
/*-------------------------------------------------------------------------*/
bool TLPropagatorAC6::CheckAC6(const TLPtrSeq<TLVariable> &aVarSet)
/* Performs the AC-6 constraint propagation algorithm on the given set
of variables. Returns nonzero if the variable configuration is
consistent, else zero.
This function is an adaptation of the algorithm as published in:
C. Bessiere: Arc-consistency and arc-consistency again, AI 65 (1994),
pp. 179-190.
---------------------------------------------------------------------------*/
{
// Build a list of all constraints connecting the given set of variables.
// Constraints that end outside this set are not taken into account.
//
// At the same time, we are clearing all support lists of the variables.
TLPtrSeq<TLConstraintAC6> constraints(aVarSet.Count(), 100);
size_t maxdomsize = 0;
for (index_t i = aVarSet.Mini(); i <= aVarSet.Maxi(); i++)
{
TLVariableAC6 *var = DYNACAST(TLVariableAC6 *, aVarSet.PeekAt(i));
TLX_ASSERT_PTR(var);
TLX_TRACE(TLX, (50, "Initializing variable %s", var->GetName()));
// Clear support lists and update maximum domain size found so far.
var->ClearSupport();
maxdomsize = tlMax(maxdomsize, var->Domain().Count());
// Check all constraints to see if they must be added
for (index_t j = var->Constraints().Mini();
j <= var->Constraints().Maxi(); j++)
{
TLConstraintAC6 *con = DYNACAST(TLConstraintAC6 *,
var->Constraints().PeekAt(j));
TLX_ASSERT_PTR(con);
// Add the constraint to the list if it's not already in it,
// and if the other end of the constraint is linked to a
// variable that is also in the set of variables under
// consideration.
if (!constraints.Contains(con) &&
aVarSet.Contains(&con->OppositeOf(*var)))
{
TLX_TRACE(TLX, (51, "-- Adding constraint for variable %s",
var->GetName()));
constraints.Append(con);
}
}
}
// Iterate through all constraints, initializing the support lists of
// the variables connected by them and putting unsupported values
// on a waiting list for propagation at a later stage.
//
// We attempt to create a waiting list of a reasonable initial capacity.
size_t initsize = aVarSet.Count() * maxdomsize / 2;
size_t expansion = tlMin(100U, initsize / 2);
TLWaitingList waitinglist(initsize, expansion);
TLX_TRACE(TLX, (40, "Initializing supports"));
for (index_t i2 = constraints.Mini(); i2 <= constraints.Maxi(); i2++)
{
TLConstraintAC6 *con = constraints.PeekAt(i2);
TLX_ASSERT_PTR(con);
// We assume that all constraints are used in two directions, i.e.
// that they are undirected edges rather than arcs.
InitSupport(con, &con->Var1(), &con->Var2(), waitinglist);
InitSupport(con, &con->Var2(), &con->Var1(), waitinglist);
}
// The actual propagation starts here. We iterate through the list
// of waiting variable/value pairs until it's completely empty, at
// which point we have a consisten system, or until the domain of
// one of the variables becomes empty, indicating an inconsistency.
while (!waitinglist.IsEmpty())
{
// Get the next domain element that was removed from its domain
// previously.
TLDomainRemoval removal(waitinglist.Dequeue());
// Propagate the effects of the removal of this element to the
// variable/value pairs that it supported.
TLVariableAC6 *orgvar = removal.Key();
TLDomainElement *domel = &removal.Value();
// Iterate through all previously supported variable/value pairs
iter_t supiter;
for (bool ok = domel->ResetIter(supiter); ok;
ok = domel->NextIter(supiter))
{
const TLVarValueLink *supvv = domel->PeekIter(supiter);
TLVariableAC6 *supvar = supvv->PeekVar();
tVarValue supvalue = supvv->PeekValue();
// Find the constraint that links the two variables
TLConstraintAC6 *con = orgvar->FindConstraintTo(supvar);
if (!con)
{
TLX_TRACE_WARN(TLX, ("No supporting constraint found"));
continue;
}
// Ask the constraint to find the next supporting value for
// the value of the supported variable.
tVarValue orgvalue = domel->PeekValue() + 1;
if (con->FindNextSupport(*supvar, supvalue, *orgvar, orgvalue))
{
// Found new supporting value; add the supported variable/
// value pair to its list of supports.
orgvar->AddSupport(orgvalue, *supvv);
}
else
{
// No support found; remove the value from the supported
// variable's domain and add it to the waiting list.
TLDomainRemoval newrem(supvar,
supvar->Domain().GetElement(supvalue));
waitinglist.Enqueue(newrem);
supvar->RemoveValue(supvalue);
}
}
// The removal and its support list will be automatically deleted
// by the compiler's call to its destructor.
}
// If we get here, there were no inconsistencies
return true;
}
/*-------------------------------------------------------------------------*/
bool TLPropagatorAC6::InitSupport
(
TLConstraintAC6 * aCon, // Supporting constraints
TLVariableAC6 * aVar1, // First (supported) variable
TLVariableAC6 * aVar2, // Second (supporting) variable
TLWaitingList & aList // List on which to enqueue removals
)
/* Initializes support lists for the given variables. Returns nonzero
if all went well, or zero if an empty domain was detected.
---------------------------------------------------------------------------*/
{
TLX_ASSERT_PTR(aCon);
TLX_ASSERT_PTR(aVar1);
TLX_ASSERT_PTR(aVar2);
TLX_ASSERT(aVar2 == &aCon->OppositeOf(*aVar1));
TLX_TRACE(TLX, (50, "Initializing support from %s to %s", aVar1->GetName(),
aVar2->GetName()));
// Iterate through the domain of the first variable, looking for
// support for its values.
if (aVar2->Domain().IsEmpty())
{
// If the domain of the variable is empty, there is no need
// for any further processing.
TLX_TRACE_INFO(TLX, ("Variable %s has empty domain", aVar2->GetName()));
return false;
}
for (index_t vi = aVar1->Domain().Mini(); vi <= aVar1->Domain().Maxi(); )
{
TLX_ASSERT(!aVar2->Domain().IsEmpty());
tVarValue orgvalue = aVar2->Domain().PeekFirst().PeekValue();
tVarValue supvalue = aVar1->Domain().PeekAt(vi).PeekValue();
if (aCon->FindNextSupport(*aVar1, supvalue, *aVar2, orgvalue))
{
// Found supporting value; add the supported variable/
// value pair to its list of supports.
aVar2->AddSupport(orgvalue, VV_Assoc(aVar1, supvalue));
vi++;
}
else
{
// No support found; remove the value from the supported
// variable's domain and add it to the waiting list.
TLX_TRACE(TLX, (51, "Removing unsupported value %ld from variable %s",
supvalue, aVar1->GetName()));
TLDomainRemoval newrem(aVar1,
aVar1->Domain().GetElement(supvalue));
aList.Enqueue(newrem);
aVar1->RemoveValue(supvalue); // Do not increment 'vi'
}
}
// If we get here, all domains were nonempty
return true;
}