Просмотр исходного кода

moved mrf from objrec to vislearning

Bjoern Froehlich 12 лет назад
Родитель
Сommit
34cd27cb20

+ 136 - 136
classifier/classifiercombination/VCPreRandomForest.cpp

@@ -1,4 +1,4 @@
-/** 
+/**
 * @file VCPreRandomForest.cpp
 * @brief Combination of a classifier with a pre-clustering using a random forest
 * @author Erik Rodner
@@ -21,164 +21,164 @@ using namespace NICE;
 
 
 VCPreRandomForest::VCPreRandomForest( const Config *conf, const std::string & section, VecClassifier *_leafClassifierPrototype )
-	: leafClassifierPrototype(_leafClassifierPrototype), fp(conf)
+    : leafClassifierPrototype(_leafClassifierPrototype), fp(conf)
 {
-	string cluster_section = conf->gS(section, "cluster_section", "RandomForest");
-	mEx = conf->gI("DTBRandom", "min_examples", numeric_limits<int>::max());
-	mEx = 500;
-	randomforest = new FPCRandomForests ( conf, cluster_section );
+  string cluster_section = conf->gS(section, "cluster_section", "RandomForest");
+  mEx = conf->gI("DTBRandom", "min_examples", numeric_limits<int>::max());
+  mEx = 500;
+  randomforest = new FPCRandomForests ( conf, cluster_section );
 }
-  
+
 VCPreRandomForest::~VCPreRandomForest()
 {
-	// delete the random forest
-	if ( randomforest != NULL )
-		delete randomforest;
-
-	// delete all classifiers in the leafs
-	for ( map<DecisionNode *, VecClassifier *>::const_iterator i = leafClassifiers.begin();
-		i != leafClassifiers.end(); i++ )
-	{
-		VecClassifier *lc = i->second;
-		delete lc;
-	}
+  // delete the random forest
+  if ( randomforest != NULL )
+    delete randomforest;
+
+  // delete all classifiers in the leafs
+  for ( map<DecisionNode *, VecClassifier *>::const_iterator i = leafClassifiers.begin();
+        i != leafClassifiers.end(); i++ )
+  {
+    VecClassifier *lc = i->second;
+    delete lc;
+  }
 }
 
 ClassificationResult VCPreRandomForest::classify ( const NICE::Vector & x ) const
 {
-	NICE::Vector *v = new NICE::Vector(x);
-	Example example(v);
-
-	vector<DecisionNode *> leafNodes;
-	
-	// traverse the forest and obtain all involved leaf nodes
-	randomforest->getLeafNodes(example, leafNodes);
-
-	ClassificationResult r ( ClassificationResult::REJECTION_NONE, maxClassNo );
-	r.scores.set(0.0);
-
-	for ( vector<DecisionNode *>::const_iterator i = leafNodes.begin();
-		i != leafNodes.end(); i++ )
-	{
-		DecisionNode *node = *i;
-		map<DecisionNode *, VecClassifier *>::const_iterator leafClassifierIt = 
-				leafClassifiers.find ( node );
-
-		if ( leafClassifierIt == leafClassifiers.end() ) {
-			// this leaf has no associated classifier
-			// -> we will use the random forest "score" :)
-			//
-			double sum = node->distribution.sum();
-			for(uint k = 0; k < (uint)std::min(node->distribution.size(), r.scores.size());k++)
-			{
-				r.scores[k] += node->distribution[k] / sum;
-			}
-
-			//fthrow(Exception, "Unable to find this leaf node !! (implementation bug)");
-			continue;
-		}
-		
-		VecClassifier *leafClassifier = leafClassifierIt->second;
-		ClassificationResult rSingle = leafClassifier->classify ( x );
-
-		rSingle.scores.normalize();
-		for(uint k = 0; k < (uint)std::min(rSingle.scores.size(), r.scores.size());k++)
-		{
-			r.scores[k] += rSingle.scores[k];	
-		}
-	}
-
-	r.scores.multiply ( 1.0/(leafNodes.size()) );
-	r.classno = r.scores.maxElement();
-
-	if ( fabs(r.scores.sum() - 1.0) > 1e-2 )
-	{
-		//fthrow(Exception, "Ups !\n");
-		r.scores[0] = 1.0;
-	}
-
-	example.clean();
-
-	return r;
+  NICE::Vector *v = new NICE::Vector(x);
+  Example example(v);
+
+  vector<DecisionNode *> leafNodes;
+
+  // traverse the forest and obtain all involved leaf nodes
+  randomforest->getLeafNodes(example, leafNodes);
+
+  ClassificationResult r ( ClassificationResult::REJECTION_NONE, maxClassNo );
+  r.scores.set(0.0);
+
+  for ( vector<DecisionNode *>::const_iterator i = leafNodes.begin();
+        i != leafNodes.end(); i++ )
+  {
+    DecisionNode *node = *i;
+    map<DecisionNode *, VecClassifier *>::const_iterator leafClassifierIt =
+      leafClassifiers.find ( node );
+
+    if ( leafClassifierIt == leafClassifiers.end() ) {
+      // this leaf has no associated classifier
+      // -> we will use the random forest "score" :)
+      //
+      double sum = node->distribution.sum();
+      for (uint k = 0; k < (uint)std::min(node->distribution.size(), r.scores.size());k++)
+      {
+        r.scores[k] += node->distribution[k] / sum;
+      }
+
+      //fthrow(Exception, "Unable to find this leaf node !! (implementation bug)");
+      continue;
+    }
+
+    VecClassifier *leafClassifier = leafClassifierIt->second;
+    ClassificationResult rSingle = leafClassifier->classify ( x );
+
+    rSingle.scores.normalize();
+    for (uint k = 0; k < (uint)std::min(rSingle.scores.size(), r.scores.size());k++)
+    {
+      r.scores[k] += rSingle.scores[k];
+    }
+  }
+
+  r.scores.multiply ( 1.0 / (leafNodes.size()) );
+  r.classno = r.scores.maxElement();
+
+  if ( fabs(r.scores.sum() - 1.0) > 1e-2 )
+  {
+    //fthrow(Exception, "Ups !\n");
+    r.scores[0] = 1.0;
+  }
+
+  example.clean();
+
+  return r;
 }
 
 void VCPreRandomForest::teach ( const LabeledSetVector & teachSet )
 {
-	Examples examples;
-	maxClassNo = teachSet.getMaxClassno();
-
-	LOOP_ALL(teachSet)
-	{
-		EACH(classno, x);
-		NICE::Vector *v = new Vector(x);
-		examples.push_back(	pair<int, Example> (classno, Example(v)));
-	}
-
-	uint dimension = teachSet.dimension();
-	fp.clear();
-	Feature *f = new VectorFeature(dimension);
-	f->explode(fp);
-
-	// train the forest
-	randomforest->setMaxClassNo( teachSet.getMaxClassno()  );
-	randomforest->train ( fp, examples );
-	// free some useless memory, we do not need this
-	// data structure any more
-	examples.clean();
-	
-	vector<DecisionNode *> leafNodes;
-	randomforest->getAllLeafNodes ( leafNodes );
-	
-	int lsize = leafNodes.size();
-	cout << "leafnodes: " << lsize << endl;
-	int leafNo = 0;
+  Examples examples;
+  maxClassNo = teachSet.getMaxClassno();
+
+  LOOP_ALL(teachSet)
+  {
+    EACH(classno, x);
+    NICE::Vector *v = new Vector(x);
+    examples.push_back( pair<int, Example> (classno, Example(v)));
+  }
+
+  uint dimension = teachSet.dimension();
+  fp.clear();
+  Feature *f = new VectorFeature(dimension);
+  f->explode(fp);
+
+  // train the forest
+  randomforest->setMaxClassNo( teachSet.getMaxClassno()  );
+  randomforest->train ( fp, examples );
+  // free some useless memory, we do not need this
+  // data structure any more
+  examples.clean();
+
+  vector<DecisionNode *> leafNodes;
+  randomforest->getAllLeafNodes ( leafNodes );
+
+  int lsize = leafNodes.size();
+  cout << "leafnodes: " << lsize << endl;
+  int leafNo = 0;
 #pragma omp parallel for
-	for ( int l = 0; l < lsize; l++)
-	{
-		cerr << "Training classifier for leaf " << leafNo << endl;
-		leafNo++;
+  for ( int l = 0; l < lsize; l++)
+  {
+    cerr << "Training classifier for leaf " << leafNo << endl;
+    leafNo++;
+
+    DecisionNode *node = leafNodes[l];
 
-		DecisionNode *node = leafNodes[l];
+    if ( node->distribution.entropy() <= 0.0) continue;
+    if ( ! node->isLeaf() ) continue;
 
-		if ( node->distribution.entropy() <= 0.0) continue;
-		if ( ! node->isLeaf() ) continue;
+    vector<int> examplesSet = node->trainExamplesIndices;
+    assert(examplesSet.size() > 0);
 
-		vector<int> examplesSet = node->trainExamplesIndices;
-		assert(examplesSet.size() > 0);
+    sort (examplesSet.begin(), examplesSet.end());
 
-		sort (examplesSet.begin(), examplesSet.end());
+    LabeledSetVector trainSubSet;
 
-		LabeledSetVector trainSubSet;
+    vector<double> counter(maxClassNo, 0.0);
+    uint exampleIndex = 0;
+    uint c = 0;
 
-		vector<double> counter(maxClassNo,0.0);
-		uint exampleIndex = 0;
-		uint c = 0;
+    LOOP_ALL(teachSet)
+    {
+      EACH(classno, x);
+      if ( examplesSet[c] == exampleIndex )
+      {
+        c++;
+        trainSubSet.add ( classno, x );
+      }
+      exampleIndex++;
+    }
 
-		LOOP_ALL(teachSet)
-		{
-			EACH(classno, x);
-			if ( examplesSet[c] == exampleIndex )
-			{
-				c++;
-				trainSubSet.add ( classno, x );
-			}
-			exampleIndex++;
-		}
-		
-		VecClassifier *lc = leafClassifierPrototype->clone();
+    VecClassifier *lc = leafClassifierPrototype->clone();
 
-		lc->teach ( trainSubSet );
+    lc->teach ( trainSubSet );
 
-		leafClassifiers.insert ( pair<DecisionNode *, VecClassifier *> ( node, lc ) );
-	}	
+    leafClassifiers.insert ( pair<DecisionNode *, VecClassifier *> ( node, lc ) );
+  }
 }
 
 void VCPreRandomForest::clear()
 {
-	map<DecisionNode *, VecClassifier *>::iterator iter;
-	for( iter = leafClassifiers.begin(); iter != leafClassifiers.end(); ++iter ) 
-	{
-		iter->second->clear();
-	}
-	randomforest->clear();
-}
+  map<DecisionNode *, VecClassifier *>::iterator iter;
+  for ( iter = leafClassifiers.begin(); iter != leafClassifiers.end(); ++iter )
+  {
+    iter->second->clear();
+  }
+  randomforest->clear();
+}

+ 8 - 0
mrf/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
mrf/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 0 - 0
mrf/libdepend.inc


+ 1057 - 0
mrf/mrfmin/BP-S.cpp

@@ -0,0 +1,1057 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <new>
+#include "BP-S.h"
+
+#define private public
+#include "typeTruncatedQuadratic2D.h"
+
+using namespace OBJREC;
+#undef private
+
+
+#define m_D(pix,l)  m_D[(pix)*m_nLabels+(l)]
+#define m_V(l1,l2)  m_V[(l1)*m_nLabels+(l2)]
+
+
+#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
+#define TRUNCATE_MIN(a,b) { if ((a) > (b)) (a) = (b); }
+#define TRUNCATE_MAX(a,b) { if ((a) < (b)) (a) = (b); }
+#define TRUNCATE TRUNCATE_MIN
+
+/////////////////////////////////////////////////////////////////////////////
+//                  Operations on vectors (arrays of size K)               //
+/////////////////////////////////////////////////////////////////////////////
+
+inline void CopyVector(BPS::REAL* to, MRF::CostVal* from, int K)
+{
+    BPS::REAL* to_finish = to + K;
+    do
+	{
+	    *to ++ = *from ++;
+	} while (to < to_finish);
+}
+
+inline void AddVector(BPS::REAL* to, BPS::REAL* from, int K)
+{
+    BPS::REAL* to_finish = to + K;
+    do
+	{
+	    *to ++ += *from ++;
+	} while (to < to_finish);
+}
+
+inline BPS::REAL SubtractMin(BPS::REAL *D, int K)
+{
+    int k;
+    BPS::REAL delta;
+	
+    delta = D[0];
+    for (k=1; k<K; k++) TRUNCATE(delta, D[k]);
+    for (k=0; k<K; k++) D[k] -= delta;
+
+    return delta;
+}
+
+// Functions UpdateMessageTYPE (see the paper for details):
+//
+// - Set Di[ki] := gamma*Di_hat[ki] - M[ki]
+// - Set M[kj] := min_{ki} (Di[ki] + V[ki,kj])
+// - Normalize message: 
+//        delta := min_{kj} M[kj]
+//        M[kj] := M[kj] - delta
+//        return delta
+//
+// If dir = 1, then the meaning of i and j is swapped.
+
+///////////////////////////////////////////
+//                  L1                   //
+///////////////////////////////////////////
+
+inline BPS::REAL UpdateMessageL1(BPS::REAL* M, BPS::REAL* Di_hat, int K, BPS::REAL gamma, MRF::CostVal lambda, MRF::CostVal smoothMax)
+{
+    int k;
+    BPS::REAL delta;
+
+    delta = M[0] = gamma*Di_hat[0] - M[0];
+    for (k=1; k<K; k++)
+	{
+	    M[k] = gamma*Di_hat[k] - M[k];
+	    TRUNCATE(delta, M[k]);
+	    TRUNCATE(M[k], M[k-1] + lambda);
+	}
+
+    M[--k] -= delta;
+    TRUNCATE(M[k], lambda*smoothMax);
+    for (k--; k>=0; k--)
+	{
+	    M[k] -= delta;
+	    TRUNCATE(M[k], M[k+1] + lambda);
+	    TRUNCATE(M[k], lambda*smoothMax);
+	}
+
+    return delta;
+}
+
+////////////////////////////////////////
+//               L2                   //
+////////////////////////////////////////
+
+inline BPS::REAL UpdateMessageL2(BPS::REAL* M, BPS::REAL* Di_hat, int K, BPS::REAL gamma, MRF::CostVal lambda, MRF::CostVal smoothMax, void *buf)
+{
+    BPS::REAL* Di = (BPS::REAL*) buf;
+    int* parabolas = (int*) ((char*)buf + K*sizeof(BPS::REAL));
+    int* intersections = parabolas + K;
+    TypeTruncatedQuadratic2D::REAL* Di_tmp = (TypeTruncatedQuadratic2D::REAL*) (intersections + K + 1);
+    TypeTruncatedQuadratic2D::REAL* M_tmp = Di_tmp + K;
+    TypeTruncatedQuadratic2D::Edge* tmp = NULL;
+
+    int k;
+    BPS::REAL delta;
+
+    assert(lambda >= 0);
+
+    Di[0] = gamma*Di_hat[0] - M[0];
+    delta = Di[0];
+    for (k=1; k<K; k++)
+	{
+	    Di[k] = gamma*Di_hat[k] - M[k];
+	    TRUNCATE(delta, Di[k]);
+	}
+
+    if (lambda == 0)
+	{
+	    for (k=0; k<K; k++) M[k] = 0;
+	    return delta;
+	}
+
+    for (k=0; k<K; k++) Di_tmp[k] = Di[k];
+    tmp->DistanceTransformL2(K, 1, lambda, Di_tmp, M_tmp, parabolas, intersections);
+    for (k=0; k<K; k++) M[k] = (BPS::REAL) M_tmp[k];
+
+    for (k=0; k<K; k++)
+	{
+	    M[k] -= delta;
+	    TRUNCATE(M[k], lambda*smoothMax);
+	}
+
+    return delta;
+}
+
+
+//////////////////////////////////////////////////
+//                FIXED_MATRIX                  //
+//////////////////////////////////////////////////
+
+inline BPS::REAL UpdateMessageFIXED_MATRIX(BPS::REAL* M, BPS::REAL* Di_hat, int K, BPS::REAL gamma, MRF::CostVal lambda, MRF::CostVal* V, void* buf)
+{
+    BPS::REAL* Di = (BPS::REAL*) buf;
+    int ki, kj;
+    BPS::REAL delta;
+
+    for (ki=0; ki<K; ki++)
+	{
+	    Di[ki] = gamma*Di_hat[ki] - M[ki];
+	}
+
+    for (kj=0; kj<K; kj++)
+	{
+	    M[kj] = Di[0] + lambda*V[0]; 
+	    V ++;
+	    for (ki=1; ki<K; ki++)
+		{
+		    TRUNCATE(M[kj], Di[ki] + lambda*V[0]);
+		    V ++;
+		}
+	}
+
+    delta = M[0];
+    for (kj=1; kj<K; kj++) TRUNCATE(delta, M[kj]);
+    for (kj=0; kj<K; kj++) M[kj] -= delta;
+
+    return delta;
+}
+
+/////////////////////////////////////////////
+//                GENERAL                  //
+/////////////////////////////////////////////
+
+inline BPS::REAL UpdateMessageGENERAL(BPS::REAL* M, BPS::REAL* Di_hat, int K, BPS::REAL gamma, int dir, MRF::CostVal* V, void* buf)
+{
+    BPS::REAL* Di = (BPS::REAL*) buf;
+    int ki, kj;
+    BPS::REAL delta;
+
+    for (ki=0; ki<K; ki++)
+	{
+	    Di[ki] = (gamma*Di_hat[ki] - M[ki]);
+	}
+
+    if (dir == 0)
+	{
+	    for (kj=0; kj<K; kj++)
+		{
+		    M[kj] = Di[0] + V[0]; 
+		    V ++;
+		    for (ki=1; ki<K; ki++)
+			{
+			    TRUNCATE(M[kj], Di[ki] + V[0]);
+			    V ++;
+			}
+		}
+	}
+    else
+	{
+	    for (kj=0; kj<K; kj++)
+		{
+		    M[kj] = Di[0] + V[0];
+		    V += K;
+		    for (ki=1; ki<K; ki++)
+			{
+			    TRUNCATE(M[kj], Di[ki] + V[0]);
+			    V += K;
+			}
+		    V -= K*K - 1;
+		}
+	}
+
+    delta = M[0];
+    for (kj=1; kj<K; kj++) TRUNCATE(delta, M[kj]);
+    for (kj=0; kj<K; kj++) M[kj] -= delta;
+
+    return delta;
+}
+
+inline BPS::REAL UpdateMessageGENERAL(BPS::REAL* M, BPS::REAL* Di_hat, int K, BPS::REAL gamma, BPS::SmoothCostGeneralFn fn, int i, int j, void* buf)
+{
+    BPS::REAL* Di = (BPS::REAL*) buf;
+    int ki, kj;
+    BPS::REAL delta;
+
+    for (ki=0; ki<K; ki++)
+	{
+	    Di[ki] = (gamma*Di_hat[ki] - M[ki]);
+	}
+
+    for (kj=0; kj<K; kj++)
+	{
+	    M[kj] = Di[0] + fn(i, j, 0, kj); 
+	    for (ki=1; ki<K; ki++)
+		{
+		    delta = Di[ki] + fn(i, j, ki, kj);
+		    TRUNCATE(M[kj], delta);
+		}
+	}
+
+    delta = M[0];
+    for (kj=1; kj<K; kj++) TRUNCATE(delta, M[kj]);
+    for (kj=0; kj<K; kj++) M[kj] -= delta;
+
+    return delta;
+}
+
+
+
+
+
+
+BPS::BPS(int width, int height, int nLabels,EnergyFunction *eng):MRF(width,height,nLabels,eng)
+{
+    Allocate();
+}
+BPS::BPS(int nPixels, int nLabels,EnergyFunction *eng):MRF(nPixels,nLabels,eng)
+{
+    Allocate();
+}
+
+BPS::~BPS()
+{ 
+    delete[] m_answer;
+    if ( m_needToFreeD ) delete [] m_D;
+    if ( m_needToFreeV ) delete [] m_V;
+    if ( m_messages ) delete [] m_messages;
+    if ( m_DBinary ) delete [] m_DBinary;
+    if ( m_horzWeightsBinary ) delete [] m_horzWeightsBinary;
+    if ( m_vertWeightsBinary ) delete [] m_vertWeightsBinary;
+}
+
+
+void BPS::Allocate()
+{
+    m_type = NONE;
+    m_needToFreeV = false;
+    m_needToFreeD = false;
+
+    m_D = NULL;
+    m_V = NULL;
+    m_horzWeights = NULL;
+    m_vertWeights = NULL;
+    m_horzWeightsBinary = NULL;
+    m_vertWeightsBinary = NULL;
+
+    m_DBinary = NULL;
+    m_messages = NULL;
+    m_messageArraySizeInBytes = 0;
+
+    m_answer = new Label[m_nPixels];
+}
+
+void BPS::clearAnswer()
+{
+    memset(m_answer, 0, m_nPixels*sizeof(Label));
+    if (m_messages)
+	{
+	    memset(m_messages, 0, m_messageArraySizeInBytes);
+	}
+}
+
+
+MRF::EnergyVal BPS::smoothnessEnergy()
+{
+    EnergyVal eng = (EnergyVal) 0;
+    EnergyVal weight;
+    int x,y,pix;
+
+    if ( m_grid_graph )
+	{
+	    if ( m_smoothType != FUNCTION  )
+		{
+		    for ( y = 0; y < m_height; y++ )
+			for ( x = 1; x < m_width; x++ )
+			    {
+				pix    = x+y*m_width;
+				weight = m_varWeights ? m_horzWeights[pix-1] :  1;
+				eng = eng + m_V(m_answer[pix],m_answer[pix-1])*weight;
+			    }
+
+		    for ( y = 1; y < m_height; y++ )
+			for ( x = 0; x < m_width; x++ )
+			    {
+				pix = x+y*m_width;
+				weight = m_varWeights ? m_vertWeights[pix-m_width] :  1;
+				eng = eng + m_V(m_answer[pix],m_answer[pix-m_width])*weight;
+			    }
+		}
+	    else
+		{
+		    for ( y = 0; y < m_height; y++ )
+			for ( x = 1; x < m_width; x++ )
+			    {
+				pix = x+y*m_width;
+				eng = eng + m_smoothFn(pix,pix-1,m_answer[pix],m_answer[pix-1]);
+			    }
+
+		    for ( y = 1; y < m_height; y++ )
+			for ( x = 0; x < m_width; x++ )
+			    {
+				pix = x+y*m_width;
+				eng = eng + m_smoothFn(pix,pix-m_width,m_answer[pix],m_answer[pix-m_width]);
+			    }
+		}
+	}
+    else
+	{
+	    // not implemented
+	}
+
+    return(eng);
+}
+
+
+
+MRF::EnergyVal BPS::dataEnergy()
+{
+    EnergyVal eng = (EnergyVal) 0;
+
+    
+    if ( m_dataType == ARRAY) 
+	{
+	    for ( int i = 0; i < m_nPixels; i++ )
+		eng = eng + m_D(i,m_answer[i]);
+	}
+    else
+	{
+	    for ( int i = 0; i < m_nPixels; i++ )
+		eng = eng + m_dataFn(i,m_answer[i]);
+	}
+    return(eng);
+
+}
+
+
+void BPS::setData(DataCostFn dcost)
+{
+    int i, k;
+
+    m_dataFn = dcost;
+    CostVal* ptr;
+    m_D = new CostVal[m_nPixels*m_nLabels];
+
+    for (ptr=m_D, i=0; i<m_nPixels; i++)
+	for (k=0; k<m_nLabels; k++, ptr++)
+	    {
+		*ptr = m_dataFn(i,k);
+	    }
+    m_needToFreeD = true;
+}
+
+void BPS::setData(CostVal* data)
+{
+    m_D = data;
+    m_needToFreeD = false;
+}
+
+
+void BPS::setSmoothness(SmoothCostGeneralFn cost)
+{
+    assert(m_horzWeights == NULL && m_vertWeights == NULL && m_V == NULL);
+
+    int x, y, i, ki, kj;
+    CostVal* ptr;
+
+    m_smoothFn = cost;
+    m_type = GENERAL;
+
+    if (!m_allocateArrayForSmoothnessCostFn) return;
+
+    // try to cache all the function values in an array for efficiency
+    m_V = new(std::nothrow) CostVal[2*m_nPixels*m_nLabels*m_nLabels];
+    if (!m_V) {
+	fprintf(stderr, "not caching smoothness cost values (not enough memory)\n");
+	return; // if not enough space, just call the function directly
+    }
+
+    m_needToFreeV = true;
+
+    for (ptr=m_V,i=0,y=0; y<m_height; y++)
+	for (x=0; x<m_width; x++, i++)
+	    {
+		if (x < m_width-1)
+		    {
+			for (kj=0; kj<m_nLabels; kj++)
+			    for (ki=0; ki<m_nLabels; ki++)
+				{
+				    *ptr++ = cost(i,i+1,ki,kj);
+				}
+		    }
+		else ptr += m_nLabels*m_nLabels;
+
+		if (y < m_height-1)
+		    {
+			for (kj=0; kj<m_nLabels; kj++)
+			    for (ki=0; ki<m_nLabels; ki++)
+				{
+				    *ptr++ = cost(i,i+m_width,ki,kj);
+				}
+		    }
+		else ptr += m_nLabels*m_nLabels;
+	    }
+}
+void BPS::setSmoothness(CostVal* V)
+{
+    m_type = FIXED_MATRIX;
+    m_V = V;
+}
+
+
+void BPS::setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda)
+{
+    assert(smoothExp == 1 || smoothExp == 2);
+    assert(lambda >= 0);
+
+    m_type = (smoothExp == 1) ? L1 : L2;
+
+    int ki, kj;
+    CostVal cost;
+
+    m_needToFreeV = true;
+
+    m_V = new CostVal[m_nLabels*m_nLabels];
+
+    for (ki=0; ki<m_nLabels; ki++)
+	for (kj=ki; kj<m_nLabels; kj++)
+	    {
+		cost = (CostVal) ((smoothExp == 1) ? kj - ki : (kj - ki)*(kj - ki));
+		if (cost > smoothMax) cost = smoothMax;
+		m_V[ki*m_nLabels + kj] = m_V[kj*m_nLabels + ki] = cost*lambda;
+	    }
+
+    m_smoothMax = smoothMax;
+    m_lambda = lambda;
+}
+
+
+void BPS::setCues(CostVal* hCue, CostVal* vCue)
+{
+    m_horzWeights = hCue;
+    m_vertWeights  = vCue;
+}
+
+
+void BPS::initializeAlg()
+{
+    assert(m_type != NONE);
+
+    int i;
+
+    // determine type
+    if (m_type == L1 && m_nLabels == 2)
+	{
+	    m_type = BINARY;
+	}
+
+    // allocate messages
+    int messageNum = (m_type == BINARY) ? 4*m_nPixels : 4*m_nPixels*m_nLabels;
+    m_messageArraySizeInBytes = messageNum*sizeof(REAL);
+    m_messages = new REAL[messageNum];
+    memset(m_messages, 0, messageNum*sizeof(REAL));
+
+    if (m_type == BINARY)
+	{
+	    assert(m_DBinary == NULL && m_horzWeightsBinary == NULL && m_horzWeightsBinary == NULL);
+	    m_DBinary = new CostVal[m_nPixels];
+	    m_horzWeightsBinary = new CostVal[m_nPixels];
+	    m_vertWeightsBinary = new CostVal[m_nPixels];
+
+	    if ( m_dataType == ARRAY)
+		{
+		    for (i=0; i<m_nPixels; i++)
+			{
+			    m_DBinary[i] = m_D[2*i+1] - m_D[2*i];
+			}
+		}
+	    else
+		{
+		    for (i=0; i<m_nPixels; i++)
+			{
+			    m_DBinary[i] = m_dataFn(i,1) - m_dataFn(i,0);
+			}
+		}
+
+	    assert(m_V[0] == 0 && m_V[1] == m_V[2] && m_V[3] == 0);
+	    for (i=0; i<m_nPixels; i++)
+		{
+		    m_horzWeightsBinary[i] = (m_varWeights) ? m_V[1]*m_horzWeights[i] : m_V[1];
+		    m_vertWeightsBinary[i] = (m_varWeights) ? m_V[1]*m_vertWeights[i] : m_V[1];
+		}
+	}
+}
+
+void BPS::optimizeAlg(int nIterations)
+{
+    assert(m_type != NONE);
+
+    if (m_grid_graph)
+	{
+	    switch (m_type)
+		{
+		case L1:            optimize_GRID_L1(nIterations);           break;
+		case L2:            optimize_GRID_L2(nIterations);           break;
+		case FIXED_MATRIX:  optimize_GRID_FIXED_MATRIX(nIterations); break;
+		case GENERAL:       optimize_GRID_GENERAL(nIterations);      break;
+		case BINARY:        optimize_GRID_BINARY(nIterations);       break;
+		default: assert(0); exit(1);
+		}
+	}
+    else {printf("\nNot implemented for general graphs yet, exiting!");exit(1);}
+
+    //	printf("lower bound = %f\n", m_lowerBound);
+
+    ////////////////////////////////////////////////
+    //          computing solution                //
+    ////////////////////////////////////////////////
+
+    if (m_type != BINARY)
+	{
+	    int x, y, n, K = m_nLabels;
+	    CostVal* D_ptr;
+	    REAL* M_ptr;
+	    REAL* Di;
+	    REAL delta;
+	    int ki, kj;
+
+	    Di = new REAL[K];
+
+	    n = 0;
+	    D_ptr = m_D;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, D_ptr+=K, M_ptr+=2*K, n++)
+		    {
+			CopyVector(Di, D_ptr, K);
+
+			if (m_type == GENERAL)
+			    {
+				if (m_V)
+				    {
+					CostVal* ptr = m_V + 2*(x+y*m_width-1)*K*K;
+					if (x > 0)
+					    {
+						kj = m_answer[n-1];
+						for (ki=0; ki<K; ki++)
+						    {
+							Di[ki] += ptr[kj + ki*K];
+						    }
+					    }
+					ptr -= (2*m_width-3)*K*K;
+					if (y > 0)
+					    {
+						kj = m_answer[n-m_width];
+						for (ki=0; ki<K; ki++)
+						    {
+							Di[ki] += ptr[kj + ki*K];
+						    }
+					    }
+				    }
+				else
+				    {
+					if (x > 0)
+					    {
+						kj = m_answer[n-1];
+						for (ki=0; ki<K; ki++)
+						    {
+							Di[ki] += m_smoothFn(n, n-1, ki, kj);
+						    }
+					    }
+					if (y > 0)
+					    {
+						kj = m_answer[n-m_width];
+						for (ki=0; ki<K; ki++)
+						    {
+							Di[ki] += m_smoothFn(n, n-m_width, ki, kj);
+						    }
+					    }
+				    }
+			    }
+			else // m_type == L1, L2 or FIXED_MATRIX
+			    {
+				if (x > 0)
+				    {
+					kj = m_answer[n-1];
+					CostVal lambda = (m_varWeights) ? m_horzWeights[n-1] : 1;
+					for (ki=0; ki<K; ki++)
+					    {
+						Di[ki] += lambda*m_V[kj*K + ki];
+					    }
+				    }
+				if (y > 0)
+				    {
+					kj = m_answer[n-m_width];
+					CostVal lambda = (m_varWeights) ? m_vertWeights[n-m_width] : 1;
+					for (ki=0; ki<K; ki++)
+					    {
+						Di[ki] += lambda*m_V[kj*K + ki];
+					    }
+				    }
+			    }
+
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			// compute min
+			delta = Di[0];
+			m_answer[n] = 0;
+			for (ki=1; ki<K; ki++)
+			    {
+				if (delta > Di[ki])
+				    {
+					delta = Di[ki];
+					m_answer[n] = ki;
+				    }
+			    }
+		    }
+
+	    delete [] Di;
+	}
+    else // m_type == BINARY
+	{
+	    int x, y, n;
+	    REAL* M_ptr;
+	    REAL Di;
+
+	    n = 0;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, M_ptr+=2, n++)
+		    {
+			Di = m_DBinary[n];
+			if (x > 0) Di += (m_answer[n-1] == 0)       ? m_horzWeightsBinary[n-1]       : -m_horzWeightsBinary[n-1];
+			if (y > 0) Di += (m_answer[n-m_width] == 0) ? m_vertWeightsBinary[n-m_width] : -m_vertWeightsBinary[n-m_width];
+
+			if (x < m_width-1)  Di += M_ptr[0]; // message (x+1,y)->(x,y)
+			if (y < m_height-1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+			// compute min
+			m_answer[n] = (Di >= 0) ? 0 : 1;
+		    }
+	}
+}
+
+void BPS::optimize_GRID_L1(int nIterations)
+{
+    int x, y, n, K = m_nLabels;
+    CostVal* D_ptr;
+    REAL* M_ptr;
+    REAL* Di;
+
+    Di = new REAL[K];
+
+    for ( ; nIterations > 0; nIterations --)
+	{
+	    // forward pass
+	    n = 0;
+	    D_ptr = m_D;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, D_ptr+=K, M_ptr+=2*K, n++)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			if (x < m_width-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_horzWeights[n] : m_lambda;
+				UpdateMessageL1(M_ptr, Di, K, 1, lambda, m_smoothMax);
+			    }
+			if (y < m_height-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_vertWeights[n] : m_lambda;
+				UpdateMessageL1(M_ptr+K, Di, K, 1, lambda, m_smoothMax);
+			    }
+		    }
+
+	    // backward pass
+	    n --;
+	    D_ptr -= K;
+	    M_ptr -= 2*K;
+
+	    for (y=m_height-1; y>=0; y--)
+		for (x=m_width-1; x>=0; x--, D_ptr-=K, M_ptr-=2*K, n--)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			SubtractMin(Di, K);
+
+			if (x > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_horzWeights[n-1] : m_lambda;
+				UpdateMessageL1(M_ptr-2*K, Di, K, 1, lambda, m_smoothMax);
+			    }
+			if (y > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_vertWeights[n-m_width] : m_lambda;
+				UpdateMessageL1(M_ptr-(2*m_width-1)*K, Di, K, 1, lambda, m_smoothMax);
+			    }
+		    }
+	}
+
+    delete [] Di;
+}
+
+void BPS::optimize_GRID_L2(int nIterations)
+{
+    int x, y, n, K = m_nLabels;
+    CostVal* D_ptr;
+    REAL* M_ptr;
+    REAL* Di;
+    void* buf;
+
+    Di = new REAL[K];
+    buf = new char[2*K*sizeof(TypeTruncatedQuadratic2D::REAL) + (2*K+1)*sizeof(int) + K*sizeof(REAL)];
+
+    for ( ; nIterations > 0; nIterations --)
+	{
+	    // forward pass
+	    n = 0;
+	    D_ptr = m_D;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, D_ptr+=K, M_ptr+=2*K, n++)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			if (x < m_width-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_horzWeights[n] : m_lambda;
+				UpdateMessageL2(M_ptr, Di, K, 1, lambda, m_smoothMax, buf);
+			    }
+			if (y < m_height-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_vertWeights[n] : m_lambda;
+				UpdateMessageL2(M_ptr+K, Di, K, 1, lambda, m_smoothMax, buf);
+			    }
+		    }
+
+	    // backward pass
+	    n --;
+	    D_ptr -= K;
+	    M_ptr -= 2*K;
+
+	    for (y=m_height-1; y>=0; y--)
+		for (x=m_width-1; x>=0; x--, D_ptr-=K, M_ptr-=2*K, n--)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			SubtractMin(Di, K);
+
+			if (x > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_horzWeights[n-1] : m_lambda;
+				UpdateMessageL2(M_ptr-2*K, Di, K, 1, lambda, m_smoothMax, buf);
+			    }
+			if (y > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_lambda*m_vertWeights[n-m_width] : m_lambda;
+				UpdateMessageL2(M_ptr-(2*m_width-1)*K, Di, K, 1, lambda, m_smoothMax, buf);
+			    }
+		    }
+	}
+
+    delete [] Di;
+    delete [] (REAL *)buf;
+}
+
+
+void BPS::optimize_GRID_BINARY(int nIterations)
+{
+    int x, y, n;
+    REAL* M_ptr;
+    REAL Di;
+
+    for ( ; nIterations > 0; nIterations --)
+	{
+	    // forward pass
+	    n = 0;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, M_ptr+=2, n++)
+		    {
+			Di = m_DBinary[n];
+			if (x > 0) Di += M_ptr[-2]; // message (x-1,y)->(x,y)
+			if (y > 0) Di += M_ptr[-2*m_width+1]; // message (x,y-1)->(x,y)
+			if (x < m_width-1) Di += M_ptr[0]; // message (x+1,y)->(x,y)
+			if (y < m_height-1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+			REAL DiScaled = Di * 1;
+			if (x < m_width-1) 
+			    {
+				Di = DiScaled - M_ptr[0];
+				CostVal lambda = m_horzWeightsBinary[n];
+				if (lambda < 0) { Di = -Di; lambda = -lambda; }
+				if (Di > lambda) M_ptr[0] = lambda;
+				else             M_ptr[0] = (Di < -lambda) ? -lambda : Di;
+			    }
+			if (y < m_height-1) 
+			    {
+				Di = DiScaled - M_ptr[1];
+				CostVal lambda = m_vertWeightsBinary[n];
+				if (lambda < 0) { Di = -Di; lambda = -lambda; }
+				if (Di > lambda) M_ptr[1] = lambda;
+				else             M_ptr[1] = (Di < -lambda) ? -lambda : Di;
+			    }
+		    }
+
+	    // backward pass
+	    n --;
+	    M_ptr -= 2;
+
+	    for (y=m_height-1; y>=0; y--)
+		for (x=m_width-1; x>=0; x--, M_ptr-=2, n--)
+		    {
+			Di = m_DBinary[n];
+			if (x > 0) Di += M_ptr[-2]; // message (x-1,y)->(x,y)
+			if (y > 0) Di += M_ptr[-2*m_width+1]; // message (x,y-1)->(x,y)
+			if (x < m_width-1) Di += M_ptr[0]; // message (x+1,y)->(x,y)
+			if (y < m_height-1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+			REAL DiScaled = Di * 1;
+			if (x > 0) 
+			    {
+				Di = DiScaled - M_ptr[-2];
+				CostVal lambda = m_horzWeightsBinary[n-1];
+				if (lambda < 0) { Di = -Di; lambda = -lambda; }
+				if (Di > lambda) M_ptr[-2] = lambda;
+				else             M_ptr[-2] = (Di < -lambda) ? -lambda : Di;
+			    }
+			if (y > 0) 
+			    {
+				Di = DiScaled - M_ptr[-2*m_width+1];
+				CostVal lambda = m_vertWeightsBinary[n-m_width];
+				if (lambda < 0) { Di = -Di; lambda = -lambda; }
+				if (Di > lambda) M_ptr[-2*m_width+1] = lambda;
+				else             M_ptr[-2*m_width+1] = (Di < -lambda) ? -lambda : Di;
+			    }
+		    }
+	}
+}
+
+void BPS::optimize_GRID_FIXED_MATRIX(int nIterations)
+{
+    int x, y, n, K = m_nLabels;
+    CostVal* D_ptr;
+    REAL* M_ptr;
+    REAL* Di;
+    void* buf;
+
+    Di = new REAL[K];
+    buf = new REAL[K];
+
+    for ( ; nIterations > 0; nIterations --)
+	{
+	    // forward pass
+	    n = 0;
+	    D_ptr = m_D;
+	    M_ptr = m_messages;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, D_ptr+=K, M_ptr+=2*K, n++)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			if (x < m_width-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_horzWeights[n] : 1;
+				UpdateMessageFIXED_MATRIX(M_ptr, Di, K, 1, lambda, m_V, buf);
+			    }
+			if (y < m_height-1) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_vertWeights[n] : 1;
+				UpdateMessageFIXED_MATRIX(M_ptr+K, Di, K, 1, lambda, m_V, buf);
+			    }
+		    }
+
+	    // backward pass
+	    n --;
+	    D_ptr -= K;
+	    M_ptr -= 2*K;
+
+	    for (y=m_height-1; y>=0; y--)
+		for (x=m_width-1; x>=0; x--, D_ptr-=K, M_ptr-=2*K, n--)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			SubtractMin(Di, K);
+
+			if (x > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_horzWeights[n-1] : 1;
+				UpdateMessageFIXED_MATRIX(M_ptr-2*K, Di, K, 1, lambda, m_V, buf);
+			    }
+			if (y > 0) 
+			    {
+				CostVal lambda = (m_varWeights) ? m_vertWeights[n-m_width] : 1;
+				UpdateMessageFIXED_MATRIX(M_ptr-(2*m_width-1)*K, Di, K, 1, lambda, m_V, buf);
+			    }
+		    }
+	}
+
+    delete [] Di;
+    delete [] (REAL *)buf;
+}
+
+void BPS::optimize_GRID_GENERAL(int nIterations)
+{
+    int x, y, n, K = m_nLabels;
+    CostVal* D_ptr;
+    REAL* M_ptr;
+    REAL* Di;
+    void* buf;
+
+    Di = new REAL[K];
+    buf = new REAL[K];
+
+    for ( ; nIterations > 0; nIterations --)
+	{
+	    // forward pass
+	    n = 0;
+	    D_ptr = m_D;
+	    M_ptr = m_messages;
+	    CostVal* V_ptr = m_V;
+
+	    for (y=0; y<m_height; y++)
+		for (x=0; x<m_width; x++, D_ptr+=K, M_ptr+=2*K, V_ptr+=2*K*K, n++)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			if (x < m_width-1) 
+			    {
+				if (m_V) UpdateMessageGENERAL(M_ptr, Di, K, 1, /* forward dir*/ 0, V_ptr, buf);
+				else     UpdateMessageGENERAL(M_ptr, Di, K, 1,   m_smoothFn, n, n+1,      buf);
+			    }
+			if (y < m_height-1) 
+			    {
+				if (m_V) UpdateMessageGENERAL(M_ptr+K, Di, K, 1, /* forward dir*/ 0, V_ptr+K*K, buf);
+				else     UpdateMessageGENERAL(M_ptr+K, Di, K, 1,   m_smoothFn, n, n+m_width,    buf);
+			    }
+		    }
+
+	    // backward pass
+	    n --;
+	    D_ptr -= K;
+	    M_ptr -= 2*K;
+	    V_ptr -= 2*K*K;
+
+	    for (y=m_height-1; y>=0; y--)
+		for (x=m_width-1; x>=0; x--, D_ptr-=K, M_ptr-=2*K, V_ptr-=2*K*K, n--)
+		    {
+			CopyVector(Di, D_ptr, K);
+			if (x > 0) AddVector(Di, M_ptr-2*K, K); // message (x-1,y)->(x,y)
+			if (y > 0) AddVector(Di, M_ptr-(2*m_width-1)*K, K); // message (x,y-1)->(x,y)
+			if (x < m_width-1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+			if (y < m_height-1) AddVector(Di, M_ptr+K, K); // message (x,y+1)->(x,y)
+
+			// normalize Di, update lower bound
+			SubtractMin(Di, K);
+
+			if (x > 0) 
+			    {
+				if (m_V) UpdateMessageGENERAL(M_ptr-2*K, Di, K, 1, /* backward dir */ 1, V_ptr-2*K*K, buf);
+				else     UpdateMessageGENERAL(M_ptr-2*K, Di, K, 1,   m_smoothFn, n, n-1,              buf);
+			    }
+			if (y > 0)
+			    {
+				if (m_V) UpdateMessageGENERAL(M_ptr-(2*m_width-1)*K, Di, K, 1, /* backward dir */ 1, V_ptr-(2*m_width-1)*K*K, buf);
+				else     UpdateMessageGENERAL(M_ptr-(2*m_width-1)*K, Di, K, 1,   m_smoothFn, n, n-m_width,                    buf);
+
+			    }
+		    }
+	}
+
+    delete [] Di;
+    delete [] (REAL *)buf;
+}

