aGrUM 3.0.0
a C++ library for (probabilistic) graphical models
GumBNReader_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/GumBNReader.h> // to ease IDE parser
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46
47// to ease parsing in IDE
50
51# include <agrum/base/external/json/json.hpp>
52using json = nlohmann::json;
53
54namespace gum {
55 template < GUM_Numeric GUM_SCALAR >
57 std::string_view filename,
58 bool binary) : BNReader< GUM_SCALAR >(bn, filename) {
59 GUM_CONSTRUCTOR(GumBNReader)
60 _bn_ = bn;
61 _streamName_ = filename;
62 _parseDone_ = false;
63 _binary_ = binary;
64 }
65
66 template < GUM_Numeric GUM_SCALAR >
67 GumBNReader< GUM_SCALAR >::GumBNReader(BayesNet< GUM_SCALAR >* bn) :
68 BNReader< GUM_SCALAR >(bn, "") {
69 GUM_CONSTRUCTOR(GumBNReader)
70 _bn_ = bn;
71 _streamName_ = "";
72 _parseDone_ = false;
73 _binary_ = false;
74 }
75
76 template < GUM_Numeric GUM_SCALAR >
77 GumBNReader< GUM_SCALAR >::~GumBNReader() {
78 GUM_DESTRUCTOR(GumBNReader)
79 }
80
81 template < GUM_Numeric GUM_SCALAR >
82 template < typename JsonType >
83 Size GumBNReader< GUM_SCALAR >::_proceedFromJson_(const JsonType& content) {
84 Size nberrors = 0;
85
86 if (content.contains("type") && content["type"].template get< std::string >() != "BN") {
87 addError("Invalid GUM file format: expected 'BN' type, got '"
88 + content["type"].template get< std::string >() + "'",
89 _streamName_,
90 0,
91 0);
92 return ++nberrors;
93 }
94
95 if (!content.contains("nodes") || !content.contains("parents") || !content.contains("cpt")) {
96 addError("Invalid GUM file format: missing 'nodes', 'parents' or 'cpt' sections",
97 _streamName_,
98 0,
99 0);
100 return ++nberrors;
101 }
102
103 try {
104 BayesNet< GUM_SCALAR > tmp;
105 // iterate on nodes in json
106 for (const auto& node: content["nodes"]) {
107 tmp.add(node.template get< std::string >());
108 }
109 // iterate on parents in json
110 for (const auto& parent: content["parents"].items()) {
111 const auto& nodeName = parent.key();
112 for (const auto& p: parent.value()) {
113 tmp.addArc(p.template get< std::string >(), nodeName);
114 }
115 }
116 // iterate on cpt in json
117 for (const auto& cpt: content["cpt"].items()) {
118 const auto& nodeName = cpt.key();
119 const auto& values = cpt.value();
120 tmp.cpt(nodeName).fillWith(values.template get< std::vector< double > >());
121 }
122 // iterate on properties in json (optional section)
123 if (content.contains("properties")) {
124 for (const auto& prop: content["properties"].items()) {
125 tmp.setProperty(prop.key(), prop.value().template get< std::string >());
126 }
127 }
128 *_bn_ = std::move(tmp);
129 _parseDone_ = true;
130 } catch (const gum::Exception& e) {
131 addError(e.errorContent(), _streamName_, 0, 0);
132 return ++nberrors;
133 }
134 return nberrors;
135 }
136
137 template < GUM_Numeric GUM_SCALAR >
138 Size GumBNReader< GUM_SCALAR >::proceed() {
139 if (_parseDone_) { return 0; }
140 if (_streamName_.empty()) {
142 "GumBNReader was constructed without a filename: use proceedFromString() instead "
143 "of proceed()")
144 }
145 Size nberrors = 0;
146
147 std::ifstream file(_streamName_, _binary_ ? std::ios::binary : std::ios::in);
148 if (!file.is_open()) {
149 addException("No such file " + _streamName_, _streamName_);
150 return ++nberrors;
151 }
152 try {
153 const auto content
154 = _binary_ ? json::from_msgpack(_readVector_(file)) : json::parse(file, nullptr, false);
155 file.close();
156 if (content.is_discarded()) {
157 addException("Error parsing file", _streamName_);
158 return ++nberrors;
159 }
160 return _proceedFromJson_(content);
161 } catch (const std::exception& e) {
162 addException(std::string("Error reading binary file: ") + e.what(), _streamName_);
163 return ++nberrors;
164 }
165 }
166
167 template < GUM_Numeric GUM_SCALAR >
168 Size GumBNReader< GUM_SCALAR >::proceedFromString(std::string_view content) {
169 if (_parseDone_) { return 0; }
170 const auto j = json::parse(content, nullptr, false);
171 if (j.is_discarded()) {
172 addException("Invalid JSON string", _streamName_);
173 return 1;
174 }
175 return _proceedFromJson_(j);
176 }
177
178 template < GUM_Numeric GUM_SCALAR >
179 void GumBNReader< GUM_SCALAR >::showElegantErrorsAndWarnings(std::ostream& stream) const {
180 if (_parseDone_ || count() > 0) elegantErrorsAndWarnings(stream);
181 else { GUM_ERROR(OperationNotAllowed, "File not parsed yet") }
182 }
183
184 template < GUM_Numeric GUM_SCALAR >
185 void GumBNReader< GUM_SCALAR >::showErrorCounts(std::ostream& stream) const {
186 if (_parseDone_ || count() > 0) syntheticResults(stream);
187 else { GUM_ERROR(OperationNotAllowed, "File not parsed yet") }
188 }
189} // namespace gum
190
191#endif // DOXYGEN_SHOULD_SKIP_THIS
Shared binary I/O helpers for GUM (jgum/bgum) serialization.
Pure virtual class for reading a BN from a file.
Definition BNReader.h:78
Class representing a Bayesian network.
Definition BayesNet.h:93
Base class for all aGrUM's exceptions.
Definition exceptions.h:122
GUM_NODISCARD std::string errorContent() const
Returns the message content.
GumBNReader(BayesNet< GUM_SCALAR > *bn, std::string_view filename, bool binary=false)
Constructor A reader is defined for reading a defined file.
Exception : operation not allowed.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::vector< uint8_t > _readVector_(std::istream &is)
Reads a length-prefixed byte vector from a binary stream (bgum format).