aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
spanningForestPrim.cpp
Go to the documentation of this file.
1
/**
2
*
3
* Copyright (c) 2005-2021 by 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),
_require_computation_
(
true
) {
39
if
(!
graph
|| !
cost
) {
GUM_ERROR
(
GraphError
,
"invalid null graph or edge cost pointer"
) }
40
41
// for debugging purposes
42
GUM_CONSTRUCTOR
(
SpanningForestPrim
);
43
}
44
45
// copy constructor
46
SpanningForestPrim
::
SpanningForestPrim
(
const
SpanningForestPrim
&
from
) :
47
SpanningForest
(),
_graph_
(
from
.
_graph_
),
_costTable_
(
from
.
_costTable_
),
48
_edgesToExplore_
(
from
.
_edgesToExplore_
),
_spanning_tree_
(
from
.
_spanning_tree_
),
49
_spanning_tree_cost_
(
from
.
_spanning_tree_cost_
),
50
_require_computation_
(
from
.
_require_computation_
) {
51
// for debugging purposes
52
GUM_CONS_CPY
(
SpanningForestPrim
);
53
}
54
55
// destructor
56
SpanningForestPrim
::~
SpanningForestPrim
() {
57
// for debugging purposes
58
GUM_DESTRUCTOR
(
SpanningForestPrim
);
59
}
60
61
/// Returns the cost of the spanning forest
62
float
SpanningForestPrim
::
costOfSpanningForest
() {
63
if
(
_require_computation_
)
_compute_
();
64
65
return
_spanning_tree_cost_
;
66
}
67
68
/// Returns the edges in a min cost spanning forest
69
const
EdgeSet
&
SpanningForestPrim
::
edgesInSpanningForest
() {
70
if
(
_require_computation_
)
_compute_
();
71
72
return
_spanning_tree_
.
edges
();
73
}
74
75
/// Construct the spanning forest
76
const
UndiGraph
&
SpanningForestPrim
::
spanningForest
() {
77
if
(
_require_computation_
)
_compute_
();
78
79
return
_spanning_tree_
;
80
}
81
82
/// compute the spanning forest
83
void
SpanningForestPrim
::
_compute_
() {
84
// compute a spanning tree in every connected component
85
for
(
const
auto
node
:
_graph_
.
nodes
()) {
86
if
(!
_spanning_tree_
.
existsNode
(
node
)) {
_computeInAComponent_
(
node
); }
87
}
88
89
// indicate that everything was computed
90
_require_computation_
=
false
;
91
}
92
93
/// compute a spanning tree
94
void
SpanningForestPrim
::
_computeInAComponent_
(
const
NodeId
id
) {
95
// add the node to the spanning tree
96
_spanning_tree_
.
addNodeWithId
(
id
);
97
98
// explore its neighborhood
99
_exploreNode_
(
id
);
100
101
// get the next nodes to link to the current spanning tree nodes
102
103
while
(!
_edgesToExplore_
.
empty
()) {
104
const
Edge
edge
=
_edgesToExplore_
.
pop
();
105
const
NodeId
first
=
edge
.
first
();
106
const
NodeId
second
=
edge
.
second
();
107
108
// consider only the edges that have one extremal node not in the spanning
109
// tree as those that can be added to the tree
110
111
if
(!
_spanning_tree_
.
existsNode
(
first
)) {
112
// add the edge to the spanning tree
113
_spanning_tree_
.
addNodeWithId
(
first
);
114
_spanning_tree_
.
addEdge
(
first
,
second
);
115
_spanning_tree_cost_
+=
_costTable_
[
edge
];
116
117
// We must explore the first node's neighborhood
118
_exploreNode_
(
first
);
119
}
else
if
(!
_spanning_tree_
.
existsNode
(
second
)) {
120
// add the edge to the spanning tree
121
_spanning_tree_
.
addNodeWithId
(
second
);
122
_spanning_tree_
.
addEdge
(
first
,
second
);
123
_spanning_tree_cost_
+=
_costTable_
[
edge
];
124
125
// We must explore the second node
126
_exploreNode_
(
second
);
127
}
128
}
129
}
130
131
/// explore the neighborhood of a node belonging to the spanning tree
132
void
SpanningForestPrim
::
_exploreNode_
(
const
NodeId
id
) {
133
// add its neighbors _edgesToExplore_ to indicate that they are
134
// potential next nodes to explore
135
for
(
const
auto
node
:
_graph_
.
neighbours
(
id
)) {
136
if
(!
_spanning_tree_
.
existsNode
(
node
)) {
137
Edge
edge
(
node
,
id
);
138
_edgesToExplore_
.
insert
(
edge
,
_costTable_
[
edge
]);
139
}
140
}
141
}
142
143
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643