Mercurial > hg > silvet
diff src/AgentHypothesis.h @ 181:10e7c3ff575e noteagent
Experimental branch toward note-agent stuff (not actually plumbed in yet)
author | Chris Cannam |
---|---|
date | Fri, 23 May 2014 12:40:18 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/AgentHypothesis.h Fri May 23 12:40:18 2014 +0100 @@ -0,0 +1,146 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Silvet + + A Vamp plugin for note transcription. + Centre for Digital Music, Queen Mary University of London. + This file Copyright 2012 Chris Cannam. + + 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 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef AGENT_HYPOTHESIS_H +#define AGENT_HYPOTHESIS_H + +#include "vamp-sdk/RealTime.h" + +#include <set> +#include <map> + +/** + * An agent used to test an incoming series of timed observations or + * estimates to see whether they fit a consistent single-object + * relationship. + * + * A freshly constructed hypothesis object should be in New state and + * should accept any observation. + */ + +class AgentHypothesis +{ +public: + virtual ~AgentHypothesis() { } + + enum State { + + /// Just constructed, will provisionally accept any observation + New, + + /// Accepted at least one observation, but not enough evidence to satisfy + Provisional, + + /// Could not find enough consistency in offered observations + Rejected, + + /// Have accepted enough consistent observations to satisfy hypothesis + Satisfied, + + /// Have been satisfied, but evidence has now changed: we're done + Expired + }; + + struct Observation { + + Observation() : value(0), time(), confidence(1) { } + + Observation(double _f, Vamp::RealTime _t, double _c) : + value(_f), time(_t), confidence(_c) { } + + bool operator==(const Observation &o) const { + return o.value == value && o.time == time && o.confidence == confidence; + } + bool operator<(const Observation &o) const { + return + (time < o.time || + (time == o.time && value < o.value) || + (time == o.time && value == o.value && confidence < o.confidence)); + } + + double value; + Vamp::RealTime time; + double confidence; + }; + typedef std::set<Observation> Observations; + + /** + * Test the given observation to see whether it is consistent with + * this hypothesis, and adjust the hypothesis' internal state + * accordingly. If the observation is not inconsistent with the + * hypothesis, return true. + *!!! should be called e.g. test? + */ + virtual bool accept(Observation) = 0; + + /** + * Return the current state of this hypothesis. + */ + virtual State getState() const = 0; + + /** + * If the hypothesis has been satisfied (i.e. is in Satisfied or + * Expired state), return the set of observations that it + * accepted. Otherwise return an empty set + */ + virtual Observations getAcceptedObservations() const = 0; + + /** + * Convert the given set of accepted hypotheses (of type + * subclassed from AgentHypothesis) into a flattened set of their + * accepted observations. + * + * That is, only one is included for at any given moment, so in + * the case of overlapping hypotheses, the observations for the + * earlier are taken until the next hypothesis begins and then the + * latter's observations begin instead. + * + * (If there are gaps between hypotheses, the gaps remain in the + * output.) + */ + template <typename HypothesisType> + static Observations flatten(const std::set<HypothesisType> &agents) { + + typedef typename std::set<HypothesisType>::const_iterator Itr; + Observations flattened; + + if (agents.empty()) return flattened; + Observations obs = agents.begin()->getAcceptedObservations(); + + for (Itr i = agents.begin(); i != agents.end(); ++i) { + + Itr j = i; + ++j; + + Observations nextObs; + if (j != agents.end()) nextObs = j->getAcceptedObservations(); + + for (Observations::const_iterator i = obs.begin(); + i != obs.end(); ++i) { + if (!nextObs.empty() && i->time >= nextObs.begin()->time) { + break; + } + flattened.insert(*i); + } + + obs = nextObs; + } + + return flattened; + } +}; + +#endif