aGrUM 2.3.2
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-2025 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-2025 *
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#pragma once
41
42
43#ifndef DOXYGEN_SHOULD_SKIP_THIS
44
45# include <fstream>
46# include <iostream>
47# include <sstream>
48
50
52
53namespace gum {
54 /*
55 * Constructor
56 * A reader is created to reading a defined file.
57 * Note that an ID as to be created before and given in parameter.
58 */
59 template < typename GUM_SCALAR >
61 const std::string& filePath) :
62 IDReader< GUM_SCALAR >(infdiag, filePath) {
63 GUM_CONSTRUCTOR(BIFXMLIDReader);
64 _infdiag_ = infdiag;
65 _filePath_ = filePath;
66 }
67
68 /*
69 * Default destructor.
70 */
71 template < typename GUM_SCALAR >
72 INLINE BIFXMLIDReader< GUM_SCALAR >::~BIFXMLIDReader() {
73 GUM_DESTRUCTOR(BIFXMLIDReader);
74 }
75
76 /*
77 * Reads the influence diagram from the file referenced by filePath given at
78 * the
79 * creation of class
80 * @return Returns the number of error during the parsing (0 if none).
81 */
82 template < typename GUM_SCALAR >
83 void BIFXMLIDReader< GUM_SCALAR >::proceed() {
84 try {
85 // Loading file
86 std::string status = "Loading File ...";
87 GUM_EMIT2(onProceed, 0, status);
88
89 ticpp::Document xmlDoc(_filePath_);
90 xmlDoc.LoadFile();
91
92 if (xmlDoc.NoChildren()) {
93 GUM_ERROR(IOError, ": Loading fail, please check the file for any syntax error.")
94 }
95
96 // Finding BIF element
97 status = "File loaded. Now looking for BIF element ...";
98 GUM_EMIT2(onProceed, 4, status);
99
100 ticpp::Element* bifElement = xmlDoc.FirstChildElement("BIF");
101
102 // Finding network element
103 status = "BIF Element reached. Now searching network ...";
104 GUM_EMIT2(onProceed, 7, status);
105
106 ticpp::Element* networkElement = bifElement->FirstChildElement("NETWORK");
107
108 // Finding id variables
109 status = "Network found. Now proceeding variables instanciation...";
110 GUM_EMIT2(onProceed, 10, status);
111
112 _parsingVariables_(networkElement);
113
114 // Filling diagram
115 status = "All variables have been instancied. Now filling up diagram...";
116 GUM_EMIT2(onProceed, 55, status);
117
118 _fillingDiagram_(networkElement);
119
120 status = "Instanciation of network completed";
121 GUM_EMIT2(onProceed, 100, status);
122 } catch (ticpp::Exception& tinyexception) { GUM_ERROR(IOError, tinyexception.what()) }
123 }
124
125 template < typename GUM_SCALAR >
126 void BIFXMLIDReader< GUM_SCALAR >::_parsingVariables_(ticpp::Element* parentNetwork) {
127 // Counting the number of variable for the signal
128 int nbVar = 0;
129 ticpp::Iterator< ticpp::Element > varIte("VARIABLE");
130
131 for (varIte = varIte.begin(parentNetwork); varIte != varIte.end(); ++varIte)
132 nbVar++;
133
134 // Iterating on variable element
135 int nbIte = 0;
136
137 for (varIte = varIte.begin(parentNetwork); varIte != varIte.end(); ++varIte) {
138 ticpp::Element* currentVar = varIte.Get();
139
140 // Getting variable name
141 ticpp::Element* varNameElement = currentVar->FirstChildElement("NAME");
142 std::string varName = varNameElement->GetTextOrDefault("");
143
144 std::string description = "";
145 std::string fast = "";
146
147 // Getting variable description and/or fast syntax
148 ticpp::Iterator< ticpp::Element > varPropertiesIte("PROPERTY");
149 for (varPropertiesIte = varPropertiesIte.begin(currentVar);
150 varPropertiesIte != varPropertiesIte.end();
151 ++varPropertiesIte) {
152 const auto pair = gum::split(varPropertiesIte->GetTextOrDefault(""), "=");
153 if (pair.size() == 2) {
154 const auto property = gum::toLower(gum::trim_copy(pair[0]));
155 const auto value = gum::trim_copy(pair[1]);
156 // check for descritpion and fast
157 if (property == "description") {
158 description = value;
159 } else if (property == "fast") {
160 fast = value;
161 }
162 }
163 }
164 // Getting variable type
165 const auto nodeType = currentVar->GetAttribute< std::string >("TYPE");
166 if (fast == "") {
167 // if no fast syntax, we create a variable with the default}
168 // Instanciation de la variable
169 auto newVar = new LabelizedVariable(varName, description, 0);
170
171 // Getting variable outcomes
172 ticpp::Iterator< ticpp::Element > varOutComesIte("OUTCOME");
173
174 for (varOutComesIte = varOutComesIte.begin(currentVar);
175 varOutComesIte != varOutComesIte.end();
176 ++varOutComesIte)
177 newVar->addLabel(varOutComesIte->GetTextOrDefault(""));
178
179
180 // Add the variable to the id
181 if (nodeType == "decision") _infdiag_->addDecisionNode(*newVar);
182 else if (nodeType == "utility") _infdiag_->addUtilityNode(*newVar);
183 else _infdiag_->addChanceNode(*newVar);
184 delete newVar;
185 } else {
186 auto newVar = gum::fastVariable(fast, (nodeType == "utility") ? 1 : 2);
187 newVar->setDescription(description);
188 // we could check if varName is OK
189 if (newVar->name() != varName) {
191 "Variable name (" << varName << ") and fast syntax (" << fast
192 << ") are not compatible. Please check the syntax.")
193 }
194
195 // Add the variable to the id
196 if (nodeType == "decision") _infdiag_->addDecisionNode(*newVar);
197 else if (nodeType == "utility") _infdiag_->addUtilityNode(*newVar);
198 else _infdiag_->addChanceNode(*newVar);
199 ;
200 }
201
202 // Emitting progress.
203 std::string status = "Network found. Now proceedind variables instanciation...";
204 int progress = (int)((float)nbIte / (float)nbVar * 45) + 10;
205 GUM_EMIT2(onProceed, progress, status);
206 nbIte++;
207 }
208 }
209
210 template < typename GUM_SCALAR >
211 void BIFXMLIDReader< GUM_SCALAR >::_fillingDiagram_(ticpp::Element* parentNetwork) {
212 // Counting the number of variable for the signal
213 int nbDef = 0;
214 ticpp::Iterator< ticpp::Element > definitionIte("DEFINITION");
215
216 for (definitionIte = definitionIte.begin(parentNetwork); definitionIte != definitionIte.end();
217 ++definitionIte)
218 nbDef++;
219
220 // Iterating on definition nodes
221 int nbIte = 0;
222
223 for (definitionIte = definitionIte.begin(parentNetwork); definitionIte != definitionIte.end();
224 ++definitionIte) {
225 ticpp::Element* currentVar = definitionIte.Get();
226
227 // Considered Node
228 std::string currentVarName = currentVar->FirstChildElement("FOR")->GetTextOrDefault("");
229 NodeId currentVarId = _infdiag_->idFromName(currentVarName);
230
231 // Get Node's parents
232 ticpp::Iterator< ticpp::Element > givenIte("GIVEN");
233 List< NodeId > parentList;
234
235 for (givenIte = givenIte.begin(currentVar); givenIte != givenIte.end(); ++givenIte) {
236 std::string parentNode = givenIte->GetTextOrDefault("");
237 NodeId parentId = _infdiag_->idFromName(parentNode);
238 parentList.pushBack(parentId);
239 }
240
241 for (List< NodeId >::iterator_safe parentListIte = parentList.rbeginSafe();
242 parentListIte != parentList.rendSafe();
243 --parentListIte)
244 _infdiag_->addArc(*parentListIte, currentVarId);
245
246 // Recuperating tables values
247 if (!_infdiag_->isDecisionNode(currentVarId)) {
248 ticpp::Element* tableElement = currentVar->FirstChildElement("TABLE");
249 std::istringstream issTableString(tableElement->GetTextOrDefault(""));
250 std::list< GUM_SCALAR > tablelist;
251 GUM_SCALAR value;
252
253 while (!issTableString.eof()) {
254 issTableString >> value;
255 tablelist.push_back(value);
256 }
257
258 std::vector< GUM_SCALAR > tablevector(tablelist.begin(), tablelist.end());
259
260 // Filling tables
261 if (_infdiag_->isChanceNode(currentVarId)) {
262 const Tensor< GUM_SCALAR >* table = &_infdiag_->cpt(currentVarId);
263 table->populate(tablevector);
264 } else if (_infdiag_->isUtilityNode(currentVarId)) {
265 const Tensor< GUM_SCALAR >* table = &_infdiag_->utility(currentVarId);
266 table->populate(tablevector);
267 }
268 }
269
270 // Emitting progress.
271 std::string status = "All variables have been instancied. Now filling up diagram...";
272 int progress = (int)((float)nbIte / (float)nbDef * 45) + 55;
273 GUM_EMIT2(onProceed, progress, status);
274 nbIte++;
275 }
276 }
277} /* namespace gum */
278
279#endif // DOXYGEN_SHOULD_SKIP_THIS
classe for import of Influence Diagram from a XML file written with BIF Format
BIFXMLIDReader(InfluenceDiagram< GUM_SCALAR > *infdiag, const std::string &filePath)
Constructor A reader is created to reading a defined file.
Pure virtual class for importing an ID from a file.
Definition IDReader.h:74
Exception : input/output problem.
Class representing an Influence Diagram.
Wrapper around TiXmlDocument.
Definition ticpp.h:1409
Wrapper around TiXmlElement.
Definition ticpp.h:1500
std::string GetTextOrDefault(const std::string &defaultValue) const
Gets the text of an Element, if it doesn't exist it will return the defaultValue.
Definition ticpp.h:1636
T GetAttribute(const std::string &name, bool throwIfNotFound=true) const
Returns an attribute of name from an element.
Definition ticpp.h:1799
This is a ticpp exception class.
Definition ticpp.h:74
const char * what() const
Override std::exception::what() to return m_details.
Definition ticpp.cpp:920
Iterator for conveniently stepping through Nodes and Attributes.
Definition ticpp.h:1112
Element * FirstChildElement(bool throwIfNoChildren=true) const
The first child element of this node.
Definition ticpp.cpp:501
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
std::string toLower(std::string str)
Returns the lowercase version of str.
std::vector< std::string > split(const std::string &str, const std::string &delim)
Split str using the delimiter.
std::string trim_copy(const std::string &s)
trim from both ends (copying)
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 signaler2.h:61
Utilities for manipulating strings.