annotate src/AgentFeederPoly.h @ 182:e1718e64a921 noteagent

Remove some irrelevant code
author Chris Cannam
date Fri, 23 May 2014 17:03:27 +0100
parents 10e7c3ff575e
children 9b9cdfccbd14
rev   line source
Chris@181 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@181 2
Chris@181 3 /*
Chris@181 4 Silvet
Chris@181 5
Chris@181 6 A Vamp plugin for note transcription.
Chris@181 7 Centre for Digital Music, Queen Mary University of London.
Chris@181 8 This file Copyright 2012 Chris Cannam.
Chris@181 9
Chris@181 10 This program is free software; you can redistribute it and/or
Chris@181 11 modify it under the terms of the GNU General Public License as
Chris@181 12 published by the Free Software Foundation; either version 2 of the
Chris@181 13 License, or (at your option) any later version. See the file
Chris@181 14 COPYING included with this distribution for more information.
Chris@181 15 */
Chris@181 16
Chris@181 17 #ifndef AGENT_FEEDER_POLY_H
Chris@181 18 #define AGENT_FEEDER_POLY_H
Chris@181 19
Chris@181 20 #include "AgentFeeder.h"
Chris@181 21
Chris@181 22 #include <cassert>
Chris@181 23
Chris@181 24 //#define DEBUG_FEEDER 1
Chris@181 25
Chris@181 26 /**
Chris@181 27 * Take a series of observations or estimates (one at a time) and feed
Chris@181 28 * them to a set of agent hypotheses, creating a new candidate agent
Chris@181 29 * for each observation and also testing the observation against the
Chris@181 30 * existing set of hypotheses.
Chris@181 31 *
Chris@181 32 *!!! -- todo: document poly-ness of it
Chris@181 33 *
Chris@181 34 * Call feed() to provide a new observation. Call finish() when all
Chris@181 35 * observations have been provided. The set of hypotheses returned by
Chris@181 36 * getAcceptedHypotheses() will not be complete unless finish() has
Chris@181 37 * been called.
Chris@181 38 */
Chris@181 39 template <typename Hypothesis>
Chris@181 40 class AgentFeederPoly : public AgentFeeder
Chris@181 41 {
Chris@181 42 public:
Chris@181 43 typedef std::set<Hypothesis> Hypotheses;
Chris@181 44
Chris@181 45 private:
Chris@181 46 struct State {
Chris@181 47 Hypotheses provisional;
Chris@181 48 Hypotheses satisfied;
Chris@181 49 Hypotheses completed;
Chris@181 50 };
Chris@181 51 State m_state;
Chris@181 52
Chris@181 53 public:
Chris@181 54 AgentFeederPoly() { }
Chris@181 55
Chris@181 56 virtual void feed(AgentHypothesis::Observation o) {
Chris@181 57 #ifdef DEBUG_FEEDER
Chris@181 58 std::cerr << "feed: have observation [value = " << o.value << ", time = " << o.time << "]" << std::endl;
Chris@181 59 #endif
Chris@181 60
Chris@181 61 update(m_state, o);
Chris@181 62 }
Chris@181 63
Chris@181 64 virtual void finish() {
Chris@181 65 #ifdef DEBUG_FEEDER
Chris@181 66 std::cerr << "finish: satisfied count == " << m_state.satisfied.size() << std::endl;
Chris@181 67 #endif
Chris@181 68 for (typename Hypotheses::const_iterator i = m_state.satisfied.begin();
Chris@181 69 i != m_state.satisfied.end(); ++i) {
Chris@181 70 m_state.completed.insert(*i);
Chris@181 71 }
Chris@181 72 }
Chris@181 73
Chris@181 74 Hypotheses getAcceptedHypotheses() const {
Chris@181 75 return m_state.completed;
Chris@181 76 }
Chris@181 77
Chris@181 78 private:
Chris@181 79 void update(State &s, AgentHypothesis::Observation o) {
Chris@181 80
Chris@181 81 /*
Chris@181 82 An observation can "belong" to any number of provisional
Chris@181 83 hypotheses, but only to one satisfied hypothesis.
Chris@181 84
Chris@181 85 A new observation is first offered to the hypotheses that
Chris@181 86 have already been satisfied. If one of these accepts it, it
Chris@181 87 gets to keep it and no other hypothesis can have it.
Chris@181 88
Chris@181 89 Any observation not accepted by a hypothesis in satisfied
Chris@181 90 state is then offered to the provisional hypotheses; any
Chris@181 91 number of these may accept it. Also, every observation that
Chris@181 92 belongs to no satisfied hypothesis is used as the first
Chris@181 93 observation in its own new hypothesis (regardless of how
Chris@181 94 many other provisional hypotheses have accepted it).
Chris@181 95
Chris@181 96 When a hypothesis subsequently becomes satisfied, all other
Chris@181 97 provisional hypotheses containing any of its observations
Chris@181 98 must be discarded.
Chris@181 99 */
Chris@181 100
Chris@181 101 // We only ever add to the completed hypotheses, never remove
Chris@181 102 // anything from them. But we may remove from provisional (if
Chris@181 103 // rejected or transferred to satisfied) and satisfied (when
Chris@181 104 // completed).
Chris@181 105
Chris@181 106 Hypotheses toCompleted;
Chris@181 107 Hypotheses toSatisfied;
Chris@181 108 Hypotheses toProvisional;
Chris@181 109
Chris@181 110 bool swallowed = false;
Chris@181 111
Chris@181 112 for (typename Hypotheses::iterator i = s.satisfied.begin();
Chris@181 113 i != s.satisfied.end(); ++i) {
Chris@181 114
Chris@181 115 Hypothesis h = *i;
Chris@181 116
Chris@181 117 assert(h.getState() == Hypothesis::Satisfied);
Chris@181 118
Chris@181 119 if (swallowed) {
Chris@181 120
Chris@181 121 // An observation that has already been accepted by a
Chris@181 122 // hypothesis cannot be offered to any other, because
Chris@181 123 // it can only belong to one satisfied hypothesis. Any
Chris@181 124 // subsequent satisfied hypotheses are retained
Chris@181 125 // unchanged in our updated state. We can't test them
Chris@181 126 // for expiry, because the state is only updated when
Chris@181 127 // accept() is called.
Chris@181 128 //!!! That looks like a limitation in the Hypothesis API
Chris@181 129
Chris@181 130 } else { // !swallowed
Chris@181 131
Chris@181 132 if (h.accept(o)) {
Chris@181 133 #ifdef DEBUG_FEEDER
Chris@181 134 std::cerr << "accepted by satisfied hypothesis " << &(*i) << ", state is " << h.getState() << std::endl;
Chris@181 135 #endif
Chris@181 136 swallowed = true;
Chris@181 137 } else if (h.getState() == Hypothesis::Expired) {
Chris@181 138 toCompleted.insert(h);
Chris@181 139 }
Chris@181 140 }
Chris@181 141 }
Chris@181 142
Chris@181 143 if (swallowed) {
Chris@181 144
Chris@181 145 #ifdef DEBUG_FEEDER
Chris@181 146 std::cerr << "was swallowed by satisfied hypothesis" << std::endl;
Chris@181 147 #endif
Chris@181 148 // no provisional hypotheses have become satisfied, no new
Chris@181 149 // ones have been introduced
Chris@181 150
Chris@181 151 } else {
Chris@181 152
Chris@181 153 #ifdef DEBUG_FEEDER
Chris@181 154 std::cerr << "remained unswallowed by " << newState.satisfied.size() << " satisfied hypotheses" << std::endl;
Chris@181 155 #endif
Chris@181 156
Chris@181 157 // not swallowed by any satisfied hypothesis
Chris@181 158
Chris@181 159 Hypothesis promoted;
Chris@181 160
Chris@181 161 for (typename Hypotheses::iterator i = s.provisional.begin();
Chris@181 162 i != s.provisional.end(); ++i) {
Chris@181 163
Chris@181 164 Hypothesis h = *i;
Chris@181 165
Chris@181 166 assert(h.getState() == Hypothesis::Provisional);
Chris@181 167
Chris@181 168 // can only have one satisfied hypothesis for each
Chris@181 169 // observation, so try this only if promoted has not been
Chris@181 170 // set to something else yet
Chris@181 171 if (promoted == Hypothesis() &&
Chris@181 172 h.accept(o) &&
Chris@181 173 h.getState() == Hypothesis::Satisfied) {
Chris@181 174 toSatisfied.insert(h);
Chris@181 175 #ifdef DEBUG_FEEDER
Chris@181 176 std::cerr << "promoting a hypothesis to satisfied, have " << newState.satisfied.size() << " satisfied now" << std::endl;
Chris@181 177 #endif
Chris@181 178 promoted = h;
Chris@181 179 } else if (h.getState() != Hypothesis::Rejected) {
Chris@181 180 // leave as provisional
Chris@181 181 }
Chris@181 182 }
Chris@181 183
Chris@181 184 if (promoted == Hypothesis()) {
Chris@181 185
Chris@181 186 // No provisional hypothesis has become satisfied
Chris@181 187
Chris@181 188 Hypothesis h;
Chris@181 189 h.accept(o);
Chris@181 190
Chris@181 191 if (h.getState() == Hypothesis::Provisional) {
Chris@181 192 toProvisional.insert(h);
Chris@181 193 } else if (h.getState() == Hypothesis::Satisfied) {
Chris@181 194 toSatisfied.insert(h);
Chris@181 195 }
Chris@181 196
Chris@181 197 #ifdef DEBUG_FEEDER
Chris@181 198 std::cerr << "update: new hypothesis of state " << h.getState() << ", provisional count -> " << newState.provisional.size() << std::endl;
Chris@181 199 #endif
Chris@181 200
Chris@181 201 }
Chris@181 202 }
Chris@181 203
Chris@181 204 for (typename Hypotheses::const_iterator i = toCompleted.begin();
Chris@181 205 i != toCompleted.end(); ++i) {
Chris@181 206 s.satisfied.erase(*i);
Chris@181 207 s.completed.insert(*i);
Chris@181 208 }
Chris@181 209 for (typename Hypotheses::const_iterator i = toSatisfied.begin();
Chris@181 210 i != toSatisfied.end(); ++i) {
Chris@181 211 s.provisional.erase(*i);
Chris@181 212 s.satisfied.insert(*i);
Chris@181 213 }
Chris@181 214 for (typename Hypotheses::const_iterator i = toProvisional.begin();
Chris@181 215 i != toProvisional.end(); ++i) {
Chris@181 216 s.provisional.insert(*i);
Chris@181 217 }
Chris@181 218
Chris@181 219 reap(s);
Chris@181 220 }
Chris@181 221
Chris@181 222 void reap(State &s) {
Chris@181 223
Chris@181 224 // "When a hypothesis subsequently becomes satisfied, all
Chris@181 225 // other provisional hypotheses containing any of its
Chris@181 226 // observations must be discarded."
Chris@181 227
Chris@181 228 if (s.provisional.empty()) return;
Chris@181 229
Chris@181 230 int reaped = 0;
Chris@181 231
Chris@181 232 Hypotheses toRemove = Hypotheses();;
Chris@181 233
Chris@181 234 for (typename Hypotheses::const_iterator hi = s.provisional.begin();
Chris@181 235 hi != s.provisional.end(); ++hi) {
Chris@181 236
Chris@181 237 const AgentHypothesis::Observations obs =
Chris@181 238 hi->getAcceptedObservations();
Chris@181 239
Chris@181 240 bool keep = true;
Chris@181 241
Chris@181 242 for (AgentHypothesis::Observations::const_iterator oi = obs.begin();
Chris@181 243 oi != obs.end(); ++oi) {
Chris@181 244
Chris@181 245 for (typename Hypotheses::const_iterator si = s.satisfied.end();
Chris@181 246 si != s.satisfied.begin(); ) {
Chris@181 247
Chris@181 248 --si;
Chris@181 249
Chris@181 250 const AgentHypothesis::Observations sobs =
Chris@181 251 si->getAcceptedObservations();
Chris@181 252
Chris@181 253 if (sobs.find(*oi) != sobs.end()) {
Chris@181 254 keep = false;
Chris@181 255 break;
Chris@181 256 }
Chris@181 257 }
Chris@181 258
Chris@181 259 if (!keep) {
Chris@181 260 break;
Chris@181 261 }
Chris@181 262 }
Chris@181 263
Chris@181 264 if (!keep) {
Chris@181 265 toRemove.insert(*hi);
Chris@181 266 ++reaped;
Chris@181 267 }
Chris@181 268 }
Chris@181 269
Chris@181 270 for (typename Hypotheses::const_iterator i = toRemove.begin();
Chris@181 271 i != toRemove.end(); ++i) {
Chris@181 272 s.provisional.erase(i);
Chris@181 273 }
Chris@181 274
Chris@181 275 #ifdef DEBUG_FEEDER
Chris@181 276 std::cerr << "reap: have "
Chris@181 277 << s.satisfied.size() << " satisfied, "
Chris@181 278 << s.provisional.size() << " provisional, "
Chris@181 279 << s.completed.size() << " completed, reaped "
Chris@181 280 << reaped << std::endl;
Chris@181 281 #endif
Chris@181 282 }
Chris@181 283 };
Chris@181 284
Chris@181 285 #endif