-
Notifications
You must be signed in to change notification settings - Fork 4
/
PkTable.cpp
executable file
·346 lines (296 loc) · 10.9 KB
/
PkTable.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*
* Copyright. Gaël Dottel, Christoph Hilken, and Jan Peleska 2016 - 2021
*
* Licensed under the EUPL V.1.1
*/
#include "fsm/PkTable.h"
#include "fsm/FsmNode.h"
#include "fsm/Dfsm.h"
#include "fsm/FsmLabel.h"
#include "fsm/FsmTransition.h"
#include "fsm/PkTableRow.h"
#include "interface/FsmPresentationLayer.h"
using namespace std;
int PkTable::counter;
PkTable::PkTable(const int numStates, const int maxInput, const shared_ptr<FsmPresentationLayer>& presentationLayer)
: s2c(numStates), maxInput(maxInput), presentationLayer(presentationLayer)
{
rows.insert(rows.end(), numStates, nullptr);
}
PkTable::PkTable(const int numStates, const int maxInput, const vector<shared_ptr<PkTableRow>>& rows, const shared_ptr<FsmPresentationLayer>& presentationLayer)
: rows(rows), s2c(numStates), maxInput(maxInput), presentationLayer(presentationLayer)
{
}
void PkTable::setRow(const int s, const shared_ptr<PkTableRow>& row)
{
rows[s] = row;
}
void PkTable::setClass(const int n, const int c)
{
s2c[n] = c;
}
int PkTable::getClass(const int n) const
{
return s2c.at(n);
}
int PkTable::maxClassId() const
{
int id = 0;
for (unsigned int i = 0; i < s2c.size(); ++i)
{
if (s2c.at(i) > id)
{
id = s2c.at(i);
}
}
return id;
}
shared_ptr<PkTable> PkTable::getPkPlusOneTable() const
{
shared_ptr<PkTable> pkp1 = make_shared<PkTable>(rows.size(), maxInput, rows, presentationLayer);
int thisClass = 0;
int thisNewClassId = maxClassId() + 1;
shared_ptr<PkTableRow> refRow;
shared_ptr<PkTableRow> newClassRefRow = nullptr;
bool haveNewClasses = false;
do
{
refRow = nullptr;
// For each class thisClass, we loop over the number of rows
// which is the same for each Pk-table (= number if states)
for (unsigned int i = 0; i < rows.size(); ++i)
{
// We are only interested in rows that were assigned to thisClass
// in this Pk-table.
if (s2c.at(i) != thisClass)
{
continue;
}
// In the new Pk-table pkp1 (P_(k+1)-table), we only want to
// assign class number to rows that do not have a class number yet.
// These rows are still marked with -1 ("undefined class number"),
// this initialisation is performed by the constructor of Int2intMap.
if (pkp1->getClass(i) >= 0)
{
continue;
}
// We want to mark the first row associated in this Pk-table as
// reference row.
// refRow == nullptr indicates that we do not yet have
// a reference row.
// The reference row is the first row to be associated
// with class thisClass.
if (refRow == nullptr)
{
refRow = rows.at(i);
pkp1->setClass(i, thisClass);
// We are done with this loop cycle, because the reference row
// has been found, and now rows with a greater index shall be
// investigated with respect to equivalence to the reference row.
continue;
}
// Here, we handle the row rows.at(i) which comes AFTER
// the reference row.
// This means that index i is greater than the index of
// the reference row.
// We know already that rows.at(i) has been associated with
// thisClass in this Pk-table,
// but is not yet associated with a class in the new
// P_(k+1) table pkp1.
if ( refRow->isEquivalent(*rows.at(i), s2c) )
{
// The actual row rows.at(i) is also equivalent
// to the reference row in the new table pkp1.
// Therefore it gets the same class number as the reference row.
// Note that this is also the same class number it had been associated
// with in this Pk-table.
pkp1->setClass(i, thisClass);
// We are done with row rows.at(i)
continue;
}
// rows.at(i) was in the same class as the reference row
// in this Pk-table,
// but has to be moved into a new class in the P_(k+1)-table.
// This new class must have a new number above 0..maxClassId(),
// because a row which is no longer equivalent to the othrs
// in thisClass
// will never be moved into a class from 0..maxClassId()
// which already existed in this
// Pk-table. The new class id to be used is stored in thisNewClassId.
haveNewClasses = true;
newClassRefRow = rows.at(i);
pkp1->setClass(i, thisNewClassId);
// Now we check whether any other rows above rows.at(i),
// which were originally
// in the same class thisClass as rows.at(i),
// are equivalent to rows.at(i)
// in the new table php1. These rows get the same
// new class id as rows.at(i).
// After having run through this loop, there are
// no more rows which might be
// equivalent to rows.at(i).
for (unsigned int j = i + 1; j < rows.size(); ++j)
{
if ( s2c.at(j) == thisClass and
pkp1->getClass(j) < 0 and
newClassRefRow->isEquivalent(*rows.at(j), s2c) )
{
pkp1->setClass(j, thisNewClassId);
}
}
// We might find other rows above rows.at(i)
// that may have been equivalent to the reference row in
// this Pk-table,
// but are neither equivalent to the reference row nor to rows.at(i)
// in pkp1. These rows will be associated with the next
// new class id set here.
++thisNewClassId;
// newClassRefRow is no longer valid
newClassRefRow = nullptr;
}
// All rows that may still belong to thisClass in pkp1 have been identified now.
// We switch to the next class.
++thisClass;
// refRow == nullPtr means that all rows are already associated
// with a new class ID,
// so that we can terminate.
} while (refRow != nullptr);
return haveNewClasses ? pkp1 : nullptr;
}
Dfsm PkTable::toFsm(string name, const int maxOutput)
{
string minFsmName("");
vector<shared_ptr<FsmNode>> nodeLst;
/* We need a new presentation layer.
* Input and output names are the same as for the original FSM,
* but states should have new names including the set of
* original nodes that are equivalent.
*/
vector<string> minState2String;
for (int i = 0; i <= maxClassId(); ++i) {
string newName(minFsmName + getMembers(i));
minState2String.push_back(newName);
}
shared_ptr<FsmPresentationLayer> minPl =
make_shared<FsmPresentationLayer>(presentationLayer->getIn2String(),
presentationLayer->getOut2String(),
minState2String);
/*Create the FSM states, one for each class*/
for (int i = 0; i <= maxClassId(); ++i)
{
shared_ptr<FsmNode> newNode = make_shared<FsmNode>(i, "", minPl);
nodeLst.push_back(newNode);
}
/*For each FSM state, add outgoing transitions*/
for (shared_ptr<FsmNode> srcNode : nodeLst)
{
int classId = srcNode->getId();
shared_ptr<PkTableRow> row = nullptr;
for (unsigned int i = 0; i < rows.size() && row == nullptr; ++i)
{
if (classId == s2c.at(i))
{
row = rows.at(i);
}
}
for (int x = 0; x <= maxInput; ++ x)
{
int y = row->getIOMap().at(x);
int cAux = row->getI2PMap().at(x);
// If the Fsm is not completely specified,
// it may be the case that no transition for this
// input exists.
if ( cAux < 0 ) continue;
int cTarget = s2c.at(cAux);
shared_ptr<FsmNode> tgtNode = nullptr;
// Find the new FsmNode in the minimised FSM
// which has cTarget as node id
for (shared_ptr<FsmNode> node : nodeLst)
{
if (node->getId() == cTarget)
{
tgtNode = node;
break;
}
}
shared_ptr<FsmLabel> lbl = make_shared<FsmLabel>(x, y, minPl);
srcNode->addTransition(make_shared<FsmTransition>(srcNode,
tgtNode,
lbl));
}
}
return Dfsm(minFsmName, maxInput, maxOutput, nodeLst, minPl);
}
string PkTable::getMembers(const int c) const
{
string memSet = "{";
bool first = true;
for (unsigned int i = 0; i < rows.size(); ++i)
{
if (s2c.at(i) != c)
{
continue;
}
if (!first)
{
memSet += ",";
}
first = false;
memSet += presentationLayer->getStateId(i,"");
}
memSet += "}";
return memSet;
}
ostream & operator<<(ostream & out, const PkTable & pkTable)
{
// Create the table header
out << endl << "\\begin{center}" << endl << "\\begin{tabular}{|c|c||";
for (int i = 0; i <= pkTable.maxInput; ++i)
{
out << "c|";
}
out << "|";
for (int i = 0; i <= pkTable.maxInput; ++i)
{
out << "c|";
}
out << "}\\hline\\hline" << endl;
out << " & & \\multicolumn{" << pkTable.maxInput + 1;
out << "}{|c||}{\\bf I2O} & \\multicolumn{" << pkTable.maxInput + 1;
out << "}{|c|}{$\\bf I2[P]_{" << PkTable::counter << "}$}" << endl << "\\\\\\hline" << endl;
out << "{$\\bf [q]_{" << PkTable::counter << "}$} & {\\bf q} ";
for (int i = 0; i <= pkTable.maxInput; ++i)
{
out << " & " << i;
}
for (int i = 0; i <= pkTable.maxInput; ++i)
{
out << " & " << i;
}
out << "\\\\\\hline\\hline" << endl;
// Output each table row
for (unsigned int i = 0; i < pkTable.rows.size(); ++i)
{
if (pkTable.rows.at(i) == nullptr)
{
continue;
}
//out << pkTable.s2c.at(i) << " & " << i << " " << *pkTable.rows.at(i);
out << "\\bf{\\underline " << pkTable.s2c.at(i) << "} & " << i << " ";
for (auto& map : (*pkTable.rows.at(i)).getIOMap()) {
out << " & " << map.second;
}
for (auto& map : (*pkTable.rows.at(i)).getI2PMap()) {
S2CMap::const_iterator iterator = pkTable.s2c.find(map.second);
if (iterator == pkTable.s2c.end()) {
out << " & ";
continue;
}
out << " & \\bf{\\underline " << (*iterator).second << "}";
}
out << "\\\\\\hline" << endl;
}
// Create the table footer
out << "\\hline" << endl << "\\end{tabular}" << endl << "\\end{center}" << endl << endl;
return out;
}