1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
4  *   info_at_agrum_dot_org
5  *
6  *  This library is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 #ifndef DOXYGEN_SHOULD_SKIP_THIS
23 
24 // to ease parsing in IDE
25 #  include <agrum/BN/io/cnf/GeneralizedCNFWriter.h>
26 
27 namespace gum {
28 
29   /* =========================================================================*/
30   /* ===                           GUM_BN_WRITER === */
31   /* =========================================================================*/
32   // Default constructor.
33   template < typename GUM_SCALAR, template < class > class IApproximationPolicy >
GeneralizedCNFWriter()34   INLINE GeneralizedCNFWriter< GUM_SCALAR, IApproximationPolicy >::GeneralizedCNFWriter() {
35     GUM_CONSTRUCTOR(GeneralizedCNFWriter);
36   }
37 
38   // Default destructor.
39   template < typename GUM_SCALAR, template < class > class IApproximationPolicy >
~GeneralizedCNFWriter()40   INLINE GeneralizedCNFWriter< GUM_SCALAR, IApproximationPolicy >::~GeneralizedCNFWriter() {
41     GUM_DESTRUCTOR(GeneralizedCNFWriter);
42   }
43 
44   //
45   // Writes a Bayesian network in the output stream using the BN format.
46   //
47   // @param ouput The output stream.
48   // @param bn The Bayesian network writen in output.
49   // @throws Raised if an I/O error occurs.
50   template < typename GUM_SCALAR, template < class > class IApproximationPolicy >
write(std::ostream & output,const IBayesNet<GUM_SCALAR> & bn)51   INLINE void GeneralizedCNFWriter< GUM_SCALAR, IApproximationPolicy >::write(
52      std::ostream&                  output,
53      const IBayesNet< GUM_SCALAR >& bn) {
54     if (!output.good()) GUM_ERROR(IOError, "Stream states flags are not all unset.")
55 
56     std::stringstream strfile, strfile2;
57 
58     Size num      = 0;
59     Size numparam = 0;
60 
61     for (auto node: bn.nodes())
62       numparam += bn.variable(node).domainSize();
63 
64     Idx                                clause = 0;
65     std::stringstream                  clausstr;
66     gum::HashTable< std::string, Idx > vartable;   // key name::label val num;
67     gum::HashTable< std::string, Idx > protable;
68 
69     for (auto node: bn.nodes()) {
70       const auto& var = bn.variable(node);
71 
72       for (Idx i = 0; i < var.domainSize(); i++) {
73         std::stringstream str;
74         str << var.name() << "_" << var.label(i);
75         vartable.insert(str.str(), ++num);
76         strfile << num << "::" << str.str() << "\n";
77       }
78 
79       const Potential< GUM_SCALAR >& cpt = bn.cpt(node);
80 
81       Instantiation inst(cpt);
82 
83       for (inst.setFirst(); !inst.end(); ++inst) {
84         std::stringstream strinst;
85         strinst << inst.toString();
86         strinst << "_val=" << this->fromExact(cpt[inst]);
87 
88         protable.insert(inst.toString(), ++numparam);
89         strfile2 << numparam << "::" << strinst.str() << "\n";
90       }
91     }
92 
93     for (auto node: bn.nodes()) {
94       const auto&       var = bn.variable(node);
95       std::stringstream str0, str1, str2, str3;
96 
97       for (Idx i = 0; i < var.domainSize(); i++) {
98         std::stringstream stri;   //= bn.variable(iter).name()+"_"+
99         // bn.variable(iter).label( i ) ;
100         stri << var.name() << "_" << var.label(i);
101         str0 << vartable[stri.str()] << " ";
102 
103         for (Idx j = i + 1; j < var.domainSize(); j++) {
104           std::stringstream strj;
105           strj << var.name() << "_" << var.label(j);
106           str1 << "-" << vartable[stri.str()] << " -" << vartable[strj.str()] << " 0\n";
107           clause++;
108         }
109       }
110 
111       str0 << "0\n";
112       clause++;
113       clausstr << str0.str() << str1.str();
114       const Potential< GUM_SCALAR >& cpt = bn.cpt(node);
115       Instantiation                  inst(cpt);
116 
117       for (inst.setFirst(); !inst.end(); ++inst) {
118         for (Idx i = 0; i < inst.nbrDim(); i++) {
119           std::stringstream str;
120           str << inst.variable(i).name() << "_" << inst.val(inst.variable(i));
121           str2 << "-" << vartable[str.str()] << " ";
122           str3 << "-" << protable[inst.toString()] << " " << vartable[str.str()] << " 0\n";
123           clause++;
124         }
125 
126         str2 << protable[inst.toString()] << " 0\n";
127         clause++;
128       }
129 
130       clausstr << str2.str() << str3.str();
131     }
132 
133     output << "p cnf " << num + numparam << " " << clause << "\n" << clausstr.str() << std::endl;
134     output.flush();
135   }
136 
137   // Writes a Bayesian network in the referenced file using the BN format.
138   // If the file doesn't exists, it is created.
139   // If the file exists, it's content will be erased.
140   //
141   // @param filePath The path to the file used to write the Bayesian network.
142   // @param bn The Bayesian network writed in the file.
143   // @throws Raised if an I/O error occurs.
144   template < typename GUM_SCALAR, template < class > class IApproximationPolicy >
write(const std::string & filePath,const IBayesNet<GUM_SCALAR> & bn)145   INLINE void GeneralizedCNFWriter< GUM_SCALAR, IApproximationPolicy >::write(
146      const std::string&             filePath,
147      const IBayesNet< GUM_SCALAR >& bn) {
148     std::ofstream output(filePath.c_str(), std::ios_base::trunc);
149     std::ofstream outputvar((filePath + ".var").c_str(), std::ios_base::trunc);
150 
151     if (!output.good()) GUM_ERROR(IOError, "Stream states flags are not all unset.")
152 
153     std::stringstream strfile, strfile2;
154 
155     if (!outputvar.good()) GUM_ERROR(IOError, "Stream states flags are not all unset.")
156 
157     Idx num      = 0;
158     Idx numparam = 0;
159 
160     for (auto node: bn.nodes())
161       numparam += bn.variable(node).domainSize();
162 
163     Idx                                clause = 0;
164     std::stringstream                  clausstr;
165     gum::HashTable< std::string, Idx > vartable;   // key name::label val num;
166     gum::HashTable< std::string, Idx > protable;
167 
168     for (auto node: bn.nodes()) {
169       const auto& var = bn.variable(node);
170 
171       for (Idx i = 0; i < var.domainSize(); i++) {
172         std::stringstream str;
173         str << var.name() << "_" << var.label(i);
174         vartable.insert(str.str(), ++num);
175         strfile << num << "::" << str.str() << "\n";
176       }
177 
178       const Potential< GUM_SCALAR >& cpt = bn.cpt(node);
179 
180       Instantiation inst(cpt);
181 
182       for (inst.setFirst(); !inst.end(); ++inst) {
183         std::stringstream strinst;
184         strinst << inst.toString();
185         strinst << "_val=" << this->fromExact(cpt[inst]);
186 
187         protable.insert(inst.toString(), ++numparam);
188         strfile2 << numparam << "::" << strinst.str() << "\n";
189       }
190     }
191 
192     for (auto node: bn.nodes()) {
193       const auto&       var = bn.variable(node);
194       std::stringstream str0, str1, str2, str3;
195 
196       for (Idx i = 0; i < var.domainSize(); i++) {
197         std::stringstream stri;   //= bn.variable(iter).name()+"_"+
198         // bn.variable(iter).label( i ) ;
199         stri << var.name() << "_" << var.label(i);
200         str0 << vartable[stri.str()] << " ";
201 
202         for (Idx j = i + 1; j < var.domainSize(); j++) {
203           std::stringstream strj;
204           strj << var.name() << "_" << var.label(j);
205           str1 << "-" << vartable[stri.str()] << " -" << vartable[strj.str()] << " 0\n";
206           clause++;
207         }
208       }
209 
210       str0 << "0\n";
211       clause++;
212       clausstr << str0.str() << str1.str();
213       const Potential< GUM_SCALAR >& cpt = bn.cpt(node);
214       Instantiation                  inst(cpt);
215 
216       for (inst.setFirst(); !inst.end(); ++inst) {
217         for (Idx i = 0; i < inst.nbrDim(); i++) {
218           std::stringstream str;
219           str << inst.variable(i).name() << "_" << inst.val(inst.variable(i));
220           str2 << "-" << vartable[str.str()] << " ";
221           str3 << "-" << protable[inst.toString()] << " " << vartable[str.str()] << " 0\n";
222           clause++;
223         }
224 
225         str2 << protable[inst.toString()] << " 0\n";
226         clause++;
227       }
228 
229       clausstr << str2.str() << str3.str();
230     }
231 
232     output << "p cnf " << num + numparam << " " << clause << "\n" << clausstr.str() << std::endl;
233     output.flush();
234     outputvar << strfile.str() << strfile2.str();
235     outputvar.flush();
236     outputvar.close();
237     output.close();
238 
239     if (outputvar.fail()) GUM_ERROR(IOError, "Writting in the ostream failed.")
240 
241     if (output.fail()) GUM_ERROR(IOError, "Writting in the ostream failed.")
242   }
243 
244   // Returns a bloc defining a variable's CPT in the BN format.
245   /*template<typename GUM_SCALAR, template<class> class IApproximationPolicy >
246   INLINE
247     std::string
248     CNFWriter<GUM_SCALAR>:: _variableCPT_( const Potential<GUM_SCALAR>& cpt ) {
249     std::stringstream str;
250     str << "";
251     return str.str();
252     }
253 
254   // Returns the header of the BN file.
255   template<typename GUM_SCALAR,> INLINE
256   std::string
257   CNFWriter<GUM_SCALAR>:: _header_( const IBayesNet<GUM_SCALAR>& ) {
258   std::stringstream str;
259   str << "";
260   return str.str();
261   }
262 
263   // Returns a bloc defining a variable in the BN format.
264   template<typename GUM_SCALAR> INLINE
265   std::string
266   CNFWriter<GUM_SCALAR>:: _variableBloc_( const DiscreteVariable& var ) {
267   std::stringstream str;
268   str << "" ;
269   return str.str();
270   }*/
271 
272   // Returns the modalities labels of the variables in varsSeq
273 
274 } /* namespace gum */
275 
276 #endif   // DOXYGEN_SHOULD_SKIP_THIS
277