reduce.cc 9.89 KB
Newer Older
1
2
// Copyright (C) 2008, 2009, 2010 Laboratoire de Recherche et
// Dveloppement de l'Epita (LRDE).
Guillaume Sadegh's avatar
Guillaume Sadegh committed
3
// Copyright (C) 2004, 2006, 2007 Laboratoire d'Informatique de
Alexandre Duret-Lutz's avatar
Alexandre Duret-Lutz committed
4
// Paris 6 (LIP6), dpartement Systmes Rpartis Coopratifs (SRC),
5
// Universit Pierre et Marie Curie.
martinez's avatar
martinez committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING.  If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.

24
#include "reduce.hh"
25
#include "basicreduce.hh"
26
#include "syntimpl.hh"
27
#include "ltlast/allnodes.hh"
martinez's avatar
martinez committed
28
29
30
#include <cassert>

#include "lunabbrev.hh"
31
#include "simpfg.hh"
martinez's avatar
martinez committed
32
#include "nenoform.hh"
33
#include "contain.hh"
martinez's avatar
martinez committed
34
35
36
37
38

namespace spot
{
  namespace ltl
  {
39
    namespace
martinez's avatar
martinez committed
40
    {
41
      class reduce_visitor: public visitor
martinez's avatar
martinez committed
42
      {
43
      public:
44

45
46
47
48
	reduce_visitor(int opt)
	  : opt_(opt)
	{
	}
martinez's avatar
martinez committed
49

50
51
52
	virtual ~reduce_visitor()
	{
	}
53

54
55
56
57
58
	formula*
	result() const
	{
	  return result_;
	}
59

60
61
62
	void
	visit(atomic_prop* ap)
	{
63
	  formula* f = ap->clone();
64
65
	  result_ = f;
	}
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
	void
	visit(constant* c)
	{
	  result_ = c;
	}

	void
	visit(unop* uo)
	{
	  result_ = recurse(uo->child());

	  switch (uo->op())
	    {
	    case unop::Not:
	      result_ = unop::instance(unop::Not, result_);
	      return;

	    case unop::X:
	      result_ = unop::instance(unop::X, result_);
	      return;

	    case unop::F:
	      /* If f is a pure eventuality formula then F(f)=f.  */
	      if (!(opt_ & Reduce_Eventuality_And_Universality)
		  || !is_eventual(result_))
		result_ = unop::instance(unop::F, result_);
	      return;

	    case unop::G:
	      /* If f is a pure universality formula then G(f)=f.  */
	      if (!(opt_ & Reduce_Eventuality_And_Universality)
		  || !is_universal(result_))
		result_ = unop::instance(unop::G, result_);
	      return;
101
102
103
104

	    case unop::Finish:
	      result_ = unop::instance(unop::Finish, result_);
	      return;
105
106
107
108
109
110
111
112
	    }
	  /* Unreachable code.  */
	  assert(0);
	}

	void
	visit(binop* bo)
	{
113
114
	  binop::type op = bo->op();

115
	  formula* f2 = recurse(bo->second());
116
	  bool f2_eventual = false;
117

118
	  if (opt_ & Reduce_Eventuality_And_Universality)
119
	    {
120
121
122
123
124
125
126
127
128
	      f2_eventual = is_eventual(f2);
	      /* If b is a pure eventuality formula then a U b = b.
		 If b is a pure universality formula a R b = b. */
	      if ((f2_eventual && (op == binop::U))
		  || (is_universal(f2) && (op == binop::R)))
		{
		  result_ = f2;
		  return;
		}
129
	    }
130

131
	  formula* f1 = recurse(bo->first());
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
	  if (opt_ & Reduce_Eventuality_And_Universality)
	    {
	      /* If a&b is a pure eventuality formula then a M b = a & b.
		 If a is a pure universality formula a W b = a|b. */
	      if (is_eventual(f1) && f2_eventual && (op == binop::M))
		{
		  result_ = multop::instance(multop::And, f1, f2);
		  return;
		}
	      if (is_universal(f1) && (op == binop::W))
		{
		  result_ = multop::instance(multop::Or, f1, f2);
		  return;
		}
	    }
147

148
149

	  /* case of implies */
150
151
	  if (opt_ & Reduce_Syntactic_Implications)
	    {
152
	      switch (op)
153
		{
154
155
156
157
158
159
160
		case binop::Xor:
		case binop::Equiv:
		case binop::Implies:
		  break;

		case binop::U:
		  /* a < b => a U b = b */
Alexandre Duret-Lutz's avatar
Alexandre Duret-Lutz committed
161
		  if (syntactic_implication(f1, f2))
162
163
		    {
		      result_ = f2;
164
		      f1->destroy();
165
166
		      return;
		    }
167
		  /* !b < a => a U b = Fb */
Alexandre Duret-Lutz's avatar
Alexandre Duret-Lutz committed
168
		  if (syntactic_implication_neg(f2, f1, false))
169
170
		    {
		      result_ = unop::instance(unop::F, f2);
171
		      f1->destroy();
172
173
174
		      return;
		    }
		  /* a < b => a U (b U c) = (b U c) */
175
		  /* a < b => a U (b W c) = (b W c) */
176
		  {
177
		    binop* bo = dynamic_cast<binop*>(f2);
178
		    if (bo && (bo->op() == binop::U || bo->op() == binop::W)
179
180
181
			&& syntactic_implication(f1, bo->first()))
		      {
			result_ = f2;
182
			f1->destroy();
183
184
			return;
		      }
185
		  }
186
187
188
189
		  break;

		case binop::R:
		  /* b < a => a R b = b */
Alexandre Duret-Lutz's avatar
Alexandre Duret-Lutz committed
190
		  if (syntactic_implication(f2, f1))
191
192
		    {
		      result_ = f2;
193
		      f1->destroy();
194
195
		      return;
		    }
196
		  /* b < !a => a R b = Gb */
Alexandre Duret-Lutz's avatar
Alexandre Duret-Lutz committed
197
		  if (syntactic_implication_neg(f2, f1, true))
198
199
		    {
		      result_ = unop::instance(unop::G, f2);
200
		      f1->destroy();
201
202
203
		      return;
		    }
		  /* b < a => a R (b R c) = b R c */
204
		  /* b < a => a R (b M c) = b M c */
205
206
		  {
		    binop* bo = dynamic_cast<binop*>(f2);
207
		    if (bo && (bo->op() == binop::R || bo->op() == binop::M)
208
209
210
			&& syntactic_implication(bo->first(), f1))
		      {
			result_ = f2;
211
			f1->destroy();
212
213
214
			return;
		      }
		  }
215
216
217
218
219
220
221
222
223
224
225
226
		  /* a < b => a R (b R c) = a R c */
		  {
		    binop* bo = dynamic_cast<binop*>(f2);
		    if (bo && bo->op() == binop::R
			&& syntactic_implication(f1, bo->first()))
		      {
			result_ = binop::instance(binop::R, f1,
						  bo->second()->clone());
			f2->destroy();
			return;
		      }
		  }
227
		  break;
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

		case binop::W:
		  /* a < b => a W b = b */
		  if (syntactic_implication(f1, f2))
		    {
		      result_ = f2;
		      f1->destroy();
		      return;
		    }
		  /* !b < a => a W b = 1 */
		  if (syntactic_implication_neg(f2, f1, false))
		    {
		      result_ = constant::true_instance();
		      f1->destroy();
		      f2->destroy();
		      return;
		    }
		  /* a < b => a W (b W c) = (b W c) */
		  {
		    binop* bo = dynamic_cast<binop*>(f2);
248
		    if (bo && bo->op() == binop::W
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
			&& syntactic_implication(f1, bo->first()))
		      {
			result_ = f2;
			f1->destroy();
			return;
		      }
		  }
		  break;

		case binop::M:
		  /* b < a => a M b = b */
		  if (syntactic_implication(f2, f1))
		    {
		      result_ = f2;
		      f1->destroy();
		      return;
		    }
		  /* b < !a => a M b = 0 */
		  if (syntactic_implication_neg(f2, f1, true))
		    {
		      result_ = constant::false_instance();
		      f1->destroy();
		      f2->destroy();
		      return;
		    }
274
		  /* b < a => a M (b M c) = b M c */
275
276
		  {
		    binop* bo = dynamic_cast<binop*>(f2);
277
		    if (bo && bo->op() == binop::M
278
279
280
281
282
283
284
			&& syntactic_implication(bo->first(), f1))
		      {
			result_ = f2;
			f1->destroy();
			return;
		      }
		  }
285
286
287
288
289
290
291
292
293
294
295
296
297
		  /* a < b => a M (b M c) = a M c */
		  /* a < b => a M (b R c) = a M c */
		  {
		    binop* bo = dynamic_cast<binop*>(f2);
		    if (bo && (bo->op() == binop::M || bo->op() == binop::R)
			&& syntactic_implication(f1, bo->first()))
		      {
			result_ = binop::instance(binop::M, f1,
						  bo->second()->clone());
			f2->destroy();
			return;
		      }
		  }
298
		  break;
299
		}
300
	    }
301
	  result_ = binop::instance(op, f1, f2);
302
	}
303

304
305
306
307
308
309
	void
	visit(automatop*)
	{
	  assert(0);
	}

310
311
312
313
314
	void
	visit(multop* mo)
	{
	  unsigned mos = mo->size();
	  multop::vec* res = new multop::vec;
martinez's avatar
martinez committed
315

316
317
	  for (unsigned i = 0; i < mos; ++i)
	    res->push_back(recurse(mo->nth(i)));
318

319
320
	  if (opt_ & Reduce_Syntactic_Implications)
	    {
321

322
323
324
	      bool removed = true;
	      multop::vec::iterator f1;
	      multop::vec::iterator f2;
325

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
	      while (removed)
		{
		  removed = false;
		  f2 = f1 = res->begin();
		  ++f1;
		  while (f1 != res->end())
		    {
		      assert(f1 != f2);
		      // a < b => a + b = b
		      // a < b => a & b = a
		      if ((syntactic_implication(*f1, *f2) && // f1 < f2
			   (mo->op() == multop::Or)) ||
			  ((syntactic_implication(*f2, *f1)) && // f2 < f1
			   (mo->op() == multop::And)))
			{
			  // We keep f2
342
			  (*f1)->destroy();
343
344
345
346
347
348
349
350
351
352
			  res->erase(f1);
			  removed = true;
			  break;
			}
		      else if ((syntactic_implication(*f2, *f1) && // f2 < f1
				(mo->op() == multop::Or)) ||
			       ((syntactic_implication(*f1, *f2)) && // f1 < f2
				(mo->op() == multop::And)))
			{
			  // We keep f1
353
			  (*f2)->destroy();
354
355
356
357
358
359
360
361
			  res->erase(f2);
			  removed = true;
			  break;
			}
		      else
			++f1;
		    }
		}
362

363
364
365
366
367
368
369
370
371
372
	      /* f1 < !f2 => f1 & f2 = false
		 !f1 < f2 => f1 | f2 = true */
	      for (f1 = res->begin(); f1 != res->end(); f1++)
		for (f2 = res->begin(); f2 != res->end(); f2++)
		  if (f1 != f2 &&
		      syntactic_implication_neg(*f1, *f2,
						mo->op() !=  multop::Or))
		    {
		      for (multop::vec::iterator j = res->begin();
			   j != res->end(); j++)
373
			(*j)->destroy();
374
375
376
377
378
379
380
381
		      res->clear();
		      delete res;
		      if (mo->op() == multop::Or)
			result_ = constant::true_instance();
		      else
			result_ = constant::false_instance();
		      return;
		    }
382

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
	    }

	  if (!res->empty())
	    {
	      result_ = multop::instance(mo->op(), res);
	      return;
	    }
	  assert(0);
	}

	formula*
	recurse(formula* f)
	{
	  return reduce(f, opt_);
	}

      protected:
	formula* result_;
	int opt_;
      };
martinez's avatar
martinez committed
403

404
    } // anonymous
martinez's avatar
martinez committed
405
406

