/* Copyright (c) 1997-2004
Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de
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, or (at your option) any
later version: http://www.gnu.org/licenses/gpl.txt.
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.
*/
#ifndef _POLYMAKE_BISTELLAR_COMPLEX_H
#define _POLYMAKE_BISTELLAR_COMPLEX_H "$Project: polymake $$Id: BistellarComplex.h 7579 2007-01-22 11:34:46Z gawrilow $"
#include <complex_tools.h>
#include <FacetList.h>
#include <RandomSubset.h>
#include <IncidenceMatrix.h>
#include <list>
#include <ext/hash_map>
namespace polymake { namespace topaz {
class BistellarComplex {
protected:
typedef std::pair< Set<int>,Set<int> > option;
class OptionsList {
protected:
int the_size;
std_ext::hash_map< Set<int>,int > index_map;
Array<option> the_options;
public:
OptionsList() : the_size(0) {};
int size()
{
return the_size;
}
void insert(const option& opt)
{
if (the_options.size()==0)
the_options.resize(1);
if (the_size>=the_options.size())
the_options.resize(2*the_options.size());
the_options[the_size]=opt;
index_map[opt.first]=the_size;
++the_size;
}
void insert(const Set<int>& f, const Set<int>& V)
{
insert(option(f,V));
}
void remove(const Set<int>& f)
{
std_ext::hash_map< Set<int>,int >::const_iterator find=index_map.find(f);
if (find!=index_map.end()) {
const int index = find->second;
the_options[index] = the_options[the_size-1];
index_map[the_options[the_size-1].first] = index;
index_map.erase(f);
--the_size;
}
}
Array<option> options() {
return Array<option>(the_size,the_options.begin());
}
/*
void print_options()
{
for (int i=0; i<the_size; ++i)
cout << "(" << the_options[i].first << "," << the_options[i].second << ") ";
cout << endl;
}
*/
};
FacetList the_facets;
Array<OptionsList> raw_options;
int dim;
unsigned long seed;
int verts;
option next_move;
Set<int> rev_move;
bool allow_rev_move;
Array<int> the_flip_vector;
bool verbose;
int apex;
bool closed;
public:
BistellarComplex() : dim(0), seed(0), verts(0), allow_rev_move(false), verbose(false), apex(0), closed(true) {};
BistellarComplex(const HasseDiagram<>& HD, const unsigned long in_seed,
const bool verb=false, const bool in_closed=false, const bool in_allow_rev_move=false) {
verbose = verb;
dim = HD.dim()-1;
seed = in_seed;
verts = 0;
apex = 0;
next_move = option();
rev_move = Set<int>();
allow_rev_move = in_allow_rev_move;
the_flip_vector.resize((dim+1)/2);
closed = in_closed;
raw_options.resize(dim+1);
// test if the complex is closed.
if (!closed) {
const polymake::topaz::Boundary_of_PseudoManifold B = polymake::topaz::boundary_of_pseudo_manifold(HD);
bool closed = B.empty();
if (!closed) {
// compute C + cone(bound(C))
std::list< Set<int> > S;
for (Entire<sequence>::const_iterator f=entire(HD.nodes_of_dim(HD.dim()-1));
!f.at_end(); ++f) {
S.push_back(HD.node(*f));
const int w = HD.node(*f).back();
if (w >= verts)
verts = w+1;
}
apex = verts;
++verts;
for (Entire<polymake::topaz::Boundary_of_PseudoManifold>::const_iterator b=entire(B);
!b.at_end(); ++b)
S.push_back(*b+apex);
const HasseDiagram<> new_HD = polymake::topaz::pure_hasse_diagram(S);
// compute raw options
for (int d=0; d<=dim; ++d)
for (Entire<sequence>::const_iterator n=entire(new_HD.nodes_of_dim(d));
!n.at_end(); ++n) {
const Set<int> face = new_HD.node(*n);
if (d==0 && face.front() == apex) // the apex is not an option
continue;
if (d==dim) { // each facet is an option
the_facets.insert(face);
raw_options[d].insert(face, Set<int>());
} else {
const FacetList link = polymake::topaz::link_in_HD(new_HD,*n);
const Set<int> V = accumulate(link, operations::add());
if (V.size()+face.size()==dim+2) // face is raw option
raw_options[d].insert(face,V);
}
}
}
}
if (closed)
for (int d=0; d<=dim; ++d)
for (Entire<sequence>::const_iterator n=entire(HD.nodes_of_dim(d));
!n.at_end(); ++n) {
const Set<int> face=HD.node(*n);
if (d==0) { // face is a vertex
const int v = face.front();
if (v >= verts)
verts = v+1;
}
if (d==dim) { // each facet is an option
the_facets.insert(face);
raw_options[d].insert(face, Set<int>());
} else {
const FacetList link = polymake::topaz::link_in_HD(HD,*n);
const Set<int> V = accumulate(link, operations::add());
if (V.size()+face.size()==dim+2) // face is raw option
raw_options[d].insert(face,V);
}
}
}
int n_raw_options_of_dim(const int d) {
return raw_options[d].options().size();
}
// Finds a reversed move of minimal dimension >= dim_min
// and returns the dimension of the move. The move is != next_move.second
// The move is stored in next_move.
int find_move(const int dim_min) {
for (int d=dim_min; d<=dim; ++d) {
const RandomPermutation< Array<option> > P(raw_options[d].options(),seed++);
for (Entire< RandomPermutation< Array<option> > >::const_iterator
opt=(entire(P));
!opt.at_end(); ++opt)
if ( (allow_rev_move || incl(opt->first,rev_move)!=0) &&
(d==dim || the_facets.findMax(opt->second).at_end()) ) {
next_move = *opt;
return opt->first.size() - 1;
}
}
throw std::runtime_error("BistellarComplex: No move found.");
}
int find_move() {
return find_move(0);
}
protected:
// Determines if a face is an option.
bool is_option(const Set<int>& f, Set<int>& V) {
if (!closed && f.size()==1 && f.front()==apex) // apex is not an option
return false;
for (FacetList::iteratorMax star = the_facets.findMax(f);
!star.at_end(); ++star)
V += *star;
V -= f;
return V.size()+f.size()==dim+2;
}
public:
// Executes what ever move is set by find_move() or find_move(const int).
// You MUST set a move by using find_move() or find_move(const int) befor executing it.
void execute_move()
{
const Set<int> face = next_move.first;
const int face_dim = face.size()-1;
if (face_dim==dim) // allocate an index for the new vertex
next_move.second = scalar2set(verts++);
const Set<int> co_face= next_move.second;
if (!allow_rev_move) rev_move = co_face;
if (verbose)
cout << "BistellarComplex: executing move of dim "
<< face.size()-1 << ": (" << face << "," << co_face << ")\n";
// update the_flip_vector
if (dim%2==1 || face_dim!=dim/2)
if (face_dim < (dim+1)/2)
--the_flip_vector[face_dim];
else
++the_flip_vector[dim-face_dim];
// remove star(face) from raw_options and the_facets
std::list< Set<int> > star;
the_facets.eraseMin(face, std::back_inserter(star));
HasseDiagram<> star_HD = polymake::topaz::pure_hasse_diagram(star);
for (int d=0; d<=dim; ++d)
for (Entire<sequence>::const_iterator n=entire(star_HD.nodes_of_dim(d));
!n.at_end(); ++n)
raw_options[d].remove(star_HD.node(*n));
// add co_face * boundary(face)
std::list< Set<int> > new_facets;
for (Entire< Set<int> >::const_iterator w=entire(face);
!w.at_end(); ++w) {
Set<int> f=face;
f-=*w;
f+=co_face;
the_facets.insert(f);
new_facets.push_back(f);
}
// find new raw_options
HasseDiagram<> lokal_HD = polymake::topaz::pure_hasse_diagram(new_facets);
for (int d=0; d<=dim; ++d)
for (Entire<sequence>::const_iterator n=entire(lokal_HD.nodes_of_dim(d));
!n.at_end(); ++n) {
const Set<int> f = lokal_HD.node(*n);
if (d==dim)
raw_options[d].insert(f, Set<int>());
else {
Set<int> V;
if( is_option(f,V) )
raw_options[d].insert(f,V);
}
}
}
// Finds minimal revers move >= dim_min and executes it. Return the dimension of the move.
int min_rev_move(const int dim_min) {
const int d = find_move(dim_min);
execute_move();
return d;
}
int min_rev_move() {
return min_rev_move(0);
}
// A zero move.
void zero_move() {
min_rev_move(dim);
}
// The facets. Vertices are NOT numbered according to the topaz standard.
FacetList facets() {
if (closed)
return the_facets;
// remove star(apex)
FacetList real_facets = the_facets;
real_facets.eraseMin(scalar2set(apex));
return real_facets;
}
IncidenceMatrix<> as_incid_matrix() {
FacetList F=facets();
F.squeeze();
return IncidenceMatrix<>(F.size(), F.cols(), F.begin());
}
int n_facets() {
if (closed)
return the_facets.size();
return facets().size();
}
const Array<int>& flip_vector() {
return the_flip_vector;
}
};
} } // end namespace polymake::topaz
#endif // _POLYMAKE_BISTELLAR_COMPLEX_H
// Local Variables:
// mode:C++
// c-basic-offset:3
// End:
syntax highlighted by Code2HTML, v. 0.9.1