aGrUM 3.2.0
a C++ library for (probabilistic) graphical models
BIFXMLIDReader_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/ID/io/BIFXML/BIFXMLIDReader.h> // to ease IDE parser
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46
47# include <fstream>
48# include <iostream>
49# include <sstream>
50
52
54
55namespace gum {
56 /*
57 * Constructor
58 * A reader is created to reading a defined file.
59 * Note that an ID as to be created before and given in parameter.
60 */
61 template < GUM_Numeric GUM_SCALAR >
63 std::string_view filePath) :
64 IDReader< GUM_SCALAR >(infdiag, filePath) {
65 GUM_CONSTRUCTOR(BIFXMLIDReader);
66 _infdiag_ = infdiag;
67 _filePath_ = filePath;
68 }
69
70 /*
71 * Default destructor.
72 */
73 template < GUM_Numeric GUM_SCALAR >
74 BIFXMLIDReader< GUM_SCALAR >::~BIFXMLIDReader() {
75 GUM_DESTRUCTOR(BIFXMLIDReader);
76 }
77
78 /*
79 * Reads the influence diagram from the file referenced by filePath given at
80 * the
81 * creation of class
82 * @return Returns the number of error during the parsing (0 if none).
83 */
84 template < GUM_Numeric GUM_SCALAR >
85 Size BIFXMLIDReader< GUM_SCALAR >::proceed() {
86 try {
87 // Loading file
88 std::string status = "Loading File ...";
89 GUM_EMIT2(onProceed, 0, status);
90
91 XmlDocument xmlDoc(_filePath_);
92 xmlDoc.loadFile();
93
94 if (xmlDoc.noChildren()) {
95 GUM_ERROR(IOError, ": Loading fail, please check the file for any syntax error.")
96 }
97
98 // Finding BIF element
99 status = "File loaded. Now looking for BIF element ...";
100 GUM_EMIT2(onProceed, 4, status);
101
102 XmlElement bifElement = xmlDoc.firstChildElement("BIF");
103
104 // Finding network element
105 status = "BIF Element reached. Now searching network ...";
106 GUM_EMIT2(onProceed, 7, status);
107
108 XmlElement networkElement = bifElement.firstChildElement("NETWORK");
109
110 // Finding id variables
111 status = "Network found. Now proceeding variables instanciation...";
112 GUM_EMIT2(onProceed, 10, status);
113
114 _parsingVariables_(networkElement);
115
116 // Filling diagram
117 status = "All variables have been instancied. Now filling up diagram...";
118 GUM_EMIT2(onProceed, 55, status);
119
120 _fillingDiagram_(networkElement);
121
122 status = "Instanciation of network completed";
123 GUM_EMIT2(onProceed, 100, status);
124 } catch (XmlException& xmlException) { GUM_ERROR(IOError, xmlException.what()) }
125 return 0;
126 }
127
128 template < GUM_Numeric GUM_SCALAR >
129 void BIFXMLIDReader< GUM_SCALAR >::_parsingVariables_(XmlElement parentNetwork) {
130 // Counting the number of variable for the signal
131 int nbVar = 0;
132 for (const auto& _: parentNetwork.children("VARIABLE")) {
133 nbVar++;
134 }
135
136 // Iterating on variable element
137 int nbIte = 0;
138
139 for (const auto& currentVar: parentNetwork.children("VARIABLE")) {
140 // Getting variable name
141 XmlElement varNameElement = currentVar.firstChildElement("NAME");
142 std::string varName = varNameElement.textOrDefault("");
143
144 std::string description = "";
145 std::string fast = "";
146
147 // Getting variable description and/or fast syntax
148 for (const auto& property: currentVar.children("PROPERTY")) {
149 const auto pair = gum::split(property.textOrDefault(""), "=");
150 if (pair.size() == 2) {
151 const auto propertyName = gum::toLower(gum::trim_copy(pair[0]));
152 const auto value = gum::trim_copy(pair[1]);
153 // check for descritpion and fast
154 if (propertyName == "description") {
155 description = value;
156 } else if (propertyName == "fast") {
157 fast = value;
158 }
159 }
160 }
161 // Getting variable type
162 const auto nodeType = currentVar.attribute("TYPE");
163 if (fast == "") {
164 // if no fast syntax, we create a variable with the default}
165 // Instanciation de la variable
166 auto newVar = new LabelizedVariable(varName, description, 0);
167
168 // Getting variable outcomes
169 for (const auto& outcome: currentVar.children("OUTCOME")) {
170 newVar->addLabel(outcome.textOrDefault(""));
171 }
172
173 // Add the variable to the id
174 if (nodeType == "decision") _infdiag_->addDecisionNode(*newVar);
175 else if (nodeType == "utility") _infdiag_->addUtilityNode(*newVar);
176 else _infdiag_->addChanceNode(*newVar);
177 delete newVar;
178 } else {
179 auto newVar = gum::fastVariable(fast, (nodeType == "utility") ? 1 : 2);
180 newVar->setDescription(description);
181 // we could check if varName is OK
182 if (newVar->name() != varName) {
184 "Variable name (" << varName << ") and fast syntax (" << fast
185 << ") are not compatible. Please check the syntax.")
186 }
187
188 // Add the variable to the id
189 if (nodeType == "decision") _infdiag_->addDecisionNode(*newVar);
190 else if (nodeType == "utility") _infdiag_->addUtilityNode(*newVar);
191 else _infdiag_->addChanceNode(*newVar);
192 ;
193 }
194
195 // Emitting progress.
196 std::string status = "Network found. Now proceedind variables instanciation...";
197 int progress = (int)((float)nbIte / (float)nbVar * 45) + 10;
198 GUM_EMIT2(onProceed, progress, status);
199 nbIte++;
200 }
201 }
202
203 template < GUM_Numeric GUM_SCALAR >
204 void BIFXMLIDReader< GUM_SCALAR >::_fillingDiagram_(XmlElement parentNetwork) {
205 // Counting the number of variable for the signal
206 int nbDef = 0;
207 for (const auto& _: parentNetwork.children("DEFINITION")) {
208 nbDef++;
209 }
210
211 // Iterating on definition nodes
212 int nbIte = 0;
213
214 for (const auto& currentVar: parentNetwork.children("DEFINITION")) {
215 // Considered Node
216 std::string currentVarName = currentVar.firstChildElement("FOR").textOrDefault("");
217 NodeId currentVarId = _infdiag_->idFromName(currentVarName);
218
219 // Get Node's parents
220 List< NodeId > parentList;
221
222 for (const auto& given: currentVar.children("GIVEN")) {
223 std::string parentNode = given.textOrDefault("");
224 NodeId parentId = _infdiag_->idFromName(parentNode);
225 parentList.pushBack(parentId);
226 }
227
228 for (List< NodeId >::iterator_safe parentListIte = parentList.rbeginSafe();
229 parentListIte != parentList.rendSafe();
230 --parentListIte)
231 _infdiag_->addArc(*parentListIte, currentVarId);
232
233 // Recuperating tables values
234 if (!_infdiag_->isDecisionNode(currentVarId)) {
235 XmlElement tableElement = currentVar.firstChildElement("TABLE");
236 std::istringstream issTableString(tableElement.textOrDefault(""));
237 std::list< GUM_SCALAR > tablelist;
238 GUM_SCALAR value;
239
240 while (!issTableString.eof()) {
241 issTableString >> value;
242 tablelist.push_back(value);
243 }
244
245 std::vector< GUM_SCALAR > tablevector(tablelist.begin(), tablelist.end());
246
247 // Filling tables
248 if (_infdiag_->isChanceNode(currentVarId)) {
249 const Tensor< GUM_SCALAR >* table = &_infdiag_->cpt(currentVarId);
250 table->populate(tablevector);
251 } else if (_infdiag_->isUtilityNode(currentVarId)) {
252 const Tensor< GUM_SCALAR >* table = &_infdiag_->utility(currentVarId);
253 table->populate(tablevector);
254 }
255 }
256
257 // Emitting progress.
258 std::string status = "All variables have been instancied. Now filling up diagram...";
259 int progress = (int)((float)nbIte / (float)nbDef * 45) + 55;
260 GUM_EMIT2(onProceed, progress, status);
261 nbIte++;
262 }
263 }
264} /* namespace gum */
265
266#endif // DOXYGEN_SHOULD_SKIP_THIS
classe for import of Influence Diagram from a XML file written with BIF Format
BIFXMLIDReader(InfluenceDiagram< GUM_SCALAR > *infdiag, std::string_view filePath)
Constructor A reader is created to reading a defined file.
GUM_NODISCARD const char * what() const noexcept override
Pure virtual class for importing an ID from a file.
Definition IDReader.h:76
Exception : input/output problem.
Class representing an Influence Diagram.
#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.