Basically, libcnf's main feature is that it provides a '===' operator for achieving exactly that.
#include <iostream> #include <vector> #include <string> #include <libmonitor/automaton.cc> #include <libmonitor/moore_automaton.cc> #include <libmonitor/transition.cc> #include <libmonitor/state.cc> #include <libmonitor/graph_manipulator.cc> #include <libcnf/cnf.hh> #include "graph_manipulator_cnf.cc" using namespace std; void start_automaton (); monitor::Moore_Automaton<cnf::CNF> _monitor; void threadd (); int main (int argc, char* argv[]) { // Initialise automaton. Graph_Manipulator_CNF<cnf::CNF> graph; vector<monitor::State<cnf::CNF> > states; vector<monitor::Transition<cnf::CNF> > transitions; graph.read ("/path/to/graph.dot"); graph.construct (states, transitions); _monitor.set_start_state (states[0]); _monitor.init (); // Start automaton. start_automaton (); return 0; } void start_automaton () { monitor::State<cnf::CNF>* new_state = NULL; int Spawn, Init; for (;;) { cnf::CNF action; // Create some dummy events, Spawn = 1, Init = 2. cout << "Spawn Thread? (1 = yes, -1 = no) "; cin >> Spawn; cout << "Init? (2 = yes, -2 = no) "; cin >> Init; // Optional: convert input to zchaff format. if (Spawn == -1) Spawn = 3; else Spawn = 2; if (Init == -2) Init = 5; else Init = 4; // Create one-element arrays with variables. int input_vector[1] = { Spawn }; int input_vector2[1] = { Init }; // Create clauses. action.push_back_clause (input_vector, 1); action.push_back_clause (input_vector2, 1); action.set_num_vars (2); // Trigger automaton with clauses. if (!(new_state = _monitor.process_input (action))) exit (0); cout << new_state->label () << endl; } }
If libmonitor was installed properly, the example will compile using 'g++ -lmonitor -lcnf program.cc'. Of course, just as documented in libmonitor, we need to provide an according graph manipulator, which you can use in your own code if you need libmonitor + libcnf together:
#ifndef GRAPH_MANIPULATOR_CNF_HH #define GRAPH_MANIPULATOR_CNF_HH #include <vector> #include <string> #include <libmonitor/transition.cc> #include <libmonitor/state.cc> #include <libmonitor/graph_manipulator.cc> #include <libcnf/cnf.hh> using namespace std; template <typename T> class Graph_Manipulator_CNF : public monitor::Graph_Manipulator<T> { protected: void split (const string& s, char c, vector<string>& v) { int i = 0; int j = s.find (c); if ((unsigned)j == string::npos) v.push_back (s); while (j >= 0) { v.push_back (s.substr (i, j-i)); i = ++j; j = s.find (c, j); if (j < 0) v.push_back (s.substr (i, s.length ())); } } void clause_to_CNF (const char* clause, vector<int>& CNF_clause) { vector<string> literals; split (clause, ' ', literals); for (vector<string>::iterator curl = literals.begin (); curl != literals.end (); curl++) { int val = 0; if (atoi (curl->c_str ()) < 0) val = abs (atoi (curl->c_str ()) * 2) + 1; else if (atoi (curl->c_str ()) > 0) val = atoi (curl->c_str ()) * 2; // Ignore 0! if (val != 0) CNF_clause.push_back (val); } } public: ~Graph_Manipulator_CNF () {}; void construct (vector<monitor::State<cnf::CNF> >& states, vector<monitor::Transition<cnf::CNF> > transitions) { vector<string> raw_clauses, raw_state_labels; vector<int> sources, targets; // Read all transitions' labels and store in raw_clauses. monitor::Graph_Manipulator<T>::get_transition_labels (raw_clauses, sources, targets); // Read all states' labels and store in raw_state_labels; monitor::Graph_Manipulator<T>::get_state_labels (raw_state_labels); // Generate states. for (int i = 0; i < monitor::Graph_Manipulator<T>::num_vertices (); i++) { monitor::State<cnf::CNF> tmp_state; tmp_state.set_label (raw_state_labels[i].c_str ()); states.push_back (tmp_state); } // Generate transitions. for (int i = 0; i < monitor::Graph_Manipulator<T>::num_edges (); i++) { monitor::Transition<cnf::CNF> tmp_trans; cnf::CNF the_T; vector<string> raw_trans; // Convert the transition's label to a T. split (raw_clauses[i].c_str (), ',', raw_trans); for (vector<string>::iterator s = raw_trans.begin (); s != raw_trans.end (); s++) { vector<int> tmp_T; monitor::State<cnf::CNF> tmp_state; clause_to_CNF (s->c_str (), tmp_T); // Add clause to T. the_T.push_back_clause (tmp_T); } // Set the T as input for the transition object. tmp_trans.set_input (the_T); // Set target for the transition object. tmp_trans.set_target (states[targets[i]]); // Store transition. transitions.push_back (tmp_trans); } // Add transitions to the states for (int i = 0; i < monitor::Graph_Manipulator<T>::num_edges (); i++) states[sources[i]].add_transition (transitions[i]); } }; #endif
To find out how it works in detail, refer to the libmonitor documentation as this has little to do with libcnf.
We're starting in state a, and remain in a as long as -1 and -2 hold. If 1 and -2 hold, we proceed to state b, if merely 2 holds (and either 1 or -1), we proceed to state d. That is, the comma separatd list of variables represent clauses, whereas spaces between variables are delimiters within a single clause.
Once zchaff is installed, and its sources reside inside your libcnf directory, you are ready to go.
1.4.5