aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
spanningForestPrim.cpp
Go to the documentation of this file.
1
/**
2
*
3
* Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4
* info_at_agrum_dot_org
5
*
6
* This library is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18
*
19
*/
20
21
22
/** @file
23
* @brief The Prim algorithm for computing min cost spanning trees or forests
24
*
25
* @author Jean-Philippe DUBUS & Christophe GONZALES(@AMU)
26
*/
27
28
#
include
<
agrum
/
agrum
.
h
>
29
30
#
include
<
agrum
/
tools
/
graphs
/
algorithms
/
spanningForestPrim
.
h
>
31
32
namespace
gum
{
33
34
/// Default constructor
35
SpanningForestPrim
::
SpanningForestPrim
(
const
UndiGraph
*
graph
,
36
const
EdgeProperty
<
float
>*
cost
) :
37
SpanningForest
(),
38
graph__
(*
graph
),
costTable__
(*
cost
),
spanning_tree_cost__
(0),
39
require_computation__
(
true
) {
40
if
(!
graph
|| !
cost
) {
41
GUM_ERROR
(
GraphError
,
"invalid null graph or edge cost pointer"
);
42
}
43
44
// for debugging purposes
45
GUM_CONSTRUCTOR
(
SpanningForestPrim
);
46
}
47
48
// copy constructor
49
SpanningForestPrim
::
SpanningForestPrim
(
const
SpanningForestPrim
&
from
) :
50
SpanningForest
(),
graph__
(
from
.
graph__
),
costTable__
(
from
.
costTable__
),
51
edgesToExplore__
(
from
.
edgesToExplore__
),
52
spanning_tree__
(
from
.
spanning_tree__
),
53
spanning_tree_cost__
(
from
.
spanning_tree_cost__
),
54
require_computation__
(
from
.
require_computation__
) {
55
// for debugging purposes
56
GUM_CONS_CPY
(
SpanningForestPrim
);
57
}
58
59
// destructor
60
SpanningForestPrim
::~
SpanningForestPrim
() {
61
// for debugging purposes
62
GUM_DESTRUCTOR
(
SpanningForestPrim
);
63
}
64
65
/// Returns the cost of the spanning forest
66
float
SpanningForestPrim
::
costOfSpanningForest
() {
67
if
(
require_computation__
)
compute__
();
68
69
return
spanning_tree_cost__
;
70
}
71
72
/// Returns the edges in a min cost spanning forest
73
const
EdgeSet
&
SpanningForestPrim
::
edgesInSpanningForest
() {
74
if
(
require_computation__
)
compute__
();
75
76
return
spanning_tree__
.
edges
();
77
}
78
79
/// Construct the spanning forest
80
const
UndiGraph
&
SpanningForestPrim
::
spanningForest
() {
81
if
(
require_computation__
)
compute__
();
82
83
return
spanning_tree__
;
84
}
85
86
/// compute the spanning forest
87
void
SpanningForestPrim
::
compute__
() {
88
// compute a spanning tree in every connected component
89
for
(
const
auto
node
:
graph__
.
nodes
()) {
90
if
(!
spanning_tree__
.
existsNode
(
node
)) {
computeInAComponent__
(
node
); }
91
}
92
93
// indicate that everything was computed
94
require_computation__
=
false
;
95
}
96
97
/// compute a spanning tree
98
void
SpanningForestPrim
::
computeInAComponent__
(
const
NodeId
id
) {
99
// add the node to the spanning tree
100
spanning_tree__
.
addNodeWithId
(
id
);
101
102
// explore its neighborhood
103
exploreNode__
(
id
);
104
105
// get the next nodes to link to the current spanning tree nodes
106
107
while
(!
edgesToExplore__
.
empty
()) {
108
const
Edge
edge
=
edgesToExplore__
.
pop
();
109
const
NodeId
first
=
edge
.
first
();
110
const
NodeId
second
=
edge
.
second
();
111
112
// consider only the edges that have one extremal node not in the spanning
113
// tree as those that can be added to the tree
114
115
if
(!
spanning_tree__
.
existsNode
(
first
)) {
116
// add the edge to the spanning tree
117
spanning_tree__
.
addNodeWithId
(
first
);
118
spanning_tree__
.
addEdge
(
first
,
second
);
119
spanning_tree_cost__
+=
costTable__
[
edge
];
120
121
// We must explore the first node's neighborhood
122
exploreNode__
(
first
);
123
}
else
if
(!
spanning_tree__
.
existsNode
(
second
)) {
124
// add the edge to the spanning tree
125
spanning_tree__
.
addNodeWithId
(
second
);
126
spanning_tree__
.
addEdge
(
first
,
second
);
127
spanning_tree_cost__
+=
costTable__
[
edge
];
128
129
// We must explore the second node
130
exploreNode__
(
second
);
131
}
132
}
133
}
134
135
/// explore the neighborhood of a node belonging to the spanning tree
136
void
SpanningForestPrim
::
exploreNode__
(
const
NodeId
id
) {
137
// add its neighbors edgesToExplore__ to indicate that they are
138
// potential next nodes to explore
139
for
(
const
auto
node
:
graph__
.
neighbours
(
id
)) {
140
if
(!
spanning_tree__
.
existsNode
(
node
)) {
141
Edge
edge
(
node
,
id
);
142
edgesToExplore__
.
insert
(
edge
,
costTable__
[
edge
]);
143
}
144
}
145
}
146
147
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669