Beispiel #1
0
TreeEP::TreeEP( const FactorGraph &fg, const PropertySet &opts ) : JTree(fg, opts("updates",string("HUGIN")), false), _maxdiff(0.0), _iters(0), props(), _Q() {
    setProperties( opts );

    if( opts.hasKey("tree") ) {
        construct( fg, opts.getAs<RootedTree>("tree") );
    } else {
        if( props.type == Properties::TypeType::ORG || props.type == Properties::TypeType::ALT ) {
            // ORG: construct weighted graph with as weights a crude estimate of the
            // mutual information between the nodes
            // ALT: construct weighted graph with as weights an upper bound on the
            // effective interaction strength between pairs of nodes

            WeightedGraph<Real> wg;
            // in order to get a connected weighted graph, we start
            // by connecting every variable to the zero'th variable with weight 0
            for( size_t i = 1; i < fg.nrVars(); i++ )
                wg[UEdge(i,0)] = 0.0;
            for( size_t i = 0; i < fg.nrVars(); i++ ) {
                SmallSet<size_t> delta_i = fg.bipGraph().delta1( i, false );
                const Var& v_i = fg.var(i);
                bforeach( size_t j, delta_i ) 
                    if( i < j ) {
                        const Var& v_j = fg.var(j);
                        VarSet v_ij( v_i, v_j );
                        SmallSet<size_t> nb_ij = fg.bipGraph().nb1Set( i ) | fg.bipGraph().nb1Set( j );
                        Factor piet;
                        bforeach( size_t I, nb_ij ) {
                            const VarSet& Ivars = fg.factor(I).vars();
                            if( props.type == Properties::TypeType::ORG ) {
                                if( (Ivars == v_i) || (Ivars == v_j) )
                                    piet *= fg.factor(I);
                                else if( Ivars >> v_ij )
                                    piet *= fg.factor(I).marginal( v_ij );
                            } else {
                                if( Ivars >> v_ij )
                                    piet *= fg.factor(I);
                            }
                        }
                        if( props.type == Properties::TypeType::ORG ) {
                            if( piet.vars() >> v_ij ) {
                                piet = piet.marginal( v_ij );
                                Factor pietf = piet.marginal(v_i) * piet.marginal(v_j);
                                wg[UEdge(i,j)] = dist( piet, pietf, DISTKL );
                            } else {
                                // this should never happen...
                                DAI_ASSERT( 0 == 1 );
                                wg[UEdge(i,j)] = 0;
                            }
                        } else
                            wg[UEdge(i,j)] = piet.strength(v_i, v_j);
                    }
Beispiel #2
0
void RegionGraph::constructCVM( const FactorGraph &fg, const std::vector<VarSet> &cl, size_t verbose ) {
    if( verbose )
        cerr << "constructCVM called (" << fg.nrVars() << " vars, " << fg.nrFactors() << " facs, " << cl.size() << " clusters)" << endl;

    // Retain only maximal clusters
    if( verbose )
        cerr << "  Constructing ClusterGraph" << endl;
    ClusterGraph cg( cl );
    if( verbose )
        cerr << "  Erasing non-maximal clusters" << endl;
    cg.eraseNonMaximal();

    // Create inner regions - first pass
    if( verbose )
        cerr << "  Creating inner regions (first pass)" << endl;
    set<VarSet> betas;
    for( size_t alpha = 0; alpha < cg.nrClusters(); alpha++ )
        for( size_t alpha2 = alpha; (++alpha2) != cg.nrClusters(); ) {
            VarSet intersection = cg.cluster(alpha) & cg.cluster(alpha2);
            if( intersection.size() > 0 )
                betas.insert( intersection );
        }

    // Create inner regions - subsequent passes
    if( verbose )
        cerr << "  Creating inner regions (next passes)" << endl;
    set<VarSet> new_betas;
    do {
        new_betas.clear();
        for( set<VarSet>::const_iterator gamma = betas.begin(); gamma != betas.end(); gamma++ )
            for( set<VarSet>::const_iterator gamma2 = gamma; (++gamma2) != betas.end(); ) {
                VarSet intersection = (*gamma) & (*gamma2);
                if( (intersection.size() > 0) && (betas.count(intersection) == 0) )
                    new_betas.insert( intersection );
            }
        betas.insert(new_betas.begin(), new_betas.end());
    } while( new_betas.size() );

    // Create inner regions - final phase
    if( verbose )
        cerr << "  Creating inner regions (final phase)" << endl;
    vector<Region> irs;
    irs.reserve( betas.size() );
    for( set<VarSet>::const_iterator beta = betas.begin(); beta != betas.end(); beta++ )
        irs.push_back( Region(*beta,0.0) );

    // Create edges
    if( verbose )
        cerr << "  Creating edges" << endl;
    vector<pair<size_t,size_t> > edges;
    for( size_t beta = 0; beta < irs.size(); beta++ )
        for( size_t alpha = 0; alpha < cg.nrClusters(); alpha++ )
            if( cg.cluster(alpha) >> irs[beta] )
                edges.push_back( pair<size_t,size_t>(alpha,beta) );

    // Construct region graph
    if( verbose )
        cerr << "  Constructing region graph" << endl;
    construct( fg, cg.clusters(), irs, edges );

    // Calculate counting numbers
    if( verbose )
        cerr << "  Calculating counting numbers" << endl;
    calcCVMCountingNumbers();
    
    if( verbose )
        cerr << "Done." << endl;
}
Beispiel #3
0
void TestHSMM::test_marginal_cut(const char* filename, size_t ID){

	HSMMparam param(filename);

	FactorGraph *graph;
	JTree *jt;

	// Set some constants
	size_t maxiter = 10000;
	Real   tol = 1e-9;
	size_t verb = 0;

	//window size
    size_t W = 20;
    size_t start = 0;

	// Store the constants in a PropertySet object
	PropertySet opts;
	opts.set("maxiter",maxiter);  // Maximum number of iterations
	opts.set("tol",tol);          // Tolerance for convergence
	opts.set("verbose",verb);     // Verbosity (amount of output generated)

	Factor O_last;
	vector< vector<Real> > all_marginal;
	vector<Real> sequence_marginal;
	all_marginal.reserve(test_data.size());


	cout << "Now we do testing...\n";

	for(size_t i=0; i<test_data.size(); i++) {

		//allocate memory
		sequence_marginal.reserve(test_data[i].size());

		//initialize HSMM of ever increasing size up to test_data[i].size()
		graph = new FactorGraph();
		graph->createHSMMFactorGraph(param.init, param.dist, test_data[i].size());

		jt = new JTree(*graph, opts("updates",string("HUGIN"))("heuristic",string("MINWEIGHT")) );

		jt->init();
		jt->run();

		O_last = jt->calcMarginal(graph->var(4));
		sequence_marginal.push_back( log(O_last.p().get(test_data[i][0].second)) );

		delete jt;

		for(size_t k=1; k < test_data[i].size(); k++){

			jt = new JTree(*graph, opts("updates",string("HUGIN"))("heuristic",string("MINWEIGHT")) );

			//clamp a window of observable variables to their values, except last variable which is not clamped
			start = k-W;
			if(start < 0) start = 0;

			for(size_t j = start; j <= k-1; j++){
				jt->clamp(test_data[i][j].first, test_data[i][j].second);
			}

			jt->init();
			jt->run();

			//compute p(o_last=c | o_1...o_{last-1})
			//this will give us a distribution: {o_last=1, o_last=2, ... o_last=M}
			O_last = jt->calcMarginal(graph->var(3*k+4));

			//since we have a specific observation at last time step: o_last=c, get its probability:
			sequence_marginal.push_back( log(O_last.p().get(test_data[i][k].second)) );

			delete jt;
		}

		cout << "Tested point " << i << " out of " << test_data.size() <<"\n";

		all_marginal.push_back(sequence_marginal);
		sequence_marginal.clear();

		delete graph;
	}

	cout << "Testing done.\n";

	ofstream os;
	stringstream result;
	result << string("data/HSMMmarginal_test_") << ID << string(".txt");
	os.open(result.str().c_str(), ios::trunc);

	for(size_t i=0; i<all_marginal.size(); i++){
		for(size_t j=0; j<all_marginal[i].size(); j++){
			os << all_marginal[i][j]<<" ";
		}
		os << "\n";
	}
}
Beispiel #4
0
void TestHSMM::test_loglik(const char* filename, size_t ID, string type, int dummy, int ID2){

	//"type" specifies the suffix of the output file "test" or "true"

	//read in HSMM parameters from textfile
	HSMMparam param(filename, 0);

	vector<Real> likelihood_test;
	FactorGraph *graph;
	JTree *jt;

	VarSet X;

	// Set some constants
	size_t maxiter = 10000;
	Real   tol = 1e-9;
	size_t verb = 0;

	// Store the constants in a PropertySet object
	PropertySet opts;
	opts.set("maxiter",maxiter);  // Maximum number of iterations
	opts.set("tol",tol);          // Tolerance for convergence
	opts.set("verbose",verb);     // Verbosity (amount of output generated)


	cout << "Now we do testing...\n";

	for(size_t i=0; i<test_data.size(); i++) {

		//initialize HSMM of size equal the number of observations
		graph = new FactorGraph();
		graph->createHSMMFactorGraph(param.init, param.dist, test_data[i].size(), 0);

		jt = new JTree(*graph, opts("updates",string("HUGIN"))("heuristic",string("MINWEIGHT")) );


		//clamp the observation variables to their observed values
		for(size_t j = 0; j < test_data[i].size(); j++ ){
			//cout << "clamping var" << test_data[i][j].first << " to value " << test_data[i][j].second << "\n";
			jt->clamp(test_data[i][j].first, test_data[i][j].second);
		}

		jt->init();
		jt->run();

		//compute normalized loglikelihood
		//likelihood_test.push_back(jt->logZ()/test_data[i].size());
		likelihood_test.push_back(jt->logZ());

		delete jt;
		delete graph;

		cout << "Tested point " << i << " out of " << test_data.size() <<"\n";

		//cout << "jt->logZ() = " << likelihood_test.at(0) << "\n";
		//exit(1);
	}

	cout << "done.\n";

	ofstream os;
	stringstream result;

	//ID2 is used to wirte test results with fixed number of training iterations
	if(ID2 >= 0){
		result << string("data/HSMMlikelihood_") << type << string("_") << ID << string("-") << ID2 << string(".txt");
	}
	else{
		result << string("data/HSMMlikelihood_") << type << string("_") << ID << string(".txt");
	}
	os.open(result.str().c_str(), ios::trunc);


	os.unsetf ( std::ios::floatfield );
	os.precision(18);
	for(size_t i=0; i<likelihood_test.size(); i++){
		os << likelihood_test.at(i)<<"\n";
	}
}
Beispiel #5
0
/// Main function
int main( int argc, char *argv[] ) {
    // Variables to store command line options
    // Filename of factor graph
    string filename;
    // Filename for aliases
    string aliases;
    // Approximate Inference methods to use
    vector<string> methods;
    // Which marginals to output
    MarginalsOutputType marginals;
    // Output number of iterations?
    bool report_iters = true;
    // Output calculation time?
    bool report_time = true;

    // Define required command line options
    po::options_description opts_required("Required options");
    opts_required.add_options()
        ("filename", po::value< string >(&filename), "Filename of factor graph")
        ("methods", po::value< vector<string> >(&methods)->multitoken(), "DAI methods to perform")
    ;

    // Define allowed command line options
    po::options_description opts_optional("Allowed options");
    opts_optional.add_options()
        ("help", "Produce help message")
        ("aliases", po::value< string >(&aliases), "Filename for aliases")
        ("marginals", po::value< MarginalsOutputType >(&marginals), "Output marginals? (NONE/VAR/FAC/VARFAC/ALL, default=NONE)")
        ("report-time", po::value< bool >(&report_time), "Output calculation time (default==1)?")
        ("report-iters", po::value< bool >(&report_iters), "Output iterations needed (default==1)?")
    ;

    // Define all command line options
    po::options_description cmdline_options;
    cmdline_options.add(opts_required).add(opts_optional);

    // Parse command line
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, cmdline_options), vm);
    po::notify(vm);

    // Display help message if necessary
    if( vm.count("help") || !(vm.count("filename") && vm.count("methods")) ) {
        cout << "This program is part of libDAI - http://www.libdai.org/" << endl << endl;
        cout << "Usage: ./testdai --filename <filename.fg> --methods <method1> [<method2> <method3> ...]" << endl << endl;
        cout << "Reads factor graph <filename.fg> and performs the approximate inference algorithms" << endl;
        cout << "<method*>, reporting for each method:" << endl;
        cout << "  o the calculation time needed, in seconds (if report-time == 1);" << endl;
        cout << "  o the number of iterations needed (if report-iters == 1);" << endl;
        cout << "  o the maximum (over all variables) total variation error in the variable marginals;" << endl;
        cout << "  o the average (over all variables) total variation error in the variable marginals;" << endl;
        cout << "  o the maximum (over all factors) total variation error in the factor marginals;" << endl;
        cout << "  o the average (over all factors) total variation error in the factor marginals;" << endl;
        cout << "  o the error (difference) of the logarithm of the partition sums;" << endl << endl;
        cout << "All errors are calculated by comparing the results of the current method with" << endl; 
        cout << "the results of the first method (the base method). If marginals==VAR, additional" << endl;
        cout << "output consists of the variable marginals, if marginals==FAC, the factor marginals" << endl;
        cout << "if marginals==VARFAC, both variable and factor marginals, and if marginals==ALL, all" << endl;
        cout << "marginals calculated by the method are reported." << endl << endl;
        cout << "<method*> should be a list of one or more methods, seperated by spaces, in the format:" << endl << endl;
        cout << "    name[key1=val1,key2=val2,key3=val3,...,keyn=valn]" << endl << endl;
        cout << "where name should be the name of an algorithm in libDAI (or an alias, if an alias" << endl;
        cout << "filename is provided), followed by a list of properties (surrounded by rectangular" << endl;
        cout << "brackets), where each property consists of a key=value pair and the properties are" << endl;
        cout << "seperated by commas. If an alias file is specified, alias substitution is performed." << endl;
        cout << "This is done by looking up the name in the alias file and substituting the alias" << endl;
        cout << "by its corresponding method as defined in the alias file. Properties are parsed from" << endl;
        cout << "left to right, so if a property occurs repeatedly, the right-most value is used." << endl << endl;
        cout << opts_required << opts_optional << endl;
#ifdef DAI_DEBUG
        cout << "Note: this is a debugging build of libDAI." << endl << endl;
#endif
        cout << "Example:  ./testdai --filename testfast.fg --aliases aliases.conf --methods JTREE_HUGIN BP_SEQFIX BP_PARALL[maxiter=5]" << endl;
        return 1;
    }

    try {
        // Read aliases
        map<string,string> Aliases;
        if( !aliases.empty() )
            Aliases = readAliasesFile( aliases );

        // Read factor graph
        FactorGraph fg;
        fg.ReadFromFile( filename.c_str() );

        // Declare variables used for storing variable factor marginals and log partition sum of base method
        vector<Factor> varMarginals0;
        vector<Factor> facMarginals0;
        Real logZ0 = 0.0;

        // Output header
        cout.setf( ios_base::scientific );
        cout.precision( 3 );
        cout << "# " << filename << endl;
        cout.width( 39 );
        cout << left << "# METHOD" << "\t";
        if( report_time )
            cout << right << "SECONDS  " << "\t";
        if( report_iters )
            cout << "ITERS" << "\t";
        cout << "MAX VAR ERR" << "\t";
        cout << "AVG VAR ERR" << "\t";
        cout << "MAX FAC ERR" << "\t";
        cout << "AVG FAC ERR" << "\t";
        cout << "LOGZ ERROR" << "\t";
        cout << "MAXDIFF" << "\t";
        cout << endl;

        // For each method...
        for( size_t m = 0; m < methods.size(); m++ ) {
            // Parse method
            pair<string, PropertySet> meth = parseNameProperties( methods[m], Aliases );

            // Construct object for running the method
            TestDAI testdai(fg, meth.first, meth.second );

            // Run the method
            testdai.doDAI();

            // For the base method, store its variable marginals and logarithm of the partition sum
            if( m == 0 ) {
                varMarginals0 = testdai.varMarginals;
                facMarginals0 = testdai.facMarginals;
                logZ0 = testdai.logZ;
            }

            // Calculate errors relative to base method
            testdai.calcErrors( varMarginals0, facMarginals0 );

            // Output method name
            cout.width( 39 );
            cout << left << methods[m] << "\t";
            // Output calculation time, if requested
            if( report_time )
                cout << right << testdai.time << "\t";
            // Output number of iterations, if requested
            if( report_iters ) {
                if( testdai.has_iters ) {
                    cout << testdai.iters << "\t";
                } else {
                    cout << "N/A  \t";
                }
            }

            // If this is not the base method
            if( m > 0 ) {
                cout.setf( ios_base::scientific );
                cout.precision( 3 );

                // Output maximum error in variable marginals
                Real mev = clipReal( testdai.maxVarErr(), 1e-9 );
                cout << mev << "\t";

                // Output average error in variable marginals
                Real aev = clipReal( testdai.avgVarErr(), 1e-9 );
                cout << aev << "\t";

                // Output maximum error in factor marginals
                Real mef = clipReal( testdai.maxFacErr(), 1e-9 );
                if( mef == INFINITY )
                    cout << "N/A       \t";
                else
                    cout << mef << "\t";

                // Output average error in factor marginals
                Real aef = clipReal( testdai.avgFacErr(), 1e-9 );
                if( aef == INFINITY )
                    cout << "N/A       \t";
                else
                    cout << aef << "\t";

                // Output error in log partition sum
                if( testdai.has_logZ ) {
                    cout.setf( ios::showpos );
                    Real le = clipReal( testdai.logZ - logZ0, 1e-9 );
                    cout << le << "\t";
                    cout.unsetf( ios::showpos );
                } else
                    cout << "N/A       \t";

                // Output maximum difference in last iteration
                if( testdai.has_maxdiff ) {
                    Real md = clipReal( testdai.maxdiff, 1e-9 );
                    if( dai::isnan( mev ) )
                        md = mev;
                    if( dai::isnan( aev ) )
                        md = aev;
                    if( md == INFINITY )
                        md = 1.0;
                    cout << md << "\t";
                } else
                    cout << "N/A    \t";
            }
            cout << endl;

            // Output marginals, if requested
            if( marginals == MarginalsOutputType::VAR || marginals == MarginalsOutputType::VARFAC )
                for( size_t i = 0; i < testdai.varMarginals.size(); i++ )
                    cout << "# " << testdai.varMarginals[i] << endl;
            if( marginals == MarginalsOutputType::FAC || marginals == MarginalsOutputType::VARFAC )
                for( size_t I = 0; I < testdai.facMarginals.size(); I++ )
                    cout << "# " << testdai.facMarginals[I] << endl;
            if( marginals == MarginalsOutputType::ALL )
                for( size_t I = 0; I < testdai.allMarginals.size(); I++ )
                    cout << "# " << testdai.allMarginals[I] << endl;
        }

        return 0;
    } catch( string &s ) {
        // Abort with error message
        cerr << "Exception: " << s << endl;
        return 2;
    }
}
void MaximumCompositeLikelihood::SetupTrainingData(
	const std::vector<labeled_instance_type>& training_data,
	const std::vector<InferenceMethod*> inference_methods) {
	assert(comp_training_data.size() == 0);
	assert(comp_inference_methods.size() == 0);
	assert(inference_methods.size() == training_data.size());

	// Number of times each component will be covered
	unsigned int cover_count = 1;
	assert(decomp >= -1);
	if (decomp == DecomposePseudolikelihood) {
		cover_count = 1;
	} else if (decomp > 0) {
		cover_count = decomp;
	}

	// Produce composite factor graphs
	boost::timer decomp_timer;
	int training_data_size = static_cast<int>(training_data.size());
	fg_cc_var_label.resize(cover_count * training_data_size);
	fg_cc_count.resize(cover_count * training_data_size);
	fg_orig_index.resize(cover_count * training_data_size);
	std::fill(fg_cc_count.begin(), fg_cc_count.end(), 0);
	unsigned int cn = 0;
	for (int n = 0; n < training_data_size; ++n) {
		FactorGraph* fg = training_data[n].first;
		size_t var_count = fg->Cardinalities().size();

		// Get observation
		const FactorGraphObservation* obs = training_data[n].second;

		// Obtain one or more decomposition(s)
		for (unsigned int cover_iter = 0; cover_iter < cover_count;
			++cover_iter) {
			VAcyclicDecomposition vac(fg);
			std::vector<bool> factor_is_removed;

			if (decomp == DecomposePseudolikelihood) {
				factor_is_removed.resize(fg->Factors().size());
				std::fill(factor_is_removed.begin(),
					factor_is_removed.end(), true);
			} else {
				std::vector<double> factor_weight(fg->Factors().size(), 0.0);
				if (decomp == DecomposeUniform) {
					// Use constant weights
					std::fill(factor_weight.begin(), factor_weight.end(), 1.0);
				} else {
					// Use uniform random weights
					boost::uniform_real<double> uniform_dist(0.0, 1.0);
					boost::variate_generator<boost::mt19937&,
						boost::uniform_real<double> >
						rgen(RandomSource::GlobalRandomSampler(), uniform_dist);

					for (unsigned int fi = 0; fi < factor_weight.size(); ++fi)
						factor_weight[fi] = rgen();
				}
				vac.ComputeDecompositionSP(factor_weight, factor_is_removed);
			}

			// Shatter factor graph into trees
			fg_cc_count[cn] += FactorGraphStructurizer::ConnectedComponents(
				fg, factor_is_removed, fg_cc_var_label[cn]);
#if 0
			std::cout << "MCL, instance " << n << " decomposed into " << cc_count
				<< " components" << std::endl;
#endif

			// Add each component as separate factor graph
			for (unsigned int ci = 0; ci < fg_cc_count[cn]; ++ci) {
				std::vector<unsigned int> cond_var_set;
				cond_var_set.reserve(var_count);

				// Add all variables not in this component to the conditioning set
				for (size_t vi = 0; vi < var_count; ++vi) {
					if (fg_cc_var_label[cn][vi] != ci)
						cond_var_set.push_back(static_cast<unsigned int>(vi));
				}
				AddTrainingComponentCond(fg, obs, inference_methods[n],
					cond_var_set);
			}
			fg_orig_index[cn] = n;
			cn += 1;
		}
	}
	std::cout << "MCL, decomposed " << training_data.size() << " instances "
		<< "into " << comp_training_data.size() << " instances "
		<< (decomp == DecomposeUniform ? "(uniform)" : "(randomized)")
		<< " in " << decomp_timer.elapsed() << "s." << std::endl;

	// Initialize MLE training data from created components
	SetupMLETrainingData();
}
Beispiel #7
0
VarIds
readQueryAndEvidence (
    FactorGraph& fg,
    int argc,
    const char* argv[],
    int start)
{
  VarIds queryIds;
  for (int i = start; i < argc; i++) {
    const string& arg = argv[i];
    if (arg.find ('=') == std::string::npos) {
      if (Util::isInteger (arg) == false) {
        cerr << "error: `" << arg << "' " ;
        cerr << "is not a variable id" ;
        cerr << endl;
        exit (0);
      }
      VarId vid = Util::stringToUnsigned (arg);
      VarNode* queryVar = fg.getVarNode (vid);
      if (queryVar == false) {
        cerr << "error: unknow variable with id " ;
        cerr << "`" << vid << "'"  << endl;
        exit (0);
      }
      queryIds.push_back (vid);
    } else {
      size_t pos = arg.find ('=');
      string leftArg  = arg.substr (0, pos);
      string rightArg = arg.substr (pos + 1);
      if (leftArg.empty()) {
        cerr << "error: missing left argument" << endl;
        cerr << USAGE << endl;
        exit (0);
      }
      if (Util::isInteger (leftArg) == false) {
        cerr << "error: `" << leftArg << "' " ;
        cerr << "is not a variable id" << endl ;
        exit (0);
        continue;
      }
      VarId vid = Util::stringToUnsigned (leftArg);
      VarNode* observedVar = fg.getVarNode (vid);
      if (observedVar == false) {
        cerr << "error: unknow variable with id " ;
        cerr << "`" << vid << "'"  << endl;
        exit (0);
      }
      if (rightArg.empty()) {
        cerr << "error: missing right argument" << endl;
        cerr << USAGE << endl;
        exit (0);
      }
      if (Util::isInteger (rightArg) == false) {
        cerr << "error: `" << rightArg << "' " ;
        cerr << "is not a state index" << endl ;
        exit (0);
      }
      unsigned stateIdx = Util::stringToUnsigned (rightArg);
      if (observedVar->isValidState (stateIdx) == false) {
        cerr << "error: `" << stateIdx << "' " ;
        cerr << "is not a valid state index for variable with id " ;
        cerr << "`" << vid << "'"  << endl;
        exit (0);
      }
      observedVar->setEvidence (stateIdx);
    }
  }
  return queryIds;
}
Beispiel #8
0
int main( int argc, char *argv[] ) {
    if( argc != 3 ) {
        cout << "Usage: " << argv[0] << " <in.fg> <tw>" << endl << endl;
        cout << "Reports some characteristics of the .fg network." << endl;
        cout << "Also calculates treewidth (which may take some time) unless <tw> == 0." << endl;
        return 1;
    } else {
        // Read factorgraph
        FactorGraph fg;
        char *infile = argv[1];
        int calc_tw = atoi(argv[2]);
        fg.ReadFromFile( infile );

        cout << "Number of variables:   " << fg.nrVars() << endl;
        cout << "Number of factors:     " << fg.nrFactors() << endl;
        cout << "Connected:             " << fg.isConnected() << endl;
        cout << "Tree:                  " << fg.isTree() << endl;
        cout << "Has short loops:       " << hasShortLoops(fg.factors()) << endl;
        cout << "Has negatives:         " << hasNegatives(fg.factors()) << endl;
        cout << "Binary variables?      " << fg.isBinary() << endl;
        cout << "Pairwise interactions? " << fg.isPairwise() << endl;
        if( calc_tw ) {
            std::pair<size_t,size_t> tw = treewidth(fg);
            cout << "Treewidth:           " << tw.first << endl;
            cout << "Largest cluster for JTree has " << tw.second << " states " << endl;
        }
        double stsp = 1.0;
        for( size_t i = 0; i < fg.nrVars(); i++ )
            stsp *= fg.var(i).states();
        cout << "Total state space:   " << stsp << endl;

        double cavsum_lcbp = 0.0;
        double cavsum_lcbp2 = 0.0;
        size_t max_Delta_size = 0;
        map<size_t,size_t> cavsizes;
        for( size_t i = 0; i < fg.nrVars(); i++ ) {
            VarSet di = fg.delta(i);
            if( cavsizes.count(di.size()) )
                cavsizes[di.size()]++;
            else
                cavsizes[di.size()] = 1;
            size_t Ds = fg.Delta(i).nrStates();
            if( Ds > max_Delta_size )
                max_Delta_size = Ds;
            cavsum_lcbp += di.nrStates();
            for( VarSet::const_iterator j = di.begin(); j != di.end(); j++ )
                cavsum_lcbp2 += j->states();
        }
        cout << "Maximum pancake has " << max_Delta_size << " states" << endl;
        cout << "LCBP with full cavities needs " << cavsum_lcbp << " BP runs" << endl;
        cout << "LCBP with only pairinteractions needs " << cavsum_lcbp2 << " BP runs" << endl;
        cout << "Cavity sizes: ";
        for( map<size_t,size_t>::const_iterator it = cavsizes.begin(); it != cavsizes.end(); it++ ) 
            cout << it->first << "(" << it->second << ") ";
        cout << endl;

        cout << "Type: " << (fg.isPairwise() ? "pairwise" : "higher order") << " interactions, " << (fg.isBinary() ? "binary" : "nonbinary") << " variables" << endl;

        if( fg.isPairwise() ) {
            bool girth_reached = false;
            size_t loopdepth;
            for( loopdepth = 2; loopdepth <= fg.nrVars() && !girth_reached; loopdepth++ ) {
                size_t nr_loops = countLoops( fg, loopdepth );
                cout << "Loops up to " << loopdepth << " variables: " << nr_loops << endl;
                if( nr_loops > 0 )
                    girth_reached = true;
            }
            if( girth_reached )
                cout << "Girth: " << loopdepth-1 << endl;
            else
                cout << "Girth: infinity" << endl;
        }

        return 0;
    }
}
Beispiel #9
0
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;
}