spot  2.3.3.dev
interpolate.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2016, 2017 Laboratoire de Recherche et
3 // Developpement de l'Epita
4 //
5 // This file is part of Spot, a model checking library.
6 //
7 // Spot is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // Spot is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 
20 #pragma once
21 
22 #include <functional>
23 #include <stdlib.h>
24 #include <spot/mc/reachability.hh>
25 #include <spot/misc/timer.hh>
26 #include <chrono>
27 
28 #include <bricks/brick-hashset>
29 #include <atomic>
30 
31 namespace spot
32 {
33  template<typename State, typename SuccIterator,
34  typename StateHash, typename StateEqual>
35  class count_valid : public seq_reach_kripke<State, SuccIterator,
36  StateHash, StateEqual,
37  count_valid<State, SuccIterator,
38  StateHash, StateEqual>>
39  {
40  public:
42  State new_initial,
43  std::function<bool(const State)> count_valid_fun,
44  std::function<int(State)> get_depth,
45  std::function<int(State)> get_pos,
46  unsigned id,
47  unsigned tid, bool& stop, std::string algoname)
48  : seq_reach_kripke<State, SuccIterator, StateHash, StateEqual,
49  count_valid<State, SuccIterator,
50  StateHash, StateEqual>>(sys, tid, stop),
51  new_initial_(new_initial), count_valid_fun_(count_valid_fun),
52  get_depth_(get_depth), get_pos_(get_pos), id_(id), algoname_(algoname)
53  {
54  }
55 
56  virtual ~count_valid()
57  {
58 
59  }
60 
61  void setup()
62  {
63  }
64 
65  bool push(State st, unsigned int dfsnum)
66  {
67  if (dfsnum == 0)
68  {
69  // Here Hack the reachability to specify startup
70  this->visited.erase(st);
71  this->sys_.recycle(this->todo.back().it, this->tid_);
72  this->todo.pop_back();
73  this->todo.push_back({new_initial_,
74  this->sys_.succ(new_initial_, this->tid_)});
75  this->visited[new_initial_] = this->dfs_number;
76  this->dfs_number = 1;
77  if (count_valid_fun_(new_initial_))
78  ++counter_;
79  return false;
80  }
81 
82  if (count_valid_fun_(st))
83  {
84  ++counter_;
85  if (first_depth_ == -1)
86  {
87  first_depth_ = get_depth_(st);
88  first_pos_ = get_pos_(st);
89  }
90  }
91  return true;
92  }
93 
94  bool pop(State)
95  {
96  return true;
97  }
98 
99  void edge(unsigned int, unsigned int)
100  {
101  }
102 
103  void finalize()
104  {
105  float x = (float) counter_ / this->states();
106  std::cout << '@' << id_
107  << ',' << algoname_
108  << ',' << first_depth_
109  << ',' << first_pos_
110  << ',' << x
111  << ',' << this->states()
112  << ',' << this->trans()
113  << ',' << counter_
114  << (this->stop_? ",ABORTED" : ",FINISHED");
115  this->stop_ = true;
116  }
117 
118  private:
119  State new_initial_;
120  std::function<bool(const State)> count_valid_fun_;
121  std::function<int(State)> get_depth_;
122  std::function<int(State)> get_pos_;
123  unsigned int counter_ = 0;
124  int first_depth_ = -1;
125  int first_pos_ = -1;
126  unsigned id_ = 0;
127  std::string algoname_;
128  };
129 
130  template<typename State, typename SuccIterator,
131  typename StateHash, typename StateEqual>
132  class interpolate : public seq_reach_kripke<State, SuccIterator,
133  StateHash, StateEqual,
134  interpolate<State, SuccIterator,
135  StateHash, StateEqual>>
136  {
137  public:
139  std::function<void(State, unsigned int)> display,
140  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun,
141  unsigned tid, bool& stop, std::string algoname)
142  : seq_reach_kripke<State, SuccIterator, StateHash, StateEqual,
143  interpolate<State, SuccIterator,
144  StateHash, StateEqual>>(sys, tid, stop),
145  display_(display), interpolate_fun_(interpolate_fun), algoname_(algoname)
146  {
147  (void) display;
148  depth.reserve(1000);
149  }
150 
151  virtual ~interpolate()
152  {
153  }
154 
155  void setup()
156  {
157  tm_.start("original DFS");
158  }
159 
160  bool push(State st, unsigned int dfsnum)
161  {
162  if (dfsnum <= 1000) // FIXME threshold
163  sample_.push_back(st);
164 
165  depth.insert({st, (int) this->todo.size()});
166  dfspos.insert({st, (int) this->dfs_number});
167 
168  return true;
169  }
170 
171  bool pop(State)
172  {
173  return true;
174  }
175 
176  void edge(unsigned int, unsigned int)
177  {
178  }
179 
180  void finalize()
181  {
182  using namespace std::literals::chrono_literals;
183  tm_.stop("original DFS");
184 
185  std::cout << "STATES : " << this->states() << std::endl;
186  std::cout << "TRANSITIONS : " << this->trans() << std::endl;
187  std::cout << "TIME : " << tm_.timer("original DFS").walltime()
188  << std::endl;
189  tm_.start("Generation of states");
190  auto* gen = interpolate_fun_(sample_);
191  tm_.stop("Generation of states");
192 
193  std::cout << "GenPop : " << tm_.timer("Generation of states").walltime()
194  << std::endl;
195 
196  for (unsigned i = 0; i < gen->size(); ++i)
197  {
198  bool stop = false;
199  //SPOT_ASSERT(gen[i] != nullptr);
201  cv(this->sys_, (*gen)[i], [this](State s) -> bool
202  {
203  return this->visited.find(s) != this->visited.end();
204  },
205  [this](State s) -> int
206  {
207  return depth[s];
208  },
209  [this](State s) -> int
210  {
211  return dfspos[s];
212  },
213  i,
214  0, /* FIXME tid */
215  stop, algoname_);
216  std::thread th
218  cv);
219 
220  // Sleep for 10 minutes
221  for (unsigned t = 0; t < 600 && !stop; ++t)
222  std::this_thread::sleep_for(1s);
223  stop = true;
224  th.join();
225  std::cout << std::endl;
226  }
227  delete gen;
228  }
229 
230  private:
231  std::function<void(State, unsigned int)> display_;
232  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun_;
233  std::vector<State> sample_;
234  spot::timer_map tm_;
235  typedef std::unordered_map<const State, int,
236  StateHash, StateEqual> visited_map;
237  visited_map depth;
238  visited_map dfspos;
239  std::string algoname_;
240  };
241 
242 
243 
244  template<typename State, typename SuccIterator,
245  typename StateHash, typename StateEqual>
246  class swarmed_dfs :
247  public seq_reach_kripke<State, SuccIterator,
248  StateHash, StateEqual,
249  swarmed_dfs<State, SuccIterator,
250  StateHash, StateEqual>>
251  {
252  struct my_pair
253  {
254  my_pair(): color(0){}
255  my_pair(const my_pair& p): st(p.st), color(p.color.load()){}
256  my_pair(const State st, int bar): st(st), color(bar) { }
257  my_pair& operator=(my_pair& other)
258  {
259  if (this == &other)
260  return *this;
261  st = other.st;
262  color = other.color.load();
263  return *this;
264  }
265  State st;
266  std::atomic<int> color;
267  };
268 
269  struct inner_pair_hasher
270  {
271  inner_pair_hasher(const my_pair&)
272  { }
273 
274  inner_pair_hasher() = default;
275 
276  brick::hash::hash128_t
277  hash(const my_pair& lhs) const
278  {
279  StateHash hash;
280  auto u = hash(lhs.st);
281  return {u, u}; // Just ignore the second part
282  }
283 
284  bool equal(const my_pair& lhs,
285  const my_pair& rhs) const
286  {
287  StateEqual equal;
288  return equal(lhs.st, rhs.st);
289  }
290  };
291 
292  enum st_status // Describe the status of a state
293  {
294  OPEN = 0, // The state is currently processed by a thread
295  CLOSED = 1 // All the successors of this state have been visited
296  };
297 
298  public:
299  using shared_map = brick::hashset::FastConcurrent <my_pair,
300  inner_pair_hasher>;
301 
303  shared_map& map,
304  unsigned tid, bool& stop)
305  : seq_reach_kripke<State, SuccIterator, StateHash, StateEqual,
306  swarmed_dfs<State, SuccIterator,
307  StateHash, StateEqual>>(sys, tid, stop),
308  map_(map)
309  { }
310 
311  virtual ~swarmed_dfs()
312  {
313  }
314 
315  void setup()
316  {
317  tm_.start("DFS thread " + std::to_string(this->tid_));
318  }
319 
320  bool push(State s, unsigned int)
321  {
322  ++states_;
323  auto it = map_.insert({s, OPEN});
324 
325  // State has been marked as dead by another thread
326  // just skip the insertion
327  bool b = it.isnew();
328  inserted_ += b;
329  if (!b && it->color.load(std::memory_order_relaxed) == CLOSED)
330  {
331  return false;
332  }
333  return true;
334  }
335 
336  bool pop(State s)
337  {
338  // Don't avoid pop but modify the status of the state
339  // during backtrack
340  auto it = map_.insert({s, CLOSED}); // FIXME Find is enough
341  it->color.store(CLOSED, std::memory_order_relaxed);
342  return true;
343  }
344 
345  void edge(unsigned int, unsigned int)
346  {
347  ++edges_;
348  }
349 
350  void finalize()
351  {
352  this->stop_ = true;
353  tm_.stop("DFS thread " + std::to_string(this->tid_));
354  }
355 
356  unsigned walltime()
357  {
358  return tm_.timer("DFS thread " + std::to_string(this->tid_))
359  .walltime();
360  }
361 
362  unsigned inserted()
363  {
364  return inserted_;
365  }
366 
367  unsigned states()
368  {
369  return states_;
370  }
371 
372  unsigned edges()
373  {
374  return edges_;
375  }
376 
377  unsigned how_many_generations()
378  {
379  return nb_gens_;
380  }
381 
382  private:
383  spot::timer_map tm_;
384  shared_map map_;
385  unsigned inserted_ = 0;
386  unsigned nb_gens_ = 0;
387  unsigned states_ = 0;
388  unsigned edges_ = 0;
389  };
390 
391 
392 
393  template<typename State, typename SuccIterator,
394  typename StateHash, typename StateEqual>
395  class swarmed_gp :
396  public seq_reach_kripke<State, SuccIterator,
397  StateHash, StateEqual,
398  swarmed_gp<State, SuccIterator,
399  StateHash, StateEqual>>
400  {
401  struct my_pair
402  {
403  my_pair(): color(0){}
404  my_pair(const my_pair& p): st(p.st), color(p.color.load()){}
405  my_pair(const State st, int bar): st(st), color(bar) { }
406  my_pair& operator=(my_pair& other)
407  {
408  if (this == &other)
409  return *this;
410  st = other.st;
411  color = other.color.load();
412  return *this;
413  }
414  State st;
415  std::atomic<int> color;
416  };
417 
418  struct inner_pair_hasher
419  {
420  inner_pair_hasher(const my_pair&)
421  { }
422 
423  inner_pair_hasher() = default;
424 
425  brick::hash::hash128_t
426  hash(const my_pair& lhs) const
427  {
428  StateHash hash;
429  auto u = hash(lhs.st);
430  return {u, u}; // Just ignore the second part
431  }
432 
433  bool equal(const my_pair& lhs,
434  const my_pair& rhs) const
435  {
436  StateEqual equal;
437  return equal(lhs.st, rhs.st);
438  }
439  };
440 
441  enum st_status // Describe the status of a state
442  {
443  OPEN = 0, // The state is currently processed by a thread
444  CLOSED = 1, // All the successors of this state have been visited
445  UNKNOWN = 2,
446  UNKNOWN_CLOSED = 3
447  };
448 
449  public:
450  using shared_map = brick::hashset::FastConcurrent <my_pair,
451  inner_pair_hasher>;
452 
454  std::function<std::vector<State>*(std::vector<State>&)>
455  interpolate_fun,
456  shared_map& map,
457  unsigned tid, bool& stop)
458  : seq_reach_kripke<State, SuccIterator, StateHash, StateEqual,
459  swarmed_gp<State, SuccIterator,
460  StateHash, StateEqual>>(sys, tid, stop),
461  interpolate_fun_(interpolate_fun), map_(map)
462  {
463  if (!tid%2) // FIXME How many !
464  phase1 = false; // Reference, no GP for this thread
465  }
466 
467  virtual ~swarmed_gp()
468  {
469  }
470 
471  void setup()
472  {
473  tm_.start("DFS GP thread " + std::to_string(this->tid_));
474  }
475 
476  bool push(State s, unsigned int dfsnum)
477  {
478  ++states_;
479  if (SPOT_UNLIKELY(dfsnum <= 1000 && phase1)) // FIXME threshold
480  {
481  sample_.push_back(s);
482 
483  // Here we decide to reset the current DFS using states
484  // that have been mutated from GP.
485  if (dfsnum == 1000)
486  {
487  phase1 = false;
488  insert_status_ = UNKNOWN;
489  new_gen = interpolate_fun_(sample_);
490 
491  // Recycle iterators
492  for (auto& e: this->todo)
493  this->sys_.recycle(e.it, this->tid_);
494 
495  // Clear structures.
496  this->todo.clear();
497  this->dfs_number = 0;
498  this->visited.clear();
499 
500  // Select a "new" initial state among those generated
501  this->todo.push_back({new_gen->at(new_gen_idx),
502  this->sys_.succ(new_gen->at(new_gen_idx), this->tid_)});
503  this->visited[new_gen->at(new_gen_idx)] = this->dfs_number;
504  this->dfs_number = 1;
505  s = new_gen->at(new_gen_idx);
506  ++new_gen_idx;
507  }
508  }
509 
510  auto it = map_.insert({s, insert_status_});
511 
512  // State has been marked as dead by another thread
513  // just skip the insertion
514  st_status status = (st_status) it->color.load(std::memory_order_relaxed);
515  bool b = it.isnew();
516  inserted_ += b;
517  if (!b && status == CLOSED)
518  //(status == CLOSED || status == UNKNOWN_CLOSED))
519  return false;
520  return true;
521  }
522 
523  bool pop(State s)
524  {
525  // Don't avoid pop but modify the status of the state
526  // during backtrack
527  auto it = map_.insert({s, CLOSED}); // FIXME Find is enough
528 
529  // st_status status = (st_status) it->color.load(std::memory_order_relaxed);
530  // if (status == OPEN)
531  it->color.store(CLOSED, std::memory_order_relaxed);
532  // else
533  // it->color.store(UNKNOWN_CLOSED, std::memory_order_relaxed);
534 
535  // Go ahead with another state iff popping the "initial" state
536  // Do not worry about terminaison: the thread with tid = 0 will
537  // stop the world as soon as it finishes
538  if (SPOT_UNLIKELY(insert_status_ != OPEN && this->todo.size() == 1))
539  {
540  ++nb_gens_;
541  for (auto& e: this->todo)
542  this->sys_.recycle(e.it, this->tid_);
543 
544  // Clear structures.
545  this->todo.clear();
546  this->dfs_number = 0;
547  this->visited.clear();
548 
549  // When this condition holds it means that
550  // (1) all the state-spaces from mutated initial states
551  // have been explored
552  // (2) the "valid" state-space from the initial state
553  // has not yet finished
554  // In this case, relaunch a DFS to help the other one.
555  if (SPOT_UNLIKELY(new_gen_idx == new_gen->size()))
556  {
557  new_gen_idx = 0;
558  new_gen->clear();
559  new_gen->push_back(this->sys_.initial(this->tid_));
560  insert_status_ = OPEN;
561  }
562 
563  // Select a "new" initial state among those generated
564  this->todo.push_back({new_gen->at(new_gen_idx),
565  this->sys_.succ(new_gen->at(new_gen_idx), this->tid_)});
566  this->visited[new_gen->at(new_gen_idx)] = this->dfs_number;
567  this->dfs_number = 1;
568  ++new_gen_idx;
569  return false;
570  }
571 
572  return true;
573  }
574 
575  void edge(unsigned int, unsigned int)
576  {
577  ++edges_;
578  }
579 
580  void finalize()
581  {
582  if (insert_status_ == OPEN)
583  this->stop_ = true;
584  tm_.stop("DFS GP thread " + std::to_string(this->tid_));
585  }
586 
587  unsigned walltime()
588  {
589  return tm_.timer("DFS GP thread " + std::to_string(this->tid_))
590  .walltime();
591  }
592 
593  unsigned inserted()
594  {
595  return inserted_;
596  }
597 
598  unsigned states()
599  {
600  return states_;
601  }
602 
603  unsigned edges()
604  {
605  return edges_;
606  }
607 
608  unsigned how_many_generations()
609  {
610  return nb_gens_;
611  }
612 
613  private:
614  spot::timer_map tm_;
615  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun_;
616  shared_map map_;
617  std::vector<State> sample_;
618  bool phase1 = true;
619  std::vector<State>* new_gen = nullptr;
620  unsigned new_gen_idx = 0;
621  st_status insert_status_ = OPEN;
622  unsigned inserted_ = 0;
623  unsigned nb_gens_ = 0;
624  unsigned states_ = 0;
625  unsigned edges_ = 0;
626  };
627 }
Definition: graph.hh:33
Definition: interpolate.hh:246
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition: kripke.hh:37
A map of timer, where each timer has a name.
Definition: timer.hh:227
Definition: interpolate.hh:395
Definition: interpolate.hh:35
Definition: interpolate.hh:132
This template class provide a sequential reachability of a kripkecube. The algorithm uses a single DF...
Definition: reachability.hh:33

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Tue Apr 18 2017 14:42:56 for spot by doxygen 1.8.13