libgsjj  1
Deterministic finite automata learning library
HeuleVerwerCNFMethod.cpp
Go to the documentation of this file.
1 
8 
9 #include <iostream>
10 
11 using namespace Minisat;
12 
13 namespace gsjj {
14  namespace passive {
15  namespace CNF {
16  HeuleVerwerCNFMethod::HeuleVerwerCNFMethod(const std::set<std::string> &SpSet, const std::set<std::string> &SmSet, const std::set<std::string> &SSet, const std::set<std::string> &prefixesSet, const std::set<char> &alphabetSet, unsigned int n) :
17  SATCNFMethod(SpSet, SmSet, SSet, prefixesSet, alphabetSet, n)
18  {
20  }
21 
23  }
24 
26  return "heule";
27  }
28 
30  // The x variables (same as for Grinchtein, Leucker and Piterman's unary method)
31  for (const auto &u : m_prefixes) {
32  for (unsigned int q = 0; q < m_numberStates; q++) {
33  auto pair = std::make_pair(u, q);
34  Var var = newVariable();
35  m_xVars.emplace(pair, var);
36  }
37  }
38 
39  // The d variables : for each state, for each symbol, for each state, there is a distinct variable
40  for (unsigned int p = 0; p < m_numberStates; p++) {
41  for (const char &a : m_alphabet) {
42  for (unsigned int q = 0; q < m_numberStates; q++) {
43  auto trip = std::make_tuple(p, a, q);
44  Var var = newVariable();
45  m_dVars.emplace(trip, var);
46  }
47  }
48  }
49 
50  // The f variables : for each state, there is a distinct variable
51  for (unsigned int q = 0; q < m_numberStates; q++) {
52  m_fVars.emplace(q, newVariable());
53  }
54  }
55 
57  // Equation 4.5.1
58  // For every p in Q, a in Sigma, q, q' in Q such that q != q', we must have NOT (d_{p, a, q} AND d_{p, a, q'})
59  // In other words, d must encode a deterministic transition function
60  vec<Lit> clause(2);
61  for (unsigned int p = 0; p < m_numberStates; p++) {
62  for (const char &a : m_alphabet) {
63  for (unsigned int q = 0; q < m_numberStates; q++) {
64  for (unsigned int r = 0; r < m_numberStates; r++) {
65  if (q != r) {
66  clause[0] = mkLit(m_dVars.find(std::make_tuple(p, a, q))->second, true);
67  clause[1] = mkLit(m_dVars.find(std::make_tuple(p, a, r))->second, true);
68  addClause(clause);
69  }
70  }
71  }
72  }
73  }
74 
75  // Equation 4.5.2
76  // For every u in Pref, we must have that there exists (at least) one q in Q such that x_{u, q} is true
77  // In other words, every prefix must reach at least one state
78  clause.clear();
79  clause.growTo(m_numberStates);
80  for (const auto &u : m_prefixes) {
81  for (unsigned int q = 0 ; q < m_numberStates ; q++) {
82  clause[q] = mkLit(m_xVars.find(std::make_pair(u, q))->second, false);
83  }
84  addClause(clause);
85  }
86 
87  // Equation 4.5.3
88  // For every ua in Pref, p, q in Q, we must have (x_{u, p} AND d_{p, a, q}) => x_{ua, q}
89  // In other words, if delta(q_0, u) = p and delta(p, a) = q, we must have delta(q_0, ua) = q
90  clause.clear();
91  clause.growTo(3);
92  for (const auto &ua : m_prefixes) {
93  if (ua.size() > 0) {
94  const std::string &u = ua.substr(0, ua.size() - 1);
95  const char &a = ua.at(ua.size() - 1);
96 
97  for (unsigned int p = 0 ; p < m_numberStates ; p++) {
98  for (unsigned int q = 0 ; q < m_numberStates ; q++) {
99  clause[0] = mkLit(m_xVars.find(std::make_pair(u, p))->second, true);
100  clause[1] = mkLit(m_dVars.find(std::make_tuple(p, a, q))->second, true);
101  clause[2] = mkLit(m_xVars.find(std::make_pair(ua, q))->second, false);
102  addClause(clause);
103  }
104  }
105  }
106  }
107 
108  // Equation 4.5.4
109  // For every u in S_+, q in Q, x_{u, q} => f_q
110  // AND
111  // For every u in S_-, q in Q, x_{u, q} => NOT f_q
112  // In other words, the DFA must be consistent with S
113  clause.clear();
114  clause.growTo(2);
115  for (unsigned int q = 0; q < m_numberStates; q++) {
116  for (const auto &u : m_Sp) {
117  clause[0] = mkLit(m_xVars.find(std::make_pair(u, q))->second, true);
118  clause[1] = mkLit(m_fVars.find(q)->second, false);
119  addClause(clause);
120  }
121 
122  for (const auto &u : m_Sm) {
123  clause[0] = mkLit(m_xVars.find(std::make_pair(u, q))->second, true);
124  clause[1] = mkLit(m_fVars.find(q)->second, true);
125  addClause(clause);
126  }
127  }
128 
129  // Equation 4.5.5
130  // For every p in Q, a in Sigma, we must have that there exists (at least) on q in Q such that d_{p, a, q} is true
131  // This equation forces that every state has an outgoing transition for every symbol in the alphabet
132  clause.clear();
133  clause.growTo(m_numberStates);
134  for (unsigned int p = 0; p < m_numberStates; p++) {
135  for (const char &a : m_alphabet) {
136  for (unsigned int q = 0; q < m_numberStates; q++) {
137  clause[q] = mkLit(m_dVars.find(std::make_tuple(p, a, q))->second, false);
138  }
139  addClause(clause);
140  }
141  }
142 
143  // Equation 4.5.6
144  // For every u in Pref, p, q in Q such that p != q, me must have NOT (x_{u, p} AND x_{u, q})
145  // This equation forces that at most one variable in x_{u, q_0}, ..., x_{u, q_n} is true
146  // Therefore, along with 4.5.2, we now have that every prefix ends in exactly one state
147  clause.clear();
148  clause.growTo(2);
149  for (const auto &u : m_prefixes) {
150  for (unsigned int p = 0 ; p < m_numberStates ; p++) {
151  for (unsigned int q = 0 ; q < m_numberStates ; q++) {
152  if (p != q) {
153  clause[0] = mkLit(m_xVars.find(std::make_pair(u, p))->second, true);
154  clause[1] = mkLit(m_xVars.find(std::make_pair(u, q))->second, true);
155  addClause(clause);
156  }
157  }
158  }
159  }
160 
161  // Equation 4.5.7
162  // For every ua in Pref, p, q in Q, we must have that (x_{u, p} AND x_{ua, q}) => d_{p, a, q}
163  // If we have delta(q_0, u) = p and delta(q_0, ua) = q, then we must have that delta(p, a) = q to remain coherent
164  clause.clear();
165  clause.growTo(3);
166  for (const auto &ua : m_prefixes) {
167  if (ua.size() > 0) {
168  const std::string &u = ua.substr(0, ua.size() - 1);
169  const char &a = ua.at(ua.size() - 1);
170 
171  for (unsigned int p = 0 ; p < m_numberStates ; p++) {
172  for (unsigned int q = 0 ; q < m_numberStates ; q++) {
173  clause[0] = mkLit(m_xVars.find(std::make_pair(u, p))->second, true);
174  clause[1] = mkLit(m_xVars.find(std::make_pair(ua, q))->second, true);
175  clause[2] = mkLit(m_dVars.find(std::make_tuple(p, a, q))->second, false);
176  addClause(clause);
177  }
178  }
179  }
180  }
181  }
182 
183  std::unique_ptr<DFA<char>> HeuleVerwerCNFMethod::toDFA(const Minisat::vec<Minisat::lbool> &model) const {
184  // First, we must seek the initial state
185  unsigned int initial = 0;
186  for (unsigned int i = 0; i < m_numberStates; i++) {
187  Var v = m_xVars.find(std::make_pair("", i))->second;
188  if (model[v] == l_True) {
189  initial = i;
190  break;
191  }
192  }
193 
194  // The initial state is accepting if f_{initial} is true
195  std::unique_ptr<DFA<char>> dfa = std::make_unique<DFA<char>>(initial, model[m_fVars.find(initial)->second] == l_True);
196 
197  // Now, we create every other state (and define the accepting ones)
198  for (unsigned int q = 0; q < m_numberStates; q++) {
199  if (q != initial) {
200  dfa->addState(q, model[m_fVars.find(q)->second] == l_True);
201  }
202  }
203 
204  // Finally, we create the transitions
205  for (unsigned int p = 0; p < m_numberStates; p++) {
206  for (const char &a : m_alphabet) {
207  for (unsigned int q = 0; q < m_numberStates; q++) {
208  if (model[m_dVars.find(std::make_tuple(p, a, q))->second] == l_True) {
209  dfa->addTransition(p, a, q);
210  }
211  }
212  }
213  }
214 
215  return dfa;
216  }
217  }
218  }
219 }
const std::set< char > m_alphabet
Definition: Method.h:121
std::map< unsigned int, Minisat::Var > m_fVars
The namespace of the library.
Definition: binary.h:11
void createVariables() override
Creates all needed variables for the method.
void addClause(const Minisat::vec< Minisat::Lit > &clause)
Adds a new clause to the SAT solver.
const std::set< std::string > m_Sm
The set of words to reject .
Definition: Method.h:105
std::map< std::tuple< unsigned int, char, unsigned int >, Minisat::Var > m_dVars
const std::set< std::string > m_prefixes
Definition: Method.h:117
This file declares the Heule and Verwer method that relies on CNF SAT solver.
static bool s_registered
Useful to make sure the template is correctly used by the compiler.
Definition: MethodFactory.h:97
std::unique_ptr< DFA< char > > toDFA(const Minisat::vec< Minisat::lbool > &model) const override
Effectively creates the DFA from the values of the variables in the given model.
std::map< std::pair< std::string, unsigned int >, Minisat::Var > m_xVars
const unsigned int m_numberStates
The number of states in the DFA to construct.
Definition: Method.h:109
Base class for every method that relies on a SAT solver.
Definition: SATCNFMethod.h:22
const std::set< std::string > m_Sp
The set of words to accept .
Definition: Method.h:101
void createClauses() override
Creates all needed clauses for the method.
Minisat::Var newVariable()
Creates a new variable in the SAT solver.