Features
features.hpp
Go to the documentation of this file.
1 
10 #ifndef FEATURES_H
11 #define FEATURES_H
12 
13 #include <string>
14 #include <vector>
15 #include <map>
16 
17 #include <set>
18 #include <algorithm>
19 #include <exception>
20 #include <cstddef>
21 #include <iostream>
22 #include <climits>
23 #include <cstdint> // because of std::uintmax_t
24 
28 namespace features
29 {
30  const std::string set_begin { "{" };
31  const std::string set_end { "}" };
32  const std::string set_intersection { "&" };
33  const std::string set_difference { "\\" };
34  const std::string set_union { "|" };
35  const std::string set_separator { " " };
36  const std::string set_comma { "," };
37  const std::string feature_and { "*" };
38  const std::string feature_or { "+" };
39  const std::string feature_not { "!" };
40  const std::string feature { "f" };
41  const std::string feature_separator { " " };
42  const std::string system { "S" };
43  const std::string difference_expression { "E" };
44  const std::string separator { "\t" };
45  const std::string opening_parenthesis { "(" };
46  const std::string closing_parenthesis { ")" };
47 
50  using feature_id_t = unsigned short int;
53  using model_id_t = unsigned short int;
56  using maxnat_t = uintmax_t;
57 
61  using feature_expression_t = std::vector<std::pair<std::string,maxnat_t>>;
64  using expression_feature_t = std::map<maxnat_t,std::string>;
67  using feature_names_t = std::vector<std::string>;
74  using systems_t = std::vector<system_t>;
75 
79  {
83  std::set<std::string> intersections,
88  };
89 
95  {
101  std::string feature;
105  };
106 
107  using features_isolation_t = std::map<std::string,systems_difference_t>;
108  using differences_t = std::vector<system_feature_difference_t>;
109 
113  {
114  if (from == 0llu || to == 0llu)
115  return 0llu;
116  maxnat_t result { 1llu };
117  while (from <= to)
118  {
119  result *= to--;
120  }
121  return result;
122  }
123 
127  {
128  return n == 0llu ? 1llu : product(1llu,n);
129  }
130 
134  {
135  return product(n + 1llu - k,n) / factorial(k);
136  }
137 
141  {
142  maxnat_t result { 0llu };
143  while (k <= n)
144  {
145  result += combinations(n,k++);
146  }
147  return result;
148  }
149 
153  {
154  maxnat_t result { 1llu };
155  while (exponent--)
156  {
157  result *= base;
158  }
159  return result;
160  }
161 
165  {
166  return power(2,exponent);
167  }
168 
171  template <class T>
172  std::vector<T>& concat(std::vector<T>& destination,const std::vector<T>& v)
173  {
174  destination.reserve(destination.size() + v.size());
175  destination.insert(destination.end(),v.cbegin(),v.cend());
176  return destination;
177  }
178 
181  template <class T>
182  bool contains(const std::vector<T>& v,const T& e)
183  {
184  return std::find(v.cbegin(),v.cend(),e) != v.cend();
185 
186  }
187 
192  std::vector<feature_id_t> negate(const std::vector<feature_id_t>& v,feature_id_t n)
193  {
194  std::vector<feature_id_t> result;
195  for (feature_id_t i { 1 }; i <= n; ++i)
196  {
197  if (!contains(v,i))
198  {
199  result.push_back(i);
200  }
201  }
202  return result;
203  }
204 
207  bool hasO(model_id_t M)
208  {
209  return (M == 2 || M == 4 || M == 6 || M == 8 || M == 11 || M == 13 ||
210  M == 14 || M == 16 || M == 17 || M == 19
211  );
212  }
213 
216  bool hasA(model_id_t M)
217  {
218  return (M == 3 || M == 4 || M == 7 || M == 8 || M == 12 || M == 13 ||
219  M == 15 || M == 16 || M == 18 || M == 19
220  );
221  }
222 
225  bool hasN(model_id_t M)
226  {
227  return (M == 5 || M == 6 || M == 7 || M == 8 || M == 9 || M == 10 ||
228  M == 11 || M == 12 || M == 13 || M == 14 || M == 15 ||
229  M == 16 || M == 17 || M == 18 || M == 19
230  );
231  }
232 
236  {
237  return (M == 9 || M == 11 || M == 12 || M == 13 || M == 17 ||
238  M == 18 || M == 19
239  );
240  }
241 
245  {
246  return (M == 10 || M == 14 || M == 15 || M == 16 || M == 17 ||
247  M == 18 || M == 19
248  );
249  }
250 
254  {
255  return feature + std::to_string(i);
256  }
257 
260  std::string or_feature_name(const std::vector<feature_id_t>& ids)
261  {
262  std::string result { feature + std::to_string(ids.at(0)) };
263  for (std::size_t i { 1 }; i < ids.size(); ++i)
264  {
265  result = result + feature_separator + feature_or + feature_separator
266  + feature
267  + std::to_string(ids.at(i));
268  }
269  return result;
270  }
271 
274  std::string and_feature_name(const std::vector<feature_id_t>& ids)
275  {
276  std::string result { feature + std::to_string(ids.at(0)) };
277  for (std::size_t i { 1 }; i < ids.size(); ++i)
278  {
279  result = result + feature_separator + feature_and + feature_separator
280  + feature
281  + std::to_string(ids.at(i));
282  }
283  return result;
284  }
285 
289  {
290  return feature_not + feature + std::to_string(i);
291  }
292 
295  std::string or_not_feature_name(const std::vector<feature_id_t>& ids)
296  {
297  std::string result { feature_not + feature +
298  std::to_string(ids.at(0)) };
299  for (std::size_t i { 1 }; i < ids.size(); ++i)
300  {
301  result = result + feature_separator + feature_or + feature_separator
302  + feature_not
303  + feature + std::to_string(ids.at(i));
304  }
305  return result;
306  }
307 
310  std::string and_not_feature_name(const std::vector<feature_id_t>& ids)
311  {
312  std::string result { feature_not + feature +
313  std::to_string(ids.at(0)) };
314  for (std::size_t i { 1 }; i < ids.size(); ++i)
315  {
316  result = result + feature_separator + feature_and + feature_separator
317  + feature_not
318  + feature + std::to_string(ids.at(i));
319  }
320  return result;
321  }
322 
325  std::string system_name(feature_id_t n)
326  {
327  return system + std::to_string(n);
328  }
329 
333  {
334  return difference_expression + std::to_string(n);
335  }
336 
339  maxnat_t or_feature_value(const std::vector<feature_id_t>& ids,const feature_expression_t& idf)
340  {
341  maxnat_t result { 0 };
342  for (const auto& v : ids)
343  {
344  result |= idf.at(v - 1).second;
345  }
346  return result;
347  }
348 
351  maxnat_t and_feature_value(const std::vector<feature_id_t>& ids,const feature_expression_t& idf)
352  {
353  maxnat_t result { ~0ull };
354  for (const auto& v : ids)
355  {
356  result &= idf.at(v - 1).second;
357  }
358  return result;
359  }
360 
363  maxnat_t or_not_feature_value(const std::vector<feature_id_t>& ids,const feature_expression_t& nf)
364  {
365  maxnat_t result { 0 };
366  for (const auto& v : ids)
367  {
368  result |= nf.at(v - 1).second;
369  }
370  return result;
371  }
372 
375  maxnat_t and_not_feature_value(const std::vector<feature_id_t>& ids,const feature_expression_t& nf,const maxnat_t& bitmask)
376  {
377  maxnat_t result { ~bitmask };
378  for (const auto& v : ids)
379  {
380  result &= nf.at(v - 1).second;
381  }
382  return result;
383  }
384 
387  std::vector<feature_id_t> unsigned2vector(maxnat_t u)
388  {
389  std::vector<feature_id_t> result;
390  for (maxnat_t bit { 0 }; bit < sizeof(u) * CHAR_BIT; ++bit)
391  {
392  if (u & 1ull << bit)
393  {
394  result.push_back(bit + 1);
395  }
396  }
397  return result;
398  }
399 
402  template <class T>
404  {
405  public:
408  combination_t(const std::vector<T> symbols,std::size_t k)
409  :m_symbols(symbols),m_k(k)
410  {
411  if (k > symbols.size())
412  {
413  throw std::logic_error("n = " +
414  std::to_string(symbols.size()) +
415  ", k = " + std::to_string(k) +
416  " violates n >= k!\n"
417  );
418  }
419  initialize();
420  }
423  void initialize()
424  {
425  std::size_t start { };
426  for (auto i { k() }; i > 0; --i)
427  {
428  m_state.push_back(start++);
429  }
430  };
433  std::size_t k() const
434  {
435  return m_k;
436  }
439  bool next()
440  {
441  for (auto i { m_state.size() }; i > 0; --i)
442  {
443  auto v { m_state.at(i - 1) };
444  if (v < m_symbols.size() &&
445  v + 1 + k() - i < m_symbols.size()
446  )
447  {
448  m_state.at(i - 1) += 1;
449  for (auto j { i }; j < m_state.size(); ++j)
450  {
451  m_state.at(j) = m_state.at(j - 1) + 1;
452  }
453  return true;
454  }
455  }
456  return false;
457  }
461  std::vector<T> operator()() const
462  {
463  std::vector<T> result;
464  for (const auto& e : m_state)
465  {
466  result.push_back(m_symbols.at(e));
467  }
468  return result;
469  }
470  private:
471  std::vector<T> m_symbols;
472  std::vector <std::size_t> m_state;
473  std::size_t m_k;
474  };
475 
479  {
480  public:
485  feature_id_t m_)
486  :m_n { n_ },
487  m_F { n_ },
488  m_M { m_ },
489  m_S { power2(n_) },
490  m_O { hasO(m_) ? sum_of_combinations(n_,2) : 0 },
491  m_A { hasA(m_) ? sum_of_combinations(n_,2) : 0 },
492  m_N { hasN(m_) ? n_ : 0u },
493  m_ON { hasON(m_) ? sum_of_combinations(n_,2) : 0 },
494  m_AN { hasAN(m_) ? sum_of_combinations(n_,2) : 0 },
495  m_I { (hasO(m_) ? sum_of_combinations(n_,2) : 0) +
496  (hasA(m_) ? sum_of_combinations(n_,2) : 0) +
497  (hasN(m_) ? n_ : 0) +
498  (hasAN(m_) ? sum_of_combinations(n_,2) : 0) +
499  (hasON(m_) ? sum_of_combinations(n_,2) : 0)
500  },
501  m_T { n_ +
502  (hasO(m_) ? sum_of_combinations(n_,2) : 0) +
503  (hasA(m_) ? sum_of_combinations(n_,2) : 0) +
504  (hasN(m_) ? n_ : 0) +
505  (hasAN(m_) ? sum_of_combinations(n_,2) : 0) +
506  (hasON(m_) ? sum_of_combinations(n_,2) : 0)
507  },
508  m_D { power2(power2(n_)) }
509  {
510  for (std::size_t i { 1 }; i <= m_n; ++i)
511  {
512  m_raw_independent_features.push_back(i);
513  }
514  for (std::size_t i { 2 }; i <= m_n; ++i)
515  {
517  do
518  {
519  m_raw_dependent_features.push_back(c());
520  } while (c.next());
521  }
522  m_all_systems = generate_all_systems();
523  }
526  const auto& n() const
527  {
528  return m_n;
529  }
532  const auto& F() const
533  {
534  return m_F;
535  }
538  const auto& S() const
539  {
540  return m_S;
541  }
544  const auto& M() const
545  {
546  return m_M;
547  }
550  const auto& O() const
551  {
552  return m_O;
553  }
556  const auto& A() const
557  {
558  return m_A;
559  }
562  const auto& N() const
563  {
564  return m_N;
565  }
568  const auto& ON() const
569  {
570  return m_ON;
571  }
574  const auto& AN() const
575  {
576  return m_AN;
577  }
580  const auto& DF() const
581  {
582  return m_I;
583  }
586  const auto& T() const
587  {
588  return m_T;
589  }
592  const auto& D() const
593  {
594  return m_D;
595  }
599  feature_names_t generate_independent_features(const std::vector<feature_id_t>& f) const
600  {
601  std::vector<std::string> result;
602  for (const auto& i : f)
603  {
604  result.push_back(independent_feature_name(i));
605  }
606  return result;
607  }
611  feature_names_t generate_or_features(const std::vector<feature_id_t>& f) const
612  {
613  std::vector<std::string> result;
614  if (hasO(M()))
615  {
616  for (auto i : f)
617  {
618  for (const auto& j : raw_dependent_features())
619  if (auto t { or_feature_name(j) };
620  (contains(j,i) && !contains(result,t))
621  )
622  {
623  result.push_back(t);
624  }
625  }
626  sort(result.begin(),result.end());
627  }
628  return result;
629  }
633  feature_names_t generate_and_features(const std::vector<feature_id_t>& f) const
634  {
635  std::vector<std::string> result;
636  if (hasA(M()))
637  {
638  for (const auto& i : raw_dependent_features())
639  {
640  bool valid { true };
641  for (auto j : i)
642  {
643  if (!contains(f,j))
644  {
645  valid = false;
646  break;
647  }
648  }
649  if (valid)
650  {
651  result.push_back(and_feature_name(i));
652  }
653  }
654  sort(result.begin(),result.end());
655  }
656  return result;
657  }
661  feature_names_t generate_not_features(const std::vector<feature_id_t>& nf) const
662  {
663  std::vector<std::string> result;
664  if (hasN(M()))
665  {
666  auto f { negate(nf,n()) };
667  for (const auto& i : f)
668  {
669  result.push_back(not_feature_name(i));
670  }
671  }
672  return result;
673  }
677  feature_names_t generate_or_not_features(const std::vector<feature_id_t>& nf) const
678  {
679  std::vector<std::string> result;
680  if (hasON(M()))
681  {
682  auto f { negate(nf,n()) };
683  for (auto i : f)
684  {
685  for (const auto& j : raw_dependent_features())
686  if (auto t { or_not_feature_name(j) };
687  (contains(j,i) && !contains(result,t))
688  )
689  {
690  result.push_back(t);
691  }
692  }
693  sort(result.begin(),result.end());
694  }
695  return result;
696  }
700  feature_names_t generate_and_not_features(const std::vector<feature_id_t>& nf) const
701  {
702  std::vector<std::string> result;
703  if (hasAN(M()))
704  {
705  auto f { negate(nf,n()) };
706  for (const auto& i : raw_dependent_features())
707  {
708  bool valid { true };
709  for (auto j : i)
710  {
711  if (!contains(f,j))
712  {
713  valid = false;
714  break;
715  }
716  }
717  if (valid)
718  {
719  result.push_back(and_not_feature_name(i));
720  }
721  }
722  sort(result.begin(),result.end());
723  }
724  return result;
725  }
729  system_t generate_system(const std::vector<feature_id_t>& f) const
730  {
731  std::vector<std::string> result;
733  concat(result,generate_or_features(f));
734  concat(result,generate_and_features(f));
735  concat(result,generate_not_features(f));
736  concat(result,generate_or_not_features(f));
738  sort(result.begin(),result.end());
739  return result;
740  }
744  {
745  std::vector<std::vector<std::string>> result;
746  for (maxnat_t s { 0 }; s < S(); ++s)
747  {
748  result.push_back(generate_system(unsigned2vector(s)));
749  }
750  return result;
751  }
754  const std::vector<feature_id_t>& raw_independent_features() const
755  {
756  return m_raw_independent_features;
757  }
761  const std::vector<std::vector<feature_id_t>>& raw_dependent_features() const
762  {
763  return m_raw_dependent_features;
764  }
767  const auto& all_systems() const
768  {
769  return m_all_systems;
770  }
774  void print_header(std::ostream& os = std::cout)
775  {
776  os << "M" << M() << separator << "selected model\n"
777  << T() << separator << "T" << separator << "actual total number of features\n"
778  << F() << separator << "F" << separator << "number of independent features\n"
779  << DF() << separator << "DF" << separator << "actual total number of inherently dependent features\n"
780  << O() << separator << "O" << separator << "actual number of or-features\n"
781  << A() << separator << "A" << separator << "actual number of and-features\n"
782  << N() << separator << "N" << separator << "actual number of not-features\n"
783  << ON() << separator << "ON" << separator << "actual number of or-not-features\n"
784  << AN() << separator << "AN" << separator << "actual number of and-not-features\n"
785  << S() << separator << "S" << separator << "number of systems of SPL\n"
786  << D() << separator << "D" << separator << "number of all set differences of SPL systems\n";
787  }
788 
792  void print_systems(std::ostream& os = std::cout)
793  {
794  for (maxnat_t i { 0 };const auto & system : all_systems())
795  {
796  os << system_name(++i) << separator;
797  for (const auto& feature : system)
798  {
799  os << feature << separator;
800  }
801  os << std::endl;
802  }
803  }
804  private:
805  const feature_id_t m_n;
806  const maxnat_t m_F;
807  const feature_id_t m_M;
808 
809  const maxnat_t m_S,
810  m_O,
811  m_A,
812  m_N,
813  m_ON,
814  m_AN,
815  m_I,
816  m_T,
817  m_D;
818  std::vector<feature_id_t> m_raw_independent_features;
819  std::vector<std::vector<feature_id_t>> m_raw_dependent_features;
820  std::vector<feature_names_t> m_all_systems;
821  };
822 
828  {
829  public:
834  feature_id_t m_)
835  :feature_location_t(n_,m_)
836  {
837  m_independent_features = generate_independent_features();
838  m_or_features = generate_or_features();
839  m_and_features = generate_and_features();
840  m_not_features = generate_not_features();
841  m_or_not_features = generate_or_not_features();
842  m_and_not_features = generate_and_not_features();
843  m_all_features.reserve(m_all_features.size()
844  + m_independent_features.size()
845  + m_or_features.size()
846  + m_and_features.size()
847  + m_not_features.size()
848  + m_or_not_features.size()
849  + m_and_not_features.size()
850  );
851  concat(concat(concat(concat(concat(concat(m_all_features,
852  m_independent_features),m_or_features),m_and_features),
853  m_not_features),m_or_not_features),m_and_not_features
854  );
855  std::sort(m_all_features.begin(),m_all_features.end());
856  m_feature_isolations = generate_feature_isolations();
857  }
862  {
864  }
869  {
870  feature_names_t result;
871  if (hasO(M()))
872  {
873  for (feature_id_t k { 2 }; k <= n(); ++k)
874  {
875  combination_t combination { raw_independent_features(),k };
876  do
877  {
878  result.push_back(or_feature_name(combination()));
879  } while (combination.next());
880  }
881  }
882  return result;
883  }
888  {
889  feature_names_t result;
890  if (hasA(M()))
891  {
892  for (feature_id_t k { 2 }; k <= n(); ++k)
893  {
894  combination_t combination { raw_independent_features(),k };
895  do
896  {
897  result.push_back(and_feature_name(combination()));
898  } while (combination.next());
899  }
900  }
901  return result;
902  }
907  {
908  feature_names_t result;
909  if (hasN(M()))
910  {
911  for (const auto& i : raw_independent_features()) {
912  result.push_back(not_feature_name(i));
913  }
914  }
915  return result;
916  }
921  {
922  feature_names_t result;
923  if (hasON(M()))
924  {
925  for (feature_id_t k { 2 }; k <= N(); ++k)
926  {
927  combination_t combination { raw_independent_features(),k };
928  do
929  {
930  result.push_back(or_not_feature_name(combination()));
931  } while (combination.next());
932  }
933  }
934  return result;
935  }
940  {
941  feature_names_t result;
942  if (hasAN(M()))
943  {
944  for (feature_id_t k { 2 }; k <= N(); ++k)
945  {
946  combination_t combination { raw_independent_features(),k };
947  do
948  {
949  result.push_back(and_not_feature_name(combination()));
950  } while (combination.next());
951  }
952  }
953  return result;
954  }
958  {
959  return m_independent_features;
960  }
963  const std::vector<std::string>& or_features() const
964  {
965  return m_or_features;
966  }
969  const std::vector<std::string>& and_features() const
970  {
971  return m_and_features;
972  }
975  const std::vector<std::string>& not_features() const
976  {
977  return m_not_features;
978  }
981  const std::vector<std::string>& or_not_features() const
982  {
983  return m_or_not_features;
984  }
987  const std::vector<std::string>& and_not_features() const
988  {
989  return m_and_not_features;
990  }
993  const std::vector<std::string>& all_features() const
994  {
995  return m_all_features;
996  }
999  const features_isolation_t& feature_isolations() const
1000  {
1001  return m_feature_isolations;
1002  }
1005  features_isolation_t generate_feature_isolations() const
1006  {
1007  features_isolation_t result;
1008  for (const auto& f : all_features())
1009  {
1010  systems_difference_t difference;
1011  maxnat_t system_no { 0 };
1012  for (const auto& s: all_systems())
1013  {
1014  ++system_no;
1015  if (contains(s,f))
1016  {
1017  difference.intersections.insert(system_name(system_no));
1018  }
1019  else
1020  {
1021  difference.unions.insert(system_name(system_no));
1022  }
1023  }
1024  result.insert(std::make_pair(f,difference));
1025  }
1026  return result;
1027  }
1031  void print_intersections(const std::set<std::string>& s,std::ostream& os = std::cout) const
1032  {
1033  std::size_t counter { },
1034  size { s.size() };
1035  os << opening_parenthesis << set_separator;
1036  for (const auto& e : s)
1037  {
1038  os << e;
1039  if (++counter < size)
1040  {
1041  os << set_separator << set_intersection << set_separator;
1042  }
1043  }
1044  os << set_separator << closing_parenthesis;
1045  }
1049  void print_unions(const std::set<std::string>& s,std::ostream& os = std::cout) const
1050  {
1051  std::size_t counter { },
1052  size { s.size() };
1053  os << opening_parenthesis << set_separator;
1054  for (const auto& e : s)
1055  {
1056  os << e;
1057  if (++counter < size)
1058  {
1059  os << set_separator << set_union << set_separator;
1060  }
1061  }
1062  os << set_separator << closing_parenthesis;
1063  }
1067  void print_results(std::ostream& os = std::cout) const
1068  {
1069  for (const auto& e : feature_isolations())
1070  {
1071  os << e.first << separator;
1072  print_intersections(e.second.intersections,os);
1073  os << set_separator << set_difference << set_separator;
1074  print_unions(e.second.unions,os);
1075  os << std::endl;
1076  }
1077  }
1078  private:
1079  std::vector<std::string> m_independent_features,
1080  m_or_features,
1081  m_and_features,
1082  m_not_features,
1083  m_or_not_features,
1084  m_and_not_features,
1085  m_all_features;
1086  features_isolation_t m_feature_isolations;
1087  };
1088 
1094  {
1095  public:
1100  feature_id_t m_)
1102  {
1103  m_non_empty_differences = generate_non_empty_differences();
1104  }
1108  std::set<std::string> system2features(std::string s) const
1109  {
1110  if (s.length() < system.length() + 1 || s.find(system) != 0)
1111  {
1112  throw std::logic_error(s + " is not a system identifier.");
1113  }
1114  std::set<std::string> result;
1115  std::size_t pos { stoull(s.erase(0,system.size())) };
1116  for (const auto& f : all_systems().at(pos - 1))
1117  {
1118  result.insert(f);
1119  }
1120  return result;
1121  }
1127  {
1128  systems_difference_t result;
1129  for (maxnat_t position { 0 }; position < S(); ++position)
1130  {
1131  if (s & 1ull << position)
1132  {
1133  result.intersections.insert(system_name(position + 1));
1134  }
1135  else
1136  {
1137  result.unions.insert(system_name(position + 1));
1138  }
1139  }
1140  return result;
1141  }
1146  std::set<std::string> evaluate_intersections(const systems_difference_t& diff) const
1147  {
1148  std::set<std::string> result;
1149  if (diff.intersections.size() >= 1)
1150  {
1151  auto first { diff.intersections.cbegin() };
1152  result = system2features(*first);
1153  while (++first != diff.intersections.end())
1154  {
1155  auto left { result };
1156  auto right { system2features(*first) };
1157  result.clear();
1158  std::set_intersection(left.begin(),left.end(),
1159  right.begin(),right.end(),
1160  std::inserter(result,result.begin()));
1161  if (result.size() == 0)
1162  {
1163  break;
1164  }
1165  }
1166  }
1167  return result;
1168  }
1173  std::set<std::string> evaluate_unions(const systems_difference_t& diff) const
1174  {
1175  std::set<std::string> result;
1176  if (diff.unions.size() >= 1)
1177  {
1178  auto first { diff.unions.cbegin() };
1179  result = system2features(*first);
1180  while (++first != diff.unions.end())
1181  {
1182  auto left { result };
1183  auto right { system2features(*first) };
1184  result.clear();
1185  std::set_union(left.begin(),left.end(),
1186  right.begin(),right.end(),
1187  std::inserter(result,result.begin()));
1188  }
1189  }
1190  return result;
1191  }
1195  std::set<std::string> evaluate_difference(const systems_difference_t& diff) const
1196  {
1197  auto intersections { evaluate_intersections(diff) };
1198  auto unions { evaluate_unions(diff) };
1199  std::set<std::string> result;
1200  std::set_difference(intersections.begin(),intersections.end(),
1201  unions.begin(),unions.end(),
1202  std::inserter(result,result.begin()));
1203 
1204  return result;
1205  }
1206  differences_t generate_non_empty_differences() const
1207  {
1208  differences_t result { };
1209  for (maxnat_t e { 1 }; e < D(); ++e)
1210  {
1211  const auto& diff { generate_difference(e) };
1212  const auto& res { evaluate_difference(diff) };
1213  if (res.size() > 0)
1214  {
1215  if (res.size() != 1)
1216  {
1217  throw std::length_error("Set size = " + std::to_string(res.size()) + ", must be 1!");
1218  }
1219  result.push_back(system_feature_difference_t { e,*res.begin(),diff });
1220  }
1221  }
1222  return result;
1223  }
1226  differences_t non_empty_differences() const
1227  {
1228  return m_non_empty_differences;
1229  }
1233  void print_results(std::ostream& os = std::cout) const
1234  {
1235  for (const auto& e : non_empty_differences())
1236  {
1237  os << difference_name(e.difference_id) << separator
1238  << e.feature << separator;
1239  print_intersections(e.difference.intersections,os);
1240  os << set_separator << set_difference << set_separator;
1241  print_unions(e.difference.unions,os);
1242  os << std::endl;
1243  }
1244  }
1245  private:
1246  differences_t m_non_empty_differences;
1247  };
1248 
1254  {
1255  public:
1260  feature_id_t m_)
1261  :feature_location_t(n_,m_),
1262  m_systems_bitmask { initialize_bitmask() }
1263  {
1264  m_independent_features = calculate_independent_features();
1265  m_or_features = calculate_or_features();
1266  m_and_features = calculate_and_features();
1267  m_not_features = calculate_not_features();
1268  m_or_not_features = calculate_or_not_features();
1269  m_and_not_features = calculate_and_not_features();
1270  concat(concat(concat(concat(concat(concat(m_all_features,
1271  m_independent_features),m_or_features),m_and_features),
1272  m_not_features),m_or_not_features),m_and_not_features
1273  );
1274  m_differences = calculate_differences();
1275  }
1280  {
1281  maxnat_t bitmask {};
1282  for (maxnat_t s {}; s < S(); ++s)
1283  {
1284  bitmask |= (1llu << s);
1285  }
1286  return ~bitmask;
1287  }
1290  const maxnat_t& systems_bitmask() const
1291  {
1292  return m_systems_bitmask;
1293  }
1297  system_feature_difference_t calculate_difference(maxnat_t index,const std::string& name) const
1298  {
1299  system_feature_difference_t result { index,name };
1300  for (maxnat_t s { 0llu }; s < S(); ++s)
1301  {
1302  if (index & (1llu << s))
1303  {
1304  result.difference.intersections.insert(system_name(s + 1));
1305  }
1306  else
1307  {
1308  result.difference.unions.insert(system_name(s + 1));
1309  }
1310  }
1311  return result;
1312  }
1315  differences_t calculate_differences() const
1316  {
1317  differences_t result;
1318  for (const auto& [name,value] : all_features())
1319  {
1320  result.push_back(calculate_difference(value,name));
1321  }
1322  sort(result.begin(),result.end(),[] (auto a,auto b) -> bool { return a.difference_id < b.difference_id; });
1323  return result;
1324  }
1327  differences_t differences() const
1328  {
1329  return m_differences;
1330  }
1334  {
1335  feature_expression_t result;
1336  for (maxnat_t f { 0 }; f < n(); ++f)
1337  {
1338  maxnat_t value { 0 };
1339  maxnat_t bit { 1 };
1340  maxnat_t counter { power2(f) };
1341  for (maxnat_t s { 0 }; s < power2(n()) - 1; ++s)
1342  {
1343  value |= bit;
1344  --counter;
1345  value <<= 1llu;
1346  if (counter == 0llu)
1347  {
1348  bit = (bit == 1llu ? 0llu : 1llu);
1349  counter = power2(f);
1350  }
1351  }
1352  result.push_back(make_pair(independent_feature_name(f + 1),value));
1353  }
1354  return result;
1355  }
1359  {
1360  feature_expression_t result;
1361  if (hasO(M()))
1362  {
1363  for (feature_id_t k { 2 }; k <= n(); ++k)
1364  {
1365  combination_t combination { raw_independent_features(),k };
1366  do
1367  {
1368  result.push_back( { or_feature_name(combination()), or_feature_value(combination(),independent_features()) } );
1369  } while (combination.next());
1370  }
1371  }
1372  return result;
1373  }
1377  {
1378  feature_expression_t result;
1379  if (hasA(M()))
1380  {
1381  for (feature_id_t k { 2 }; k <= n(); ++k)
1382  {
1383  combination_t combination { raw_independent_features(),k };
1384  do
1385  {
1386  result.push_back( { and_feature_name(combination()), and_feature_value(combination(),independent_features()) } );
1387  } while (combination.next());
1388  }
1389  }
1390  return result;
1391  }
1395  {
1396  feature_expression_t result;
1397  if (hasN(M()))
1398  {
1399  for (const auto& f : independent_features())
1400  {
1401  // Possible source of errors: The following line does not call
1402  // not_feature_name()! Instead it uses feature_not + f.first!
1403  result.push_back(make_pair(feature_not + f.first,~(f.second ^ systems_bitmask())));
1404  }
1405  }
1406  return result;
1407  }
1411  {
1412  feature_expression_t result;
1413  if (hasON(M()))
1414  {
1415  for (feature_id_t k { 2 }; k <= n(); ++k)
1416  {
1417  combination_t combination { raw_independent_features(),k };
1418  do
1419  {
1420  result.push_back( { or_not_feature_name(combination()), or_not_feature_value(combination(),not_features()) } );
1421  } while (combination.next());
1422  }
1423  }
1424  return result;
1425  }
1429  {
1430  feature_expression_t result;
1431  if (hasAN(M()))
1432  {
1433  for (feature_id_t k { 2 }; k <= n(); ++k)
1434  {
1435  combination_t combination { raw_independent_features(),k };
1436  do
1437  {
1438  result.push_back( { and_not_feature_name(combination()), and_not_feature_value(combination(),not_features(),systems_bitmask()) } );
1439  } while (combination.next());
1440  }
1441  }
1442  return result;
1443  }
1447  {
1448  return m_independent_features;
1449  }
1453  {
1454  return m_or_features;
1455  }
1459  {
1460  return m_and_features;
1461  }
1465  {
1466  return m_not_features;
1467  }
1471  {
1472  return m_or_not_features;
1473  }
1477  {
1478  return m_and_not_features;
1479  }
1483  {
1484  return m_all_features;
1485  }
1489  void print_intersections(const std::set<std::string>& s,std::ostream& os = std::cout) const
1490  {
1491  std::size_t counter { },
1492  size { s.size() };
1493  os << opening_parenthesis << set_separator;
1494  for (const auto& e : s)
1495  {
1496  os << e;
1497  if (++counter < size)
1498  {
1499  os << set_separator << set_intersection << set_separator;
1500  }
1501  }
1502  os << set_separator << closing_parenthesis;
1503  }
1507  void print_unions(const std::set<std::string>& s,std::ostream& os = std::cout) const
1508  {
1509  std::size_t counter { },
1510  size { s.size() };
1511  os << opening_parenthesis << set_separator;
1512  for (const auto& e : s)
1513  {
1514  os << e;
1515  if (++counter < size)
1516  {
1517  os << set_separator << set_union << set_separator;
1518  }
1519  }
1520  os << set_separator << closing_parenthesis;
1521  }
1525  void print_results(std::ostream& os = std::cout) const
1526  {
1527  for (const auto& e : differences())
1528  {
1529  os << difference_name(e.difference_id) << separator
1530  << e.feature << separator;
1531  print_intersections(e.difference.intersections,os);
1532  os << set_separator << set_difference << set_separator;
1533  print_unions(e.difference.unions,os);
1534  os << std::endl;
1535  }
1536  }
1537  private:
1538  const maxnat_t m_systems_bitmask;
1539  differences_t m_differences;
1540  feature_expression_t m_independent_features,
1541  m_or_features,
1542  m_and_features,
1543  m_not_features,
1544  m_or_not_features,
1545  m_and_not_features,
1546  m_all_features;
1547  };
1548 }
1549 
1550 #endif // FEATURES_H
Definition: features.hpp:404
bool next()
Definition: features.hpp:439
void initialize()
Definition: features.hpp:423
std::size_t k() const
Definition: features.hpp:433
combination_t(const std::vector< T > symbols, std::size_t k)
Definition: features.hpp:408
std::vector< T > operator()() const
Definition: features.hpp:461
Definition: features.hpp:1254
feature_expression_t and_features() const
Definition: features.hpp:1458
differences_t calculate_differences() const
Definition: features.hpp:1315
void print_results(std::ostream &os=std::cout) const
Definition: features.hpp:1525
maxnat_t initialize_bitmask() const
Definition: features.hpp:1279
feature_expression_t all_features() const
Definition: features.hpp:1482
feature_expression_t not_features() const
Definition: features.hpp:1464
feature_expression_t calculate_and_not_features() const
Definition: features.hpp:1428
feature_expression_t independent_features() const
Definition: features.hpp:1446
void print_unions(const std::set< std::string > &s, std::ostream &os=std::cout) const
Definition: features.hpp:1507
feature_expression_t calculate_not_features() const
Definition: features.hpp:1394
feature_expression_t calculate_and_features() const
Definition: features.hpp:1376
feature_expression_t or_not_features() const
Definition: features.hpp:1470
feature_expression_t and_not_features() const
Definition: features.hpp:1476
feature_expression_t calculate_or_features() const
Definition: features.hpp:1358
system_feature_difference_t calculate_difference(maxnat_t index, const std::string &name) const
Definition: features.hpp:1297
void print_intersections(const std::set< std::string > &s, std::ostream &os=std::cout) const
Definition: features.hpp:1489
feature_expression_t or_features() const
Definition: features.hpp:1452
feature_expression_t calculate_or_not_features() const
Definition: features.hpp:1410
feature_location_calculation_t(feature_id_t n_, feature_id_t m_)
Definition: features.hpp:1259
differences_t differences() const
Definition: features.hpp:1327
const maxnat_t & systems_bitmask() const
Definition: features.hpp:1290
feature_expression_t calculate_independent_features() const
Definition: features.hpp:1333
Definition: features.hpp:1094
std::set< std::string > evaluate_intersections(const systems_difference_t &diff) const
Definition: features.hpp:1146
systems_difference_t generate_difference(maxnat_t s) const
Definition: features.hpp:1126
feature_location_differences_t(feature_id_t n_, feature_id_t m_)
Definition: features.hpp:1099
void print_results(std::ostream &os=std::cout) const
Definition: features.hpp:1233
std::set< std::string > evaluate_unions(const systems_difference_t &diff) const
Definition: features.hpp:1173
std::set< std::string > system2features(std::string s) const
Definition: features.hpp:1108
differences_t non_empty_differences() const
Definition: features.hpp:1226
std::set< std::string > evaluate_difference(const systems_difference_t &diff) const
Definition: features.hpp:1195
Definition: features.hpp:828
feature_names_t generate_or_not_features() const
Definition: features.hpp:920
feature_names_t generate_and_features() const
Definition: features.hpp:887
feature_names_t generate_or_features() const
Definition: features.hpp:868
const std::vector< std::string > & or_not_features() const
Definition: features.hpp:981
const std::vector< std::string > & not_features() const
Definition: features.hpp:975
void print_unions(const std::set< std::string > &s, std::ostream &os=std::cout) const
Definition: features.hpp:1049
feature_names_t generate_and_not_features() const
Definition: features.hpp:939
void print_intersections(const std::set< std::string > &s, std::ostream &os=std::cout) const
Definition: features.hpp:1031
void print_results(std::ostream &os=std::cout) const
Definition: features.hpp:1067
const std::vector< std::string > & and_features() const
Definition: features.hpp:969
feature_names_t generate_not_features() const
Definition: features.hpp:906
const features_isolation_t & feature_isolations() const
Definition: features.hpp:999
const std::vector< std::string > & all_features() const
Definition: features.hpp:993
const std::vector< std::string > & and_not_features() const
Definition: features.hpp:987
const std::vector< std::string > & or_features() const
Definition: features.hpp:963
feature_names_t generate_independent_features() const
Definition: features.hpp:861
features_isolation_t generate_feature_isolations() const
Definition: features.hpp:1005
feature_location_isolation_t(feature_id_t n_, feature_id_t m_)
Definition: features.hpp:833
const feature_names_t & independent_features() const
Definition: features.hpp:957
Definition: features.hpp:479
feature_names_t generate_and_not_features(const std::vector< feature_id_t > &nf) const
Definition: features.hpp:700
feature_location_t(feature_id_t n_, feature_id_t m_)
Definition: features.hpp:484
const auto & T() const
Definition: features.hpp:586
const auto & D() const
Definition: features.hpp:592
const auto & DF() const
Definition: features.hpp:580
const auto & all_systems() const
Definition: features.hpp:767
void print_header(std::ostream &os=std::cout)
Definition: features.hpp:774
const auto & O() const
Definition: features.hpp:550
const auto & M() const
Definition: features.hpp:544
systems_t generate_all_systems() const
Definition: features.hpp:743
const auto & S() const
Definition: features.hpp:538
feature_names_t generate_or_not_features(const std::vector< feature_id_t > &nf) const
Definition: features.hpp:677
feature_names_t generate_not_features(const std::vector< feature_id_t > &nf) const
Definition: features.hpp:661
const auto & F() const
Definition: features.hpp:532
feature_names_t generate_or_features(const std::vector< feature_id_t > &f) const
Definition: features.hpp:611
const std::vector< feature_id_t > & raw_independent_features() const
Definition: features.hpp:754
feature_names_t generate_and_features(const std::vector< feature_id_t > &f) const
Definition: features.hpp:633
feature_names_t generate_independent_features(const std::vector< feature_id_t > &f) const
Definition: features.hpp:599
const auto & AN() const
Definition: features.hpp:574
const auto & n() const
Definition: features.hpp:526
system_t generate_system(const std::vector< feature_id_t > &f) const
Definition: features.hpp:729
const std::vector< std::vector< feature_id_t > > & raw_dependent_features() const
Definition: features.hpp:761
const auto & N() const
Definition: features.hpp:562
const auto & A() const
Definition: features.hpp:556
void print_systems(std::ostream &os=std::cout)
Definition: features.hpp:792
const auto & ON() const
Definition: features.hpp:568
uintmax_t maxnat_t
Definition: fl.cpp:30
Definition: features.hpp:29
std::string difference_name(feature_id_t n)
Definition: features.hpp:332
bool hasN(model_id_t M)
Definition: features.hpp:225
maxnat_t factorial(maxnat_t n)
Definition: features.hpp:126
maxnat_t combinations(maxnat_t n, maxnat_t k)
Definition: features.hpp:133
maxnat_t power2(maxnat_t exponent)
Definition: features.hpp:164
unsigned short int model_id_t
Definition: features.hpp:53
std::string or_feature_name(const std::vector< feature_id_t > &ids)
Definition: features.hpp:260
unsigned short int feature_id_t
Definition: features.hpp:50
maxnat_t product(maxnat_t from, maxnat_t to)
Definition: features.hpp:112
std::vector< feature_id_t > negate(const std::vector< feature_id_t > &v, feature_id_t n)
Definition: features.hpp:192
std::vector< feature_id_t > unsigned2vector(maxnat_t u)
Definition: features.hpp:387
std::vector< std::pair< std::string, maxnat_t > > feature_expression_t
Definition: features.hpp:61
maxnat_t and_not_feature_value(const std::vector< feature_id_t > &ids, const feature_expression_t &nf, const maxnat_t &bitmask)
Definition: features.hpp:375
bool hasAN(model_id_t M)
Definition: features.hpp:244
std::vector< T > & concat(std::vector< T > &destination, const std::vector< T > &v)
Definition: features.hpp:172
bool contains(const std::vector< T > &v, const T &e)
Definition: features.hpp:182
bool hasO(model_id_t M)
Definition: features.hpp:207
std::string and_feature_name(const std::vector< feature_id_t > &ids)
Definition: features.hpp:274
std::string independent_feature_name(feature_id_t i)
Definition: features.hpp:253
feature_names_t system_t
Definition: features.hpp:70
std::string system_name(feature_id_t n)
Definition: features.hpp:325
bool hasA(model_id_t M)
Definition: features.hpp:216
maxnat_t power(maxnat_t base, maxnat_t exponent)
Definition: features.hpp:152
std::vector< std::string > feature_names_t
Definition: features.hpp:67
std::string or_not_feature_name(const std::vector< feature_id_t > &ids)
Definition: features.hpp:295
std::string and_not_feature_name(const std::vector< feature_id_t > &ids)
Definition: features.hpp:310
std::map< maxnat_t, std::string > expression_feature_t
Definition: features.hpp:64
bool hasON(model_id_t M)
Definition: features.hpp:235
maxnat_t sum_of_combinations(maxnat_t n, maxnat_t k)
Definition: features.hpp:140
std::vector< system_t > systems_t
Definition: features.hpp:74
maxnat_t or_not_feature_value(const std::vector< feature_id_t > &ids, const feature_expression_t &nf)
Definition: features.hpp:363
uintmax_t maxnat_t
Definition: features.hpp:56
std::string not_feature_name(feature_id_t i)
Definition: features.hpp:288
maxnat_t or_feature_value(const std::vector< feature_id_t > &ids, const feature_expression_t &idf)
Definition: features.hpp:339
maxnat_t and_feature_value(const std::vector< feature_id_t > &ids, const feature_expression_t &idf)
Definition: features.hpp:351
Definition: features.hpp:95
maxnat_t difference_id
Definition: features.hpp:98
systems_difference_t difference
Definition: features.hpp:104
std::string feature
Definition: features.hpp:101
Definition: features.hpp:79
std::set< std::string > unions
Definition: features.hpp:87
std::set< std::string > intersections
Definition: features.hpp:83