/*---------------------------------------------------------------
	FILE: CGraphPartitioner.h
	USE: See below.

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#ifndef CGRAPHPARTITIONER_H
#define CGRAPHPARTITIONER_H

#include <MRPT/UTILS/utils_defs.h>
#include <MRPT/UTILS/CDebugOutputCapable.h>
#include <MRPT/UTILS/CMatrix.h>

namespace UTILS
{
	/** Algorithms for finding the min-normalized-cut of a weighted undirected graph.
	 *    Two static methods are provided, one for bisection and the other for
	 *      iterative N-parts partition.
	 *  It is based on the Shi-Malik method, proposed for example in:<br><br>
	 *  <code>J. Shi and J. Malik, "Normalized Cuts and Image Segmentation,"IEEE Transactions on Pattern Analysis and Machine Intelligence, vol.22, no.8, pp. 888-905, Aug. 2000.</code><br>
	 *
	 */
	class CGraphPartitioner : public CDebugOutputCapable
	{
	public:
		/** Performs the spectral recursive partition into K-parts for a given graph.
		 *   The default threshold for the N-cut is 1, which correspond to a cut equal
		 *   of the geometric mean of self-associations of each pair of groups.
		 *
		 * \param in_A			 [IN] The weights matrix for the graph. It must be a square matrix, where element W<sub>ij</sub> is the "likelihood" between nodes "i" and "j", and typically W<sub>ii</sub> = 1.
		 * \param out_parts		 [OUT] An array of partitions, where each partition is represented as a vector of indexs for nodes.
		 * \param threshold_Ncut [IN] If it is desired to use other than the default threshold, it can be passed here.
		 * \param forceSimetry	 [IN] If set to true (default) the elements W<sub>ij</sub> and W<sub>ji</sub> are replaced by 0.5·(W<sub>ij</sub>+W<sub>ji</sub>). Set to false if matrix is known to be simetric.
		 * \param useSpectralBisection [IN] If set to true (default) a quick spectral bisection will be used. If set to false, a brute force, exact finding of the min-cut is performed.
		 * \param recursive [IN] Default=true, recursive algorithm for finding N partitions. Set to false to force 1 bisection as maximum.
		 *
		 * \sa CMatrix, SpectralBisection
		 *
		 * \exception Throws a std::logic_error if an invalid matrix is passed.
		 */
		static void  RecursiveSpectralPartition(
									  CMatrix					&in_A,
									  std::vector<vector_uint>	&out_parts,
									  float						threshold_Ncut = 1.0f,
									  bool						forceSimetry = true,
									  bool						useSpectralBisection = true,
									  bool						recursive = true);

		/** Performs the spectral bisection of a graph. This method always perform
		 *   the bisection, and a measure of the goodness for this cut is returned.
		 *
		 * \param in_A			[IN] The weights matrix for the graph. It must be a square matrix, where element W<sub>ij</sub> is the "likelihood" between nodes "i" and "j", and typically W<sub>ii</sub> = 1.
		 * \param out_part1		[OUT] The indexs of the nodes that fall into the first group.
		 * \param out_part2		[OUT] The indexs of the nodes that fall into the second group.
		 * \param out_cut_value	[OUT] The N-cut value for the proposed cut, in the range [0-2].
		 * \param forceSimetry	[IN] If set to true (default) the elements W<sub>ij</sub> and W<sub>ji</sub> are replaced by 0.5·(W<sub>ij</sub>+W<sub>ji</sub>). Set to false if matrix is known to be simetric.
		 *
		 * \sa CMatrix, RecursiveSpectralPartition
		 *
		 * \exception Throws a std::logic_error if an invalid matrix is passed.
		 */
		static void  SpectralBisection(
							CMatrix					&in_A,
							vector_uint				&out_part1,
							vector_uint				&out_part2,
							float					&out_cut_value,
							bool					forceSimetry = true );

		/** Performs an EXACT minimum n-Cut graph bisection, (Use CGraphPartitioner::SpectralBisection for a faster algorithm)
		 *
		 * \param in_A			[IN] The weights matrix for the graph. It must be a square matrix, where element W<sub>ij</sub> is the "likelihood" between nodes "i" and "j", and typically W<sub>ii</sub> = 1.
		 * \param out_part1		[OUT] The indexs of the nodes that fall into the first group.
		 * \param out_part2		[OUT] The indexs of the nodes that fall into the second group.
		 * \param out_cut_value	[OUT] The N-cut value for the proposed cut, in the range [0-2].
		 * \param forceSimetry	[IN] If set to true (default) the elements W<sub>ij</sub> and W<sub>ji</sub> are replaced by 0.5·(W<sub>ij</sub>+W<sub>ji</sub>). Set to false if matrix is known to be simetric.
		 *
		 * \sa CMatrix, RecursiveSpectralPartition
		 *
		 * \exception Throws a std::logic_error if an invalid matrix is passed.
		 */
		static void  exactBisection(
							CMatrix			&in_A,
							vector_uint		&out_part1,
							vector_uint		&out_part2,
							float			&out_cut_value,
							bool			forceSimetry = true );

		/** Returns the normaliced cut of a graph, given its adjacency matrix A and a bisection:
		  */
		static float  nCut(
							CMatrix			&in_A,
							vector_uint		&in_part1,
							vector_uint		&in_part2 );

	}; // End of class def.

} // End of namespace

#endif