+ 94 - 0
mrf/mrfmin/BP-S.h

@@ -0,0 +1,94 @@
+#ifndef __BPS_H__
+#define __BPS_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mrf.h"
+
+namespace OBJREC {
+
+class BPS : public MRF {
+  public:
+    typedef CostVal REAL;
+
+    BPS(int width, int height, int nLabels, EnergyFunction *eng);
+    BPS(int nPixels, int nLabels, EnergyFunction *eng);
+    ~BPS();
+    void setNeighbors(int /*pix1*/, int /*pix2*/, CostVal /*weight*/) {
+      printf("Not implemented");
+      exit(1);
+    }
+    Label getLabel(int pixel) {
+      return(m_answer[pixel]);
+    };
+    void setLabel(int pixel, Label label) {
+      m_answer[pixel] = label;
+    };
+    Label* getAnswerPtr() {
+      return(m_answer);
+    };
+    void clearAnswer();
+    void setParameters(int /*numParam*/, void * /*param*/) {
+      printf("No optional parameters to set");
+      exit(1);
+    }
+    EnergyVal smoothnessEnergy();
+    EnergyVal dataEnergy();
+
+  protected:
+    void setData(DataCostFn dcost);
+    void setData(CostVal* data);
+    void setSmoothness(SmoothCostGeneralFn cost);
+    void setSmoothness(CostVal* V);
+    void setSmoothness(int smoothExp, CostVal smoothMax, CostVal lambda);
+    void setCues(CostVal* hCue, CostVal* vCue);
+    void Allocate();
+    void initializeAlg();
+    void optimizeAlg(int nIterations);
+
+  private:
+
+    enum
+    {
+      NONE,
+      L1,
+      L2,
+      FIXED_MATRIX,
+      GENERAL,
+      BINARY,
+    } m_type;
+
+    CostVal m_smoothMax; // used only if
+    CostVal m_lambda;    // m_type == L1 or m_type == L2
+
+    Label *m_answer;
+    CostVal *m_V; // points to array of size nLabels^2 (if type==FIXED_MATRIX) or of size nEdges*nLabels^2 (if type==GENERAL)
+    CostVal *m_D;
+    CostVal *m_DBinary; // valid if type == BINARY
+    CostVal *m_horzWeights;
+    CostVal *m_vertWeights;
+    CostVal *m_horzWeightsBinary;
+    CostVal *m_vertWeightsBinary;
+    DataCostFn m_dataFn;
+    SmoothCostGeneralFn m_smoothFn;
+    bool m_needToFreeV;
+    bool m_needToFreeD;
+
+    REAL* m_messages; // size of one message: N = 1 if m_type == BINARY, N = K otherwise
+    // message between edges (x,y)-(x+1,y): m_messages+(2*x+2*y*m_width)*N
+    // message between edges (x,y)-(x,y+1): m_messages+(2*x+2*y*m_width+1)*N
+
+    int   m_messageArraySizeInBytes;
+
+    void optimize_GRID_L1(int nIterations);
+    void optimize_GRID_L2(int nIterations);
+    void optimize_GRID_FIXED_MATRIX(int nIterations);
+    void optimize_GRID_GENERAL(int nIterations);
+    void optimize_GRID_BINARY(int nIterations);
+};
+
+}
+
+#endif /*  __BPS_H__ */

+ 1 - 0
mrf/mrfmin/CHANGES.txt

@@ -0,0 +1 @@
+06/11/2006: fixed memory leak in CSoptimization.cpp

+ 833 - 0
mrf/mrfmin/GCoptimization.cpp

