#pragma once
/*
Copyright (c) 2003-2021 Tommi Junttila
Released under the GNU Lesser General Public License version 3.
This file is part of bliss.
bliss is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 3 of the License.
bliss 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with bliss. If not, see .
*/
namespace bliss {
class Partition;
}
#include
#include
#include "bliss/kqueue.hh"
#include "bliss/abstractgraph.hh"
namespace bliss {
/**
* \brief A class for refinable, backtrackable ordered partitions.
*
* This is rather a data structure with some helper functions than
* a proper self-contained class.
* That is, for efficiency reasons the fields of this class are directly
* manipulated from bliss::AbstractGraph and its subclasses.
* Conversely, some methods of this class modify the fields of
* bliss::AbstractGraph, too.
*/
class Partition
{
public:
/**
* \brief Data structure for holding information about a cell in a Partition.
*/
class Cell
{
friend class Partition;
public:
unsigned int length;
/* Index of the first element of the cell in
the Partition::elements array */
unsigned int first;
unsigned int max_ival;
unsigned int max_ival_count;
private:
bool in_splitting_queue;
public:
bool in_neighbour_heap;
/* Pointer to the next cell, null if this is the last one. */
Cell* next;
Cell* prev;
Cell* next_nonsingleton;
Cell* prev_nonsingleton;
unsigned int split_level;
/** Is this a unit cell? */
bool is_unit() const {return(length == 1); }
/** Is this cell in splitting queue? */
bool is_in_splitting_queue() const {return(in_splitting_queue); }
};
private:
/** \internal
* Data structure for remembering information about splits in order to
* perform efficient backtracking over the splits.
*/
class RefInfo {
public:
unsigned int split_cell_first;
int prev_nonsingleton_first;
int next_nonsingleton_first;
};
/** \internal
* A stack for remembering the splits, used for backtracking.
*/
std::vector refinement_stack;
class BacktrackInfo {
public:
unsigned int refinement_stack_size;
unsigned int cr_backtrack_point;
};
/** \internal
* The main stack for enabling backtracking.
*/
std::vector bt_stack;
public:
AbstractGraph* graph;
/* Used during equitable partition refinement */
KQueue splitting_queue;
void splitting_queue_add(Cell* const cell);
Cell* splitting_queue_pop();
bool splitting_queue_is_empty() const;
void splitting_queue_clear();
/** Type for backtracking points. */
typedef unsigned int BacktrackPoint;
/**
* Get a new backtrack point for the current partition
*/
BacktrackPoint set_backtrack_point();
/**
* Backtrack to the point \a p and remove it.
*/
void goto_backtrack_point(BacktrackPoint p);
/**
* Split the non-unit Cell \a cell = {\a element,e1,e2,...,en} containing
* the element \a element in two:
* \a cell = {e1,...,en} and \a newcell = {\a element}.
* @param cell a non-unit Cell
* @param element an element in \a cell
* @return the new unit Cell \a newcell
*/
Cell* individualize(Cell* const cell,
const unsigned int element);
Cell* aux_split_in_two(Cell* const cell,
const unsigned int first_half_size);
private:
unsigned int N;
Cell* cells;
Cell* free_cells;
unsigned int discrete_cell_count;
public:
Cell* first_cell;
Cell* first_nonsingleton_cell;
unsigned int *elements;
/* invariant_values[e] gives the invariant value of the element e */
unsigned int *invariant_values;
/* element_to_cell_map[e] gives the cell of the element e */
Cell **element_to_cell_map;
/** Get the cell of the element \a e */
Cell* get_cell(const unsigned int e) const {
assert(e < N);
return element_to_cell_map[e];
}
/* in_pos[e] points to the elements array s.t. *in_pos[e] = e */
unsigned int **in_pos;
Partition();
~Partition();
/**
* Initialize the partition to the unit partition (all elements in one cell)
* over the \a N > 0 elements {0,...,\a N-1}.
*/
void init(const unsigned int N);
/**
* Returns true iff the partition is discrete, meaning that all
* the elements are in their own cells.
*/
bool is_discrete() const {return(free_cells == 0); }
unsigned int nof_discrete_cells() const {return(discrete_cell_count); }
/**
* Print the partition into the file stream \a fp.
*/
size_t print(FILE* const fp, const bool add_newline = true) const;
/**
* Print the partition cell sizes into the file stream \a fp.
*/
size_t print_signature(FILE* const fp, const bool add_newline = true) const;
/*
* Splits the Cell \a cell into [cell_1,...,cell_n]
* according to the invariant_values of the elements in \a cell.
* After splitting, cell_1 == \a cell.
* Returns the pointer to the Cell cell_n;
* cell_n != cell iff the Cell \a cell was actually splitted.
* The flag \a max_ival_info_ok indicates whether the max_ival and
* max_ival_count fields of the Cell \a cell have consistent values
* when the method is called.
* Clears the invariant values of the elements in the Cell \a cell as well as
* the max_ival and max_ival_count fields of the Cell \a cell.
*/
Cell *zplit_cell(Cell * const cell, const bool max_ival_info_ok);
/*
* Routines for component recursion
*/
void cr_init();
void cr_free();
unsigned int cr_get_level(const unsigned int cell_index) const;
unsigned int cr_split_level(const unsigned int level,
const std::vector& cells);
/** Clear the invariant_values of the elements in the Cell \a cell. */
void clear_ivs(Cell* const cell);
private:
/*
* Component recursion data structures
*/
/* Is component recursion support in use? */
bool cr_enabled;
class CRCell {
public:
unsigned int level;
CRCell* next;
CRCell** prev_next_ptr;
void detach() {
if(next)
next->prev_next_ptr = prev_next_ptr;
*(prev_next_ptr) = next;
level = UINT_MAX;
next = nullptr;
prev_next_ptr = nullptr;
}
};
CRCell* cr_cells;
CRCell** cr_levels;
class CR_BTInfo {
public:
unsigned int created_trail_index;
unsigned int splitted_level_trail_index;
};
std::vector cr_created_trail;
std::vector cr_splitted_level_trail;
std::vector cr_bt_info;
unsigned int cr_max_level;
void cr_create_at_level(const unsigned int cell_index, unsigned int level);
void cr_create_at_level_trailed(const unsigned int cell_index, unsigned int level);
unsigned int cr_get_backtrack_point();
void cr_goto_backtrack_point(const unsigned int btpoint);
/*
*
* Auxiliary routines for sorting and splitting cells
*
*/
Cell* sort_and_split_cell1(Cell* cell);
Cell* sort_and_split_cell255(Cell* const cell, const unsigned int max_ival);
bool shellsort_cell(Cell* cell);
Cell* split_cell(Cell* const cell);
/*
* Some auxiliary stuff needed for distribution count sorting.
* To make the code thread-safe (modulo the requirement that each graph is
* only accessed in one thread at a time), the arrays are owned by
* the partition instance, not statically defined.
*/
unsigned int dcs_count[256];
unsigned int dcs_start[256];
void dcs_cumulate_count(const unsigned int max);
};
inline Partition::Cell*
Partition::splitting_queue_pop()
{
assert(!splitting_queue.is_empty());
Cell* const cell = splitting_queue.pop_front();
assert(cell->in_splitting_queue);
cell->in_splitting_queue = false;
return cell;
}
inline bool
Partition::splitting_queue_is_empty() const
{
return splitting_queue.is_empty();
}
inline unsigned int
Partition::cr_get_level(const unsigned int cell_index) const
{
assert(cr_enabled);
assert(cell_index < N);
assert(cr_cells[cell_index].level != UINT_MAX);
return(cr_cells[cell_index].level);
}
} // namespace bliss
|