1 /* Copyright (C) 2006-2008 Joris Mooij [joris dot mooij at tuebingen dot mpg dot de]
2 Radboud University Nijmegen, The Netherlands /
3 Max Planck Institute for Biological Cybernetics, Germany
5 This file is part of libDAI.
7 libDAI is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 libDAI is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with libDAI; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <boost/program_options.hpp>
29 #include <boost/numeric/ublas/matrix_sparse.hpp>
30 #include <boost/numeric/ublas/io.hpp>
31 #include <dai/factorgraph.h>
32 #include <dai/weightedgraph.h>
38 namespace po
= boost::program_options
;
39 typedef boost::numeric::ublas::compressed_matrix
<double> matrix
;
40 typedef matrix::value_array_type::const_iterator matrix_vcit
;
41 typedef matrix::index_array_type::const_iterator matrix_icit
;
44 Factor
BinaryFactor( const Var
&n
, double field
) {
45 DAI_ASSERT( n
.states() == 2 );
47 buf
[0] = std::exp(-field
);
48 buf
[1] = std::exp(field
);
49 return Factor(n
, &buf
[0]);
53 Factor
BinaryFactor( const Var
&n1
, const Var
&n2
, double coupling
) {
54 DAI_ASSERT( n1
.states() == 2 );
55 DAI_ASSERT( n2
.states() == 2 );
56 DAI_ASSERT( n1
!= n2
);
58 buf
[0] = (buf
[3] = std::exp(coupling
));
59 buf
[1] = (buf
[2] = std::exp(-coupling
));
60 return Factor( VarSet(n1
, n2
), &buf
[0] );
64 Factor
RandomFactor( const VarSet
&ns
, double beta
) {
66 for( size_t t
= 0; t
< fac
.states(); t
++ )
67 fac
[t
] = std::exp(rnd_stdnormal() * beta
);
72 Factor
PottsFactor( const Var
&n1
, const Var
&n2
, double beta
) {
73 Factor
fac( VarSet( n1
, n2
), 1.0 );
74 DAI_ASSERT( n1
.states() == n2
.states() );
75 for( size_t s
= 0; s
< n1
.states(); s
++ )
76 fac
[ s
* (n1
.states() + 1) ] = std::exp(beta
);
81 void MakeHOIFG( size_t N
, size_t M
, size_t k
, double sigma
, FactorGraph
&fg
) {
83 vector
<Factor
> factors
;
86 for( size_t i
= 0; i
< N
; i
++ )
87 vars
.push_back(Var(i
,2));
89 for( size_t I
= 0; I
< M
; I
++ ) {
91 while( vars
.size() < k
) {
93 size_t newind
= (size_t)(N
* rnd_uniform());
94 Var newvar
= Var(newind
, 2);
95 if( !vars
.contains( newvar
) ) {
101 factors
.push_back( RandomFactor( vars
, sigma
) );
104 fg
= FactorGraph( factors
.begin(), factors
.end(), vars
.begin(), vars
.end(), factors
.size(), vars
.size() );
108 // w should be upper triangular or lower triangular
109 void WTh2FG( const matrix
&w
, const vector
<double> &th
, FactorGraph
&fg
) {
111 vector
<Factor
> factors
;
113 size_t N
= th
.size();
114 DAI_ASSERT( (w
.size1() == N
) && (w
.size2() == N
) );
117 for( size_t i
= 0; i
< N
; i
++ )
118 vars
.push_back(Var(i
,2));
120 factors
.reserve( w
.nnz() + N
);
121 // walk through the sparse array structure
122 // this is similar to matlab sparse arrays
123 // index2 gives the column index (similar to ir in matlab)
124 // index1 gives the starting indices for each row (similar to jc in matlab)
126 for( size_t pos
= 0; pos
< w
.nnz(); pos
++ ) {
127 while( pos
== w
.index1_data()[i
+1] )
129 size_t j
= w
.index2_data()[pos
];
130 double w_ij
= w
.value_data()[pos
];
131 factors
.push_back( BinaryFactor( vars
[i
], vars
[j
], w_ij
) );
133 for( size_t i
= 0; i
< N
; i
++ )
134 factors
.push_back( BinaryFactor( vars
[i
], th
[i
] ) );
136 fg
= FactorGraph( factors
.begin(), factors
.end(), vars
.begin(), vars
.end(), factors
.size(), vars
.size() );
140 void MakeFullFG( size_t N
, double mean_w
, double mean_th
, double sigma_w
, double sigma_th
, FactorGraph
&fg
) {
141 matrix
w(N
,N
,N
*(N
-1)/2);
142 vector
<double> th(N
,0.0);
144 for( size_t i
= 0; i
< N
; i
++ ) {
145 for( size_t j
= i
+1; j
< N
; j
++ )
146 w(i
,j
) = rnd_stdnormal() * sigma_w
+ mean_w
;
147 th
[i
] = rnd_stdnormal() * sigma_th
+ mean_th
;
154 void Make3DPotts( size_t n1
, size_t n2
, size_t n3
, size_t states
, double beta
, FactorGraph
&fg
) {
156 vector
<Factor
> factors
;
158 for( size_t i1
= 0; i1
< n1
; i1
++ )
159 for( size_t i2
= 0; i2
< n2
; i2
++ )
160 for( size_t i3
= 0; i3
< n3
; i3
++ ) {
161 vars
.push_back( Var( i1
*n2
*n3
+ i2
*n3
+ i3
, states
) );
163 factors
.push_back( PottsFactor( vars
.back(), vars
[ (i1
-1)*n2
*n3
+ i2
*n3
+ i3
], beta
) );
165 factors
.push_back( PottsFactor( vars
.back(), vars
[ i1
*n2
*n3
+ (i2
-1)*n3
+ i3
], beta
) );
167 factors
.push_back( PottsFactor( vars
.back(), vars
[ i1
*n2
*n3
+ i2
*n3
+ (i3
-1) ], beta
) );
170 fg
= FactorGraph( factors
.begin(), factors
.end(), vars
.begin(), vars
.end(), factors
.size(), vars
.size() );
174 void MakeGridFG( long periodic
, size_t n
, double mean_w
, double mean_th
, double sigma_w
, double sigma_th
, FactorGraph
&fg
) {
178 vector
<double> th(N
,0.0);
180 for( size_t i
= 0; i
< n
; i
++ )
181 for( size_t j
= 0; j
< n
; j
++ ) {
182 if( i
+1 < n
|| periodic
)
183 w(i
*n
+j
, ((i
+1)%n
)*n
+j
) = rnd_stdnormal() * sigma_w
+ mean_w
;
184 if( j
+1 < n
|| periodic
)
185 w(i
*n
+j
, i
*n
+((j
+1)%n
)) = rnd_stdnormal() * sigma_w
+ mean_w
;
186 th
[i
*n
+j
] = rnd_stdnormal() * sigma_th
+ mean_th
;
193 void MakeGridNonbinaryFG( bool periodic
, size_t n
, size_t states
, double beta
, FactorGraph
&fg
) {
197 vector
<Factor
> factors
;
200 for( size_t i
= 0; i
< N
; i
++ )
201 vars
.push_back(Var(i
, states
));
203 factors
.reserve( 2 * N
);
204 for( size_t i
= 0; i
< n
; i
++ ) {
205 for( size_t j
= 0; j
< n
; j
++ ) {
206 if( i
+1 < n
|| periodic
)
207 factors
.push_back( RandomFactor( VarSet( vars
[i
*n
+j
], vars
[((i
+1)%n
)*n
+j
] ), beta
) );
208 if( j
+1 < n
|| periodic
)
209 factors
.push_back( RandomFactor( VarSet( vars
[i
*n
+j
], vars
[i
*n
+((j
+1)%n
)] ), beta
) );
213 fg
= FactorGraph( factors
.begin(), factors
.end(), vars
.begin(), vars
.end(), factors
.size(), vars
.size() );
217 void MakeLoopFG( size_t N
, double mean_w
, double mean_th
, double sigma_w
, double sigma_th
, FactorGraph
&fg
) {
219 vector
<double> th(N
,0.0);
221 for( size_t i
= 0; i
< N
; i
++ ) {
222 w(i
, (i
+1)%N
) = rnd_stdnormal() * sigma_w
+ mean_w
;
223 th
[i
] = rnd_stdnormal() * sigma_th
+ mean_th
;
230 void MakeLoopNonbinaryFG( size_t N
, size_t states
, double beta
, FactorGraph
&fg
) {
232 vector
<Factor
> factors
;
235 for( size_t i
= 0; i
< N
; i
++ )
236 vars
.push_back(Var(i
, states
));
238 factors
.reserve( N
);
239 for( size_t i
= 0; i
< N
; i
++ ) {
240 factors
.push_back( RandomFactor( VarSet( vars
[i
], vars
[(i
+1)%N
] ), beta
) );
243 fg
= FactorGraph( factors
.begin(), factors
.end(), vars
.begin(), vars
.end(), factors
.size(), vars
.size() );
247 void MakeTreeFG( size_t N
, double mean_w
, double mean_th
, double sigma_w
, double sigma_th
, FactorGraph
&fg
) {
249 vector
<double> th(N
,0.0);
251 for( size_t i
= 0; i
< N
; i
++ ) {
252 th
[i
] = rnd_stdnormal() * sigma_th
+ mean_th
;
254 size_t j
= rnd_int( 0, i
-1 );
255 w(i
,j
) = rnd_stdnormal() * sigma_w
+ mean_w
;
263 void MakeDRegFG( size_t N
, size_t d
, double mean_w
, double mean_th
, double sigma_w
, double sigma_th
, FactorGraph
&fg
) {
264 matrix
w(N
,N
,(d
*N
)/2);
265 vector
<double> th(N
,0.0);
267 UEdgeVec g
= RandomDRegularGraph( N
, d
);
268 for( size_t i
= 0; i
< g
.size(); i
++ )
269 w(g
[i
].n1
, g
[i
].n2
) = rnd_stdnormal() * sigma_w
+ mean_w
;
271 for( size_t i
= 0; i
< N
; i
++ )
272 th
[i
] = rnd_stdnormal() * sigma_th
+ mean_th
;
278 // N = number of variables
279 // n = size of variable neighborhoods
280 // K = number of factors
281 // k = size of factor neighborhoods
282 // asserts: N * n == K * k
283 BipartiteGraph
CreateRandomBipartiteGraph( size_t N
, size_t K
, size_t n
, size_t k
) {
286 DAI_ASSERT( N
* n
== K
* k
);
288 // build lists of degree-repeated vertex numbers
289 std::vector
<size_t> stubs1(N
*n
,0);
290 for( size_t i
= 0; i
< N
; i
++ )
291 for( size_t t
= 0; t
< n
; t
++ )
294 // build lists of degree-repeated vertex numbers
295 std::vector
<size_t> stubs2(K
*k
,0);
296 for( size_t I
= 0; I
< K
; I
++ )
297 for( size_t t
= 0; t
< k
; t
++ )
301 random_shuffle( stubs1
.begin(), stubs1
.end() );
302 random_shuffle( stubs2
.begin(), stubs2
.end() );
305 vector
<BipartiteGraph::Edge
> edges
;
306 edges
.reserve( N
*n
);
307 for( size_t e
= 0; e
< N
*n
; e
++ )
308 edges
.push_back( BipartiteGraph::Edge(stubs1
[e
], stubs2
[e
]) );
310 // finish construction
311 G
.construct( N
, K
, edges
.begin(), edges
.end() );
317 // Returns x**n % p, assuming p is prime
318 int powmod (int x
, int n
, int p
) {
320 for( int m
= 0; m
< n
; m
++ )
326 // Returns order of x in GF(p) with p prime
327 size_t order (int x
, int p
) {
329 DAI_ASSERT( x
!= 0 );
333 prod
= (prod
* x
) % p
;
335 } while( prod
!= 1 );
340 // Returns whether n is a prime number
341 bool isPrime (size_t n
) {
343 for( size_t k
= 2; (k
< n
) && result
; k
++ )
350 // Make a regular LDPC graph with N=6, j=2, K=4, k=3
351 BipartiteGraph
CreateSmallLDPCGraph() {
353 size_t N
=4, j
=3, K
=4; // k=3;
355 typedef BipartiteGraph::Edge Edge
;
357 edges
.reserve( N
*j
);
358 edges
.push_back( Edge(0,0) ); edges
.push_back( Edge(1,0) ); edges
.push_back( Edge(2,0) );
359 edges
.push_back( Edge(0,1) ); edges
.push_back( Edge(1,1) ); edges
.push_back( Edge(3,1) );
360 edges
.push_back( Edge(0,2) ); edges
.push_back( Edge(2,2) ); edges
.push_back( Edge(3,2) );
361 edges
.push_back( Edge(1,3) ); edges
.push_back( Edge(2,3) ); edges
.push_back( Edge(3,3) );
363 // finish construction
364 G
.construct( N
, K
, edges
.begin(), edges
.end() );
370 // Use construction described in "A Class of Group-Structured LDPC Codes"
371 // by R. M. Tanner, D. Sridhara and T. Fuja
372 // Proceedings of ICSTA, 2001
374 // Example parameters: (p,j,k) = (31,3,5)
375 // j and k must be divisors of p-1
376 BipartiteGraph
CreateGroupStructuredLDPCGraph( size_t p
, size_t j
, size_t k
) {
384 for( a
= 2; a
< p
; a
++ )
385 if( order(a
,p
) == k
)
387 DAI_ASSERT( a
!= p
);
388 for( b
= 2; b
< p
; b
++ )
389 if( order(b
,p
) == j
)
391 DAI_ASSERT( b
!= p
);
392 // cout << "# order(a=" << a << ") = " << order(a,p) << endl;
393 // cout << "# order(b=" << b << ") = " << order(b,p) << endl;
395 DAI_ASSERT( N
* n
== K
* k
);
397 typedef BipartiteGraph::Edge Edge
;
399 edges
.reserve( N
* n
);
401 for( size_t s
= 0; s
< j
; s
++ )
402 for( size_t t
= 0; t
< k
; t
++ ) {
403 size_t P
= (powmod(b
,s
,p
) * powmod(a
,t
,p
)) % p
;
404 for( size_t m
= 0; m
< p
; m
++ )
405 edges
.push_back( Edge(t
*p
+ m
, s
*p
+ ((m
+ P
) % p
)) );
408 // finish construction
409 G
.construct( N
, K
, edges
.begin(), edges
.end() );
415 // Make parity check table
416 void MakeParityCheck( double *result
, size_t n
, double eps
) {
418 for( size_t i
= 0; i
< N
; i
++ ) {
420 for( size_t t
= 0; t
< n
; t
++ )
426 result
[i
] = 1.0 - eps
;
432 const char *FULL_TYPE
= "full";
433 const char *GRID_TYPE
= "grid";
434 const char *GRID_TORUS_TYPE
= "grid_torus";
435 const char *DREG_TYPE
= "dreg";
436 const char *HOI_TYPE
= "hoi";
437 const char *LDPC_RANDOM_TYPE
= "ldpc_random";
438 const char *LDPC_GROUP_TYPE
= "ldpc_group";
439 const char *LDPC_SMALL_TYPE
= "ldpc_small";
440 const char *LOOP_TYPE
= "loop";
441 const char *TREE_TYPE
= "tree";
442 const char *POTTS3D_TYPE
= "potts3d";
445 int main( int argc
, char *argv
[] ) {
447 size_t N
, K
, k
, d
, j
, n1
, n2
, n3
;
450 double beta
, sigma_w
, sigma_th
, noise
, mean_w
, mean_th
;
454 // Declare the supported options.
455 po::options_description
desc("Allowed options");
457 ("help", "produce help message")
458 ("type", po::value
<string
>(&type
), "factor graph type:\n\t'full', 'grid', 'grid_torus', 'dreg', 'loop', 'tree', 'hoi', 'ldpc_random', 'ldpc_group', 'ldpc_small', 'potts3d'")
459 ("seed", po::value
<size_t>(&seed
), "random number seed (tries to read from /dev/urandom if not specified)")
460 ("N", po::value
<size_t>(&N
), "number of variables (not for type=='ldpc_small')")
461 ("n1", po::value
<size_t>(&n1
), "width of 3D grid (only for type=='potts3d')")
462 ("n2", po::value
<size_t>(&n2
), "height of 3D grid (only for type=='potts3d')")
463 ("n3", po::value
<size_t>(&n3
), "length of 3D grid (only for type=='potts3d')")
464 ("K", po::value
<size_t>(&K
), "number of factors\n\t(only for type=='hoi' and 'type=='ldpc_{random,group}')")
465 ("k", po::value
<size_t>(&k
), "number of variables per factor\n\t(only for type=='hoi' and type=='ldpc_{random,group}')")
466 ("d", po::value
<size_t>(&d
), "variable connectivity\n\t(only for type=='dreg')")
467 ("j", po::value
<size_t>(&j
), "number of parity checks per bit\n\t(only for type=='ldpc_{random,group}')")
468 ("prime", po::value
<size_t>(&prime
), "prime number for construction of LDPC code\n\t(only for type=='ldpc_group')")
469 ("beta", po::value
<double>(&beta
), "stddev of log-factor entries\n\t(only for type=='hoi', 'potts3d', 'grid' if states>2)")
470 ("mean_w", po::value
<double>(&mean_w
), "mean of pairwise interactions w_{ij}\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')")
471 ("mean_th", po::value
<double>(&mean_th
), "mean of singleton interactions th_i\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')")
472 ("sigma_w", po::value
<double>(&sigma_w
), "stddev of pairwise interactions w_{ij}\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')")
473 ("sigma_th", po::value
<double>(&sigma_th
), "stddev of singleton interactions th_i\n\t(not for type=='hoi', 'ldpc_*', 'potts3d'")
474 ("noise", po::value
<double>(&noise
), "bitflip probability for binary symmetric channel (only for type=='ldpc')")
475 ("states", po::value
<size_t>(&states
), "number of states of each variable (should be 2 for all but type=='grid', 'grid_torus', 'loop', 'potts3d')")
478 po::variables_map vm
;
479 po::store(po::parse_command_line(argc
, argv
, desc
), vm
);
482 if( vm
.count("help") || !vm
.count("type") ) {
483 if( vm
.count("type") ) {
484 if( type
== FULL_TYPE
) {
485 cout
<< "Creates fully connected pairwise graphical model of <N> binary variables;" << endl
;
486 } else if( type
== GRID_TYPE
) {
487 cout
<< "Creates (non-periodic) 2D Ising grid of (approx.) <N> variables (which need not be binary);" << endl
;
488 } else if( type
== GRID_TORUS_TYPE
) {
489 cout
<< "Creates periodic 2D Ising grid of (approx.) <N> variables (which need not be binary);" << endl
;
490 } else if( type
== DREG_TYPE
) {
491 cout
<< "Creates random d-regular graph of <N> binary variables with uniform degree <d>" << endl
;
492 cout
<< "(where <d><N> should be even);" << endl
;
493 } else if( type
== LOOP_TYPE
) {
494 cout
<< "Creates a pairwise graphical model consisting of a single loop of" << endl
;
495 cout
<< "<N> variables (which need not be binary);" << endl
;
496 } else if( type
== TREE_TYPE
) {
497 cout
<< "Creates a pairwise, connected graphical model without cycles (i.e., a tree)" << endl
;
498 cout
<< "of <N> binary variables;" << endl
;
499 } else if( type
== HOI_TYPE
) {
500 cout
<< "Creates a random factor graph of <N> binary variables and" << endl
;
501 cout
<< "<K> factors, each factor being an interaction of <k> variables." << endl
;
502 cout
<< "The entries of the factors are exponentials of i.i.d. Gaussian" << endl
;
503 cout
<< "variables with mean 0 and standard deviation <beta>." << endl
;
504 } else if( type
== LDPC_RANDOM_TYPE
) {
505 cout
<< "Simulates LDPC decoding problem, using a LDPC code of <N> bits and <K> parity" << endl
;
506 cout
<< "checks, with <k> bits per check and <j> checks per bit, transmitted on a binary" << endl
;
507 cout
<< "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl
;
508 cout
<< "codeword has all bits set to zero. The LDPC code is randomly generated." << endl
;
509 } else if( type
== LDPC_GROUP_TYPE
) {
510 cout
<< "Simulates LDPC decoding problem, using a LDPC code of <N> bits and <K> parity" << endl
;
511 cout
<< "checks, with <k> bits per check and <j> checks per bit, transmitted on a binary" << endl
;
512 cout
<< "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl
;
513 cout
<< "codeword has all bits set to zero. The LDPC code is constructed (using group" << endl
;
514 cout
<< "theory) using a parameter <prime>; <j> and <k> should both be divisors of <prime>-1." << endl
;
515 } else if( type
== LDPC_SMALL_TYPE
) {
516 cout
<< "Simulates LDPC decoding problem, using a LDPC code of 4 bits and 4 parity" << endl
;
517 cout
<< "checks, with 3 bits per check and 3 checks per bit, transmitted on a binary" << endl
;
518 cout
<< "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl
;
519 cout
<< "codeword has all bits set to zero. The LDPC code is fixed." << endl
;
520 } else if( type
== POTTS3D_TYPE
) {
521 cout
<< "Builds 3D Potts model of size <n1>x<n2>x<n3> with nearest-neighbour Potts" << endl
;
522 cout
<< "interactions with <states> states and inverse temperature <beta>." << endl
;
524 cerr
<< "Unknown type (should be one of 'full', 'grid', 'grid_torus', 'dreg', 'loop', 'tree', 'hoi', 'ldpc_random', 'ldpc_group', 'ldpc_small', 'potts3d')" << endl
;
526 if( type
== FULL_TYPE
|| type
== GRID_TYPE
|| type
== GRID_TORUS_TYPE
|| type
== DREG_TYPE
|| type
== LOOP_TYPE
|| type
== TREE_TYPE
) {
527 if( type
== GRID_TYPE
|| type
== GRID_TORUS_TYPE
|| type
== LOOP_TYPE
) {
528 cout
<< "if <states> > 2: factor entries are exponents of Gaussians with mean 0 and standard deviation beta; otherwise," << endl
;
530 cout
<< "singleton interactions are Gaussian with mean <mean_th> and standard" << endl
;
531 cout
<< "deviation <sigma_th>; pairwise interactions are Gaussian with mean" << endl
;
532 cout
<< "<mean_w> and standard deviation <sigma_w>." << endl
;
535 cout
<< endl
<< desc
<< endl
;
539 if( !vm
.count("states") )
542 if( !vm
.count("seed") ) {
545 infile
.open( "/dev/urandom" );
546 success
= infile
.is_open();
548 infile
.read( (char *)&seed
, sizeof(size_t) / sizeof(char) );
549 success
= infile
.good();
553 throw "Please specify random number seed.";
559 cout
<< "# Factor graph made by " << argv
[0] << endl
;
560 cout
<< "# type = " << type
<< endl
;
562 if( type
== FULL_TYPE
) {
563 if( !vm
.count("N") || !vm
.count("mean_w") || !vm
.count("mean_th") || !vm
.count("sigma_w") || !vm
.count("sigma_th") )
564 throw "Please specify all required arguments";
565 MakeFullFG( N
, mean_w
, mean_th
, sigma_w
, sigma_th
, fg
);
567 cout
<< "# N = " << N
<< endl
;
568 cout
<< "# mean_w = " << mean_w
<< endl
;
569 cout
<< "# mean_th = " << mean_th
<< endl
;
570 cout
<< "# sigma_w = " << sigma_w
<< endl
;
571 cout
<< "# sigma_th = " << sigma_th
<< endl
;
572 } else if( type
== GRID_TYPE
|| type
== GRID_TORUS_TYPE
) {
574 if( !vm
.count("N") || !vm
.count("beta") )
575 throw "Please specify all required arguments";
577 if( !vm
.count("N") || !vm
.count("mean_w") || !vm
.count("mean_th") || !vm
.count("sigma_w") || !vm
.count("sigma_th") )
578 throw "Please specify all required arguments";
581 size_t n
= (size_t)sqrt((long double)N
);
584 bool periodic
= false;
585 if( type
== GRID_TYPE
)
591 MakeGridNonbinaryFG( periodic
, n
, states
, beta
, fg
);
593 MakeGridFG( periodic
, n
, mean_w
, mean_th
, sigma_w
, sigma_th
, fg
);
595 cout
<< "# n = " << n
<< endl
;
596 cout
<< "# N = " << N
<< endl
;
599 cout
<< "# beta = " << beta
<< endl
;
601 cout
<< "# mean_w = " << mean_w
<< endl
;
602 cout
<< "# mean_th = " << mean_th
<< endl
;
603 cout
<< "# sigma_w = " << sigma_w
<< endl
;
604 cout
<< "# sigma_th = " << sigma_th
<< endl
;
606 } else if( type
== DREG_TYPE
) {
607 if( !vm
.count("N") || !vm
.count("mean_w") || !vm
.count("mean_th") || !vm
.count("sigma_w") || !vm
.count("sigma_th") || !vm
.count("d") )
608 throw "Please specify all required arguments";
610 MakeDRegFG( N
, d
, mean_w
, mean_th
, sigma_w
, sigma_th
, fg
);
612 cout
<< "# N = " << N
<< endl
;
613 cout
<< "# d = " << d
<< endl
;
614 cout
<< "# mean_w = " << mean_w
<< endl
;
615 cout
<< "# mean_th = " << mean_th
<< endl
;
616 cout
<< "# sigma_w = " << sigma_w
<< endl
;
617 cout
<< "# sigma_th = " << sigma_th
<< endl
;
618 } else if( type
== LOOP_TYPE
) {
620 if( !vm
.count("N") || !vm
.count("beta") )
621 throw "Please specify all required arguments";
623 if( !vm
.count("N") || !vm
.count("mean_w") || !vm
.count("mean_th") || !vm
.count("sigma_w") || !vm
.count("sigma_th") )
624 throw "Please specify all required arguments";
627 MakeLoopNonbinaryFG( N
, states
, beta
, fg
);
629 MakeLoopFG( N
, mean_w
, mean_th
, sigma_w
, sigma_th
, fg
);
631 cout
<< "# N = " << N
<< endl
;
634 cout
<< "# beta = " << beta
<< endl
;
636 cout
<< "# mean_w = " << mean_w
<< endl
;
637 cout
<< "# mean_th = " << mean_th
<< endl
;
638 cout
<< "# sigma_w = " << sigma_w
<< endl
;
639 cout
<< "# sigma_th = " << sigma_th
<< endl
;
641 } else if( type
== TREE_TYPE
) {
642 if( !vm
.count("N") || !vm
.count("mean_w") || !vm
.count("mean_th") || !vm
.count("sigma_w") || !vm
.count("sigma_th") )
643 throw "Please specify all required arguments";
644 MakeTreeFG( N
, mean_w
, mean_th
, sigma_w
, sigma_th
, fg
);
646 cout
<< "# N = " << N
<< endl
;
647 cout
<< "# mean_w = " << mean_w
<< endl
;
648 cout
<< "# mean_th = " << mean_th
<< endl
;
649 cout
<< "# sigma_w = " << sigma_w
<< endl
;
650 cout
<< "# sigma_th = " << sigma_th
<< endl
;
651 } else if( type
== HOI_TYPE
) {
652 if( !vm
.count("N") || !vm
.count("K") || !vm
.count("k") || !vm
.count("beta") )
653 throw "Please specify all required arguments";
655 MakeHOIFG( N
, K
, k
, beta
, fg
);
656 } while( !fg
.isConnected() );
658 cout
<< "# N = " << N
<< endl
;
659 cout
<< "# K = " << K
<< endl
;
660 cout
<< "# k = " << k
<< endl
;
661 cout
<< "# beta = " << beta
<< endl
;
662 } else if( type
== LDPC_RANDOM_TYPE
|| type
== LDPC_GROUP_TYPE
|| type
== LDPC_SMALL_TYPE
) {
663 if( !vm
.count("noise") )
664 throw "Please specify all required arguments";
666 if( type
== LDPC_RANDOM_TYPE
) {
667 if( !vm
.count("N") || !vm
.count("K") || !vm
.count("j") || !vm
.count("k") )
668 throw "Please specify all required arguments";
671 throw "Parameters should satisfy N * j == K * k";
672 } else if( type
== LDPC_GROUP_TYPE
) {
673 if( !vm
.count("prime") || !vm
.count("j") || !vm
.count("k") )
674 throw "Please specify all required arguments";
676 if( !isPrime(prime
) )
677 throw "Parameter <prime> should be prime";
678 if( !((prime
-1) % j
== 0 ) )
679 throw "Parameters should satisfy (prime-1) % j == 0";
680 if( !((prime
-1) % k
== 0 ) )
681 throw "Parameters should satisfy (prime-1) % k == 0";
685 } else if( type
== LDPC_SMALL_TYPE
) {
692 cout
<< "# N = " << N
<< endl
;
693 cout
<< "# K = " << K
<< endl
;
694 cout
<< "# j = " << j
<< endl
;
695 cout
<< "# k = " << k
<< endl
;
696 if( type
== LDPC_GROUP_TYPE
)
697 cout
<< "# prime = " << prime
<< endl
;
698 cout
<< "# noise = " << noise
<< endl
;
700 // p = 31, j = 3, k = 5
701 // p = 37, j = 3, k = 4
702 // p = 7 , j = 2, k = 3
703 // p = 29, j = 2, k = 4
705 // Construct likelihood and paritycheck factors
706 double likelihood
[4] = {1.0 - noise
, noise
, noise
, 1.0 - noise
};
707 double *paritycheck
= new double[1 << k
];
708 MakeParityCheck(paritycheck
, k
, 0.0);
710 // Create LDPC structure
711 BipartiteGraph ldpcG
;
714 if( type
== LDPC_GROUP_TYPE
)
715 ldpcG
= CreateGroupStructuredLDPCGraph( prime
, j
, k
);
716 else if( type
== LDPC_RANDOM_TYPE
)
717 ldpcG
= CreateRandomBipartiteGraph( N
, K
, j
, k
);
718 else if( type
== LDPC_SMALL_TYPE
)
719 ldpcG
= CreateSmallLDPCGraph();
722 for( size_t i
= 0; i
< N
; i
++ )
723 if( ldpcG
.nb1(i
).size() != j
)
725 for( size_t I
= 0; I
< K
; I
++ )
726 if( ldpcG
.nb2(I
).size() != k
)
728 } while( !regular
&& !ldpcG
.isConnected() );
730 // Convert to FactorGraph
731 vector
<Factor
> factors
;
732 for( size_t I
= 0; I
< K
; I
++ ) {
734 for( size_t _i
= 0; _i
< k
; _i
++ ) {
735 size_t i
= ldpcG
.nb2(I
)[_i
];
738 factors
.push_back( Factor( vs
, paritycheck
) );
742 // Generate noise vector
743 vector
<char> noisebits(N
,0);
745 for( size_t i
= 0; i
< N
; i
++ ) {
746 if( rnd_uniform() < noise
) {
751 cout
<< "# bitflips = " << bitflips
<< endl
;
753 // Simulate transmission of all-zero codeword
754 vector
<char> input(N
,0);
755 vector
<char> output(N
,0);
756 for( size_t i
= 0; i
< N
; i
++ )
757 output
[i
] = (input
[i
] + noisebits
[i
]) & 1;
760 for( size_t i
= 0; i
< N
; i
++ )
761 factors
.push_back( Factor(Var(i
,2), likelihood
+ output
[i
]*2) );
763 // Construct Factor Graph
764 fg
= FactorGraph( factors
);
765 } else if( type
== POTTS3D_TYPE
) {
766 if( !vm
.count("n1") || !vm
.count("n2") || !vm
.count("n3") || !vm
.count("beta") || !vm
.count("states") )
767 throw "Please specify all required arguments";
768 Make3DPotts( n1
, n2
, n3
, states
, beta
, fg
);
770 cout
<< "# N = " << n1
*n2
*n3
<< endl
;
771 cout
<< "# n1 = " << n1
<< endl
;
772 cout
<< "# n2 = " << n2
<< endl
;
773 cout
<< "# n3 = " << n3
<< endl
;
774 cout
<< "# beta = " << beta
<< endl
;
775 cout
<< "# states = " << states
<< endl
;
777 throw "Invalid type";
780 cout
<< "# seed = " << seed
<< endl
;
782 } catch( const char *e
) {
783 cerr
<< "Error: " << e
<< endl
;