///////////////////////////////////////////////// // Graph Hash Table Key class TGraphKey { public: static const int RoundTo; private: public: TInt Nodes; TIntPrV EdgeV; // renumbers the graph (node ids 0..nodes-1) TFltV SigV; // signature (for hashing) TInt VariantId; // if graphs have same signature but are different public: TGraphKey() : Nodes(-1), EdgeV(), SigV(), VariantId(0) { } TGraphKey(const TSFltV& GraphSigV); TGraphKey(const TIntV& GraphSigV); TGraphKey(const TFltV& GraphSigV); TGraphKey(const TGraphKey& GraphKey); TGraphKey(TSIn& SIn); void Save(TSOut& SOut) const; TGraphKey& operator = (const TGraphKey& GraphKey); bool operator == (const TGraphKey& GraphKey) const { return SigV==GraphKey.SigV && VariantId==GraphKey.VariantId; } int GetPrimHashCd() const { return abs(SigV.GetPrimHashCd() ^ VariantId); } int GetSecHashCd() const { return abs(SigV.GetSecHashCd() ^ VariantId<<8); } int GetNodes() const { return Nodes; } int GetEdges() const { return EdgeV.Len(); } int GetSigLen() const { return SigV.Len(); } int GetVariant() const { return VariantId; } void SetVariant(const int& Variant) { VariantId = Variant; } void SetEdgeV(const TIntPrV& EdgeIdV) { EdgeV = EdgeIdV; } PNGraph GetNGraph() const; void TakeGraph(const PNGraph& Graph); // renumbers the nodes void TakeGraph(const PNGraph& Graph, TIntPrV& NodeMap); // renumbers the nodes void TakeSig(const PNGraph& Graph, const int& MnSvdGraph, const int& MxSvdGraph); // create graph signature void SaveTxt(FILE *F) const; void SaveGViz(const TStr& OutFNm, const TStr& Desc = TStr(), const TStr& NodeAttrs="", const int& Size=-1) const; void PlotGViz(const TStr& OutFNm, const TStr& Desc = TStr(), const TStr& NodeAttrs="", const int& Size=-1) const; static bool IsIsomorph(const TGraphKey& Key1, const TGraphKey& Key2, const TIntV& NodeIdMap); static bool IsIsomorph(const TGraphKey& Key1, const TGraphKey& Key2, const TVec<TIntV>& NodeIdMapV); static bool IsIsomorph(const TGraphKey& Key1, const TGraphKey& Key2, const TVec<TIntV>& NodeIdMapV, int& IsoPermId); }; ///////////////////////////////////////////////// // Graph Hash Table template <class TDat> class TGHash { public: typedef typename THash<TGraphKey, TDat>::TIter TIter; private: TInt MxIsoCheck; // brute force graph isomorphism check TInt MxSvdGraph; // SVD isomorphism check THash<TInt, TVec<TIntV> > GSzToPermH; // node permutations up to MxIsoCkeck nodes TBool HashOnlyTrees; // hashing only trees (exact isomorphism test) THash<TGraphKey, TDat> GraphH; private: void InitPermutations(); int IsGetKeyId(const PNGraph& Graph) const; int IsGetKeyId(const PNGraph& Graph, TGraphKey& GKey) const; int IsGetKeyId(const PNGraph& Graph, TGraphKey& GKey, TIntPrV& NodeMap) const; public: TGHash(const bool& HashTrees, const int& MaxIsoCheck=8, const int& MaxSvdGraph=500); TGHash(TSIn& SIn); void Save(TSOut& SOut) const; const TDat& operator [] (const int& KeyId) const { return GraphH[KeyId]; } TDat& operator [] (const int& KeyId) { return GraphH[KeyId]; } const TDat& operator () (const TGraphKey& Key) const { return GraphH.GetDat(Key); } TDat& operator () (const TGraphKey& Key) { return GraphH.GetDat(Key); } TIter BegI() const { return GraphH.BegI(); } TIter EndI() const { return GraphH.EndI(); } TIter GetI(const int& KeyId) const { return GraphH.GetI(KeyId); } bool HashTrees() const { return HashOnlyTrees; } void Gen(const int& Ports) { GraphH.Gen(Ports); } void Clr(const bool& DoDel=true, const int& NoDelLim=-1) { GraphH.Clr(DoDel, NoDelLim); } bool Empty() const { return GraphH.Empty(); } int Len() const { return GraphH.Len(); } int GetPorts() const { return GraphH.GetPorts(); } bool IsAutoSize() const { return GraphH.IsAutoSize(); } int GetMxKeyIds() const { return GraphH.GetMxKeyIds(); } bool IsKeyIdEqKeyN() const { return GraphH.IsKeyIdEqKeyN(); } int AddKey(const PNGraph& Graph); TDat& AddDat(const PNGraph& Graph) { return GraphH[AddKey(Graph)]; } TDat& AddDat(const PNGraph& Graph, const TDat& Dat) { return GraphH[AddKey(Graph)] = Dat; } bool IsKey(const PNGraph& Graph) const { int k=IsGetKeyId(Graph); return k!=-1; } int GetKeyId(const PNGraph& Graph) const { int k=IsGetKeyId(Graph); IAssert(k!=-1); return k; } const TDat& GetDat(const PNGraph& Graph) const { return GraphH[GetKeyId(Graph)]; } TDat& GetDat(const PNGraph& Graph) { return GraphH[GetKeyId(Graph)]; } const TGraphKey& GetKey(const int& KeyId) const { return GraphH.GetKey(KeyId); } int GetKeyId(const TGraphKey& Key) const { return GraphH.GetKeyId(Key); } bool IsKey(const TGraphKey& Key) const { return GraphH.IsKey(Key); } bool IsKey(const TGraphKey& Key, int& KeyId) const { return GraphH.IsKey(Key, KeyId); } bool IsKeyId(const int& KeyId) const { return GraphH.IsKeyId(KeyId); } const TDat& GetDat(const TGraphKey& Key) const { return GraphH.GetDat(Key); } TDat& GetDat(const TGraphKey& Key) { return GraphH.GetDat(Key); } const TDat& GetDatId(const int& KeyId) const { return GraphH[KeyId]; } TDat& GetDatId(const int& KeyId) { return GraphH[KeyId]; } void GetKeyDat(const int& KeyId, TGraphKey& Key, TDat& Dat) const { GraphH.GetKeyDat(KeyId, Key, Dat); } bool IsKeyGetDat(const TGraphKey& Key, TDat& Dat) const { return GraphH.IsKeyGetDat(Key, Dat); } bool GetNodeMap(const PNGraph& Graph, TIntPrV& NodeMapV) const; bool GetNodeMap(const PNGraph& Graph, TIntPrV& NodeMapV, int& KeyId) const; int FFirstKeyId() const { return 0-1; } bool FNextKeyId(int& KeyId) const { return GraphH.FNextKeyId(KeyId); } void GetKeyV(TVec<TGraphKey>& KeyV) const { GraphH.GetKeyV(KeyV); } void GetDatV(TVec<TDat>& DatV) const { GraphH.GetDatV(DatV); } void GetKeyIdByDat(TIntV& KeyIdV, const bool& Asc = true) const; // order keyIds by data void GetKeyIdByGSz(TIntV& KeyIdV, const bool& Asc = true) const; // order keyIds by graph size void GetKeyDatPrV(TVec<TPair<TGraphKey, TDat> >& KeyDatPrV) const { GraphH.GetKeyDatPrV(KeyDatPrV); } void GetDatKeyPrV(TVec<TPair<TDat, TGraphKey> >& DatKeyPrV) const { GraphH.GetDatKeyPrV(DatKeyPrV); } void Defrag() { GraphH.Defrag(); } void Pack() { GraphH.Pack(); } void PlotGViz(const int& KeyId, const TStr& OutFNmPref, const TStr& OutputType = "gif", TStr Desc="") const; void PlotGViz(const TIntV& KeyIdV, const TStr& OutFNmPref, const TStr& OutputType = "gif") const; void SaveTxt(const TStr& OutFNm, const TStr& Desc, const TStr& DatColNm, const bool& SortByKeyVal=true) const; void SaveDetailTxt(const TStr& OutFNm, const TStr& Desc, const TStr& DatColNm) const; }; template <class TDat> void TGHash<TDat>::InitPermutations() { GSzToPermH.Clr(); for (int nodes = 2; nodes <= MxIsoCheck; nodes++) { TVec<TIntV> NodePermutationV; TIntV NodeIdV(nodes, 0); for (int i = 0; i < nodes; i++) NodeIdV.Add(i); NodeIdV.Pack(); NodePermutationV.Add(NodeIdV); while (NodeIdV.NextPerm()) { NodePermutationV.Add(NodeIdV); } NodePermutationV.Pack(); GSzToPermH.AddDat(nodes, NodePermutationV); } } template <class TDat> TGHash<TDat>::TGHash(const bool& HashTrees, const int& MaxIsoCheck, const int& MaxSvdGraph) : MxIsoCheck(MaxIsoCheck), MxSvdGraph(MaxSvdGraph), GSzToPermH(), HashOnlyTrees(HashTrees), GraphH() { if (! HashTrees) { InitPermutations(); } } template <class TDat> TGHash<TDat>::TGHash(TSIn& SIn) : MxIsoCheck(SIn), MxSvdGraph(SIn), GSzToPermH(), HashOnlyTrees(SIn), GraphH(SIn) { if (! HashOnlyTrees) { InitPermutations(); } } template <class TDat> void TGHash<TDat>::Save(TSOut& SOut) const { MxIsoCheck.Save(SOut); MxSvdGraph.Save(SOut); HashOnlyTrees.Save(SOut); GraphH.Save(SOut); } template <class TDat> int TGHash<TDat>::AddKey(const PNGraph& Graph) { if (HashOnlyTrees) { int RootNId; IAssert(TSnap::IsTree(Graph, RootNId)); TIntV TreeSig; TSnap::GetTreeSig(Graph, RootNId, TreeSig); TGraphKey GKey(TreeSig); const int KeyId = GraphH.GetKeyId(GKey); if (KeyId == -1) { GKey.TakeGraph(Graph); return GraphH.AddKey(GKey); } return KeyId; } else { TGraphKey GKey; GKey.TakeSig(Graph, MxIsoCheck+1, MxSvdGraph); // get signature const int Nodes = GKey.GetNodes(); if (Nodes > 2 && Nodes <= MxIsoCheck) { GKey.TakeGraph(Graph); // check all variants with same signature for (int variant = 1; ; variant++) { GKey.SetVariant(variant); int KeyId = GraphH.GetKeyId(GKey); if (KeyId == -1) { KeyId = GraphH.AddKey(GKey); //printf(" new variant: %d (%d)\n", KeyId, variant); return KeyId; } if (TGraphKey::IsIsomorph(GKey, GraphH.GetKey(KeyId), GSzToPermH.GetDat(Nodes))) { //printf(" isomorphic to: %d\n", KeyId); return KeyId; } // found isomorphic graph } } else { const int KeyId = GraphH.GetKeyId(GKey); if (KeyId == -1) { GKey.TakeGraph(Graph); return GraphH.AddKey(GKey); } return KeyId; } } Fail; return -1; } template <class TDat> int TGHash<TDat>::IsGetKeyId(const PNGraph& Graph) const { TGraphKey GKey; return IsGetKeyId(Graph, GKey); } template <class TDat> int TGHash<TDat>::IsGetKeyId(const PNGraph& Graph, TGraphKey& GKey) const { if (HashOnlyTrees) { int RootNId; IAssert(TSnap::IsTree(Graph, RootNId)); TIntV TreeSig; TSnap::GetTreeSig(Graph, RootNId, TreeSig); GKey = TGraphKey(TreeSig); const int KeyId = GraphH.GetKeyId(GKey); //IAssert(KeyId != -1); return KeyId; } else { GKey.TakeSig(Graph, MxIsoCheck+1, MxSvdGraph); const int Nodes = GKey.GetNodes(); if (Nodes > 2 && Nodes <= MxIsoCheck) { GKey.TakeGraph(Graph); for (int variant = 1; ; variant++) { GKey.SetVariant(variant); int KeyId = GraphH.GetKeyId(GKey); //IAssert(KeyId != -1); if (TGraphKey::IsIsomorph(GKey, GraphH.GetKey(KeyId), GSzToPermH.GetDat(Nodes))) { return KeyId; } } return -1; } else { const int KeyId = GraphH.GetKeyId(GKey); //IAssert(KeyId != -1); return KeyId; } } Fail; return -1; } template <class TDat> bool TGHash<TDat>::GetNodeMap(const PNGraph& Graph, TIntPrV& NodeMapV) const { int KeyId; return GetNodeMap(Graph, NodeMapV, KeyId); } template <class TDat> bool TGHash<TDat>::GetNodeMap(const PNGraph& Graph, TIntPrV& NodeMapV, int& KeyId) const { NodeMapV.Clr(false); if (HashOnlyTrees) { int RootNId; IAssert(TSnap::IsTree(Graph, RootNId)); TIntV TreeSig; TSnap::GetTreeSig(Graph, RootNId, TreeSig, NodeMapV); TGraphKey GKey(TreeSig); KeyId = GraphH.GetKeyId(GKey); return KeyId != -1; } else { const int Nodes = Graph->GetNodes(); int IsoPermId = -1; NodeMapV.Clr(false); if (Nodes == 0) { return true; } else if (Nodes == 1) { NodeMapV.Add(TIntPr(Graph->BegNI().GetId(), 0)); return true; } else if (Nodes <= MxIsoCheck) { TGraphKey GKey; GKey.TakeSig(Graph, MxIsoCheck+1, MxSvdGraph); GKey.TakeGraph(Graph, NodeMapV); for (int variant = 1; ; variant++) { GKey.SetVariant(variant); KeyId = GraphH.GetKeyId(GKey); if (KeyId == -1) return false; if (TGraphKey::IsIsomorph(GKey, GraphH.GetKey(KeyId), GSzToPermH.GetDat(Nodes), IsoPermId)) { const TIntV& K1K2Perm = GSzToPermH.GetDat(Nodes)[IsoPermId]; // map from graph to key1 to key2 for (int i = 0; i < NodeMapV.Len(); i++) { NodeMapV[i].Val2 = K1K2Perm[NodeMapV[i].Val2]; } return true; } } return false; } else { return false; // graph too big to find the mapping } } Fail; return false; } template <class TDat> void TGHash<TDat>::GetKeyIdByDat(TIntV& KeyIdV, const bool& Asc) const { TVec<TQuad<TDat, TInt,TInt, TInt> > DatKeyIdV(Len(), 0); // <TDat,Nodes,Edges,KeyId> for (int i = FFirstKeyId(); FNextKeyId(i); ) { DatKeyIdV.Add(TQuad<TDat, TInt,TInt, TInt>(GetDatId(i), GetKey(i).GetNodes(), GetKey(i).GetEdges(), i)); } DatKeyIdV.Sort(Asc); KeyIdV.Gen(Len(), 0); for (int i = 0; i < Len(); i++) { KeyIdV.Add(DatKeyIdV[i].Val4); } } template <class TDat> void TGHash<TDat>::GetKeyIdByGSz(TIntV& KeyIdV, const bool& Asc) const { TVec<TQuad<TInt,TInt, TDat, TInt> > DatKeyIdV(Len(), 0); // <Nodes,Edges,TDat,KeyId> for (int i = FFirstKeyId(); FNextKeyId(i); ) { DatKeyIdV.Add(TQuad< TInt,TInt, TDat, TInt>(GetKey(i).GetNodes(), GetKey(i).GetEdges(), GetDatId(i), i)); } DatKeyIdV.Sort(Asc); KeyIdV.Gen(Len(), 0); for (int i = 0; i < Len(); i++) { KeyIdV.Add(DatKeyIdV[i].Val4); } } template <class TDat> void TGHash<TDat>::PlotGViz(const int& KeyId, const TStr& OutFNmPref, const TStr& OutputType, TStr Desc) const { IAssert(OutputType == "ps" || OutputType == "gif" || OutputType == "png"); const TGraphKey& GKey = GetKey(KeyId); const TStr Desc1 = TStr::Fmt("%s (%d, %d)", Desc.CStr(), GKey.GetNodes(), GKey.GetEdges()); GKey.SaveGViz(OutFNmPref+".dot", Desc1); TGraphViz::DoLayout(OutFNmPref+".dot", OutFNmPref+"."+OutputType, gvlDot); } template <class TDat> void TGHash<TDat>::PlotGViz(const TIntV& KeyIdV, const TStr& OutFNmPref, const TStr& OutputType) const { IAssert(OutputType == "ps" || OutputType == "gif" || OutputType == "png"); TExeTm ExeTm; printf("Plotting %d graphs\n", KeyIdV.Len()); for (int i = 0; i < KeyIdV.Len(); i++) { const TStr FNm = TStr::Fmt("%s.%03d.key%d.", OutFNmPref.CStr(), i+1, KeyIdV[i]); const TStr Desc = TStr::Fmt("KeyId:%d", KeyIdV[i]); const TGraphKey& GKey = GetKey(KeyIdV[i]); printf("\r %d g(%d, %d) ", i, GKey.GetNodes(), GKey.GetEdges()); GKey.SaveGViz(FNm+"dot", Desc); TGraphViz::DoLayout(FNm+"dot", FNm+OutputType, gvlDot); } printf("done [%s].\n", ExeTm.GetTmStr()); } template <class TDat> void TGHash<TDat>::SaveTxt(const TStr& OutFNm, const TStr& Desc, const TStr& DatColNm, const bool& SortByKeyVal) const { TIntV KeyIdV; if (SortByKeyVal) GetKeyIdByDat(KeyIdV, false); else GetKeyIdByGSz(KeyIdV, true); FILE *F = fopen(OutFNm.CStr(), "wt"); fprintf(F, "Graph-Hash-Table"); fprintf(F, "%s\n", Desc.CStr()); fprintf(F, "%d graphs\n", KeyIdV.Len()); fprintf(F, "Rank\tKeyId\tNodes\tEdges\t%s\n", DatColNm.CStr()); for (int i = 0; i < KeyIdV.Len(); i++) { const TGraphKey& Key = GetKey(KeyIdV[i]); fprintf(F, "%d\t%d\t%d\t%d\t%s\n", i+1, KeyIdV[i], Key.GetNodes(), Key.GetEdges(), GetDatId(KeyIdV[i]).GetStr().CStr()); } fclose(F); } template <class TDat> void TGHash<TDat>::SaveDetailTxt(const TStr& OutFNm, const TStr& Desc, const TStr& DatColNm) const { TIntV KeyIdV; GetKeyIdByDat(KeyIdV, false); FILE *F = fopen(OutFNm.CStr(), "wt"); fprintf(F, "Graph-Hash-Table\n"); fprintf(F, "%s\n", Desc.CStr()); fprintf(F, "%d graphs", KeyIdV.Len()); for (int i = 0; i < KeyIdV.Len(); i++) { fprintf(F, "\n\n[%5d]\tRank: %d\n", KeyIdV[i], i+1); fprintf(F, "Dat: %s\n", GetDat(KeyIdV[i]).GetStr().CStr()); GetDatId(KeyIdV[i]).SaveTxt(F); } fclose(F); } ///////////////////////////////////////////////// // Simple Edge Graph class TSimpleGraph { private: TIntPrV EdgeV; public: TSimpleGraph() { } TSimpleGraph(const TIntPrV& GEdgeV) : EdgeV(GEdgeV) { } bool operator == (const TSimpleGraph& Graph) const { return EdgeV == Graph.EdgeV; } bool operator < (const TSimpleGraph& Graph) const { return EdgeV < Graph.EdgeV; } int GetEdges() const { return EdgeV.Len(); } void AddEdge(const int& SrcNId, const int& DstNId) { EdgeV.Add(TIntPr(SrcNId, DstNId)); } bool Join(const TSimpleGraph& G1, const TSimpleGraph& G2); TIntPrV& GetEdgeV() { return EdgeV; } TIntPrV& operator () () { return EdgeV; } void Dump(const TStr& Desc = TStr()) const; }; typedef TVec<TSimpleGraph> TSimpleGraphV; ///////////////////////////////////////////////// // Connected Sub-graph Enumeration class TSubGraphsEnum { private: TSimpleGraphV SgV, NextSgV; THash<TIntPr, TIntH> EdgeH; PNGraph NGraph; public: TSubGraphsEnum(PNGraph Graph) : NGraph(Graph) { } void Gen2Graphs(); void EnumSubGraphs(const int& MaxEdges); void RecurBfs(const int& MxDepth); void RecurBfs(const int& NId, const int& Depth, TSimpleGraph& PrevG); void RecurBfs1(const int& MxDepth); void RecurBfs1(const int& NId, const int& Depth); //void RecurBfs(const int& NId, const int& Depth, const THash<TIntPr, TInt>& EdgeH); };