/*
* 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 .
*/
/*
* Histogram.cpp
*
* Created on: Jul 26, 2012
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "CodePatterns/MemDebug.hpp"
#include "Histogram.hpp"
#include
#include
#include
#include
#include
#include
#include
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
/** Tiny helper struct to create equally spaced bins with count of zero.
*
*/
struct BinCreator_t {
BinCreator_t( const double lowerend, const double _width ) :
currentstart(lowerend),
width(_width)
{}
Histogram::Bin_t operator()() {
Histogram::Bin_t bin( make_pair( currentstart, 0.) );
currentstart+=width;
return bin;
}
private:
double currentstart;
const double width;
};
// see http://stackoverflow.com/questions/634087/stdcopy-to-stdcout-for-stdpair
// printing a pair is not easy, especially so with ostream_iterator as it cannot find
// overload operator<<() as it is not in namespace std.
template
struct PrintPair : public std::unary_function
{
std::ostream& os;
PrintPair(std::ostream& strm) : os(strm) {}
void operator()(const T& elem) const
{
os << "(" << elem.first << "," << elem.second << ") ";
}
};
std::ostream & operator<<(std::ostream &ost, const Histogram::Bin_t &elem)
{
ost << "(" << elem.first << "," << elem.second << ") ";
return ost;
}
Histogram::Histogram(const samples_t &samples, const int _CountBins) :
binwidth(0.5),
CountBins(_CountBins)
{
// build histogram from samples
if (!samples.empty()) {
if (CountBins == -1) {
CountBins = ceil(pow(samples.size(), 1./3.));
}
// 2. get min and max and determine width
samples_t::const_iterator maxiter = max_element(samples.begin(), samples.end());
samples_t::const_iterator miniter = min_element(samples.begin(), samples.end());
ASSERT((maxiter != samples.end()) || (miniter != samples.end()),
"Histogram::Histogram() - cannot find min/max despite non-empty range.");
LOG(1, "DEBUG: min is " << *miniter << " and max is " << *maxiter << ".");
binwidth = (*maxiter - *miniter)/(CountBins-1);
// 3. create each bin
BinCreator_t BinCreator( *miniter, binwidth );
std::vector vectorbins;
// we need one extra bin for get...Bin()'s find to work properly
vectorbins.resize(CountBins+1, Bin_t( make_pair(0., 0.) ) );
std::generate( vectorbins.begin(), vectorbins.end(), BinCreator );
bins.insert(vectorbins.begin(), vectorbins.end());
// 4. place each sample into bin
BOOST_FOREACH( double value, samples) {
const Bins_t::iterator biniter = getLowerEndBin(value);
ASSERT( biniter != bins.end(),
"Histogram::Histogram() - cannot find bin for value from given samples.");
biniter->second += 1.;
}
std::stringstream output;
std::for_each( bins.begin(), bins.end(), PrintPair(output));
LOG(2, "DEBUG: Bins are " << output.str() << ".");
} else {
LOG(1, "INFO: Given vector of samples is empty.");
}
}
Histogram& Histogram::operator+=(const Histogram &other)
{
return *this;
}
Histogram& Histogram::operator-=(const Histogram &other)
{
return *this;
}
bool Histogram::isEmpty() const
{
bool status = true;
for (Bins_t::const_iterator iter = bins.begin(); iter != bins.end(); ++iter)
status &= iter->second == 0;
return status;
}
Histogram::Bins_t::iterator Histogram::getLowerEndBin(const double _value)
{
// lower bound returns key that is equal or greater
Bins_t::iterator iter = bins.lower_bound(_value);
if (iter != bins.end()) {
// if we are not on the boundary we always have to step back by one
if (_value != iter->first) {
if (iter != bins.begin()) {
--iter;
} else {
iter = bins.end();
}
} else if (iter == --bins.end()) {
// if we actually are on boundary of "last bin", set to end
iter = bins.end();
}
}
return iter;
}
Histogram::Bins_t::iterator Histogram::getHigherEndBin(const double _value)
{
// upper bound return key that is strictly greater
Bins_t::iterator iter = bins.upper_bound(_value);
// if we are on the boundary we have to step back by one
if (iter != bins.end())
if (_value == iter->first)
if (iter != bins.begin())
--iter;
return iter;
}