@@ -0,0 +1,833 @@
+#include "GCoptimization.h"
+#include "LinkedBlockList.h"
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+
+using namespace OBJREC;
+
+// will leave this one just for the laughs :)
+//#define olga_assert(expr) assert(!(expr))
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//   First we have functions for the base class
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Constructor for base class
+GCoptimization::GCoptimization(SiteID nSites, LabelID nLabels)
+    : m_datacostIndividual(0)
+    , m_smoothcostIndividual(0)
+    , m_smoothcostFn(0)
+    , m_datacostFn(0)
+    , m_set_up_t_links_swap(0)
+    , m_set_up_t_links_expansion(0)
+    , m_set_up_n_links_swap(0)
+    , m_set_up_n_links_expansion(0)
+    , m_giveSmoothEnergyInternal(0)
+    , m_giveDataEnergyInternal(0)
+    , m_datacostFnDelete(0)
+    , m_smoothcostFnDelete(0)
+    , m_random_label_order(false)
+{
+  assert( nLabels > 1 && nSites > 0);
+  m_num_labels = nLabels;
+  m_num_sites  = nSites;
+
+
+  m_lookupSiteVar = (SiteID *)  new SiteID[m_num_sites];
+  m_labelTable    = (LabelID *) new LabelID[m_num_labels];
+  m_labeling      = (LabelID *) new LabelID[m_num_sites];
+
+  if ( !m_lookupSiteVar || !m_labelTable || !m_labeling) {
+    if (m_lookupSiteVar) delete [] m_lookupSiteVar;
+    if (m_labelTable) delete [] m_labelTable;
+    if (m_labeling) delete [] m_labeling;
+    handleError("Not enough memory");
+
+
+  }
+
+  for ( LabelID i = 0; i < m_num_labels; i++ )
+    m_labelTable[i] = i;
+
+
+  for ( SiteID i = 0; i < m_num_sites; i++ ) {
+    m_labeling[i] = (LabelID) 0;
+    m_lookupSiteVar[i] = (SiteID) - 1;
+  }
+
+  srand((unsigned int) time(NULL));
+}
+
+//-------------------------------------------------------------------
+
+GCoptimization::~GCoptimization()
+{
+  delete [] m_labelTable;
+  delete [] m_lookupSiteVar;
+  delete [] m_labeling;
+
+  if (m_datacostFnDelete) m_datacostFnDelete(m_datacostFn);
+  if (m_smoothcostFnDelete) m_smoothcostFnDelete(m_smoothcostFn);
+
+  if (m_datacostIndividual) delete [] m_datacostIndividual;
+  if (m_smoothcostIndividual) delete [] m_smoothcostIndividual;
+}
+
+
+//------------------------------------------------------------------
+
+void GCoptimization::setDataCost(DataCostFn fn) {
+  specializeDataCostFunctor(DataCostFnFromFunction(fn));
+}
+
+
+//------------------------------------------------------------------
+
+void GCoptimization::setDataCost(DataCostFnExtra fn, void *extraData) {
+  specializeDataCostFunctor(DataCostFnFromFunctionExtra(fn, extraData));
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setDataCost(EnergyTermType *dataArray) {
+  specializeDataCostFunctor(DataCostFnFromArray(dataArray, m_num_labels));
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setDataCost(SiteID s, LabelID l, EnergyTermType e) {
+  if (!m_datacostIndividual) {
+    if ( m_datacostFn ) handleError("Data Costs are already initialized");
+    m_datacostIndividual = new EnergyTermType[m_num_sites*m_num_labels];
+    memset(m_datacostIndividual, 0, m_num_sites*m_num_labels*sizeof(EnergyTermType));
+    specializeDataCostFunctor(DataCostFnFromArray(m_datacostIndividual, m_num_labels));
+  }
+  m_datacostIndividual[s*m_num_labels + l] = e;
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setDataCostFunctor(DataCostFunctor* f) {
+  if ( m_datacostFn ) handleError("Data Costs are already initialized");
+
+  m_datacostFn = f;
+  m_giveDataEnergyInternal   = &GCoptimization::giveDataEnergyInternal<DataCostFunctor>;
+  m_set_up_t_links_expansion = &GCoptimization::set_up_t_links_expansion<DataCostFunctor>;
+  m_set_up_t_links_swap      = &GCoptimization::set_up_t_links_swap<DataCostFunctor>;
+}
+
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setSmoothCost(SmoothCostFn fn) {
+  specializeSmoothCostFunctor(SmoothCostFnFromFunction(fn));
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setSmoothCost(SmoothCostFnExtra fn, void* extraData) {
+  specializeSmoothCostFunctor(SmoothCostFnFromFunctionExtra(fn, extraData));
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setSmoothCost(EnergyTermType *smoothArray) {
+  specializeSmoothCostFunctor(SmoothCostFnFromArray(smoothArray, m_num_labels));
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setSmoothCost(LabelID l1, GCoptimization::LabelID l2, EnergyTermType e) {
+  if (!m_smoothcostIndividual) {
+    if ( m_smoothcostFn ) handleError("Smoothness Costs are already initialized");
+    m_smoothcostIndividual = new EnergyTermType[m_num_labels*m_num_labels];
+    memset(m_smoothcostIndividual, 0, m_num_labels*m_num_labels*sizeof(EnergyTermType));
+    specializeSmoothCostFunctor(SmoothCostFnFromArray(m_smoothcostIndividual, m_num_labels));
+  }
+  m_smoothcostIndividual[l1*m_num_labels + l2] = e;
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setSmoothCostFunctor(SmoothCostFunctor* f) {
+  if ( m_smoothcostFn ) handleError("Smoothness Costs are already initialized");
+
+  m_smoothcostFn = f;
+  m_giveSmoothEnergyInternal = &GCoptimization::giveSmoothEnergyInternal<SmoothCostFunctor>;
+  m_set_up_n_links_expansion = &GCoptimization::set_up_n_links_expansion<SmoothCostFunctor>;
+  m_set_up_n_links_swap      = &GCoptimization::set_up_n_links_swap<SmoothCostFunctor>;
+}
+
+//-------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::giveSmoothEnergy()
+{
+
+  if (readyToOptimise())
+    return(  (this->*m_giveSmoothEnergyInternal)() );
+  else {
+    handleError("Not ready to optimize yet. Set up data and smooth costs first");
+    return(0);
+  }
+
+}
+//-------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::giveDataEnergy()
+{
+
+
+  if (readyToOptimise())
+    return( (this->*m_giveDataEnergyInternal)() );
+  else {
+    handleError("Not ready to optimize yet. Set up data and smooth costs first");
+    return(0);
+  }
+
+}
+
+//-------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::compute_energy()
+{
+  if (readyToOptimise())
+    return( (this->*m_giveDataEnergyInternal)() + (this->*m_giveSmoothEnergyInternal)());
+  else {
+    handleError("Not ready to optimize yet. Set up data and smooth costs first");
+    return(0);
+  }
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::scramble_label_table()
+{
+  LabelID r1, r2, temp;
+  LabelID num_times, cnt;
+
+  num_times = m_num_labels;
+
+  for ( cnt = 0; cnt < num_times; cnt++ )
+  {
+    r1 = rand() % m_num_labels;
+    r2 = rand() % m_num_labels;
+
+    temp             = m_labelTable[r1];
+    m_labelTable[r1] = m_labelTable[r2];
+    m_labelTable[r2] = temp;
+  }
+}
+
+
+//-------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::expansion(int max_num_iterations )
+{
+  int curr_cycle = 1;
+  EnergyType new_energy, old_energy;
+
+
+  new_energy = compute_energy();
+
+  old_energy = new_energy + 1;
+
+  while ( old_energy > new_energy  && curr_cycle <= max_num_iterations)
+  {
+    old_energy = new_energy;
+    new_energy = oneExpansionIteration();
+    curr_cycle++;
+  }
+
+  return(new_energy);
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimization::setLabelOrder(bool RANDOM_LABEL_ORDER)
+{
+  m_random_label_order = RANDOM_LABEL_ORDER;
+}
+
+//-------------------------------------------------------------------
+
+bool GCoptimization::readyToOptimise()
+{
+  if (!m_smoothcostFn)
+  {
+    handleError("Smoothness term is not set up yet!");
+    return(false);
+  }
+  if (!m_datacostFn)
+  {
+    handleError("Data term is not set up yet!");
+    return(false);
+  }
+  return(true);
+
+}
+
+//------------------------------------------------------------------
+
+void GCoptimization::handleError(const char *message)
+{
+  throw  GCException(message);
+}
+
+
+//-------------------------------------------------------------------//
+//                  METHODS for EXPANSION MOVES                      //
+//-------------------------------------------------------------------//
+
+void GCoptimization::set_up_expansion_energy(SiteID size, LabelID alpha_label, Energy *e,
+    VarID *variables, SiteID *activeSites )
+{
+
+
+  (this->*m_set_up_t_links_expansion)(size, alpha_label, e, variables, activeSites);
+  (this->*m_set_up_n_links_expansion)(size, alpha_label, e, variables, activeSites);
+}
+
+
+//-------------------------------------------------------------------
+// Sets up the energy and optimizes it. Also updates labels of sites, if needed. ActiveSites
+// are the sites participating in expansion. They are not labeled alpha currrently
+void GCoptimization::solveExpansion(SiteID size, SiteID *activeSites, LabelID alpha_label)
+{
+  SiteID i, site;
+
+  if ( !readyToOptimise() ) handleError("Set up data and smoothness terms first. ");
+  if ( size == 0 ) return;
+
+
+  Energy *e = new Energy();
+
+  Energy::Var *variables = (Energy::Var *) new Energy::Var[size];
+
+  for ( i = 0; i < size; i++ )
+    variables[i] = e ->add_variable();
+
+  set_up_expansion_energy(size, alpha_label, e, variables, activeSites);
+
+  Energy::TotalValue Emin = e -> minimize();
+
+  for ( i = 0; i < size; i++ )
+  {
+    site = activeSites[i];
+    if ( m_labeling[site] != alpha_label )
+    {
+      if ( e->get_var(variables[i]) == 0 )
+      {
+        m_labeling[site] = alpha_label;
+      }
+    }
+    m_lookupSiteVar[site] = -1;
+  }
+
+  delete [] variables;
+  delete e;
+}
+//-------------------------------------------------------------------
+// alpha expansion on all sites not currently labeled alpha
+void GCoptimization::alpha_expansion(LabelID alpha_label)
+{
+  SiteID i  = 0, size = 0;
+  assert( alpha_label >= 0 && alpha_label < m_num_labels);
+
+  SiteID *activeSites = new SiteID[m_num_sites];
+
+  for ( i = 0; i < m_num_sites; i++ )
+  {
+    if ( m_labeling[i] != alpha_label )
+    {
+      activeSites[size] = i;
+      m_lookupSiteVar[i] = size;
+      size++;
+    }
+  }
+
+  solveExpansion(size, activeSites, alpha_label);
+
+  delete [] activeSites;
+}
+
+//-------------------------------------------------------------------
+// alpha expansion on subset of sites in array *sites
+void GCoptimization::alpha_expansion(LabelID alpha_label, SiteID *sites, SiteID num )
+{
+  SiteID i, size = 0;
+  SiteID *activeSites = new SiteID[num];
+
+  for ( i = 0; i < num; i++ )
+  {
+    if ( m_labeling[sites[i]] != alpha_label )
+    {
+      m_lookupSiteVar[sites[i]] = size;
+      activeSites[size] = sites[i];
+      size++;
+    }
+  }
+
+  solveExpansion(size, activeSites, alpha_label);
+
+  delete [] activeSites;
+}
+
+//-------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::oneExpansionIteration()
+{
+  LabelID next;
+
+  if (m_random_label_order) scramble_label_table();
+
+  for (next = 0;  next < m_num_labels;  next++ )
+  {
+    alpha_expansion(m_labelTable[next]);
+  }
+
+  return(compute_energy());
+}
+
+//-------------------------------------------------------------------//
+//                  METHODS for SWAP MOVES                           //
+//-------------------------------------------------------------------//
+
+GCoptimization::EnergyType GCoptimization::swap(int max_num_iterations )
+{
+
+  int curr_cycle = 1;
+  EnergyType new_energy, old_energy;
+
+
+  new_energy = compute_energy();
+
+  old_energy = new_energy + 1;
+
+  while ( old_energy > new_energy  && curr_cycle <= max_num_iterations)
+  {
+    old_energy = new_energy;
+    new_energy = oneSwapIteration();
+
+    curr_cycle++;
+  }
+
+  return(new_energy);
+}
+
+//--------------------------------------------------------------------------------
+
+GCoptimization::EnergyType GCoptimization::oneSwapIteration()
+{
+  LabelID next, next1;
+
+  if (m_random_label_order) scramble_label_table();
+
+
+  for (next = 0;  next < m_num_labels;  next++ )
+    for (next1 = m_num_labels - 1;  next1 >= 0;  next1-- )
+      if ( m_labelTable[next] < m_labelTable[next1] )
+        alpha_beta_swap(m_labelTable[next], m_labelTable[next1]);
+
+
+  return(compute_energy());
+}
+
+//---------------------------------------------------------------------------------
+
+void GCoptimization::alpha_beta_swap(LabelID alpha_label, LabelID beta_label)
+{
+  assert( alpha_label >= 0 && alpha_label < m_num_labels && beta_label >= 0 && beta_label < m_num_labels);
+
+  SiteID i  = 0, size = 0;
+  SiteID *activeSites = new SiteID[m_num_sites];
+
+  for ( i = 0; i < m_num_sites; i++ ) {
+    if ( m_labeling[i] == alpha_label || m_labeling[i] == beta_label ) {
+      activeSites[size] = i;
+      m_lookupSiteVar[i] = size;
+      size++;
+    }
+  }
+
+  solveSwap(size, activeSites, alpha_label, beta_label);
+
+  delete [] activeSites;
+
+}
+//-----------------------------------------------------------------------------------
+
+void GCoptimization::alpha_beta_swap(LabelID alpha_label, LabelID beta_label,
+                                     SiteID *alphaSites, SiteID alpha_size, SiteID *betaSites,
+                                     SiteID beta_size)
+
+{
+  assert( !(alpha_label < 0 || alpha_label >= m_num_labels || beta_label < 0 || beta_label >= m_num_labels) );
+  SiteID i, site, size = 0;
+
+  SiteID *activeSites = new SiteID[alpha_size+beta_size];
+
+  for ( i = 0; i < alpha_size; i++ )
+  {
+    site = alphaSites[i];
+
+    assert(site >= 0 && site < m_num_sites );
+    assert(m_labeling[site] == alpha_label);
+
+    activeSites[size]     = site;
+    m_lookupSiteVar[site] = size;
+    size++;
+
+  }
+
+  for ( i = 0; i < beta_size; i++ )
+  {
+    site = betaSites[i];
+    assert(site >= 0 && site < m_num_sites );
+    assert(m_labeling[site] == beta_label);
+
+    activeSites[size]     = site;
+    m_lookupSiteVar[site] = size;
+    size++;
+
+  }
+
+  solveSwap(size, activeSites, alpha_label, beta_label);
+
+  delete [] activeSites;
+}
+
+//-----------------------------------------------------------------------------------
+void GCoptimization::solveSwap(SiteID size, SiteID *activeSites, LabelID alpha_label,
+                               LabelID beta_label)
+{
+
+  SiteID i, site;
+
+  if ( !readyToOptimise() ) handleError("Set up data and smoothness terms first. ");
+  if ( size == 0 ) return;
+
+
+  Energy *e = new Energy();
+  Energy::Var *variables = (Energy::Var *) new Energy::Var[size];
+
+  for ( i = 0; i < size; i++ )
+    variables[i] = e ->add_variable();
+
+  set_up_swap_energy(size, alpha_label, beta_label, e, variables, activeSites);
+
+  Energy::TotalValue Emin = e -> minimize();
+
+  for ( i = 0; i < size; i++ )
+  {
+    site = activeSites[i];
+    if ( e->get_var(variables[i]) == 0 )
+      m_labeling[site] = alpha_label;
+    else m_labeling[site] = beta_label;
+    m_lookupSiteVar[site] = -1;
+  }
+
+  delete [] variables;
+  delete e;
+
+}
+//-----------------------------------------------------------------------------------
+
+void GCoptimization::set_up_swap_energy(SiteID size, LabelID alpha_label, LabelID beta_label,
+                                        Energy* e, Energy::Var *variables, SiteID *activeSites)
+{
+  (this->*m_set_up_t_links_swap)(size, alpha_label, beta_label, e, variables, activeSites);
+  (this->*m_set_up_n_links_swap)(size, alpha_label, beta_label, e, variables, activeSites);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// Functions for the GCoptimizationGridGraph, derived from GCoptimization
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+GCoptimizationGridGraph::GCoptimizationGridGraph(SiteID width, SiteID height, LabelID num_labels)
+    : GCoptimization(width*height, num_labels)
+{
+
+  assert( (width > 1) && (height > 1) && (num_labels > 1 ));
+
+  m_weightedGraph = 0;
+
+  for (int  i = 0; i < 4; i ++ ) m_unityWeights[i] = 1;
+
+  m_width  = width;
+  m_height = height;
+
+  m_numNeighbors = new SiteID[m_num_sites];
+  m_neighbors = new SiteID[4*m_num_sites];
+
+  SiteID indexes[4] = { -1, 1, -m_width, m_width};
+
+  SiteID indexesL[3] = {1, -m_width, m_width};
+  SiteID indexesR[3] = { -1, -m_width, m_width};
+  SiteID indexesU[3] = {1, -1, m_width};
+  SiteID indexesD[3] = {1, -1, -m_width};
+
+  SiteID indexesUL[2] = {1, m_width};
+  SiteID indexesUR[2] = { -1, m_width};
+  SiteID indexesDL[2] = {1, -m_width};
+  SiteID indexesDR[2] = { -1, -m_width};
+
+  setupNeighbData(1, m_height - 1, 1, m_width - 1, 4, indexes);
+
+  setupNeighbData(1, m_height - 1, 0, 1, 3, indexesL);
+  setupNeighbData(1, m_height - 1, m_width - 1, m_width, 3, indexesR);
+  setupNeighbData(0, 1, 1, width - 1, 3, indexesU);
+  setupNeighbData(m_height - 1, m_height, 1, m_width - 1, 3, indexesD);
+
+  setupNeighbData(0, 1, 0, 1, 2, indexesUL);
+  setupNeighbData(0, 1, m_width - 1, m_width, 2, indexesUR);
+  setupNeighbData(m_height - 1, m_height, 0, 1, 2, indexesDL);
+  setupNeighbData(m_height - 1, m_height, m_width - 1, m_width, 2, indexesDR);
+}
+
+//-------------------------------------------------------------------
+
+GCoptimizationGridGraph::~GCoptimizationGridGraph()
+{
+  delete [] m_numNeighbors;
+  delete [] m_neighbors;
+  if (m_weightedGraph) delete [] m_neighborsWeights;
+}
+
+
+//-------------------------------------------------------------------
+
+void GCoptimizationGridGraph::setupNeighbData(SiteID startY, SiteID endY, SiteID startX,
+    SiteID endX, SiteID maxInd, SiteID *indexes)
+{
+  SiteID x, y, pix;
+  SiteID n;
+
+  for ( y = startY; y < endY; y++ )
+    for ( x = startX; x < endX; x++ )
+    {
+      pix = x + y * m_width;
+      m_numNeighbors[pix] = maxInd;
+
+      for (n = 0; n < maxInd; n++ )
+        m_neighbors[pix*4+n] = pix + indexes[n];
+    }
+}
+
+//-------------------------------------------------------------------
+
+bool GCoptimizationGridGraph::readyToOptimise()
+{
+  GCoptimization::readyToOptimise();
+  return(true);
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimizationGridGraph::setSmoothCostVH(EnergyTermType *smoothArray, EnergyTermType *vCosts, EnergyTermType *hCosts)
+{
+  setSmoothCost(smoothArray);
+  m_weightedGraph = 1;
+  computeNeighborWeights(vCosts, hCosts);
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimizationGridGraph::giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights)
+{
+  *numSites  = m_numNeighbors[site];
+  *neighbors = &m_neighbors[site*4];
+
+  if (m_weightedGraph) *weights  = &m_neighborsWeights[site*4];
+  else *weights = m_unityWeights;
+}
+
+//-------------------------------------------------------------------
+
+void GCoptimizationGridGraph::computeNeighborWeights(EnergyTermType *vCosts, EnergyTermType *hCosts)
+{
+  SiteID i, n, nSite;
+  GCoptimization::EnergyTermType weight;
+
+
+  m_neighborsWeights = new EnergyTermType[m_num_sites*4];
+
+  for ( i = 0; i < m_num_sites; i++ )
+  {
+    for ( n = 0; n < m_numNeighbors[i]; n++ )
+    {
+      nSite = m_neighbors[4*i+n];
+      if ( i - nSite == 1 )            weight = hCosts[nSite];
+      else if (i - nSite == -1 )       weight = hCosts[i];
+      else if ( i - nSite == m_width ) weight = vCosts[nSite];
+      else if (i - nSite == -m_width ) weight = vCosts[i];
+
+      m_neighborsWeights[i*4+n] = weight;
+    }
+  }
+
+}
+////////////////////////////////////////////////////////////////////////////////////////////////
+// Functions for the GCoptimizationGeneralGraph, derived from GCoptimization
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+GCoptimizationGeneralGraph::GCoptimizationGeneralGraph(SiteID num_sites, LabelID num_labels): GCoptimization(num_sites, num_labels)
+{
+  assert( num_sites > 1 && num_labels > 1 );
+
+  m_neighborsIndexes = 0;
+  m_neighborsWeights = 0;
+  m_numNeighbors     = 0;
+  m_neighbors        = 0;
+
+  m_needTodeleteNeighbors        = true;
+  m_needToFinishSettingNeighbors = true;
+}
+
+//------------------------------------------------------------------
+
+GCoptimizationGeneralGraph::~GCoptimizationGeneralGraph()
+{
+
+  if ( m_neighbors ) {
+    delete [] m_neighbors;
+  }
+
+  if ( m_numNeighbors && m_needTodeleteNeighbors )
+  {
+    for ( SiteID i = 0; i < m_num_sites; i++ )
+    {
+      if (m_numNeighbors[i] != 0 )
+      {
+        delete [] m_neighborsIndexes[i];
+        delete [] m_neighborsWeights[i];
+      }
+    }
+
+    delete [] m_numNeighbors;
+    delete [] m_neighborsIndexes;
+    delete [] m_neighborsWeights;
+  }
+
+
+}
+
+//-------------------------------------------------------------------
+
+bool GCoptimizationGeneralGraph::readyToOptimise()
+{
+  GCoptimization::readyToOptimise();
+  if (m_needToFinishSettingNeighbors) finishSettingNeighbors();
+  return(true);
+}
+
+//------------------------------------------------------------------
+
+void GCoptimizationGeneralGraph::finishSettingNeighbors()
+{
+
+  Neighbor *tmp;
+  SiteID i, site, count;
+
+  m_needToFinishSettingNeighbors = false;
+
+  EnergyTermType *tempWeights = new EnergyTermType[m_num_sites];
+  SiteID *tempIndexes         = new SiteID[m_num_sites];
+
+  if ( !tempWeights || !tempIndexes ) handleError("Not enough memory");
+
+  m_numNeighbors     = new SiteID[m_num_sites];
+  m_neighborsIndexes = new SiteID*[m_num_sites];
+  m_neighborsWeights = new EnergyTermType*[m_num_sites];
+
+  if ( !m_numNeighbors || !m_neighborsIndexes || !m_neighborsWeights ) handleError("Not enough memory");
+
+  for ( site = 0; site < m_num_sites; site++ )
+  {
+    if ( !m_neighbors[site].isEmpty() )
+    {
+      m_neighbors[site].setCursorFront();
+      count = 0;
+
+      while ( m_neighbors[site].hasNext() )
+      {
+        tmp = (Neighbor *) (m_neighbors[site].next());
+        tempIndexes[count] =  tmp->to_node;
+        tempWeights[count] =  tmp->weight;
+        delete tmp;
+        count++;
+      }
+      m_numNeighbors[site]     = count;
+      m_neighborsIndexes[site] = new SiteID[count];
+      m_neighborsWeights[site] = new EnergyTermType[count];
+
+      if ( !m_neighborsIndexes[site] || !m_neighborsWeights[site] ) handleError("Not enough memory");
+
+      for ( i = 0; i < count; i++ )
+      {
+        m_neighborsIndexes[site][i] = tempIndexes[i];
+        m_neighborsWeights[site][i] = tempWeights[i];
+      }
+    }
+    else m_numNeighbors[site] = 0;
+
+  }
+
+  delete [] tempIndexes;
+  delete [] tempWeights;
+  delete [] m_neighbors;
+  m_neighbors = (LinkedBlockList *) new LinkedBlockList[1];
+  // this signals that the neibhorhood system is set, in case user calls setAllNeighbors
+}
+//------------------------------------------------------------------------------
+
+void GCoptimizationGeneralGraph::giveNeighborInfo(SiteID site, SiteID *numSites,
+    SiteID **neighbors, EnergyTermType **weights)
+{
+  (*numSites)  =  m_numNeighbors[site];
+  (*neighbors) = m_neighborsIndexes[site];
+  (*weights)   = m_neighborsWeights[site];
+}
+
+
+//------------------------------------------------------------------
+
+void GCoptimizationGeneralGraph::setNeighbors(SiteID site1, SiteID site2, EnergyTermType weight)
+{
+
+  assert( site1 < m_num_sites && site1 >= 0 && site2 < m_num_sites && site2 >= 0);
+  if ( m_needToFinishSettingNeighbors == false ) handleError("Already set up neighborhood system");
+
+  if ( !m_neighbors )
+  {
+    m_neighbors = (LinkedBlockList *) new LinkedBlockList[m_num_sites];
+    if ( !m_neighbors ) handleError("Not enough memory");
+  }
+
+  Neighbor *temp1 = (Neighbor *) new Neighbor;
+  Neighbor *temp2 = (Neighbor *) new Neighbor;
+
+  temp1->weight  = weight;
+  temp1->to_node = site2;
+
+  temp2->weight  = weight;
+  temp2->to_node = site1;
+
+  m_neighbors[site1].addFront(temp1);
+  m_neighbors[site2].addFront(temp2);
+
+}
+//------------------------------------------------------------------
+
+void GCoptimizationGeneralGraph::setAllNeighbors(SiteID *numNeighbors, SiteID **neighborsIndexes,
+    EnergyTermType **neighborsWeights)
+{
+  m_needTodeleteNeighbors = false;
+  m_needToFinishSettingNeighbors = false;
+  if ( m_neighbors ) handleError("Already set up neighborhood system");
+
+  m_numNeighbors     = numNeighbors;
+  m_neighborsIndexes = neighborsIndexes;
+  m_neighborsWeights = neighborsWeights;
+}
+

+ 661 - 0
mrf/mrfmin/GCoptimization.h

@@ -0,0 +1,661 @@
+/*#########################################################################
+#                                                                       #
+#    GC_optimization - software for energy minimization with graph cuts #
+#                        Version 2.3                                    #
+#    http://www.csd.uwo.ca/faculty/olga/software.html                   #
+#                                                                       #
+#    Copyright 2007 Olga Veksler (olga@csd.uwo.ca)                      #
+#                                                                       #
+#    I would like to thank Andrew Delong for his invaluable help        #
+#    with C++ when redesigning the GC interface.  Thank you for         #
+#    helping me to make my code 5 times shorter and 100 times more      #
+#    debuggable. And not for scaring me with DLL's :)                   #
+#########################################################################
+*/
+// Copyright 2007 Olga Veksler (olga@csd.uwo.ca)
+// email olga@csd.uwo.ca for any questions, suggestions and bug reports
+
+////////////////////////////////////////////////////////////////////////////////////
+//  IMPORTANT!!!!!!
+//  If you use this software, YOU HAVE TO REFERENCE (at least) 3 papers, the citations [1]
+//  [2] and [3] below
+///////////////////////////////////////////////////////////////////////////////////
+// For description and  example usage see GC_README.TXT
+///////////////////////////////////////////////////////////////////////////////////
+/*
+ This software library implements the Graph Cuts Energy Minimization methods
+ described in
+
+
+  [1] Efficient Approximate Energy Minimization via Graph Cuts
+      Yuri Boykov, Olga Veksler, Ramin Zabih,
+      IEEE transactions on PAMI, vol. 20, no. 12, p. 1222-1239, November 2001.
+
+
+
+ This software can be used only for research purposes, you should cite
+ the aforementioned paper in any resulting publication.
+ If you wish to use this software (or the algorithms described in the aforementioned paper)
+ for commercial purposes, you should be aware that there is a US patent:
+
+  R. Zabih, Y. Boykov, O. Veksler,
+  "System and method for fast approximate energy minimization via graph cuts ",
+  United Stated Patent 6,744,923, June 1, 2004
+
+*/
+
+/* Together with the library implemented by O. Veksler, we provide, with the permission of the
+    V. Kolmogorov and Y. Boykov the following libraries:  */
+
+
+/*1) energy.h, which was developed by Vladimir Kolmogorov and  implements binary energy minimization
+ technique described in
+
+ [2] What Energy Functions can be Minimized via Graph Cuts?
+     Vladimir Kolmogorov and Ramin Zabih.
+     To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI).
+     Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002.
+
+
+ We use "energy.h" to implement the binary energy minimization step
+ for the alpha-expansion and swap algorithms. The graph construction provided by "energy.h" is
+ more efficient (and slightly more general) than the original graph construction for the
+ alpha-expansion algorithm in the paper cited as [1]
+
+
+ This software can be used only for research purposes. IF YOU USE THIS SOFTWARE,
+ YOU SHOULD CITE THE AFOREMENTIONED PAPER [2] IN ANY RESULTING PUBLICATION.
+
+
+
+2)  graph.h, block.h, maxflow.cpp
+
+ This software library implements the maxflow algorithm
+ described in
+
+  [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms
+      for Energy Minimization in Vision.
+      Yuri Boykov and Vladimir Kolmogorov.
+      In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI),
+      September 2004
+
+ This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov
+ at Siemens Corporate Research. To make it available for public use,
+ it was later reimplemented by Vladimir Kolmogorov based on open publications.
+
+ If you use this software for research purposes, you should cite
+ the aforementioned paper in any resulting publication.
+*/
+
+/* These 4 files (energy.h,graph.h, block.h, maxflow.cpp) are included in the curent library with permission of
+Vladimir Kolmogorov and Yuri Boykov.
+The can  also be downloaded independently from Vladimir Kolmogorov's
+website:http://www.adastral.ucl.ac.uk/~vladkolm/software.html
+*/
+
+
+///////////////////////////////////////////////////////////////////////////////////
+/*
+
+    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.
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __GCOPTIMIZATION_H__
+#define __GCOPTIMIZATION_H__
+
+#include "energy.h"
+#include "graph.h"
+#include <memory.h>
+#include <stdio.h>
+#include <limits.h>
+
+#ifdef _MSC_EXTENSIONS
+#define OLGA_INLINE __forceinline
+#else
+#define OLGA_INLINE inline
+#endif
+
+namespace OBJREC {
+
+class LinkedBlockList;
+
+class GCoptimization
+{
+  public:
+    typedef Graph::flowtype EnergyType;     // Type for the total energy the energy function.Change it in Graph.h
+    typedef Graph::captype EnergyTermType;  // Type for the individual terms in the energy function.Change it in Graph.h
+    typedef Energy::Var VarID;
+    typedef int LabelID;                   // Type for labels
+    typedef int SiteID;                    // Type for sites
+    typedef EnergyTermType (*SmoothCostFn)(SiteID s1, SiteID s2, LabelID l1, LabelID l2);
+    typedef EnergyTermType (*DataCostFn)(SiteID s, LabelID l);
+    typedef EnergyTermType (*SmoothCostFnExtra)(SiteID s1, SiteID s2, LabelID l1, LabelID l2, void *);
+    typedef EnergyTermType (*DataCostFnExtra)(SiteID s, LabelID l, void *);
+
+
+    GCoptimization(SiteID num_sites, LabelID num_labels);
+    virtual ~GCoptimization();
+
+    // Peforms expansion algorithm. Runs the number of iterations specified by max_num_iterations
+    // If no input specified,runs until convergence. Returns total energy of labeling.
+    EnergyType expansion(int max_num_iterations = INT_MAX);
+
+    // Peforms  expansion on one label, specified by the input parameter alpha_label
+    void alpha_expansion(LabelID alpha_label);
+
+    // Peforms  expansion on label alpha_label only for sites specified by *sites.
+    // num is the size of  array "sites"
+    void alpha_expansion(LabelID alpha_label, SiteID *sites, SiteID num);
+
+    // Peforms swap algorithm. Runs it the specified number of iterations. If no
+    // input is specified,runs until convergence
+    EnergyType swap(int max_num_iterations = INT_MAX);
+
+    // Peforms  swap on a pair of labels, specified by the input parameters alpha_label, beta_label
+    void alpha_beta_swap(LabelID alpha_label, LabelID beta_label);
+
+    // Peforms  swap on a pair of labels, specified by the input parameters alpha_label, beta_label
+    // only on the sitess in the specified arrays, alphaSites and betaSitess, and the array sizes
+    // are, respectively, alpha_size and beta_size
+    void alpha_beta_swap(LabelID alpha_label, LabelID beta_label, SiteID *alphaSites,
+                         SiteID alpha_size, SiteID *betaSites, SiteID beta_size);
+
+    struct DataCostFunctor;      // use this class to pass a functor to setDataCost
+    struct SmoothCostFunctor;    // use this class to pass a functor to setSmoothCost
+
+    void setDataCost(DataCostFn fn);
+    void setDataCost(DataCostFnExtra fn, void *extraData);
+    void setDataCost(EnergyTermType *dataArray);
+    void setDataCost(SiteID s, LabelID l, EnergyTermType e);
+    void setDataCostFunctor(DataCostFunctor* f);
+    struct DataCostFunctor {
+      virtual EnergyTermType compute(SiteID s, LabelID l) = 0;
+    };
+
+    void setSmoothCost(SmoothCostFn fn);
+    void setSmoothCost(SmoothCostFnExtra fn, void *extraData);
+    void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e);
+    void setSmoothCost(EnergyTermType *smoothArray);
+    void setSmoothCostFunctor(SmoothCostFunctor* f);
+    struct SmoothCostFunctor {
+      virtual EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) = 0;
+    };
+
+
+    // Returns current label assigned to input site
+    inline LabelID whatLabel(SiteID site) {
+      assert(site >= 0 && site < m_num_sites);
+      return(m_labeling[site]);
+    };
+
+    // This function can be used to change the label of any site at any time
+    inline void setLabel(SiteID site, LabelID label) {
+      assert(label >= 0 && label < m_num_labels && site >= 0 && site < m_num_sites);
+      m_labeling[site] = label;
+    };
+
+    // setLabelOrder(false) sets the order to be not random; setLabelOrder(true)
+    // sets the order to random. By default, the labels are visited in non-random order
+    // for both the swap and alpha-expansion moves
+    void setLabelOrder(bool RANDOM_LABEL_ORDER);
+
+    // returns total energy
+    EnergyType compute_energy();
+
+    // Returns Data Energy of current labeling
+    EnergyType giveDataEnergy();
+
+    // Returns Smooth Energy of current labeling
+    EnergyType giveSmoothEnergy();
+
+    // For advanced users who want to squeeze maximum performance out of
+    // their custom functors. By specializing the GCoptimization class
+    // (via this method), the compiler knows the exact class you intend
+    // to use to compute costs. The compiler then inlines your compute
+    // function in all the right places, provided it's not virtual.
+    // The functor class need not derive from anything in this case.
+    template <typename UserFunctor> void specializeDataCostFunctor(const UserFunctor f);
+    template <typename UserFunctor> void specializeSmoothCostFunctor(const UserFunctor f);
+
+  protected:
+
+    LabelID m_num_labels;
+    SiteID m_num_sites;
+    LabelID *m_labeling;
+    SiteID  *m_lookupSiteVar; // holds index of variable corresponding to site participating in a move,
+    // -1 for nonparticipating site
+    LabelID *m_labelTable;    // to figure out label order in which to do expansion/swaps
+    int m_random_label_order;
+    EnergyTermType* m_datacostIndividual;
+    EnergyTermType* m_smoothcostIndividual;
+
+    void*   m_datacostFn;
+    void*   m_smoothcostFn;
+
+    EnergyType (GCoptimization::*m_giveDataEnergyInternal)();
+    EnergyType (GCoptimization::*m_giveSmoothEnergyInternal)();
+    void (GCoptimization::*m_set_up_n_links_expansion)(SiteID, LabelID, Energy*, VarID*, SiteID*);
+    void (GCoptimization::*m_set_up_t_links_expansion)(SiteID, LabelID, Energy*, VarID*, SiteID*);
+    void (GCoptimization::*m_set_up_n_links_swap)(SiteID, LabelID, LabelID, Energy*, VarID*, SiteID*);
+    void (GCoptimization::*m_set_up_t_links_swap)(SiteID, LabelID, LabelID, Energy*, VarID*, SiteID*);
+    void (*m_datacostFnDelete)(void* f);
+    void (*m_smoothcostFnDelete)(void* f);
+
+    // returns a pointer to the neighbors of a site and the weights
+    virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights) = 0;
+
+    virtual bool readyToOptimise();
+
+    template <typename DataCostT>
+    void set_up_t_links_expansion(SiteID size, LabelID alpha_label, Energy *e, VarID *variables, SiteID *activeSites );
+
+    template <typename DataCostT>
+    void set_up_t_links_swap(SiteID size, LabelID alpha_label, LabelID beta_label, Energy *e, VarID *variables, SiteID *activeSites );
+
+    template <typename SmoothCostT>
+    void set_up_n_links_expansion(SiteID size, LabelID alpha_label, Energy *e, VarID *variables, SiteID *activeSites );
+
+    template <typename SmoothCostT>
+    void set_up_n_links_swap(SiteID size, LabelID alpha_label, LabelID beta_label, Energy *e, VarID *variables, SiteID *activeSites );
+
+
+    // Returns Data Energy of current labeling
+    template <typename DataCostT>
+    EnergyType giveDataEnergyInternal();
+
+    // Returns Smooth Energy of current labeling
+    template <typename SmoothCostT>
+    EnergyType giveSmoothEnergyInternal();
+
+    template <typename Functor>
+    static void deleteFunctor(void* f) {
+      delete reinterpret_cast<Functor*>(f);
+    }
+
+    struct DataCostFnFromArray {
+      DataCostFnFromArray(EnergyTermType* theArray, LabelID num_labels)
+          : m_array(theArray), m_num_labels(num_labels) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l) {
+        return m_array[s*m_num_labels+l];
+      }
+
+    private:
+      const EnergyTermType* const m_array;
+      const LabelID m_num_labels;
+    };
+
+    struct DataCostFnFromFunction {
+      DataCostFnFromFunction(DataCostFn fn): m_fn(fn) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l) {
+        return m_fn(s, l);
+      }
+    private:
+      const DataCostFn m_fn;
+    };
+
+    struct DataCostFnFromFunctionExtra {
+      DataCostFnFromFunctionExtra(DataCostFnExtra fn, void *extraData): m_fn(fn), m_extraData(extraData) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l) {
+        return m_fn(s, l, m_extraData);
+      }
+    private:
+      const DataCostFnExtra m_fn;
+      void *m_extraData;
+    };
+
+    struct SmoothCostFnFromArray {
+      SmoothCostFnFromArray(EnergyTermType* theArray, LabelID num_labels)
+          : m_array(theArray), m_num_labels(num_labels) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) {
+        return m_array[l1*m_num_labels+l2];
+      }
+    private:
+      const EnergyTermType* const m_array;
+      const LabelID m_num_labels;
+    };
+
+    struct SmoothCostFnFromFunction {
+      SmoothCostFnFromFunction(SmoothCostFn fn)
+          : m_fn(fn) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) {
+        return m_fn(s1, s2, l1, l2);
+      }
+    private:
+      const SmoothCostFn m_fn;
+    };
+
+    struct SmoothCostFnFromFunctionExtra {
+      SmoothCostFnFromFunctionExtra(SmoothCostFnExtra fn, void *extraData)
+          : m_fn(fn), m_extraData(extraData) {}
+      OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) {
+        return m_fn(s1, s2, l1, l2, m_extraData);
+      }
+    private:
+      const SmoothCostFnExtra m_fn;
+      void *m_extraData;
+    };
+
+    void handleError(const char *message);
+  private:
+    void solveExpansion(SiteID size, SiteID *activeSites, LabelID alpha_label);
+    EnergyType oneExpansionIteration();
+    void set_up_expansion_energy(SiteID size, LabelID alpha_label, Energy *e, VarID *variables, SiteID *activeSites );
+
+    void solveSwap(SiteID size, SiteID *activeSites, LabelID alpha_label, LabelID beta_label);
+    // Peforms one iteration (one pass over all pairs of labels)  of swap algorithm
+    EnergyType oneSwapIteration();
+    void set_up_swap_energy(SiteID size, LabelID alpha_label, LabelID beta_label,
+                            Energy* e, Energy::Var *variables, SiteID *activeSites);
+
+    void scramble_label_table();
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// Use this derived class for grid graphs
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+class GCoptimizationGridGraph: public GCoptimization
+{
+  public:
+    GCoptimizationGridGraph(SiteID width, SiteID height, LabelID num_labels);
+    virtual ~GCoptimizationGridGraph();
+
+    void setSmoothCostVH(EnergyTermType *smoothArray, EnergyTermType *vCosts, EnergyTermType *hCosts);
+    virtual bool readyToOptimise();
+
+  protected:
+    virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights);
+    EnergyTermType m_unityWeights[4];
+    int m_weightedGraph;  // true if spatially varying w_pq's are present. False otherwise.
+
+  private:
+    SiteID m_width;
+    SiteID m_height;
+    SiteID *m_numNeighbors;              // holds num of neighbors
+    SiteID *m_neighbors;                 // holds neighbor indexes
+    EnergyTermType *m_neighborsWeights;    // holds neighbor weights
+
+    void setupNeighbData(SiteID startY, SiteID endY, SiteID startX, SiteID endX, SiteID maxInd, SiteID *indexes);
+    void computeNeighborWeights(EnergyTermType *vCosts, EnergyTermType *hCosts);
+
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+class GCoptimizationGeneralGraph: public GCoptimization
+{
+
+  public:
+    // This is the constructor for non-grid graphs. Neighborhood structure must  be specified by
+    // setNeighbors()  function
+    GCoptimizationGeneralGraph(SiteID num_sites, LabelID num_labels);
+    virtual ~GCoptimizationGeneralGraph();
+
+    virtual bool readyToOptimise();
+
+    // Makes site1 and site2 neighbors of each other. Can be called only 1 time for each
+    // unordered pair of sites. Parameter weight can be used to set spacially varying terms
+    // If the desired penalty for neighboring sites site1 and site2 is
+    // V(label1,label2) = weight*SmoothnessPenalty(label1,label2), then
+    // member function setLabel should be called as: setLabel(site1,site2,weight)
+    void setNeighbors(SiteID site1, SiteID site2, EnergyTermType weight = 1);
+
+    // passes pointers to arrays storing neighbor information
+    // numNeighbors[i] is the number of neighbors for site i
+    // neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i
+    // neighborWeights[i] is a pointer to array storing the weights between site i and its neighbors
+    // in the same order as neighborIndexes[i] stores the indexes
+    void setAllNeighbors(SiteID *numNeighbors, SiteID **neighborsIndexes, EnergyTermType **neighborsWeights);
+
+  protected:
+    virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights);
+
+  private:
+
+    typedef struct NeighborStruct {
+      SiteID  to_node;
+      EnergyTermType weight;
+    } Neighbor;
+
+
+    LinkedBlockList *m_neighbors;
+    bool m_needToFinishSettingNeighbors;
+    SiteID *m_numNeighbors;
+    SiteID **m_neighborsIndexes;
+    EnergyTermType **m_neighborsWeights;
+    bool m_needTodeleteNeighbors;
+
+
+    //Call this function when you are finished setting neibhbors
+    void finishSettingNeighbors();
+
+
+};
+
+
+/////////////////////////////////////////////////////////////////////
+// Class for handling errors
+/////////////////////////////////////////////////////////////////////
+
+class GCException
+{
+  public:
+    const char* message;
+    GCException( const char* m ) {
+      message = m;
+    }
+    void Report() {
+      printf("\n%s\n", message);
+      exit(0);
+    }
+};
+
+
+
+
+////////////////////////////////////////////////////////////////////
+// Methods
+////////////////////////////////////////////////////////////////////
+
+template <typename UserFunctor>
+void GCoptimization::specializeDataCostFunctor(const UserFunctor f) {
+  if ( m_datacostFn ) handleError("Data Costs are already initialized");
+
+  m_datacostFn = new UserFunctor(f);
+  m_datacostFnDelete         = &GCoptimization::deleteFunctor<UserFunctor>;
+  m_giveDataEnergyInternal   = &GCoptimization::giveDataEnergyInternal<UserFunctor>;
+  m_set_up_t_links_expansion = &GCoptimization::set_up_t_links_expansion<UserFunctor>;
+  m_set_up_t_links_swap      = &GCoptimization::set_up_t_links_swap<UserFunctor>;
+}
+
+template <typename UserFunctor>
+void GCoptimization::specializeSmoothCostFunctor(const UserFunctor f) {
+  if ( m_smoothcostFn ) handleError("Smoothness Costs are already initialized");
+
+  m_smoothcostFn = new UserFunctor(f);
+  m_smoothcostFnDelete       = &GCoptimization::deleteFunctor<UserFunctor>;
+  m_giveSmoothEnergyInternal = &GCoptimization::giveSmoothEnergyInternal<UserFunctor>;
+  m_set_up_n_links_expansion = &GCoptimization::set_up_n_links_expansion<UserFunctor>;
+  m_set_up_n_links_swap      = &GCoptimization::set_up_n_links_swap<UserFunctor>;
+}
+
+//-------------------------------------------------------------------
+template <typename DataCostT>
+GCoptimization::EnergyType GCoptimization::giveDataEnergyInternal()
+{
+
+  EnergyType eng = (EnergyType) 0;
+
+  DataCostT* tc = (DataCostT*)m_datacostFn;
+
+  for ( SiteID i = 0; i < m_num_sites; i++ )
+  {
+    assert(m_labeling[i] >= 0 && m_labeling[i] < m_num_labels);
+    eng = eng + tc->compute(i, m_labeling[i]);
+  }
+
+  return(eng);
+}
+
+//-------------------------------------------------------------------
+template <typename SmoothCostT>
+GCoptimization::EnergyType GCoptimization::giveSmoothEnergyInternal()
+{
+
+  EnergyType eng = (EnergyType) 0;
+  SiteID i, numN, *nPointer, nSite, n;
+  EnergyTermType *weights;
+
+  SmoothCostT* sc = (SmoothCostT*) m_smoothcostFn;
+
+  for ( i = 0; i < m_num_sites; i++ )
+  {
+    giveNeighborInfo(i, &numN, &nPointer, &weights);
+
+    for ( n = 0; n < numN; n++ )
+    {
+      nSite = nPointer[n];
+      if ( nSite < i ) eng =
+          eng + weights[n] * (sc->compute(i, nSite, m_labeling[i], m_labeling[nSite]));
+    }
+  }
+
+  return(eng);
+}
+
+
+//-------------------------------------------------------------------//
+//                  METHODS for EXPANSION MOVES                      //
+//-------------------------------------------------------------------//
+
+template <typename DataCostT>
+void GCoptimization::set_up_t_links_expansion(SiteID size, LabelID alpha_label, Energy *e,
+    VarID *variables, SiteID *activeSites )
+{
+  DataCostT* dc = (DataCostT*)m_datacostFn;
+
+  for ( SiteID i = 0; i < size; i++ )
+  {
+    e -> add_term1(variables[i], dc->compute(activeSites[i], alpha_label),
+                   dc->compute(activeSites[i], m_labeling[activeSites[i]]));
+  }
+}
+
+//-------------------------------------------------------------------
+
+template <typename SmoothCostT>
+void GCoptimization::set_up_n_links_expansion(SiteID size, LabelID alpha_label, Energy *e,
+    VarID *variables, SiteID *activeSites )
+{
+  SiteID i, nSite, site, n, nNum, *nPointer;
+  EnergyTermType *weights;
+
+  SmoothCostT* sc = (SmoothCostT*)m_smoothcostFn;
+
+  for ( i = size - 1; i >= 0; i-- )
+  {
+    site = activeSites[i];
+
+    giveNeighborInfo(site, &nNum, &nPointer, &weights);
+    for ( n = 0; n < nNum; n++ )
+    {
+      nSite = nPointer[n];
+
+
+      if ( nSite < site )
+      {
+        if ( m_lookupSiteVar[nSite] != -1 )
+          e ->add_term2(variables[i], variables[m_lookupSiteVar[nSite]],
+                        sc->compute(site, nSite, alpha_label, alpha_label)*weights[n],
+                        sc->compute(site, nSite, alpha_label, m_labeling[nSite])*weights[n],
+                        sc->compute(site, nSite, m_labeling[site], alpha_label)*weights[n],
+                        sc->compute(site, nSite, m_labeling[site], m_labeling[nSite])*weights[n]);
+        else   e ->add_term1(variables[i], sc->compute(site, nSite, alpha_label, m_labeling[nSite])*weights[n],
+                               sc->compute(site, nSite, m_labeling[site], m_labeling[nSite])*weights[n]);
+      }
+      else
+      {
+        if (m_lookupSiteVar[nSite] == -1 )
+          e ->add_term1(variables[i], sc->compute(site, nSite, alpha_label, m_labeling[nSite])*weights[n],
+                        sc->compute(site, nSite, m_labeling[site], m_labeling[nSite])*weights[n]);
+      }
+    }
+  }
+}
+
+
+//-------------------------------------------------------------------//
+//                  METHODS for SWAP MOVES                           //
+//-------------------------------------------------------------------//
+
+
+template <typename DataCostT>
+void GCoptimization::set_up_t_links_swap(SiteID size, LabelID alpha_label, LabelID beta_label,
+    Energy *e, VarID *variables, SiteID *activeSites )
+{
+  DataCostT* dc = (DataCostT*)m_datacostFn;
+
+  for ( SiteID i = 0; i < size; i++ )
+  {
+    e -> add_term1(variables[i], dc->compute(activeSites[i], alpha_label),
+                   dc->compute(activeSites[i], beta_label) );
+  }
+}
+
+//-------------------------------------------------------------------
+
+template <typename SmoothCostT>
+void GCoptimization::set_up_n_links_swap(SiteID size, LabelID alpha_label, LabelID beta_label,
+    Energy *e, VarID *variables, SiteID *activeSites )
+{
+  SiteID i, nSite, site, n, nNum, *nPointer;
+  EnergyTermType *weights;
+
+  SmoothCostT* sc = (SmoothCostT*)m_smoothcostFn;
+
+  for ( i = size - 1; i >= 0; i-- )
+  {
+    site = activeSites[i];
+
+    giveNeighborInfo(site, &nNum, &nPointer, &weights);
+    for ( n = 0; n < nNum; n++ )
+    {
+      nSite = nPointer[n];
+
+      if ( nSite < site )
+      {
+        if ( m_lookupSiteVar[nSite] != -1 )
+          e ->add_term2(variables[i], variables[m_lookupSiteVar[nSite]],
+                        sc->compute(site, nSite, alpha_label, alpha_label)*weights[n],
+                        sc->compute(site, nSite, alpha_label, beta_label)*weights[n],
+                        sc->compute(site, nSite, beta_label, alpha_label)*weights[n],
+                        sc->compute(site, nSite, beta_label, beta_label)*weights[n]);
+        else   e ->add_term1(variables[i], sc->compute(site, nSite, alpha_label, m_labeling[nSite])*weights[n],
+                               sc->compute(site, nSite, beta_label, m_labeling[nSite])*weights[n]);
+      }
+      else
+      {
+        if (m_lookupSiteVar[nSite] == -1 )
+          e ->add_term1(variables[i], sc->compute(site, nSite, alpha_label, m_labeling[nSite])*weights[n],
+                        sc->compute(site, nSite, beta_label, m_labeling[nSite])*weights[n]);
+      }
+    }
+  }
+}
+
+} //namespace
+
+#endif

+ 328 - 0
mrf/mrfmin/ICM.cpp

@@ -0,0 +1,328 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "ICM.h"
+
+using namespace OBJREC;
+
+#define m_D(pix,l)  m_D[(pix)*m_nLabels+(l)]
+#define m_V(l1,l2)  m_V[(l1)*m_nLabels+(l2)]
+
+
+        
+
+
+ICM::ICM(int width, int height, int nLabels,EnergyFunction *eng):MRF(width,height,nLabels,eng)
+{
+    m_needToFreeV = 0;
+    initializeAlg();
+}
+ICM::ICM(int nPixels, int nLabels,EnergyFunction *eng):MRF(nPixels,nLabels,eng)
+{
+    m_needToFreeV = 0;
+    initializeAlg();
+}
+
+ICM::~ICM()
+{ 
+    delete[] m_answer;
+    if (!m_grid_graph) delete[] m_neighbors;
+    if ( m_needToFreeV ) delete[] m_V;
+}
+
+
+void ICM::initializeAlg()
+{
+    m_answer = (Label *) new Label[m_nPixels];
+    if ( !m_answer ){printf("\nNot enough memory, exiting");exit(0);}
+
+    if (!m_grid_graph)
+    {
+        m_neighbors = (LinkedBlockList *) new LinkedBlockList[m_nPixels];
+        if (!m_neighbors) {printf("Not enough memory,exiting");exit(0);};
+    }
+}
+
+void ICM::clearAnswer()
+{
+    memset(m_answer, 0, m_nPixels*sizeof(Label));
+}
+
+void ICM::setNeighbors(int pixel1, int pixel2, CostVal weight)
+{
+    assert(!m_grid_graph);
+    assert(pixel1 < m_nPixels && pixel1 >= 0 && pixel2 < m_nPixels && pixel2 >= 0);
+
+
+    Neighbor *temp1 = (Neighbor *) new Neighbor;
+    Neighbor *temp2 = (Neighbor *) new Neighbor;
+
+    if ( !temp1 || ! temp2 ) {printf("\nNot enough memory, exiting");exit(0);}
+
+    temp1->weight  = weight;
+    temp1->to_node = pixel2;
+
+    temp2->weight  = weight;
+    temp2->to_node = pixel1;
+
+    m_neighbors[pixel1].addFront(temp1);
+    m_neighbors[pixel2].addFront(temp2);
+}
+
+
+MRF::EnergyVal ICM::smoothnessEnergy()
+{
+    EnergyVal eng = (EnergyVal) 0;
+    EnergyVal weight;
+    int x,y,pix,i;
+
+    if ( m_grid_graph )
+    {
+        if ( m_smoothType != FUNCTION  )
+        {
+            for ( y = 0; y < m_height; y++ )
+                for ( x = 1; x < m_width; x++ )
+                {
+                    pix    = x+y*m_width;
+                    weight = m_varWeights ? m_horizWeights[pix-1] :  1;
+                    eng = eng + m_V(m_answer[pix],m_answer[pix-1])*weight;
+                }
+
+            for ( y = 1; y < m_height; y++ )
+                for ( x = 0; x < m_width; x++ )
+                {
+                    pix = x+y*m_width;
+                    weight = m_varWeights ? m_vertWeights[pix-m_width] :  1;
+                    eng = eng + m_V(m_answer[pix],m_answer[pix-m_width])*weight;
+                }
+        }
+        else
+        {
+            for ( y = 0; y < m_height; y++ )
+                for ( x = 1; x < m_width; x++ )
+                {
+                    pix = x+y*m_width;
+                    eng = eng + m_smoothFn(pix,pix-1,m_answer[pix],m_answer[pix-1]);
+                }
+
+            for ( y = 1; y < m_height; y++ )
+                for ( x = 0; x < m_width; x++ )
+                {
+                    pix = x+y*m_width;
+                    eng = eng + m_smoothFn(pix,pix-m_width,m_answer[pix],m_answer[pix-m_width]);
+                }
+        }
+    }
+    else
+    {
+        
+        Neighbor *temp; 
+
+        if ( m_smoothType != FUNCTION  )
+        {
+            for ( i = 0; i < m_nPixels; i++ )
+                if ( !m_neighbors[i].isEmpty() )
+                {
+                    m_neighbors[i].setCursorFront();
+                    while ( m_neighbors[i].hasNext() )
+                    {
+                        temp = (Neighbor *) m_neighbors[i].next();
+
+                        if ( i < temp->to_node )
+                            eng = eng + m_V(m_answer[i],m_answer[temp->to_node])*(temp->weight);
+                    }
+                }
+        }
+        else
+        {
+            for ( i = 0; i < m_nPixels; i++ )
+                if ( !m_neighbors[i].isEmpty() )
+                {
+                    m_neighbors[i].setCursorFront();
+                    while ( m_neighbors[i].hasNext() )
+                    {
+                        temp = (Neighbor *) m_neighbors[i].next();
+                        if ( i < temp->to_node )
+                            eng = eng + m_smoothFn(i,temp->to_node, m_answer[i],m_answer[temp->to_node]);
+                }
+            }
+        }
+        
+    }
+
+    return(eng);
+}
+
+
+
+MRF::EnergyVal ICM::dataEnergy()
+{
+    EnergyVal eng = (EnergyVal) 0;
+
+    
+    if ( m_dataType == ARRAY) 
+    {
+        for ( int i = 0; i < m_nPixels; i++ )
+            eng = eng + m_D(i,m_answer[i]);
+    }
+    else
+    {
+        for ( int i = 0; i < m_nPixels; i++ )
+            eng = eng + m_dataFn(i,m_answer[i]);
+    }
+    return(eng);
+
+}
+
+
+void ICM::setData(DataCostFn dcost)
+{
+    m_dataFn = dcost;
+}
+
+void ICM::setData(CostVal* data)
+{
+    m_D = data;
+}
+
+
+void ICM::setSmoothness(SmoothCostGeneralFn cost)
+{
+    m_smoothFn = cost;
+}
+void ICM::setSmoothness(CostVal* V)
+{
+    m_V = V;
+}
+
+
+void ICM::setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda)
+{
+    int i, j;
+    CostVal cost;
+
+
+    m_needToFreeV = 1;
+
+    m_V = (CostVal *) new CostVal[m_nLabels*m_nLabels*sizeof(CostVal)];
+    if (!m_V) { fprintf(stderr, "Not enough memory!\n"); exit(1); }
+
+
+    for (i=0; i<m_nLabels; i++)
+        for (j=i; j<m_nLabels; j++)
+        {
+            cost = (CostVal) ((smoothExp == 1) ? j - i : (j - i)*(j - i));
+            if (cost > smoothMax) cost = smoothMax;
+            m_V[i*m_nLabels + j] = m_V[j*m_nLabels + i] = cost*lambda;
+        }
+
+}
+
+
+void ICM::setCues(CostVal* hCue, CostVal* vCue)
+{
+    m_horizWeights = hCue;
+    m_vertWeights  = vCue;
+}
+
+
+void ICM::optimizeAlg(int nIterations)
+{
+    int x, y, i, j, n;
+    Label* l;
+    CostVal* dataPtr;
+    CostVal *D = (CostVal *) new CostVal[m_nLabels];
+    if ( !D ) {printf("\nNot enough memory, exiting");exit(0);}
+
+    if ( !m_grid_graph) {printf("\nICM is not implemented for nongrids yet!");exit(1);}
+
+    for ( ; nIterations > 0; nIterations --)
+    {
+        n = 0;
+        l = m_answer;
+        dataPtr = m_D;
+
+        for (y=0; y<m_height; y++)
+        for (x=0; x<m_width; x++, l++, dataPtr+=m_nLabels, n++)
+        {
+            // set array D
+            if (m_dataType == FUNCTION)
+            {
+                for (i=0; i<m_nLabels; i++)
+                {
+                    D[i] = m_dataFn(x+y*m_width, i);
+                }
+            }
+            else memcpy(D, dataPtr, m_nLabels*sizeof(CostVal));
+            
+
+            // add smoothness costs
+            if (m_smoothType == FUNCTION)
+            {
+                if (x > 0)
+                {
+                    j = *(l-1);
+                    for (i=0; i<m_nLabels; i++) D[i] += m_smoothFn(x+y*m_width-1, x+y*m_width, j, i);
+                }
+                if (y > 0)
+                {
+                    j = *(l-m_width);
+                    for (i=0; i<m_nLabels; i++) D[i] += m_smoothFn(x+y*m_width-m_width,x+y*m_width , j, i);
+                }
+                if (x < m_width-1)
+                {
+                    j = *(l+1);
+                    for (i=0; i<m_nLabels; i++) D[i] += m_smoothFn(x+y*m_width+1, x+y*m_width, i, j);
+                }
+                if (y < m_height-1)
+                {
+                    j = *(l+m_width);
+                    for (i=0; i<m_nLabels; i++) D[i] += m_smoothFn(x+y*m_width+m_width, x+y*m_width, i, j);
+                }
+            }
+            else
+            {
+                if (x > 0)
+                {
+                    j = *(l-1);
+                    CostVal lambda = (m_varWeights) ? m_horizWeights[n-1] : 1;
+                    for (i=0; i<m_nLabels; i++) D[i] += lambda * m_V[j*m_nLabels + i];
+                }
+                if (y > 0)
+                {
+                    j = *(l-m_width);
+                    CostVal lambda = (m_varWeights) ? m_vertWeights[n-m_width] : 1;
+                    for (i=0; i<m_nLabels; i++) D[i] += lambda * m_V[j*m_nLabels + i];
+                }
+                if (x < m_width-1)
+                {
+                    j = *(l+1);
+                    CostVal lambda = (m_varWeights) ? m_horizWeights[n] : 1;
+                    for (i=0; i<m_nLabels; i++) D[i] += lambda * m_V[j*m_nLabels + i];
+                }
+                if (y < m_height-1)
+                {
+                    j = *(l+m_width);
+                    CostVal lambda = (m_varWeights) ? m_vertWeights[n] : 1;
+                    for (i=0; i<m_nLabels; i++) D[i] += lambda * m_V[j*m_nLabels + i];
+                }
+            }
+
+            // compute minimum of D, set new label for (x,y)
+            CostVal D_min = D[0];
+            *l = 0;
+            for (i=1; i<m_nLabels; i++)
+            {
+                if (D_min > D[i])
+                {
+                    D_min = D[i];
+                    *l = i;
+                }
+            }
+        }
+    }
+
+    delete[] D;
+}
+

+ 60 - 0
mrf/mrfmin/ICM.h

@@ -0,0 +1,60 @@
+#ifndef __ICM_H__
+#define __ICM_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mrf.h"
+#include "LinkedBlockList.h"
+
+namespace OBJREC {
+
+class ICM : public MRF{
+public:
+    ICM(int width, int height, int nLabels, EnergyFunction *eng);
+    ICM(int nPixels, int nLabels,EnergyFunction *eng);
+    ~ICM();
+    void setNeighbors(int pix1, int pix2, CostVal weight);
+    Label getLabel(int pixel){return(m_answer[pixel]);};
+    void setLabel(int pixel,Label label){m_answer[pixel] = label;};
+    Label* getAnswerPtr(){return(m_answer);};
+    void clearAnswer();
+    void setParameters(int /*numParam*/, void * /*param*/){printf("No optional parameters to set"); exit(1);}
+    EnergyVal smoothnessEnergy();
+    EnergyVal dataEnergy();
+
+protected:
+    void setData(DataCostFn dcost); 
+    void setData(CostVal* data);    
+    void setSmoothness(SmoothCostGeneralFn cost);
+    void setSmoothness(CostVal* V);
+    void setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda);
+    void setCues(CostVal* hCue, CostVal* vCue); 
+    void initializeAlg();
+    void optimizeAlg(int nIterations);
+
+private:
+    Label *m_answer;
+    CostVal *m_V;
+    CostVal *m_D;
+    CostVal *m_horizWeights;
+    CostVal *m_vertWeights;
+    DataCostFn m_dataFn;
+    SmoothCostGeneralFn m_smoothFn;
+    bool m_needToFreeV;
+
+    typedef struct NeighborStruct{
+        int     to_node;
+        CostVal weight;
+    } Neighbor;
+
+    LinkedBlockList *m_neighbors;
+};
+
+}
+
+
+#endif /*  __ICM_H__ */
+
+

+ 72 - 0
mrf/mrfmin/LinkedBlockList.cpp

@@ -0,0 +1,72 @@
+#include "LinkedBlockList.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace OBJREC;
+
+/*********************************************************************/
+
+void LinkedBlockList::addFront(ListType item) {
+
+  if ( m_head_block_size == GCLL_BLOCK_SIZE )
+  {
+    LLBlock *tmp      = (LLBlock *) new LLBlock;
+    if ( !tmp ) {
+      printf("\nOut of memory");
+      exit(1);
+    }
+    tmp -> m_next     = m_head;
+    m_head            = tmp;
+    m_head_block_size = 0;
+  }
+
+  m_head ->m_item[m_head_block_size] = item;
+  m_head_block_size++;
+}
+
+/*********************************************************************/
+
+ListType LinkedBlockList::next()
+{
+  ListType toReturn = m_cursor -> m_item[m_cursor_ind];
+
+  m_cursor_ind++;
+
+  if ( m_cursor == m_head && m_cursor_ind >= m_head_block_size )
+  {
+    m_cursor     = m_cursor ->m_next;
+    m_cursor_ind = 0;
+  }
+  else if ( m_cursor_ind == GCLL_BLOCK_SIZE )
+  {
+    m_cursor = m_cursor ->m_next;
+    m_cursor_ind = 0;
+  }
+  return(toReturn);
+}
+
+/*********************************************************************/
+
+bool LinkedBlockList::hasNext()
+{
+  if ( m_cursor != 0 ) return (true);
+  else return(false);
+}
+
+
+/*********************************************************************/
+
+LinkedBlockList::~LinkedBlockList()
+{
+  LLBlock *tmp;
+
+  while ( m_head != 0 )
+  {
+    tmp = m_head;
+    m_head = m_head->m_next;
+    delete tmp;
+  }
+};
+
+/*********************************************************************/
+

+ 63 - 0
mrf/mrfmin/LinkedBlockList.h

@@ -0,0 +1,63 @@
+/* Singly Linked List of Blocks */
+// This data structure should be used only for the GCoptimization class implementation
+// because it lucks some important general functions for general list, like remove_item()
+// The head block may be not full
+// For regular 2D grids, it's better to set GCLL_BLOCK_SIZE to 2
+// For other graphs, it should be set to the average expected number of neighbors
+// Data in linked list for the neighborhood system is allocated in blocks of size GCLL_BLOCK_SIZE
+
+#ifndef __LINKEDBLOCKLIST_H__
+#define __LINKEDBLOCKLIST_H__
+
+#define GCLL_BLOCK_SIZE 4
+// GCLL_BLOCKSIZE should "fit" into the type BlockType. That is
+// if GCLL_BLOCKSIZE is larger than 255 but smaller than largest short integer
+// then  BlockType should be set to short
+typedef char BlockType;
+
+//The type of data stored in the linked list
+typedef void * ListType;
+
+namespace OBJREC {
+
+class LinkedBlockList {
+
+  public:
+    void addFront(ListType item);
+    inline bool isEmpty() {
+      if (m_head == 0) return(true);
+      else return(false);
+    };
+    inline LinkedBlockList() {
+      m_head = 0;
+      m_head_block_size = GCLL_BLOCK_SIZE;
+    };
+    ~LinkedBlockList();
+
+    // Next three functins are for the linked list traversal
+    inline void setCursorFront() {
+      m_cursor = m_head;
+      m_cursor_ind = 0;
+    };
+    ListType next();
+    bool hasNext();
+
+  private:
+    typedef struct LLBlockStruct {
+      ListType m_item[GCLL_BLOCK_SIZE];
+      struct LLBlockStruct *m_next;
+    } LLBlock;
+
+    LLBlock *m_head;
+    // Remembers the number of elements in the head block, since it may not be full
+    BlockType m_head_block_size;
+    // For block traversal, points to current element in the current block
+    BlockType m_cursor_ind;
+    // For block traversal, points to current block in the linked list
+    LLBlock *m_cursor;
+};
+
+} //namespace
+
+#endif
+

+ 8 - 0
mrf/mrfmin/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
mrf/mrfmin/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 386 - 0
mrf/mrfmin/MaxProdBP.cpp

@@ -0,0 +1,386 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include "MaxProdBP.h"
+#include "regions-new.h"
+
+using namespace OBJREC;
+
+#define m_D(pix,l)  m_D[(pix)*m_nLabels+(l)]
+#define m_V(l1,l2)  m_V[(l1)*m_nLabels+(l2)]
+
+
+
+
+MaxProdBP::MaxProdBP(int width, int height, int nLabels, EnergyFunction *eng): MRF(width, height, nLabels, eng)
+{
+  m_needToFreeV = 0;
+  BPinitializeAlg();
+}
+MaxProdBP::MaxProdBP(int nPixels, int nLabels, EnergyFunction *eng): MRF(nPixels, nLabels, eng)
+{
+  m_needToFreeV = 0;
+  BPinitializeAlg();
+}
+
+MaxProdBP::~MaxProdBP()
+{
+  delete[] m_answer;
+  if (m_message_chunk) delete[] m_message_chunk;
+  if (!m_grid_graph) delete[] m_neighbors;
+  if ( m_needToFreeV ) delete[] m_V;
+}
+
+
+void MaxProdBP::initializeAlg()
+{
+}
+
+void MaxProdBP::BPinitializeAlg()
+{
+  m_answer = (Label *) new Label[m_nPixels];
+  if ( !m_answer ) {
+    printf("\nNot enough memory, exiting");
+    exit(0);
+  }
+
+  m_scratchMatrix = new FLOATTYPE[m_nLabels * m_nLabels];
+  // MEMORY LEAK? where does this ever get deleted??
+
+  nodeArray =     new OneNodeCluster[m_nPixels];
+  // MEMORY LEAK? where does this ever get deleted??
+
+  OneNodeCluster::numStates = m_nLabels;
+
+  if (!m_grid_graph)
+  {
+    assert(0);
+    // Only Grid Graphs are supported
+    m_neighbors = (LinkedBlockList *) new LinkedBlockList[m_nPixels];
+    if (!m_neighbors) {
+      printf("Not enough memory,exiting");
+      exit(0);
+    };
+  }
+  else
+  {
+//    const int clen = 4*m_nPixels * m_nLabels + 4*m_nPixels * m_nLabels * m_nLabels;
+    const int clen = 4 * m_nPixels * m_nLabels ;
+    //printf("clen:%d\n",clen/1024/1024);
+    m_message_chunk = (FloatType *) new FloatType[clen];
+    if ( !m_message_chunk ) {
+      printf("\nNot enough memory for messages, exiting");
+      exit(0);
+    }
+    for (int i = 0; i < clen; i++)
+      m_message_chunk[i] = 0;
+    initOneNodeMsgMem(nodeArray, m_message_chunk, m_nPixels, m_nLabels);
+  }
+}
+
+MRF::InputType MaxProdBP::getSmoothType()
+{
+  return m_smoothType;
+}
+
+EnergyFunction *MaxProdBP::getEnergyFunction()
+{
+  return m_e;
+}
+
+void MaxProdBP::setExpScale(int expScale)
+{
+  m_exp_scale = (float)expScale;
+}
+
+int MaxProdBP::getNLabels()
+{
+  return m_nLabels;
+}
+
+int MaxProdBP::getWidth()
+{
+  return m_width;
+}
+
+int MaxProdBP::getHeight()
+{
+  return m_height;
+}
+FLOATTYPE MaxProdBP::getExpV(int i)
+{
+  return m_ExpData[i];
+}
+
+FLOATTYPE *MaxProdBP::getExpV()
+{
+  return m_ExpData;
+}
+
+
+MRF::CostVal MaxProdBP::getHorizWeight(int r, int c)
+{
+  int x = c;
+  int y = r;
+  int pix    = x + y * m_width;
+  return m_varWeights ? m_horizWeights[pix] :  1;
+}
+
+MRF::CostVal MaxProdBP::getVertWeight(int r, int c)
+{
+  int x = c;
+  int y = r;
+  int pix    = x + y * m_width;
+  return  m_varWeights ? m_vertWeights[pix] :  1;
+}
+
+bool MaxProdBP::varWeights()
+{
+  return m_varWeights;
+}
+
+FLOATTYPE *MaxProdBP::getScratchMatrix()
+{
+  return m_scratchMatrix;
+}
+
+void MaxProdBP::clearAnswer()
+{
+  memset(m_answer, 0, m_nPixels*sizeof(Label));
+}
+
+
+void MaxProdBP::setNeighbors(int pixel1, int pixel2, CostVal weight)
+{
+  assert(0);
+  //Only Grid Graphs are supported
+  assert(!m_grid_graph);
+  assert(pixel1 < m_nPixels && pixel1 >= 0 && pixel2 < m_nPixels && pixel2 >= 0);
+
+
+  Neighbor *temp1 = (Neighbor *) new Neighbor;
+  Neighbor *temp2 = (Neighbor *) new Neighbor;
+
+  if ( !temp1 || ! temp2 ) {
+    printf("\nNot enough memory, exiting");
+    exit(0);
+  }
+
+  temp1->weight  = weight;
+  temp1->to_node = pixel2;
+
+  temp2->weight  = weight;
+  temp2->to_node = pixel1;
+
+  m_neighbors[pixel1].addFront(temp1);
+  m_neighbors[pixel2].addFront(temp2);
+}
+
+
+MRF::EnergyVal MaxProdBP::smoothnessEnergy()
+{
+  EnergyVal eng = (EnergyVal) 0;
+  EnergyVal weight;
+  int x, y, pix;
+  if ( m_smoothType != FUNCTION  )
+  {
+    for ( y = 0; y < m_height; y++ )
+      for ( x = 1; x < m_width; x++ )
+      {
+        pix    = x + y * m_width;
+        weight = m_varWeights ? m_horizWeights[pix-1] :  1;
+        eng = eng + m_V(m_answer[pix], m_answer[pix-1]) * weight;
+      }
+
+    for ( y = 1; y < m_height; y++ )
+      for ( x = 0; x < m_width; x++ )
+      {
+        pix = x + y * m_width;
+        weight = m_varWeights ? m_vertWeights[pix-m_width] :  1;
+        eng = eng + m_V(m_answer[pix], m_answer[pix-m_width]) * weight;
+      }
+  }
+  else
+  {
+    for ( y = 0; y < m_height; y++ )
+      for ( x = 1; x < m_width; x++ )
+      {
+        pix = x + y * m_width;
+        eng = eng + m_smoothFn(pix, pix - 1, m_answer[pix], m_answer[pix-1]);
+      }
+
+    for ( y = 1; y < m_height; y++ )
+      for ( x = 0; x < m_width; x++ )
+      {
+        pix = x + y * m_width;
+        eng = eng + m_smoothFn(pix, pix - m_width, m_answer[pix], m_answer[pix-m_width]);
+      }
+  }
+  return(eng);
+
+}
+
+
+
+MRF::EnergyVal MaxProdBP::dataEnergy()
+{
+  EnergyVal eng = (EnergyVal) 0;
+
+
+  if ( m_dataType == ARRAY)
+  {
+    for ( int i = 0; i < m_nPixels; i++ )
+      eng = eng + m_D(i, m_answer[i]);
+  }
+  else
+  {
+    for ( int i = 0; i < m_nPixels; i++ )
+      eng = eng + m_dataFn(i, m_answer[i]);
+  }
+  return(eng);
+
+}
+
+
+void MaxProdBP::setData(DataCostFn dcost)
+{
+  m_dataFn = dcost;
+  int i;
+  int j;
+  m_ExpData = new FloatType[m_nPixels * m_nLabels];
+  // MEMORY LEAK? where does this ever get deleted??
+  if (!m_ExpData)
+  {
+    exit(0);
+  }
+
+
+  m_exp_scale = 1;//FLOATTYPE(cmax)*4.0;
+  FloatType *cData = m_ExpData;
+  for ( i = 0; i < m_nPixels; i++)
+  {
+    nodeArray[i].localEv = cData;
+    for ( j = 0; j < m_nLabels; j++)
+    {
+      *cData = (float)m_dataFn(i, j);
+      cData++;
+    }
+  }
+}
+
+void MaxProdBP::setData(CostVal* data)
+{
+  int i;
+  int j;
+  m_D = data;
+  m_ExpData = new FloatType[m_nPixels * m_nLabels];
+  // MEMORY LEAK? where does this ever get deleted??
+  if (!m_ExpData)
+  {
+    exit(0);
+  }
+
+
+  m_exp_scale = 1;//FLOATTYPE(cmax)*4.0;
+  FloatType *cData = m_ExpData;
+  for ( i = 0; i < m_nPixels; i++)
+  {
+    nodeArray[i].localEv = cData;
+    for ( j = 0; j < m_nLabels; j++)
+    {
+      *cData = (float)m_D(i, j);
+      cData++;
+    }
+  }
+}
+
+
+void MaxProdBP::setSmoothness(SmoothCostGeneralFn cost)
+{
+  m_smoothFn = cost;
+}
+void MaxProdBP::setSmoothness(CostVal* V)
+{
+  m_type = FIXED_MATRIX;
+  m_V = V;
+}
+
+
+void MaxProdBP::setSmoothness(int smoothExp, CostVal smoothMax, CostVal lambda)
+{
+  int i, j;
+  CostVal cost;
+  m_type = (smoothExp == 1) ? L1 : L2; //borrowed from BP-S.cpp from vnk
+  m_lambda = lambda;
+  m_smoothMax = smoothMax;
+  m_smoothExp = smoothExp;
+  m_needToFreeV = 1;
+
+  m_V = (CostVal *) new CostVal[m_nLabels*m_nLabels*sizeof(CostVal)];
+  if (!m_V) {
+    fprintf(stderr, "Not enough memory!\n");
+    exit(1);
+  }
+
+
+  for (i = 0; i < m_nLabels; i++)
+    for (j = i; j < m_nLabels; j++)
+    {
+      cost = (MRF::CostVal)((smoothExp == 1) ? j - i : (j - i) * (j - i));
+      if (cost > smoothMax) cost = smoothMax;
+      m_V[i*m_nLabels + j] = m_V[j*m_nLabels + i] = cost * lambda;
+    }
+
+
+
+}
+
+
+void MaxProdBP::setCues(CostVal* hCue, CostVal* vCue)
+{
+  m_horizWeights = hCue;
+  m_vertWeights  = vCue;
+}
+
+
+void MaxProdBP::optimizeAlg(int nIterations)
+{
+  //int x, y, i, j, n;
+  //Label* l;
+  //CostVal* dataPtr;
+
+  if ( !m_grid_graph) {
+    printf("\nMaxProdBP is not implemented for nongrids yet!");
+    exit(1);
+  }
+
+  int numRows = getHeight();
+  int numCols = getWidth();
+  const FLOATTYPE alpha = 0.8f;
+  for (int niter = 0; niter < nIterations; niter++)
+  {
+    for (int r = 0; r < numRows; r++)
+    {
+      computeMessagesLeftRight(nodeArray, numCols, numRows, r, alpha, this);
+    }
+    for (int c = 0; c < numCols; c++)
+    {
+      computeMessagesUpDown(nodeArray, numCols, numRows, c, alpha, this);
+    }
+  }
+
+
+  Label *currAssign = m_answer;
+  for (int m = 0; m < numRows; m++)
+  {
+    for (int n = 0; n < numCols; n++)
+    {
+      int maxInd = nodeArray[m*numCols+n].getBeliefMaxInd();
+      currAssign[m * numCols +n] = maxInd;
+    }
+  }
+
+}
+

+ 109 - 0
mrf/mrfmin/MaxProdBP.h

@@ -0,0 +1,109 @@
+#ifndef __MAXPRODBP_H__
+#define __MAXPRODBP_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mrf.h"
+#include "LinkedBlockList.h"
+#include "regions-new.h"
+
+namespace OBJREC {
+
+#define FloatType float
+#define FLOATTYPE float
+class MaxProdBP;
+
+class MaxProdBP : public MRF {
+  public:
+    MaxProdBP(int width, int height, int nLabels, EnergyFunction *eng);
+    MaxProdBP(int nPixels, int nLabels, EnergyFunction *eng);
+    ~MaxProdBP();
+    void setNeighbors(int pix1, int pix2, CostVal weight);
+    Label getLabel(int pixel) {
+      return(m_answer[pixel]);
+    };
+    void setLabel(int pixel, Label label) {
+      m_answer[pixel] = label;
+    };
+    Label* getAnswerPtr() {
+      return(m_answer);
+    };
+    void clearAnswer();
+    void setParameters(int , void *) {
+      printf("No optional parameters to set");
+    }
+    EnergyVal smoothnessEnergy();
+    EnergyVal dataEnergy();
+    EnergyFunction *getEnergyFunction();
+    int getWidth();
+    int getHeight();
+    FLOATTYPE *getScratchMatrix();
+    int getNLabels();
+    bool varWeights();
+    void setExpScale(int expScale);
+    friend void getPsiMat(OneNodeCluster &cluster, FLOATTYPE *&destMatrix,
+                          int r, int c, MaxProdBP *mrf, int direction, FLOATTYPE &var_weight);
+
+    InputType getSmoothType();
+    FLOATTYPE getExpV(int i);
+    FLOATTYPE *getExpV();
+
+    CostVal getHorizWeight(int r, int c);
+    CostVal getVertWeight(int r, int c);
+
+
+    CostVal m_lambda;
+    CostVal m_smoothMax;
+    int m_smoothExp;
+
+    enum //Borrowed from BP-S.h by vnk
+    {
+      NONE,
+      L1,
+      L2,
+      FIXED_MATRIX,
+      GENERAL,
+      BINARY,
+    } m_type;
+
+  protected:
+    void setData(DataCostFn dcost);
+    void setData(CostVal* data);
+    void setSmoothness(SmoothCostGeneralFn cost);
+    void setSmoothness(CostVal* V);
+    void setSmoothness(int smoothExp, CostVal smoothMax, CostVal lambda);
+    void setCues(CostVal* hCue, CostVal* vCue);
+    void initializeAlg();
+    void BPinitializeAlg();
+    void optimizeAlg(int nIterations);
+
+  private:
+    Label *m_answer;
+    CostVal *m_V;
+    CostVal *m_D;
+    CostVal *m_horizWeights;
+    CostVal *m_vertWeights;
+    FLOATTYPE m_exp_scale;
+    DataCostFn m_dataFn;
+    SmoothCostGeneralFn m_smoothFn;
+    bool m_needToFreeV;
+    FLOATTYPE *m_scratchMatrix;
+    FLOATTYPE *m_ExpData;
+    FLOATTYPE *m_message_chunk;
+    OneNodeCluster *nodeArray;
+    typedef struct NeighborStruct {
+      int     to_node;
+      CostVal weight;
+    } Neighbor;
+
+    LinkedBlockList *m_neighbors;
+};
+
+}
+
+
+#endif /*  __ICM_H__ */
+
+

+ 33 - 0
mrf/mrfmin/README.txt

@@ -0,0 +1,33 @@
+========================================================================
+    CONSOLE APPLICATION : GCoptimization Project Overview
+========================================================================
+
+AppWizard has created this GCoptimization application for you.  
+
+This file contains a summary of what you will find in each of the files that
+make up your GCoptimization application.
+
+
+GCoptimization.vcproj
+    This is the main project file for VC++ projects generated using an Application Wizard. 
+    It contains information about the version of Visual C++ that generated the file, and 
+    information about the platforms, configurations, and project features selected with the
+    Application Wizard.
+
+GCoptimization.cpp
+    This is the main application source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+    These files are used to build a precompiled header (PCH) file
+    named GCoptimization.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////

+ 1116 - 0
mrf/mrfmin/TRW-S.cpp

@@ -0,0 +1,1116 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <new>
+#include "TRW-S.h"
+
+#define private public
+#include "typeTruncatedQuadratic2D.h"
+
+using namespace OBJREC;
+#undef private
+
+
+#define m_D(pix,l)  m_D[(pix)*m_nLabels+(l)]
+#define m_V(l1,l2)  m_V[(l1)*m_nLabels+(l2)]
+
+
+#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
+#define TRUNCATE_MIN(a,b) { if ((a) > (b)) (a) = (b); }
+#define TRUNCATE_MAX(a,b) { if ((a) < (b)) (a) = (b); }
+#define TRUNCATE TRUNCATE_MIN
+
+/////////////////////////////////////////////////////////////////////////////
+//                  Operations on vectors (arrays of size K)               //
+/////////////////////////////////////////////////////////////////////////////
+
+inline void CopyVector(TRWS::REAL* to, MRF::CostVal* from, int K)
+{
+  TRWS::REAL* to_finish = to + K;
+  do
+  {
+    *to ++ = *from ++;
+  } while (to < to_finish);
+}
+
+inline void AddVector(TRWS::REAL* to, TRWS::REAL* from, int K)
+{
+  TRWS::REAL* to_finish = to + K;
+  do
+  {
+    *to ++ += *from ++;
+  } while (to < to_finish);
+}
+
+inline TRWS::REAL SubtractMin(TRWS::REAL *D, int K)
+{
+  int k;
+  TRWS::REAL delta;
+
+  delta = D[0];
+  for (k = 1; k < K; k++) TRUNCATE(delta, D[k]);
+  for (k = 0; k < K; k++) D[k] -= delta;
+
+  return delta;
+}
+
+// Functions UpdateMessageTYPE (see the paper for details):
+//
+// - Set Di[ki] := gamma*Di_hat[ki] - M[ki]
+// - Set M[kj] := min_{ki} (Di[ki] + V[ki,kj])
+// - Normalize message:
+//        delta := min_{kj} M[kj]
+//        M[kj] := M[kj] - delta
+//        return delta
+//
+// If dir = 1, then the meaning of i and j is swapped.
+
+///////////////////////////////////////////
+//                  L1                   //
+///////////////////////////////////////////
+
+inline TRWS::REAL UpdateMessageL1(TRWS::REAL* M, TRWS::REAL* Di_hat, int K, TRWS::REAL gamma, MRF::CostVal lambda, MRF::CostVal smoothMax)
+{
+  int k;
+  TRWS::REAL delta;
+
+  delta = M[0] = gamma * Di_hat[0] - M[0];
+  for (k = 1; k < K; k++)
+  {
+    M[k] = gamma * Di_hat[k] - M[k];
+    TRUNCATE(delta, M[k]);
+    TRUNCATE(M[k], M[k-1] + lambda);
+  }
+
+  M[--k] -= delta;
+  TRUNCATE(M[k], lambda*smoothMax);
+  for (k--; k >= 0; k--)
+  {
+    M[k] -= delta;
+    TRUNCATE(M[k], M[k+1] + lambda);
+    TRUNCATE(M[k], lambda*smoothMax);
+  }
+
+  return delta;
+}
+
+////////////////////////////////////////
+//               L2                   //
+////////////////////////////////////////
+
+inline TRWS::REAL UpdateMessageL2(TRWS::REAL* M, TRWS::REAL* Di_hat, int K, TRWS::REAL gamma, MRF::CostVal lambda, MRF::CostVal smoothMax, void *buf)
+{
+  TRWS::REAL* Di = (TRWS::REAL*) buf;
+  int* parabolas = (int*) ((char*)buf + K * sizeof(TRWS::REAL));
+  int* intersections = parabolas + K;
+  TypeTruncatedQuadratic2D::Edge* tmp = NULL;
+
+  int k;
+  TRWS::REAL delta;
+
+  assert(lambda >= 0);
+
+  Di[0] = gamma * Di_hat[0] - M[0];
+  delta = Di[0];
+  for (k = 1; k < K; k++)
+  {
+    Di[k] = gamma * Di_hat[k] - M[k];
+    TRUNCATE(delta, Di[k]);
+  }
+
+  if (lambda == 0)
+  {
+    for (k = 0; k < K; k++) M[k] = 0;
+    return delta;
+  }
+
+  tmp->DistanceTransformL2(K, 1, lambda, Di, M, parabolas, intersections);
+
+  for (k = 0; k < K; k++)
+  {
+    M[k] -= delta;
+    TRUNCATE(M[k], lambda*smoothMax);
+  }
+
+  return delta;
+}
+
+
+//////////////////////////////////////////////////
+//                FIXED_MATRIX                  //
+//////////////////////////////////////////////////
+
+inline TRWS::REAL UpdateMessageFIXED_MATRIX(TRWS::REAL* M, TRWS::REAL* Di_hat, int K, TRWS::REAL gamma, MRF::CostVal lambda, MRF::CostVal* V, void* buf)
+{
+  TRWS::REAL* Di = (TRWS::REAL*) buf;
+  int ki, kj;
+  TRWS::REAL delta;
+
+  if (lambda == 0)
+  {
+    delta = gamma * Di_hat[0] - M[0];
+    M[0] = 0;
+    for (ki = 1; ki < K; ki++)
+    {
+      TRUNCATE(delta, gamma*Di_hat[ki] - M[ki]);
+      M[ki] = 0;
+    }
+    return delta;
+  }
+
+  for (ki = 0; ki < K; ki++)
+  {
+    Di[ki] = (gamma * Di_hat[ki] - M[ki]) * (1 / (TRWS::REAL)lambda);
+  }
+
+  if (lambda > 0)
+  {
+    for (kj = 0; kj < K; kj++)
+    {
+      M[kj] = Di[0] + V[0];
+      V ++;
+      for (ki = 1; ki < K; ki++)
+      {
+        TRUNCATE(M[kj], Di[ki] + V[0]);
+        V ++;
+      }
+      M[kj] *= lambda;
+    }
+  }
+  else
+  {
+    for (kj = 0; kj < K; kj++)
+    {
+      M[kj] = Di[0] + V[0];
+      V ++;
+      for (ki = 1; ki < K; ki++)
+      {
+        TRUNCATE_MAX(M[kj], Di[ki] + V[0]);
+        V ++;
+      }
+      M[kj] *= lambda;
+    }
+  }
+
+  delta = M[0];
+  for (kj = 1; kj < K; kj++) TRUNCATE(delta, M[kj]);
+  for (kj = 0; kj < K; kj++) M[kj] -= delta;
+
+  return delta;
+}
+
+/////////////////////////////////////////////
+//                GENERAL                  //
+/////////////////////////////////////////////
+
+inline TRWS::REAL UpdateMessageGENERAL(TRWS::REAL* M, TRWS::REAL* Di_hat, int K, TRWS::REAL gamma, int dir, MRF::CostVal* V, void* buf)
+{
+  TRWS::REAL* Di = (TRWS::REAL*) buf;
+  int ki, kj;
+  TRWS::REAL delta;
+
+  for (ki = 0; ki < K; ki++)
+  {
+    Di[ki] = (gamma * Di_hat[ki] - M[ki]);
+  }
+
+  if (dir == 0)
+  {
+    for (kj = 0; kj < K; kj++)
+    {
+      M[kj] = Di[0] + V[0];
+      V ++;
+      for (ki = 1; ki < K; ki++)
+      {
+        TRUNCATE(M[kj], Di[ki] + V[0]);
+        V ++;
+      }
+    }
+  }
+  else
+  {
+    for (kj = 0; kj < K; kj++)
+    {
+      M[kj] = Di[0] + V[0];
+      V += K;
+      for (ki = 1; ki < K; ki++)
+      {
+        TRUNCATE(M[kj], Di[ki] + V[0]);
+        V += K;
+      }
+      V -= K * K - 1;
+    }
+  }
+
+  delta = M[0];
+  for (kj = 1; kj < K; kj++) TRUNCATE(delta, M[kj]);
+  for (kj = 0; kj < K; kj++) M[kj] -= delta;
+
+  return delta;
+}
+
+inline TRWS::REAL UpdateMessageGENERAL(TRWS::REAL* M, TRWS::REAL* Di_hat, int K, TRWS::REAL gamma, TRWS::SmoothCostGeneralFn fn, int i, int j, void* buf)
+{
+  TRWS::REAL* Di = (TRWS::REAL*) buf;
+  int ki, kj;
+  TRWS::REAL delta;
+
+  for (ki = 0; ki < K; ki++)
+  {
+    Di[ki] = (gamma * Di_hat[ki] - M[ki]);
+  }
+
+  for (kj = 0; kj < K; kj++)
+  {
+    M[kj] = Di[0] + fn(i, j, 0, kj);
+    for (ki = 1; ki < K; ki++)
+    {
+      delta = Di[ki] + fn(i, j, ki, kj);
+      TRUNCATE(M[kj], delta);
+    }
+  }
+
+  delta = M[0];
+  for (kj = 1; kj < K; kj++) TRUNCATE(delta, M[kj]);
+  for (kj = 0; kj < K; kj++) M[kj] -= delta;
+
+  return delta;
+}
+
+
+
+
+
+
+TRWS::TRWS(int width, int height, int nLabels, EnergyFunction *eng): MRF(width, height, nLabels, eng)
+{
+  Allocate();
+}
+TRWS::TRWS(int nPixels, int nLabels, EnergyFunction *eng): MRF(nPixels, nLabels, eng)
+{
+  Allocate();
+}
+
+TRWS::~TRWS()
+{
+  delete[] m_answer;
+  if ( m_needToFreeD ) delete [] m_D;
+  if ( m_needToFreeV ) delete [] m_V;
+  if ( m_messages ) delete [] m_messages;
+  if ( m_DBinary ) delete [] m_DBinary;
+  if ( m_horzWeightsBinary ) delete [] m_horzWeightsBinary;
+  if ( m_vertWeightsBinary ) delete [] m_vertWeightsBinary;
+}
+
+
+void TRWS::Allocate()
+{
+  m_type = NONE;
+  m_needToFreeV = false;
+  m_needToFreeD = false;
+
+  m_D = NULL;
+  m_V = NULL;
+  m_horzWeights = NULL;
+  m_vertWeights = NULL;
+  m_horzWeightsBinary = NULL;
+  m_vertWeightsBinary = NULL;
+
+  m_DBinary = NULL;
+  m_messages = NULL;
+  m_messageArraySizeInBytes = 0;
+
+  m_answer = new Label[m_nPixels];
+}
+
+void TRWS::clearAnswer()
+{
+  memset(m_answer, 0, m_nPixels*sizeof(Label));
+  if (m_messages)
+  {
+    memset(m_messages, 0, m_messageArraySizeInBytes);
+  }
+}
+
+
+MRF::EnergyVal TRWS::smoothnessEnergy()
+{
+  EnergyVal eng = (EnergyVal) 0;
+  EnergyVal weight;
+  int x, y, pix;
+
+  if ( m_grid_graph )
+  {
+    if ( m_smoothType != FUNCTION  )
+    {
+      for ( y = 0; y < m_height; y++ )
+        for ( x = 1; x < m_width; x++ )
+        {
+          pix    = x + y * m_width;
+          weight = m_varWeights ? m_horzWeights[pix-1] :  1;
+          eng = eng + m_V(m_answer[pix], m_answer[pix-1]) * weight;
+        }
+
+      for ( y = 1; y < m_height; y++ )
+        for ( x = 0; x < m_width; x++ )
+        {
+          pix = x + y * m_width;
+          weight = m_varWeights ? m_vertWeights[pix-m_width] :  1;
+          eng = eng + m_V(m_answer[pix], m_answer[pix-m_width]) * weight;
+        }
+    }
+    else
+    {
+      for ( y = 0; y < m_height; y++ )
+        for ( x = 1; x < m_width; x++ )
+        {
+          pix = x + y * m_width;
+          eng = eng + m_smoothFn(pix, pix - 1, m_answer[pix], m_answer[pix-1]);
+        }
+
+      for ( y = 1; y < m_height; y++ )
+        for ( x = 0; x < m_width; x++ )
+        {
+          pix = x + y * m_width;
+          eng = eng + m_smoothFn(pix, pix - m_width, m_answer[pix], m_answer[pix-m_width]);
+        }
+    }
+  }
+  else
+  {
+    // not implemented
+  }
+
+  return(eng);
+}
+
+
+
+MRF::EnergyVal TRWS::dataEnergy()
+{
+  EnergyVal eng = (EnergyVal) 0;
+
+
+  if ( m_dataType == ARRAY)
+  {
+    for ( int i = 0; i < m_nPixels; i++ )
+      eng = eng + m_D(i, m_answer[i]);
+  }
+  else
+  {
+    for ( int i = 0; i < m_nPixels; i++ )
+      eng = eng + m_dataFn(i, m_answer[i]);
+  }
+  return(eng);
+
+}
+
+
+void TRWS::setData(DataCostFn dcost)
+{
+  int i, k;
+
+  m_dataFn = dcost;
+  CostVal* ptr;
+  m_D = new CostVal[m_nPixels*m_nLabels];
+
+  for (ptr = m_D, i = 0; i < m_nPixels; i++)
+    for (k = 0; k < m_nLabels; k++, ptr++)
+    {
+      *ptr = m_dataFn(i, k);
+    }
+  m_needToFreeD = true;
+}
+
+void TRWS::setData(CostVal* data)
+{
+  m_D = data;
+  m_needToFreeD = false;
+}
+
+
+void TRWS::setSmoothness(SmoothCostGeneralFn cost)
+{
+  assert(m_horzWeights == NULL && m_vertWeights == NULL && m_V == NULL);
+
+  int x, y, i, ki, kj;
+  CostVal* ptr;
+
+  m_smoothFn = cost;
+  m_type = GENERAL;
+
+  if (!m_allocateArrayForSmoothnessCostFn) return;
+
+  // try to cache all the function values in an array for efficiency
+  m_V = new(std::nothrow) CostVal[2*m_nPixels*m_nLabels*m_nLabels];
+  if (!m_V) return; // if not enough space, just call the function directly
+
+  m_needToFreeV = true;
+
+  for (ptr = m_V, i = 0, y = 0; y < m_height; y++)
+    for (x = 0; x < m_width; x++, i++)
+    {
+      if (x < m_width - 1)
+      {
+        for (kj = 0; kj < m_nLabels; kj++)
+          for (ki = 0; ki < m_nLabels; ki++)
+          {
+            *ptr++ = cost(i, i + 1, ki, kj);
+          }
+      }
+      else ptr += m_nLabels * m_nLabels;
+
+      if (y < m_height - 1)
+      {
+        for (kj = 0; kj < m_nLabels; kj++)
+          for (ki = 0; ki < m_nLabels; ki++)
+          {
+            *ptr++ = cost(i, i + m_width, ki, kj);
+          }
+      }
+      else ptr += m_nLabels * m_nLabels;
+    }
+}
+void TRWS::setSmoothness(CostVal* V)
+{
+  m_type = FIXED_MATRIX;
+  m_V = V;
+}
+
+
+void TRWS::setSmoothness(int smoothExp, CostVal smoothMax, CostVal lambda)
+{
+  assert(smoothExp == 1 || smoothExp == 2);
+  assert(lambda >= 0);
+
+  m_type = (smoothExp == 1) ? L1 : L2;
+
+  int ki, kj;
+  CostVal cost;
+
+  m_needToFreeV = true;
+
+  m_V = new CostVal[m_nLabels*m_nLabels];
+
+  for (ki = 0; ki < m_nLabels; ki++)
+    for (kj = ki; kj < m_nLabels; kj++)
+    {
+      cost = (CostVal) ((smoothExp == 1) ? kj - ki : (kj - ki) * (kj - ki));
+      if (cost > smoothMax) cost = smoothMax;
+      m_V[ki*m_nLabels + kj] = m_V[kj*m_nLabels + ki] = cost * lambda;
+    }
+
+  m_smoothMax = smoothMax;
+  m_lambda = lambda;
+}
+
+
+void TRWS::setCues(CostVal* hCue, CostVal* vCue)
+{
+  m_horzWeights = hCue;
+  m_vertWeights  = vCue;
+}
+
+
+void TRWS::initializeAlg()
+{
+  assert(m_type != NONE);
+
+  int i;
+
+  // determine type
+  if (m_type == L1 && m_nLabels == 2)
+  {
+    m_type = BINARY;
+  }
+
+  // allocate messages
+  int messageNum = (m_type == BINARY) ? 4 * m_nPixels : 4 * m_nPixels * m_nLabels;
+  m_messageArraySizeInBytes = messageNum * sizeof(REAL);
+  m_messages = new REAL[messageNum];
+  memset(m_messages, 0, messageNum*sizeof(REAL));
+
+  if (m_type == BINARY)
+  {
+    assert(m_DBinary == NULL && m_horzWeightsBinary == NULL && m_horzWeightsBinary == NULL);
+    m_DBinary = new CostVal[m_nPixels];
+    m_horzWeightsBinary = new CostVal[m_nPixels];
+    m_vertWeightsBinary = new CostVal[m_nPixels];
+
+    if ( m_dataType == ARRAY)
+    {
+      for (i = 0; i < m_nPixels; i++)
+      {
+        m_DBinary[i] = m_D[2*i+1] - m_D[2*i];
+      }
+    }
+    else
+    {
+      for (i = 0; i < m_nPixels; i++)
+      {
+        m_DBinary[i] = m_dataFn(i, 1) - m_dataFn(i, 0);
+      }
+    }
+
+    assert(m_V[0] == 0 && m_V[1] == m_V[2] && m_V[3] == 0);
+    for (i = 0; i < m_nPixels; i++)
+    {
+      m_horzWeightsBinary[i] = (m_varWeights) ? m_V[1] * m_horzWeights[i] : m_V[1];
+      m_vertWeightsBinary[i] = (m_varWeights) ? m_V[1] * m_vertWeights[i] : m_V[1];
+    }
+  }
+}
+
+void TRWS::optimizeAlg(int nIterations)
+{
+  assert(m_type != NONE);
+
+  if (m_grid_graph)
+  {
+    switch (m_type)
+    {
+      case L1:
+        optimize_GRID_L1(nIterations);
+        break;
+      case L2:
+        optimize_GRID_L2(nIterations);
+        break;
+      case FIXED_MATRIX:
+        optimize_GRID_FIXED_MATRIX(nIterations);
+        break;
+      case GENERAL:
+        optimize_GRID_GENERAL(nIterations);
+        break;
+      case BINARY:
+        optimize_GRID_BINARY(nIterations);
+        break;
+      default:
+        assert(0);
+        exit(1);
+    }
+  }
+  else {
+    printf("\nNot implemented for general graphs yet, exiting!");
+    exit(1);
+  }
+
+  // printf("lower bound = %f\n", m_lowerBound);
+
+  ////////////////////////////////////////////////
+  //          computing solution                //
+  ////////////////////////////////////////////////
+
+  if (m_type != BINARY)
+  {
+    int x, y, n, K = m_nLabels;
+    CostVal* D_ptr;
+    REAL* M_ptr;
+    REAL* Di;
+    REAL delta;
+    int ki, kj;
+
+    Di = new REAL[K];
+
+    n = 0;
+    D_ptr = m_D;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, D_ptr += K, M_ptr += 2 * K, n++)
+      {
+        CopyVector(Di, D_ptr, K);
+
+        if (m_type == GENERAL)
+        {
+          if (m_V)
+          {
+            CostVal* ptr = m_V + 2 * (x + y * m_width - 1) * K * K;
+            if (x > 0)
+            {
+              kj = m_answer[n-1];
+              for (ki = 0; ki < K; ki++)
+              {
+                Di[ki] += ptr[kj + ki*K];
+              }
+            }
+            ptr -= (2 * m_width - 3) * K * K;
+            if (y > 0)
+            {
+              kj = m_answer[n-m_width];
+              for (ki = 0; ki < K; ki++)
+              {
+                Di[ki] += ptr[kj + ki*K];
+              }
+            }
+          }
+          else
+          {
+            if (x > 0)
+            {
+              kj = m_answer[n-1];
+              for (ki = 0; ki < K; ki++)
+              {
+                Di[ki] += m_smoothFn(n, n - 1, ki, kj);
+              }
+            }
+            if (y > 0)
+            {
+              kj = m_answer[n-m_width];
+              for (ki = 0; ki < K; ki++)
+              {
+                Di[ki] += m_smoothFn(n, n - m_width, ki, kj);
+              }
+            }
+          }
+        }
+        else // m_type == L1, L2 or FIXED_MATRIX
+        {
+          if (x > 0)
+          {
+            kj = m_answer[n-1];
+            CostVal lambda = (m_varWeights) ? m_horzWeights[n-1] : 1;
+            for (ki = 0; ki < K; ki++)
+            {
+              Di[ki] += lambda * m_V[kj*K + ki];
+            }
+          }
+          if (y > 0)
+          {
+            kj = m_answer[n-m_width];
+            CostVal lambda = (m_varWeights) ? m_vertWeights[n-m_width] : 1;
+            for (ki = 0; ki < K; ki++)
+            {
+              Di[ki] += lambda * m_V[kj*K + ki];
+            }
+          }
+        }
+
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        // compute min
+        delta = Di[0];
+        m_answer[n] = 0;
+        for (ki = 1; ki < K; ki++)
+        {
+          if (delta > Di[ki])
+          {
+            delta = Di[ki];
+            m_answer[n] = ki;
+          }
+        }
+      }
+
+    delete [] Di;
+  }
+  else // m_type == BINARY
+  {
+    int x, y, n;
+    REAL* M_ptr;
+    REAL Di;
+
+    n = 0;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, M_ptr += 2, n++)
+      {
+        Di = m_DBinary[n];
+        if (x > 0) Di += (m_answer[n-1] == 0)       ? m_horzWeightsBinary[n-1]       : -m_horzWeightsBinary[n-1];
+        if (y > 0) Di += (m_answer[n-m_width] == 0) ? m_vertWeightsBinary[n-m_width] : -m_vertWeightsBinary[n-m_width];
+
+        if (x < m_width - 1)  Di += M_ptr[0]; // message (x+1,y)->(x,y)
+        if (y < m_height - 1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+        // compute min
+        m_answer[n] = (Di >= 0) ? 0 : 1;
+      }
+  }
+}
+
+void TRWS::optimize_GRID_L1(int nIterations)
+{
+  int x, y, n, K = m_nLabels;
+  CostVal* D_ptr;
+  REAL* M_ptr;
+  REAL* Di;
+
+  Di = new REAL[K];
+
+  for ( ; nIterations > 0; nIterations --)
+  {
+    // forward pass
+    n = 0;
+    D_ptr = m_D;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, D_ptr += K, M_ptr += 2 * K, n++)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        if (x < m_width - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_horzWeights[n] : m_lambda;
+          UpdateMessageL1(M_ptr, Di, K, 0.5, lambda, m_smoothMax);
+        }
+        if (y < m_height - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_vertWeights[n] : m_lambda;
+          UpdateMessageL1(M_ptr + K, Di, K, 0.5, lambda, m_smoothMax);
+        }
+      }
+
+    // backward pass
+    m_lowerBound = 0;
+
+    n --;
+    D_ptr -= K;
+    M_ptr -= 2 * K;
+
+    for (y = m_height - 1; y >= 0; y--)
+      for (x = m_width - 1; x >= 0; x--, D_ptr -= K, M_ptr -= 2 * K, n--)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        m_lowerBound += SubtractMin(Di, K);
+
+        if (x > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_horzWeights[n-1] : m_lambda;
+          m_lowerBound += UpdateMessageL1(M_ptr - 2 * K, Di, K, 0.5, lambda, m_smoothMax);
+        }
+        if (y > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_vertWeights[n-m_width] : m_lambda;
+          m_lowerBound += UpdateMessageL1(M_ptr - (2 * m_width - 1) * K, Di, K, 0.5, lambda, m_smoothMax);
+        }
+      }
+  }
+
+  delete [] Di;
+}
+
+void TRWS::optimize_GRID_L2(int nIterations)
+{
+  int x, y, n, K = m_nLabels;
+  CostVal* D_ptr;
+  REAL* M_ptr;
+  REAL* Di;
+  void* buf;
+
+  Di = new REAL[K];
+  buf = new char[(2*K+1)*sizeof(int) + K*sizeof(REAL)];
+
+  for ( ; nIterations > 0; nIterations --)
+  {
+    // forward pass
+    n = 0;
+    D_ptr = m_D;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, D_ptr += K, M_ptr += 2 * K, n++)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        if (x < m_width - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_horzWeights[n] : m_lambda;
+          UpdateMessageL2(M_ptr, Di, K, 0.5, lambda, m_smoothMax, buf);
+        }
+        if (y < m_height - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_vertWeights[n] : m_lambda;
+          UpdateMessageL2(M_ptr + K, Di, K, 0.5, lambda, m_smoothMax, buf);
+        }
+      }
+
+    // backward pass
+    m_lowerBound = 0;
+
+    n --;
+    D_ptr -= K;
+    M_ptr -= 2 * K;
+
+    for (y = m_height - 1; y >= 0; y--)
+      for (x = m_width - 1; x >= 0; x--, D_ptr -= K, M_ptr -= 2 * K, n--)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        m_lowerBound += SubtractMin(Di, K);
+
+        if (x > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_horzWeights[n-1] : m_lambda;
+          m_lowerBound += UpdateMessageL2(M_ptr - 2 * K, Di, K, 0.5, lambda, m_smoothMax, buf);
+        }
+        if (y > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_lambda * m_vertWeights[n-m_width] : m_lambda;
+          m_lowerBound += UpdateMessageL2(M_ptr - (2 * m_width - 1) * K, Di, K, 0.5, lambda, m_smoothMax, buf);
+        }
+      }
+  }
+
+  delete [] Di;
+  delete [] (char *)buf;
+}
+
+
+void TRWS::optimize_GRID_BINARY(int nIterations)
+{
+  int x, y, n;
+  REAL* M_ptr;
+  REAL Di;
+
+  for ( ; nIterations > 0; nIterations --)
+  {
+    // forward pass
+    n = 0;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, M_ptr += 2, n++)
+      {
+        Di = m_DBinary[n];
+        if (x > 0) Di += M_ptr[-2]; // message (x-1,y)->(x,y)
+        if (y > 0) Di += M_ptr[-2*m_width+1]; // message (x,y-1)->(x,y)
+        if (x < m_width - 1) Di += M_ptr[0]; // message (x+1,y)->(x,y)
+        if (y < m_height - 1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+        REAL DiScaled = Di * 0.5;
+        if (x < m_width - 1)
+        {
+          Di = DiScaled - M_ptr[0];
+          CostVal lambda = m_horzWeightsBinary[n];
+          if (lambda < 0) {
+            Di = -Di;
+            lambda = -lambda;
+          }
+          if (Di > lambda) M_ptr[0] = lambda;
+          else             M_ptr[0] = (Di < -lambda) ? -lambda : Di;
+        }
+        if (y < m_height - 1)
+        {
+          Di = DiScaled - M_ptr[1];
+          CostVal lambda = m_vertWeightsBinary[n];
+          if (lambda < 0) {
+            Di = -Di;
+            lambda = -lambda;
+          }
+          if (Di > lambda) M_ptr[1] = lambda;
+          else             M_ptr[1] = (Di < -lambda) ? -lambda : Di;
+        }
+      }
+
+    // backward pass
+    n --;
+    M_ptr -= 2;
+
+    for (y = m_height - 1; y >= 0; y--)
+      for (x = m_width - 1; x >= 0; x--, M_ptr -= 2, n--)
+      {
+        Di = m_DBinary[n];
+        if (x > 0) Di += M_ptr[-2]; // message (x-1,y)->(x,y)
+        if (y > 0) Di += M_ptr[-2*m_width+1]; // message (x,y-1)->(x,y)
+        if (x < m_width - 1) Di += M_ptr[0]; // message (x+1,y)->(x,y)
+        if (y < m_height - 1) Di += M_ptr[1]; // message (x,y+1)->(x,y)
+
+        REAL DiScaled = Di * 0.5;
+        if (x > 0)
+        {
+          Di = DiScaled - M_ptr[-2];
+          CostVal lambda = m_horzWeightsBinary[n-1];
+          if (lambda < 0) {
+            Di = -Di;
+            lambda = -lambda;
+          }
+          if (Di > lambda) M_ptr[-2] = lambda;
+          else             M_ptr[-2] = (Di < -lambda) ? -lambda : Di;
+        }
+        if (y > 0)
+        {
+          Di = DiScaled - M_ptr[-2*m_width+1];
+          CostVal lambda = m_vertWeightsBinary[n-m_width];
+          if (lambda < 0) {
+            Di = -Di;
+            lambda = -lambda;
+          }
+          if (Di > lambda) M_ptr[-2*m_width+1] = lambda;
+          else             M_ptr[-2*m_width+1] = (Di < -lambda) ? -lambda : Di;
+        }
+      }
+  }
+
+  m_lowerBound = 0;
+}
+
+void TRWS::optimize_GRID_FIXED_MATRIX(int nIterations)
+{
+  int x, y, n, K = m_nLabels;
+  CostVal* D_ptr;
+  REAL* M_ptr;
+  REAL* Di;
+  void* buf;
+
+  Di = new REAL[K];
+  buf = new REAL[K];
+
+  for ( ; nIterations > 0; nIterations --)
+  {
+    // forward pass
+    n = 0;
+    D_ptr = m_D;
+    M_ptr = m_messages;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, D_ptr += K, M_ptr += 2 * K, n++)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        if (x < m_width - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_horzWeights[n] : 1;
+          UpdateMessageFIXED_MATRIX(M_ptr, Di, K, 0.5, lambda, m_V, buf);
+        }
+        if (y < m_height - 1)
+        {
+          CostVal lambda = (m_varWeights) ? m_vertWeights[n] : 1;
+          UpdateMessageFIXED_MATRIX(M_ptr + K, Di, K, 0.5, lambda, m_V, buf);
+        }
+      }
+
+    // backward pass
+    m_lowerBound = 0;
+
+    n --;
+    D_ptr -= K;
+    M_ptr -= 2 * K;
+
+    for (y = m_height - 1; y >= 0; y--)
+      for (x = m_width - 1; x >= 0; x--, D_ptr -= K, M_ptr -= 2 * K, n--)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        m_lowerBound += SubtractMin(Di, K);
+
+        if (x > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_horzWeights[n-1] : 1;
+          m_lowerBound += UpdateMessageFIXED_MATRIX(M_ptr - 2 * K, Di, K, 0.5, lambda, m_V, buf);
+        }
+        if (y > 0)
+        {
+          CostVal lambda = (m_varWeights) ? m_vertWeights[n-m_width] : 1;
+          m_lowerBound += UpdateMessageFIXED_MATRIX(M_ptr - (2 * m_width - 1) * K, Di, K, 0.5, lambda, m_V, buf);
+        }
+      }
+  }
+
+  delete [] Di;
+  delete [] (REAL *)buf;
+}
+
+void TRWS::optimize_GRID_GENERAL(int nIterations)
+{
+  int x, y, n, K = m_nLabels;
+  CostVal* D_ptr;
+  REAL* M_ptr;
+  REAL* Di;
+  void* buf;
+
+  Di = new REAL[K];
+  buf = new REAL[K];
+
+  for ( ; nIterations > 0; nIterations --)
+  {
+    // forward pass
+    n = 0;
+    D_ptr = m_D;
+    M_ptr = m_messages;
+    CostVal* V_ptr = m_V;
+
+    for (y = 0; y < m_height; y++)
+      for (x = 0; x < m_width; x++, D_ptr += K, M_ptr += 2 * K, V_ptr += 2 * K * K, n++)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        if (x < m_width - 1)
+        {
+          if (m_V) UpdateMessageGENERAL(M_ptr, Di, K, 0.5, /* forward dir*/ 0, V_ptr, buf);
+          else     UpdateMessageGENERAL(M_ptr, Di, K, 0.5,   m_smoothFn, n, n + 1,      buf);
+        }
+        if (y < m_height - 1)
+        {
+          if (m_V) UpdateMessageGENERAL(M_ptr + K, Di, K, 0.5, /* forward dir*/ 0, V_ptr + K*K, buf);
+          else     UpdateMessageGENERAL(M_ptr + K, Di, K, 0.5,   m_smoothFn, n, n + m_width,    buf);
+        }
+      }
+
+    // backward pass
+    m_lowerBound = 0;
+
+    n --;
+    D_ptr -= K;
+    M_ptr -= 2 * K;
+    V_ptr -= 2 * K * K;
+
+    for (y = m_height - 1; y >= 0; y--)
+      for (x = m_width - 1; x >= 0; x--, D_ptr -= K, M_ptr -= 2 * K, V_ptr -= 2 * K * K, n--)
+      {
+        CopyVector(Di, D_ptr, K);
+        if (x > 0) AddVector(Di, M_ptr - 2*K, K); // message (x-1,y)->(x,y)
+        if (y > 0) AddVector(Di, M_ptr - (2*m_width - 1)*K, K); // message (x,y-1)->(x,y)
+        if (x < m_width - 1) AddVector(Di, M_ptr, K); // message (x+1,y)->(x,y)
+        if (y < m_height - 1) AddVector(Di, M_ptr + K, K); // message (x,y+1)->(x,y)
+
+        // normalize Di, update lower bound
+        m_lowerBound += SubtractMin(Di, K);
+
+        if (x > 0)
+        {
+          if (m_V) m_lowerBound += UpdateMessageGENERAL(M_ptr - 2 * K, Di, K, 0.5, /* backward dir */ 1, V_ptr - 2 * K * K, buf);
+          else     m_lowerBound += UpdateMessageGENERAL(M_ptr - 2 * K, Di, K, 0.5,   m_smoothFn, n, n - 1,              buf);
+        }
+        if (y > 0)
+        {
+          if (m_V) m_lowerBound += UpdateMessageGENERAL(M_ptr - (2 * m_width - 1) * K, Di, K, 0.5, /* backward dir */ 1, V_ptr - (2 * m_width - 1) * K * K, buf);
+          else     m_lowerBound += UpdateMessageGENERAL(M_ptr - (2 * m_width - 1) * K, Di, K, 0.5,   m_smoothFn, n, n - m_width,                    buf);
+        }
+      }
+  }
+
+  delete [] Di;
+  delete [] (REAL *)buf;
+}

