1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_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 implementation of the base class for all elimination sequence
24  *algorithms
25  *
26  * @author Christophe GONZALES(_at_AMU) and Pierre-Henri WUILLEMIN(_at_LIP6)
27  */
28 
29 #include <agrum/agrum.h>
30 #include <agrum/tools/graphs/algorithms/triangulations/eliminationStrategies/eliminationSequenceStrategy.h>
31 
32 #ifdef GUM_NO_INLINE
33 #  include <agrum/tools/graphs/algorithms/triangulations/eliminationStrategies/eliminationSequenceStrategy_inl.h>
34 #endif   // GUM_NOINLINE
35 
36 namespace gum {
37 
38   // an empty fill-ins set returned by default when we ask for a fill-ins set
_empty_fill_ins_()39   const EdgeSet& EliminationSequenceStrategy::_empty_fill_ins_() {
40 #ifdef GUM_DEBUG_MODE
41     static bool first_use = true;
42     if (first_use) {
43       first_use = false;
44       __debug__::_dec_creation_("Set", " __empty_edge_set", 0, "static variable correction", 0);
45       __debug__::_dec_creation_("HashTable",
46                                 " __empty_edge_set",
47                                 0,
48                                 "static variable correction",
49                                 0);
50     }
51 #endif
52     static EdgeSet empty_fill_ins;
53     return empty_fill_ins;
54   }
55 
56   // default constructor
EliminationSequenceStrategy()57   EliminationSequenceStrategy::EliminationSequenceStrategy() {
58     GUM_CONSTRUCTOR(EliminationSequenceStrategy);
59   }
60 
61   // constructor for an a priori non empty graph
EliminationSequenceStrategy(UndiGraph * graph,const NodeProperty<Size> * domain_sizes)62   EliminationSequenceStrategy::EliminationSequenceStrategy(
63      UndiGraph*                  graph,
64      const NodeProperty< Size >* domain_sizes) {
65     EliminationSequenceStrategy::setGraph(graph, domain_sizes);
66 
67     GUM_CONSTRUCTOR(EliminationSequenceStrategy);
68   }
69 
70   // copy constructor
EliminationSequenceStrategy(const EliminationSequenceStrategy & from)71   EliminationSequenceStrategy::EliminationSequenceStrategy(
72      const EliminationSequenceStrategy& from) :
73       graph_(from.graph_),
74       domain_sizes_(from.domain_sizes_), log_domain_sizes_(from.log_domain_sizes_) {
75     GUM_CONS_CPY(EliminationSequenceStrategy);
76   }
77 
78   /// move constructor
EliminationSequenceStrategy(EliminationSequenceStrategy && from)79   EliminationSequenceStrategy::EliminationSequenceStrategy(EliminationSequenceStrategy&& from) :
80       graph_(from.graph_), domain_sizes_(from.domain_sizes_),
81       log_domain_sizes_(std::move(from.log_domain_sizes_)) {
82     GUM_CONS_MOV(EliminationSequenceStrategy);
83   }
84 
85   // destructor
~EliminationSequenceStrategy()86   EliminationSequenceStrategy::~EliminationSequenceStrategy() {
87     GUM_DESTRUCTOR(EliminationSequenceStrategy);
88   }
89 
90   // performs all the graph/fill-ins updates provided
eliminationUpdate(const NodeId node)91   void EliminationSequenceStrategy::eliminationUpdate(const NodeId node) {}
92 
93   /** @brief in case fill-ins are provided, this function returns the fill-ins
94    * due to all the nodes eliminated so far */
fillIns()95   const EdgeSet& EliminationSequenceStrategy::fillIns() { return _empty_fill_ins_(); }
96 
97   // clears the sequence (to prepare, for instance, a new elimination sequence)
clear()98   void EliminationSequenceStrategy::clear() {
99     graph_        = nullptr;
100     domain_sizes_ = nullptr;
101     log_domain_sizes_.clear();
102   }
103 
104   // sets a new graph to be triangulated
setGraph(UndiGraph * graph,const NodeProperty<Size> * dom_sizes)105   bool EliminationSequenceStrategy::setGraph(UndiGraph*                  graph,
106                                              const NodeProperty< Size >* dom_sizes) {
107     // check that both the graph and the domain sizes are different from nullptr
108     // or else that both are equal to nullptr
109     if (((graph != nullptr) && (dom_sizes == nullptr))
110         || ((graph == nullptr) && (dom_sizes != nullptr))) {
111       GUM_ERROR(GraphError,
112                 "EliminationSequenceStrategy: one of the graph or the set of "
113                 "domain sizes is a null pointer.");
114     }
115 
116     // check that each node has a domain size
117     if (graph != nullptr) {
118       for (const auto node: *graph)
119         if (!dom_sizes->exists(node))
120           GUM_ERROR(GraphError,
121                     "EliminationSequenceStrategy needs a domain size "
122                     "for every node in the graph.");
123     }
124 
125     // avoid empty modifications
126     if ((graph != graph_) || (dom_sizes != domain_sizes_)) {
127       // remove, if any, the current graph
128       clear();
129 
130       // assign a new graph
131       graph_        = graph;
132       domain_sizes_ = dom_sizes;
133 
134       if (graph_ != nullptr) {
135         // compute the log of the modalities
136         log_domain_sizes_.resize(graph_->sizeNodes() / 2);
137 
138         for (const auto node: *graph_)
139           log_domain_sizes_.insert(node, std::log((*domain_sizes_)[node]));
140       }
141 
142       return true;
143     }
144 
145     return false;
146   }
147 
148 } /* namespace gum */
149