Eigen::MatrixXd localWeighting( const Eigen::MatrixXd &W, bool isFull, bool isSymmetric)
{
	int n = W.rows();
	double Ls = (W.count()-n)/2; //count number of edges of the graph

	Eigen::MatrixXd C = Eigen::MatrixXd::Zero(n,n);
	double Ws = 0.5*W.sum();

	Eigen::VectorXd D = W.colwise().sum();

	if (isFull)
	{
		if (isSymmetric)
		{
			computeC_symmetric_full(const_cast<Eigen::MatrixXd &>(W),C,D,n);
		}
		else
		{
			// this is a trick to ensure vectorizatoin and no cache misses! some tranpositions have to be made though
			const_cast<Eigen::MatrixXd &>(W).transposeInPlace();
			computeC_symmetric_full(const_cast<Eigen::MatrixXd &>(W),C,D,n);
			const_cast<Eigen::MatrixXd &>(W).transposeInPlace();
			C.transposeInPlace();
			// the original code use vertical access to rows, but is slower
			//compute_C_asymmetric_full(const_cast<Eigen::MatrixXd &>(W),C,D,n);
		}
	}
	else
	{
		if (isSymmetric)
		{
			computeC_symmetric_sparse(const_cast<Eigen::MatrixXd &>(W),C,D,n);
		}
		else
		{
			compute_C_asymmetric_sparse(const_cast<Eigen::MatrixXd &>(W),C,D,n);
		}
	}

	Eigen::MatrixXd G = ((Ls/Ws)*W).cwiseProduct(C);

	Eigen::VectorXd DG = G.colwise().sum();

	for (int i=0; i<n; i++)
	{
		G.row(i)/=DG(i);
	}
	
	return G;
}