1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmComputeComponentGraph.cxx,v $
6 Date: $Date: 2008-02-07 21:14:05 $
7 Version: $Revision: 1.1 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmComputeComponentGraph.h"
23 //----------------------------------------------------------------------------
24 cmComputeComponentGraph::cmComputeComponentGraph(Graph
const& input
):
27 // Identify components.
30 // Compute the component graph.
31 this->ComponentGraph
.resize(0);
32 this->ComponentGraph
.resize(this->Components
.size());
33 this->TransferEdges();
36 //----------------------------------------------------------------------------
37 cmComputeComponentGraph::~cmComputeComponentGraph()
41 //----------------------------------------------------------------------------
42 void cmComputeComponentGraph::Tarjan()
44 int n
= static_cast<int>(this->InputGraph
.size());
45 TarjanEntry entry
= {0,0};
46 this->TarjanEntries
.resize(0);
47 this->TarjanEntries
.resize(n
, entry
);
48 this->TarjanComponents
.resize(0);
49 this->TarjanComponents
.resize(n
, -1);
50 this->TarjanWalkId
= 0;
51 this->TarjanVisited
.resize(0);
52 this->TarjanVisited
.resize(n
, 0);
53 for(int i
= 0; i
< n
; ++i
)
55 // Start a new DFS from this node if it has never been visited.
56 if(!this->TarjanVisited
[i
])
58 assert(this->TarjanStack
.empty());
60 this->TarjanIndex
= 0;
66 //----------------------------------------------------------------------------
67 void cmComputeComponentGraph::TarjanVisit(int i
)
69 // We are now visiting this node.
70 this->TarjanVisited
[i
] = this->TarjanWalkId
;
72 // Initialize the entry.
73 this->TarjanEntries
[i
].Root
= i
;
74 this->TarjanComponents
[i
] = -1;
75 this->TarjanEntries
[i
].VisitIndex
= ++this->TarjanIndex
;
76 this->TarjanStack
.push(i
);
78 // Follow outgoing edges.
79 NodeList
const& nl
= this->InputGraph
[i
];
80 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
84 // Ignore edges to nodes that have been reached by a previous DFS
85 // walk. Since we did not reach the current node from that walk
86 // it must not belong to the same component and it has already
87 // been assigned to a component.
88 if(this->TarjanVisited
[j
] > 0 &&
89 this->TarjanVisited
[j
] < this->TarjanWalkId
)
94 // Visit the destination if it has not yet been visited.
95 if(!this->TarjanVisited
[j
])
100 // If the destination has not yet been assigned to a component,
101 // check if it has a better root for the current object.
102 if(this->TarjanComponents
[j
] < 0)
104 if(this->TarjanEntries
[this->TarjanEntries
[j
].Root
].VisitIndex
<
105 this->TarjanEntries
[this->TarjanEntries
[i
].Root
].VisitIndex
)
107 this->TarjanEntries
[i
].Root
= this->TarjanEntries
[j
].Root
;
112 // Check if we have found a component.
113 if(this->TarjanEntries
[i
].Root
== i
)
116 int c
= static_cast<int>(this->Components
.size());
117 this->Components
.push_back(NodeList());
118 NodeList
& component
= this->Components
[c
];
120 // Populate the component list.
124 // Get the next member of the component.
125 j
= this->TarjanStack
.top();
126 this->TarjanStack
.pop();
128 // Assign the member to the component.
129 this->TarjanComponents
[j
] = c
;
130 this->TarjanEntries
[j
].Root
= i
;
132 // Store the node in its component.
133 component
.push_back(j
);
136 // Sort the component members for clarity.
137 std::sort(component
.begin(), component
.end());
141 //----------------------------------------------------------------------------
142 void cmComputeComponentGraph::TransferEdges()
144 // Map inter-component edges in the original graph to edges in the
146 int n
= static_cast<int>(this->InputGraph
.size());
147 for(int i
=0; i
< n
; ++i
)
149 int i_component
= this->TarjanComponents
[i
];
150 NodeList
const& nl
= this->InputGraph
[i
];
151 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
154 int j_component
= this->TarjanComponents
[j
];
155 if(i_component
!= j_component
)
157 this->ComponentGraph
[i_component
].push_back(j_component
);