2 #ifndef OPENGM_SWENDSENWANG_HXX
3 #define OPENGM_SWENDSENWANG_HXX
22 #include "opengm/inference/visitors/visitor.hxx"
28 namespace detail_swendsenwang {
29 template<
class OPERATOR,
class ACCUMULATOR,
class PROBABILITY>
30 struct ValueToProbability;
32 template<
class PROBABILITY>
33 struct ValueToProbability<Multiplier, Maximizer, PROBABILITY>
35 typedef PROBABILITY ProbabilityType;
37 static ProbabilityType convert(
const T x)
38 {
return static_cast<ProbabilityType
>(x); }
41 template<
class PROBABILITY>
42 struct ValueToProbability<Adder, Minimizer, PROBABILITY>
44 typedef PROBABILITY ProbabilityType;
46 static ProbabilityType convert(
const T x)
47 {
return static_cast<ProbabilityType
>(std::exp(-x)); }
58 void operator()(
const SwendsenWangType&,
const size_t,
const size_t,
59 const bool,
const bool)
const;
69 void operator()(
const SwendsenWangType&,
const size_t,
const size_t,
70 const bool,
const bool)
const;
78 typedef typename SwendsenWangType::ValueType
ValueType;
85 void assign(
const GraphicalModelType&);
88 template<
class VariableIndexIterator>
89 size_t addMarginal(VariableIndexIterator, VariableIndexIterator);
91 void operator()(
const SwendsenWangType&,
const size_t,
const size_t,
92 const bool,
const bool);
99 const IndependentFactorType&
marginal(
const size_t)
const;
102 const GraphicalModelType* gm_;
103 size_t numberOfSamples_;
104 size_t numberOfAcceptedSamples_;
105 size_t numberOfRejectedSamples_;
106 std::vector<IndependentFactorType> marginals_;
107 std::vector<typename GraphicalModelType::LabelType> stateCache_;
114 template<
class GM,
class ACC>
130 const size_t maxNumberOfSamplingSteps = 1e5,
131 const size_t numberOfBurnInSteps = 1e5,
132 ProbabilityType lowestAllowedProbability = 1e-6,
133 const std::vector<LabelType>& initialState = std::vector<LabelType>()
148 virtual std::string
name()
const;
150 virtual void reset();
152 template<
class VISITOR>
162 void computeEdgeProbabilities();
164 template<
bool BURNED_IN,
class VARIABLE_ITERATOR,
class STATE_ITERATOR>
165 bool move(VARIABLE_ITERATOR, VARIABLE_ITERATOR, STATE_ITERATOR);
168 const GraphicalModelType& gm_;
170 std::vector<RandomAccessSet<size_t> > variableAdjacency_;
171 std::vector<std::vector<ProbabilityType> > edgeProbabilities_;
172 std::vector<LabelType> currentBestState_;
176 template<
class GM,
class ACC>
186 variableAdjacency_(gm.numberOfVariables()),
187 edgeProbabilities_(gm.numberOfVariables()),
188 currentBestState_(gm.numberOfVariables()),
189 currentBestValue_(movemaker_.value())
191 if(parameter_.initialState_.size() != 0 && parameter_.initialState_.size() != gm.numberOfVariables()) {
192 throw RuntimeError(
"The size of the initial state does not match the number of variables.");
194 gm.variableAdjacencyList(variableAdjacency_);
195 for(
size_t j=0; j<gm_.numberOfVariables(); ++j) {
196 edgeProbabilities_[j].resize(variableAdjacency_[j].size());
198 computeEdgeProbabilities();
201 template<
class GM,
class ACC>
205 if(parameter_.initialState_.size() == gm_.numberOfVariables()) {
206 movemaker_.initialize(parameter_.initialState_.begin());
207 currentBestState_.assign(parameter_.initialState_.begin(),parameter_.initialState_.end());
209 else if(parameter_.initialState_.size() != 0) {
210 throw RuntimeError(
"The size of the initial state does not match the number of variables.");
214 std::fill(currentBestState_.begin(),currentBestState_.end(),0);
216 currentBestValue_ = movemaker_.value();
217 computeEdgeProbabilities();
220 template<
class GM,
class ACC>
224 return "SwendsenWang";
227 template<
class GM,
class ACC>
234 template<
class GM,
class ACC>
235 template<
class VISITOR>
243 std::vector<size_t> representatives(gm_.numberOfVariables());
244 std::vector<bool> visited(gm_.numberOfVariables());
245 std::stack<size_t> stack;
246 std::vector<size_t> variablesInCluster;
247 std::vector<size_t> variablesAroundCluster;
248 for(
size_t j=0; j<parameter_.numberOfBurnInSteps_ + parameter_.maxNumberOfSamplingSteps_; ++j) {
253 partition.representatives(representatives.begin());
254 RandomUniform<size_t> randomNumberGeneratorCluster(0, partition.numberOfSets());
255 const size_t representative = representatives[randomNumberGeneratorCluster()];
257 variablesInCluster.clear();
258 variablesAroundCluster.clear();
259 visited[representative] =
true;
260 stack.push(representative);
261 while(!stack.empty()) {
262 const size_t variable = stack.top();
264 variablesInCluster.push_back(variable);
265 for(
size_t k=0; k<variableAdjacency_[variable].size(); ++k) {
266 const size_t adjacentVariable = variableAdjacency_[variable][k];
267 if(!visited[adjacentVariable]) {
268 visited[adjacentVariable] =
true;
269 if(partition.find(adjacentVariable) == representative) {
270 stack.push(adjacentVariable);
273 variablesAroundCluster.push_back(adjacentVariable);
280 for(
size_t k=0; k<variablesInCluster.size(); ++k) {
281 visited[variablesInCluster[k]] =
false;
283 for(
size_t k=0; k<variablesAroundCluster.size(); ++k) {
284 visited[variablesAroundCluster[k]] =
false;
289 for(
size_t k=0; k<visited.size(); ++k) {
292 for(
size_t k=0; k<variablesInCluster.size(); ++k) {
293 OPENGM_ASSERT(gm_.numberOfLabels(variablesInCluster[k]) == gm_.numberOfLabels(representative));
298 RandomUniform<size_t> randomNumberGeneratorState(0, gm_.numberOfLabels(representative));
299 size_t targetLabel = randomNumberGeneratorState();
300 std::vector<size_t> targetLabels(variablesInCluster.size(), targetLabel);
302 if(j < parameter_.numberOfBurnInSteps_) {
303 move<false>(variablesInCluster.begin(), variablesInCluster.end(), targetLabels.begin());
304 visitor(*
this, j, variablesInCluster.size(),
true,
true);
309 const ProbabilityType currentPDF =
310 detail_swendsenwang::ValueToProbability<OperatorType, AccumulationType, ProbabilityType>::convert
311 (movemaker_.value());
312 const ProbabilityType targetPDF =
313 detail_swendsenwang::ValueToProbability<OperatorType, AccumulationType, ProbabilityType>::convert
314 (movemaker_.valueAfterMove(variablesInCluster.begin(), variablesInCluster.end(), targetLabels.begin()));
317 ProbabilityType currentValueProposal = 1;
318 ProbabilityType targetValueProposal = 1;
319 for(std::vector<size_t>::const_iterator vi = variablesAroundCluster.begin(); vi != variablesAroundCluster.end(); ++vi) {
320 if(movemaker_.state(*vi) == movemaker_.state(representative)) {
321 for(
size_t k=0; k<variableAdjacency_[*vi].size(); ++k) {
322 const size_t nvi = variableAdjacency_[*vi][k];
323 if(partition.find(nvi) == representative) {
324 currentValueProposal *= (1.0 - edgeProbabilities_[*vi][k]);
328 else if(movemaker_.state(*vi) == targetLabel) {
329 for(
size_t k=0; k<variableAdjacency_[*vi].size(); ++k) {
330 const size_t nvi = variableAdjacency_[*vi][k];
331 if(partition.find(nvi) == representative) {
332 targetValueProposal *= (1.0 - edgeProbabilities_[*vi][k]);
339 const ProbabilityType metropolisHastingsProbability = (targetValueProposal / currentValueProposal) * (targetPDF / currentPDF);
341 if(metropolisHastingsProbability >= 1) {
342 move<true>(variablesInCluster.begin(), variablesInCluster.end(), targetLabels.begin());
343 visitor(*
this, j, variablesInCluster.size(),
true,
false);
346 RandomUniform<ProbabilityType> randomNumberGeneratorAcceptance(0, 1);
347 if(metropolisHastingsProbability >= randomNumberGeneratorAcceptance()) {
348 move<true>(variablesInCluster.begin(), variablesInCluster.end(), targetLabels.begin());
349 visitor(*
this, j, variablesInCluster.size(),
true,
false);
352 visitor(*
this, j, variablesInCluster.size(),
false,
false);
360 template<
class GM,
class ACC>
364 EmptyVisitorType visitor;
365 return infer(visitor);
368 template<
class GM,
class ACC>
372 std::vector<LabelType>& x,
376 x = currentBestState_;
384 template<
class GM,
class ACC>
392 return movemaker_.state(j);
395 template<
class GM,
class ACC>
399 return movemaker_.value();
402 template<
class GM,
class ACC>
410 return currentBestState_[j];
413 template<
class GM,
class ACC>
417 return currentBestValue_;
420 template<
class GM,
class ACC>
421 template<
bool BURNED_IN,
class VARIABLE_ITERATOR,
class STATE_ITERATOR>
424 VARIABLE_ITERATOR begin,
425 VARIABLE_ITERATOR end,
429 movemaker_.move(begin, end, it);
431 if(ACC::bop(movemaker_.value(), currentBestValue_)) {
432 currentBestValue_ = movemaker_.value();
433 std::copy(movemaker_.stateBegin(), movemaker_.stateEnd(), currentBestState_.begin());
440 template<
class GM,
class ACC>
442 SwendsenWang<GM, ACC>::computeEdgeProbabilities()
444 std::set<size_t> factors;
445 std::set<size_t> connectedVariables;
446 size_t variables[] = {0, 0};
447 for(variables[0] = 0; variables[0] < gm_.numberOfVariables(); ++variables[0]) {
448 for(
size_t j = 0; j < variableAdjacency_[variables[0]].size(); ++j) {
449 variables[1] = variableAdjacency_[variables[0]][j];
450 if(gm_.numberOfLabels(variables[0]) == gm_.numberOfLabels(variables[1])) {
456 connectedVariables.clear();
459 for(
size_t k = 0; k < 2; ++k) {
460 for(
typename GraphicalModelType::ConstFactorIterator it = gm_.factorsOfVariableBegin(variables[k]);
461 it != gm_.factorsOfVariableEnd(variables[k]); ++it) {
463 for(
size_t m = 0; m < gm_[*it].numberOfVariables(); ++m) {
464 connectedVariables.insert(gm_[*it].variableIndex(m));
486 IndependentFactorType localFactor(gm_,
487 connectedVariables.begin(),
488 connectedVariables.end(),
489 OperatorType::template neutral<ValueType>());
490 for(std::set<size_t>::const_iterator it = factors.begin(); it != factors.end(); ++it) {
491 OperatorType::op(gm_[*it], localFactor);
495 size_t indices[] = {0, 0};
496 for(
size_t k = 0; k < localFactor.numberOfVariables(); ++k) {
497 if(localFactor.variableIndex(k) == variables[0]) {
500 else if(localFactor.variableIndex(k) == variables[1]) {
504 ProbabilityType probEqual = 0;
505 ProbabilityType probUnequal = 0;
506 ShapeWalker< typename IndependentFactorType::ShapeIteratorType>
507 walker(localFactor.shapeBegin(), localFactor.numberOfVariables());
508 for(
size_t k = 0; k < localFactor.size(); ++k, ++walker) {
509 const ValueType value = localFactor(walker.coordinateTuple().begin());
510 const ProbabilityType p = detail_swendsenwang::ValueToProbability<OperatorType, AccumulationType, ProbabilityType>::convert(value);
511 if(walker.coordinateTuple()[indices[0]] == walker.coordinateTuple()[indices[1]]) {
520 ProbabilityType sum = probEqual + probUnequal;
522 throw RuntimeError(
"Some local probabilities are exactly zero.");
526 if(probEqual < parameter_.lowestAllowedProbability_ || probUnequal < parameter_.lowestAllowedProbability_) {
527 throw RuntimeError(
"Marginal probabilities are smaller than the allowed minimum.");
530 edgeProbabilities_[variables[0]][j] = probUnequal;
536 template<
class GM,
class ACC>
538 SwendsenWang<GM, ACC>::cluster
540 Partition<size_t>& out
544 out.reset(gm_.numberOfVariables());
545 opengm::RandomUniform<ProbabilityType> randomNumberGenerator(0.0, 1.0);
546 size_t variables[] = {0, 0};
547 for(variables[0] = 0; variables[0] < gm_.numberOfVariables(); ++variables[0]) {
548 for(
size_t j = 0; j < variableAdjacency_[variables[0]].size(); ++j) {
549 variables[1] = variableAdjacency_[variables[0]][j];
550 if(variables[0] < variables[1]) {
551 if(movemaker_.state(variables[0]) == movemaker_.state(variables[1])) {
552 if(edgeProbabilities_[variables[0]][j] > randomNumberGenerator()) {
554 out.merge(variables[0], variables[1]);
566 const size_t iteration,
567 const size_t clusterSize,
577 const size_t iteration,
578 const size_t clusterSize,
582 std::cout <<
"Step " << iteration
583 <<
": " <<
"V_opt=" << sw.currentBestValue()
584 <<
", " <<
"V_markov=" << sw.markovValue()
585 <<
", " <<
"cs=" << clusterSize
586 <<
", " << (accepted ?
"accepted" :
"rejected")
587 <<
", " << (burningIn ?
"burning in" :
"sampling")
606 numberOfAcceptedSamples_(0),
607 numberOfRejectedSamples_(0),
619 numberOfAcceptedSamples_(0),
620 numberOfRejectedSamples_(0),
638 const size_t iteration,
639 const size_t clusterSize,
646 ++numberOfAcceptedSamples_;
649 ++numberOfRejectedSamples_;
651 for(
size_t j = 0; j < marginals_.size(); ++j) {
652 for(
size_t k = 0; k < marginals_[j].numberOfVariables(); ++k) {
653 stateCache_[k] = sw.markovState(marginals_[j].variableIndex(k));
655 ++marginals_[j](stateCache_.begin());
661 template<
class VariableIndexIterator>
664 VariableIndexIterator begin,
665 VariableIndexIterator end
668 if(marginals_.back().numberOfVariables() > stateCache_.size()) {
669 stateCache_.resize(marginals_.back().numberOfVariables());
671 return marginals_.size() - 1;
677 const size_t variableIndex
679 size_t variableIndices[] = {variableIndex};
680 return addMarginal(variableIndices, variableIndices + 1);
686 return numberOfSamples_;
692 return numberOfAcceptedSamples_;
698 return numberOfRejectedSamples_;
704 return marginals_.size();
710 const size_t setIndex
712 return marginals_[setIndex];
717 #endif // #ifndef OPENGM_SWENDSENWANG_HXX
void operator()(const SwendsenWangType &, const size_t, const size_t, const bool, const bool) const
size_t numberOfRejectedSamples() const
void operator()(const SwendsenWangType &, const size_t, const size_t, const bool, const bool) const
virtual std::string name() const
const IndependentFactorType & marginal(const size_t) const
virtual InferenceTermination infer()
TimingVisitor< SwendsenWang< GM, ACC > > TimingVisitorType
Generalized Swendsen-Wang sampling A. Barbu, S. Zhu, "Generalizing swendsen-wang to sampling arbitra...
size_t numberOfMarginals() const
std::vector< LabelType > initialState_
#define OPENGM_ASSERT(expression)
ValueType currentBestValue() const
size_t numberOfAcceptedSamples() const
SwendsenWangType::GraphicalModelType GraphicalModelType
SwendsenWangType::ValueType ValueType
LabelType markovState(const size_t) const
SwendsenWangVerboseVisitor< SwendsenWang< GM, ACC > > VerboseVisitorType
size_t numberOfSamples() const
LabelType currentBestState(const size_t) const
SwendsenWangEmptyVisitor< SwendsenWang< GM, ACC > > EmptyVisitorType
size_t numberOfBurnInSteps_
GraphicalModelType::ValueType ValueType
Inference algorithm interface.
GraphicalModelType::IndependentFactorType IndependentFactorType
virtual const GraphicalModelType & graphicalModel() const
size_t addMarginal(VariableIndexIterator, VariableIndexIterator)
ValueType markovValue() const
void assign(const GraphicalModelType &)
void operator()(const SwendsenWangType &, const size_t, const size_t, const bool, const bool)
SwendsenWang(const GraphicalModelType &, const Parameter ¶m=Parameter())
Disjoint set data structure with path compression.
SwendsenWangMarginalVisitor()
Parameter(const size_t maxNumberOfSamplingSteps=1e5, const size_t numberOfBurnInSteps=1e5, ProbabilityType lowestAllowedProbability=1e-6, const std::vector< LabelType > &initialState=std::vector< LabelType >())
GraphicalModelType::LabelType LabelType
size_t maxNumberOfSamplingSteps_
ProbabilityType lowestAllowedProbability_
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution