template <class T> void MRFEnergy<T>::AddRandomMessages(unsigned int random_seed, REAL min_value, REAL max_value)
{
	Node* i;
	MRFEdge* e;
	int k;

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	srand(random_seed);

	for (i=m_nodeFirst; i; i=i->m_next)
	{
		for (e=i->m_firstForward; e; e=e->m_nextForward)
		{
			Vector* M = e->m_message.GetMessagePtr();
			for (k=0; k<M->GetArraySize(m_Kglobal, i->m_K); k++)
			{
				REAL x = (REAL)( min_value + rand()/((double)RAND_MAX) * (max_value - min_value) );
				x += M->GetArrayValue(m_Kglobal, i->m_K, k);
				M->SetArrayValue(m_Kglobal, i->m_K, k, x);
			}
		}
	}
}
template <class T> void MRFEnergy<T>::ZeroMessages()
{
	Node* i;
	MRFEdge* e;

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	for (i=m_nodeFirst; i; i=i->m_next)
	{
		for (e=i->m_firstForward; e; e=e->m_nextForward)
		{
			e->m_message.GetMessagePtr()->SetZero(m_Kglobal, i->m_K);
		}
	}
}
Exemple #3
0
template <class T> void MRFEnergy<T>::SetMonotonicTrees()
{
	Node* i;
	MRFEdge* e;

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	for (i=m_nodeFirst; i; i=i->m_next)
	{
		REAL mu;

		int nForward = 0, nBackward = 0;
		for (e=i->m_firstForward; e; e=e->m_nextForward)
		{
			nForward ++;
		}
		for (e=i->m_firstBackward; e; e=e->m_nextBackward)
		{
			nBackward ++;
		}
		int ni = (nForward > nBackward) ? nForward : nBackward;

		mu = (REAL)1 / ni;
		for (e=i->m_firstBackward; e; e=e->m_nextBackward)
		{
			e->m_gammaBackward = mu;
		}
		for (e=i->m_firstForward; e; e=e->m_nextForward)
		{
			e->m_gammaForward = mu;
		}
	}
}
Exemple #4
0
template <class T> int MRFEnergy<T>::Minimize_TRW_S(Options& options, std::vector<REAL> &lowerBound_arr, std::vector<REAL> &energy_arr, std::vector<clock_t> &time_arr, REAL* min_marginals)
{
	Node* i;
	Node* j;
	MRFEdge* e;
	REAL vMin;
	int iter;
	REAL lowerBoundPrev;
	clock_t tStart = clock();

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	printf("TRW_S algorithm\n");

	SetMonotonicTrees();

	Vector* Di = (Vector*) m_buf;
	void* buf = (void*) (m_buf + m_vectorMaxSizeInBytes);

	iter = 0;
	bool lastIter = false;

	// main loop
	for (iter=1; ; iter++)
	{
		if (iter >= options.m_iterMax) lastIter = true;

		////////////////////////////////////////////////
		//                forward pass                //
		////////////////////////////////////////////////
		REAL* min_marginals_ptr = min_marginals;

		for (i=m_nodeFirst; i; i=i->m_next)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// normalize Di, update lower bound
			// vMin = Di->ComputeAndSubtractMin(m_Kglobal, i->m_K); // do not compute lower bound
			// lowerBound += vMin;                                  // during the forward pass

			// pass messages from i to nodes with higher m_ordering
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				assert(e->m_tail == i);
				j = e->m_head;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, e->m_gammaForward, 0, buf);

				// lowerBound += vMin; // do not compute lower bound during the forward pass
			}

			if (lastIter && min_marginals)
			{
				min_marginals_ptr += Di->GetArraySize(m_Kglobal, i->m_K);
			}
		}

		////////////////////////////////////////////////
		//               backward pass                //
		////////////////////////////////////////////////
		REAL lowerBound = 0;

		for (i=m_nodeLast; i; i=i->m_prev)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// normalize Di, update lower bound
			vMin = Di->ComputeAndSubtractMin(m_Kglobal, i->m_K);
			lowerBound += vMin;

			// pass messages from i to nodes with smaller m_ordering
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				assert(e->m_head == i);
				j = e->m_tail;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, e->m_gammaBackward, 1, buf);

				lowerBound += vMin;
			}

			if (lastIter && min_marginals)
			{
				min_marginals_ptr -= Di->GetArraySize(m_Kglobal, i->m_K);
				for (int k=0; k<Di->GetArraySize(m_Kglobal, i->m_K); k++) 
				{
					min_marginals_ptr[k] = Di->GetArrayValue(m_Kglobal, i->m_K, k);
				}
			}
		}

		////////////////////////////////////////////////
		//          check stopping criterion          //
		////////////////////////////////////////////////


		// Add lower bound, energy and time to output array
		lowerBound_arr.push_back(lowerBound);
		energy_arr.push_back(ComputeSolutionAndEnergy());
		time_arr.push_back((clock() - tStart) * 1.0 / CLOCKS_PER_SEC);

		// print lower bound and energy, if necessary
		if (  lastIter || 
			( iter>=options.m_printMinIter && 
			(options.m_printIter<1 || iter%options.m_printIter==0) )
		)
		{
			REAL energy = ComputeSolutionAndEnergy();
			printf("iter %d: lower bound = %f, energy = %f\n", iter, lowerBound, energy);
		}

		if (lastIter) break;

		// check convergence of lower bound
		if (options.m_eps >= 0)
		{
			if (iter > 1 && lowerBound - lowerBoundPrev <= options.m_eps)
			{
				lastIter = true;
			}
			lowerBoundPrev = lowerBound;
		}
	}

	return iter;
}
Exemple #5
0
template <class T> int MRFEnergy<T>::Minimize_BP(Options& options, std::vector<REAL> &energy_arr, std::vector<clock_t> &time_arr, REAL* min_marginals)
{
	Node* i;
	Node* j;
	MRFEdge* e;
	REAL vMin;
	int iter;
	clock_t tStart = clock();

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	printf("BP algorithm\n");

	Vector* Di = (Vector*) m_buf;
	void* buf = (void*) (m_buf + m_vectorMaxSizeInBytes);

	iter = 0;
	bool lastIter = false;

	// main loop
	for (iter=1; ; iter++)
	{
		if (iter >= options.m_iterMax) lastIter = true;

		////////////////////////////////////////////////
		//                forward pass                //
		////////////////////////////////////////////////
		REAL* min_marginals_ptr = min_marginals;

		for (i=m_nodeFirst; i; i=i->m_next)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// pass messages from i to nodes with higher m_ordering
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				assert(i == e->m_tail);
				j = e->m_head;

				const REAL gamma = 1;

				e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 0, buf);
			}

			if (lastIter && min_marginals)
			{
				min_marginals_ptr += Di->GetArraySize(m_Kglobal, i->m_K);
			}
		}

		////////////////////////////////////////////////
		//               backward pass                //
		////////////////////////////////////////////////

		for (i=m_nodeLast; i; i=i->m_prev)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// pass messages from i to nodes with smaller m_ordering
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				assert(i == e->m_head);
				j = e->m_tail;

				const REAL gamma = 1;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 1, buf);
			}

			if (lastIter && min_marginals)
			{
				min_marginals_ptr -= Di->GetArraySize(m_Kglobal, i->m_K);
				for (int k=0; k<Di->GetArraySize(m_Kglobal, i->m_K); k++) 
				{
					min_marginals_ptr[k] = Di->GetArrayValue(m_Kglobal, i->m_K, k);
				}
			}
		}

		////////////////////////////////////////////////
		//          check stopping criterion          //
		////////////////////////////////////////////////

		// Add energy and time to output array
		energy_arr.push_back(ComputeSolutionAndEnergy());
		time_arr.push_back((clock() - tStart) * 1.0 / CLOCKS_PER_SEC);
		// print energy, if necessary
		if ( lastIter || 
			( iter>=options.m_printMinIter && 
			(options.m_printIter<1 || iter%options.m_printIter==0) )
		)
		{
			REAL energy = ComputeSolutionAndEnergy();
			printf("iter %d: energy = %f\n", iter, energy);
		}

		// if finishFlag==true terminate
		if (lastIter) break;
	}

	return iter;
}
template <class T> void MRFEnergy<T>::SetAutomaticOrdering()
{
	int dMin;
	Node* i;
	Node* iMin;
	Node* list;
	Node* listBoundary;
	MRFEdge* e;

	if (m_isEnergyConstructionCompleted)
	{
		m_errorFn("Error in SetAutomaticOrdering(): function cannot be called after graph construction is completed");
	}

	printf("Setting automatic ordering... ");

	list = m_nodeFirst;
	listBoundary = NULL;
	m_nodeFirst = m_nodeLast = NULL;
	for (i=list; i; i=i->m_next)
	{
		i->m_ordering = 2*m_nodeNum; // will contain remaining degree mod m_nodeNum (i.e. number of edges connecting to nodes in 'listBoundary' and 'list')
		                             // if i->m_ordering \in [2*m_nodeNum;  3*m_nodeNum) - not assigned yet, belongs to 'list'
		                             // if i->m_ordering \in [m_nodeNum;    2*m_nodeNum) - not assigned yet, belongs to 'listBoundary'
		                             // if i->m_ordering \in [0;            m_nodeNum  ) - assigned, belongs to 'm_nodeFirst'
		for (e=i->m_firstForward; e; e=e->m_nextForward)
		{
			i->m_ordering ++;
		}
		for (e=i->m_firstBackward; e; e=e->m_nextBackward)
		{
			i->m_ordering ++;
		}
	}

	while (list)
	{
		// find node with the smallest remaining degree in list
		dMin = m_nodeNum;
		for (i=list; i; i=i->m_next)
		{
			assert(i->m_ordering >= 2*m_nodeNum);
			if (dMin > i->m_ordering - 2*m_nodeNum)
			{
				dMin = i->m_ordering - 2*m_nodeNum;
				iMin = i;
			}
		}
		i = iMin;

		// remove i from list
		if (i->m_prev) i->m_prev->m_next = i->m_next;
		else           list              = i->m_next;
		if (i->m_next) i->m_next->m_prev = i->m_prev;

		// add i to listBoundary
		listBoundary = i;
		i->m_prev = NULL;
		i->m_next = NULL;
		i->m_ordering -= m_nodeNum;

		while (listBoundary)
		{
			// find node with the smallest remaining degree in listBoundary
			dMin = m_nodeNum;
			for (i=listBoundary; i; i=i->m_next)
			{
				assert(i->m_ordering >= m_nodeNum && i->m_ordering < 2*m_nodeNum);
				if (dMin > i->m_ordering - m_nodeNum)
				{
					dMin = i->m_ordering - m_nodeNum;
					iMin = i;
				}
			}
			i = iMin;

			// remove i from listBoundary
			if (i->m_prev) i->m_prev->m_next = i->m_next;
			else           listBoundary      = i->m_next;
			if (i->m_next) i->m_next->m_prev = i->m_prev;

			// add i to m_nodeFirst
			if (m_nodeLast)
			{
				m_nodeLast->m_next = i;
				i->m_ordering = m_nodeLast->m_ordering + 1;
			}
			else
			{
				m_nodeFirst = i;
				i->m_ordering = 0;
			}
			i->m_prev = m_nodeLast;
			m_nodeLast = i;
			i->m_next = NULL;

			// process neighbors of i=m_nodeLast: decrease their remaining degree,
			// put them into listBoundary (if they are in list)
			for (e=m_nodeLast->m_firstForward; e; e=e->m_nextForward)
			{
				assert(m_nodeLast == e->m_tail);
				i = e->m_head;
				if (i->m_ordering >= m_nodeNum)
				{
					i->m_ordering --; // decrease remaining degree of i
					if (i->m_ordering >= 2*m_nodeNum)
					{
						// remove i from list
						if (i->m_prev) i->m_prev->m_next = i->m_next;
						else           list              = i->m_next;
						if (i->m_next) i->m_next->m_prev = i->m_prev;

						// add i to listBoundary
						if (listBoundary) listBoundary->m_prev = i;
						i->m_prev = NULL;
						i->m_next = listBoundary;
						listBoundary = i;
						i->m_ordering -= m_nodeNum;
					}
				}
			}
			for (e=m_nodeLast->m_firstBackward; e; e=e->m_nextBackward)
			{
				assert(m_nodeLast == e->m_head);
				i = e->m_tail;
				if (i->m_ordering >= m_nodeNum)
				{
					i->m_ordering --; // decrease remaining degree of i
					if (i->m_ordering >= 2*m_nodeNum)
					{
						// remove i from list
						if (i->m_prev) i->m_prev->m_next = i->m_next;
						else           list              = i->m_next;
						if (i->m_next) i->m_next->m_prev = i->m_prev;

						// add i to listBoundary
						if (listBoundary) listBoundary->m_prev = i;
						i->m_prev = NULL;
						i->m_next = listBoundary;
						listBoundary = i;
						i->m_ordering -= m_nodeNum;
					}
				}
			}
		}
	}

	printf("done\n");

	CompleteGraphConstruction();
}
template <class T> int MRFEnergy<T>::Minimize_BP(Options& options, REAL& energy, REAL* min_marginals)
{
    Node* i;
    Node* j;
    MRFEdge* e;
    REAL vMin;
    int iter;

    if (!m_isEnergyConstructionCompleted)
    {
        CompleteGraphConstruction();
    }

    if (verbosityLevel >= 1)
        printf("BP algorithm\n");

    Vector* Di = (Vector*) m_buf;
    void* buf = (void*) (m_buf + m_vectorMaxSizeInBytes);

    iter = 0;
    bool lastIter = false;

    //init time measurements: Anton
    timePlot.resize(options.m_iterMax, -1);
    lbPlot.resize(options.m_iterMax, -1);
    ePlot.resize(options.m_iterMax, -1);
    clock_t tStart = clock();


    // main loop
    for (iter=1; ; iter++)
    {
        if (iter >= options.m_iterMax) lastIter = true;

        ////////////////////////////////////////////////
        //                forward pass                //
        ////////////////////////////////////////////////
        REAL* min_marginals_ptr = min_marginals;

        for (i=m_nodeFirst; i; i=i->m_next)
        {
            Di->Copy(m_Kglobal, i->m_K, &i->m_D);
            for (e=i->m_firstForward; e; e=e->m_nextForward)
            {
                Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
            }
            for (e=i->m_firstBackward; e; e=e->m_nextBackward)
            {
                Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
            }

            // pass messages from i to nodes with higher m_ordering
            for (e=i->m_firstForward; e; e=e->m_nextForward)
            {
                assert(i == e->m_tail);
                j = e->m_head;

                const REAL gamma = 1;

                e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 0, buf);
            }

            if (lastIter && min_marginals)
            {
                min_marginals_ptr += Di->GetArraySize(m_Kglobal, i->m_K);
            }
        }

        ////////////////////////////////////////////////
        //               backward pass                //
        ////////////////////////////////////////////////

        for (i=m_nodeLast; i; i=i->m_prev)
        {
            Di->Copy(m_Kglobal, i->m_K, &i->m_D);
            for (e=i->m_firstBackward; e; e=e->m_nextBackward)
            {
                Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
            }
            for (e=i->m_firstForward; e; e=e->m_nextForward)
            {
                Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
            }

            // pass messages from i to nodes with smaller m_ordering
            for (e=i->m_firstBackward; e; e=e->m_nextBackward)
            {
                assert(i == e->m_head);
                j = e->m_tail;

                const REAL gamma = 1;

                vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 1, buf);
            }

            if (lastIter && min_marginals)
            {
                min_marginals_ptr -= Di->GetArraySize(m_Kglobal, i->m_K);
                for (int k=0; k<Di->GetArraySize(m_Kglobal, i->m_K); k++)
                {
                    min_marginals_ptr[k] = Di->GetArrayValue(m_Kglobal, i->m_K, k);
                }
            }
        }

        ////////////////////////////////////////////////
        //          check stopping criterion          //
        ////////////////////////////////////////////////

        //update time measurements: Anton
        timePlot[iter - 1] = (double)(clock() - tStart) / CLOCKS_PER_SEC;
        lbPlot[iter - 1] = std::numeric_limits<double>::signaling_NaN();
        ePlot[iter - 1] = ComputeSolutionAndEnergy();

        // print energy, if necessary
        if ( lastIter ||
                ( iter>=options.m_printMinIter &&
                  (options.m_printIter<1 || iter%options.m_printIter==0) )
           )
        {
            //energy = ComputeSolutionAndEnergy();
            energy = ePlot[iter - 1]; //Anton
            if( (verbosityLevel == 2) || (lastIter && (verbosityLevel == 1)) )
                printf("iter %d: energy = %f\n", iter, energy);
        }

        // if finishFlag==true terminate
        if (lastIter) break;
    }

    return iter;
}
template <class T> int MRFEnergy<T>::Minimize_TRW_S(Options& options, REAL& lowerBound, REAL& energy)
{
	Node* i;
	Node* j;
	MRFEdge* e;
	REAL vMin;
	int iter;
	REAL lowerBoundPrev;

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	SetMonotonicTrees();

	Vector* Di = (Vector*) m_buf;
	void* buf = (void*) (m_buf + m_vectorMaxSizeInBytes);

	iter = 0;

	// main loop
	for (iter=1; ; iter++)
	{
		////////////////////////////////////////////////
		//                forward pass                //
		////////////////////////////////////////////////
		for (i=m_nodeFirst; i; i=i->m_next)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// normalize Di, update lower bound
			// vMin = Di->ComputeAndSubtractMin(m_Kglobal, i->m_K); // do not compute lower bound
			// lowerBound += vMin;                                  // during the forward pass

			// pass messages from i to nodes with higher m_ordering
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				assert(e->m_tail == i);
				j = e->m_head;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, e->m_gammaForward, 0, buf);

				// lowerBound += vMin; // do not compute lower bound during the forward pass
			}
		}

		////////////////////////////////////////////////
		//               backward pass                //
		////////////////////////////////////////////////
		lowerBound = 0;

		for (i=m_nodeLast; i; i=i->m_prev)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// normalize Di, update lower bound
			vMin = Di->ComputeAndSubtractMin(m_Kglobal, i->m_K);
			lowerBound += vMin;

			// pass messages from i to nodes with smaller m_ordering
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				assert(e->m_head == i);
				j = e->m_tail;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, e->m_gammaBackward, 1, buf);

				lowerBound += vMin;
			}
		}

		////////////////////////////////////////////////
		//          check stopping criterion          //
		////////////////////////////////////////////////
		bool finishFlag = false;
		if (iter >= options.m_iterMax)
			finishFlag = true;

		energy = ComputeSolutionAndEnergy();
		REAL rel_gap = (energy - lowerBound)/energy;
		
		if (options.m_printMinIter)
		{
			mexPrintf("iter: %d ", iter);

			if (std::isinf(energy))
				mexPrintf("lower bound: %g, inconsistent solution. \n", lowerBound);
			else
				mexPrintf("energy: %g lower bound: %g rel_gap: %g \n", energy, lowerBound, rel_gap);

			mexEvalString("drawnow");
		}

		if (rel_gap < options.m_relgapMax)
			finishFlag = true;

		// if finishFlag==true terminate
		if (finishFlag)
			break;
	}

	return iter;
}
template <class T> int MRFEnergy<T>::Minimize_BP(Options& options, REAL& energy)
{
	Node* i;
	Node* j;
	MRFEdge* e;
	REAL vMin;
	int iter;

	if (!m_isEnergyConstructionCompleted)
	{
		CompleteGraphConstruction();
	}

	Vector* Di = (Vector*) m_buf;
	void* buf = (void*) (m_buf + m_vectorMaxSizeInBytes);

	iter = 0;

	// main loop
	for (iter=1; ; iter++)
	{
		////////////////////////////////////////////////
		//                forward pass                //
		////////////////////////////////////////////////
		for (i=m_nodeFirst; i; i=i->m_next)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// pass messages from i to nodes with higher m_ordering
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				assert(i == e->m_tail);
				j = e->m_head;

				const REAL gamma = 1;

				e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 0, buf);
			}
		}

		////////////////////////////////////////////////
		//               backward pass                //
		////////////////////////////////////////////////

		for (i=m_nodeLast; i; i=i->m_prev)
		{
			Di->Copy(m_Kglobal, i->m_K, &i->m_D);
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}
			for (e=i->m_firstForward; e; e=e->m_nextForward)
			{
				Di->Add(m_Kglobal, i->m_K, e->m_message.GetMessagePtr());
			}

			// pass messages from i to nodes with smaller m_ordering
			for (e=i->m_firstBackward; e; e=e->m_nextBackward)
			{
				assert(i == e->m_head);
				j = e->m_tail;

				const REAL gamma = 1;

				vMin = e->m_message.UpdateMessage(m_Kglobal, i->m_K, j->m_K, Di, gamma, 1, buf);
			}
		}

		////////////////////////////////////////////////
		//          check stopping criterion          //
		////////////////////////////////////////////////
		bool finishFlag = false;
		if (iter >= options.m_iterMax)
		{
			finishFlag = true;
		}

		// if finishFlag==true terminate
		if (finishFlag)
		{
			break;
		}
	}

	return iter;
}