status.hh 6.53 KB
Newer Older
1
2
3
4
5
6
7
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
 *   See the file COPYING for full copying permissions.                      *
 *                                                                           *
 *   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    *
Dennis Gläser's avatar
Dennis Gläser committed
8
 *   the Free Software Foundation, either version 3 of the License, or       *
9
10
11
12
13
14
15
16
17
18
19
20
 *   (at your option) any later version.                                     *
 *                                                                           *
 *   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.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 *****************************************************************************/
/*!
 * \file
21
 * \ingroup Sampling
22
23
24
25
26
27
 * \brief Class that can be used to define target counters in
 *        sampling procedures and which outputs the current status.
 */
#ifndef FRACKIT_SAMPLING_STATUS_HH
#define FRACKIT_SAMPLING_STATUS_HH

28
29
#include <iomanip>
#include <iostream>
30
#include <algorithm>
31
#include <numeric>
32
#include <utility>
33
34
35
36
37
38
39
40
#include <unordered_map>
#include <initializer_list>

#include <frackit/common/id.hh>

namespace Frackit {

/*!
41
 * \ingroup Sampling
42
43
44
45
46
47
48
49
50
 * \brief Class that can be used to define target counters in
 *        sampling procedures and which outputs the current status.
 */
class SamplingStatus
{

public:

    /*!
51
     * \brief Set the target sample count for a specific id.
52
53
54
55
56
57
58
59
     */
    void setTargetCount(const Id& id, std::size_t targetCount)
    {
        targetCount_[id.get()] = targetCount;

        auto it = count_.find(id.get());
        if (it == count_.end())
            count_[id.get()] = 0;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        else if (it->second > targetCount)
            std::cout << "Warning: given target count is below current count" << std::endl;
    }

    /*!
     * \brief Reset all counters.
     */
    void resetCounters()
    {
        for (auto& count : count_) count.second = 0;
    }

    /*!
     * \brief Reset counter for the given id.
     */
    void resetCounter(const Id& id)
    {
        count_[id.get()] = 0;
78
79
80
    }

    /*!
81
82
     * \brief Returns true when the target
     *        sample count is reached.
83
84
85
86
     */
    bool finished()
    {
        for (const auto& pair : count_)
87
            if (pair.second < targetCount_.at(pair.first))
88
89
90
91
92
                return false;
        return true;
    }

    /*!
93
94
     * \brief Returns true when the target count
     *        for a specific id is reached.
95
96
97
98
99
100
     */
    bool finished(const Id& id)
    {
        auto it = count_.find(id.get());
        if (it == count_.end())
            throw std::runtime_error("Target count not set for given id");
101
        return it->second >= targetCount_.at(it->first);
102
103
104
    }

    /*!
105
     * \brief Increase counter for a specific id.
106
107
108
109
     */
    void increaseCounter(const Id& id)
    {
        count_[id.get()]++;
110
111
        if (count_[id.get()] > targetCount_[id.get()])
            std::cout << "Warning: target count for id " << id.get() << " was surpassed" << std::endl;
112
113
114
    }

    /*!
115
     * \brief Increase counter of rejected samples.
116
117
118
119
120
121
     */
    void increaseRejectedCounter()
    {
        rejectedCount_++;
    }

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    /*!
     * \brief Returns the entity count for the given id.
     */
    std::size_t getCount(const Id& id)
    { return count_[id.get()]; }

    /*!
     * \brief Returns the overall entity count.
     */
    std::size_t getCount()
    {
        return std::accumulate(count_.begin(),
                               count_.end(),
                               0,
                               [] (const auto& curCount, const auto& idCountPair)
                               { return curCount + idCountPair.second; });
    }

140
    /*!
141
     * \brief Print current status to terminal.
142
143
144
145
146
     */
    void print(bool forceHeaderPrint = false)
    {
        if (!headerPrinted_ || forceHeaderPrint)
        {
147
148
149
            std::cout << "#####################################################################################\n"
                      << "# Accepted count   |   Rejected count   |   Acceptance Ratio [%]   |   Progress [%] #\n"
                      << "#-----------------------------------------------------------------------------------#\n";
150
151
152
153
154
155
156
157
            headerPrinted_ = true;
        }

        std::size_t curCount = 0;
        std::size_t curTargetCount = 0;
        for (const auto& pair : count_) curCount += pair.second;
        for (const auto& pair : targetCount_) curTargetCount += pair.second;

158
        const auto ratio = 100.0*double(double(curCount)/double(curCount+rejectedCount_));
159
160
        const auto progress = 100.0*double(curCount)/double(curTargetCount);

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
        std::cout << std::setprecision(2) << std::fixed;
        const auto ratioNumChars = std::to_string(int(ratio)).size() + 3;
        const auto progressNumChars = std::to_string(int(progress)).size() + 3;

        const auto countString = std::to_string(curCount);
        const auto rejectedCountString = std::to_string(rejectedCount_);

        using std::max;
        const std::size_t zero = 0;
        const std::size_t paddingCount    = max(zero, 13 - countString.size());
        const std::size_t paddingRejected = max(zero, 13 - rejectedCountString.size());
        const std::size_t paddingRatio    = max(zero, 16 - ratioNumChars);
        const std::size_t paddingProgess  = max(zero, 8  - progressNumChars);

        std::cout << "  "      << std::string( paddingCount, ' ')    << countString + ' '
                  << "   |   " << std::string( paddingRejected, ' ') << rejectedCountString + ' '
                  << "   |   " << std::string( paddingRatio, ' ')    << ratio << std::string(4, ' ')
                  << "   |   " << std::string( paddingProgess, ' ')  << progress << std::endl;
179
180
181
182
183
184
185
186
187
188
189
190
    }

private:
    bool headerPrinted_ = false;
    std::size_t rejectedCount_ = 0;
    std::unordered_map<std::size_t, std::size_t> count_;
    std::unordered_map<std::size_t, std::size_t> targetCount_;
};

} // end namespace Frackit

#endif // FRACKIT_SAMPLING_STATUS_HH