aGrUM 3.2.0
a C++ library for (probabilistic) graphical models
BIFXMLBNReader_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
44#include <agrum/BN/io/BIFXML/BIFXMLBNReader.h> // to ease IDE parser
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
47
49
50namespace gum {
51 /*
52 * Constructor
53 * A reader is created to reading a defined file.
54 * Note that an BN as to be created before and given in parameter.
55 */
56 template < GUM_Numeric GUM_SCALAR >
58 std::string_view filePath) :
59 BNReader< GUM_SCALAR >(bn, filePath) {
60 GUM_CONSTRUCTOR(BIFXMLBNReader);
61 _bn_ = bn;
62 _filePath_ = filePath;
63 }
64
65 /*
66 * Constructor from an input stream.
67 */
68 template < GUM_Numeric GUM_SCALAR >
69 BIFXMLBNReader< GUM_SCALAR >::BIFXMLBNReader(BayesNet< GUM_SCALAR >* bn, std::istream& stream) :
70 BNReader< GUM_SCALAR >(bn, "<stream>") {
71 GUM_CONSTRUCTOR(BIFXMLBNReader);
72 _bn_ = bn;
73 _isFromStream_ = true;
74 _xmlContent_
75 = std::string(std::istreambuf_iterator< char >(stream), std::istreambuf_iterator< char >());
76 }
77
78 /*
79 * Default destructor.
80 */
81 template < GUM_Numeric GUM_SCALAR >
82 BIFXMLBNReader< GUM_SCALAR >::~BIFXMLBNReader() {
83 GUM_DESTRUCTOR(BIFXMLBNReader);
84 }
85
86 /*
87 * Reads the bayes net from the file referenced by filePath given at the
88 * creation
89 * of class
90 * @return Returns the number of errors during the parsing (0 if none).
91 */
92 template < GUM_Numeric GUM_SCALAR >
93 Size BIFXMLBNReader< GUM_SCALAR >::proceed() {
94 try {
95 // Loading file or parsing string
96 std::string status = _isFromStream_ ? "Parsing XML content ..." : "Loading File ...";
97 GUM_EMIT2(onProceed, 0, status);
98
99 XmlDocument xmlDoc;
100 if (_isFromStream_) {
101 xmlDoc.parse(_xmlContent_);
102 } else {
103 xmlDoc = XmlDocument(_filePath_);
104 xmlDoc.loadFile();
105 }
106
107 if (xmlDoc.noChildren()) {
108 GUM_ERROR(IOError, ": Loading fail, please check the file for any syntax error.")
109 }
110
111 // Finding BIF element
112 status = "File loaded. Now looking for BIF element ...";
113 GUM_EMIT2(onProceed, 4, status);
114
115 XmlElement bifElement = xmlDoc.firstChildElement("BIF");
116
117 // Finding network element
118 status = "BIF Element reached. Now searching network ...";
119 GUM_EMIT2(onProceed, 7, status);
120
121 XmlElement networkElement = bifElement.firstChildElement("NETWORK");
122
123 // Reading network name (optional)
124 XmlElement nameElement = networkElement.firstChildElement("NAME", false);
125 if (!nameElement.isNull()) { _bn_->setProperty("name", nameElement.textOrDefault("")); }
126
127 // Finding id variables
128 status = "Network found. Now proceeding variables instantiation...";
129 GUM_EMIT2(onProceed, 10, status);
130
131 _parsingVariables_(networkElement);
132
133 // Filling diagram
134 status = "All variables have been instantiated. Now filling up diagram...";
135 GUM_EMIT2(onProceed, 55, status);
136
137 _fillingBN_(networkElement);
138
139 status = "Instantiation of network completed";
140 GUM_EMIT2(onProceed, 100, status);
141
142 return 0;
143 } catch (XmlException& xmlException) { GUM_ERROR(IOError, xmlException.what()) }
144 }
145
146 template < GUM_Numeric GUM_SCALAR >
147 void BIFXMLBNReader< GUM_SCALAR >::_parsingVariables_(XmlElement parentNetwork) {
148 int nbVar = 0;
149 for (const auto& _: parentNetwork.children("VARIABLE")) {
150 nbVar++;
151 }
152
153 // Iterating on variable element
154 int nbIte = 0;
155
156 for (const auto& currentVar: parentNetwork.children("VARIABLE")) {
157 // Getting variable name
158 XmlElement varNameElement = currentVar.firstChildElement("NAME");
159 std::string varName = varNameElement.textOrDefault("");
160
161 std::string description = "";
162 std::string fast = "";
163 // Getting variable description and/or fast syntax
164 for (const auto& property: currentVar.children("PROPERTY")) {
165 const auto pair = gum::split(property.textOrDefault(""), "=");
166 if (pair.size() == 2) {
167 const auto propertyName = gum::toLower(gum::trim_copy(pair[0]));
168 const auto value = gum::trim_copy(pair[1]);
169 // check for descritpion and fast
170 if (propertyName == "description") {
171 description = value;
172 } else if (propertyName == "fast") {
173 fast = value;
174 }
175 }
176 }
177
178 if (fast == "") {
179 // if no fast syntax, we create a variable with the default}
180 // Instanciation de la variable
181 auto newVar = new LabelizedVariable(varName, description, 0);
182
183 // Getting variable outcomes
184 for (const auto& outcome: currentVar.children("OUTCOME"))
185 newVar->addLabel(outcome.textOrDefault(""));
186
187 // Add the variable to the bn and then delete newVar (add makes a copy)
188 _bn_->add(*newVar);
189 delete newVar;
190 } else {
191 auto newVar = gum::fastVariable(fast, 2);
192 newVar->setDescription(description);
193 // we could check if varName is OK
194 if (newVar->name() != varName) {
196 "Variable name (" << varName << ") and fast syntax (" << fast
197 << ") are not compatible. Please check the syntax.")
198 }
199 // Add the variable to the bn and then delete newVar (add makes a copy)
200 _bn_->add(*newVar);
201 }
202
203 // Emitting progress.
204 std::string status = "Network found. Now proceedind variables instanciation...";
205 int progress = (int)((float)nbIte / (float)nbVar * 45) + 10;
206 GUM_EMIT2(onProceed, progress, status);
207 nbIte++;
208 }
209 }
210
211 template < GUM_Numeric GUM_SCALAR >
212
213
214 void BIFXMLBNReader< GUM_SCALAR >::_fillingBN_(XmlElement parentNetwork) {
215 // Counting the number of variable for the signal
216 int nbDef = 0;
217 for (const auto& _: parentNetwork.children("DEFINITION")) {
218 nbDef++;
219 }
220
221 // Iterating on definition nodes
222 int nbIte = 0;
223
224 for (const auto& currentVar: parentNetwork.children("DEFINITION")) {
225 // Considered Node
226 std::string currentVarName = currentVar.firstChildElement("FOR").textOrDefault("");
227 NodeId currentVarId = _bn_->idFromName(currentVarName);
228
229 // Get Node's parents
230 List< NodeId > parentList;
231
232 for (const auto& given: currentVar.children("GIVEN")) {
233 std::string parentNode = given.textOrDefault("");
234 NodeId parentId = _bn_->idFromName(parentNode);
235 parentList.pushBack(parentId);
236 }
237
238 for (List< NodeId >::iterator_safe parentListIte = parentList.rbeginSafe();
239 parentListIte != parentList.rendSafe();
240 --parentListIte)
241 _bn_->addArc(*parentListIte, currentVarId);
242
243 // Recuperating tables values
244 XmlElement tableElement = currentVar.firstChildElement("TABLE");
245 std::istringstream issTableString(tableElement.textOrDefault(""));
246 std::list< GUM_SCALAR > tablelist;
247 GUM_SCALAR value;
248
249 while (!issTableString.eof()) {
250 issTableString >> value;
251 tablelist.push_back(value);
252 }
253
254 std::vector< GUM_SCALAR > tablevector(tablelist.begin(), tablelist.end());
255
256 // Filling tables
257 _bn_->cpt(currentVarId).fillWith(tablevector);
258
259 // Emitting progress.
260 std::string status = "All variables have been instancied. Now filling up diagram...";
261 int progress = (int)((float)nbIte / (float)nbDef * 45) + 55;
262 GUM_EMIT2(onProceed, progress, status);
263 nbIte++;
264 }
265 }
266} /* namespace gum */
267
268#endif // DOXYGEN_SHOULD_SKIP_THIS
classe for import of bayes net from a XML file written with BIF Format
BIFXMLBNReader(BayesNet< GUM_SCALAR > *bn, std::string_view filePath)
Constructor A reader is created to reading a defined file.
Pure virtual class for reading a BN from a file.
Definition BNReader.h:78
Class representing a Bayesian network.
Definition BayesNet.h:99
GUM_NODISCARD const char * what() const noexcept override
Exception : input/output problem.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
GUM_SHARED_PUBLIC std::string toLower(std::string_view str)
Returns the lowercase version of str.
GUM_SHARED_PUBLIC std::string trim_copy(std::string_view s)
trim from both ends (copying)
std::vector< std::string > split(std::string_view str, std::string_view delim)
Split str using the delimiter.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::unique_ptr< DiscreteVariable > fastVariable(std::string var_description, Size default_domain_size)
Create a pointer on a Discrete Variable from a "fast" syntax.
#define GUM_EMIT2(signal, arg1, arg2)
Definition signaler.h:290
Utilities for manipulating strings.