aGrUM 3.2.0
a C++ library for (probabilistic) graphical models
GumBNWriter_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
42#pragma once
43
44#include <agrum/BN/io/GUM/GumBNWriter.h> // to ease IDE parser
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46
47// to ease parsing in IDE
52
53# include <agrum/base/external/json/json.hpp>
54using json = nlohmann::json;
55using ordered_json = nlohmann::ordered_json;
56
57namespace gum {
58 // Default constructor.
59 template < GUM_Numeric GUM_SCALAR >
60 GumBNWriter< GUM_SCALAR >::GumBNWriter(bool binary, int indent) : BNWriter< GUM_SCALAR >() {
61 _binary_ = binary;
62 _indent_ = (indent < -1) ? -1 : indent;
63 GUM_CONSTRUCTOR(GumBNWriter);
64 }
65
66 // Default destructor.
67 template < GUM_Numeric GUM_SCALAR >
68 GumBNWriter< GUM_SCALAR >::~GumBNWriter() {
69 GUM_DESTRUCTOR(GumBNWriter);
70 }
71
72 //
73 // Writes a Bayesian network in the output stream using the BN format.
74 //
75 // @param ouput The output stream.
76 // @param bn The Bayesian network writen in output.
77 // @throws Raised if an I/O error occurs.
78 template < GUM_Numeric GUM_SCALAR >
79 void GumBNWriter< GUM_SCALAR >::_doWrite(std::ostream& output,
80 const IBayesNet< GUM_SCALAR >& bn) {
81 if (!output.good()) GUM_ERROR(IOError, "Input/Output error : stream not writable.");
82
83 ordered_json content;
84 content["type"] = "BN";
85 content["GumJsonVersion"] = "1.0";
86
87 // add variables (always written, even empty, so the section always exists)
88 content["nodes"] = ordered_json::array();
89 for (const auto& node: bn.nodes()) {
90 content["nodes"].push_back(bn.variable(node).toFast());
91 }
92 // add parents (always written, even empty, so the section always exists)
93 content["parents"] = ordered_json::object();
94 auto& parentsObj = content["parents"].template get_ref< ordered_json::object_t& >();
95 parentsObj.reserve(bn.size());
96 for (const auto& node: bn.nodes()) {
97 ordered_json parentList = ordered_json::array();
98 const auto& cpt = bn.cpt(node);
99 for (Idx i = 1; i < cpt.nbrDim(); i++)
100 parentList.push_back(cpt.variable(i).name());
101 parentsObj.emplace_back(bn.variable(node).name(), std::move(parentList));
102 }
103 // add cpts (always written, even empty, so the section always exists)
104 content["cpt"] = ordered_json::object();
105 auto& cptObj = content["cpt"].template get_ref< ordered_json::object_t& >();
106 cptObj.reserve(bn.size());
107 for (const auto& node: bn.nodes()) {
108 const auto& cpt = bn.cpt(node);
109
110 if (const auto* agg
112 cpt.content())) {
113 std::string name = agg->aggregatorName();
114 const auto bracket = name.find('[');
115 if (bracket != std::string::npos) name.erase(bracket);
116
117 ordered_json aggJson;
118 aggJson["kind"] = "aggregator";
119 aggJson["name"] = name;
120 if (const auto value = agg->value()) aggJson["value"] = *value;
121
122 cptObj.emplace_back(bn.variable(node).name(), std::move(aggJson));
123 continue;
124 }
125
126 if (const auto* ici = dynamic_cast< const MultiDimICIModel< GUM_SCALAR >* >(cpt.content())) {
127 ordered_json weights = ordered_json::object();
128 for (Idx i = 1; i < cpt.nbrDim(); i++)
129 weights[cpt.variable(i).name()] = ici->causalWeight(cpt.variable(i));
130
131 ordered_json iciJson;
132 iciJson["kind"] = "ici";
133 iciJson["name"] = ici->name();
134 iciJson["externalWeight"] = ici->externalWeight();
135 iciJson["causalWeights"] = weights;
136
137 cptObj.emplace_back(bn.variable(node).name(), std::move(iciJson));
138 continue;
139 }
140
141 json cptValues;
142 Instantiation I(cpt);
143 for (I.setFirst(); !I.end(); ++I) {
144 cptValues.push_back(cpt[I]);
145 }
146 cptObj.emplace_back(bn.variable(node).name(), std::move(cptValues));
147 }
148 // add properties
149 for (const auto& prop: bn.properties()) {
150 content["properties"][prop] = bn.property(prop);
151 }
152
153 // write the content in the output stream
154 if (_binary_) {
155 // binary mode
156 _writeVector_(output, json::to_msgpack(content));
157 } else {
158 // text mode
159 output << content.dump(_indent_); // pretty print with 2 spaces indentation
160 }
161
162 if (output.fail()) {
163 GUM_ERROR(IOError, "Writing in the ostream failed. Check if the stream is writable.")
164 }
165 }
166
167 // Writes a Bayesian network in the referenced file using the BN format.
168 // If the file doesn't exists, it is created.
169 // If the file exists, it's content will be erased.
170 //
171 // @param filePath The path to the file used to write the Bayesian network.
172 // @param bn The Bayesian network writed in the file.
173 // @throws Raised if an I/O error occurs.
174 template < GUM_Numeric GUM_SCALAR >
175 void GumBNWriter< GUM_SCALAR >::_doWrite(std::string_view filePath,
176 const IBayesNet< GUM_SCALAR >& bn) {
177 std::ofstream output(std::string(filePath),
178 _binary_ ? (std::ios_base::trunc | std::ios::binary)
179 : std::ios_base::trunc);
180
181 _doWrite(output, bn);
182
183 output.close();
184 if (output.fail()) { GUM_ERROR(IOError, "Writing in the ostream failed.") }
185 }
186
187} // namespace gum
188#endif // DOXYGEN_SHOULD_SKIP_THIS
Definition of classe for GUM (json) file output manipulation.
Shared binary I/O helpers for GUM (jgum/bgum) serialization.
virtual class for writing a BN to a file.
Definition BNWriter.h:79
GumBNWriter(bool binary=false, int indent=-1)
Default constructor.
Exception : input/output problem.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
MultiDimAggregator.
Abstract base class for all multi dimensionnal Causal Independency models.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
GUM_SHARED_PUBLIC void _writeVector_(std::ostream &os, const std::vector< uint8_t > &vec)
Writes a length-prefixed byte vector to a binary stream (bgum format).