1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

477 lines
14 KiB
C++
Executable File

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Linnea Ingmar <linnea.ingmar@hotmail.com>
* Mikael Lagerkvist <lagerkvist@gecode.org>
* Christian Schulte <schulte@gecode.org>
*
* Copyright:
* Linnea Ingmar, 2017
* Mikael Lagerkvist, 2007
* Christian Schulte, 2017
*
* This file is part of Gecode, the generic constraint
* development environment:
* http://www.gecode.org
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <gecode/int.hh>
#include <algorithm>
namespace Gecode { namespace Int { namespace Extensional {
/// Import tuple type
typedef ::Gecode::TupleSet::Tuple Tuple;
/// Tuple comparison
class TupleCompare {
private:
/// The arity of the tuples to compare
int arity;
public:
/// Initialize with arity \a a
TupleCompare(int a);
/// Comparison of tuples \a a and \a b
bool operator ()(const Tuple& a, const Tuple& b);
};
/// Tuple comparison by position
class PosCompare {
private:
/// The position of the tuples to compare
int p;
public:
/// Initialize with position \a p
PosCompare(int p);
/// Comparison of tuples \a a and \a b
bool operator ()(const Tuple& a, const Tuple& b);
};
forceinline
TupleCompare::TupleCompare(int a) : arity(a) {}
forceinline bool
TupleCompare::operator ()(const Tuple& a, const Tuple& b) {
for (int i=0; i<arity; i++)
if (a[i] < b[i])
return true;
else if (a[i] > b[i])
return false;
return false;
}
forceinline
PosCompare::PosCompare(int p0) : p(p0) {}
forceinline bool
PosCompare::operator ()(const Tuple& a, const Tuple& b) {
return a[p] < b[p];
}
}}}
namespace Gecode {
/*
* Tuple set data
*
*/
void
TupleSet::Data::finalize(void) {
using namespace Int::Extensional;
assert(!finalized());
// Mark as finalized
n_free = -1;
// Initialization
if (n_tuples == 0) {
heap.rfree(td);
td=nullptr;
return;
}
// Compact and copy data
Region r;
// Set up tuple pointers
Tuple* tuple = r.alloc<Tuple>(n_tuples);
{
for (int t=0; t<n_tuples; t++)
tuple[t] = td + t*arity;
TupleCompare tc(arity);
Support::quicksort(tuple, n_tuples, tc);
// Remove duplicates
int j=1;
for (int t=1; t<n_tuples; t++) {
for (int a=0; a<arity; a++)
if (tuple[t-1][a] != tuple[t][a])
goto notsame;
goto same;
notsame: ;
tuple[j++] = tuple[t];
same: ;
}
assert(j <= n_tuples);
n_tuples=j;
// Initialize hash key
key = static_cast<std::size_t>(n_tuples);
cmb_hash(key, arity);
// Copy into now possibly smaller area
int* new_td = heap.alloc<int>(n_tuples*arity);
for (int t=0; t<n_tuples; t++) {
for (int a=0; a<arity; a++) {
new_td[t*arity+a] = tuple[t][a];
cmb_hash(key,tuple[t][a]);
}
tuple[t] = new_td + t*arity;
}
heap.rfree(td);
td = new_td;
}
// Only now compute how many tuples are needed!
n_words = BitSetData::data(static_cast<unsigned int>(n_tuples));
// Compute range information
{
/*
* Pass one: compute how many values and ranges are needed
*/
// How many values
unsigned int n_vals = 0U;
// How many ranges
unsigned int n_ranges = 0U;
for (int a=0; a<arity; a++) {
// Sort tuple according to position
PosCompare pc(a);
Support::quicksort(tuple, n_tuples, pc);
// Scan values
{
int max=tuple[0][a];
n_vals++; n_ranges++;
for (int i=1; i<n_tuples; i++) {
assert(tuple[i-1][a] <= tuple[i][a]);
if (max+1 == tuple[i][a]) {
n_vals++;
max=tuple[i][a];
} else if (max+1 < tuple[i][a]) {
n_vals++; n_ranges++;
max=tuple[i][a];
} else {
assert(max == tuple[i][a]);
}
}
}
}
/*
* Pass 2: allocate memory and fill data structures
*/
// Allocate memory for ranges
Range* cr = range = heap.alloc<Range>(n_ranges);
// Allocate and initialize memory for supports
BitSetData* cs = support = heap.alloc<BitSetData>(n_words * n_vals);
for (unsigned int i=0; i<n_vals * n_words; i++)
cs[i].init();
for (int a=0; a<arity; a++) {
// Set range pointer
vd[a].r = cr;
// Sort tuple according to position
PosCompare pc(a);
Support::quicksort(tuple, n_tuples, pc);
// Update min and max
min = std::min(min,tuple[0][a]);
max = std::max(max,tuple[n_tuples-1][a]);
// Compress into non-overlapping ranges
{
unsigned int j=0U;
vd[a].r[0].max=vd[a].r[0].min=tuple[0][a];
for (int i=1; i<n_tuples; i++) {
assert(tuple[i-1][a] <= tuple[i][a]);
if (vd[a].r[j].max+1 == tuple[i][a]) {
vd[a].r[j].max=tuple[i][a];
} else if (vd[a].r[j].max+1 < tuple[i][a]) {
j++; vd[a].r[j].min=vd[a].r[j].max=tuple[i][a];
} else {
assert(vd[a].r[j].max == tuple[i][a]);
}
}
vd[a].n = j+1U;
cr += j+1U;
}
// Set support pointer and set bits
for (unsigned int i=0U; i<vd[a].n; i++) {
vd[a].r[i].s = cs;
cs += n_words * vd[a].r[i].width();
}
{
int j=0;
for (int i=0; i<n_tuples; i++) {
while (tuple[i][a] > vd[a].r[j].max)
j++;
set(const_cast<BitSetData*>
(vd[a].r[j].supports(n_words,tuple[i][a])),
tuple2idx(tuple[i]));
}
}
}
assert(cs == support + n_words * n_vals);
assert(cr == range + n_ranges);
}
if ((min < Int::Limits::min) || (max > Int::Limits::max))
throw Int::OutOfLimits("TupleSet::finalize()");
assert(finalized());
}
void
TupleSet::Data::resize(void) {
assert(n_free == 0);
int n = static_cast<int>(1+n_tuples*1.5);
td = heap.realloc<int>(td, n_tuples * arity, n * arity);
n_free = n - n_tuples;
}
TupleSet::Data::~Data(void) {
heap.rfree(td);
heap.rfree(vd);
heap.rfree(range);
heap.rfree(support);
}
/*
* Tuple set
*
*/
TupleSet::TupleSet(int a)
: SharedHandle(new Data(a)) {}
void
TupleSet::init(int a) {
object(new Data(a));
}
TupleSet::TupleSet(const TupleSet& ts)
: SharedHandle(ts) {}
TupleSet&
TupleSet::operator =(const TupleSet& ts) {
(void) SharedHandle::operator =(ts);
return *this;
}
TupleSet::TupleSet(int a, const Gecode::DFA& dfa) {
/// Edges in layered graph
struct Edge {
int i_state; ///< Number of in-state
int o_state; ///< Number of out-state
};
/// State in layered graph
struct State {
int i_deg; ///< In-degree (number of incoming arcs)
int o_deg; ///< Out-degree (number of outgoing arcs)
int n_tuples; ///< Number of tuples
int* tuples; ///< The tuples
};
/// Support for a value
struct Support {
int val; ///< Supported value
int n_edges; ///< Number of supporting edges
Edge* edges; ///< Supporting edges
};
/// Layer in layered graph
struct Layer {
State* states; ///< States
Support* supports; ///< Supported values
int n_supports; ///< Number of supported values
};
// Initialize
object(new Data(a));
Region r;
// Number of states
int max_states = dfa.n_states();
// Allocate memory for all layers and states
Layer* layers = r.alloc<Layer>(a+1);
State* states = r.alloc<State>(max_states*(a+1));
for (int i=0; i<max_states*(a+1); i++) {
states[i].i_deg = 0; states[i].o_deg = 0;
states[i].n_tuples = 0;
states[i].tuples = nullptr;
}
for (int i=0; i<a+1; i++) {
layers[i].states = states + i*max_states;
layers[i].n_supports = 0;
}
// Mark initial state as being reachable
layers[0].states[0].i_deg = 1;
layers[0].states[0].n_tuples = 1;
layers[0].states[0].tuples = r.alloc<int>(1);
assert(layers[0].states[0].tuples != nullptr);
// Allocate temporary memory for edges and supports
Edge* edges = r.alloc<Edge>(dfa.max_degree());
Support* supports = r.alloc<Support>(dfa.n_symbols());
// Forward pass: accumulate
for (int i=0; i<a; i++) {
int n_supports=0;
for (DFA::Symbols s(dfa); s(); ++s) {
int n_edges=0;
for (DFA::Transitions t(dfa,s.val()); t(); ++t) {
if (layers[i].states[t.i_state()].i_deg != 0) {
// Create edge
edges[n_edges].i_state = t.i_state();
edges[n_edges].o_state = t.o_state();
n_edges++;
// Adjust degrees
layers[i].states[t.i_state()].o_deg++;
layers[i+1].states[t.o_state()].i_deg++;
// Adjust number of tuples
layers[i+1].states[t.o_state()].n_tuples
+= layers[i].states[t.i_state()].n_tuples;
}
assert(static_cast<unsigned int>(n_edges) <= dfa.max_degree());
}
// Found a support for the value
if (n_edges > 0) {
Support& support = supports[n_supports++];
support.val = s.val();
support.n_edges = n_edges;
support.edges = Heap::copy(r.alloc<Edge>(n_edges),edges,n_edges);
}
}
// Create supports
if (n_supports > 0) {
layers[i].supports =
Heap::copy(r.alloc<Support>(n_supports),supports,n_supports);
layers[i].n_supports = n_supports;
} else {
finalize();
return;
}
}
// Mark final states as being reachable
for (int s=dfa.final_fst(); s<dfa.final_lst(); s++) {
if (layers[a].states[s].i_deg != 0U)
layers[a].states[s].o_deg = 1U;
}
// Backward pass: validate
for (int i=a; i--; ) {
for (int j = layers[i].n_supports; j--; ) {
Support& s = layers[i].supports[j];
for (int k = s.n_edges; k--; ) {
int i_state = s.edges[k].i_state;
int o_state = s.edges[k].o_state;
// State is unreachable
if (layers[i+1].states[o_state].o_deg == 0) {
// Adjust degree
--layers[i+1].states[o_state].i_deg;
--layers[i].states[i_state].o_deg;
// Remove edge
assert(s.n_edges > 0);
s.edges[k] = s.edges[--s.n_edges];
}
}
// Lost support
if (s.n_edges == 0)
layers[i].supports[j] = layers[i].supports[--layers[i].n_supports];
}
if (layers[i].n_supports == 0U) {
finalize();
return;
}
}
// Generate tuples
for (int i=0; i<a; i++) {
for (int j = layers[i].n_supports; j--; ) {
Support& s = layers[i].supports[j];
for (int k = s.n_edges; k--; ) {
int i_state = s.edges[k].i_state;
int o_state = s.edges[k].o_state;
// Allocate memory for tuples if not done
if (layers[i+1].states[o_state].tuples == nullptr) {
int n_tuples = layers[i+1].states[o_state].n_tuples;
layers[i+1].states[o_state].tuples = r.alloc<int>((i+1)*n_tuples);
layers[i+1].states[o_state].n_tuples = 0;
}
int n = layers[i+1].states[o_state].n_tuples;
// Write tuples
for (int t=0; t < layers[i].states[i_state].n_tuples; t++) {
// Copy the first i number of digits from the previous layer
Heap::copy(&layers[i+1].states[o_state].tuples[n*(i+1)+t*(i+1)],
&layers[i].states[i_state].tuples[t*i], i);
// Write the last digit
layers[i+1].states[o_state].tuples[n*(i+1)+t*(i+1)+i] = s.val;
}
layers[i+1].states[o_state].n_tuples
+= layers[i].states[i_state].n_tuples;
}
}
}
// Add tuples to tuple set
for (int s = dfa.final_fst(); s < dfa.final_lst(); s++) {
for (int i=0; i<layers[a].states[s].n_tuples; i++) {
int* tuple = &layers[a].states[s].tuples[i*a];
add(IntArgs(a,tuple));
}
}
finalize();
}
bool
TupleSet::equal(const TupleSet& t) const {
assert(tuples() == t.tuples());
assert(arity() == t.arity());
assert(min() == t.min());
assert(max() == t.max());
for (int i=0; i<tuples(); i++)
for (int j=0; j<arity(); j++)
if ((*this)[i][j] != t[i][j])
return false;
return true;
}
void
TupleSet::_add(const IntArgs& t) {
if (!*this)
throw Int::UninitializedTupleSet("TupleSet::add()");
if (raw().finalized())
throw Int::AlreadyFinalized("TupleSet::add()");
if (t.size() != raw().arity)
throw Int::ArgumentSizeMismatch("TupleSet::add()");
Tuple a = raw().add();
for (int i=0; i<t.size(); i++)
a[i]=t[i];
}
}
// STATISTICS: int-prop