+ 107 - 0
mrf/mrfmin/TRW-S.h

@@ -0,0 +1,107 @@
+#ifndef __TRWS_H__
+#define __TRWS_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mrf.h"
+
+#undef REAL
+
+namespace OBJREC {
+
+class TRWS : public MRF {
+  public:
+    typedef double REAL;
+
+    TRWS(int width, int height, int nLabels, EnergyFunction *eng);
+    TRWS(int nPixels, int nLabels, EnergyFunction *eng);
+    ~TRWS();
+    void setNeighbors(int /*pix1*/, int /*pix2*/, CostVal /*weight*/) {
+      printf("Not implemented");
+      exit(1);
+    }
+    Label getLabel(int pixel) {
+      return(m_answer[pixel]);
+    };
+    void setLabel(int pixel, Label label) {
+      m_answer[pixel] = label;
+    };
+    Label* getAnswerPtr() {
+      return(m_answer);
+    };
+    void clearAnswer();
+    void setParameters(int /*numParam*/, void * /*param*/) {
+      printf("No optional parameters to set");
+      exit(1);
+    }
+    EnergyVal smoothnessEnergy();
+    EnergyVal dataEnergy();
+    double lowerBound() {
+      return (double)m_lowerBound;
+    }
+
+    // For general smoothness functions, this code tries to cache all function values in an array
+    // for efficiency.  To prevent this, call the following function before calling initialize():
+    void dontCacheSmoothnessCosts() {
+      m_allocateArrayForSmoothnessCostFn = false;
+    }
+
+  protected:
+    void setData(DataCostFn dcost);
+    void setData(CostVal* data);
+    void setSmoothness(SmoothCostGeneralFn cost);
+    void setSmoothness(CostVal* V);
+    void setSmoothness(int smoothExp, CostVal smoothMax, CostVal lambda);
+    void setCues(CostVal* hCue, CostVal* vCue);
+    void Allocate();
+    void initializeAlg();
+    void optimizeAlg(int nIterations);
+
+  private:
+
+    enum
+    {
+      NONE,
+      L1,
+      L2,
+      FIXED_MATRIX,
+      GENERAL,
+      BINARY,
+    } m_type;
+
+    CostVal m_smoothMax; // used only if
+    CostVal m_lambda;    // m_type == L1 or m_type == L2
+
+    Label *m_answer;
+    CostVal *m_V; // points to array of size nLabels^2 (if type==FIXED_MATRIX) or of size nEdges*nLabels^2 (if type==GENERAL)
+    CostVal *m_D;
+    CostVal *m_DBinary; // valid if type == BINARY
+    CostVal *m_horzWeights;
+    CostVal *m_vertWeights;
+    CostVal *m_horzWeightsBinary;
+    CostVal *m_vertWeightsBinary;
+    DataCostFn m_dataFn;
+    SmoothCostGeneralFn m_smoothFn;
+    bool m_needToFreeV;
+    bool m_needToFreeD;
+
+    REAL* m_messages; // size of one message: N = 1 if m_type == BINARY, N = K otherwise
+    // message between edges (x,y)-(x+1,y): m_messages+(2*x+2*y*m_width)*N
+    // message between edges (x,y)-(x,y+1): m_messages+(2*x+2*y*m_width+1)*N
+
+    int   m_messageArraySizeInBytes;
+
+    REAL m_lowerBound;
+
+    void optimize_GRID_L1(int nIterations);
+    void optimize_GRID_L2(int nIterations);
+    void optimize_GRID_FIXED_MATRIX(int nIterations);
+    void optimize_GRID_GENERAL(int nIterations);
+    void optimize_GRID_BINARY(int nIterations);
+};
+
+}
+
+#endif /*  __TRWS_H__ */

