/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2012 University of Bonn. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder 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.
*
* MoleCuilder 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 MoleCuilder. If not, see .
*/
/*
* SubsetMap.cpp
*
* Created on: Jul 3, 2012
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "CodePatterns/MemDebug.hpp"
#include "SubsetMap.hpp"
#include
#include
#include
#include
#include
#include
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
SubsetMap::SubsetMap(IndexSetContainer &_container) :
tempset(new IndexSet())
{
/// go through all IndexSets
const IndexSetContainer::Container_t &container = _container.getContainer();
for (IndexSetContainer::Container_t::const_iterator iter = container.begin();
iter != container.end(); ++iter) {
// check whether its the super set
if (*iter == _container.getSuperSet()) {
// place all other sets as its subsets
std::vector returnsets;
returnsets.reserve(container.size());
for (IndexSetContainer::Container_t::const_iterator insertiter = container.begin();
insertiter != container.end(); ++insertiter)
if (iter != insertiter) {
LOG(2, "INFO: Current subset is " << **insertiter << " for super set.");
ASSERT( _container.getSuperSet()->contains(**insertiter),
"SubsetMap::SubsetMap() - "+toString(**insertiter)+" is not contained in super set "
+toString(*_container.getSuperSet())+".");
returnsets.push_back(**insertiter);
}
Lookup.insert( std::make_pair(*iter, IndexSetContainer::ptr(new IndexSetContainer(returnsets))) );
} else {
gatherSubsets(*iter);
}
}
}
void SubsetMap::gatherSubsets(const IndexSet_ptr &ptr) {
// get the sets size and the size of the power sets
const size_t SetSize = ptr->size();
LOG(2, "DEBUG: Current set to gather all subsets for is " << *ptr << " with size " << SetSize << ".");
const size_t NoPowerSubsets = getNoPowerSets(SetSize);
LOG(2, "DEBUG: There are " << NoPowerSubsets << " sets to check for containment.");
std::vector returnsets;
// sets is the number of possible subsets to check: NotContained means still
// needs check or is not contained; Contained means is contained, or has
// already been treated via a super(sub)set.
typedef std::vector StateOfSubsets;
StateOfSubsets sets( NoPowerSubsets, NotContained);
// we have to traverse backwards, i.e. from greatest subsets to smallest to
// make the best possible use of the subset knowledge we already have for these
// subsets of the subset.
// WARNING: last set is the set itself which must not be in IndexSetContainer due to
// cyclic structure which shared_ptr cannot resolve.
StateOfSubsets::reverse_iterator iter = sets.rbegin()+1;
for (;iter != sets.rend(); iter = std::find(iter+1, sets.rend(), NotContained)) {
// get IndexSet (get index via distance)
// NOTE: reverse iterator naturally give reverse distance, hence flip both arguments
// also, reverse iterator is off by one, see ASSERT
const size_t index = std::distance(iter, sets.rend())-1;
ASSERT( sets.at(index) == *iter,
"SubsetMap::gatherSubsets() - distance from begin to iterator is not correct.");
*tempset = getSubset(*ptr, index );
LOG(3, "DEBUG: Current subset is " << *tempset << " at " << index << ".");
// check whether IndexSet is contained and known
if (ptr->contains(*tempset)) {
// mark as contained
*iter = Contained;
LOG(4, "DEBUG: Marking subset as Contained.");
if (Lookup.count(tempset)) {
LOG(3, "DEBUG: Subset is present in Lookup, adding.");
returnsets.push_back(*tempset);
// if so, also add its contained sets and mark them out
const IndexSetContainer::Container_t &container = getSubsets(tempset)->getContainer();
if (container.size()) {
LOG(3, "DEBUG: Subset is also present in Lookup, adding all its subsets");
for(IndexSetContainer::Container_t::const_iterator containeriter = container.begin();
containeriter != container.end();
++containeriter) {
const size_t subindex = getPowerSetIndex(ptr, **containeriter);
LOG(5, "INFO: Current subset of subset is " << **containeriter << " at " << subindex << ".");
if (sets[subindex] != Contained) {
LOG(6, "DEBUG: Setting power subset to Contained.");
sets[subindex] = Contained;
returnsets.push_back(**containeriter);
}
}
}
}
}
}
LOG(2, "DEBUG: Adding " << returnsets.size() << " sets to Lookup for set " << *ptr << ".");
Lookup.insert( std::make_pair(ptr, IndexSetContainer::ptr(new IndexSetContainer(returnsets))) );
}
const size_t SubsetMap::getPowerSetIndex(const IndexSet_ptr &ptr, const IndexSet &subset) {
ASSERT( (ptr->size() < MAX_SETSIZE) && (subset.size() < MAX_SETSIZE),
"SubsetMap::getPowerSetIndex() - power sets of subsets must not be bigger than "
+toString((int)MAX_SETSIZE)+".");
ASSERT( ptr->contains(subset),
"SubsetMap::getPowerSetIndex() - "+(toString(*ptr))+" does not contain "
+toString(subset)+".");
std::bitset bits(0);
// go through each and search for indices present in both
IndexSet::iterator indexiter = ptr->begin();
IndexSet::iterator subindexiter = subset.begin();
for (; subindexiter != subset.end();) {
if (*indexiter == *subindexiter) {
// if matching, set bit and advance both iterators
bits.set( (size_t)std::distance(ptr->begin(), indexiter) );
++indexiter;
++subindexiter;
// if not, advance the iterator lacking behind
} else if ( *indexiter < *subindexiter) {
++indexiter;
} else {
++subindexiter;
}
}
return bits.to_ulong();
}
IndexSet SubsetMap::getSubset(const IndexSet &_set, size_t PowerSetNo) {
ASSERT( _set.size() < MAX_SETSIZE,
"SubsetMap::getSubset() - power sets of subsets must not be bigger than "
+toString((int)MAX_SETSIZE)+".");
ASSERT((PowerSetNo >= 0) && (PowerSetNo < getNoPowerSets(_set.size())),
"SubsetMap::getSubset() - Power set index "+toString(PowerSetNo)+" is out of range.");
std::bitset bits(PowerSetNo);
// place index into container with random access
std::vector indices(_set.begin(), _set.end());
IndexSet indexset;
// go through each bit and insert if 1, not if 0
for (size_t index=0; index < indices.size(); ++index)
if (bits[index])
indexset.insert(indices[index]);
return indexset;
}
size_t SubsetMap::getMaximumSetLevel() const
{
if (Lookup.empty())
return 0;
// last one is super set
Lookup_t::const_iterator iter = --Lookup.end();
return iter->first->size();
}