/** \param N1 = number of nodes of type 1 * \param d1 = size of neighborhoods of nodes of type 1 * \param N2 = number of nodes of type 2 * \param d2 = size of neighborhoods of nodes of type 2 * \note asserts that N1 * d1 == N2 * d2 */ BipartiteGraph createRandomBipartiteGraph( size_t N1, size_t N2, size_t d1, size_t d2 ) { BipartiteGraph G; DAI_ASSERT( N1 * d1 == N2 * d2 ); // build lists of degree-repeated vertex numbers std::vector<size_t> stubs1( N1*d1, 0 ); for( size_t n1 = 0; n1 < N1; n1++ ) for( size_t t = 0; t < d1; t++ ) stubs1[n1*d1 + t] = n1; // build lists of degree-repeated vertex numbers std::vector<size_t> stubs2( N2*d2, 0 ); for( size_t n2 = 0; n2 < N2; n2++ ) for( size_t t = 0; t < d2; t++ ) stubs2[n2*d2 + t] = n2; // shuffle lists random_shuffle( stubs1.begin(), stubs1.end() ); random_shuffle( stubs2.begin(), stubs2.end() ); // add edges vector<BipartiteGraph::Edge> edges; edges.reserve( N1*d1 ); for( size_t e = 0; e < N1*d1; e++ ) edges.push_back( BipartiteGraph::Edge(stubs1[e], stubs2[e]) ); // finish construction G.construct( N1, N2, edges.begin(), edges.end() ); return G; }
// N = number of variables // n = size of variable neighborhoods // K = number of factors // k = size of factor neighborhoods // asserts: N * n == K * k BipartiteGraph CreateRandomBipartiteGraph( size_t N, size_t K, size_t n, size_t k ) { BipartiteGraph G; DAI_ASSERT( N * n == K * k ); // build lists of degree-repeated vertex numbers std::vector<size_t> stubs1(N*n,0); for( size_t i = 0; i < N; i++ ) for( size_t t = 0; t < n; t++ ) stubs1[i*n + t] = i; // build lists of degree-repeated vertex numbers std::vector<size_t> stubs2(K*k,0); for( size_t I = 0; I < K; I++ ) for( size_t t = 0; t < k; t++ ) stubs2[I*k + t] = I; // shuffle lists random_shuffle( stubs1.begin(), stubs1.end() ); random_shuffle( stubs2.begin(), stubs2.end() ); // add edges vector<BipartiteGraph::Edge> edges; edges.reserve( N*n ); for( size_t e = 0; e < N*n; e++ ) edges.push_back( BipartiteGraph::Edge(stubs1[e], stubs2[e]) ); // finish construction G.construct( N, K, edges.begin(), edges.end() ); return G; }
void checkAddEdge(unsigned numOfVertices, Edge toBeAdded, Edges existing, Edges missing) { g.addEdge(toBeAdded); ASSERT_EQ(existing.size(), g.numOfEdges()); ASSERT_EQ(numOfVertices, g.numOfVertices()); for (auto elem : existing) ASSERT_TRUE(g.edgeExists(elem)); for (auto elem : missing) ASSERT_FALSE(g.edgeExists(elem)); }
/// Constructs a regular LDPC graph with N=6, j=2, K=4, k=3 BipartiteGraph createSmallLDPCGraph() { BipartiteGraph G; size_t N=4, j=3, K=4; // k=3; typedef BipartiteGraph::Edge Edge; vector<Edge> edges; edges.reserve( N*j ); edges.push_back( Edge(0,0) ); edges.push_back( Edge(1,0) ); edges.push_back( Edge(2,0) ); edges.push_back( Edge(0,1) ); edges.push_back( Edge(1,1) ); edges.push_back( Edge(3,1) ); edges.push_back( Edge(0,2) ); edges.push_back( Edge(2,2) ); edges.push_back( Edge(3,2) ); edges.push_back( Edge(1,3) ); edges.push_back( Edge(2,3) ); edges.push_back( Edge(3,3) ); // finish construction G.construct( N, K, edges.begin(), edges.end() ); return G; }
void PlotGraph::PlotAugmentingPath(BipartiteGraph& _bg, vector<EID>& _path){ //get assignment size, assume the sizes of agents and tasks are identical size_t as_size = _bg.GetNumAgents(); double plx[as_size]; double ply[as_size]; /* //gnuplot_resetplot(g); gnuplot_cmd(g, (char*)"unset label"); gnuplot_cmd(g, (char*)"set xrange [-0.25:1.25]"); gnuplot_cmd(g, (char*)"set yrange [-0.25:%f]", as_size-1+.25); gnuplot_cmd(g, (char*)"set xtics 0"); gnuplot_cmd(g, (char*)"set ytics 0"); gnuplot_cmd(g, (char*)"set nokey"); */ //gnuplot_cmd(g, (char*)"set style line 2 lt 2 lc rgb \"blue\" lw 3"); // Plot matching //cout<<endl<<"Set M: "<<endl; //DisplayData(_M); bool alter = true; for (unsigned int i = 0; i < _path.size(); i++){ plx[0] = _path[i].first; ply[0] = 0.0; plx[1] = _path[i].second; ply[1] = 1.0; //gnuplot_setstyle(g, (char*)"linespoints lc rgb \"#55DD99\" lw 3"); if(alter) gnuplot_setstyle(g, (char*)"lines lc rgb \"#458B74\" lw 3"); else gnuplot_setstyle(g, (char*)"lines lc rgb \"#7CCD7C\" lw 3"); alter = !alter; gnuplot_plot_xy(g, plx, ply, 2, NULL); } #ifdef SAVE_PLOTS stringstream ss; ss << setw(3) << setfill('0') << Cnt++; string postfix = ss.str(); string name="save/plot"+postfix+".jpeg"; gnuplot_cmd(g, (char*)"set terminal jpeg"); //gnuplot_cmd(g, (char*)"set terminal jpeg small size 320,240");//bad gnuplot_cmd(g, (char*)"set output \"%s\"", name.c_str()); printf("saved jpeg: \"%s\"\n", name.c_str()); #endif gnuplot_cmd(g, (char*)"replot"); sleep(period); }
void verifyMatching(BipartiteGraph g, unsigned expectedSize) { Matching matching = findMaximumMatching(g); typedef boost::unordered_set<unsigned> VertexSet; VertexSet first; VertexSet second; for (auto elem : matching) { ASSERT_TRUE(first.insert(elem.first).second); ASSERT_TRUE(second.insert(elem.second).second); ASSERT_TRUE(g.edgeExists(elem)); } ASSERT_EQ(expectedSize, matching.size()); }
/** Use construction described in "A Class of Group-Structured LDPC Codes" * by R. M. Tanner, D. Sridhara and T. Fuja * Proceedings of ICSTA, 2001 * * Example parameters: (p,j,k) = (31,3,5) * (p,j,k) = (37,3,4) * (p,j,k) = (7,2,4) * (p,j,k) = (29,2,4) * * j and k must be divisors of p-1 */ BipartiteGraph createGroupStructuredLDPCGraph( size_t p, size_t j, size_t k ) { BipartiteGraph G; size_t n = j; size_t N = p * k; size_t K = p * j; size_t a, b; for( a = 2; a < p; a++ ) if( order(a,p) == k ) break; DAI_ASSERT( a != p ); for( b = 2; b < p; b++ ) if( order(b,p) == j ) break; DAI_ASSERT( b != p ); // cout << "# order(a=" << a << ") = " << order(a,p) << endl; // cout << "# order(b=" << b << ") = " << order(b,p) << endl; DAI_ASSERT( N * n == K * k ); typedef BipartiteGraph::Edge Edge; vector<Edge> edges; edges.reserve( N * n ); for( size_t s = 0; s < j; s++ ) for( size_t t = 0; t < k; t++ ) { size_t P = (powmod(b,s,p) * powmod(a,t,p)) % p; for( size_t m = 0; m < p; m++ ) edges.push_back( Edge(t*p + m, s*p + ((m + P) % p)) ); } // finish construction G.construct( N, K, edges.begin(), edges.end() ); return G; }
void PlotGraph::PlotBipartiteGraph(BipartiteGraph& _bg, vector<VID>& _S, vector<VID>& _T, vector<VID>& _N, vector<EID>& _EG, vector<EID>& _M, int target_task){ //get assignment size, assume the sizes of agents and tasks are identical size_t as_size = _bg.GetNumAgents(); double plx[as_size]; double ply[as_size]; //g=gnuplot_init(); gnuplot_resetplot(g); gnuplot_cmd(g, (char*)"unset label"); gnuplot_cmd(g, (char*)"set xrange [-0.25:%f]", as_size-1+.25); gnuplot_cmd(g, (char*)"set yrange [-0.25:1.25]"); gnuplot_cmd(g, (char*)"set xtics 0"); gnuplot_cmd(g, (char*)"set ytics 0"); gnuplot_cmd(g, (char*)"set nokey"); // Plot matching //cout<<endl<<"Set M: "<<endl; //DisplayData(_M); for (unsigned int i = 0; i < _M.size(); i++){ plx[0] = _M[i].first; ply[0] = 0.0; plx[1] = _M[i].second; ply[1] = 1.0; gnuplot_setstyle(g, (char*)"lines lc rgb \"red\" lw 3"); gnuplot_plot_xy(g, plx, ply, 2, NULL); } // Plot admissible edges (EG) //cout<<"EG: "<<endl; //DisplayData(_EG); for(unsigned int i=0; i<_EG.size(); i++){ plx[0] = _EG[i].first; ply[0] = 0.0; plx[1] = _EG[i].second; ply[1] = 1.0; gnuplot_setstyle(g, (char*)"lines lc rgb \"gray\""); gnuplot_plot_xy(g, plx, ply, 2, NULL); plx[0] = (0.9*plx[0] + 0.1*plx[1]); ply[0] = 0.11; gnuplot_setstyle(g, (char*)"points pointsize 2 lc rgb \"#FFFFFF\" pt 7"); gnuplot_plot_xy(g, plx, ply, 1, NULL); //cout<<"EG "<<i<<": "<<_bg.GetMatrix(_EG[i])->GetWeight()<<endl; gnuplot_cmd(g, (char*)"set label \"%d\" at %f-0.04,0.1 front tc rgb \"#4682B4\" font \",8\"", int(_bg.GetMatrix(_EG[i])->GetWeight()), plx[0]); } // Plot membership of set S //cout<<"S: "<<endl; //DisplayData(_S); for(unsigned int i=0; i<_S.size(); i++){ plx[0] = _S[i]; ply[0] = 0.0; gnuplot_setstyle(g, (char*)"points pointsize 3 lc rgb \"green\" pt 7"); gnuplot_plot_xy(g, plx, ply, 1, NULL); } // Plot membership of the set T //cout<<"T: "<<endl; //DisplayData(_T); for(unsigned int i=0; i<_T.size(); i++){ plx[0] = _T[i]; ply[0] = 1.0; gnuplot_setstyle(g, (char*)"points pointsize 3 lc rgb \"#00BFFF\" pt 7"); gnuplot_plot_xy(g, plx, ply, 1, NULL); } if (target_task != -1) // not yet unioned, but the reversal point for the { // alternating path plx[0] = target_task; ply[0] = 1.0; gnuplot_setstyle(g, (char*)"points pointsize 3 lc rgb \"grey\" pt 7"); gnuplot_plot_xy(g, plx, ply, 1, NULL); } // Plot nodes for(unsigned int i = 0; i < as_size; i++) { plx[i] = i; ply[i] = 0.0; } gnuplot_setstyle(g, (char*)"points pointsize 2 lc rgb \"#102063\" pt 7"); gnuplot_plot_xy(g, plx, ply, as_size, NULL); for(unsigned int i = 0; i < as_size; i++) { plx[i] = i; ply[i] = 1.0; } gnuplot_setstyle(g, (char*)"points pointsize 2 lc rgb \"#102063\" pt 7"); gnuplot_plot_xy(g, plx, ply, as_size, NULL); for (unsigned int i = 0; i < as_size; i++) { gnuplot_cmd(g, (char*)"set label \"x%d\" at %d-0.025,-0.08 tc rgb \"black\"", i, i); gnuplot_cmd(g, (char*)"set label \"y%d\" at %d-0.025,1.08 tc rgb \"black\"", i, i); //cout<<"Label "<<i<<": "<<_bg.GetAgent(i)->GetLabel()<<endl; //cout<<"Label "<<i<<": "<<_bg.GetTask(i)->GetLabel()<<endl; gnuplot_cmd(g, (char*)"set label \"%d\" at %d-0.025,-0.15 tc rgb \"#112244\"", int(_bg.GetAgent(i)->GetLabel()), i); gnuplot_cmd(g, (char*)"set label \"%d\" at %d-0.025,1.15 tc rgb \"#112244\"", int(_bg.GetTask(i)->GetLabel()), i); } /* //image setting set terminal png {{no}transparent} {{no}interlace} {tiny | small | medium | large | giant} {font <face> {<pointsize>}} {size <x>,<y>} {{no}crop} {{no}enhanced} {<color0> <color1> <color2> ...} */ #ifdef SAVE_PLOTS stringstream ss; ss << setw(3) << setfill('0') << Cnt++; string postfix = ss.str(); string name="save/plot"+postfix+".jpeg"; gnuplot_cmd(g, (char*)"set terminal jpeg"); //gnuplot_cmd(g, (char*)"set terminal jpeg small size 320,240");//bad gnuplot_cmd(g, (char*)"set output \"%s\"", name.c_str()); printf("saved jpeg: \"%s\"\n", name.c_str()); #endif gnuplot_cmd(g, (char*)"replot"); sleep(period); //gnuplot_close(g); }
/// Main function int main( int argc, char *argv[] ) { try { // Variables for storing command line arguments size_t seed; size_t states = 2; string type; size_t d, N, K, k, j, n1, n2, n3, prime; bool periodic = false; FactorType ft; LDPCType ldpc; Real beta, sigma_w, sigma_th, mean_w, mean_th, noise; // Declare the supported options. po::options_description opts("General command line options"); opts.add_options() ("help", "produce help message") ("seed", po::value<size_t>(&seed), "random number seed (tries to read from /dev/urandom if not specified)") ("states", po::value<size_t>(&states), "number of states of each variable (default=2 for binary variables)") ; // Graph structure options po::options_description opts_graph("Options for specifying graph structure"); opts_graph.add_options() ("type", po::value<string>(&type), "factor graph type (one of 'FULL', 'DREG', 'LOOP', 'TREE', 'GRID', 'GRID3D', 'HOI', 'LDPC')") ("d", po::value<size_t>(&d), "variable connectivity (only for type=='DREG');\n\t<d><N> should be even") ("N", po::value<size_t>(&N), "number of variables (not for type=='GRID','GRID3D')") ("n1", po::value<size_t>(&n1), "width of grid (only for type=='GRID','GRID3D')") ("n2", po::value<size_t>(&n2), "height of grid (only for type=='GRID','GRID3D')") ("n3", po::value<size_t>(&n3), "length of grid (only for type=='GRID3D')") ("periodic", po::value<bool>(&periodic), "periodic grid? (only for type=='GRID','GRID3D'; default=0)") ("K", po::value<size_t>(&K), "number of factors (only for type=='HOI','LDPC')") ("k", po::value<size_t>(&k), "number of variables per factor (only for type=='HOI','LDPC')") ; // Factor options po::options_description opts_factors("Options for specifying factors"); opts_factors.add_options() ("factors", po::value<FactorType>(&ft), "factor type (one of 'EXPGAUSS','POTTS','ISING')") ("beta", po::value<Real>(&beta), "inverse temperature (ignored for factors=='ISING')") ("mean_w", po::value<Real>(&mean_w), "mean of pairwise interactions w_{ij} (only for factors=='ISING')") ("mean_th", po::value<Real>(&mean_th), "mean of unary interactions th_i (only for factors=='ISING')") ("sigma_w", po::value<Real>(&sigma_w), "stddev of pairwise interactions w_{ij} (only for factors=='ISING')") ("sigma_th", po::value<Real>(&sigma_th), "stddev of unary interactions th_i (only for factors=='ISING'") ; // LDPC options po::options_description opts_ldpc("Options for specifying LDPC code factor graphs"); opts_ldpc.add_options() ("ldpc", po::value<LDPCType>(&ldpc), "type of LDPC code (one of 'SMALL','GROUP','RANDOM')") ("j", po::value<size_t>(&j), "number of parity checks per bit (only for type=='LDPC')") ("noise", po::value<Real>(&noise), "bitflip probability for binary symmetric channel (only for type=='LDPC')") ("prime", po::value<size_t>(&prime), "prime number for construction of LDPC code (only for type=='LDPC' with ldpc='GROUP'))") ; // All options opts.add(opts_graph).add(opts_factors).add(opts_ldpc); // Parse command line arguments po::variables_map vm; po::store(po::parse_command_line(argc, argv, opts), vm); po::notify(vm); // Display help message if necessary if( vm.count("help") || !vm.count("type") ) { cout << "This program is part of libDAI - http://www.libdai.org/" << endl << endl; cout << "Usage: ./createfg [options]" << endl << endl; cout << "Creates a factor graph according to the specified options." << endl << endl; cout << endl << opts << endl; cout << "The following factor graph types with pairwise interactions can be created:" << endl; cout << "\t'FULL': fully connected graph of <N> variables" << endl; cout << "\t'DREG': random regular graph of <N> variables where each variable is connected with <d> others" << endl; cout << "\t'LOOP': a single loop of <N> variables" << endl; cout << "\t'TREE': random tree-structured (acyclic, connected) graph of <N> variables" << endl; cout << "\t'GRID': 2D grid of <n1>x<n2> variables" << endl; cout << "\t'GRID3D': 3D grid of <n1>x<n2>x<n3> variables" << endl; cout << "The following higher-order interactions factor graphs can be created:" << endl; cout << "\t'HOI': random factor graph consisting of <N> variables and <K> factors," << endl; cout << "\t each factor being an interaction of <k> variables." << endl; cout << "The following LDPC code factor graphs can be created:" << endl; cout << "\t'LDPC': simulates LDPC decoding problem, using an LDPC code of <N> bits and <K>" << endl; cout << "\t parity checks, with <k> bits per check and <j> checks per bit, transmitted" << endl; cout << "\t on a binary symmetric channel with probability <noise> of flipping a bit." << endl; cout << "\t The transmitted codeword has all bits set to zero. The argument 'ldpc'" << endl; cout << "\t determines how the LDPC code is constructed: either using a group structure," << endl; cout << "\t or randomly, or a fixed small code with (N,K,k,j) = (4,4,3,3)." << endl << endl; cout << "For all types except type=='LDPC', the factors have to be specified as well." << endl << endl; cout << "EXPGAUSS factors (the default) are created by drawing all log-factor entries" << endl; cout << "independently from a Gaussian with mean 0 and standard deviation <beta>." << endl << endl; cout << "In case of pairwise interactions, one can also choose POTTS factors, for which" << endl; cout << "the log-factors are simply delta functions multiplied by the strength <beta>." << endl << endl; cout << "For pairwise interactions and binary variables, one can also use ISING factors." << endl; cout << "Here variables x1...xN are assumed to be +1/-1--valued, and unary interactions" << endl; cout << "are of the form exp(th*xi) with th drawn from a Gaussian distribution with mean" << endl; cout << "<mean_th> and standard deviation <sigma_th>, and pairwise interactions are of the" << endl; cout << "form exp(w*xi*xj) with w drawn from a Gaussian distribution with mean <mean_w>" << endl; cout << "and standard deviation <sigma_w>." << endl; return 1; } // Set default number of states if( !vm.count("states") ) states = 2; // Set default factor type if( !vm.count("factors") ) ft = FactorType::EXPGAUSS; // Check validness of factor type if( ft == FactorType::POTTS ) if( type == HOI_TYPE ) throw "For factors=='POTTS', interactions should be pairwise (type!='HOI')"; if( ft == FactorType::ISING ) if( ((states != 2) || (type == HOI_TYPE)) ) throw "For factors=='ISING', variables should be binary (states==2) and interactions should be pairwise (type!='HOI')"; // Read random seed if( !vm.count("seed") ) { ifstream infile; bool success; infile.open( "/dev/urandom" ); success = infile.is_open(); if( success ) { infile.read( (char *)&seed, sizeof(size_t) / sizeof(char) ); success = infile.good(); infile.close(); } if( !success ) throw "Please specify random number seed."; } rnd_seed( seed ); // Set default periodicity if( !vm.count("periodic") ) periodic = false; // Store some options in a PropertySet object PropertySet options; if( vm.count("mean_th") ) options.Set("mean_th", mean_th); if( vm.count("sigma_th") ) options.Set("sigma_th", sigma_th); if( vm.count("mean_w") ) options.Set("mean_w", mean_w); if( vm.count("sigma_w") ) options.Set("sigma_w", sigma_w); if( vm.count("beta") ) options.Set("beta", beta); // Output some comments cout << "# Factor graph made by " << argv[0] << endl; cout << "# type = " << type << endl; cout << "# states = " << states << endl; // The factor graph to be constructed FactorGraph fg; #define NEED_ARG(name, desc) do { if(!vm.count(name)) throw "Please specify " desc " with --" name; } while(0); if( type == FULL_TYPE || type == DREG_TYPE || type == LOOP_TYPE || type == TREE_TYPE || type == GRID_TYPE || type == GRID3D_TYPE ) { // Pairwise interactions // Check command line options if( type == GRID_TYPE ) { NEED_ARG("n1", "width of grid"); NEED_ARG("n2", "height of grid"); N = n1 * n2; } else if( type == GRID3D_TYPE ) { NEED_ARG("n1", "width of grid"); NEED_ARG("n2", "height of grid"); NEED_ARG("n3", "depth of grid"); N = n1 * n2 * n3; } else NEED_ARG("N", "number of variables"); if( states > 2 || ft == FactorType::POTTS ) { NEED_ARG("beta", "stddev of log-factor entries"); } else { NEED_ARG("mean_w", "mean of pairwise interactions"); NEED_ARG("mean_th", "mean of unary interactions"); NEED_ARG("sigma_w", "stddev of pairwise interactions"); NEED_ARG("sigma_th", "stddev of unary interactions"); } if( type == DREG_TYPE ) NEED_ARG("d", "connectivity (number of neighboring variables of each variable)"); // Build pairwise interaction graph GraphAL G; if( type == FULL_TYPE ) G = createGraphFull( N ); else if( type == DREG_TYPE ) G = createGraphRegular( N, d ); else if( type == LOOP_TYPE ) G = createGraphLoop( N ); else if( type == TREE_TYPE ) G = createGraphTree( N ); else if( type == GRID_TYPE ) G = createGraphGrid( n1, n2, periodic ); else if( type == GRID3D_TYPE ) G = createGraphGrid3D( n1, n2, n3, periodic ); // Construct factor graph from pairwise interaction graph fg = createFG( G, ft, states, options ); // Output some additional comments if( type == GRID_TYPE || type == GRID3D_TYPE ) { cout << "# n1 = " << n1 << endl; cout << "# n2 = " << n2 << endl; if( type == GRID3D_TYPE ) cout << "# n3 = " << n3 << endl; } if( type == DREG_TYPE ) cout << "# d = " << d << endl; cout << "# options = " << options << endl; } else if( type == HOI_TYPE ) { // Higher order interactions // Check command line arguments NEED_ARG("N", "number of variables"); NEED_ARG("K", "number of factors"); NEED_ARG("k", "number of variables per factor"); NEED_ARG("beta", "stddev of log-factor entries"); // Create higher-order interactions factor graph do { fg = createHOIFG( N, K, k, beta ); } while( !fg.isConnected() ); // Output some additional comments cout << "# K = " << K << endl; cout << "# k = " << k << endl; cout << "# beta = " << beta << endl; } else if( type == LDPC_TYPE ) { // LDPC codes // Check command line arguments NEED_ARG("ldpc", "type of LDPC code"); NEED_ARG("noise", "bitflip probability for binary symmetric channel"); // Check more command line arguments (seperately for each LDPC type) if( ldpc == LDPCType::RANDOM ) { NEED_ARG("N", "number of variables"); NEED_ARG("K", "number of factors"); NEED_ARG("k", "number of variables per factor"); NEED_ARG("j", "number of parity checks per bit"); if( N * j != K * k ) throw "Parameters should satisfy N * j == K * k"; } else if( ldpc == LDPCType::GROUP ) { NEED_ARG("prime", "prime number"); NEED_ARG("k", "number of variables per factor"); NEED_ARG("j", "number of parity checks per bit"); if( !isPrime(prime) ) throw "Parameter <prime> should be prime"; if( !((prime-1) % j == 0 ) ) throw "Parameters should satisfy (prime-1) % j == 0"; if( !((prime-1) % k == 0 ) ) throw "Parameters should satisfy (prime-1) % k == 0"; N = prime * k; K = prime * j; } else if( ldpc == LDPCType::SMALL ) { N = 4; K = 4; j = 3; k = 3; } // Output some additional comments cout << "# N = " << N << endl; cout << "# K = " << K << endl; cout << "# j = " << j << endl; cout << "# k = " << k << endl; if( ldpc == LDPCType::GROUP ) cout << "# prime = " << prime << endl; cout << "# noise = " << noise << endl; // Construct likelihood and paritycheck factors Real likelihood[4] = {1.0 - noise, noise, noise, 1.0 - noise}; Real *paritycheck = new Real[1 << k]; createParityCheck(paritycheck, k, 0.0); // Create LDPC structure BipartiteGraph ldpcG; bool regular; do { if( ldpc == LDPCType::GROUP ) ldpcG = createGroupStructuredLDPCGraph( prime, j, k ); else if( ldpc == LDPCType::RANDOM ) ldpcG = createRandomBipartiteGraph( N, K, j, k ); else if( ldpc == LDPCType::SMALL ) ldpcG = createSmallLDPCGraph(); regular = true; for( size_t i = 0; i < N; i++ ) if( ldpcG.nb1(i).size() != j ) regular = false; for( size_t I = 0; I < K; I++ ) if( ldpcG.nb2(I).size() != k ) regular = false; } while( !regular && !ldpcG.isConnected() ); // Convert to FactorGraph vector<Factor> factors; for( size_t I = 0; I < K; I++ ) { VarSet vs; for( size_t _i = 0; _i < k; _i++ ) { size_t i = ldpcG.nb2(I)[_i]; vs |= Var( i, 2 ); } factors.push_back( Factor( vs, paritycheck ) ); } delete paritycheck; // Generate noise vector vector<char> noisebits(N,0); size_t bitflips = 0; for( size_t i = 0; i < N; i++ ) { if( rnd_uniform() < noise ) { noisebits[i] = 1; bitflips++; } } cout << "# bitflips = " << bitflips << endl; // Simulate transmission of all-zero codeword vector<char> input(N,0); vector<char> output(N,0); for( size_t i = 0; i < N; i++ ) output[i] = (input[i] + noisebits[i]) & 1; // Add likelihoods for( size_t i = 0; i < N; i++ ) factors.push_back( Factor(Var(i,2), likelihood + output[i]*2) ); // Construct Factor Graph fg = FactorGraph( factors ); } else throw "Invalid type"; // Output additional comments cout << "# N = " << fg.nrVars() << endl; cout << "# seed = " << seed << endl; // Output factor graph cout << fg; } catch( const char *e ) { /// Display error message cerr << "Error: " << e << endl; return 1; } return 0; }
void checkMatching(unsigned matchingSize, Edges edgesToAdd) { for (auto edge : edgesToAdd) g.addEdge(edge); verifyMatching(g, matchingSize); }
int main( int argc, char *argv[] ) { try { size_t N, K, k, d, j, n1, n2, n3; size_t prime; size_t seed; Real beta, sigma_w, sigma_th, noise, mean_w, mean_th; string type; size_t states = 2; // Declare the supported options. po::options_description desc("Allowed options"); desc.add_options() ("help", "produce help message") ("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'") ("seed", po::value<size_t>(&seed), "random number seed (tries to read from /dev/urandom if not specified)") ("N", po::value<size_t>(&N), "number of variables (not for type=='ldpc_small')") ("n1", po::value<size_t>(&n1), "width of 3D grid (only for type=='potts3d')") ("n2", po::value<size_t>(&n2), "height of 3D grid (only for type=='potts3d')") ("n3", po::value<size_t>(&n3), "length of 3D grid (only for type=='potts3d')") ("K", po::value<size_t>(&K), "number of factors\n\t(only for type=='hoi' and 'type=='ldpc_{random,group}')") ("k", po::value<size_t>(&k), "number of variables per factor\n\t(only for type=='hoi' and type=='ldpc_{random,group}')") ("d", po::value<size_t>(&d), "variable connectivity\n\t(only for type=='dreg')") ("j", po::value<size_t>(&j), "number of parity checks per bit\n\t(only for type=='ldpc_{random,group}')") ("prime", po::value<size_t>(&prime), "prime number for construction of LDPC code\n\t(only for type=='ldpc_group')") ("beta", po::value<Real>(&beta), "stddev of log-factor entries\n\t(only for type=='hoi', 'potts3d', 'grid' if states>2)") ("mean_w", po::value<Real>(&mean_w), "mean of pairwise interactions w_{ij}\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')") ("mean_th", po::value<Real>(&mean_th), "mean of singleton interactions th_i\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')") ("sigma_w", po::value<Real>(&sigma_w), "stddev of pairwise interactions w_{ij}\n\t(not for type=='hoi', 'ldpc_*', 'potts3d')") ("sigma_th", po::value<Real>(&sigma_th), "stddev of singleton interactions th_i\n\t(not for type=='hoi', 'ldpc_*', 'potts3d'") ("noise", po::value<Real>(&noise), "bitflip probability for binary symmetric channel (only for type=='ldpc')") ("states", po::value<size_t>(&states), "number of states of each variable (should be 2 for all but type=='grid', 'grid_torus', 'loop', 'potts3d')") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if( vm.count("help") || !vm.count("type") ) { if( vm.count("type") ) { if( type == FULL_TYPE ) { cout << "Creates fully connected pairwise graphical model of <N> binary variables;" << endl; } else if( type == GRID_TYPE ) { cout << "Creates (non-periodic) 2D Ising grid of (approx.) <N> variables (which need not be binary);" << endl; } else if( type == GRID_TORUS_TYPE ) { cout << "Creates periodic 2D Ising grid of (approx.) <N> variables (which need not be binary);" << endl; } else if( type == DREG_TYPE ) { cout << "Creates random d-regular graph of <N> binary variables with uniform degree <d>" << endl; cout << "(where <d><N> should be even);" << endl; } else if( type == LOOP_TYPE ) { cout << "Creates a pairwise graphical model consisting of a single loop of" << endl; cout << "<N> variables (which need not be binary);" << endl; } else if( type == TREE_TYPE ) { cout << "Creates a pairwise, connected graphical model without cycles (i.e., a tree)" << endl; cout << "of <N> binary variables;" << endl; } else if( type == HOI_TYPE ) { cout << "Creates a random factor graph of <N> binary variables and" << endl; cout << "<K> factors, each factor being an interaction of <k> variables." << endl; cout << "The entries of the factors are exponentials of i.i.d. Gaussian" << endl; cout << "variables with mean 0 and standard deviation <beta>." << endl; } else if( type == LDPC_RANDOM_TYPE ) { cout << "Simulates LDPC decoding problem, using a LDPC code of <N> bits and <K> parity" << endl; cout << "checks, with <k> bits per check and <j> checks per bit, transmitted on a binary" << endl; cout << "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl; cout << "codeword has all bits set to zero. The LDPC code is randomly generated." << endl; } else if( type == LDPC_GROUP_TYPE ) { cout << "Simulates LDPC decoding problem, using a LDPC code of <N> bits and <K> parity" << endl; cout << "checks, with <k> bits per check and <j> checks per bit, transmitted on a binary" << endl; cout << "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl; cout << "codeword has all bits set to zero. The LDPC code is constructed (using group" << endl; cout << "theory) using a parameter <prime>; <j> and <k> should both be divisors of <prime>-1." << endl; } else if( type == LDPC_SMALL_TYPE ) { cout << "Simulates LDPC decoding problem, using a LDPC code of 4 bits and 4 parity" << endl; cout << "checks, with 3 bits per check and 3 checks per bit, transmitted on a binary" << endl; cout << "symmetric channel with probability <noise> of flipping a bit. The transmitted" << endl; cout << "codeword has all bits set to zero. The LDPC code is fixed." << endl; } else if( type == POTTS3D_TYPE ) { cout << "Builds 3D Potts model of size <n1>x<n2>x<n3> with nearest-neighbour Potts" << endl; cout << "interactions with <states> states and inverse temperature <beta>." << endl; } else cerr << "Unknown type (should be one of 'full', 'grid', 'grid_torus', 'dreg', 'loop', 'tree', 'hoi', 'ldpc_random', 'ldpc_group', 'ldpc_small', 'potts3d')" << endl; if( type == FULL_TYPE || type == GRID_TYPE || type == GRID_TORUS_TYPE || type == DREG_TYPE || type == LOOP_TYPE || type == TREE_TYPE ) { if( type == GRID_TYPE || type == GRID_TORUS_TYPE || type == LOOP_TYPE ) { cout << "if <states> > 2: factor entries are exponents of Gaussians with mean 0 and standard deviation beta; otherwise," << endl; } cout << "singleton interactions are Gaussian with mean <mean_th> and standard" << endl; cout << "deviation <sigma_th>; pairwise interactions are Gaussian with mean" << endl; cout << "<mean_w> and standard deviation <sigma_w>." << endl; } } cout << endl << desc << endl; return 1; } if( !vm.count("states") ) states = 2; if( !vm.count("seed") ) { ifstream infile; bool success; infile.open( "/dev/urandom" ); success = infile.is_open(); if( success ) { infile.read( (char *)&seed, sizeof(size_t) / sizeof(char) ); success = infile.good(); infile.close(); } if( !success ) throw "Please specify random number seed."; } rnd_seed( seed ); FactorGraph fg; cout << "# Factor graph made by " << argv[0] << endl; cout << "# type = " << type << endl; if( type == FULL_TYPE ) { if( !vm.count("N") || !vm.count("mean_w") || !vm.count("mean_th") || !vm.count("sigma_w") || !vm.count("sigma_th") ) throw "Please specify all required arguments"; MakeFullFG( N, mean_w, mean_th, sigma_w, sigma_th, fg ); cout << "# N = " << N << endl; cout << "# mean_w = " << mean_w << endl; cout << "# mean_th = " << mean_th << endl; cout << "# sigma_w = " << sigma_w << endl; cout << "# sigma_th = " << sigma_th << endl; } else if( type == GRID_TYPE || type == GRID_TORUS_TYPE ) { #define NEED_ARG(name, desc) do { if(!vm.count(name)) throw "Please specify " desc " with --" name; } while(0); if( states > 2 ) { NEED_ARG("N", "number of nodes"); NEED_ARG("beta", "stddev of log-factor entries"); } else { NEED_ARG("N", "number of nodes"); NEED_ARG("mean_w", "mean of pairwise interactions"); NEED_ARG("mean_th", "mean of singleton interactions"); NEED_ARG("sigma_w", "stddev of pairwise interactions"); NEED_ARG("sigma_th", "stddev of singleton interactions"); } size_t n = (size_t)sqrt((long double)N); N = n * n; bool periodic = false; if( type == GRID_TYPE ) periodic = false; else periodic = true; if( states > 2 ) MakeGridNonbinaryFG( periodic, n, states, beta, fg ); else MakeGridFG( periodic, n, mean_w, mean_th, sigma_w, sigma_th, fg ); cout << "# n = " << n << endl; cout << "# N = " << N << endl; if( states > 2 ) cout << "# beta = " << beta << endl; else { cout << "# mean_w = " << mean_w << endl; cout << "# mean_th = " << mean_th << endl; cout << "# sigma_w = " << sigma_w << endl; cout << "# sigma_th = " << sigma_th << endl; } } else if( type == DREG_TYPE ) { if( !vm.count("N") || !vm.count("mean_w") || !vm.count("mean_th") || !vm.count("sigma_w") || !vm.count("sigma_th") || !vm.count("d") ) throw "Please specify all required arguments"; MakeDRegFG( N, d, mean_w, mean_th, sigma_w, sigma_th, fg ); cout << "# N = " << N << endl; cout << "# d = " << d << endl; cout << "# mean_w = " << mean_w << endl; cout << "# mean_th = " << mean_th << endl; cout << "# sigma_w = " << sigma_w << endl; cout << "# sigma_th = " << sigma_th << endl; } else if( type == LOOP_TYPE ) { if( states > 2 ) { if( !vm.count("N") || !vm.count("beta") ) throw "Please specify all required arguments"; } else { if( !vm.count("N") || !vm.count("mean_w") || !vm.count("mean_th") || !vm.count("sigma_w") || !vm.count("sigma_th") ) throw "Please specify all required arguments"; } if( states > 2 ) MakeLoopNonbinaryFG( N, states, beta, fg ); else MakeLoopFG( N, mean_w, mean_th, sigma_w, sigma_th, fg ); cout << "# N = " << N << endl; if( states > 2 ) cout << "# beta = " << beta << endl; else { cout << "# mean_w = " << mean_w << endl; cout << "# mean_th = " << mean_th << endl; cout << "# sigma_w = " << sigma_w << endl; cout << "# sigma_th = " << sigma_th << endl; } } else if( type == TREE_TYPE ) { if( !vm.count("N") || !vm.count("mean_w") || !vm.count("mean_th") || !vm.count("sigma_w") || !vm.count("sigma_th") ) throw "Please specify all required arguments"; MakeTreeFG( N, mean_w, mean_th, sigma_w, sigma_th, fg ); cout << "# N = " << N << endl; cout << "# mean_w = " << mean_w << endl; cout << "# mean_th = " << mean_th << endl; cout << "# sigma_w = " << sigma_w << endl; cout << "# sigma_th = " << sigma_th << endl; } else if( type == HOI_TYPE ) { if( !vm.count("N") || !vm.count("K") || !vm.count("k") || !vm.count("beta") ) throw "Please specify all required arguments"; do { MakeHOIFG( N, K, k, beta, fg ); } while( !fg.isConnected() ); cout << "# N = " << N << endl; cout << "# K = " << K << endl; cout << "# k = " << k << endl; cout << "# beta = " << beta << endl; } else if( type == LDPC_RANDOM_TYPE || type == LDPC_GROUP_TYPE || type == LDPC_SMALL_TYPE ) { if( !vm.count("noise") ) throw "Please specify all required arguments"; if( type == LDPC_RANDOM_TYPE ) { if( !vm.count("N") || !vm.count("K") || !vm.count("j") || !vm.count("k") ) throw "Please specify all required arguments"; if( N * j != K * k ) throw "Parameters should satisfy N * j == K * k"; } else if( type == LDPC_GROUP_TYPE ) { if( !vm.count("prime") || !vm.count("j") || !vm.count("k") ) throw "Please specify all required arguments"; if( !isPrime(prime) ) throw "Parameter <prime> should be prime"; if( !((prime-1) % j == 0 ) ) throw "Parameters should satisfy (prime-1) % j == 0"; if( !((prime-1) % k == 0 ) ) throw "Parameters should satisfy (prime-1) % k == 0"; N = prime * k; K = prime * j; } else if( type == LDPC_SMALL_TYPE ) { N = 4; K = 4; j = 3; k = 3; } cout << "# N = " << N << endl; cout << "# K = " << K << endl; cout << "# j = " << j << endl; cout << "# k = " << k << endl; if( type == LDPC_GROUP_TYPE ) cout << "# prime = " << prime << endl; cout << "# noise = " << noise << endl; // p = 31, j = 3, k = 5 // p = 37, j = 3, k = 4 // p = 7 , j = 2, k = 3 // p = 29, j = 2, k = 4 // Construct likelihood and paritycheck factors Real likelihood[4] = {1.0 - noise, noise, noise, 1.0 - noise}; Real *paritycheck = new Real[1 << k]; MakeParityCheck(paritycheck, k, 0.0); // Create LDPC structure BipartiteGraph ldpcG; bool regular; do { if( type == LDPC_GROUP_TYPE ) ldpcG = CreateGroupStructuredLDPCGraph( prime, j, k ); else if( type == LDPC_RANDOM_TYPE ) ldpcG = CreateRandomBipartiteGraph( N, K, j, k ); else if( type == LDPC_SMALL_TYPE ) ldpcG = CreateSmallLDPCGraph(); regular = true; for( size_t i = 0; i < N; i++ ) if( ldpcG.nb1(i).size() != j ) regular = false; for( size_t I = 0; I < K; I++ ) if( ldpcG.nb2(I).size() != k ) regular = false; } while( !regular && !ldpcG.isConnected() ); // Convert to FactorGraph vector<Factor> factors; for( size_t I = 0; I < K; I++ ) { VarSet vs; for( size_t _i = 0; _i < k; _i++ ) { size_t i = ldpcG.nb2(I)[_i]; vs |= Var( i, 2 ); } factors.push_back( Factor( vs, paritycheck ) ); } delete paritycheck; // Generate noise vector vector<char> noisebits(N,0); size_t bitflips = 0; for( size_t i = 0; i < N; i++ ) { if( rnd_uniform() < noise ) { noisebits[i] = 1; bitflips++; } } cout << "# bitflips = " << bitflips << endl; // Simulate transmission of all-zero codeword vector<char> input(N,0); vector<char> output(N,0); for( size_t i = 0; i < N; i++ ) output[i] = (input[i] + noisebits[i]) & 1; // Add likelihoods for( size_t i = 0; i < N; i++ ) factors.push_back( Factor(Var(i,2), likelihood + output[i]*2) ); // Construct Factor Graph fg = FactorGraph( factors ); } else if( type == POTTS3D_TYPE ) { if( !vm.count("n1") || !vm.count("n2") || !vm.count("n3") || !vm.count("beta") || !vm.count("states") ) throw "Please specify all required arguments"; Make3DPotts( n1, n2, n3, states, beta, fg ); cout << "# N = " << n1*n2*n3 << endl; cout << "# n1 = " << n1 << endl; cout << "# n2 = " << n2 << endl; cout << "# n3 = " << n3 << endl; cout << "# beta = " << beta << endl; cout << "# states = " << states << endl; } else { throw "Invalid type"; } cout << "# seed = " << seed << endl; cout << fg; } catch( const char *e ) { cerr << "Error: " << e << endl; return 1; } return 0; }