+ 290 - 0
mrf/mrfmin/block.h

@@ -0,0 +1,290 @@
+/* block.h */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    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.
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/*
+	Template classes Block and DBlock
+	Implement adding and deleting items of the same type in blocks.
+
+	If there there are many items then using Block or DBlock
+	is more efficient than using 'new' and 'delete' both in terms
+	of memory and time since
+	(1) On some systems there is some minimum amount of memory
+	    that 'new' can allocate (e.g., 64), so if items are
+	    small that a lot of memory is wasted.
+	(2) 'new' and 'delete' are designed for items of varying size.
+	    If all items has the same size, then an algorithm for
+	    adding and deleting can be made more efficient.
+	(3) All Block and DBlock functions are inline, so there are
+	    no extra function calls.
+
+	Differences between Block and DBlock:
+	(1) DBlock allows both adding and deleting items,
+	    whereas Block allows only adding items.
+	(2) Block has an additional operation of scanning
+	    items added so far (in the order in which they were added).
+	(3) Block allows to allocate several consecutive
+	    items at a time, whereas DBlock can add only a single item.
+
+	Note that no constructors or destructors are called for items.
+
+	Example usage for items of type 'MyType':
+
+	///////////////////////////////////////////////////
+	#include "block.h"
+	#define BLOCK_SIZE 1024
+	typedef struct { int a, b; } MyType;
+	MyType *ptr, *array[10000];
+
+	...
+
+	Block<MyType> *block = new Block<MyType>(BLOCK_SIZE);
+
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		ptr = block -> New();
+		ptr -> a = ptr -> b = rand();
+	}
+
+	// reading items
+	for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext())
+	{
+		printf("%d %d\n", ptr->a, ptr->b);
+	}
+
+	delete block;
+
+	...
+
+	DBlock<MyType> *dblock = new DBlock<MyType>(BLOCK_SIZE);
+	
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		array[i] = dblock -> New();
+	}
+
+	// deleting items
+	for (int i=0; i<sizeof(array); i+=2)
+	{
+		dblock -> Delete(array[i]);
+	}
+
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		array[i] = dblock -> New();
+	}
+
+	delete dblock;
+
+	///////////////////////////////////////////////////
+
+	Note that DBlock deletes items by marking them as
+	empty (i.e., by adding them to the list of free items),
+	so that this memory could be used for subsequently
+	added items. Thus, at each moment the memory allocated
+	is determined by the maximum number of items allocated
+	simultaneously at earlier moments. All memory is
+	deallocated only when the destructor is called.
+*/
+
+#ifndef __BLOCK_H__
+#define __BLOCK_H__
+
+#include <stdlib.h>
+
+namespace OBJREC {
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+template <class Type> class Block
+{
+public:
+	/* Constructor. Arguments are the block size and
+	   (optionally) the pointer to the function which
+	   will be called if allocation failed; the message
+	   passed to this function is "Not enough memory!" */
+	Block(int size, void (*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
+
+	/* Destructor. Deallocates all items added so far */
+	~Block() { while (first) { block *next = first -> next; delete [] first; first = next; } }
+
+	/* Allocates 'num' consecutive items; returns pointer
+	   to the first item. 'num' cannot be greater than the
+	   block size since items must fit in one block */
+	Type *New(int num = 1)
+	{
+		Type *t;
+
+		if (!last || last->current + num > last->last)
+		{
+			if (last && last->next) last = last -> next;
+			else
+			{
+				block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)];
+				if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
+				if (last) last -> next = next;
+				else first = next;
+				last = next;
+				last -> current = & ( last -> data[0] );
+				last -> last = last -> current + block_size;
+				last -> next = NULL;
+			}
+		}
+
+		t = last -> current;
+		last -> current += num;
+		return t;
+	}
+
+	/* Returns the first item (or NULL, if no items were added) */
+	Type *ScanFirst()
+	{
+		scan_current_block = first;
+		if (!scan_current_block) return NULL;
+		scan_current_data = & ( scan_current_block -> data[0] );
+		return scan_current_data ++;
+	}
+
+	/* Returns the next item (or NULL, if all items have been read)
+	   Can be called only if previous ScanFirst() or ScanNext()
+	   call returned not NULL. */
+	Type *ScanNext()
+	{
+		if (scan_current_data >= scan_current_block -> current)
+		{
+			scan_current_block = scan_current_block -> next;
+			if (!scan_current_block) return NULL;
+			scan_current_data = & ( scan_current_block -> data[0] );
+		}
+		return scan_current_data ++;
+	}
+
+	/* Marks all elements as empty */
+	void Reset()
+	{
+		block *b;
+		if (!first) return;
+		for (b=first; ; b=b->next)
+		{
+			b -> current = & ( b -> data[0] );
+			if (b == last) break;
+		}
+		last = first;
+	}
+
+/***********************************************************************/
+
+private:
+
+	typedef struct block_st
+	{
+		Type					*current, *last;
+		struct block_st			*next;
+		Type					data[1];
+	} block;
+
+	int		block_size;
+	block	*first;
+	block	*last;
+
+	block	*scan_current_block;
+	Type	*scan_current_data;
+
+	void	(*error_function)(char *);
+};
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+template <class Type> class DBlock
+{
+public:
+	/* Constructor. Arguments are the block size and
+	   (optionally) the pointer to the function which
+	   will be called if allocation failed; the message
+	   passed to this function is "Not enough memory!" */
+	DBlock(int size, void (*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
+
+	/* Destructor. Deallocates all items added so far */
+	~DBlock() { while (first) { block *next = first -> next; 
+		delete [] first; 
+		first = next; } }
+
+	/* Allocates one item */
+	Type *New()
+	{
+		block_item *item;
+
+		if (!first_free)
+		{
+			block *next = first;
+			first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)];
+			if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
+			first_free = & (first -> data[0] );
+			for (item=first_free; item<first_free+block_size-1; item++)
+				item -> next_free = item + 1;
+			item -> next_free = NULL;
+			first -> next = next;
+		}
+
+		item = first_free;
+		first_free = item -> next_free;
+		return (Type *) item;
+	}
+
+	/* Deletes an item allocated previously */
+	void Delete(Type *t)
+	{
+		((block_item *) t) -> next_free = first_free;
+		first_free = (block_item *) t;
+	}
+
+/***********************************************************************/
+
+private:
+
+	typedef union block_item_st
+	{
+		Type			t;
+		block_item_st	*next_free;
+	} block_item;
+
+	typedef struct block_st
+	{
+		struct block_st			*next;
+		block_item				data[1];
+	} block;
+
+	int			block_size;
+	block		*first;
+	block_item	*first_free;
+
+	void	(*error_function)(char *);
+};
+
+}
+
+#endif
+

+ 331 - 0
mrf/mrfmin/energy.h

