namespace TSnap {

	/////////////////////////////////////////////////
	// Spectral graph properties
	void PlotEigValRank(const PUNGraph& Graph, const int& EigVals, const TStr& FNmPref, TStr DescStr) {
		TFltV EigValV;
		TSnap::GetEigVals(Graph, EigVals, EigValV);
		EigValV.Sort(false);
		if (DescStr.Empty()) { DescStr = FNmPref; }
		TGnuPlot::PlotValV(EigValV, "eigVal." + FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f",
			DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), EigValV[0].Val), "Rank", "Eigen value", gpsLog10XY, false, gpwLinesPoints);
	}

	void PlotEigValDistr(const PUNGraph& Graph, const int& EigVals, const TStr& FNmPref, TStr DescStr) {
		const int NBuckets = 50;
		TFltV EigValV;
		for (int f = 1; EigValV.Empty() && f < 4; f++) {
			TSnap::GetEigVals(Graph, f*EigVals, EigValV);
		}
		EigValV.Sort(true);
		THash<TFlt, TFlt> BucketCntH;
		double Step = (EigValV.Last() - EigValV[0]) / double(NBuckets - 1);
		for (int i = 0; i < NBuckets; i++) {
			BucketCntH.AddDat(EigValV[0] + Step*(i + 0.5), 0);
		}
		for (int i = 0; i < EigValV.Len(); i++) {
			const int Bucket = (int)floor((EigValV[i] - EigValV[0]) / Step);
			BucketCntH[Bucket] += 1;
		}
		TFltPrV EigCntV;
		BucketCntH.GetKeyDatPrV(EigCntV);
		if (DescStr.Empty()) { DescStr = FNmPref; }
		TGnuPlot::PlotValV(EigCntV, "eigDistr." + FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f", DescStr.CStr(),
			Graph->GetNodes(), Graph->GetEdges(), EigValV.Last().Val), "Eigen value", "Count", gpsAuto, false, gpwLinesPoints);
	}

	// Inverse participation ratio: normalize EigVec to have L2=1 and then I=sum_k EigVec[i]^4
	// see Spectra of "real-world" graphs: Beyond the semicircle law by Farkas, Derenyi, Barabasi and Vicsek
	void PlotInvParticipRat(const PUNGraph& Graph, const int& MaxEigVecs, const int& TimeLimit, const TStr& FNmPref, TStr DescStr) {
		TFltPrV EigIprV;
		GetInvParticipRat(Graph, MaxEigVecs, TimeLimit, EigIprV);
		if (DescStr.Empty()) { DescStr = FNmPref; }
		if (EigIprV.Empty()) { DescStr += ". FAIL"; EigIprV.Add(TFltPr(-1, -1)); return; }
		TGnuPlot::PlotValV(EigIprV, "eigIPR." + FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f (%d values)",
			DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), EigIprV.Last().Val1(), EigIprV.Len()),
			"Eigenvalue", "Inverse Participation Ratio of corresponding Eigenvector", gpsLog10Y, false, gpwPoints);
	}

	void PlotSngValRank(const PNGraph& Graph, const int& SngVals, const TStr& FNmPref, TStr DescStr) {
		TFltV SngValV;
		TSnap::GetSngVals(Graph, SngVals, SngValV);
		SngValV.Sort(false);
		if (DescStr.Empty()) { DescStr = FNmPref; }
		TGnuPlot::PlotValV(SngValV, "sngVal." + FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f",
			DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), SngValV[0].Val), "Rank", "Singular value", gpsLog10XY, false, gpwLinesPoints);
	}

	void PlotSngValDistr(const PNGraph& Graph, const int& SngVals, const TStr& FNmPref, TStr DescStr) {
		const int NBuckets = 50;
		TFltV SngValV;
		for (int f = 1; SngValV.Empty() && f < 4; f++) {
			TSnap::GetSngVals(Graph, f*SngVals, SngValV);
		}
		SngValV.Sort(true);
		THash<TFlt, TFlt> BucketCntH;
		double Step = (SngValV.Last() - SngValV[0]) / double(NBuckets - 1);
		for (int i = 0; i < NBuckets; i++) {
			BucketCntH.AddDat(SngValV[0] + Step*(i + 0.5), 0);
		}
		for (int i = 0; i < SngValV.Len(); i++) {
			const int Bucket = (int)floor((SngValV[i] - SngValV[0]) / Step);
			BucketCntH[Bucket] += 1;
		}
		TFltPrV EigCntV;
		BucketCntH.GetKeyDatPrV(EigCntV);
		if (DescStr.Empty()) { DescStr = FNmPref; }
		TGnuPlot::PlotValV(EigCntV, "sngDistr." + FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f", DescStr.CStr(),
			Graph->GetNodes(), Graph->GetEdges(), SngValV.Last().Val), "Singular value", "Count", gpsAuto, false, gpwLinesPoints);
	}

	void PlotSngVec(const PNGraph& Graph, const TStr& FNmPref, TStr DescStr) {
		TFltV LeftSV, RightSV;
		TSnap::GetSngVec(Graph, LeftSV, RightSV);
		LeftSV.Sort(false);
		RightSV.Sort(false);
		TFltV BinV;
		if (DescStr.Empty()) { DescStr = FNmPref; }
		TGUtil::MakeExpBins(LeftSV, BinV, 1.01);
		TGnuPlot::PlotValV(BinV, "sngVecL." + FNmPref, TStr::Fmt("%s. G(%d, %d). Left signular vector",
			DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges()), "Rank", "Component of left singular vector", gpsLog10XY, false, gpwLinesPoints);
		TGnuPlot::PlotValV(BinV, "sngVecL." + FNmPref, TStr::Fmt("%s. G(%d, %d). Right signular vector",
			DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges()), "Rank", "Component of right singular vector", gpsLog10XY, false, gpwLinesPoints);
	}

} // namespace TSnap
