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  void setup()
61  {
62  }
63 
64  bool push(State st, unsigned int dfsnum)
65  {
66  if (dfsnum == 0)
67  {
68  for (auto& e: this->todo)
69  this->sys_.recycle(e.it, this->tid_);
70 
71  // Clear structures.
72  this->todo.clear();
73  this->dfs_number = 0;
74  this->visited.clear();
75 
76 
77  // Select a "new" initial state among those generated
78  this->todo.push_back({new_initial_,
79  this->sys_.succ(new_initial_, this->tid_)});
80  this->visited[new_initial_] = this->dfs_number;
81  this->dfs_number = 1;
82 
83  if (count_valid_fun_(new_initial_))
84  ++counter_;
85 
86  return false;
87  }
88 
89  if (count_valid_fun_(st))
90  {
91  ++counter_;
92  if (first_depth_ == -1)
93  {
94  first_depth_ = get_depth_(st);
95  first_pos_ = get_pos_(st);
96  }
97  }
98  return true;
99  }
100 
101  bool pop(State)
102  {
103  return true;
104  }
105 
106  void edge(unsigned int, unsigned int)
107  {
108  }
109 
110  void finalize()
111  {
112  float x = (float) counter_ / this->states();
113  std::cout << '@' << id_
114  << ",count_" << algoname_
115  << ',' << first_depth_
116  << ',' << first_pos_
117  << ',' << x
118  << ',' << this->states()
119  << ',' << this->trans()
120  << ',' << counter_
121  << (this->stop_? ",ABORTED" : ",FINISHED");
122  this->stop_ = true;
123  }
124 
125  private:
126  State new_initial_;
127  std::function<bool(const State)> count_valid_fun_;
128  std::function<int(State)> get_depth_;
129  std::function<int(State)> get_pos_;
130  unsigned int counter_ = 0;
131  int first_depth_ = -1;
132  int first_pos_ = -1;
133  unsigned id_ = 0;
134  std::string algoname_;
135  };
136 
137  template<typename State, typename SuccIterator,
138  typename StateHash, typename StateEqual>
139  class interpolate : public seq_reach_kripke<State, SuccIterator,
140  StateHash, StateEqual,
141  interpolate<State, SuccIterator,
142  StateHash, StateEqual>>
143  {
144  public:
146  std::function<void(State, unsigned int)> display,
147  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun,
148  unsigned tid, bool& stop, std::string algoname, int init_pop)
149  : seq_reach_kripke<State, SuccIterator, StateHash, StateEqual,
150  interpolate<State, SuccIterator,
151  StateHash, StateEqual>>(sys, tid, stop),
152  display_(display), interpolate_fun_(interpolate_fun), algoname_(algoname),
153  init_pop_(init_pop)
154  {
155  (void) display;
156  depth.reserve(1000);
157  }
158 
159  virtual ~interpolate()
160  {
161  }
162 
163  void setup()
164  {
165  tm_.start("original DFS");
166  }
167 
168  bool push(State st, unsigned int dfsnum)
169  {
170  if (((int)dfsnum) <= init_pop_)
171  sample_.push_back(st);
172 
173  depth.insert({st, (int) this->todo.size()});
174  dfspos.insert({st, (int) this->dfs_number});
175 
176  return true;
177  }
178 
179  bool pop(State)
180  {
181  return true;
182  }
183 
184  void edge(unsigned int, unsigned int)
185  {
186  }
187 
188  void finalize()
189  {
190  using namespace std::literals::chrono_literals;
191  tm_.stop("original DFS");
192 
193  std::cout << "STATES : " << this->states() << std::endl;
194  std::cout << "TRANSITIONS : " << this->trans() << std::endl;
195  std::cout << "TIME : " << tm_.timer("original DFS").walltime()
196  << std::endl;
197  tm_.start("Generation of states");
198  std::vector<State>* gen = nullptr;
199  gen = interpolate_fun_(sample_);
200  tm_.stop("Generation of states");
201 
202  std::cout << "GenPop : " << tm_.timer("Generation of states").walltime()
203  << std::endl;
204 
205  for (unsigned i = 0; i < gen->size(); ++i)
206  {
207  bool stop = false;
208  //SPOT_ASSERT(gen[i] != nullptr);
210  cv(this->sys_, (*gen)[i], [this](State s) -> bool
211  {
212  return this->visited.find(s) != this->visited.end();
213  },
214  [this](State s) -> int
215  {
216  return depth[s];
217  },
218  [this](State s) -> int
219  {
220  return dfspos[s];
221  },
222  i,
223  0, /* FIXME tid */
224  stop, algoname_);
225  std::thread th
227  cv);
228 
229  // Sleep for 10 minutes
230  for (unsigned t = 0; t < 600 && !stop; ++t)
231  std::this_thread::sleep_for(1s);
232  stop = true;
233  th.join();
234  std::cout << std::endl;
235  }
236  delete gen;
237  }
238 
239  private:
240  std::function<void(State, unsigned int)> display_;
241  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun_;
242  std::vector<State> sample_;
243  spot::timer_map tm_;
244  typedef std::unordered_map<const State, int,
245  StateHash, StateEqual> visited_map;
246  visited_map depth;
247  visited_map dfspos;
248  std::string algoname_;
249  int init_pop_;
250  };
251 
252 
253  template<typename State, typename SuccIterator,
254  typename StateHash, typename StateEqual>
256  {
257  enum st_status // Describe the status of a state
258  {
259  OPEN = 1, // The state is currently processed by this thread
260  CLOSED = 2, // All the successors of this state have been visited
261  UNKNOWN = 4 // First time this state is discoverd by this thread
262  };
263 
264  struct my_pair
265  {
266  State st;
267  int* colors;
268  };
269 
270  struct inner_pair_hasher
271  {
272  inner_pair_hasher(const my_pair&)
273  { }
274 
275  inner_pair_hasher() = default;
276 
277  brick::hash::hash128_t
278  hash(const my_pair& lhs) const
279  {
280  StateHash hash;
281  // FIXME without that insert/find fail !!
282  unsigned u = hash(lhs.st) % (1<<30);
283  return {u, u};
284  }
285 
286  bool equal(const my_pair& lhs,
287  const my_pair& rhs) const
288  {
289  StateEqual equal;
290  return equal(lhs.st, rhs.st);
291  }
292  };
293 
294  public:
295  using shared_map = brick::hashset::FastConcurrent <my_pair,
296  inner_pair_hasher>;
297 
299  shared_map& map, unsigned tid):
300  sys_(sys), tid_(tid), map_(map),
301  nb_th_(std::thread::hardware_concurrency()),
302  p_(sizeof(int)*std::thread::hardware_concurrency())
303  {
304  SPOT_ASSERT(is_a_kripkecube(sys));
305  }
306 
307  virtual ~swarmed_dfs()
308  {
309  }
310 
311  void setup()
312  {
313  tm_.start("DFS thread " + std::to_string(this->tid_));
314  }
315 
316  bool push(State s, unsigned int tid)
317  {
318  (void) tid;
319  // Prepare data for a newer allocation
320  int* ref = (int*) p_.allocate();
321  for (unsigned i = 0; i < nb_th_; ++i)
322  ref[i] = UNKNOWN;
323 
324  // Try to insert the new state in the shared map.
325  auto it = map_.insert({s, ref});
326  bool b = it.isnew();
327  inserted_ += b;
328 
329  // Insertion failed, delete element
330  // FIXME add a cache to avoid useless allocations.
331  if (!b)
332  p_.deallocate(ref);
333 
334  // The state has been mark dead by another thread
335  for (unsigned i = 0; !b && i < nb_th_; ++i)
336  if (it->colors[i] == static_cast<int>(CLOSED))
337  return false;
338 
339  // The state has already been visited by the current thread
340  if (it->colors[tid_] == static_cast<int>(OPEN))
341  return false;
342 
343  // Keep a ptr over the array of colors
344  refs_.push_back(it->colors);
345 
346  // Mark state as visited.
347  it->colors[tid_] = OPEN;
348  ++states_;
349  return true;
350  }
351 
352  bool pop(State s)
353  {
354  (void) s;
355  // Don't avoid pop but modify the status of the state
356  // during backtrack
357  refs_.back()[tid_] = CLOSED;
358  refs_.pop_back();
359  return true;
360  }
361 
362  void edge(unsigned int, unsigned int)
363  {
364  ++edges_;
365  }
366 
367  void finalize()
368  {
369  tm_.stop("DFS thread " + std::to_string(this->tid_));
370  }
371 
372  unsigned walltime()
373  {
374  return tm_.timer("DFS thread " + std::to_string(this->tid_))
375  .walltime();
376  }
377 
378  unsigned inserted()
379  {
380  return inserted_;
381  }
382 
383  unsigned states()
384  {
385  return states_;
386  }
387 
388  unsigned edges()
389  {
390  return edges_;
391  }
392 
393  unsigned how_many_generations()
394  {
395  return nb_gens_;
396  }
397 
398  void run()
399  {
400  setup();
401  State initial = sys_.initial(tid_);
402  if (SPOT_LIKELY(push(initial, dfs_number)))
403  {
404  todo.push_back({initial, sys_.succ(initial, tid_)});
405  ++dfs_number;
406  }
407  while (!todo.empty())
408  {
409  if (todo.back().it->done())
410  {
411  if (SPOT_LIKELY(pop(todo.back().s)))
412  {
413  sys_.recycle(todo.back().it, tid_);
414  todo.pop_back();
415  }
416  }
417  else
418  {
419  ++transitions;
420  State dst = todo.back().it->state();
421 
422  if (SPOT_LIKELY(push(dst, dfs_number)))
423  {
424  ++dfs_number;
425  todo.back().it->next();
426  todo.push_back({dst, sys_.succ(dst, tid_)});
427  }
428  else
429  {
430  todo.back().it->next();
431  }
432  }
433  }
434  finalize();
435  }
436 
437 
438  private:
439  struct todo_element
440  {
441  State s;
442  SuccIterator* it;
443  };
445  std::vector<todo_element> todo;
446  unsigned int dfs_number = 0;
447  unsigned int transitions = 0;
448  unsigned int tid_;
449 
450  spot::timer_map tm_;
451  shared_map map_;
452  unsigned inserted_ = 0;
453  unsigned nb_gens_ = 0;
454  unsigned states_ = 0;
455  unsigned edges_ = 0;
456  unsigned nb_th_ = 0;
457  fixed_size_pool p_;
458  std::vector<int*> refs_;
459  };
460 
461  std::mutex iomutex; // TOREMOVE
462 
463  template<typename State, typename SuccIterator,
464  typename StateHash, typename StateEqual>
466  {
467  enum st_status // Describe the status of a state
468  {
469  OPEN = 1, // The state is currently processed by this thread
470  CLOSED = 2, // All the successors of this state have been visited
471  UNKNOWN = 4, // First time this state is discoverd by this thread
472  UNKNOWN_OPEN = 8,
473  PHASE_1 = 16
474  };
475 
476  struct my_pair
477  {
478  State st;
479  int* colors;
480  };
481 
482  struct inner_pair_hasher
483  {
484  inner_pair_hasher(const my_pair&)
485  { }
486 
487  inner_pair_hasher() = default;
488 
489  brick::hash::hash128_t
490  hash(const my_pair& lhs) const
491  {
492  StateHash hash;
493  // FIXME without that insert/find fail !!
494  unsigned u = hash(lhs.st) % (1<<30);
495  return {u, u};
496  }
497 
498  bool equal(const my_pair& lhs,
499  const my_pair& rhs) const
500  {
501  StateEqual equal;
502  return equal(lhs.st, rhs.st);
503  }
504  };
505 
506  public:
507  st_status insert_status_;
508  using shared_map = brick::hashset::FastConcurrent <my_pair,
509  inner_pair_hasher>;
510 
512  shared_map& map, unsigned tid,
513  std::function<std::vector<State>*(std::vector<State>&)> fun,
514  std::atomic<bool>& stop, unsigned initial_population = 1000,
515  float strategy = 0.5):
516  sys_(sys), tid_(tid), map_(map),
517  nb_th_(std::thread::hardware_concurrency()),
518  p_(sizeof(int)*std::thread::hardware_concurrency()),
519  interpolate_fun_(fun), stop_(stop), THRESHOLD(initial_population)
520  {
521  SPOT_ASSERT(is_a_kripkecube(sys));
522 
523  if (strategy == 0.5)
524  {
525  // Keep the previous default behavior
526  if (!(tid_%2))
527  phase1 = false;
528  }
529  else if (strategy >= 0 && strategy <= 1)
530  {
531  if (tid < (sys.nb_threads_ * strategy))
532  {
533  phase1 = false;
534  std::cout << tid << " "<< std::endl;
535  }
536  }
537 
538  }
539 
540  virtual ~swarmed_dfs2()
541  {
542  delete new_gen_;
543  }
544 
545  void setup()
546  {
547  tm_.start("DFS thread " + std::to_string(this->tid_));
548  }
549 
550  bool push(State s, unsigned int tid)
551  {
552  (void) tid;
553 
554  // Prepare data for a newer allocation
555  int* ref = (int*) p_.allocate();
556  for (unsigned i = 0; i < nb_th_; ++i)
557  ref[i] = UNKNOWN;
558 
559  // Try to insert the new state in the shared map.
560  auto it = map_.insert({s, ref});
561  bool b = it.isnew();
562  inserted_ += b;
563 
564  // Insertion failed, delete element
565  // FIXME add a cache to avoid useless allocations.
566  if (!b)
567  p_.deallocate(ref);
568 
569  // The state has been mark dead by another thread
570  for (unsigned i = 0; !b && i < nb_th_; ++i)
571  if (it->colors[i] == static_cast<int>(CLOSED))
572  return false;
573 
574  // The state has already been visited by the current thread
575  if (it->colors[tid_] == static_cast<int>(insert_status_))
576  return false;
577 
578  // Keep a ptr over the array of colors
579  refs_.push_back(it->colors);
580 
581  // Mark state as visited.
582  it->colors[tid_] = insert_status_;// FIX for GP previous was OPEN;
583  ++states_;
584  return true;
585  }
586 
587  bool pop(State s)
588  {
589  (void) s;
590  // Don't avoid pop but modify the status of the state
591  // during backtrack
592  refs_.back()[tid_] = CLOSED;
593  refs_.pop_back();
594  return true;
595  }
596 
597  void edge(unsigned int, unsigned int)
598  {
599  ++edges_;
600  }
601 
602  void finalize()
603  {
604  tm_.stop("DFS thread " + std::to_string(this->tid_));
605  }
606 
607  unsigned walltime()
608  {
609  return tm_.timer("DFS thread " + std::to_string(this->tid_))
610  .walltime();
611  }
612 
613  unsigned inserted()
614  {
615  return inserted_;
616  }
617 
618  unsigned states()
619  {
620  return states_;
621  }
622 
623  unsigned edges()
624  {
625  return edges_;
626  }
627 
628  unsigned how_many_generations()
629  {
630  return nb_gens_;
631  }
632 
633  void sampling()
634  {
635  State initial = sys_.initial(tid_);
636  if (SPOT_LIKELY(push(initial, dfs_number)))
637  {
638  todo.push_back({initial, sys_.succ(initial, tid_)});
639  ++dfs_number;
640  sample_.push_back(initial);
641  }
642  while (!todo.empty() && sample_.size() < THRESHOLD)
643  {
644  if (todo.back().it->done())
645  {
646  if (SPOT_LIKELY(pop(todo.back().s)))
647  {
648  sys_.recycle(todo.back().it, tid_);
649  todo.pop_back();
650  }
651  }
652  else
653  {
654  ++transitions;
655  State dst = todo.back().it->state();
656 
657  if (SPOT_LIKELY(push(dst, dfs_number)))
658  {
659  ++dfs_number;
660  todo.back().it->next();
661  todo.push_back({dst, sys_.succ(dst, tid_)});
662  sample_.push_back(dst);
663  }
664  else
665  {
666  todo.back().it->next();
667  }
668  }
669  }
670  }
671 
672  void cleaning()
673  {
674  todo.clear();
675  refs_.clear();
676  dfs_number = 0;
677  }
678 
679  void swarming(State initial)
680  {
681  if (SPOT_LIKELY(push(initial, dfs_number)))
682  {
683  todo.push_back({initial, sys_.succ(initial, tid_)});
684  ++dfs_number;
685  }
686  while (!todo.empty() && !stop_.load(std::memory_order_relaxed))
687  {
688  if (todo.back().it->done())
689  {
690  if (SPOT_LIKELY(pop(todo.back().s)))
691  {
692  sys_.recycle(todo.back().it, tid_);
693  todo.pop_back();
694  }
695  }
696  else
697  {
698  ++transitions;
699  State dst = todo.back().it->state();
700 
701  if (SPOT_LIKELY(push(dst, dfs_number)))
702  {
703  ++dfs_number;
704  todo.back().it->next();
705  todo.push_back({dst, sys_.succ(dst, tid_)});
706  }
707  else
708  {
709  todo.back().it->next();
710  }
711  }
712  }
713  }
714 
715 
716  void run()
717  {
718  setup();
719  if (phase1)
720  {
721  insert_status_ = PHASE_1;
722  sampling();
723  cleaning();
724 
725  // Generate the next geneation from the sample
726  new_gen_ = interpolate_fun_(sample_);
727 
728  // Use all mutated states as initial state
729  unsigned i = 0;
730  while (i < new_gen_->size() && !stop_.load(std::memory_order_relaxed))
731  {
732  insert_status_ = UNKNOWN_OPEN;
733  swarming(new_gen_->at(i));
734  ++i;
735  ++nb_gens_;
736  }
737  }
738  else
739  {
740  insert_status_ = OPEN;
741  swarming(sys_.initial(tid_));
742  stop_.store(true, std::memory_order_relaxed);
743  }
744  finalize();
745  }
746 
747 
748 
749  private:
750  struct todo_element
751  {
752  State s;
753  SuccIterator* it;
754  };
756  std::vector<todo_element> todo;
757  unsigned int dfs_number = 0;
758  unsigned int transitions = 0;
759  unsigned int tid_;
760 
761  spot::timer_map tm_;
762  shared_map map_;
763  unsigned inserted_ = 0;
764  unsigned nb_gens_ = 0;
765  unsigned states_ = 0;
766  unsigned edges_ = 0;
767  unsigned nb_th_ = 0;
768  fixed_size_pool p_;
769  std::vector<int*> refs_;
770  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun_;
771  std::atomic<bool>& stop_;
772  std::vector<State> sample_;
773  bool phase1 = true;
774  std::vector<State>* new_gen_ = nullptr;
775  unsigned THRESHOLD = 1000;
776  };
777 
778 
779 
780 
781 
782  template<typename State, typename SuccIterator,
783  typename StateHash, typename StateEqual>
785  {
786  enum st_status // Describe the status of a state
787  {
788  OPEN = 1, // The state is currently processed by this thread
789  CLOSED = 2, // All the successors of this state have been visited
790  UNKNOWN = 4 // First time this state is discoverd by this thread
791  };
792 
793  struct my_pair
794  {
795  State st;
796  int* colors;
797  };
798 
799  struct inner_pair_hasher
800  {
801  inner_pair_hasher(const my_pair&)
802  { }
803 
804  inner_pair_hasher() = default;
805 
806  brick::hash::hash128_t
807  hash(const my_pair& lhs) const
808  {
809  StateHash hash;
810  // FIXME without that insert/find fail !!
811  unsigned u = hash(lhs.st) % (1<<30);
812  return {u, u};
813  }
814 
815  bool equal(const my_pair& lhs,
816  const my_pair& rhs) const
817  {
818  StateEqual equal;
819  return equal(lhs.st, rhs.st);
820  }
821  };
822 
823  public:
824  using shared_map = brick::hashset::FastConcurrent <my_pair,
825  inner_pair_hasher>;
826 
828  shared_map& map, unsigned tid, std::atomic<bool>& stop):
829  sys_(sys), tid_(tid), map_(map),
830  nb_th_(std::thread::hardware_concurrency()),
831  p_(sizeof(int)*std::thread::hardware_concurrency()), stop_(stop)
832  {
833  SPOT_ASSERT(is_a_kripkecube(sys));
834  }
835 
836  virtual ~swarmed_deadlock()
837  {
838  }
839 
840  void setup()
841  {
842  tm_.start("DFS thread " + std::to_string(this->tid_));
843  }
844 
845  bool push(State s, unsigned int tid)
846  {
847  (void) tid;
848  // Prepare data for a newer allocation
849  int* ref = (int*) p_.allocate();
850  for (unsigned i = 0; i < nb_th_; ++i)
851  ref[i] = UNKNOWN;
852 
853  // Try to insert the new state in the shared map.
854  auto it = map_.insert({s, ref});
855  bool b = it.isnew();
856  inserted_ += b;
857 
858  // Insertion failed, delete element
859  // FIXME add a cache to avoid useless allocations.
860  if (!b)
861  p_.deallocate(ref);
862 
863  // The state has been mark dead by another thread
864  for (unsigned i = 0; !b && i < nb_th_; ++i)
865  if (it->colors[i] == static_cast<int>(CLOSED))
866  return false;
867 
868  // The state has already been visited by the current thread
869  if (it->colors[tid_] == static_cast<int>(OPEN))
870  return false;
871 
872  // Keep a ptr over the array of colors
873  refs_.push_back(it->colors);
874 
875  // Mark state as visited.
876  it->colors[tid_] = OPEN;
877  ++states_;
878  return true;
879  }
880 
881  bool pop(State s)
882  {
883  (void) s;
884  // Don't avoid pop but modify the status of the state
885  // during backtrack
886  refs_.back()[tid_] = CLOSED;
887  refs_.pop_back();
888  return true;
889  }
890 
891  void edge(unsigned int, unsigned int)
892  {
893  ++edges_;
894  }
895 
896  void finalize()
897  {
898  this->stop_ = true;
899  tm_.stop("DFS thread " + std::to_string(this->tid_));
900  }
901 
902  unsigned walltime()
903  {
904  return tm_.timer("DFS thread " + std::to_string(this->tid_))
905  .walltime();
906  }
907 
908  unsigned inserted()
909  {
910  return inserted_;
911  }
912 
913  unsigned states()
914  {
915  return states_;
916  }
917 
918  unsigned edges()
919  {
920  return edges_;
921  }
922 
923  unsigned how_many_generations()
924  {
925  return nb_gens_;
926  }
927 
928  void run()
929  {
930  setup();
931  State initial = sys_.initial(tid_);
932  if (SPOT_LIKELY(push(initial, dfs_number)))
933  {
934  todo.push_back({initial, sys_.succ(initial, tid_), transitions});
935  ++dfs_number;
936  }
937  while (!todo.empty() && !stop_.load(std::memory_order_relaxed))
938  {
939  if (todo.back().it->done())
940  {
941  if (SPOT_LIKELY(pop(todo.back().s)))
942  {
943  deadlock_ = todo.back().current_tr == transitions;
944  if (deadlock_)
945  break;
946  sys_.recycle(todo.back().it, tid_);
947  todo.pop_back();
948  }
949  }
950  else
951  {
952  ++transitions;
953  State dst = todo.back().it->state();
954 
955  if (SPOT_LIKELY(push(dst, dfs_number)))
956  {
957  ++dfs_number;
958  todo.back().it->next();
959  todo.push_back({dst, sys_.succ(dst, tid_), transitions});
960  }
961  else
962  {
963  todo.back().it->next();
964  }
965  }
966  }
967  finalize();
968  }
969 
970  bool has_deadlock()
971  {
972  return deadlock_;
973  }
974 
975  private:
976  struct todo_element
977  {
978  State s;
979  SuccIterator* it;
980  unsigned current_tr;
981  };
983  std::vector<todo_element> todo;
984  unsigned int dfs_number = 0;
985  unsigned int transitions = 0;
986  unsigned int tid_;
987 
988  spot::timer_map tm_;
989  shared_map map_;
990  unsigned inserted_ = 0;
991  unsigned nb_gens_ = 0;
992  unsigned states_ = 0;
993  unsigned edges_ = 0;
994  unsigned nb_th_ = 0;
995  fixed_size_pool p_;
996  std::vector<int*> refs_;
997  bool deadlock_ = false;
998  std::atomic<bool>& stop_;
999  };
1000 
1001 
1002  template<typename State, typename SuccIterator,
1003  typename StateHash, typename StateEqual>
1005  {
1006  enum st_status // Describe the status of a state
1007  {
1008  OPEN = 1, // The state is currently processed by this thread
1009  CLOSED = 2, // All the successors of this state have been visited
1010  CLOSED_DEADLOCK = 3,
1011  UNKNOWN = 4, // First time this state is discoverd by this thread
1012  UNKNOWN_OPEN = 8,
1013  PHASE_1 = 16
1014  };
1015 
1016  struct my_pair
1017  {
1018  State st;
1019  int* colors;
1020  };
1021 
1022  struct inner_pair_hasher
1023  {
1024  inner_pair_hasher(const my_pair&)
1025  { }
1026 
1027  inner_pair_hasher() = default;
1028 
1029  brick::hash::hash128_t
1030  hash(const my_pair& lhs) const
1031  {
1032  StateHash hash;
1033  // FIXME without that insert/find fail !!
1034  unsigned u = hash(lhs.st) % (1<<30);
1035  return {u, u};
1036  }
1037 
1038  bool equal(const my_pair& lhs,
1039  const my_pair& rhs) const
1040  {
1041  StateEqual equal;
1042  return equal(lhs.st, rhs.st);
1043  }
1044  };
1045 
1046  public:
1047  st_status insert_status_;
1048  using shared_map = brick::hashset::FastConcurrent <my_pair,
1049  inner_pair_hasher>;
1050 
1052  shared_map& map, unsigned tid,
1053  std::function<std::vector<State>*(std::vector<State>&)> fun,
1054  std::atomic<bool>& stop, unsigned initial_population = 1000,
1055  float strategy = 0.5):
1056  sys_(sys), tid_(tid), map_(map),
1057  nb_th_(std::thread::hardware_concurrency()),
1058  p_(sizeof(int)*std::thread::hardware_concurrency()),
1059  interpolate_fun_(fun), stop_(stop), THRESHOLD(initial_population)
1060  {
1061  SPOT_ASSERT(is_a_kripkecube(sys));
1062 
1063  if (strategy == 0.5)
1064  {
1065  // Keep the previous default behavior
1066  if (!(tid_%2))
1067  phase1 = false;
1068  }
1069  else if (strategy >= 0 && strategy <= 1)
1070  {
1071  if (tid < (sys.nb_threads_ * strategy))
1072  {
1073  phase1 = false;
1074  std::cout << tid << " "<< std::endl;
1075  }
1076  }
1077  }
1078 
1079  virtual ~swarmed_gp_deadlock()
1080  {
1081  delete new_gen_;
1082  }
1083 
1084  void setup()
1085  {
1086  tm_.start("DFS thread " + std::to_string(this->tid_));
1087  }
1088 
1089  bool push(State s, unsigned int tid)
1090  {
1091  (void) tid;
1092 
1093  // Prepare data for a newer allocation
1094  int* ref = (int*) p_.allocate();
1095  for (unsigned i = 0; i < nb_th_; ++i)
1096  ref[i] = UNKNOWN;
1097 
1098  // Try to insert the new state in the shared map.
1099  auto it = map_.insert({s, ref});
1100  bool b = it.isnew();
1101  inserted_ += b;
1102 
1103  // Insertion failed, delete element
1104  // FIXME add a cache to avoid useless allocations.
1105  if (!b)
1106  p_.deallocate(ref);
1107 
1108  // The state has been mark dead by another thread
1109  for (unsigned i = 0; !b && i < nb_th_; ++i)
1110  {
1111  if (it->colors[i] == static_cast<int>(CLOSED))
1112  return false;
1113  if (it->colors[i] == static_cast<int>(CLOSED_DEADLOCK) &&
1114  insert_status_ == OPEN)
1115  {
1116  deadlock_ = true; // deaddlock detected by another thread
1117  stop_.store(true, std::memory_order_relaxed);
1118  return false;
1119  }
1120  }
1121 
1122  // The state has already been visited by the current thread
1123  if (it->colors[tid_] == static_cast<int>(insert_status_))
1124  return false;
1125 
1126  // Keep a ptr over the array of colors
1127  refs_.push_back(it->colors);
1128 
1129  // Mark state as visited.
1130  it->colors[tid_] = insert_status_;// FIX for GP previous was OPEN;
1131  ++states_;
1132  return true;
1133  }
1134 
1135  bool pop(State s)
1136  {
1137  (void) s;
1138  // Don't avoid pop but modify the status of the state
1139  // during backtrack
1140  refs_.back()[tid_] = CLOSED;
1141  refs_.pop_back();
1142  return true;
1143  }
1144 
1145  void edge(unsigned int, unsigned int)
1146  {
1147  ++edges_;
1148  }
1149 
1150  void finalize()
1151  {
1152  tm_.stop("DFS thread " + std::to_string(this->tid_));
1153  }
1154 
1155  unsigned walltime()
1156  {
1157  return tm_.timer("DFS thread " + std::to_string(this->tid_))
1158  .walltime();
1159  }
1160 
1161  unsigned inserted()
1162  {
1163  return inserted_;
1164  }
1165 
1166  unsigned states()
1167  {
1168  return states_;
1169  }
1170 
1171  unsigned edges()
1172  {
1173  return edges_;
1174  }
1175 
1176  unsigned how_many_generations()
1177  {
1178  return nb_gens_;
1179  }
1180 
1181  void sampling()
1182  {
1183  State initial = sys_.initial(tid_);
1184  if (SPOT_LIKELY(push(initial, dfs_number)))
1185  {
1186  todo.push_back({initial, sys_.succ(initial, tid_), transitions});
1187  ++dfs_number;
1188  sample_.push_back(initial);
1189  }
1190  while (!todo.empty() && sample_.size() < THRESHOLD)
1191  {
1192  if (todo.back().it->done())
1193  {
1194  if (SPOT_LIKELY(pop(todo.back().s)))
1195  {
1196  if (todo.back().current_tr == transitions)
1197  {
1198  deadlock_ = true;
1199  stop_.store(true, std::memory_order_relaxed);
1200  break;
1201  }
1202  sys_.recycle(todo.back().it, tid_);
1203  todo.pop_back();
1204  }
1205  }
1206  else
1207  {
1208  ++transitions;
1209  State dst = todo.back().it->state();
1210 
1211  if (SPOT_LIKELY(push(dst, dfs_number)))
1212  {
1213  ++dfs_number;
1214  todo.back().it->next();
1215  todo.push_back({dst, sys_.succ(dst, tid_), transitions});
1216  sample_.push_back(dst);
1217  }
1218  else
1219  {
1220  todo.back().it->next();
1221  }
1222  }
1223  }
1224  }
1225 
1226  void cleaning()
1227  {
1228  todo.clear();
1229  refs_.clear();
1230  dfs_number = 0;
1231  }
1232 
1233  void swarming(State initial)
1234  {
1235  if (SPOT_LIKELY(push(initial, dfs_number)))
1236  {
1237  todo.push_back({initial, sys_.succ(initial, tid_), transitions});
1238  ++dfs_number;
1239  }
1240  while (!todo.empty() && !stop_.load(std::memory_order_relaxed))
1241  {
1242  if (todo.back().it->done())
1243  {
1244  if (SPOT_LIKELY(pop(todo.back().s)))
1245  {
1246  // Handle deadlocks
1247  if (todo.back().current_tr == transitions)
1248  {
1249  if (insert_status_ == OPEN)
1250  {
1251  stop_.store(true, std::memory_order_relaxed);
1252  deadlock_ = true;
1253  break;
1254  }
1255  else
1256  {
1257  while (!refs_.empty())
1258  {
1259  refs_.back()[tid_] = CLOSED_DEADLOCK;
1260  refs_.pop_back();
1261  }
1262  break;
1263  }
1264  }
1265  sys_.recycle(todo.back().it, tid_);
1266  todo.pop_back();
1267  }
1268  }
1269  else
1270  {
1271  ++transitions;
1272  State dst = todo.back().it->state();
1273 
1274  if (SPOT_LIKELY(push(dst, dfs_number)))
1275  {
1276  ++dfs_number;
1277  todo.back().it->next();
1278  todo.push_back({dst, sys_.succ(dst, tid_), transitions});
1279  }
1280  else
1281  {
1282  todo.back().it->next();
1283  }
1284  }
1285  }
1286  }
1287 
1288 
1289  void run()
1290  {
1291  setup();
1292  if (phase1)
1293  {
1294  insert_status_ = PHASE_1;
1295  sampling();
1296  cleaning();
1297 
1298  // Generate the next geneation from the sample
1299  new_gen_ = interpolate_fun_(sample_);
1300 
1301  // Use all mutated states as initial state
1302  unsigned i = 0;
1303  while (i < new_gen_->size() && !stop_.load(std::memory_order_relaxed))
1304  {
1305  insert_status_ = UNKNOWN_OPEN;
1306  swarming(new_gen_->at(i));
1307  ++i;
1308  ++nb_gens_;
1309  cleaning();
1310  }
1311  }
1312  else
1313  {
1314  insert_status_ = OPEN;
1315  swarming(sys_.initial(tid_));
1316  stop_.store(true, std::memory_order_relaxed);
1317  }
1318  finalize();
1319  }
1320 
1321 
1322  bool has_deadlock()
1323  {
1324  return deadlock_;
1325  }
1326 
1327  private:
1328  struct todo_element
1329  {
1330  State s;
1331  SuccIterator* it;
1332  unsigned current_tr;
1333  };
1335  std::vector<todo_element> todo;
1336  unsigned int dfs_number = 0;
1337  unsigned int transitions = 0;
1338  unsigned int tid_;
1339 
1340  spot::timer_map tm_;
1341  shared_map map_;
1342  unsigned inserted_ = 0;
1343  unsigned nb_gens_ = 0;
1344  unsigned states_ = 0;
1345  unsigned edges_ = 0;
1346  unsigned nb_th_ = 0;
1347  fixed_size_pool p_;
1348  std::vector<int*> refs_;
1349  std::function<std::vector<State>*(std::vector<State>&)> interpolate_fun_;
1350  std::atomic<bool>& stop_;
1351  std::vector<State> sample_;
1352  bool phase1 = true;
1353  std::vector<State>* new_gen_ = nullptr;
1354  unsigned THRESHOLD = 1000;
1355  bool deadlock_ = false;
1356  };
1357 }
Definition: graph.hh:33
Definition: interpolate.hh:465
Definition: interpolate.hh:255
bool is_a_kripkecube(kripkecube< State, SuccIter > &)
This method allows to ensure (at compile time) if a given parameter is of type kripkecube. It also check if the iterator has the good interface.
Definition: kripke.hh:63
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:784
Definition: interpolate.hh:35
Definition: interpolate.hh:1004
Definition: interpolate.hh:139
This template class provide a sequential reachability of a kripkecube. The algorithm uses a single DF...
Definition: reachability.hh:33
A fixed-size memory pool implementation.
Definition: fixpool.hh:31

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Mon Jul 29 2019 10:30:37 for spot by doxygen 1.8.13