@@ -0,0 +1,331 @@
+/* energy.h */
+/* Vladimir Kolmogorov (vnk@cs.cornell.edu), 2003. */
+
+/*
+ This software implements an energy minimization technique described in
+
+ What Energy Functions can be Minimized via Graph Cuts?
+ Vladimir Kolmogorov and Ramin Zabih.
+ To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI).
+ Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002.
+
+ More specifically, it computes the global minimum of a function E of binary
+ variables x_1, ..., x_n which can be written as a sum of terms involving
+ at most three variables at a time:
+
+  E(x_1, ..., x_n) = \sum_{i}     E^{i}    (x_i)
+                   + \sum_{i,j}   E^{i,j}  (x_i, x_j)
+                   + \sum_{i,j,k} E^{i,j,k}(x_i, x_j, x_k)
+
+ The method works only if each term is "regular". Definitions of regularity
+ for terms E^{i}, E^{i,j}, E^{i,j,k} are given below as comments to functions
+ add_term1(), add_term2(), add_term3().
+
+ This software can be used only for research purposes. IF YOU USE THIS SOFTWARE,
+ YOU SHOULD CITE THE AFOREMENTIONED PAPER IN ANY RESULTING PUBLICATION.
+
+ In order to use it, you will also need a MAXFLOW software which can be
+ obtained from http://www.cs.cornell.edu/People/vnk/software.html
+
+
+ Example usage
+ (Minimizes the following function of 3 binary variables:
+ E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|):
+
+ ///////////////////////////////////////////////////
+
+ #include <stdio.h>
+ #include "energy.h"
+
+ void main()
+ {
+  // Minimize the following function of 3 binary variables:
+  // E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|
+
+  Energy::Var varx, vary, varz;
+  Energy *e = new Energy();
+
+  varx = e -> add_variable();
+  vary = e -> add_variable();
+  varz = e -> add_variable();
+
+  e -> add_term1(varx, 0, 1);  // add term x
+  e -> add_term1(vary, 0, -2); // add term -2*y
+  e -> add_term1(varz, 3, 0);  // add term 3*(1-z)
+
+  e -> add_term2(x, y, 0, 0, 0, -4); // add term -4*x*y
+  e -> add_term2(y, z, 0, 5, 5, 0); // add term 5*|y-z|
+
+  Energy::TotalValue Emin = e -> minimize();
+
+  printf("Minimum = %d\n", Emin);
+  printf("Optimal solution:\n");
+  printf("x = %d\n", e->get_var(varx));
+  printf("y = %d\n", e->get_var(vary));
+  printf("z = %d\n", e->get_var(varz));
+
+  delete e;
+ }
+
+ ///////////////////////////////////////////////////
+*/
+
+#ifndef __ENERGY_H__
+#define __ENERGY_H__
+
+#include <assert.h>
+#include "graph.h"
+
+namespace OBJREC {
+
+class Energy : Graph
+{
+  public:
+    typedef node_id Var;
+
+    /* Types of energy values.
+       Value is a type of a value in a single term
+       TotalValue is a type of a value of the total energy.
+       By default Value = short, TotalValue = int.
+       To change it, change the corresponding types in graph.h */
+    typedef captype Value;
+    typedef flowtype TotalValue;
+
+    /* interface functions */
+
+    /* Constructor. Optional argument is the pointer to the
+       function which will be called if an error occurs;
+       an error message is passed to this function. If this
+       argument is omitted, exit(1) will be called. */
+    Energy(void (*err_function)(char *) = NULL);
+
+    /* Destructor */
+    ~Energy();
+
+    /* Adds a new binary variable */
+    Var add_variable();
+
+    /* Adds a constant E to the energy function */
+    void add_constant(Value E);
+
+    /* Adds a new term E(x) of one binary variable
+       to the energy function, where
+           E(0) = E0, E(1) = E1
+       E0 and E1 can be arbitrary */
+    void add_term1(Var x,
+                   Value E0, Value E1);
+
+    /* Adds a new term E(x,y) of two binary variables
+       to the energy function, where
+           E(0,0) = E00, E(0,1) = E01
+           E(1,0) = E10, E(1,1) = E11
+       The term must be regular, i.e. E00 + E11 <= E01 + E10 */
+    void add_term2(Var x, Var y,
+                   Value E00, Value E01,
+                   Value E10, Value E11);
+
+    /* Adds a new term E(x,y,z) of three binary variables
+       to the energy function, where
+           E(0,0,0) = E000, E(0,0,1) = E001
+           E(0,1,0) = E010, E(0,1,1) = E011
+           E(1,0,0) = E100, E(1,0,1) = E101
+           E(1,1,0) = E110, E(1,1,1) = E111
+       The term must be regular. It means that if one
+       of the variables is fixed (for example, y=1), then
+       the resulting function of two variables must be regular.
+       Since there are 6 ways to fix one variable
+       (3 variables times 2 binary values - 0 and 1),
+       this is equivalent to 6 inequalities */
+    void add_term3(Var x, Var y, Var z,
+                   Value E000, Value E001,
+                   Value E010, Value E011,
+                   Value E100, Value E101,
+                   Value E110, Value E111);
+
+    /* After the energy function has been constructed,
+       call this function to minimize it.
+       Returns the minimum of the function */
+    TotalValue minimize();
+
+    /* After 'minimize' has been called, this function
+       can be used to determine the value of variable 'x'
+       in the optimal solution.
+       Returns either 0 or 1 */
+    int get_var(Var x);
+
+    /***********************************************************************/
+    /***********************************************************************/
+    /***********************************************************************/
+
+  private:
+    /* internal variables and functions */
+
+    TotalValue Econst;
+    void  (*error_function)(char *); /* this function is called if a error occurs,
+           with a corresponding error message
+           (or exit(1) is called if it's NULL) */
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/***********************************************************************/
+/************************  Implementation ******************************/
+/***********************************************************************/
+
+inline Energy::Energy(void (*err_function)(char *)) : Graph(err_function)
+{
+  Econst = 0;
+  error_function = err_function;
+}
+
+inline Energy::~Energy() {}
+
+inline Energy::Var Energy::add_variable() {
+  return add_node();
+}
+
+inline void Energy::add_constant(Value A) {
+  Econst += A;
+}
+
+inline void Energy::add_term1(Var x,
+                              Value A, Value B)
+{
+  add_tweights(x, B, A);
+}
+
+inline void Energy::add_term2(Var x, Var y,
+                              Value A, Value B,
+                              Value C, Value D)
+{
+  /*
+     E = A A  +  0   B-A
+         D D     C-D 0
+     Add edges for the first term
+  */
+  add_tweights(x, D, A);
+  B -= A;
+  C -= D;
+
+  /* now need to represent
+     0 B
+     C 0
+  */
+
+  assert(B + C >= 0); /* check regularity */
+  if (B < 0)
+  {
+    /* Write it as
+       B B  +  -B 0  +  0   0
+       0 0     -B 0     B+C 0
+    */
+    add_tweights(x, 0, B); /* first term */
+    add_tweights(y, 0, -B); /* second term */
+    add_edge(x, y, 0, B + C); /* third term */
+  }
+  else if (C < 0)
+  {
+    /* Write it as
+       -C -C  +  C 0  +  0 B+C
+        0  0     C 0     0 0
+    */
+    add_tweights(x, 0, -C); /* first term */
+    add_tweights(y, 0, C); /* second term */
+    add_edge(x, y, B + C, 0); /* third term */
+  }
+  else /* B >= 0, C >= 0 */
+  {
+    add_edge(x, y, B, C);
+  }
+}
+
+inline void Energy::add_term3(Var x, Var y, Var z,
+                              Value E000, Value E001,
+                              Value E010, Value E011,
+                              Value E100, Value E101,
+                              Value E110, Value E111)
+{
+  register Value pi = (E000 + E011 + E101 + E110) - (E100 + E010 + E001 + E111);
+  register Value delta;
+  register Var u;
+
+  if (pi >= 0)
+  {
+    Econst += E111 - (E011 + E101 + E110);
+
+    add_tweights(x, E101, E001);
+    add_tweights(y, E110, E100);
+    add_tweights(z, E011, E010);
+
+    delta = (E010 + E001) - (E000 + E011); /* -pi(E[x=0]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(y, z, delta, 0);
+
+    delta = (E100 + E001) - (E000 + E101); /* -pi(E[y=0]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(z, x, delta, 0);
+
+    delta = (E100 + E010) - (E000 + E110); /* -pi(E[z=0]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(x, y, delta, 0);
+
+    if (pi > 0)
+    {
+      u = add_variable();
+      add_edge(x, u, pi, 0);
+      add_edge(y, u, pi, 0);
+      add_edge(z, u, pi, 0);
+      add_tweights(u, 0, pi);
+    }
+  }
+  else
+  {
+    Econst += E000 - (E100 + E010 + E001);
+
+    add_tweights(x, E110, E010);
+    add_tweights(y, E011, E001);
+    add_tweights(z, E101, E100);
+
+    delta = (E110 + E101) - (E100 + E111); /* -pi(E[x=1]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(z, y, delta, 0);
+
+    delta = (E110 + E011) - (E010 + E111); /* -pi(E[y=1]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(x, z, delta, 0);
+
+    delta = (E101 + E011) - (E001 + E111); /* -pi(E[z=1]) */
+    assert(delta >= 0); /* check regularity */
+    add_edge(y, x, delta, 0);
+
+    u = add_variable();
+    add_edge(u, x, -pi, 0);
+    add_edge(u, y, -pi, 0);
+    add_edge(u, z, -pi, 0);
+    add_tweights(u, -pi, 0);
+  }
+}
+
+inline Energy::TotalValue Energy::minimize() {
+  return Econst + maxflow();
+}
+
+inline int Energy::get_var(Var x) {
+  return (int) what_segment(x);
+}
+
+} //namespace
+
+#endif

+ 372 - 0
mrf/mrfmin/graph.cpp

@@ -0,0 +1,372 @@
+/* graph.cpp */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    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.
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include <stdio.h>
+#include <iostream>
+#include "graph.h"
+
+using namespace OBJREC;
+
+Graph::Graph(void (*err_function)(char *))
+{
+  error_function = err_function;
+  node_block_first = NULL;
+  arc_for_block_first = NULL;
+  arc_rev_block_first = NULL;
+  flow = 0;
+}
+
+Graph::~Graph()
+{
+  while (node_block_first)
+  {
+    node_block *next = node_block_first -> next;
+    delete node_block_first;
+    node_block_first = next;
+  }
+
+  while (arc_for_block_first)
+  {
+    arc_for_block *next = arc_for_block_first -> next;
+    delete [] arc_for_block_first -> start;
+    arc_for_block_first = next;
+  }
+
+  while (arc_rev_block_first)
+  {
+    arc_rev_block *next = arc_rev_block_first -> next;
+    delete [] arc_rev_block_first -> start;
+    arc_rev_block_first = next;
+  }
+}
+
+Graph::node_id Graph::add_node()
+{
+  node *i;
+
+  if (!node_block_first || node_block_first->current + 1 > &node_block_first->nodes[NODE_BLOCK_SIZE-1])
+  {
+    node_block *next = node_block_first;
+    node_block_first = (node_block *) new node_block;
+    if (!node_block_first) {
+      if (error_function) (*error_function)("Not enough memory!");
+      exit(1);
+    }
+    node_block_first -> current = & ( node_block_first -> nodes[0] );
+    node_block_first -> next = next;
+  }
+
+  i = node_block_first -> current ++;
+  i -> first_out = (arc_forward *) 0;
+  i -> first_in = (arc_reverse *) 0;
+
+  i -> tr_cap = 0;
+
+  return (node_id) i;
+}
+
+void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap)
+{
+  arc_forward *a_for;
+  arc_reverse *a_rev;
+
+  if (!arc_for_block_first || arc_for_block_first->current + 1 > &arc_for_block_first->arcs_for[ARC_BLOCK_SIZE])
+  {
+    arc_for_block *next = arc_for_block_first;
+    char *ptr = new char[sizeof(arc_for_block)+1];
+    if (!ptr) {
+      if (error_function) (*error_function)("Not enough memory!");
+      exit(1);
+    }
+    if ((PTR_CAST)ptr & 1) arc_for_block_first = (arc_for_block *) (ptr + 1);
+    else              arc_for_block_first = (arc_for_block *) ptr;
+    arc_for_block_first -> start = ptr;
+    arc_for_block_first -> current = & ( arc_for_block_first -> arcs_for[0] );
+    arc_for_block_first -> next = next;
+  }
+
+  if (!arc_rev_block_first || arc_rev_block_first->current + 1 > &arc_rev_block_first->arcs_rev[ARC_BLOCK_SIZE])
+  {
+    arc_rev_block *next = arc_rev_block_first;
+    char *ptr = new char[sizeof(arc_rev_block)+1];
+    if (!ptr) {
+      if (error_function) (*error_function)("Not enough memory!");
+      exit(1);
+    }
+    if ((PTR_CAST)ptr & 1) arc_rev_block_first = (arc_rev_block *) (ptr + 1);
+    else              arc_rev_block_first = (arc_rev_block *) ptr;
+    arc_rev_block_first -> start = ptr;
+    arc_rev_block_first -> current = & ( arc_rev_block_first -> arcs_rev[0] );
+    arc_rev_block_first -> next = next;
+  }
+
+  a_for = arc_for_block_first -> current ++;
+  a_rev = arc_rev_block_first -> current ++;
+
+  a_rev -> sister = (arc_forward *) from;
+  a_for -> shift  = (PTR_CAST) to;
+  a_for -> r_cap = cap;
+  a_for -> r_rev_cap = rev_cap;
+
+  ((node *)from) -> first_out =
+    (arc_forward *) ((PTR_CAST)(((node *)from) -> first_out) + 1);
+  ((node *)to) -> first_in =
+    (arc_reverse *) ((PTR_CAST)(((node *)to) -> first_in) + 1);
+}
+
+void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink)
+{
+  flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+  ((node*)i) -> tr_cap = cap_source - cap_sink;
+}
+
+void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink)
+{
+  register captype delta = ((node*)i) -> tr_cap;
+  if (delta > 0) cap_source += delta;
+  else           cap_sink   -= delta;
+  flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+  ((node*)i) -> tr_cap = cap_source - cap_sink;
+}
+
+/*
+ Converts arcs added by 'add_edge()' calls
+ to a forward star graph representation.
+
+ Linear time algorithm.
+ No or little additional memory is allocated
+ during this process
+ (it may be necessary to allocate additional
+ arc blocks, since arcs corresponding to the
+ same node must be contiguous, i.e. be in one
+ arc block.)
+*/
+void Graph::prepare_graph()
+{
+  node *i;
+  arc_for_block *ab_for, *ab_for_first;
+  arc_rev_block *ab_rev, *ab_rev_first, *ab_rev_scan;
+  arc_forward *a_for;
+  arc_reverse *a_rev, *a_rev_scan, a_rev_tmp;
+  node_block *nb;
+  bool for_flag = false, rev_flag = false;
+  PTR_CAST k;
+
+  if (!arc_rev_block_first)
+  {
+    node_id from = add_node(), to = add_node();
+    add_edge(from, to, 1, 0);
+  }
+
+  /* FIRST STAGE */
+  a_rev_tmp.sister = NULL;
+  for (a_rev = arc_rev_block_first->current; a_rev < &arc_rev_block_first->arcs_rev[ARC_BLOCK_SIZE]; a_rev++)
+  {
+    a_rev -> sister = NULL;
+  }
+
+  ab_for = ab_for_first = arc_for_block_first;
+  ab_rev = ab_rev_first = ab_rev_scan = arc_rev_block_first;
+  a_for = &ab_for->arcs_for[0];
+  a_rev = a_rev_scan = &ab_rev->arcs_rev[0];
+
+  for (nb = node_block_first; nb; nb = nb->next)
+  {
+    for (i = &nb->nodes[0]; i < nb->current; i++)
+    {
+      /* outgoing arcs */
+      k = (PTR_CAST) i -> first_out;
+      if (a_for + k > &ab_for->arcs_for[ARC_BLOCK_SIZE])
+      {
+        if (k > ARC_BLOCK_SIZE) {
+          if (error_function) (*error_function)("# of arcs per node exceeds block size!");
+          exit(1);
+        }
+        if (for_flag) ab_for = NULL;
+        else          {
+          ab_for = ab_for -> next;
+          ab_rev_scan = ab_rev_scan -> next;
+        }
+        if (ab_for == NULL)
+        {
+          arc_for_block *next = arc_for_block_first;
+          char *ptr = new char[sizeof(arc_for_block)+1];
+          if (!ptr) {
+            if (error_function) (*error_function)("Not enough memory!");
+            exit(1);
+          }
+          if ((PTR_CAST)ptr & 1) arc_for_block_first = (arc_for_block *) (ptr + 1);
+          else              arc_for_block_first = (arc_for_block *) ptr;
+          arc_for_block_first -> start = ptr;
+          arc_for_block_first -> current = & ( arc_for_block_first -> arcs_for[0] );
+          arc_for_block_first -> next = next;
+          ab_for = arc_for_block_first;
+          for_flag = true;
+        }
+        else a_rev_scan = &ab_rev_scan->arcs_rev[0];
+        a_for = &ab_for->arcs_for[0];
+      }
+      if (ab_rev_scan)
+      {
+        a_rev_scan += k;
+        i -> parent = (arc_forward *) a_rev_scan;
+      }
+      else i -> parent = (arc_forward *) & a_rev_tmp;
+      a_for += k;
+      i -> first_out = a_for;
+      ab_for -> last_node = i;
+
+      /* incoming arcs */
+      k = (PTR_CAST) i -> first_in;
+      if (a_rev + k > &ab_rev->arcs_rev[ARC_BLOCK_SIZE])
+      {
+        if (k > ARC_BLOCK_SIZE) {
+          if (error_function) (*error_function)("# of arcs per node exceeds block size!");
+          exit(1);
+        }
+        if (rev_flag) ab_rev = NULL;
+        else          ab_rev = ab_rev -> next;
+        if (ab_rev == NULL)
+        {
+          arc_rev_block *next = arc_rev_block_first;
+          char *ptr = new char[sizeof(arc_rev_block)+1];
+          if (!ptr) {
+            if (error_function) (*error_function)("Not enough memory!");
+            exit(1);
+          }
+          if ((PTR_CAST)ptr & 1) arc_rev_block_first = (arc_rev_block *) (ptr + 1);
+          else              arc_rev_block_first = (arc_rev_block *) ptr;
+          arc_rev_block_first -> start = ptr;
+          arc_rev_block_first -> current = & ( arc_rev_block_first -> arcs_rev[0] );
+          arc_rev_block_first -> next = next;
+          ab_rev = arc_rev_block_first;
+          rev_flag = true;
+        }
+        a_rev = &ab_rev->arcs_rev[0];
+      }
+      a_rev += k;
+      i -> first_in = a_rev;
+      ab_rev -> last_node = i;
+    }
+    /* i is the last node in block */
+    i -> first_out = a_for;
+    i -> first_in  = a_rev;
+  }
+
+  /* SECOND STAGE */
+  for (ab_for = arc_for_block_first; ab_for; ab_for = ab_for->next)
+  {
+    ab_for -> current = ab_for -> last_node -> first_out;
+  }
+
+  for ( ab_for = ab_for_first, ab_rev = ab_rev_first;
+        ab_for;
+        ab_for = ab_for->next, ab_rev = ab_rev->next )
+    for ( a_for = &ab_for->arcs_for[0], a_rev = &ab_rev->arcs_rev[0];
+          a_for < &ab_for->arcs_for[ARC_BLOCK_SIZE];
+          a_for++, a_rev++ )
+    {
+      arc_forward *af;
+      arc_reverse *ar;
+      node *from;
+      PTR_CAST shift = 0, shift_new;
+      captype r_cap, r_rev_cap, r_cap_new, r_rev_cap_new;
+
+      if (!(from = (node *)(a_rev->sister))) continue;
+      af = a_for;
+      ar = a_rev;
+
+      do
+      {
+        ar -> sister = NULL;
+
+        shift_new = ((char *)(af->shift)) - (char *)from;
+        r_cap_new = af -> r_cap;
+        r_rev_cap_new = af -> r_rev_cap;
+        if (shift)
+        {
+          af -> shift = shift;
+          af -> r_cap = r_cap;
+          af -> r_rev_cap = r_rev_cap;
+        }
+        shift = shift_new;
+        r_cap = r_cap_new;
+        r_rev_cap = r_rev_cap_new;
+
+        af = -- from -> first_out;
+        if ((arc_reverse *)(from->parent) != &a_rev_tmp)
+        {
+          from -> parent = (arc_forward *)(((arc_reverse *)(from -> parent)) - 1);
+          ar = (arc_reverse *)(from -> parent);
+        }
+      } while (from = (node *)(ar->sister));
+
+      af -> shift = shift;
+      af -> r_cap = r_cap;
+      af -> r_rev_cap = r_rev_cap;
+    }
+
+  for (ab_for = arc_for_block_first; ab_for; ab_for = ab_for->next)
+  {
+    i = ab_for -> last_node;
+    a_for = i -> first_out;
+    ab_for -> current -> shift     = a_for -> shift;
+    ab_for -> current -> r_cap     = a_for -> r_cap;
+    ab_for -> current -> r_rev_cap = a_for -> r_rev_cap;
+    a_for -> shift = (PTR_CAST) (ab_for -> current + 1);
+    i -> first_out = (arc_forward *) (((char *)a_for) - 1);
+  }
+
+  /* THIRD STAGE */
+  for (ab_rev = arc_rev_block_first; ab_rev; ab_rev = ab_rev->next)
+  {
+    ab_rev -> current = ab_rev -> last_node -> first_in;
+  }
+
+  for (nb = node_block_first; nb; nb = nb->next)
+    for (i = &nb->nodes[0]; i < nb->current; i++)
+    {
+      arc_forward *a_for_first, *a_for_last;
+
+      a_for_first = i -> first_out;
+      if (IS_ODD(a_for_first))
+      {
+        a_for_first = (arc_forward *) (((char *)a_for_first) + 1);
+        a_for_last = (arc_forward *) ((a_for_first ++) -> shift);
+      }
+      else a_for_last = (i + 1) -> first_out;
+
+      for (a_for = a_for_first; a_for < a_for_last; a_for++)
+      {
+        node *to = NEIGHBOR_NODE(i, a_for -> shift);
+        a_rev = -- to -> first_in;
+        a_rev -> sister = a_for;
+      }
+    }
+
+  for (ab_rev = arc_rev_block_first; ab_rev; ab_rev = ab_rev->next)
+  {
+    i = ab_rev -> last_node;
+    a_rev = i -> first_in;
+    ab_rev -> current -> sister = a_rev -> sister;
+    a_rev -> sister = (arc_forward *) (ab_rev -> current + 1);
+    i -> first_in = (arc_reverse *) (((char *)a_rev) - 1);
+  }
+}

+ 264 - 0
mrf/mrfmin/graph.h

@@ -0,0 +1,264 @@
+/* graph.h */
+/*
+ This software library implements the maxflow algorithm
+ described in
+
+  An Experimental Comparison of Min-Cut/Max-Flow Algorithms
+  for Energy Minimization in Vision.
+  Yuri Boykov and Vladimir Kolmogorov.
+  In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI),
+  September 2004
+
+ This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov
+ at Siemens Corporate Research. To make it available for public use,
+ it was later reimplemented by Vladimir Kolmogorov based on open publications.
+
+ If you use this software for research purposes, you should cite
+ the aforementioned paper in any resulting publication.
+*/
+
+/*
+ Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    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.
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/*
+ For description, example usage, discussion of graph representation
+ and memory usage see README.TXT.
+*/
+
+#ifndef __GRAPH_H__
+#define __GRAPH_H__
+
+#ifndef USE_64_BIT_PTR_CAST
+#define PTR_CAST int
+#else
+#define PTR_CAST long int
+#endif
+
+#include "block.h"
+
+/*
+ Nodes, arcs and pointers to nodes are
+ added in blocks for memory and time efficiency.
+ Below are numbers of items in blocks
+*/
+#define NODE_BLOCK_SIZE 512
+#define ARC_BLOCK_SIZE 1024
+#define NODEPTR_BLOCK_SIZE 128
+
+namespace OBJREC {
+
+class Graph
+{
+  public:
+    typedef enum
+    {
+      SOURCE = 0,
+      SINK = 1
+    } termtype; /* terminals */
+
+    /* Type of edge weights.
+       Can be changed to char, int, float, double, ... */
+    typedef double captype;
+    /* Type of total flow */
+
+    typedef int flowtype;
+    typedef void * node_id;
+
+    /* interface functions */
+
+    /* Constructor. Optional argument is the pointer to the
+       function which will be called if an error occurs;
+       an error message is passed to this function. If this
+       argument is omitted, exit(1) will be called. */
+    Graph(void (*err_function)(char *) = NULL);
+
+    /* Destructor */
+    ~Graph();
+
+    /* Adds a node to the graph */
+    node_id add_node();
+
+    /* Adds a bidirectional edge between 'from' and 'to'
+       with the weights 'cap' and 'rev_cap' */
+    void add_edge(node_id from, node_id to, captype cap, captype rev_cap);
+
+    /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK'
+       Can be called at most once for each node before any call to 'add_tweights'.
+       Weights can be negative */
+    void set_tweights(node_id i, captype cap_source, captype cap_sink);
+
+    /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights
+       Can be called multiple times for each node.
+       Weights can be negative */
+    void add_tweights(node_id i, captype cap_source, captype cap_sink);
+
+    /* After the maxflow is computed, this function returns to which
+       segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */
+    termtype what_segment(node_id i);
+
+    /* Computes the maxflow. Can be called only once. */
+    flowtype maxflow();
+
+    /***********************************************************************/
+    /***********************************************************************/
+    /***********************************************************************/
+
+  private:
+    /* internal variables and functions */
+
+    struct arc_forward_st;
+    struct arc_reverse_st;
+
+#define IS_ODD(a) ((PTR_CAST)(a) & 1)
+#define MAKE_ODD(a)  ((arc_forward *) ((PTR_CAST)(a) | 1))
+#define MAKE_EVEN(a) ((arc_forward *) ((PTR_CAST)(a) & (~1)))
+#define MAKE_ODD_REV(a)  ((arc_reverse *) ((PTR_CAST)(a) | 1))
+#define MAKE_EVEN_REV(a) ((arc_reverse *) ((PTR_CAST)(a) & (~1)))
+
+    /* node structure */
+    typedef struct node_st
+    {
+      /*
+       Usually i->first_out is the first outgoing
+       arc, and (i+1)->first_out-1 is the last outgoing arc.
+       However, it is not always possible, since
+       arcs are allocated in blocks, so arcs corresponding
+       to two consecutive nodes may be in different blocks.
+
+       If outgoing arcs for i are last in the arc block,
+       then a different mechanism is used. i->first_out
+       is odd in this case; the first outgoing arc
+       is (a+1), and the last outgoing arc is
+       ((arc_forward *)(a->shift))-1, where
+       a = (arc_forward *) (((char *)(i->first_out)) + 1);
+
+       Similar mechanism is used for incoming arcs.
+      */
+      arc_forward_st *first_out; /* first outcoming arc */
+      arc_reverse_st *first_in; /* first incoming arc */
+
+      arc_forward_st *parent; /* describes node's parent
+            if IS_ODD(parent) then MAKE_EVEN(parent) points to 'arc_reverse',
+            otherwise parent points to 'arc_forward' */
+
+      node_st   *next;  /* pointer to the next active node
+            (or to itself if it is the last node in the list) */
+
+      int    TS;   /* timestamp showing when DIST was computed */
+      int    DIST;  /* distance to the terminal */
+      short   is_sink; /* flag showing whether the node is in the source or in the sink tree */
+
+      captype   tr_cap;  /* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node
+            otherwise         -tr_cap is residual capacity of the arc node->SINK */
+    } node;
+
+    /* arc structures */
+#define NEIGHBOR_NODE(i, shift) ((node *) ((char *)(i) + (shift)))
+#define NEIGHBOR_NODE_REV(i, shift) ((node *) ((char *)(i) - (shift)))
+    typedef struct arc_forward_st
+    {
+      PTR_CAST  shift;  /* node_to = NEIGHBOR_NODE(node_from, shift) */
+      captype   r_cap;  /* residual capacity */
+      captype   r_rev_cap; /* residual capacity of the reverse arc*/
+    } arc_forward;
+
+    typedef struct arc_reverse_st
+    {
+      arc_forward  *sister; /* reverse arc */
+    } arc_reverse;
+
+    /* 'pointer to node' structure */
+    typedef struct nodeptr_st
+    {
+      node_st   *ptr;
+      nodeptr_st  *next;
+    } nodeptr;
+
+    typedef struct node_block_st
+    {
+      node     *current;
+      struct node_block_st *next;
+      node     nodes[NODE_BLOCK_SIZE];
+    } node_block;
+
+#define last_node LAST_NODE.LAST_NODE
+
+    typedef struct arc_for_block_st
+    {
+      char     *start;  /* the actual start address of this block.
+              May be different from 'this' since 'this'
+              must be at an even address. */
+      arc_forward    *current;
+      struct arc_for_block_st *next;
+      arc_forward    arcs_for[ARC_BLOCK_SIZE]; /* all arcs must be at even addresses */
+      union
+      {
+        arc_forward   dummy;
+        node    *LAST_NODE; /* used in graph consruction */
+      }      LAST_NODE;
+    } arc_for_block;
+
+    typedef struct arc_rev_block_st
+    {
+      char     *start;  /* the actual start address of this block.
+              May be different from 'this' since 'this'
+              must be at an even address. */
+      arc_reverse    *current;
+      struct arc_rev_block_st *next;
+      arc_reverse    arcs_rev[ARC_BLOCK_SIZE]; /* all arcs must be at even addresses */
+      union
+      {
+        arc_reverse   dummy;
+        node    *LAST_NODE; /* used in graph consruction */
+      }      LAST_NODE;
+    } arc_rev_block;
+
+    node_block   *node_block_first;
+    arc_for_block  *arc_for_block_first;
+    arc_rev_block  *arc_rev_block_first;
+    DBlock<nodeptr>  *nodeptr_block;
+
+    void (*error_function)(char *); /* this function is called if a error occurs,
+             with a corresponding error message
+             (or exit(1) is called if it's NULL) */
+
+    flowtype   flow;  /* total flow */
+
+    /***********************************************************************/
+
+    node    *queue_first[2], *queue_last[2]; /* list of active nodes */
+    nodeptr    *orphan_first, *orphan_last;  /* list of pointers to orphans */
+    int     TIME;        /* monotonically increasing global counter */
+
+    /***********************************************************************/
+
+    /* functions for processing active list */
+    void set_active(node *i);
+    node *next_active();
+
+    void prepare_graph();
+    void maxflow_init();
+    void augment(node *s_start, node *t_start, captype *cap_middle, captype *rev_cap_middle);
+    void process_source_orphan(node *i);
+    void process_sink_orphan(node *i);
+};
+
+} //namespace
+
+#endif

+ 1 - 0
mrf/mrfmin/libdepend.inc

@@ -0,0 +1 @@
+$(call PKG_DEPEND_EXT,ICE)

+ 889 - 0
mrf/mrfmin/maxflow.cpp

