aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
BIFXMLIDWriter_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
46
47namespace gum {
48 /*
49 * Default constructor.
50 */
51 template < typename GUM_SCALAR >
53 GUM_CONSTRUCTOR(BIFXMLIDWriter);
54 }
55
56 /*
57 * Destructor.
58 */
59 template < typename GUM_SCALAR >
61 GUM_DESTRUCTOR(BIFXMLIDWriter);
62 }
63
64 /*
65 * Writes an influence diagram in the given ouput stream.
66 *
67 * @param output The output stream.
68 * @param infdiag The influence diagram writen in the stream.
69 * @throws IOError Raised if an I/O error occurs.
70 */
71 template < typename GUM_SCALAR >
72 INLINE void BIFXMLIDWriter< GUM_SCALAR >::write(std::ostream& output,
73 const InfluenceDiagram< GUM_SCALAR >& infdiag) {
74 if (!output.good()) { GUM_ERROR(IOError, "Input/Output error : stream not writable.") }
75
76 output << _heading_() << std::endl;
77 output << "<!-- Variables -->" << std::endl;
78
79 for (const auto node: infdiag.nodes()) {
80 int nodeType = 1;
81
82 if (infdiag.isChanceNode(node)) nodeType = 2;
83 else if (infdiag.isUtilityNode(node)) nodeType = 3;
84
85 output << _variableBloc_(infdiag.variable(node), nodeType) << std::endl;
86 }
87
88 output << "<!-- Probability distributions -->" << std::endl;
89
90 for (const auto node: infdiag.nodes())
91 output << _variableDefinition_(node, infdiag);
92
93 output << std::endl;
94 output << _documentend_();
95 output.flush();
96
97 if (output.fail()) { GUM_ERROR(IOError, "Writing in the ostream failed.") }
98 }
99
100 /*
101 * Writes an Influence Diagram in the file referenced by filePath.
102 * If the file doesn't exists, it is created.
103 * If the file exists, it's content will be erased.
104 *
105 * @param filePath The path to the file used to write the Influence Diagram.
106 * @param infdiag The Influence Diagram writen in the file.
107 * @throw IOError Raised if an I/O error occurs.
108 */
109 template < typename GUM_SCALAR >
110 INLINE void BIFXMLIDWriter< GUM_SCALAR >::write(std::string filePath,
111 const InfluenceDiagram< GUM_SCALAR >& infdiag) {
112 std::ofstream output(filePath.c_str(), std::ios_base::trunc);
113
114 write(output, infdiag);
115
116 output.close();
117
118 if (output.fail()) { GUM_ERROR(IOError, "Writing in the ostream failed.") }
119 }
120
121 /*
122 * Returns the header of the BIF file.
123 */
124 template < typename GUM_SCALAR >
125 INLINE std::string BIFXMLIDWriter< GUM_SCALAR >::_heading_() {
126 std::stringstream str;
127
128 // Header for every xml
129 str << "<?xml version=\"1.0\" ?>" << std::endl;
130
131 // Document type definition of BIF 0.3
132 /* https://www.cs.cmu.edu/afs/cs/user/fgcozman/www/Research/InterchangeFormat/ */
133
134 // BIF version Tag
135 str << std::endl << "<BIF VERSION=\"0.3\">" << std::endl;
136
137 // Network declaration
138 str << "<NETWORK>" << std::endl;
139
140 return str.str();
141 }
142
143 /*
144 * Returns a bloc defining a variable in the BIF format.
145 */
146 template < typename GUM_SCALAR >
148 int varType) {
149 //<VARIABLE TYPE="nature|decision|utility">
150 //<NAME>name</NAME>
151 //<PROPERTY>description = ...</PROPERTY>
152 //<PROPERTY>fast = A[4,5]</PROPERTY>PROPERTY>
153 // <!- OUTCOMES are not used but are kept for compatibility->
154 //<OUTCOME>outcome1</OUTCOME>
155 //<OUTCOME>outcome2</OUTCOME>
156 //<PROPERTY>property</PROPERTY>
157 //</VARIABLE>
158
159 std::stringstream str;
160
161 // Declaration of variable and his type
162 str << "<VARIABLE TYPE=\"";
163
164 switch (varType) {
165 case 1 : str << "decision"; break;
166
167 case 2 : str << "nature"; break;
168
169 case 3 : str << "utility"; break;
170
171 default : break;
172 }
173
174 str << "\">" << std::endl;
175
176 // Name and description
177 str << "\t<NAME>" << var.name() << "</NAME>" << std::endl;
178 str << "\t<PROPERTY>description = " << var.description() << "</PROPERTY>" << std::endl;
179 str << "\t<PROPERTY>fast = " << var.toFast() << "</PROPERTY>" << std::endl;
180
181 // Outcomes
182 str << "<!-- OUTCOME are not used in pyAgrum BIFXML (see fast property) but are kept for "
183 "compatibility-->"
184 << std::endl;
185 for (Idx i = 0; i < var.domainSize(); i++)
186 str << "\t<OUTCOME>" << var.label(i) << "</OUTCOME>" << std::endl;
187
188 // //Closing tag
189 str << "</VARIABLE>" << std::endl;
190
191 return str.str();
192 }
193
194 /*
195 * Returns a bloc defining a variable's CPT in the BIF format.
196 */
197 template < typename GUM_SCALAR >
199 const NodeId& varNodeId,
200 const InfluenceDiagram< GUM_SCALAR >& infdiag) {
201 //<DEFINITION>
202 //<FOR>var</FOR>
203 //<GIVEN>conditional var</GIVEN>
204 //<TABLE>conditional probabilities</TABLE>
205 //</DEFINITION>
206 std::stringstream str;
207
208 if (!((infdiag.isDecisionNode(varNodeId)) && (infdiag.parents(varNodeId).empty()))) {
209 // Declaration
210 str << "<DEFINITION>" << std::endl;
211
212 // Variable
213 str << "\t<FOR>" << infdiag.variable(varNodeId).name() << "</FOR>";
214
215 str << "<!--" << infdiag.variable(varNodeId).name() << " | ";
216 for (const auto n: infdiag.parents(varNodeId))
217 str << infdiag.variable(n).name() << ",";
218 str << "-->\n";
219
220 // Conditional Parents for decision node
221 if (infdiag.isDecisionNode(varNodeId)) {
222 // finding the parents in the graph
223 List< std::string > parentList;
224
225 for (const auto par: infdiag.parents(varNodeId))
226 parentList.pushBack(infdiag.variable(par).name());
227
228 for (auto parentListIte = parentList.rbegin(); parentListIte != parentList.rend();
229 --parentListIte)
230 str << "\t<GIVEN>" << (*parentListIte) << "</GIVEN>" << std::endl;
231 } else if (infdiag.isChanceNode(varNodeId)) // finding the parents in the cpt
232 for (Idx i = infdiag.cpt(varNodeId).nbrDim(); i > 1;
233 i--) // the first dimension is not a parent
234 str << "\t<GIVEN>" << infdiag.cpt(varNodeId).variable(i - 1).name() << "</GIVEN>"
235 << std::endl;
236 else if (infdiag.isUtilityNode(varNodeId)) // finding the parents in the utility
237 for (Idx i = infdiag.utility(varNodeId).nbrDim(); i > 1;
238 i--) // the first dimension is not a parent
239 str << "\t<GIVEN>" << infdiag.utility(varNodeId).variable(i - 1).name() << "</GIVEN>"
240 << std::endl;
241
242
243 if (infdiag.isChanceNode(varNodeId)) {
244 Instantiation inst(infdiag.cpt(varNodeId));
245 str << "\t<TABLE>";
246
247 for (inst.setFirst(); !inst.end(); inst.inc())
248 str << infdiag.cpt(varNodeId)[inst] << " ";
249
250 str << "</TABLE>" << std::endl;
251 } else if (infdiag.isUtilityNode(varNodeId)) {
252 // Values
253 Instantiation inst(infdiag.utility(varNodeId));
254 str << "\t<TABLE>";
255
256 for (inst.setFirst(); !inst.end(); inst.inc())
257 str << infdiag.utility(varNodeId)[inst] << " ";
258
259 str << "</TABLE>" << std::endl;
260 }
261
262 // Closing tag
263 str << "</DEFINITION>" << std::endl;
264 }
265
266 return str.str();
267 }
268
269 /*
270 * Returns the end of the BIF file.
271 */
272 template < typename GUM_SCALAR >
274 std::stringstream str;
275
276 str << "</NETWORK>" << std::endl;
277 str << "</BIF>" << std::endl;
278
279 return str.str();
280 }
281} /* namespace gum */
282
283#endif // DOXYGEN_SHOULD_SKIP_THIS
Definition file for BIF XML exportation class.
Writes an influence diagram in a XML files with BIF format.
virtual ~BIFXMLIDWriter()
Destructor.
std::string _heading_()
Returns the header of the BIF file.
std::string _variableBloc_(const DiscreteVariable &var, int nodeType)
Returns a bloc defining a variable in the BIF format.
BIFXMLIDWriter()
Default constructor.
std::string _variableDefinition_(const NodeId &varNodeId, const InfluenceDiagram< GUM_SCALAR > &infdiag)
Returns a bloc defining a variable's table (if she has) in the BIF format.
std::string _documentend_()
Returns the end of the BIF file.
virtual void write(std::ostream &output, const InfluenceDiagram< GUM_SCALAR > &infdiag)
Writes an influence diagram in the given ouput stream.
Base class for discrete random variable.
Class representing an Influence Diagram.
Class for assigning/browsing values to tuples of discrete variables.
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Definition list_tpl.h:1488
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46