.gitignore
[prop.git] / lib-src / automata / densedfa.cc
blob62cd57e2ecb101eb0120e0e99774a4c5682b4d93
1 //////////////////////////////////////////////////////////////////////////////
2 // NOTICE:
3 //
4 // ADLib, Prop and their related set of tools and documentation are in the
5 // public domain. The author(s) of this software reserve no copyrights on
6 // the source code and any code generated using the tools. You are encouraged
7 // to use ADLib and Prop to develop software, in both academic and commercial
8 // settings, and are free to incorporate any part of ADLib and Prop into
9 // your programs.
11 // Although you are under no obligation to do so, we strongly recommend that
12 // you give away all software developed using our tools.
14 // We also ask that credit be given to us when ADLib and/or Prop are used in
15 // your programs, and that this notice be preserved intact in all the source
16 // code.
18 // This software is still under development and we welcome any suggestions
19 // and help from the users.
21 // Allen Leung
22 // 1994
23 //////////////////////////////////////////////////////////////////////////////
25 #include <limits.h>
26 #include <string.h>
27 #include <AD/automata/densedfa.h>
29 //#define DEBUGMSG(e) e
30 #define DEBUGMSG(e)
32 //////////////////////////////////////////////////////////////////////////
33 // Make hidden types visible
34 //////////////////////////////////////////////////////////////////////////
35 typedef DenseDFA::Symbol Symbol;
36 typedef DenseDFA::State State;
38 //////////////////////////////////////////////////////////////////////////
39 // Constructor and destructor
40 //////////////////////////////////////////////////////////////////////////
41 DenseDFA::DenseDFA() : def(0) {}
42 DenseDFA::~DenseDFA() { delete [] def; }
44 //////////////////////////////////////////////////////////////////////////
45 // Create tables for dense dfa
46 //////////////////////////////////////////////////////////////////////////
47 void DenseDFA::create_tables (int size, int states, Symbol min, Symbol max)
48 { Super::create_tables(size,states,min,max);
49 def = new State [number_of_states];
50 for (int i = 0; i < number_of_states; i++) def[i] = 0;
53 //////////////////////////////////////////////////////////////////////////
54 // Increment the size of tables
55 //////////////////////////////////////////////////////////////////////////
56 void DenseDFA::grow_states(int increment)
57 { State * new_def = new State [number_of_states + increment];
58 memcpy(new_def, def, number_of_states * sizeof(State));
59 for (int i = number_of_states; i < number_of_states + increment; i++)
60 new_def[i] = 0;
61 delete [] def;
62 def = new_def;
63 Super::grow_states(increment);
66 //////////////////////////////////////////////////////////////////////////
67 // Start generating tabels and initialize temporary tables
68 //////////////////////////////////////////////////////////////////////////
69 void DenseDFA::start()
70 { Super::start();
71 number_of_symbols = max_symbol - min_symbol + 1;
72 diffs[0] = new State [ number_of_symbols ];
73 diffs[1] = new State [ number_of_symbols ];
74 transitions = new State [ number_of_symbols ];
75 symbols = new Symbol [ number_of_symbols ];
76 my_delta = new State [ number_of_symbols ];
77 if (number_of_symbols <= 32)
78 max_template_diff = number_of_symbols / 3;
79 else if (number_of_symbols <= 64)
80 max_template_diff = number_of_symbols / 4;
81 else
82 max_template_diff = number_of_symbols / 5;
83 max_template_diff = number_of_symbols / 3;
84 max_template_diff = number_of_symbols;
87 // Create a template for state 0, the error state
89 templates[0].state = 0;
90 templates[0].delta = new State [ number_of_symbols ];
91 templates[0].age = 0;
92 templates[0].uses = 100000; // prevent us from removing this template
93 for (int i = 0; i < number_of_symbols; i++)
94 templates[0].delta[i] = error_state;
95 number_of_templates = 1;
96 misses = 0;
97 current_age = 0;
98 empty_slots = true;
101 //////////////////////////////////////////////////////////////////////////
102 // Finish generating tables and free up temporary tables
103 //////////////////////////////////////////////////////////////////////////
104 void DenseDFA::finish()
105 { Super::finish();
106 for (int i = 0; i < number_of_templates; i++)
107 delete [] templates[i].delta;
108 delete [] diffs[0];
109 delete [] diffs[1];
110 delete [] transitions;
111 delete [] symbols;
112 delete [] my_delta;
115 //////////////////////////////////////////////////////////////////////////
116 // Add a new state into the automaton
117 //////////////////////////////////////////////////////////////////////////
118 void DenseDFA::add_state
119 (State s, int fan_out, const Symbol syms[], const State delta[])
120 { register int i;
121 for (i = number_of_symbols - 1; i >= 0; i--)
122 my_delta[i] = error_state;
123 for (i = fan_out - 1; i >= 0; i--)
124 my_delta[ syms[ i ] - min_symbol ] = delta [ i ];
125 add_state(s, my_delta);
128 //////////////////////////////////////////////////////////////////////////
129 // Add a new state into the automaton
130 //////////////////////////////////////////////////////////////////////////
131 void DenseDFA::add_state(State s, const State delta[])
132 { //
133 // First compute the current state with the set of templates.
134 // If one of the template is similar enough with the current state,
135 // use the template state as the default basis.
137 int fan_out; // the fan out, or difference of fan out
138 int available = 0; // index into the diffs table
139 int best_fan_out = INT_MAX; // mimimum fan out
140 int best_template = -1; // template that fits the best
141 int best_diffs = 0; // index of the minimal difference
142 const State same_state = error_state-1;
143 register int i;
144 for (i = number_of_templates - 1; i >= 0; i--) {
146 // compute the difference between delta and the templates
148 register State * a_template = templates[i].delta;
149 register State * result = diffs[available];
150 register int j;
151 for (fan_out = 0, j = 0; j < number_of_symbols; j++) {
152 if (a_template[j] != delta[j]) { result[j] = delta[j]; fan_out++; }
153 else result[j] = same_state;
157 // If a better template is found, update the new minimum and
158 // switch the buffer so that the minimal difference is always
159 // available in |diffs[best_diffs]|.
161 if (fan_out < best_fan_out) {
162 best_template = i; best_fan_out = fan_out; best_diffs = available;
163 available = 1 - available;
167 Bool using_template; // Are we using a template
168 const State * out; // the final out transitions
171 // Check whether a suitable template has been located. If so,
172 // use the template as the default state; otherwise, the error state
173 // is the default state.
175 DEBUGMSG(cerr << "[best fan out = " << best_fan_out
176 << " max_template_diff = " << max_template_diff);
177 if (best_template >= 0 && best_fan_out < max_template_diff) {
178 out = diffs[best_diffs];
179 using_template = true;
180 templates[best_template].uses++;
181 templates[best_template].age = current_age;
182 DEBUGMSG(cerr << " using template " << best_template
183 << " uses = " << templates[best_template].uses << "]\n");
184 } else {
185 out = delta;
186 using_template = false;
187 DEBUGMSG(cerr << "]\n");
191 // Eliminate all transitions from the transition function that
192 // goes to the same state as our template.
194 for (fan_out = 0, i = number_of_symbols - 1; i >= 0; i--)
195 if (out[i] != same_state) {
196 symbols[fan_out] = i + min_symbol;
197 transitions[fan_out] = out[i];
198 fan_out++;
202 // Emit into the table using the regular sparse compression
203 // strategy. The idea is that hopefully we'll have a useful template
204 // most of the time and thus being able to ``thin'' out the transitions.
206 Super::add_state(s, fan_out, symbols, transitions);
209 // Emit the default state of this state, which is the state of
210 // the template if available.
212 def[s] = using_template ? templates[best_template].state
213 : (State)error_state;
216 // Insert new current entry into template queue if it does not
217 // have a template and if the queue is not full.
219 // if ((! using_template ||
220 // (max_template_diff - best_fan_out) < number_of_symbols / 6)
221 // && number_of_templates < Max_templates) {
222 Bool add_template =
223 ! using_template ||
224 best_fan_out > 1 && templates[best_template].uses > 10 ||
225 best_fan_out >= number_of_symbols / 3;
227 if (add_template)
228 { if (number_of_templates < Max_templates) {
229 // Create new template
230 DEBUGMSG(cerr << "[creating template "
231 << number_of_templates << "]\n");
232 templates[number_of_templates].state = s;
233 templates[number_of_templates].age = current_age;
234 templates[number_of_templates].uses = 0;
235 memcpy(
236 templates[number_of_templates].delta
237 = new State [ number_of_symbols ],
238 delta,number_of_symbols * sizeof(State));
239 number_of_templates++;
240 } else if (empty_slots) {
241 // Replace template with the oldest used template
242 int min_age = 1000000;
243 int min_use = -1;
244 int target = -1;
245 for (int j = 1; j < Max_templates; j++)
246 { if (templates[j].age < min_age)
247 { target = j; min_age = templates[j].age; }
248 if (templates[j].uses == 0) { min_use = j; }
250 if (min_use >= 0) target = min_use;
251 if (target > 0 && (templates[target].uses == 0 || best_fan_out > 10))
253 DEBUGMSG(cerr << "[replacing template " << target << " with age "
254 << min_age << " uses = "
255 << templates[target].uses << "]\n");
256 templates[target].state = s;
257 templates[target].age = current_age;
258 templates[target].uses = 0;
259 memcpy(templates[target].delta, delta,
260 number_of_symbols * sizeof(State));
261 } //else empty_slots = false;
264 current_age++;
267 //////////////////////////////////////////////////////////////////////////
268 // Emit C++ code that reconstructs the tables
269 //////////////////////////////////////////////////////////////////////////
270 std::ostream& DenseDFA::gen_code (std::ostream& out, const char name []) const
272 Super::gen_code(out,name);
273 gen_state_table(out,name,"def",def + error_state,max_state-error_state+1);
274 return out;
277 //////////////////////////////////////////////////////////////////////////
278 // Emit C++ code that reconstructs the tables (sans base)
279 //////////////////////////////////////////////////////////////////////////
280 std::ostream& DenseDFA::gen_check_next_tables
281 (std::ostream& out, const char name [], const char * mytype) const
283 Super::gen_check_next_tables(out,name,mytype);
284 gen_state_table(out,name,"def",def + error_state,max_state-error_state+1,
285 mytype);
286 return out;