@@ -0,0 +1,889 @@
+/* maxflow.cpp */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    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.
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include <stdio.h>
+#include "graph.h"
+
+using namespace OBJREC;
+
+/*
+ special constants for node->parent
+*/
+#define TERMINAL ( (arc_forward *) 1 )  /* to terminal */
+#define ORPHAN   ( (arc_forward *) 2 )  /* orphan */
+
+#define INFINITE_D 1000000000  /* infinite distance to the terminal */
+
+/***********************************************************************/
+
+/*
+ Functions for processing active list.
+ i->next points to the next node in the list
+ (or to i, if i is the last node in the list).
+ If i->next is NULL iff i is not in the list.
+
+ There are two queues. Active nodes are added
+ to the end of the second queue and read from
+ the front of the first queue. If the first queue
+ is empty, it is replaced by the second queue
+ (and the second queue becomes empty).
+*/
+
+inline void Graph::set_active(node *i)
+{
+  if (!i->next)
+  {
+    /* it's not in the list yet */
+    if (queue_last[1]) queue_last[1] -> next = i;
+    else               queue_first[1]        = i;
+    queue_last[1] = i;
+    i -> next = i;
+  }
+}
+
+/*
+ Returns the next active node.
+ If it is connected to the sink, it stays in the list,
+ otherwise it is removed from the list
+*/
+inline Graph::node * Graph::next_active()
+{
+  node *i;
+
+  while ( 1 )
+  {
+    if (!(i = queue_first[0]))
+    {
+      queue_first[0] = i = queue_first[1];
+      queue_last[0]  = queue_last[1];
+      queue_first[1] = NULL;
+      queue_last[1]  = NULL;
+      if (!i) return NULL;
+    }
+
+    /* remove it from the active list */
+    if (i->next == i) queue_first[0] = queue_last[0] = NULL;
+    else              queue_first[0] = i -> next;
+    i -> next = NULL;
+
+    /* a node in the list is active iff it has a parent */
+    if (i->parent) return i;
+  }
+}
+
+/***********************************************************************/
+
+void Graph::maxflow_init()
+{
+  node *i;
+  node_block *nb;
+
+  queue_first[0] = queue_last[0] = NULL;
+  queue_first[1] = queue_last[1] = NULL;
+  orphan_first = NULL;
+
+  for (nb = node_block_first; nb; nb = nb->next)
+    for (i = &nb->nodes[0]; i < nb->current; i++)
+    {
+      i -> next = NULL;
+      i -> TS = 0;
+      if (i->tr_cap > 0)
+      {
+        /* i is connected to the source */
+        i -> is_sink = 0;
+        i -> parent = TERMINAL;
+        set_active(i);
+        i -> TS = 0;
+        i -> DIST = 1;
+      }
+      else if (i->tr_cap < 0)
+      {
+        /* i is connected to the sink */
+        i -> is_sink = 1;
+        i -> parent = TERMINAL;
+        set_active(i);
+        i -> TS = 0;
+        i -> DIST = 1;
+      }
+      else
+      {
+        //seems to be buggy
+        i -> parent = NULL;
+        i -> is_sink = 1;
+      }
+    }
+  TIME = 0;
+}
+
+/***********************************************************************/
+
+void Graph::augment(node *s_start, node *t_start, captype *cap_middle, captype *rev_cap_middle)
+{
+  node *i;
+  arc_forward *a;
+  captype bottleneck;
+  nodeptr *np;
+
+
+  /* 1. Finding bottleneck capacity */
+  /* 1a - the source tree */
+  bottleneck = *cap_middle;
+  for (i = s_start; ; )
+  {
+    a = i -> parent;
+    if (a == TERMINAL) break;
+    if (IS_ODD(a))
+    {
+      a = MAKE_EVEN(a);
+      if (bottleneck > a->r_cap) bottleneck = a -> r_cap;
+      i = NEIGHBOR_NODE_REV(i, a -> shift);
+    }
+    else
+    {
+      if (bottleneck > a->r_rev_cap) bottleneck = a -> r_rev_cap;
+      i = NEIGHBOR_NODE(i, a -> shift);
+    }
+  }
+  if (bottleneck > i->tr_cap) bottleneck = i -> tr_cap;
+  /* 1b - the sink tree */
+  for (i = t_start; ; )
+  {
+    a = i -> parent;
+    if (a == TERMINAL) break;
+    if (IS_ODD(a))
+    {
+      a = MAKE_EVEN(a);
+      if (bottleneck > a->r_rev_cap) bottleneck = a -> r_rev_cap;
+      i = NEIGHBOR_NODE_REV(i, a -> shift);
+    }
+    else
+    {
+      if (bottleneck > a->r_cap) bottleneck = a -> r_cap;
+      i = NEIGHBOR_NODE(i, a -> shift);
+    }
+  }
+  if (bottleneck > - i->tr_cap) bottleneck = - i -> tr_cap;
+
+
+  /* 2. Augmenting */
+  /* 2a - the source tree */
+  *rev_cap_middle += bottleneck;
+  *cap_middle -= bottleneck;
+  for (i = s_start; ; )
+  {
+    a = i -> parent;
+    if (a == TERMINAL) break;
+    if (IS_ODD(a))
+    {
+      a = MAKE_EVEN(a);
+      a -> r_rev_cap += bottleneck;
+      a -> r_cap -= bottleneck;
+      if (!a->r_cap)
+      {
+        /* add i to the adoption list */
+        i -> parent = ORPHAN;
+        np = nodeptr_block -> New();
+        np -> ptr = i;
+        np -> next = orphan_first;
+        orphan_first = np;
+      }
+      i = NEIGHBOR_NODE_REV(i, a -> shift);
+    }
+    else
+    {
+      a -> r_cap += bottleneck;
+      a -> r_rev_cap -= bottleneck;
+      if (!a->r_rev_cap)
+      {
+        /* add i to the adoption list */
+        i -> parent = ORPHAN;
+        np = nodeptr_block -> New();
+        np -> ptr = i;
+        np -> next = orphan_first;
+        orphan_first = np;
+      }
+      i = NEIGHBOR_NODE(i, a -> shift);
+    }
+  }
+  i -> tr_cap -= bottleneck;
+  if (!i->tr_cap)
+  {
+    /* add i to the adoption list */
+    i -> parent = ORPHAN;
+    np = nodeptr_block -> New();
+    np -> ptr = i;
+    np -> next = orphan_first;
+    orphan_first = np;
+  }
+  /* 2b - the sink tree */
+  for (i = t_start; ; )
+  {
+    a = i -> parent;
+    if (a == TERMINAL) break;
+    if (IS_ODD(a))
+    {
+      a = MAKE_EVEN(a);
+      a -> r_cap += bottleneck;
+      a -> r_rev_cap -= bottleneck;
+      if (!a->r_rev_cap)
+      {
+        /* add i to the adoption list */
+        i -> parent = ORPHAN;
+        np = nodeptr_block -> New();
+        np -> ptr = i;
+        np -> next = orphan_first;
+        orphan_first = np;
+      }
+      i = NEIGHBOR_NODE_REV(i, a -> shift);
+    }
+    else
+    {
+      a -> r_rev_cap += bottleneck;
+      a -> r_cap -= bottleneck;
+      if (!a->r_cap)
+      {
+        /* add i to the adoption list */
+        i -> parent = ORPHAN;
+        np = nodeptr_block -> New();
+        np -> ptr = i;
+        np -> next = orphan_first;
+        orphan_first = np;
+      }
+      i = NEIGHBOR_NODE(i, a -> shift);
+    }
+  }
+  i -> tr_cap += bottleneck;
+  if (!i->tr_cap)
+  {
+    /* add i to the adoption list */
+    i -> parent = ORPHAN;
+    np = nodeptr_block -> New();
+    np -> ptr = i;
+    np -> next = orphan_first;
+    orphan_first = np;
+  }
+
+
+  flow += bottleneck;
+}
+
+/***********************************************************************/
+
+void Graph::process_source_orphan(node *i)
+{
+  node *j;
+  arc_forward *a0_for, *a0_for_first, *a0_for_last;
+  arc_reverse *a0_rev, *a0_rev_first, *a0_rev_last;
+  arc_forward *a0_min = NULL, *a;
+  nodeptr *np;
+  int d, d_min = INFINITE_D;
+
+  /* trying to find a new parent */
+  a0_for_first = i -> first_out;
+  if (IS_ODD(a0_for_first))
+  {
+    a0_for_first = (arc_forward *) (((char *)a0_for_first) + 1);
+    a0_for_last = (arc_forward *) ((a0_for_first ++) -> shift);
+  }
+  else a0_for_last = (i + 1) -> first_out;
+  a0_rev_first = i -> first_in;
+  if (IS_ODD(a0_rev_first))
+  {
+    a0_rev_first = (arc_reverse *) (((char *)a0_rev_first) + 1);
+    a0_rev_last  = (arc_reverse *) ((a0_rev_first ++) -> sister);
+  }
+  else a0_rev_last = (i + 1) -> first_in;
+
+
+  for (a0_for = a0_for_first; a0_for < a0_for_last; a0_for++)
+    if (a0_for->r_rev_cap)
+    {
+      j = NEIGHBOR_NODE(i, a0_for -> shift);
+      if ((a = j->parent) && !j->is_sink)
+      {
+        /* checking the origin of j */
+        d = 0;
+        while ( 1 )
+        {
+          if (j->TS == TIME)
+          {
+            d += j -> DIST;
+            break;
+          }
+          a = j -> parent;
+          d ++;
+          if (a == TERMINAL)
+          {
+            j -> TS = TIME;
+            j -> DIST = 1;
+            break;
+          }
+          if (a == ORPHAN) {
+            d = INFINITE_D;
+            break;
+          }
+          if (IS_ODD(a))
+            j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+          else
+            j = NEIGHBOR_NODE(j, a -> shift);
+        }
+        if (d < INFINITE_D) /* j originates from the source - done */
+        {
+          if (d < d_min)
+          {
+            a0_min = a0_for;
+            d_min = d;
+          }
+          /* set marks along the path */
+          for (j = NEIGHBOR_NODE(i, a0_for->shift); j->TS != TIME; )
+          {
+            j -> TS = TIME;
+            j -> DIST = d --;
+            a = j->parent;
+            if (IS_ODD(a))
+              j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+            else
+              j = NEIGHBOR_NODE(j, a -> shift);
+          }
+        }
+      }
+    }
+  for (a0_rev = a0_rev_first; a0_rev < a0_rev_last; a0_rev++)
+  {
+    a0_for = a0_rev -> sister;
+    if (a0_for->r_cap)
+    {
+      j = NEIGHBOR_NODE_REV(i, a0_for -> shift);
+      if (!j->is_sink && (a = j->parent))
+      {
+        /* checking the origin of j */
+        d = 0;
+        while ( 1 )
+        {
+          if (j->TS == TIME)
+          {
+            d += j -> DIST;
+            break;
+          }
+          a = j -> parent;
+          d ++;
+          if (a == TERMINAL)
+          {
+            j -> TS = TIME;
+            j -> DIST = 1;
+            break;
+          }
+          if (a == ORPHAN) {
+            d = INFINITE_D;
+            break;
+          }
+          if (IS_ODD(a))
+            j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+          else
+            j = NEIGHBOR_NODE(j, a -> shift);
+        }
+        if (d < INFINITE_D) /* j originates from the source - done */
+        {
+          if (d < d_min)
+          {
+            a0_min = MAKE_ODD(a0_for);
+            d_min = d;
+          }
+          /* set marks along the path */
+          for (j = NEIGHBOR_NODE_REV(i, a0_for->shift); j->TS != TIME; )
+          {
+            j -> TS = TIME;
+            j -> DIST = d --;
+            a = j->parent;
+            if (IS_ODD(a))
+              j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+            else
+              j = NEIGHBOR_NODE(j, a -> shift);
+          }
+        }
+      }
+    }
+  }
+
+  if (i->parent = a0_min)
+  {
+    i -> TS = TIME;
+    i -> DIST = d_min + 1;
+  }
+  else
+  {
+    /* no parent is found */
+    i -> TS = 0;
+
+    /* process neighbors */
+    for (a0_for = a0_for_first; a0_for < a0_for_last; a0_for++)
+    {
+      j = NEIGHBOR_NODE(i, a0_for -> shift);
+      if (!j->is_sink && (a = j->parent))
+      {
+        if (a0_for->r_rev_cap) set_active(j);
+        if (a != TERMINAL && a != ORPHAN && IS_ODD(a) && NEIGHBOR_NODE_REV(j, MAKE_EVEN(a)->shift) == i)
+        {
+          /* add j to the adoption list */
+          j -> parent = ORPHAN;
+          np = nodeptr_block -> New();
+          np -> ptr = j;
+          if (orphan_last) orphan_last -> next = np;
+          else             orphan_first        = np;
+          orphan_last = np;
+          np -> next = NULL;
+        }
+      }
+    }
+    for (a0_rev = a0_rev_first; a0_rev < a0_rev_last; a0_rev++)
+    {
+      a0_for = a0_rev -> sister;
+      j = NEIGHBOR_NODE_REV(i, a0_for -> shift);
+      if (!j->is_sink && (a = j->parent))
+      {
+        if (a0_for->r_cap) set_active(j);
+        if (a != TERMINAL && a != ORPHAN && !IS_ODD(a) && NEIGHBOR_NODE(j, a->shift) == i)
+        {
+          /* add j to the adoption list */
+          j -> parent = ORPHAN;
+          np = nodeptr_block -> New();
+          np -> ptr = j;
+          if (orphan_last) orphan_last -> next = np;
+          else             orphan_first        = np;
+          orphan_last = np;
+          np -> next = NULL;
+        }
+      }
+    }
+  }
+}
+
+void Graph::process_sink_orphan(node *i)
+{
+  node *j;
+  arc_forward *a0_for, *a0_for_first, *a0_for_last;
+  arc_reverse *a0_rev, *a0_rev_first, *a0_rev_last;
+  arc_forward *a0_min = NULL, *a;
+  nodeptr *np;
+  int d, d_min = INFINITE_D;
+
+  /* trying to find a new parent */
+  a0_for_first = i -> first_out;
+  if (IS_ODD(a0_for_first))
+  {
+    a0_for_first = (arc_forward *) (((char *)a0_for_first) + 1);
+    a0_for_last = (arc_forward *) ((a0_for_first ++) -> shift);
+  }
+  else a0_for_last = (i + 1) -> first_out;
+  a0_rev_first = i -> first_in;
+  if (IS_ODD(a0_rev_first))
+  {
+    a0_rev_first = (arc_reverse *) (((char *)a0_rev_first) + 1);
+    a0_rev_last  = (arc_reverse *) ((a0_rev_first ++) -> sister);
+  }
+  else a0_rev_last = (i + 1) -> first_in;
+
+
+  for (a0_for = a0_for_first; a0_for < a0_for_last; a0_for++)
+    if (a0_for->r_cap)
+    {
+      j = NEIGHBOR_NODE(i, a0_for -> shift);
+      if (j->is_sink && (a = j->parent))
+      {
+        /* checking the origin of j */
+        d = 0;
+        while ( 1 )
+        {
+          if (j->TS == TIME)
+          {
+            d += j -> DIST;
+            break;
+          }
+          a = j -> parent;
+          d ++;
+          if (a == TERMINAL)
+          {
+            j -> TS = TIME;
+            j -> DIST = 1;
+            break;
+          }
+          if (a == ORPHAN) {
+            d = INFINITE_D;
+            break;
+          }
+          if (IS_ODD(a))
+            j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+          else
+            j = NEIGHBOR_NODE(j, a -> shift);
+        }
+        if (d < INFINITE_D) /* j originates from the sink - done */
+        {
+          if (d < d_min)
+          {
+            a0_min = a0_for;
+            d_min = d;
+          }
+          /* set marks along the path */
+          for (j = NEIGHBOR_NODE(i, a0_for->shift); j->TS != TIME; )
+          {
+            j -> TS = TIME;
+            j -> DIST = d --;
+            a = j->parent;
+            if (IS_ODD(a))
+              j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+            else
+              j = NEIGHBOR_NODE(j, a -> shift);
+          }
+        }
+      }
+    }
+  for (a0_rev = a0_rev_first; a0_rev < a0_rev_last; a0_rev++)
+  {
+    a0_for = a0_rev -> sister;
+    if (a0_for->r_rev_cap)
+    {
+      j = NEIGHBOR_NODE_REV(i, a0_for -> shift);
+      if (j->is_sink && (a = j->parent))
+      {
+        /* checking the origin of j */
+        d = 0;
+        while ( 1 )
+        {
+          if (j->TS == TIME)
+          {
+            d += j -> DIST;
+            break;
+          }
+          a = j -> parent;
+          d ++;
+          if (a == TERMINAL)
+          {
+            j -> TS = TIME;
+            j -> DIST = 1;
+            break;
+          }
+          if (a == ORPHAN) {
+            d = INFINITE_D;
+            break;
+          }
+          if (IS_ODD(a))
+            j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+          else
+            j = NEIGHBOR_NODE(j, a -> shift);
+        }
+        if (d < INFINITE_D) /* j originates from the sink - done */
+        {
+          if (d < d_min)
+          {
+            a0_min = MAKE_ODD(a0_for);
+            d_min = d;
+          }
+          /* set marks along the path */
+          for (j = NEIGHBOR_NODE_REV(i, a0_for->shift); j->TS != TIME; )
+          {
+            j -> TS = TIME;
+            j -> DIST = d --;
+            a = j->parent;
+            if (IS_ODD(a))
+              j = NEIGHBOR_NODE_REV(j, MAKE_EVEN(a) -> shift);
+            else
+              j = NEIGHBOR_NODE(j, a -> shift);
+          }
+        }
+      }
+    }
+  }
+
+  if (i->parent = a0_min)
+  {
+    i -> TS = TIME;
+    i -> DIST = d_min + 1;
+  }
+  else
+  {
+    /* no parent is found */
+    i -> TS = 0;
+
+    /* process neighbors */
+    for (a0_for = a0_for_first; a0_for < a0_for_last; a0_for++)
+    {
+      j = NEIGHBOR_NODE(i, a0_for -> shift);
+      if (j->is_sink && (a = j->parent))
+      {
+        if (a0_for->r_cap) set_active(j);
+        if (a != TERMINAL && a != ORPHAN && IS_ODD(a) && NEIGHBOR_NODE_REV(j, MAKE_EVEN(a)->shift) == i)
+        {
+          /* add j to the adoption list */
+          j -> parent = ORPHAN;
+          np = nodeptr_block -> New();
+          np -> ptr = j;
+          if (orphan_last) orphan_last -> next = np;
+          else             orphan_first        = np;
+          orphan_last = np;
+          np -> next = NULL;
+        }
+      }
+    }
+    for (a0_rev = a0_rev_first; a0_rev < a0_rev_last; a0_rev++)
+    {
+      a0_for = a0_rev -> sister;
+      j = NEIGHBOR_NODE_REV(i, a0_for -> shift);
+      if (j->is_sink && (a = j->parent))
+      {
+        if (a0_for->r_rev_cap) set_active(j);
+        if (a != TERMINAL && a != ORPHAN && !IS_ODD(a) && NEIGHBOR_NODE(j, a->shift) == i)
+        {
+          /* add j to the adoption list */
+          j -> parent = ORPHAN;
+          np = nodeptr_block -> New();
+          np -> ptr = j;
+          if (orphan_last) orphan_last -> next = np;
+          else             orphan_first        = np;
+          orphan_last = np;
+          np -> next = NULL;
+        }
+      }
+    }
+  }
+}
+
+/***********************************************************************/
+
+Graph::flowtype Graph::maxflow()
+{
+  node *i, *j, *current_node = NULL, *s_start, *t_start;
+  captype *cap_middle, *rev_cap_middle;
+  arc_forward *a_for, *a_for_first, *a_for_last;
+  arc_reverse *a_rev, *a_rev_first, *a_rev_last;
+  nodeptr *np, *np_next;
+
+  prepare_graph();
+  maxflow_init();
+  nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
+
+  while ( 1 )
+  {
+    if (i = current_node)
+    {
+      i -> next = NULL; /* remove active flag */
+      if (!i->parent) i = NULL;
+    }
+    if (!i)
+    {
+      if (!(i = next_active())) break;
+    }
+
+    /* growth */
+    s_start = NULL;
+
+    a_for_first = i -> first_out;
+    if (IS_ODD(a_for_first))
+    {
+      a_for_first = (arc_forward *) (((char *)a_for_first) + 1);
+      a_for_last = (arc_forward *) ((a_for_first ++) -> shift);
+    }
+    else a_for_last = (i + 1) -> first_out;
+    a_rev_first = i -> first_in;
+    if (IS_ODD(a_rev_first))
+    {
+      a_rev_first = (arc_reverse *) (((char *)a_rev_first) + 1);
+      a_rev_last = (arc_reverse *) ((a_rev_first ++) -> sister);
+    }
+    else a_rev_last = (i + 1) -> first_in;
+
+    if (!i->is_sink)
+    {
+      /* grow source tree */
+      for (a_for = a_for_first; a_for < a_for_last; a_for++)
+        if (a_for->r_cap)
+        {
+          j = NEIGHBOR_NODE(i, a_for -> shift);
+          if (!j->parent)
+          {
+            j -> is_sink = 0;
+            j -> parent = MAKE_ODD(a_for);
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+            set_active(j);
+          }
+          else if (j->is_sink)
+          {
+            s_start = i;
+            t_start = j;
+            cap_middle     = & ( a_for -> r_cap );
+            rev_cap_middle = & ( a_for -> r_rev_cap );
+            break;
+          }
+          else if (j->TS <= i->TS &&
+                   j->DIST > i->DIST)
+          {
+            /* heuristic - trying to make the distance from j to the source shorter */
+            j -> parent = MAKE_ODD(a_for);
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+          }
+        }
+      if (!s_start)
+        for (a_rev = a_rev_first; a_rev < a_rev_last; a_rev++)
+        {
+          a_for = a_rev -> sister;
+          if (a_for->r_rev_cap)
+          {
+            j = NEIGHBOR_NODE_REV(i, a_for -> shift);
+            if (!j->parent)
+            {
+              j -> is_sink = 0;
+              j -> parent = a_for;
+              j -> TS = i -> TS;
+              j -> DIST = i -> DIST + 1;
+              set_active(j);
+            }
+            else if (j->is_sink)
+            {
+              s_start = i;
+              t_start = j;
+              cap_middle     = & ( a_for -> r_rev_cap );
+              rev_cap_middle = & ( a_for -> r_cap );
+              break;
+            }
+            else if (j->TS <= i->TS &&
+                     j->DIST > i->DIST)
+            {
+              /* heuristic - trying to make the distance from j to the source shorter */
+              j -> parent = a_for;
+              j -> TS = i -> TS;
+              j -> DIST = i -> DIST + 1;
+            }
+          }
+        }
+    }
+    else
+    {
+      /* grow sink tree */
+      for (a_for = a_for_first; a_for < a_for_last; a_for++)
+        if (a_for->r_rev_cap)
+        {
+          j = NEIGHBOR_NODE(i, a_for -> shift);
+          if (!j->parent)
+          {
+            j -> is_sink = 1;
+            j -> parent = MAKE_ODD(a_for);
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+            set_active(j);
+          }
+          else if (!j->is_sink)
+          {
+            s_start = j;
+            t_start = i;
+            cap_middle     = & ( a_for -> r_rev_cap );
+            rev_cap_middle = & ( a_for -> r_cap );
+            break;
+          }
+          else if (j->TS <= i->TS &&
+                   j->DIST > i->DIST)
+          {
+            /* heuristic - trying to make the distance from j to the sink shorter */
+            j -> parent = MAKE_ODD(a_for);
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+          }
+        }
+      for (a_rev = a_rev_first; a_rev < a_rev_last; a_rev++)
+      {
+        a_for = a_rev -> sister;
+        if (a_for->r_cap)
+        {
+          j = NEIGHBOR_NODE_REV(i, a_for -> shift);
+          if (!j->parent)
+          {
+            j -> is_sink = 1;
+            j -> parent = a_for;
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+            set_active(j);
+          }
+          else if (!j->is_sink)
+          {
+            s_start = j;
+            t_start = i;
+            cap_middle     = & ( a_for -> r_cap );
+            rev_cap_middle = & ( a_for -> r_rev_cap );
+            break;
+          }
+          else if (j->TS <= i->TS &&
+                   j->DIST > i->DIST)
+          {
+            /* heuristic - trying to make the distance from j to the sink shorter */
+            j -> parent = a_for;
+            j -> TS = i -> TS;
+            j -> DIST = i -> DIST + 1;
+          }
+        }
+      }
+    }
+
+    TIME ++;
+
+    if (s_start)
+    {
+      i -> next = i; /* set active flag */
+      current_node = i;
+
+      /* augmentation */
+      augment(s_start, t_start, cap_middle, rev_cap_middle);
+      /* augmentation end */
+
+      /* adoption */
+      while (np = orphan_first)
+      {
+        np_next = np -> next;
+        np -> next = NULL;
+
+        while (np = orphan_first)
+        {
+          orphan_first = np -> next;
+          i = np -> ptr;
+          nodeptr_block -> Delete(np);
+          if (!orphan_first) orphan_last = NULL;
+          if (i->is_sink) process_sink_orphan(i);
+          else            process_source_orphan(i);
+        }
+
+        orphan_first = np_next;
+      }
+      /* adoption end */
+    }
+    else current_node = NULL;
+  }
+
+  delete nodeptr_block;
+
+  return flow;
+}
+
+/***********************************************************************/
+
+Graph::termtype Graph::what_segment(node_id i)
+{
+  if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE;
+  return SINK;
+}
+

+ 147 - 0
mrf/mrfmin/mrf.cpp

@@ -0,0 +1,147 @@
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mrf.h"
+
+using namespace OBJREC;
+
+
+void MRF::initialize()
+{
+
+  m_initialized = 1;
+
+  if ( m_dataType == ARRAY )
+    setData(m_e->m_dataCost->m_costArray);
+  else  setData(m_e->m_dataCost->m_costFn);
+
+  if ( m_smoothType == FUNCTION )
+    setSmoothness(m_e->m_smoothCost->m_costFn);
+  else
+  {
+    if ( m_smoothType == ARRAY )
+    {
+      checkArray(m_e->m_smoothCost->m_V);
+      setSmoothness(m_e->m_smoothCost->m_V);
+    }
+    else
+    {
+      int smoothExp = m_e->m_smoothCost->m_smoothExp;
+      if ( smoothExp != 1 && smoothExp != 2)
+      {
+        fprintf(stderr, "Wrong exponent in setSmoothness()!\n");
+        exit(1);
+      }
+      setSmoothness(smoothExp, m_e->m_smoothCost->m_smoothMax, m_e->m_smoothCost->m_lambda);
+    }
+
+    if (m_e->m_smoothCost->m_varWeights )
+    {
+      if (!m_grid_graph)
+      {
+        fprintf(stderr, "Edge multiplier cannot be used with non-grid graphs\n");
+        exit(1);
+      }
+      setCues(m_e->m_smoothCost->m_hWeights, m_e->m_smoothCost->m_vWeights);
+    }
+
+  }
+
+  initializeAlg();
+}
+
+
+void MRF::commonInitialization(EnergyFunction *e)
+{
+  m_dataType    = e->m_dataCost->m_type;
+  m_smoothType  = e->m_smoothCost->m_type;
+  m_varWeights  = e->m_smoothCost->m_varWeights;
+  m_initialized = 0;
+  m_e = e;
+  m_allocateArrayForSmoothnessCostFn = true;
+}
+
+
+MRF::MRF(int width, int height, int nLabels, EnergyFunction *e)
+{
+  m_width       = width;
+  m_height      = height;
+  m_nLabels     = nLabels;
+  m_nPixels     = width * height;
+  m_grid_graph  = 1;
+  commonInitialization(e);
+}
+
+MRF::MRF(int nPixels, int nLabels, EnergyFunction *e)
+{
+  m_nLabels     = nLabels;
+  m_nPixels     = nPixels;
+  m_grid_graph  = 0;
+  commonInitialization(e);
+}
+
+char MRF::checkEnergy()
+{
+  if ( !m_initialized) {
+    fprintf(stderr, "Call initialize() first,exiting!");
+    exit(1);
+  }
+  return(2);
+}
+
+
+MRF::EnergyVal MRF::totalEnergy()
+{
+  if (!isValid()) {
+    fprintf(stderr, "totalEnergy() cannot be called for invalid energy!\n");
+    exit(1);
+  }
+  if (!m_initialized) {
+    fprintf(stderr, "Call initialize() first!\n");
+    exit(1);
+  }
+
+  return dataEnergy() + smoothnessEnergy();
+}
+
+
+void MRF::optimize(int nIterations, float& time)
+{
+  if (!isValid()) {
+    fprintf(stderr, "optimize() cannot be called for invalid energy!\n");
+    exit(1);
+  }
+  if (!m_initialized ) {
+    fprintf(stderr, "run initialize() first!\n");
+    exit(1);
+  }
+
+  // start timer
+  clock_t start = clock();
+
+
+  optimizeAlg(nIterations);
+
+  // stop timer
+  clock_t finish = clock();
+  time = (float) (((double)(finish - start)) / CLOCKS_PER_SEC);
+}
+
+
+void MRF::checkArray(CostVal *V)
+{
+
+  int i, j;
+
+  for (i = 0; i < m_nLabels; i++)
+    for (j = i; j < m_nLabels; j++)
+      if (V[i*m_nLabels + j] != V[j*m_nLabels + i])
+      {
+        fprintf(stderr, "Error in setSmoothness(): V is not symmetric!\n");
+        exit(1);
+      }
+
+
+}

+ 277 - 0
mrf/mrfmin/mrf.h

@@ -0,0 +1,277 @@
+/* Copyright Olga Veksler, Ramin Zabih, Vladimir Kolmogorov, and Daniel Scharstein
+ * Send any questions to schar@middlebury.edu
+ */
+
+#ifndef __MRF_H__
+#define __MRF_H__
+#include <stdio.h>
+
+namespace OBJREC {
+
+class EnergyFunction;
+
+class MRF
+{
+public:
+
+    // *********** CONSTRUCTORS/DESTRUCTOR
+    // Constructor. After you call this, you must call setData and setSmoothness            
+    // Use this constructor for 2D grid graphs of size width by height Standard 4-connected 
+    // neighborhood system is assumed. Labels are in the range 0,1,...nLabels - 1           
+    // Width is in  the range 0,1,...width-1 and height is in the range 0,1,...height-1     
+    // Input parameter eng specifies the data and smoothness parts of the energy
+    // For 2D grids, since 4 connected neighborhood structure is assumed, this 
+    // fully specifies the energy
+    MRF(int width, int height, int nLabels, EnergyFunction *eng);
+
+    // Use this constructor for a general neighborhood system. Pixels are in the range      
+    // 0,1,..nPixels-1, and labels are in the range 0,1,...,nLabels-1 
+    // Input parameter eng specifies the data and smoothness parts of the energy
+    // after this constructor you need to call setNeighbors() to specify the neighborhood system
+    MRF(int nPixels, int nLabels, EnergyFunction *eng);
+
+    virtual ~MRF() { }
+    
+    // Returns true if energy function has been specified, returns false otherwise
+    // By default, it always returns true. Can be modified by the supplier of
+    // optimization algorithm                                                      
+    virtual int isValid(){return true;};  
+    
+
+    // *********** EVALUATING THE ENERGY
+    typedef int Label;
+    typedef double EnergyVal;        /* The total energy of a labeling */
+    typedef double CostVal;          /* costs of individual terms of the energy */
+ 
+    EnergyVal totalEnergy();      /* returns energy of current labeling */
+    virtual EnergyVal dataEnergy() = 0;        /* returns the data part of the energy */
+    virtual EnergyVal smoothnessEnergy() = 0;  /* returns the smoothness part of the energy */
+
+    //Functional representation for data costs
+    typedef CostVal (*DataCostFn)(int pix, Label l); 
+
+    // Functional representation for the general cost function type 
+    typedef CostVal (*SmoothCostGeneralFn)(int pix1, int pix2,  Label l1, Label l2); 
+
+    // For general smoothness functions, some implementations try to cache all function values in an array
+    // for efficiency.  To prevent this, call the following function before calling initialize():
+    void dontCacheSmoothnessCosts() {m_allocateArrayForSmoothnessCostFn = false;}
+
+    // Use this function only for non-grid graphs. Sets pix1 and pix2 to be neighbors 
+    // with the specified weight.  Can be called ONLY once for each pair of pixels    
+    // That is if pixel1 and pixel2 are neihbors, call  either setNeighbors(pixel1,pixel2,weight) 
+    // or setNeighbors(pixel2,pixel1,weight), but NOT BOTH                                     
+    virtual void setNeighbors(int pix1, int pix2, CostVal weight)= 0;
+
+
+    void initialize();
+
+    // Runs optimization for nIterations. Input parameter time returns the time it took to
+    // perform nIterations of optimization
+    void optimize(int nIterations, float& time);
+    virtual void optimizeAlg(int nIterations)=0;
+
+    // *********** ACCESS TO SOLUTION
+    // Returns pointer to array of size nPixels. Client may then read/write solution (but not deallocate array).
+    virtual Label* getAnswerPtr()= 0;
+    // returns the label of the input pixel
+    virtual Label getLabel(int pixel)= 0;
+    // sets label of a pixel
+    virtual void setLabel(int pixel,Label label)= 0;
+    // sets all the labels to zero
+    virtual void clearAnswer()  = 0;
+
+    // use this function to pass any parameters to optimization algorithm. 
+    // The first argument is the number of passed, parameters  and
+    // the second argument is the pointer to the array of parameters
+    virtual void setParameters(int numParam, void *param) = 0;
+
+    // This function returns lower bound computed by the algorithm (if any)
+    // By default, it returns 0.
+    virtual double lowerBound(){return((double) 0);};
+    // Returns 0 if the energy is not suitable for current optimization algorithm 
+    // Returns 1 if the energy is suitable for current optimization algorithm
+    // Returns 2 if current optimizaiton algorithm does not check the energy 
+    virtual char checkEnergy();
+
+    typedef enum
+        {
+            FUNCTION,
+            ARRAY,
+            THREE_PARAM,
+            NONE
+        } InputType;
+
+
+protected:
+    int  m_width, m_height;  // width and height of a grid,if graph is a grid
+    int  m_nPixels;          // number of pixels, for both grid and non-grid graphs
+    int  m_nLabels;          // number of labels, for both grid and non-grid graphs
+    bool m_grid_graph;   // true if the graph is a 2D grid
+    bool m_varWeights;   // true if weights are spatially varying. To be used only with 2D grids
+    bool m_initialized;  // true if array m_V is allocated memory.  
+    EnergyFunction *m_e;
+    
+    InputType m_dataType;     
+    InputType m_smoothType;
+
+    // *********** SET THE DATA COSTS 
+    // Following 2 functions set the data costs
+    virtual void setData(DataCostFn dcost)=0; 
+    virtual void setData(CostVal* data)=0;   
+
+    // *********** SET THE SMOOTHNESS COSTS 
+    // following 3 functions set the smoothness costs 
+    // there are 2 ways to represent the smoothness costs, one with array, one with function
+    // In addition, for 2D grid graphs spacially varying weights can be specified by 2 arrays
+
+    // Smoothness cost depends on labels  V(l1,l2) for all edges (except for a multiplier - see setCues() ).
+    // V must be symmetric: V(l1,l2) = V(l2,l1)
+    // V must be an array of size nLabels*nLabels. It is NOT copied into internal memory
+    virtual void setSmoothness(CostVal* V)=0;
+    
+    // General smoothness cost can be specified by passing pointer to a function 
+    virtual  void setSmoothness(SmoothCostGeneralFn cost)=0;
+
+    // To prevent implementations from caching all general smoothness costs values, the flag below
+    // can be set to false by calling dontCacheSmoothnessCosts() before calling initialize():
+    bool m_allocateArrayForSmoothnessCostFn;
+
+    // Use if the smoothness is V(l1,l2) = lambda * min ( |l1-l2|^m_smoothExp, m_smoothMax )
+    // Can also add optional spatially varying weights for 2D grid graphs using setCues()
+    virtual void setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda)=0;
+
+    // You are not required to call setCues, in which case there is no multiplier.
+    // Function below cannot be called for general cost function.
+    // This function can be only used for a 2D grid graph
+    // hCue and vCue must be arrays of size width*height in row major order. 
+    // They are NOT copied into internal memory.
+    // hCue(x,y) holds the variable weight for edge between pixels (x+1,y) and (x,y)
+    // vCue(x,y) holds the variable weight for edge between pixels (x,y+1) and (x,y)
+    virtual void setCues(CostVal* hCue, CostVal* vCue)=0; 
+    
+    virtual void initializeAlg()=0; // called by initialize()
+
+    void commonInitialization(EnergyFunction *e);
+    void checkArray(CostVal *V);
+};
+
+// *********** This class is for data costs
+// Data costs can be specified eithe by an array or by a pointer to a function 
+// If specified by an array, use constructor DataCost(cost) where 
+// cost is the array of type CostVal. The cost of pixel p and label l is
+// stored at cost[p*nLabels+l] where nLabels is the number of labels
+// If data costs are to be specified by a function, pass
+// a pointer to a function 
+// CostVal costFn(int pix, Label lab)
+// which returns the
+// data cost of pixel pix to be assigned label lab
+
+
+class DataCost
+{
+friend class MRF;
+public:
+    typedef MRF::CostVal CostVal;
+    typedef MRF::DataCostFn DataCostFn;
+    DataCost(CostVal *cost){m_costArray = cost;m_type = MRF::ARRAY; };
+    DataCost(DataCostFn costFn){m_costFn = costFn;m_type = MRF::FUNCTION;};
+private:
+    MRF::CostVal *m_costArray;
+    MRF::DataCostFn m_costFn;
+    MRF::InputType m_type;     
+};
+
+// ***************** This class represents smoothness costs 
+// If the smoothness is V(l1,l2) = lambda * min ( |l1-l2|^m_smoothExp, m_smoothMax )
+// use constructor SmoothnessCost(smoothExp,smoothMax,lambda)
+// If, in addition,  there are spacially varying weights use constructor
+// SmoothnessCost(smoothExp,smoothMax,lambda,hWeights,vWeights)
+// hWeights and vWeights can be only used for a 2D grid graph
+// hWeights and vWeights must be arrays of size width*height in row major order. 
+// They are NOT copied into internal memory.
+// hWeights(x,y) holds the variable weight for edge between pixels (x+1,y) and (x,y)
+// vWeights(x,y) holds the variable weight for edge between pixels (x,y+1) and (x,y)
+//  If the smoothness costs are specified by input array V of type CostVal and
+// size nLabels*nLabels, use consructor SmoothnessCost(V). 
+// If in addition, there are 
+// are spacially varying weights use constructor SmoothnessCost(V,hWeights,vWeights)
+// Note that array V must be of size nLabels*nLabels, and be symmetric. 
+// That is V[i*nLabels+j] = V[j*nLabels+i]
+// Finally, if the smoothness term is specified by a general function, use
+// constructor SmoothnessCost(costFn)
+
+
+class SmoothnessCost
+{
+    friend class MRF;
+public:
+    typedef MRF::CostVal CostVal;
+    // Can be used for  2D grids and for general graphs
+    // In case if used for 2D grids, the smoothness term WILL NOT be spacially varying
+    SmoothnessCost(int smoothExp,CostVal smoothMax,CostVal lambda)
+        {m_type=MRF::THREE_PARAM;m_smoothMax = smoothMax;m_smoothExp = smoothExp;m_lambda=lambda;m_varWeights=false;};
+
+    // Can be used only for 2D grids 
+    // the smoothness term WILL BE be spacially varying
+    SmoothnessCost(int smoothExp,CostVal smoothMax,CostVal lambda,CostVal *hWeights, CostVal *vWeights)
+        {m_type=MRF::THREE_PARAM;m_smoothMax = smoothMax;m_smoothExp = smoothExp;m_lambda=lambda;
+        m_varWeights = true;m_hWeights = hWeights; m_vWeights = vWeights;};
+    
+    // Can be used 2D grids and for general graphs
+    // In case if used for 2D grids, the smoothness term WILL NOT be spacially varying
+    SmoothnessCost(CostVal *V){m_V = V;m_type = MRF::ARRAY;m_varWeights=false;};
+
+    // Can be used only for 2D grids 
+    // the smoothness term WILL BE be spacially varying
+    SmoothnessCost(CostVal *V,CostVal *hWeights, CostVal *vWeights )
+        {m_V = V;m_hWeights = hWeights; m_vWeights = vWeights; m_varWeights = true; m_type=MRF::ARRAY;};
+
+    // Can be used 2D grids and for general graphs
+    SmoothnessCost(MRF::SmoothCostGeneralFn costFn){m_costFn = costFn;m_type = MRF::FUNCTION;m_varWeights=false;};
+
+private:
+    CostVal *m_V,*m_hWeights, *m_vWeights;
+    MRF::SmoothCostGeneralFn m_costFn;
+    MRF::InputType m_type;
+    int m_smoothExp;
+    CostVal m_smoothMax,m_lambda;
+    bool m_varWeights;
+    EnergyFunction *m_eng;
+};
+
+
+class EnergyFunction
+{
+public:
+
+    EnergyFunction(DataCost *dataCost,SmoothnessCost *smoothCost)
+        {m_dataCost = dataCost;m_smoothCost = smoothCost;};
+    DataCost *m_dataCost;
+    SmoothnessCost *m_smoothCost;
+};
+
+}
+
+
+#endif /*  __MRF_H__ */
+
+/*
+    virtual EnergyVal dataEnergy() = 0;        
+    virtual EnergyVal smoothnessEnergy() = 0;  
+    virtual void setNeighbors(int pix1, int pix2, CostVal weight)= 0;
+    virtual void optimizeAlg(int nIterations)=0;
+    virtual Label* getAnswerPtr()= 0;
+    virtual Label getLabel(int pixel)= 0;
+    virtual void setLabel(int pixel,Label label)= 0;
+    virtual void clearAnswer()  = 0;
+    virtual void setParameters(int numParam, void *param) = 0;
+    virtual void setData(DataCostFn dcost)=0; 
+    virtual void setData(CostVal* data)=0;   
+    virtual void setSmoothness(CostVal* V)=0;
+    virtual void setSmoothness(SmoothCostGeneralFn cost)=0;
+    virtual void setCues(CostVal* hCue, CostVal* vCue)=0; 
+    virtual void setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda);
+    virtual EnergyVal lowerBound(){return((EnergyVal) 0);};
+*/
+

+ 439 - 0
mrf/mrfmin/progs/example.cpp