    formula*
407
    reduce(const formula* f, int opt)
408
    {
409
410
      formula* f1;
      formula* f2;
411
      formula* prev = 0;
412

413
      int n = 0;
414

415
      while (f != prev)
416
	{
417
418
419
420
	  ++n;
	  assert(n < 100);
	  if (prev)
	    {
421
	      prev->destroy();
422
423
424
425
	      prev = const_cast<formula*>(f);
	    }
	  else
	    {
426
	      prev = f->clone();
427
428
429
	    }
	  f1 = unabbreviate_logic(f);
	  f2 = simplify_f_g(f1);
430
	  f1->destroy();
431
	  f1 = negative_normal_form(f2);
432
	  f2->destroy();
433
434
435
436
	  f2 = f1;

	  if (opt & Reduce_Basics)
	    {
437
	      f1 = basic_reduce(f2);
438
	      f2->destroy();
439
440
	      f2 = f1;
	    }
441

442
443
444
445
446
447
	  if (opt & (Reduce_Syntactic_Implications
		     | Reduce_Eventuality_And_Universality))
	    {
	      reduce_visitor v(opt);
	      f2->accept(v);
	      f1 = v.result();
448
	      f2->destroy();
449
450
	      f2 = f1;
	    }
451
452


453
454
455
456
457
458
	  if (opt & (Reduce_Containment_Checks
		     | Reduce_Containment_Checks_Stronger))
	    {
	      formula* f1 =
		reduce_tau03(f2,
			     opt & Reduce_Containment_Checks_Stronger);
459
	      f2->destroy();
460
461
462
463
	      f2 = f1;
	    }
	  f = f2;
	}
464
      prev->destroy();
465
      return const_cast<formula*>(f);
martinez's avatar
martinez committed
466
467
468
    }
  }
}