libgsjj  1
Deterministic finite automata learning library
NeiderJansenMethod.cpp
Go to the documentation of this file.
2 
3 using namespace CVC4;
4 
5 bool isAccepting(Expr f_value) {
6  return f_value.getConst<Rational>().getNumerator().toUnsignedInt() != 0;
7 }
8 
9 namespace gsjj {
10  namespace passive {
11  namespace SMT {
12  NeiderJansenMethod::NeiderJansenMethod(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) :
13  SMTMethod(SpSet, SmSet, SSet, prefixesSet, alphabetSet, n)
14  {
16  LogicInfo logic;
17  logic.enableIntegers();
18  logic.enableTheory(theory::THEORY_UF);
19  m_SMTEngine.setLogic(logic);
20  }
21 
23 
24  }
25 
27  return "neider";
28  }
29 
31  // Basic types
32  Type integer = m_exprManager.integerType();
33 
34  // Now, we create a type for the N x N domain
35  DatatypeType intTimesInt = m_exprManager.mkTupleType({integer, integer});
36  // The constructor for this tuple
37  intTimesIntConstructor = intTimesInt.getDatatype()[0].getConstructor();
38 
39  // We can finally create the function's types needed
40  // The type for f and x
41  Type intToInt = m_exprManager.mkFunctionType(integer, integer);
42  // The type for d
43  Type intTimesIntToInt = m_exprManager.mkFunctionType(intTimesInt, integer);
44 
45  // We also create the functions
46  x = m_exprManager.mkVar("x", intToInt);
47  f = m_exprManager.mkVar("f", intToInt);
48  d = m_exprManager.mkVar("d", intTimesIntToInt);
49 
50  // Some constants
51  zero = m_exprManager.mkConst(Rational(0));
52  n = m_exprManager.mkConst(Rational(m_numberStates));
53 
54  // We create a distinct constant for every prefix
55  unsigned int i = 0;
56  for (const auto &u : m_prefixes) {
57  m_prefixToInt.emplace(u, m_exprManager.mkConst(Rational(i++)));
58  }
59  }
60 
62 
63  Expr x_0 = m_exprManager.mkExpr(kind::APPLY_UF, x, zero);
64 
65  // Equation 4.6.1 : x(0) < n
66  Expr assumptions = m_exprManager.mkExpr(kind::LT, x_0, n);
67 
68  // Equation 4.6.2 : for all i in Q, a in Sigma, d(i, a) < n
69  for (unsigned int i = 0 ; i < m_numberStates ; i++) {
70  for (const char &a : m_alphabet) {
71  Expr i_a = m_exprManager.mkExpr(kind::APPLY_CONSTRUCTOR, intTimesIntConstructor, m_exprManager.mkConst(Rational(i)), m_exprManager.mkConst(Rational(a)));
72  assumptions = assumptions.andExpr(
73  m_exprManager.mkExpr(
74  kind::LT,
75  m_exprManager.mkExpr(
76  kind::APPLY_UF,
77  d,
78  i_a
79  ),
80  n
81  )
82  );
83  }
84  }
85 
86  // Equation 4.6.3 : for all u_i, u_j in Pref, for all a in Sigma such that u_j = u_i a, x(j) = d(x(i), a)
87  for (const auto &ui : m_prefixes) {
88  for (const auto &uj : m_prefixes) {
89  // We need that u_j = u_i
90  if (uj.size() > 0 && uj.substr(0, uj.size() - 1) == ui) {
91  Expr a = m_exprManager.mkConst(Rational(uj.at(uj.size() - 1)));
92  Expr i = m_prefixToInt[ui];
93  Expr j = m_prefixToInt[uj];
94 
95  Expr x_j = m_exprManager.mkExpr(kind::APPLY_UF, x, j);
96  Expr x_i = m_exprManager.mkExpr(kind::APPLY_UF, x, i);
97  Expr x_i_a = m_exprManager.mkExpr(kind::APPLY_CONSTRUCTOR, intTimesIntConstructor, x_i, a);
98 
99  assumptions = assumptions.andExpr(
100  m_exprManager.mkExpr(kind::EQUAL,
101  x_j,
102  m_exprManager.mkExpr(kind::APPLY_UF, d, x_i_a)
103  )
104  );
105  }
106  }
107  }
108 
109  // Equation 4.6.4
110  for (const auto &ui : m_Sp) {
111  Expr x_i = m_exprManager.mkExpr(kind::APPLY_UF, x, m_prefixToInt[ui]);
112  Expr f_x_i = m_exprManager.mkExpr(kind::APPLY_UF, f, x_i);
113  assumptions = assumptions.andExpr(m_exprManager.mkExpr(kind::DISTINCT, f_x_i, zero));
114  }
115  for (const auto &ui : m_Sm) {
116  Expr x_i = m_exprManager.mkExpr(kind::APPLY_UF, x, m_prefixToInt[ui]);
117  Expr f_x_i = m_exprManager.mkExpr(kind::APPLY_UF, f, x_i);
118  assumptions = assumptions.andExpr(m_exprManager.mkExpr(kind::EQUAL, f_x_i, zero));
119  }
120 
121  // Finally, we must have that x(i) >= 0 (because it's a N -> N function)
122  for (const auto &ui : m_prefixes) {
123  Expr x_i = m_exprManager.mkExpr(kind::APPLY_UF, x, m_prefixToInt[ui]);
124  assumptions = assumptions.andExpr(m_exprManager.mkExpr(kind::GEQ, x_i, zero));
125  }
126 
127  return assumptions;
128  }
129 
130  std::unique_ptr<DFA<char>> NeiderJansenMethod::toDFA() {
131  // We start by searching the initial state
132  Expr x_0 = m_exprManager.mkExpr(kind::APPLY_UF, x, zero);
133  unsigned int initial = m_SMTEngine.getValue(x_0).getConst<Rational>().getNumerator().toUnsignedInt();
134 
135  std::unique_ptr<DFA<char>> dfa = std::make_unique<DFA<char>>(initial, isAccepting(m_SMTEngine.getValue(m_exprManager.mkExpr(kind::APPLY_UF, f, x_0))));
136 
137  // Now, we process the other states
138  for (unsigned int i = 0 ; i < m_numberStates ; i++) {
139  if (i != initial) {
140  Expr f_i = m_exprManager.mkExpr(kind::APPLY_UF, f, m_exprManager.mkConst(Rational(i)));
141 
142  dfa->addState(i, isAccepting(m_SMTEngine.getValue(f_i)));
143  }
144  }
145 
146  // Finally, we create the transitions
147  for (unsigned int i = 0 ; i < m_numberStates ; i++) {
148  for (const char &a : m_alphabet) {
149  Expr i_a = m_exprManager.mkExpr(kind::APPLY_CONSTRUCTOR, intTimesIntConstructor, m_exprManager.mkConst(Rational(i)), m_exprManager.mkConst(Rational(a)));
150  Expr d_i_a = m_exprManager.mkExpr(kind::APPLY_UF, d, i_a);
151 
152  unsigned int j = m_SMTEngine.getValue(d_i_a).getConst<Rational>().getNumerator().toUnsignedInt();
153 
154  dfa->addTransition(i, a, j);
155  }
156  }
157 
158  return dfa;
159  }
160  }
161  }
162 }
const std::set< char > m_alphabet
Definition: Method.h:121
The namespace of the library.
Definition: binary.h:11
const std::set< std::string > m_Sm
The set of words to reject .
Definition: Method.h:105
const std::set< std::string > m_prefixes
Definition: Method.h:117
std::unique_ptr< DFA< char > > toDFA()
Effectively creates the DFA from the values of the variables in the SMT solver (see SMTMethod::m_SMTE...
bool isAccepting(Expr f_value)
static bool s_registered
Useful to make sure the template is correctly used by the compiler.
Definition: MethodFactory.h:97
CVC4::Expr createConstraints() override
Creates an unique expression describing the constraints of this method.
The base class for every SMT-based method.
Definition: SMTMethod.h:20
const unsigned int m_numberStates
The number of states in the DFA to construct.
Definition: Method.h:109
void createVariables() override
Creates all needed variables for the method.
CVC4::ExprManager m_exprManager
This must be used to create new variables, constants and expressions.
Definition: SMTMethod.h:35
const std::set< std::string > m_Sp
The set of words to accept .
Definition: Method.h:101
CVC4::SmtEngine m_SMTEngine
This computes acceptable values for the variables and allows to retrieve them.
Definition: SMTMethod.h:39