@@ -0,0 +1,439 @@
+//////////////////////////////////////////////////////////////////////////////
+// Example illustrating the use of GCoptimization.cpp
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Optimization problem:
+//  is a set of sites (pixels) of width 10 and hight 5. Thus number of pixels is 50
+//  grid neighborhood: each pixel has its left, right, up, and bottom pixels as neighbors
+//  7 labels
+//  Data costs: D(pixel,label) = 0 if pixel < 25 and label = 0
+//            : D(pixel,label) = 10 if pixel < 25 and label is not  0
+//            : D(pixel,label) = 0 if pixel >= 25 and label = 5
+//            : D(pixel,label) = 10 if pixel >= 25 and label is not  5
+// Smoothness costs: V(p1,p2,l1,l2) = min( (l1-l2)*(l1-l2) , 4 )
+// Below in the main program, we illustrate different ways of setting data and smoothness costs
+// that our interface allow and solve this optimizaiton problem
+
+// For most of the examples, we use no spatially varying pixel dependent terms.
+// For some examples, to demonstrate spatially varying terms we use
+// V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
+// w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#include "GCoptimization.h"
+
+using namespace OBJREC;
+
+
+struct ForDataFn {
+  int numLab;
+  Graph::captype *data;
+};
+
+
+Graph::captype smoothFn(int p1, int p2, int l1, int l2)
+{
+  if ( (l1 - l2)*(l1 - l2) <= 4 ) return((l1 -l2)*(l1 - l2));
+  else return(4);
+}
+
+Graph::captype dataFn(int p, int l, void *data)
+{
+  ForDataFn *myData = (ForDataFn *) data;
+  int numLab = myData->numLab;
+
+  return( myData->data[p*numLab+l] );
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// smoothness and data costs are set up one by one, individually
+// grid neighborhood structure is assumed
+//
+void GridGraph_Individually(int width, int height, int num_pixels, int num_labels)
+{
+
+  int *result = new int[num_pixels];   // stores result of optimization
+
+
+
+  try {
+    GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width, height, num_labels);
+
+    // first set up data costs individually
+    for ( int i = 0; i < num_pixels; i++ )
+      for (int l = 0; l < num_labels; l++ )
+        if (i < 25 ) {
+          if (  l == 0 ) gc->setDataCost(i, l, 0);
+          else gc->setDataCost(i, l, 10);
+        }
+        else {
+          if (  l == 5 ) gc->setDataCost(i, l, 0);
+          else gc->setDataCost(i, l, 10);
+        }
+
+    // next set up smoothness costs individually
+    for ( int l1 = 0; l1 < num_labels; l1++ )
+      for (int l2 = 0; l2 < num_labels; l2++ ) {
+        int cost = (l1 - l2) * (l1 - l2) <= 4  ? (l1 - l2) * (l1 - l2) : 4;
+        gc->setSmoothCost(l1, l2, cost);
+      }
+
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// in this version, set data and smoothness terms using arrays
+// grid neighborhood structure is assumed
+//
+void GridGraph_DArraySArray(int width, int height, int num_pixels, int num_labels)
+{
+
+  int *result = new int[num_pixels];   // stores result of optimization
+
+  // first set up the array for data costs
+  Graph::captype *data = new Graph::captype[num_pixels*num_labels];
+  for ( int i = 0; i < num_pixels; i++ )
+    for (int l = 0; l < num_labels; l++ )
+      if (i < 25 ) {
+        if (  l == 0 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+      else {
+        if (  l == 5 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+  // next set up the array for smooth costs
+  Graph::captype *smooth = new Graph::captype[num_labels*num_labels];
+  for ( int l1 = 0; l1 < num_labels; l1++ )
+    for (int l2 = 0; l2 < num_labels; l2++ )
+      smooth[l1+l2*num_labels] = (l1 - l2) * (l1 - l2) <= 4  ? (l1 - l2) * (l1 - l2) : 4;
+
+
+  try {
+    GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width, height, num_labels);
+    gc->setDataCost(data);
+    gc->setSmoothCost(smooth);
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+  delete [] smooth;
+  delete [] data;
+
+}
+////////////////////////////////////////////////////////////////////////////////
+// in this version, set data and smoothness terms using arrays
+// grid neighborhood structure is assumed
+//
+void GridGraph_DfnSfn(int width, int height, int num_pixels, int num_labels)
+{
+
+  int *result = new int[num_pixels];   // stores result of optimization
+
+  // first set up the array for data costs
+  Graph::captype *data = new Graph::captype[num_pixels*num_labels];
+  for ( int i = 0; i < num_pixels; i++ )
+    for (int l = 0; l < num_labels; l++ )
+      if (i < 25 ) {
+        if (  l == 0 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+      else {
+        if (  l == 5 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+
+
+  try {
+    GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width, height, num_labels);
+
+    // set up the needed data to pass to function for the data costs
+    ForDataFn toFn;
+    toFn.data = data;
+    toFn.numLab = num_labels;
+
+    gc->setDataCost(&dataFn, &toFn);
+
+    // smoothness comes from function pointer
+    gc->setSmoothCost(&smoothFn);
+
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+  delete [] data;
+
+}
+////////////////////////////////////////////////////////////////////////////////
+// Uses spatially varying smoothness terms. That is
+// V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
+// w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
+void GridGraph_DArraySArraySpatVarying(int width, int height, int num_pixels, int num_labels)
+{
+  int *result = new int[num_pixels];   // stores result of optimization
+
+  // first set up the array for data costs
+  Graph::captype *data = new Graph::captype[num_pixels*num_labels];
+  for ( int i = 0; i < num_pixels; i++ )
+    for (int l = 0; l < num_labels; l++ )
+      if (i < 25 ) {
+        if (  l == 0 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+      else {
+        if (  l == 5 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+  // next set up the array for smooth costs
+  Graph::captype *smooth = new Graph::captype[num_labels*num_labels];
+  for ( int l1 = 0; l1 < num_labels; l1++ )
+    for (int l2 = 0; l2 < num_labels; l2++ )
+      smooth[l1+l2*num_labels] = (l1 - l2) * (l1 - l2) <= 4  ? (l1 - l2) * (l1 - l2) : 4;
+
+  // next set up spatially varying arrays V and H
+
+  Graph::captype *V = new Graph::captype[num_pixels];
+  Graph::captype *H = new Graph::captype[num_pixels];
+
+
+  for ( int i = 0; i < num_pixels; i++ ) {
+    H[i] = i + (i + 1) % 3;
+    V[i] = i * (i + width) % 7;
+  }
+
+
+  try {
+    GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width, height, num_labels);
+    gc->setDataCost(data);
+    gc->setSmoothCostVH(smooth, V, H);
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+  delete [] smooth;
+  delete [] data;
+
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// in this version, set data and smoothness terms using arrays
+// grid neighborhood is set up "manually"
+//
+void GeneralGraph_DArraySArray(int width, int height, int num_pixels, int num_labels)
+{
+
+  int *result = new int[num_pixels];   // stores result of optimization
+
+  // first set up the array for data costs
+  Graph::captype *data = new Graph::captype[num_pixels*num_labels];
+  for ( int i = 0; i < num_pixels; i++ )
+    for (int l = 0; l < num_labels; l++ )
+      if (i < 25 ) {
+        if (  l == 0 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+      else {
+        if (  l == 5 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+  // next set up the array for smooth costs
+  Graph::captype *smooth = new Graph::captype[num_labels*num_labels];
+  for ( int l1 = 0; l1 < num_labels; l1++ )
+    for (int l2 = 0; l2 < num_labels; l2++ )
+      smooth[l1+l2*num_labels] = (l1 - l2) * (l1 - l2) <= 4  ? (l1 - l2) * (l1 - l2) : 4;
+
+
+  try {
+    GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels, num_labels);
+    gc->setDataCost(data);
+    gc->setSmoothCost(smooth);
+
+    // now set up a grid neighborhood system
+    // first set up horizontal neighbors
+    for (int y = 0; y < height; y++ )
+      for (int  x = 1; x < width; x++ )
+        gc->setNeighbors(x + y*width, x - 1 + y*width);
+
+    // next set up vertical neighbors
+    for (int y = 1; y < height; y++ )
+      for (int  x = 0; x < width; x++ )
+        gc->setNeighbors(x + y*width, x + (y - 1)*width);
+
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+  delete [] smooth;
+  delete [] data;
+
+}
+////////////////////////////////////////////////////////////////////////////////
+// in this version, set data and smoothness terms using arrays
+// grid neighborhood is set up "manually". Uses spatially varying terms. Namely
+// V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
+// w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
+
+void GeneralGraph_DArraySArraySpatVarying(int width, int height, int num_pixels, int num_labels)
+{
+  int *result = new int[num_pixels];   // stores result of optimization
+
+  // first set up the array for data costs
+  Graph::captype *data = new Graph::captype[num_pixels*num_labels];
+  for ( int i = 0; i < num_pixels; i++ )
+    for (int l = 0; l < num_labels; l++ )
+      if (i < 25 ) {
+        if (  l == 0 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+      else {
+        if (  l == 5 ) data[i*num_labels+l] = 0;
+        else data[i*num_labels+l] = 10;
+      }
+  // next set up the array for smooth costs
+  Graph::captype *smooth = new Graph::captype[num_labels*num_labels];
+  for ( int l1 = 0; l1 < num_labels; l1++ )
+    for (int l2 = 0; l2 < num_labels; l2++ )
+      smooth[l1+l2*num_labels] = (l1 - l2) * (l1 - l2) <= 4  ? (l1 - l2) * (l1 - l2) : 4;
+
+
+  try {
+    GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels, num_labels);
+    gc->setDataCost(data);
+    gc->setSmoothCost(smooth);
+
+    // now set up a grid neighborhood system
+    // first set up horizontal neighbors
+    for (int y = 0; y < height; y++ )
+      for (int  x = 1; x < width; x++ ) {
+        int p1 = x - 1 + y * width;
+        int p2 = x + y * width;
+        gc->setNeighbors(p1, p2, p1 + p2);
+      }
+
+    // next set up vertical neighbors
+    for (int y = 1; y < height; y++ )
+      for (int  x = 0; x < width; x++ ) {
+        int p1 = x + (y - 1) * width;
+        int p2 = x + y * width;
+        gc->setNeighbors(p1, p2, p1*p2);
+      }
+
+    printf("\nBefore optimization energy is %d", gc->compute_energy());
+    gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
+    printf("\nAfter optimization energy is %d", gc->compute_energy());
+
+    for ( int  i = 0; i < num_pixels; i++ )
+      result[i] = gc->whatLabel(i);
+
+    delete gc;
+  }
+  catch (GCException e) {
+    e.Report();
+  }
+
+  delete [] result;
+  delete [] smooth;
+  delete [] data;
+
+
+}
+////////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char **argv)
+{
+  int width = 10;
+  int height = 5;
+  int num_pixels = width * height;
+  int num_labels = 7;
+
+
+  // smoothness and data costs are set up one by one, individually
+  GridGraph_Individually(width, height, num_pixels, num_labels);
+
+  // smoothness and data costs are set up using arrays
+  GridGraph_DArraySArray(width, height, num_pixels, num_labels);
+
+  // smoothness and data costs are set up using functions
+  GridGraph_DfnSfn(width, height, num_pixels, num_labels);
+
+  // smoothness and data costs are set up using arrays.
+  // spatially varying terms are present
+  GridGraph_DArraySArraySpatVarying(width, height, num_pixels, num_labels);
+
+  //Will pretend our graph is
+  //general, and set up a neighborhood system
+  // which actually is a grid
+  GeneralGraph_DArraySArray(width, height, num_pixels, num_labels);
+
+  //Will pretend our graph is general, and set up a neighborhood system
+  // which actually is a grid. Also uses spatially varying terms
+  GeneralGraph_DArraySArraySpatVarying(width, height, num_pixels, num_labels);
+
+  printf("\n  Finished %d (%d) clock per sec %d", clock() / CLOCKS_PER_SEC, clock(), CLOCKS_PER_SEC);
+
+  return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+

+ 708 - 0
mrf/mrfmin/regions-maxprod.cpp

@@ -0,0 +1,708 @@
+// (C) 2002 Marshall Tappen, MIT AI Lab mtappen@mit.edu
+
+#include <limits>
+#include <stdio.h>
+#include "MaxProdBP.h"
+
+using namespace OBJREC;
+int numIterRun;
+// Some of the GBP code has been disabled here
+
+#define mexPrintf printf
+#define mexErrMsgTxt printf
+#define UP 0
+#define DOWN 1
+#define LEFT 2
+#define RIGHT 3
+
+
+OneNodeCluster::OneNodeCluster()
+{
+}
+
+int OneNodeCluster::numStates;
+
+namespace OBJREC {
+
+FLOATTYPE vec_min(FLOATTYPE *vec, int length)
+{
+
+  FLOATTYPE min = vec[0];
+  for (int i = 0; i < length; i++)
+    if (vec[i] < min)
+      min = vec[i];
+
+  return min;
+}
+
+FLOATTYPE vec_max(FLOATTYPE *vec, int length)
+{
+
+  FLOATTYPE max = vec[0];
+  for (int i = 0; i < length; i++)
+    if (vec[i] > max)
+      max = vec[i];
+
+  return max;
+}
+
+void getPsiMat(OneNodeCluster &/*cluster*/, FLOATTYPE *&destMatrix,
+               int r, int c, MaxProdBP *mrf, int direction, FLOATTYPE &var_weight)
+{
+  int mrfHeight = mrf->getHeight();
+  int mrfWidth = mrf->getWidth();
+  int numLabels = mrf->getNLabels();
+  int x = c;
+  int y = r;
+  int i;
+
+  FLOATTYPE *currMatrix = mrf->getScratchMatrix();
+  if (mrf->getSmoothType() != MRF::FUNCTION)
+  {
+    if (((direction == UP) && (r == 0)) ||
+        ((direction == DOWN) && (r == (mrfHeight - 1))) ||
+        ((direction == LEFT) && (c == 0)) ||
+        ((direction == RIGHT) && (c == (mrfWidth - 1))))
+    {
+      for ( i = 0; i < numLabels * numLabels; i++)
+      {
+        currMatrix[i] = 0;
+      }
+
+    }
+    else
+    {
+      MRF::CostVal weight_mod = 1;
+      if (mrf->varWeights())
+      {
+        if (direction == LEFT)
+          weight_mod = mrf->getHorizWeight(r, c - 1);
+        else if (direction == RIGHT)
+          weight_mod = mrf->getHorizWeight(r, c);
+        else if (direction == UP)
+          weight_mod = mrf->getVertWeight(r - 1, c);
+        else if (direction == DOWN)
+          weight_mod = mrf->getVertWeight(r, c);
+
+      }
+      for ( i = 0; i < numLabels*numLabels; i++)
+      {
+        if (weight_mod != 1)
+        {
+          currMatrix[i] = FLOATTYPE(mrf->m_V[i] * weight_mod);
+        }
+        else
+          currMatrix[i] = FLOATTYPE(mrf->m_V[i]);
+      }
+      destMatrix = currMatrix;
+      var_weight = (float)weight_mod;
+    }
+
+  }
+  else
+  {
+    if (((direction == UP) && (r == 0)) ||
+        ((direction == DOWN) && (r == (mrfHeight - 1))) ||
+        ((direction == LEFT) && (c == 0)) ||
+        ((direction == RIGHT) && (c == (mrfWidth - 1))))
+    {
+      for ( i = 0; i < numLabels * numLabels; i++)
+      {
+        currMatrix[i] = 0;
+      }
+    }
+    else
+    {
+      for ( i = 0; i < numLabels; i++)
+      {
+        for (int j = 0; j < numLabels; j++)
+        {
+          MRF::CostVal cCost;
+          if (direction == LEFT)
+            cCost = mrf->m_smoothFn(x + y * mrf->m_width,
+                                    x + y * mrf->m_width - 1 , j, i);
+
+          else if (direction == RIGHT)
+            cCost = mrf->m_smoothFn(x + y * mrf->m_width,
+                                    x + y * mrf->m_width + 1 , i, j);
+          else if (direction == UP)
+            cCost = mrf->m_smoothFn(x + y * mrf->m_width,
+                                    x + (y - 1) * mrf->m_width , j, i);
+          else if (direction == DOWN)
+            cCost = mrf->m_smoothFn(x + y * mrf->m_width,
+                                    x + (y + 1) * mrf->m_width , i, j);
+          else
+          {
+            cCost = mrf->m_smoothFn(x + y * mrf->m_width,
+                                    x + (y + 1) * mrf->m_width - 1 , j, i);
+            assert(0);
+          }
+
+          currMatrix[i*numLabels+j] = (float)cCost;
+        }
+      }
+    }
+  }
+  destMatrix = currMatrix;
+}
+
+
+void getVarWeight(OneNodeCluster &/*cluster*/,  int r, int c, MaxProdBP *mrf, int direction, FLOATTYPE &var_weight)
+{
+  MRF::CostVal weight_mod = 1;
+  if (mrf->varWeights())
+  {
+    if (direction == LEFT)
+      weight_mod = mrf->getHorizWeight(r, c - 1);
+    else if (direction == RIGHT)
+      weight_mod = mrf->getHorizWeight(r, c);
+    else if (direction == UP)
+      weight_mod = mrf->getVertWeight(r - 1, c);
+    else if (direction == DOWN)
+      weight_mod = mrf->getVertWeight(r, c);
+
+  }
+  var_weight = (FLOATTYPE) weight_mod;
+  //  printf("%d\n",weight_mod);
+}
+
+void initOneNodeMsgMem(OneNodeCluster *nodeArray, FLOATTYPE *memChunk,
+                       const int numNodes, const int msgChunkSize)
+{
+  FLOATTYPE *currPtr = memChunk;
+  OneNodeCluster *currNode = nodeArray;
+  FLOATTYPE *nextRoundChunk = new FLOATTYPE[nodeArray[1].numStates];
+  // MEMORY LEAK? where does this ever get deleted??
+  for (int i = 0; i < numNodes; i++)
+  {
+
+    currNode->receivedMsgs[0] = currPtr;
+    currPtr += msgChunkSize;
+    currNode->receivedMsgs[1] = currPtr;
+    currPtr += msgChunkSize;
+    currNode->receivedMsgs[2] = currPtr;
+    currPtr += msgChunkSize;
+    currNode->receivedMsgs[3] = currPtr;
+    currPtr += msgChunkSize;
+
+    currNode->nextRoundReceivedMsgs[0] = nextRoundChunk;
+    currNode->nextRoundReceivedMsgs[1] = nextRoundChunk;
+    currNode->nextRoundReceivedMsgs[2] = nextRoundChunk;
+    currNode->nextRoundReceivedMsgs[3] = nextRoundChunk;
+
+    currNode++;
+  }
+}
+
+inline void l1_dist_trans_comp(FLOATTYPE smoothMax, FLOATTYPE c, FLOATTYPE* tmpMsgDest, FLOATTYPE * msgProd, int numStates)
+{
+  int q;
+  for (int i = 0; i < numStates; i++)
+    tmpMsgDest[i] = msgProd[i];
+
+  for (q = 1; q <= numStates - 1; q++)
+  {
+    if (tmpMsgDest[q]  > tmpMsgDest[q-1] + c)
+      tmpMsgDest[q] = tmpMsgDest[q-1] + c;
+  }
+
+  for (q = numStates - 2; q >= 0; q--)
+  {
+    if (tmpMsgDest[q]  > tmpMsgDest[q+1] + c)
+      tmpMsgDest[q] = tmpMsgDest[q+1] + c;
+  }
+
+  FLOATTYPE minPotts = msgProd[0] + smoothMax;
+  for (q = 0; q <= numStates - 1; q++)
+  {
+    if ((msgProd[q] + smoothMax) < minPotts)
+      minPotts = msgProd[q] + smoothMax;
+  }
+  for (q = 0; q <= numStates - 1; q++)
+  {
+    if ((tmpMsgDest[q]) > minPotts)
+      tmpMsgDest[q] = minPotts;
+    tmpMsgDest[q] = -tmpMsgDest[q];
+  }
+  //   printf("%f %f %f\n",smoothMax,c,minPotts);
+}
+
+
+
+inline void l2_dist_trans_comp(FLOATTYPE smoothMax, FLOATTYPE c, FLOATTYPE* tmpMsgDest, FLOATTYPE * msgProd, int numStates)
+{
+
+
+  FLOATTYPE *z = new FLOATTYPE[numStates];
+  int       *v = new int[numStates];
+  int j = 0;
+  FLOATTYPE INFINITY = std::numeric_limits<float>::infinity();
+
+  z[0] = -1 * INFINITY;
+  z[1] = INFINITY;
+  v[0] = 0;
+  int q;
+  if (c == 0)
+  {
+    FLOATTYPE minVal = msgProd[0];
+
+    for (q = 0; q < numStates; q++)
+    {
+      if (msgProd[q] < minVal)
+        minVal = msgProd[q];
+    }
+    for (q = 0; q < numStates; q++)
+    {
+      tmpMsgDest[q] = -minVal;
+    }
+    delete [] z;
+    delete [] v;
+    return;
+  }
+
+  for (q = 1; q <= numStates - 1; q++)
+  {
+    FLOATTYPE s;
+    while (   (s = ((msgProd[q] + c * q * q) - (msgProd[v[j]] + c * v[j] * v[j])) /
+                   (2 * c * q - 2 * c * v[j])) <= z[j])
+    {
+      j -= 1;
+    }
+
+    j += 1;
+    v[j] = q;
+    z[j] = s;
+    z[j+1] = INFINITY;
+
+
+  }
+  j = 0;
+  FLOATTYPE minPotts = msgProd[0] + smoothMax;
+  for (q = 0; q <= numStates - 1; q++)
+  {
+    while (z[j+1] < q)
+    {
+      j += 1;
+    }
+    tmpMsgDest[q] = c * (q - v[j]) * (q - v[j]) + msgProd[v[j]];
+    if ((msgProd[q] + smoothMax) < minPotts)
+      minPotts = msgProd[q] + smoothMax;
+  }
+  for (q = 0; q <= numStates - 1; q++)
+  {
+    if ((tmpMsgDest[q]) > minPotts)
+      tmpMsgDest[q] = minPotts;
+    tmpMsgDest[q] = -tmpMsgDest[q];
+  }
+  delete [] z;
+  delete [] v;
+
+}
+
+}
+
+void OneNodeCluster::ComputeMsgRight(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf)
+{
+
+
+  FLOATTYPE *nodeLeftMsg = receivedMsgs[LEFT],
+                           *nodeDownMsg = receivedMsgs[DOWN],
+                                          *nodeUpMsg =    receivedMsgs[UP];
+
+  FLOATTYPE weight_mod;
+  getVarWeight(*this, r, c, mrf, RIGHT, weight_mod);
+
+  FLOATTYPE     *tmpMsgDest = msgDest;
+
+
+  if (mrf->m_type == MaxProdBP::L1 || mrf->m_type == MaxProdBP::L2)
+  {
+    FLOATTYPE *msgProd = new FLOATTYPE[numStates];
+    const FLOATTYPE lambda = (FLOATTYPE)mrf->m_lambda;
+    const FLOATTYPE smoothMax = (FLOATTYPE)mrf->m_smoothMax;
+    for (int leftNodeInd = 0; leftNodeInd < numStates; leftNodeInd++)
+    {
+      msgProd[leftNodeInd]  = -nodeLeftMsg[leftNodeInd] +
+                              -nodeUpMsg[leftNodeInd] +
+                              -nodeDownMsg[leftNodeInd] + localEv[leftNodeInd];
+    }
+    if (mrf->m_type == MaxProdBP::L1)
+    {
+      l1_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    }
+    else
+    {
+      l2_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    }
+    delete [] msgProd;
+  }
+  else if ((mrf->getSmoothType() == MRF::FUNCTION) || (mrf->getSmoothType() == MRF::ARRAY))
+  {
+    FLOATTYPE *psiMat, var_weight;
+
+    getPsiMat(*this, psiMat, r, c, mrf, RIGHT, var_weight);
+    FLOATTYPE *cmessage = msgDest;
+    for (int rightNodeInd = 0; rightNodeInd < numStates; rightNodeInd++)
+    {
+
+      *cmessage = 0;
+      for (int leftNodeInd = 0; leftNodeInd < numStates; leftNodeInd++)
+      {
+        FLOATTYPE tmp =  nodeLeftMsg[leftNodeInd] +
+                         nodeUpMsg[leftNodeInd] +
+                         nodeDownMsg[leftNodeInd]
+                         - localEv[leftNodeInd]
+                         - psiMat[leftNodeInd * numStates + rightNodeInd];
+
+        if ((tmp > *cmessage) || (leftNodeInd == 0))
+          *cmessage = tmp;
+
+      }
+      cmessage++;
+    }
+  }
+  else {
+    fprintf(stderr, "not implemented!\n");
+    exit(1);
+  }
+
+
+  FLOATTYPE max = msgDest[0];
+  for (int i = 0; i < numStates; i++)
+    msgDest[i] -= max;
+}
+
+
+// This means, "Compute the message to send left."
+
+void OneNodeCluster::ComputeMsgLeft(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf)
+{
+
+  FLOATTYPE *nodeRightMsg = receivedMsgs[RIGHT],
+                            *nodeDownMsg = receivedMsgs[DOWN],
+                                           *nodeUpMsg =    receivedMsgs[UP];
+
+
+  int do_dist = (int)(mrf->getSmoothType() == MRF::THREE_PARAM);
+  FLOATTYPE *tmpMsgDest = msgDest;
+  if (do_dist)
+  {
+    FLOATTYPE weight_mod;
+    getVarWeight(*this, r, c, mrf, LEFT, weight_mod);
+
+    FLOATTYPE *msgProd = new FLOATTYPE[numStates];
+
+    const FLOATTYPE lambda = (FLOATTYPE)mrf->m_lambda;
+
+    const FLOATTYPE smoothMax = (FLOATTYPE)mrf->m_smoothMax;
+
+    for (int rightNodeInd = 0; rightNodeInd < numStates; rightNodeInd++)
+    {
+      msgProd[rightNodeInd]  = -nodeRightMsg[rightNodeInd] +
+                               -nodeUpMsg[rightNodeInd] +
+                               -nodeDownMsg[rightNodeInd]
+                               + localEv[rightNodeInd] ;
+    }
+    if (mrf->m_smoothExp == 1)
+    {
+      l1_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    }
+    else
+      l2_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+
+    delete [] msgProd;
+  }
+  else if ((mrf->getSmoothType() == MRF::FUNCTION) || (mrf->getSmoothType() == MRF::ARRAY))
+  {
+    FLOATTYPE *psiMat, var_weight;
+
+    getPsiMat(*this, psiMat, r, c, mrf, LEFT, var_weight);
+
+    FLOATTYPE *cmessage = msgDest;
+
+    for (int leftNodeInd = 0; leftNodeInd < numStates; leftNodeInd++)
+    {
+
+      *cmessage = 0;
+      for (int rightNodeInd = 0; rightNodeInd < numStates; rightNodeInd++)
+      {
+        FLOATTYPE tmp =  nodeRightMsg[rightNodeInd] +
+                         nodeUpMsg[rightNodeInd] +
+                         nodeDownMsg[rightNodeInd]
+                         - localEv[rightNodeInd]
+                         - psiMat[leftNodeInd * numStates + rightNodeInd] ;
+
+        if ((tmp > *cmessage) || (rightNodeInd == 0))
+          *cmessage = tmp;
+
+      }
+      cmessage++;
+    }
+
+  }
+  else
+    assert(0);
+
+
+
+//   FLOATTYPE max = vec_max(msgDest,numStates);
+  FLOATTYPE max = msgDest[0];
+
+  for (int i = 0; i < numStates; i++)
+    msgDest[i] -= max;
+
+}
+
+void OneNodeCluster::ComputeMsgUp(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf)
+{
+  FLOATTYPE *nodeRightMsg = receivedMsgs[RIGHT],
+                            *nodeDownMsg = receivedMsgs[DOWN],
+                                           *nodeLeftMsg =    receivedMsgs[LEFT];
+
+
+
+
+  int do_dist = (int)(mrf->getSmoothType() == MRF::THREE_PARAM);
+  if (do_dist)
+  {
+    FLOATTYPE weight_mod;
+    getVarWeight(*this, r, c, mrf, UP, weight_mod);
+
+    FLOATTYPE *tmpMsgDest = msgDest;
+    FLOATTYPE *msgProd = new FLOATTYPE[numStates];
+
+    const FLOATTYPE lambda = (FLOATTYPE)mrf->m_lambda;
+
+    const FLOATTYPE smoothMax = (FLOATTYPE)mrf->m_smoothMax;
+
+    for (int downNodeInd = 0; downNodeInd < numStates; downNodeInd++)
+    {
+      msgProd[downNodeInd]  = -nodeRightMsg[downNodeInd] +
+                              -nodeLeftMsg[downNodeInd] +
+                              -nodeDownMsg[downNodeInd] +
+                              + localEv[downNodeInd] ;
+    }
+    //       printf("%f %f %f %f\n",nodeLeftMsg[leftNodeInd] ,
+    //       nodeUpMsg[leftNodeInd] ,
+    //       nodeDownMsg[leftNodeInd] ,localEv[leftNodeInd]);
+    if (mrf->m_smoothExp == 1)
+    {
+      l1_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    }
+    else
+      l2_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    delete [] msgProd;
+  }
+  else if ((mrf->getSmoothType() == MRF::FUNCTION) || (mrf->getSmoothType() == MRF::ARRAY))
+  {
+    FLOATTYPE *psiMat, var_weight;
+
+    getPsiMat(*this, psiMat, r, c, mrf, UP, var_weight);
+
+    FLOATTYPE *cmessage = msgDest;
+
+    for (int upNodeInd = 0; upNodeInd < numStates; upNodeInd++)
+    {
+
+      *cmessage = 0;
+      for (int downNodeInd = 0; downNodeInd < numStates; downNodeInd++)
+      {
+        FLOATTYPE tmp = nodeRightMsg[downNodeInd] +
+                        nodeLeftMsg[downNodeInd] +
+                        nodeDownMsg[downNodeInd] +
+                        -localEv[downNodeInd]
+                        - psiMat[upNodeInd * numStates + downNodeInd] ;
+
+        if ((tmp > *cmessage) || (downNodeInd == 0))
+          *cmessage = tmp;
+
+
+      }
+      cmessage++;
+    }
+  }
+  else
+    assert(0);
+  FLOATTYPE max = msgDest[0];
+  //  FLOATTYPE max = vec_max(msgDest,numStates);
+  for (int i = 0; i < numStates; i++)
+    msgDest[i]  -= max;
+}
+
+void OneNodeCluster::ComputeMsgDown(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf)
+{
+
+  FLOATTYPE *nodeRightMsg = receivedMsgs[RIGHT],
+                            *nodeUpMsg = receivedMsgs[UP],
+                                         *nodeLeftMsg =    receivedMsgs[LEFT];
+
+  int do_dist = (int)(mrf->getSmoothType() == MRF::THREE_PARAM);
+  if (do_dist)
+  {
+
+    FLOATTYPE weight_mod;
+    getVarWeight(*this, r, c, mrf, DOWN, weight_mod);
+
+    FLOATTYPE *tmpMsgDest = msgDest;
+    FLOATTYPE *msgProd = new FLOATTYPE[numStates];
+
+    const FLOATTYPE lambda = (FLOATTYPE)mrf->m_lambda;
+
+    const FLOATTYPE smoothMax = (FLOATTYPE)mrf->m_smoothMax;
+
+    for (int upNodeInd = 0; upNodeInd < numStates; upNodeInd++)
+    {
+      msgProd[upNodeInd]  = -nodeRightMsg[upNodeInd] +
+                            -nodeLeftMsg[upNodeInd] +
+                            -nodeUpMsg[upNodeInd] +
+                            + localEv[upNodeInd] ;
+    }
+
+    if (mrf->m_smoothExp == 1)
+    {
+      l1_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    }
+    else
+      l2_dist_trans_comp( weight_mod*smoothMax*lambda, lambda*weight_mod, tmpMsgDest, msgProd, numStates);
+    delete [] msgProd;
+
+  }
+  else if ((mrf->getSmoothType() == MRF::FUNCTION) || (mrf->getSmoothType() == MRF::ARRAY))
+  {
+    FLOATTYPE *psiMat, var_weight;
+
+    getPsiMat(*this, psiMat, r, c, mrf, DOWN, var_weight);
+
+    FLOATTYPE *cmessage = msgDest;
+
+    for (int downNodeInd = 0; downNodeInd < numStates; downNodeInd++)
+    {
+
+      *cmessage = 0;
+      for (int upNodeInd = 0; upNodeInd < numStates; upNodeInd++)
+      {
+        FLOATTYPE tmp =  nodeRightMsg[upNodeInd] +
+                         nodeLeftMsg[upNodeInd] +
+                         nodeUpMsg[upNodeInd] +
+                         -localEv[upNodeInd]
+                         - psiMat[upNodeInd * numStates + downNodeInd] ;
+
+        if ((tmp > *cmessage) || (upNodeInd == 0))
+          *cmessage = tmp;
+
+      }
+      cmessage++;
+    }
+
+  }
+  else
+    assert(0);
+
+  FLOATTYPE max = msgDest[0];
+  //  FLOATTYPE max = vec_max(msgDest,numStates);
+  for (int i = 0; i < numStates; i++)
+    msgDest[i] -= max;
+
+
+}
+
+
+
+
+
+void OneNodeCluster::getBelief(FLOATTYPE *beliefVec)
+{
+  for (int i = 0; i < numStates; i++)
+  {
+    beliefVec[i] = receivedMsgs[UP][i] + receivedMsgs[DOWN][i] +
+                   receivedMsgs[LEFT][i] + receivedMsgs[RIGHT][i] - localEv[i];
+  }
+
+}
+
+int OneNodeCluster::getBeliefMaxInd()
+{
+  FLOATTYPE currBelief, bestBelief;
+  int bestInd = 0;
+  {
+    int i = 0;
+    bestBelief = receivedMsgs[UP][i] + receivedMsgs[DOWN][i] +
+                 receivedMsgs[LEFT][i] + receivedMsgs[RIGHT][i] - localEv[i];
+  }
+  for (int i = 1; i < numStates; i++)
+  {
+    currBelief = receivedMsgs[UP][i] + receivedMsgs[DOWN][i] +
+                 receivedMsgs[LEFT][i] + receivedMsgs[RIGHT][i] - localEv[i];
+    if (currBelief > bestBelief)
+    {
+      bestInd = i;
+      bestBelief = currBelief;
+    }
+
+  }
+  return bestInd;
+
+}
+
+
+namespace OBJREC {
+
+void computeMessagesLeftRight(OneNodeCluster *nodeArray, const int numCols, const int /*numRows*/, const int currRow, const FLOATTYPE alpha, MaxProdBP *mrf)
+{
+  const int numStates = OneNodeCluster::numStates;
+  const FLOATTYPE omalpha = 1.0f - alpha;
+  int i;
+  int col;
+  for ( col = 0; col < numCols - 1; col++)
+  {
+    nodeArray[currRow * numCols + col].ComputeMsgRight(nodeArray[currRow * numCols + col+1].nextRoundReceivedMsgs[LEFT], currRow, col, mrf);
+    for (i = 0; i < numStates; i++)
+    {
+      nodeArray[currRow * numCols + col+1].receivedMsgs[LEFT][i] =
+        omalpha * nodeArray[currRow * numCols + col+1].receivedMsgs[LEFT][i] +
+        alpha * nodeArray[currRow * numCols + col+1].nextRoundReceivedMsgs[LEFT][i];
+    }
+  }
+  for ( col = numCols - 1; col > 0; col--)
+  {
+    nodeArray[currRow * numCols + col].ComputeMsgLeft(nodeArray[currRow * numCols + col-1].nextRoundReceivedMsgs[RIGHT], currRow, col, mrf);
+    for (i = 0; i < numStates; i++)
+    {
+      nodeArray[currRow * numCols + col-1].receivedMsgs[RIGHT][i] =
+        omalpha * nodeArray[currRow * numCols + col-1].receivedMsgs[RIGHT][i] +
+        alpha * nodeArray[currRow * numCols + col-1].nextRoundReceivedMsgs[RIGHT][i];
+    }
+  }
+
+}
+
+void computeMessagesUpDown(OneNodeCluster *nodeArray, const int numCols, const int numRows, const int currCol, const FLOATTYPE alpha, MaxProdBP *mrf)
+{
+  const int numStates = OneNodeCluster::numStates;
+  const FLOATTYPE omalpha = 1.0f - alpha;
+  int i;
+  int row;
+  for (row = 0; row < numRows - 1; row++)
+  {
+    nodeArray[row * numCols + currCol].ComputeMsgDown(nodeArray[(row+1) * numCols + currCol].nextRoundReceivedMsgs[UP], row, currCol, mrf);
+    for (i = 0; i < numStates; i++)
+    {
+      nodeArray[(row+1) * numCols + currCol].receivedMsgs[UP][i] =
+        omalpha * nodeArray[(row+1) * numCols + currCol].receivedMsgs[UP][i] +
+        alpha * nodeArray[(row+1) * numCols + currCol].nextRoundReceivedMsgs[UP][i];
+    }
+  }
+  for ( row = numRows - 1; row > 0; row--)
+  {
+    nodeArray[row * numCols + currCol].ComputeMsgUp(nodeArray[(row-1) * numCols + currCol].nextRoundReceivedMsgs[DOWN], row, currCol, mrf);
+    for (i = 0; i < numStates; i++)
+    {
+      nodeArray[(row-1) * numCols + currCol].receivedMsgs[DOWN][i] =
+        omalpha * nodeArray[(row-1) * numCols + currCol].receivedMsgs[DOWN][i] +
+        alpha * nodeArray[(row-1) * numCols + currCol].nextRoundReceivedMsgs[DOWN][i];
+    }
+  }
+
+}
+
+}

+ 62 - 0
mrf/mrfmin/regions-new.h

@@ -0,0 +1,62 @@
+// (C) 2002 Marshall Tappen, MIT AI Lab
+
+#ifndef _reg_h
+#define _reg_h
+
+#define FLOATTYPE float
+#define UP 0
+#define DOWN 1
+#define LEFT 2
+#define RIGHT 3
+#include "MaxProdBP.h"
+
+
+namespace OBJREC {
+
+class MaxProdBP;
+class OneNodeCluster
+{
+public:
+  OneNodeCluster();
+  
+  //static const int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3;
+  static int numStates;
+  
+  FLOATTYPE   *receivedMsgs[4],
+              *nextRoundReceivedMsgs[4],
+              *localEv;
+
+
+//   FLOATTYPE *psi[4];
+  void ComputeMsgRight(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf);
+  void ComputeMsgUp(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf);
+
+  void ComputeMsgLeft(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf);
+
+  void ComputeMsgDown(FLOATTYPE *msgDest, int r, int c, MaxProdBP *mrf);
+
+  void getBelief(FLOATTYPE *beliefVec);
+  int getBeliefMaxInd();
+  
+  int msgChange(FLOATTYPE thresh);
+
+  void deliverMsgs();
+    
+};
+
+void initOneNodeMsgMem(OneNodeCluster *nodeArray, FLOATTYPE *memChunk, const int numNodes, 
+                       const int msgChunkSize);
+
+void computeMessagesUpDown(OneNodeCluster *nodeArray, const int numCols, const int numRows,
+                           const int currCol, const FLOATTYPE alpha, MaxProdBP *mrf);
+void computeMessagesLeftRight(OneNodeCluster *nodeArray, const int numCols, const int numRows,
+                              const int currRow, const FLOATTYPE alpha, MaxProdBP *mrf);
+
+void computeOneNodeMessagesPeriodic(OneNodeCluster *nodeTopArray, OneNodeCluster *nodeBotArray,
+                                    const int numCols, const FLOATTYPE alpha);
+
+
+
+} // namespace
+
+#endif

+ 36 - 0
mrf/mrfmin/typeTruncatedQuadratic2D.h

@@ -0,0 +1,36 @@
+#ifndef __AJALSOQJAJSDFASD_H__
+#define __AJALSOQJAJSDFASD_H__
+
+#include <stdio.h>
+
+// This file is a stub, to make TRWS compile.
+
+namespace OBJREC
+{
+
+struct TypeTruncatedQuadratic2D
+{
+  typedef double REAL;
+
+  struct Edge
+  {
+    void DistanceTransformL2(int /*K*/, int /*stride*/, REAL /*alpha*/, REAL* /*source*/, REAL* /*dest*/,
+                             int* /*parabolas*/, int* /*intersections*/)
+    {
+      printf("\n\
++-------------------------------------------------------------+\n\
+|   In order to run TRW-S with truncted L2 terms,             |\n\
+|   you need to download the implementation from              |\n\
+|      http://www.adastral.ucl.ac.uk/~vnk/papers/TRW-S.html   |\n\
+|   and copy file  typeTruncatedQuadratic2D.h                 |\n\
+|   to the main directory (i.e. replace the existing file)    |\n\
++-------------------------------------------------------------+\n\
+   ");
+      exit(1);
+    }
+  };
+};
+
+}
+
+#endif