Cleaned up example_imagesegmentation
[libdai.git] / utils / createfg.cpp
1 /* This file is part of libDAI - http://www.libdai.org/
2 *
3 * libDAI is licensed under the terms of the GNU General Public License version
4 * 2, or (at your option) any later version. libDAI is distributed without any
5 * warranty. See the file COPYING for more details.
6 *
7 * Copyright (C) 2006-2010 Joris Mooij [joris dot mooij at libdai dot org]
8 * Copyright (C) 2006-2007 Radboud University Nijmegen, The Netherlands
9 */
10
11
12 #include <iostream>
13 #include <fstream>
14 #include <vector>
15 #include <iterator>
16 #include <algorithm>
17 #include <boost/program_options.hpp>
18 #include <dai/factorgraph.h>
19 #include <dai/weightedgraph.h>
20 #include <dai/util.h>
21 #include <dai/graph.h>
22 #include <dai/enum.h>
23 #include <dai/properties.h>
24
25
26 using namespace std;
27 using namespace dai;
28 namespace po = boost::program_options;
29
30
31 /// Possible factor types
32 DAI_ENUM(FactorType,ISINGGAUSS,ISINGUNIFORM,EXPGAUSS,POTTS);
33
34
35 /// Creates a factor graph from a pairwise interactions graph
36 /** \param G Graph describing interactions between variables
37 * \param ft Type of factors to use for interactions
38 * \param states Number of states of the variables
39 * \param props Additional properties for generating the interactions
40 */
41 FactorGraph createFG( const GraphAL &G, FactorType ft, size_t states, const PropertySet &props ) {
42 size_t N = G.nrNodes();
43
44 if( states > 2 )
45 DAI_ASSERT( ft != FactorType::ISINGGAUSS && ft != FactorType::ISINGUNIFORM );
46
47 // Get inverse temperature
48 Real beta = 1.0;
49 if( ft != FactorType::ISINGGAUSS && ft != FactorType::ISINGUNIFORM )
50 beta = props.getAs<Real>("beta");
51
52 // Get properties for Ising factors
53 Real mean_h = 0.0;
54 Real sigma_h = 0.0;
55 Real mean_J = 0.0;
56 Real sigma_J = 0.0;
57 if( ft == FactorType::ISINGGAUSS ) {
58 mean_h = props.getAs<Real>("mean_th");
59 sigma_h = props.getAs<Real>("sigma_th");
60 mean_J = props.getAs<Real>("mean_w");
61 sigma_J = props.getAs<Real>("sigma_w");
62 }
63 Real min_h = 0.0;
64 Real min_J = 0.0;
65 Real max_h = 0.0;
66 Real max_J = 0.0;
67 if( ft == FactorType::ISINGUNIFORM ) {
68 min_h = props.getAs<Real>("min_th");
69 min_J = props.getAs<Real>("min_w");
70 max_h = props.getAs<Real>("max_th");
71 max_J = props.getAs<Real>("max_w");
72 }
73
74 // Create variables
75 vector<Var> vars;
76 vars.reserve( N );
77 for( size_t i = 0; i < N; i++ )
78 vars.push_back( Var( i, states ) );
79
80 // Create factors
81 vector<Factor> factors;
82 factors.reserve( G.nrEdges() + N );
83 // Pairwise factors
84 for( size_t i = 0; i < N; i++ )
85 foreach( const GraphAL::Neighbor &j, G.nb(i) )
86 if( i < j ) {
87 if( ft == FactorType::POTTS )
88 factors.push_back( createFactorPotts( vars[i], vars[j], beta ) );
89 else if( ft == FactorType::EXPGAUSS )
90 factors.push_back( createFactorExpGauss( VarSet( vars[i], vars[j] ), beta ) );
91 else if( ft == FactorType::ISINGGAUSS ) {
92 Real J = rnd_stdnormal() * sigma_J + mean_J;
93 factors.push_back( createFactorIsing( vars[i], vars[j], J ) );
94 } else if( ft == FactorType::ISINGUNIFORM ) {
95 Real J = min_J + rnd_uniform() * (max_J - min_J);
96 factors.push_back( createFactorIsing( vars[i], vars[j], J ) );
97 }
98 }
99 // Unary factors
100 if( ft == FactorType::ISINGGAUSS )
101 for( size_t i = 0; i < N; i++ ) {
102 Real h = rnd_stdnormal() * sigma_h + mean_h;
103 factors.push_back( createFactorIsing( vars[i], h ) );
104 }
105 else if( ft == FactorType::ISINGUNIFORM )
106 for( size_t i = 0; i < N; i++ ) {
107 Real h = min_h + rnd_uniform() * (max_h - min_h);
108 factors.push_back( createFactorIsing( vars[i], h ) );
109 }
110
111 return FactorGraph( factors.begin(), factors.end(), vars.begin(), vars.end(), factors.size(), vars.size() );
112 }
113
114
115 /// Return a random factor graph with higher-order interactions
116 /** \param N number of variables
117 * \param M number of factors
118 * \param k number of variables that each factor depends on
119 * \param beta standard-deviation of Gaussian log-factor entries
120 */
121 FactorGraph createHOIFG( size_t N, size_t M, size_t k, Real beta ) {
122 vector<Var> vars;
123 vector<Factor> factors;
124
125 vars.reserve(N);
126 for( size_t i = 0; i < N; i++ )
127 vars.push_back(Var(i,2));
128
129 for( size_t I = 0; I < M; I++ ) {
130 VarSet vars;
131 while( vars.size() < k ) {
132 do {
133 size_t newind = (size_t)(N * rnd_uniform());
134 Var newvar = Var(newind, 2);
135 if( !vars.contains( newvar ) ) {
136 vars |= newvar;
137 break;
138 }
139 } while( 1 );
140 }
141 factors.push_back( createFactorExpGauss( vars, beta ) );
142 }
143
144 return FactorGraph( factors.begin(), factors.end(), vars.begin(), vars.end(), factors.size(), vars.size() );
145 }
146
147
148 /// Creates a regular random bipartite graph
149 /** \param N1 = number of nodes of type 1
150 * \param d1 = size of neighborhoods of nodes of type 1
151 * \param N2 = number of nodes of type 2
152 * \param d2 = size of neighborhoods of nodes of type 2
153 * \note asserts that N1 * d1 == N2 * d2
154 */
155 BipartiteGraph createRandomBipartiteGraph( size_t N1, size_t N2, size_t d1, size_t d2 ) {
156 BipartiteGraph G;
157
158 DAI_ASSERT( N1 * d1 == N2 * d2 );
159
160 // build lists of degree-repeated vertex numbers
161 std::vector<size_t> stubs1( N1*d1, 0 );
162 for( size_t n1 = 0; n1 < N1; n1++ )
163 for( size_t t = 0; t < d1; t++ )
164 stubs1[n1*d1 + t] = n1;
165
166 // build lists of degree-repeated vertex numbers
167 std::vector<size_t> stubs2( N2*d2, 0 );
168 for( size_t n2 = 0; n2 < N2; n2++ )
169 for( size_t t = 0; t < d2; t++ )
170 stubs2[n2*d2 + t] = n2;
171
172 // shuffle lists
173 random_shuffle( stubs1.begin(), stubs1.end() );
174 random_shuffle( stubs2.begin(), stubs2.end() );
175
176 // add edges
177 vector<BipartiteGraph::Edge> edges;
178 edges.reserve( N1*d1 );
179 for( size_t e = 0; e < N1*d1; e++ )
180 edges.push_back( BipartiteGraph::Edge(stubs1[e], stubs2[e]) );
181
182 // finish construction
183 G.construct( N1, N2, edges.begin(), edges.end() );
184
185 return G;
186 }
187
188
189 /// Returns x**n % p, assuming p is prime
190 int powmod (int x, int n, int p) {
191 int y = 1;
192 for( int m = 0; m < n; m++ )
193 y = (x * y) % p;
194 return y;
195 }
196
197
198 /// Returns order of x in GF(p) with p prime
199 size_t order (int x, int p) {
200 x = x % p;
201 DAI_ASSERT( x != 0 );
202 size_t n = 0;
203 size_t prod = 1;
204 do {
205 prod = (prod * x) % p;
206 n++;
207 } while( prod != 1 );
208 return n;
209 }
210
211
212 /// Returns whether n is a prime number
213 bool isPrime (size_t n) {
214 bool result = true;
215 for( size_t k = 2; (k < n) && result; k++ )
216 if( n % k == 0 )
217 result = false;
218 return result;
219 }
220
221
222 /// Constructs a regular LDPC graph with N=6, j=2, K=4, k=3
223 BipartiteGraph createSmallLDPCGraph() {
224 BipartiteGraph G;
225 size_t N=4, j=3, K=4; // k=3;
226
227 typedef BipartiteGraph::Edge Edge;
228 vector<Edge> edges;
229 edges.reserve( N*j );
230 edges.push_back( Edge(0,0) ); edges.push_back( Edge(1,0) ); edges.push_back( Edge(2,0) );
231 edges.push_back( Edge(0,1) ); edges.push_back( Edge(1,1) ); edges.push_back( Edge(3,1) );
232 edges.push_back( Edge(0,2) ); edges.push_back( Edge(2,2) ); edges.push_back( Edge(3,2) );
233 edges.push_back( Edge(1,3) ); edges.push_back( Edge(2,3) ); edges.push_back( Edge(3,3) );
234
235 // finish construction
236 G.construct( N, K, edges.begin(), edges.end() );
237
238 return G;
239 }
240
241
242 /// Creates group-structured LDPC code
243 /** Use construction described in "A Class of Group-Structured LDPC Codes"
244 * by R. M. Tanner, D. Sridhara and T. Fuja
245 * Proceedings of ICSTA, 2001
246 *
247 * Example parameters: (p,j,k) = (31,3,5)
248 * (p,j,k) = (37,3,4)
249 * (p,j,k) = (7,2,4)
250 * (p,j,k) = (29,2,4)
251 *
252 * j and k must be divisors of p-1
253 */
254 BipartiteGraph createGroupStructuredLDPCGraph( size_t p, size_t j, size_t k ) {
255 BipartiteGraph G;
256
257 size_t n = j;
258 size_t N = p * k;
259 size_t K = p * j;
260
261 size_t a, b;
262 for( a = 2; a < p; a++ )
263 if( order(a,p) == k )
264 break;
265 DAI_ASSERT( a != p );
266 for( b = 2; b < p; b++ )
267 if( order(b,p) == j )
268 break;
269 DAI_ASSERT( b != p );
270 // cout << "# order(a=" << a << ") = " << order(a,p) << endl;
271 // cout << "# order(b=" << b << ") = " << order(b,p) << endl;
272
273 DAI_ASSERT( N * n == K * k );
274
275 typedef BipartiteGraph::Edge Edge;
276 vector<Edge> edges;
277 edges.reserve( N * n );
278
279 for( size_t s = 0; s < j; s++ )
280 for( size_t t = 0; t < k; t++ ) {
281 size_t P = (powmod(b,s,p) * powmod(a,t,p)) % p;
282 for( size_t m = 0; m < p; m++ )
283 edges.push_back( Edge(t*p + m, s*p + ((m + P) % p)) );
284 }
285
286 // finish construction
287 G.construct( N, K, edges.begin(), edges.end() );
288
289 return G;
290 }
291
292
293 // Constructs a parity check table
294 void createParityCheck( Real *result, size_t n, Real eps ) {
295 size_t N = 1 << n;
296 for( size_t i = 0; i < N; i++ ) {
297 size_t c = 0;
298 for( size_t t = 0; t < n; t++ )
299 if( i & (1 << t) )
300 c ^= 1;
301 if( c )
302 result[i] = eps;
303 else
304 result[i] = 1.0 - eps;
305 }
306 return;
307 }
308
309
310 /// Predefined names of various factor graph types
311 const char *FULL_TYPE = "FULL";
312 const char *DREG_TYPE = "DREG";
313 const char *LOOP_TYPE = "LOOP";
314 const char *TREE_TYPE = "TREE";
315 const char *GRID_TYPE = "GRID";
316 const char *GRID3D_TYPE = "GRID3D";
317 const char *HOI_TYPE = "HOI";
318 const char *LDPC_TYPE = "LDPC";
319
320
321 /// Possible LDPC structures
322 DAI_ENUM(LDPCType,SMALL,GROUP,RANDOM);
323
324
325 /// Main function
326 int main( int argc, char *argv[] ) {
327 try {
328 // Variables for storing command line arguments
329 size_t seed;
330 size_t states = 2;
331 string type;
332 size_t d, N, K, k, j, n1, n2, n3, prime;
333 bool periodic = false;
334 FactorType ft;
335 LDPCType ldpc;
336 Real beta, sigma_w, sigma_th, mean_w, mean_th, min_w, min_th, max_w, max_th, noise;
337
338 // Declare the supported options.
339 po::options_description opts("General command line options");
340 opts.add_options()
341 ("help", "produce help message")
342 ("seed", po::value<size_t>(&seed), "random number seed (tries to read from /dev/urandom if not specified)")
343 ("states", po::value<size_t>(&states), "number of states of each variable (default=2 for binary variables)")
344 ;
345
346 // Graph structure options
347 po::options_description opts_graph("Options for specifying graph structure");
348 opts_graph.add_options()
349 ("type", po::value<string>(&type), "factor graph type (one of 'FULL', 'DREG', 'LOOP', 'TREE', 'GRID', 'GRID3D', 'HOI', 'LDPC')")
350 ("d", po::value<size_t>(&d), "variable connectivity (only for type=='DREG');\n\t<d><N> should be even")
351 ("N", po::value<size_t>(&N), "number of variables (not for type=='GRID','GRID3D')")
352 ("n1", po::value<size_t>(&n1), "width of grid (only for type=='GRID','GRID3D')")
353 ("n2", po::value<size_t>(&n2), "height of grid (only for type=='GRID','GRID3D')")
354 ("n3", po::value<size_t>(&n3), "length of grid (only for type=='GRID3D')")
355 ("periodic", po::value<bool>(&periodic), "periodic grid? (only for type=='GRID','GRID3D'; default=0)")
356 ("K", po::value<size_t>(&K), "number of factors (only for type=='HOI','LDPC')")
357 ("k", po::value<size_t>(&k), "number of variables per factor (only for type=='HOI','LDPC')")
358 ;
359
360 // Factor options
361 po::options_description opts_factors("Options for specifying factors");
362 opts_factors.add_options()
363 ("factors", po::value<FactorType>(&ft), "factor type (one of 'EXPGAUSS','POTTS','ISINGGAUSS','ISINGUNIFORM')")
364 ("beta", po::value<Real>(&beta), "inverse temperature (ignored for factors=='ISINGGAUSS','ISINGUNIFORM')")
365 ("mean_w", po::value<Real>(&mean_w), "mean of pairwise interactions w_{ij} (only for factors=='ISINGGAUSS')")
366 ("mean_th", po::value<Real>(&mean_th), "mean of unary interactions th_i (only for factors=='ISINGGAUSS')")
367 ("sigma_w", po::value<Real>(&sigma_w), "stddev of pairwise interactions w_{ij} (only for factors=='ISINGGAUSS')")
368 ("sigma_th", po::value<Real>(&sigma_th), "stddev of unary interactions th_i (only for factors=='ISINGGAUSS'")
369 ("min_w", po::value<Real>(&min_w), "minimum of pairwise interactions w_{ij} (only for factors=='ISINGUNIFORM')")
370 ("min_th", po::value<Real>(&min_th), "minimum of unary interactions th_i (only for factors=='ISINGUNIFORM')")
371 ("max_w", po::value<Real>(&max_w), "maximum of pairwise interactions w_{ij} (only for factors=='ISINGUNIFORM')")
372 ("max_th", po::value<Real>(&max_th), "maximum of unary interactions th_i (only for factors=='ISINGUNIFORM')")
373 ;
374
375 // LDPC options
376 po::options_description opts_ldpc("Options for specifying LDPC code factor graphs");
377 opts_ldpc.add_options()
378 ("ldpc", po::value<LDPCType>(&ldpc), "type of LDPC code (one of 'SMALL','GROUP','RANDOM')")
379 ("j", po::value<size_t>(&j), "number of parity checks per bit (only for type=='LDPC')")
380 ("noise", po::value<Real>(&noise), "bitflip probability for binary symmetric channel (only for type=='LDPC')")
381 ("prime", po::value<size_t>(&prime), "prime number for construction of LDPC code (only for type=='LDPC' with ldpc='GROUP'))")
382 ;
383
384 // All options
385 opts.add(opts_graph).add(opts_factors).add(opts_ldpc);
386
387 // Parse command line arguments
388 po::variables_map vm;
389 po::store(po::parse_command_line(argc, argv, opts), vm);
390 po::notify(vm);
391
392 // Display help message if necessary
393 if( vm.count("help") || !vm.count("type") ) {
394 cout << "This program is part of libDAI - http://www.libdai.org/" << endl << endl;
395 cout << "Usage: ./createfg [options]" << endl << endl;
396 cout << "Creates a factor graph according to the specified options." << endl << endl;
397
398 cout << endl << opts << endl;
399
400 cout << "The following factor graph types with pairwise interactions can be created:" << endl;
401 cout << "\t'FULL': fully connected graph of <N> variables" << endl;
402 cout << "\t'DREG': random regular graph of <N> variables where each variable is connected with <d> others" << endl;
403 cout << "\t'LOOP': a single loop of <N> variables" << endl;
404 cout << "\t'TREE': random tree-structured (acyclic, connected) graph of <N> variables" << endl;
405 cout << "\t'GRID': 2D grid of <n1>x<n2> variables" << endl;
406 cout << "\t'GRID3D': 3D grid of <n1>x<n2>x<n3> variables" << endl;
407 cout << "The following higher-order interactions factor graphs can be created:" << endl;
408 cout << "\t'HOI': random factor graph consisting of <N> variables and <K> factors," << endl;
409 cout << "\t each factor being an interaction of <k> variables." << endl;
410 cout << "The following LDPC code factor graphs can be created:" << endl;
411 cout << "\t'LDPC': simulates LDPC decoding problem, using an LDPC code of <N> bits and <K>" << endl;
412 cout << "\t parity checks, with <k> bits per check and <j> checks per bit, transmitted" << endl;
413 cout << "\t on a binary symmetric channel with probability <noise> of flipping a bit." << endl;
414 cout << "\t The transmitted codeword has all bits set to zero. The argument 'ldpc'" << endl;
415 cout << "\t determines how the LDPC code is constructed: either using a group structure," << endl;
416 cout << "\t or randomly, or a fixed small code with (N,K,k,j) = (4,4,3,3)." << endl << endl;
417
418 cout << "For all types except type=='LDPC', the factors have to be specified as well." << endl << endl;
419
420 cout << "EXPGAUSS factors (the default) are created by drawing all log-factor entries" << endl;
421 cout << "independently from a Gaussian with mean 0 and standard deviation <beta>." << endl << endl;
422
423 cout << "In case of pairwise interactions, one can also choose POTTS factors, for which" << endl;
424 cout << "the log-factors are simply delta functions multiplied by the strength <beta>." << endl << endl;
425
426 cout << "For pairwise interactions and binary variables, one can also use ISINGGAUSS factors." << endl;
427 cout << "Here variables x1...xN are assumed to be +1/-1--valued, and unary interactions" << endl;
428 cout << "are of the form exp(th*xi) with th drawn from a Gaussian distribution with mean" << endl;
429 cout << "<mean_th> and standard deviation <sigma_th>, and pairwise interactions are of the" << endl;
430 cout << "form exp(w*xi*xj) with w drawn from a Gaussian distribution with mean <mean_w>" << endl;
431 cout << "and standard deviation <sigma_w>." << endl;
432 cout << "Alternatively, one can use ISINGUNIFORM factors: here th is drawn from a uniform" << endl;
433 cout << "distribution on [<min_th>, <max_th>), and w is drawn from a uniform distribution" << endl;
434 cout << "on [<min_w>, <max_w>)." << endl;
435 return 1;
436 }
437
438 // Set default number of states
439 if( !vm.count("states") )
440 states = 2;
441
442 // Set default factor type
443 if( !vm.count("factors") )
444 ft = FactorType::EXPGAUSS;
445 // Check validness of factor type
446 if( ft == FactorType::POTTS )
447 if( type == HOI_TYPE )
448 throw "For factors=='POTTS', interactions should be pairwise (type!='HOI')";
449 if( ft == FactorType::ISINGGAUSS )
450 if( ((states != 2) || (type == HOI_TYPE)) )
451 throw "For factors=='ISINGGAUSS', variables should be binary (states==2) and interactions should be pairwise (type!='HOI')";
452 if( ft == FactorType::ISINGUNIFORM )
453 if( ((states != 2) || (type == HOI_TYPE)) )
454 throw "For factors=='ISINGUNIFORM', variables should be binary (states==2) and interactions should be pairwise (type!='HOI')";
455
456 // Read random seed
457 if( !vm.count("seed") ) {
458 ifstream infile;
459 bool success;
460 infile.open( "/dev/urandom" );
461 success = infile.is_open();
462 if( success ) {
463 infile.read( (char *)&seed, sizeof(size_t) / sizeof(char) );
464 success = infile.good();
465 infile.close();
466 }
467 if( !success )
468 throw "Please specify random number seed.";
469 }
470 rnd_seed( seed );
471
472 // Set default periodicity
473 if( !vm.count("periodic") )
474 periodic = false;
475
476 // Store some options in a PropertySet object
477 PropertySet options;
478 if( vm.count("mean_th") )
479 options.set("mean_th", mean_th);
480 if( vm.count("sigma_th") )
481 options.set("sigma_th", sigma_th);
482 if( vm.count("mean_w") )
483 options.set("mean_w", mean_w);
484 if( vm.count("sigma_w") )
485 options.set("sigma_w", sigma_w);
486 if( vm.count("beta") )
487 options.set("beta", beta);
488 if( vm.count("min_w") )
489 options.set("min_w", min_w);
490 if( vm.count("min_th") )
491 options.set("min_th", min_th);
492 if( vm.count("max_w") )
493 options.set("max_w", max_w);
494 if( vm.count("max_th") )
495 options.set("max_th", max_th);
496
497 // Output some comments
498 cout << "# Factor graph made by " << argv[0] << endl;
499 cout << "# type = " << type << endl;
500 cout << "# states = " << states << endl;
501
502 // The factor graph to be constructed
503 FactorGraph fg;
504
505 #define NEED_ARG(name, desc) do { if(!vm.count(name)) throw "Please specify " desc " with --" name; } while(0);
506
507 if( type == FULL_TYPE || type == DREG_TYPE || type == LOOP_TYPE || type == TREE_TYPE || type == GRID_TYPE || type == GRID3D_TYPE ) {
508 // Pairwise interactions
509
510 // Check command line options
511 if( type == GRID_TYPE ) {
512 NEED_ARG("n1", "width of grid");
513 NEED_ARG("n2", "height of grid");
514 N = n1 * n2;
515 } else if( type == GRID3D_TYPE ) {
516 NEED_ARG("n1", "width of grid");
517 NEED_ARG("n2", "height of grid");
518 NEED_ARG("n3", "depth of grid");
519 N = n1 * n2 * n3;
520 } else
521 NEED_ARG("N", "number of variables");
522
523 if( ft == FactorType::ISINGGAUSS ) {
524 NEED_ARG("mean_w", "mean of pairwise interactions");
525 NEED_ARG("mean_th", "mean of unary interactions");
526 NEED_ARG("sigma_w", "stddev of pairwise interactions");
527 NEED_ARG("sigma_th", "stddev of unary interactions");
528 } else if( ft == FactorType::ISINGUNIFORM ) {
529 NEED_ARG("min_w", "minimum of pairwise interactions");
530 NEED_ARG("min_th", "minimum of unary interactions");
531 NEED_ARG("max_w", "maximum of pairwise interactions");
532 NEED_ARG("max_th", "maximum of unary interactions");
533 } else
534 NEED_ARG("beta", "stddev of log-factor entries");
535
536 if( type == DREG_TYPE )
537 NEED_ARG("d", "connectivity (number of neighboring variables of each variable)");
538
539 // Build pairwise interaction graph
540 GraphAL G;
541 if( type == FULL_TYPE )
542 G = createGraphFull( N );
543 else if( type == DREG_TYPE )
544 G = createGraphRegular( N, d );
545 else if( type == LOOP_TYPE )
546 G = createGraphLoop( N );
547 else if( type == TREE_TYPE )
548 G = createGraphTree( N );
549 else if( type == GRID_TYPE )
550 G = createGraphGrid( n1, n2, periodic );
551 else if( type == GRID3D_TYPE )
552 G = createGraphGrid3D( n1, n2, n3, periodic );
553
554 // Construct factor graph from pairwise interaction graph
555 fg = createFG( G, ft, states, options );
556
557 // Output some additional comments
558 if( type == GRID_TYPE || type == GRID3D_TYPE ) {
559 cout << "# n1 = " << n1 << endl;
560 cout << "# n2 = " << n2 << endl;
561 if( type == GRID3D_TYPE )
562 cout << "# n3 = " << n3 << endl;
563 }
564 if( type == DREG_TYPE )
565 cout << "# d = " << d << endl;
566 cout << "# options = " << options << endl;
567 } else if( type == HOI_TYPE ) {
568 // Higher order interactions
569
570 // Check command line arguments
571 NEED_ARG("N", "number of variables");
572 NEED_ARG("K", "number of factors");
573 NEED_ARG("k", "number of variables per factor");
574 NEED_ARG("beta", "stddev of log-factor entries");
575
576 // Create higher-order interactions factor graph
577 do {
578 fg = createHOIFG( N, K, k, beta );
579 } while( !fg.isConnected() );
580
581 // Output some additional comments
582 cout << "# K = " << K << endl;
583 cout << "# k = " << k << endl;
584 cout << "# beta = " << beta << endl;
585 } else if( type == LDPC_TYPE ) {
586 // LDPC codes
587
588 // Check command line arguments
589 NEED_ARG("ldpc", "type of LDPC code");
590 NEED_ARG("noise", "bitflip probability for binary symmetric channel");
591
592 // Check more command line arguments (seperately for each LDPC type)
593 if( ldpc == LDPCType::RANDOM ) {
594 NEED_ARG("N", "number of variables");
595 NEED_ARG("K", "number of factors");
596 NEED_ARG("k", "number of variables per factor");
597 NEED_ARG("j", "number of parity checks per bit");
598 if( N * j != K * k )
599 throw "Parameters should satisfy N * j == K * k";
600 } else if( ldpc == LDPCType::GROUP ) {
601 NEED_ARG("prime", "prime number");
602 NEED_ARG("k", "number of variables per factor");
603 NEED_ARG("j", "number of parity checks per bit");
604
605 if( !isPrime(prime) )
606 throw "Parameter <prime> should be prime";
607 if( !((prime-1) % j == 0 ) )
608 throw "Parameters should satisfy (prime-1) % j == 0";
609 if( !((prime-1) % k == 0 ) )
610 throw "Parameters should satisfy (prime-1) % k == 0";
611
612 N = prime * k;
613 K = prime * j;
614 } else if( ldpc == LDPCType::SMALL ) {
615 N = 4;
616 K = 4;
617 j = 3;
618 k = 3;
619 }
620
621 // Output some additional comments
622 cout << "# N = " << N << endl;
623 cout << "# K = " << K << endl;
624 cout << "# j = " << j << endl;
625 cout << "# k = " << k << endl;
626 if( ldpc == LDPCType::GROUP )
627 cout << "# prime = " << prime << endl;
628 cout << "# noise = " << noise << endl;
629
630 // Construct likelihood and paritycheck factors
631 Real likelihood[4] = {1.0 - noise, noise, noise, 1.0 - noise};
632 Real *paritycheck = new Real[1 << k];
633 createParityCheck(paritycheck, k, 0.0);
634
635 // Create LDPC structure
636 BipartiteGraph ldpcG;
637 bool regular;
638 do {
639 if( ldpc == LDPCType::GROUP )
640 ldpcG = createGroupStructuredLDPCGraph( prime, j, k );
641 else if( ldpc == LDPCType::RANDOM )
642 ldpcG = createRandomBipartiteGraph( N, K, j, k );
643 else if( ldpc == LDPCType::SMALL )
644 ldpcG = createSmallLDPCGraph();
645
646 regular = true;
647 for( size_t i = 0; i < N; i++ )
648 if( ldpcG.nb1(i).size() != j )
649 regular = false;
650 for( size_t I = 0; I < K; I++ )
651 if( ldpcG.nb2(I).size() != k )
652 regular = false;
653 } while( !regular && !ldpcG.isConnected() );
654
655 // Convert to FactorGraph
656 vector<Factor> factors;
657 for( size_t I = 0; I < K; I++ ) {
658 VarSet vs;
659 for( size_t _i = 0; _i < k; _i++ ) {
660 size_t i = ldpcG.nb2(I)[_i];
661 vs |= Var( i, 2 );
662 }
663 factors.push_back( Factor( vs, paritycheck ) );
664 }
665 delete paritycheck;
666
667 // Generate noise vector
668 vector<char> noisebits(N,0);
669 size_t bitflips = 0;
670 for( size_t i = 0; i < N; i++ ) {
671 if( rnd_uniform() < noise ) {
672 noisebits[i] = 1;
673 bitflips++;
674 }
675 }
676 cout << "# bitflips = " << bitflips << endl;
677
678 // Simulate transmission of all-zero codeword
679 vector<char> input(N,0);
680 vector<char> output(N,0);
681 for( size_t i = 0; i < N; i++ )
682 output[i] = (input[i] + noisebits[i]) & 1;
683
684 // Add likelihoods
685 for( size_t i = 0; i < N; i++ )
686 factors.push_back( Factor(Var(i,2), likelihood + output[i]*2) );
687
688 // Construct Factor Graph
689 fg = FactorGraph( factors );
690 } else
691 throw "Invalid type";
692
693 // Output additional comments
694 cout << "# N = " << fg.nrVars() << endl;
695 cout << "# seed = " << seed << endl;
696
697 // Output factor graph
698 cout << fg;
699 } catch( const char *e ) {
700 /// Display error message
701 cerr << "Error: " << e << endl;
702 return 1;
703 }
704
705 return 0;
706 }