Home | History | Annotate | Download | only in util
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2013 Christian Seiler <christian (at) iwakd.de>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #ifndef EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H
     11 #define EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H
     12 
     13 namespace Eigen {
     14 
     15 namespace internal {
     16 
     17 namespace group_theory {
     18 
     19 /** \internal
     20   * \file CXX11/Tensor/util/TemplateGroupTheory.h
     21   * This file contains C++ templates that implement group theory algorithms.
     22   *
     23   * The algorithms allow for a compile-time analysis of finite groups.
     24   *
     25   * Currently only Dimino's algorithm is implemented, which returns a list
     26   * of all elements in a group given a set of (possibly redundant) generators.
     27   * (One could also do that with the so-called orbital algorithm, but that
     28   * is much more expensive and usually has no advantages.)
     29   */
     30 
     31 /**********************************************************************
     32  *                "Ok kid, here is where it gets complicated."
     33  *                         - Amelia Pond in the "Doctor Who" episode
     34  *                           "The Big Bang"
     35  *
     36  * Dimino's algorithm
     37  * ==================
     38  *
     39  * The following is Dimino's algorithm in sequential form:
     40  *
     41  * Input: identity element, list of generators, equality check,
     42  *        multiplication operation
     43  * Output: list of group elements
     44  *
     45  * 1. add identity element
     46  * 2. remove identities from list of generators
     47  * 3. add all powers of first generator that aren't the
     48  *    identity element
     49  * 4. go through all remaining generators:
     50  *        a. if generator is already in the list of elements
     51  *                -> do nothing
     52  *        b. otherwise
     53  *                i.   remember current # of elements
     54  *                     (i.e. the size of the current subgroup)
     55  *                ii.  add all current elements (which includes
     56  *                     the identity) each multiplied from right
     57  *                     with the current generator to the group
     58  *                iii. add all remaining cosets that are generated
     59  *                     by products of the new generator with itself
     60  *                     and all other generators seen so far
     61  *
     62  * In functional form, this is implemented as a long set of recursive
     63  * templates that have a complicated relationship.
     64  *
     65  * The main interface for Dimino's algorithm is the template
     66  * enumerate_group_elements. All lists are implemented as variadic
     67  * type_list<typename...> and numeric_list<typename = int, int...>
     68  * templates.
     69  *
     70  * 'Calling' templates is usually done via typedefs.
     71  *
     72  * This algorithm is an extended version of the basic version. The
     73  * extension consists in the fact that each group element has a set
     74  * of flags associated with it. Multiplication of two group elements
     75  * with each other results in a group element whose flags are the
     76  * XOR of the flags of the previous elements. Each time the algorithm
     77  * notices that a group element it just calculated is already in the
     78  * list of current elements, the flags of both will be compared and
     79  * added to the so-called 'global flags' of the group.
     80  *
     81  * The rationale behind this extension is that this allows not only
     82  * for the description of symmetries between tensor indices, but
     83  * also allows for the description of hermiticity, antisymmetry and
     84  * antihermiticity. Negation and conjugation each are specific bit
     85  * in the flags value and if two different ways to reach a group
     86  * element lead to two different flags, this poses a constraint on
     87  * the allowed values of the resulting tensor. For example, if a
     88  * group element is reach both with and without the conjugation
     89  * flags, it is clear that the resulting tensor has to be real.
     90  *
     91  * Note that this flag mechanism is quite generic and may have other
     92  * uses beyond tensor properties.
     93  *
     94  * IMPORTANT:
     95  *     This algorithm assumes the group to be finite. If you try to
     96  *     run it with a group that's infinite, the algorithm will only
     97  *     terminate once you hit a compiler limit (max template depth).
     98  *     Also note that trying to use this implementation to create a
     99  *     very large group will probably either make you hit the same
    100  *     limit, cause the compiler to segfault or at the very least
    101  *     take a *really* long time (hours, days, weeks - sic!) to
    102  *     compile. It is not recommended to plug in more than 4
    103  *     generators, unless they are independent of each other.
    104  */
    105 
    106 /** \internal
    107   *
    108   * \class strip_identities
    109   * \ingroup CXX11_TensorSymmetry_Module
    110   *
    111   * \brief Cleanse a list of group elements of the identity element
    112   *
    113   * This template is used to make a first pass through all initial
    114   * generators of Dimino's algorithm and remove the identity
    115   * elements.
    116   *
    117   * \sa enumerate_group_elements
    118   */
    119 template<template<typename, typename> class Equality, typename id, typename L> struct strip_identities;
    120 
    121 template<
    122   template<typename, typename> class Equality,
    123   typename id,
    124   typename t,
    125   typename... ts
    126 >
    127 struct strip_identities<Equality, id, type_list<t, ts...>>
    128 {
    129   typedef typename conditional<
    130     Equality<id, t>::value,
    131     typename strip_identities<Equality, id, type_list<ts...>>::type,
    132     typename concat<type_list<t>, typename strip_identities<Equality, id, type_list<ts...>>::type>::type
    133   >::type type;
    134   constexpr static int global_flags = Equality<id, t>::global_flags | strip_identities<Equality, id, type_list<ts...>>::global_flags;
    135 };
    136 
    137 template<
    138   template<typename, typename> class Equality,
    139   typename id
    140   EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, ts)
    141 >
    142 struct strip_identities<Equality, id, type_list<EIGEN_TPL_PP_SPEC_HACK_USE(ts)>>
    143 {
    144   typedef type_list<> type;
    145   constexpr static int global_flags = 0;
    146 };
    147 
    148 /** \internal
    149   *
    150   * \class dimino_first_step_elements_helper
    151   * \ingroup CXX11_TensorSymmetry_Module
    152   *
    153   * \brief Recursive template that adds powers of the first generator to the list of group elements
    154   *
    155   * This template calls itself recursively to add powers of the first
    156   * generator to the list of group elements. It stops if it reaches
    157   * the identity element again.
    158   *
    159   * \sa enumerate_group_elements, dimino_first_step_elements
    160   */
    161 template<
    162   template<typename, typename> class Multiply,
    163   template<typename, typename> class Equality,
    164   typename id,
    165   typename g,
    166   typename current_element,
    167   typename elements,
    168   bool dont_add_current_element   // = false
    169 >
    170 struct dimino_first_step_elements_helper :
    171   public dimino_first_step_elements_helper<
    172     Multiply,
    173     Equality,
    174     id,
    175     g,
    176     typename Multiply<current_element, g>::type,
    177     typename concat<elements, type_list<current_element>>::type,
    178     Equality<typename Multiply<current_element, g>::type, id>::value
    179   > {};
    180 
    181 template<
    182   template<typename, typename> class Multiply,
    183   template<typename, typename> class Equality,
    184   typename id,
    185   typename g,
    186   typename current_element,
    187   typename elements
    188 >
    189 struct dimino_first_step_elements_helper<Multiply, Equality, id, g, current_element, elements, true>
    190 {
    191   typedef elements type;
    192   constexpr static int global_flags = Equality<current_element, id>::global_flags;
    193 };
    194 
    195 /** \internal
    196   *
    197   * \class dimino_first_step_elements
    198   * \ingroup CXX11_TensorSymmetry_Module
    199   *
    200   * \brief Add all powers of the first generator to the list of group elements
    201   *
    202   * This template takes the first non-identity generator and generates the initial
    203   * list of elements which consists of all powers of that generator. For a group
    204   * with just one generated, it would be enumerated after this.
    205   *
    206   * \sa enumerate_group_elements
    207   */
    208 template<
    209   template<typename, typename> class Multiply,
    210   template<typename, typename> class Equality,
    211   typename id,
    212   typename generators
    213 >
    214 struct dimino_first_step_elements
    215 {
    216   typedef typename get<0, generators>::type first_generator;
    217   typedef typename skip<1, generators>::type next_generators;
    218   typedef type_list<first_generator> generators_done;
    219 
    220   typedef dimino_first_step_elements_helper<
    221     Multiply,
    222     Equality,
    223     id,
    224     first_generator,
    225     first_generator,
    226     type_list<id>,
    227     false
    228   > helper;
    229   typedef typename helper::type type;
    230   constexpr static int global_flags = helper::global_flags;
    231 };
    232 
    233 /** \internal
    234   *
    235   * \class dimino_get_coset_elements
    236   * \ingroup CXX11_TensorSymmetry_Module
    237   *
    238   * \brief Generate all elements of a specific coset
    239   *
    240   * This template generates all the elements of a specific coset by
    241   * multiplying all elements in the given subgroup with the new
    242   * coset representative. Note that the first element of the
    243   * subgroup is always the identity element, so the first element of
    244   * ther result of this template is going to be the coset
    245   * representative itself.
    246   *
    247   * Note that this template accepts an additional boolean parameter
    248   * that specifies whether to actually generate the coset (true) or
    249   * just return an empty list (false).
    250   *
    251   * \sa enumerate_group_elements, dimino_add_cosets_for_rep
    252   */
    253 template<
    254   template<typename, typename> class Multiply,
    255   typename sub_group_elements,
    256   typename new_coset_rep,
    257   bool generate_coset      // = true
    258 >
    259 struct dimino_get_coset_elements
    260 {
    261   typedef typename apply_op_from_right<Multiply, new_coset_rep, sub_group_elements>::type type;
    262 };
    263 
    264 template<
    265   template<typename, typename> class Multiply,
    266   typename sub_group_elements,
    267   typename new_coset_rep
    268 >
    269 struct dimino_get_coset_elements<Multiply, sub_group_elements, new_coset_rep, false>
    270 {
    271   typedef type_list<> type;
    272 };
    273 
    274 /** \internal
    275   *
    276   * \class dimino_add_cosets_for_rep
    277   * \ingroup CXX11_TensorSymmetry_Module
    278   *
    279   * \brief Recursive template for adding coset spaces
    280   *
    281   * This template multiplies the coset representative with a generator
    282   * from the list of previous generators. If the new element is not in
    283   * the group already, it adds the corresponding coset. Finally it
    284   * proceeds to call itself with the next generator from the list.
    285   *
    286   * \sa enumerate_group_elements, dimino_add_all_coset_spaces
    287   */
    288 template<
    289   template<typename, typename> class Multiply,
    290   template<typename, typename> class Equality,
    291   typename id,
    292   typename sub_group_elements,
    293   typename elements,
    294   typename generators,
    295   typename rep_element,
    296   int sub_group_size
    297 >
    298 struct dimino_add_cosets_for_rep;
    299 
    300 template<
    301   template<typename, typename> class Multiply,
    302   template<typename, typename> class Equality,
    303   typename id,
    304   typename sub_group_elements,
    305   typename elements,
    306   typename g,
    307   typename... gs,
    308   typename rep_element,
    309   int sub_group_size
    310 >
    311 struct dimino_add_cosets_for_rep<Multiply, Equality, id, sub_group_elements, elements, type_list<g, gs...>, rep_element, sub_group_size>
    312 {
    313   typedef typename Multiply<rep_element, g>::type new_coset_rep;
    314   typedef contained_in_list_gf<Equality, new_coset_rep, elements> _cil;
    315   constexpr static bool add_coset = !_cil::value;
    316 
    317   typedef typename dimino_get_coset_elements<
    318     Multiply,
    319     sub_group_elements,
    320     new_coset_rep,
    321     add_coset
    322   >::type coset_elements;
    323 
    324   typedef dimino_add_cosets_for_rep<
    325     Multiply,
    326     Equality,
    327     id,
    328     sub_group_elements,
    329     typename concat<elements, coset_elements>::type,
    330     type_list<gs...>,
    331     rep_element,
    332     sub_group_size
    333   > _helper;
    334 
    335   typedef typename _helper::type type;
    336   constexpr static int global_flags = _cil::global_flags | _helper::global_flags;
    337 
    338   /* Note that we don't have to update global flags here, since
    339    * we will only add these elements if they are not part of
    340    * the group already. But that only happens if the coset rep
    341    * is not already in the group, so the check for the coset rep
    342    * will catch this.
    343    */
    344 };
    345 
    346 template<
    347   template<typename, typename> class Multiply,
    348   template<typename, typename> class Equality,
    349   typename id,
    350   typename sub_group_elements,
    351   typename elements
    352   EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, empty),
    353   typename rep_element,
    354   int sub_group_size
    355 >
    356 struct dimino_add_cosets_for_rep<Multiply, Equality, id, sub_group_elements, elements, type_list<EIGEN_TPL_PP_SPEC_HACK_USE(empty)>, rep_element, sub_group_size>
    357 {
    358   typedef elements type;
    359   constexpr static int global_flags = 0;
    360 };
    361 
    362 /** \internal
    363   *
    364   * \class dimino_add_all_coset_spaces
    365   * \ingroup CXX11_TensorSymmetry_Module
    366   *
    367   * \brief Recursive template for adding all coset spaces for a new generator
    368   *
    369   * This template tries to go through the list of generators (with
    370   * the help of the dimino_add_cosets_for_rep template) as long as
    371   * it still finds elements that are not part of the group and add
    372   * the corresponding cosets.
    373   *
    374   * \sa enumerate_group_elements, dimino_add_cosets_for_rep
    375   */
    376 template<
    377   template<typename, typename> class Multiply,
    378   template<typename, typename> class Equality,
    379   typename id,
    380   typename sub_group_elements,
    381   typename elements,
    382   typename generators,
    383   int sub_group_size,
    384   int rep_pos,
    385   bool stop_condition        // = false
    386 >
    387 struct dimino_add_all_coset_spaces
    388 {
    389   typedef typename get<rep_pos, elements>::type rep_element;
    390   typedef dimino_add_cosets_for_rep<
    391     Multiply,
    392     Equality,
    393     id,
    394     sub_group_elements,
    395     elements,
    396     generators,
    397     rep_element,
    398     sub_group_elements::count
    399   > _ac4r;
    400   typedef typename _ac4r::type new_elements;
    401 
    402   constexpr static int new_rep_pos = rep_pos + sub_group_elements::count;
    403   constexpr static bool new_stop_condition = new_rep_pos >= new_elements::count;
    404 
    405   typedef dimino_add_all_coset_spaces<
    406     Multiply,
    407     Equality,
    408     id,
    409     sub_group_elements,
    410     new_elements,
    411     generators,
    412     sub_group_size,
    413     new_rep_pos,
    414     new_stop_condition
    415   > _helper;
    416 
    417   typedef typename _helper::type type;
    418   constexpr static int global_flags = _helper::global_flags | _ac4r::global_flags;
    419 };
    420 
    421 template<
    422   template<typename, typename> class Multiply,
    423   template<typename, typename> class Equality,
    424   typename id,
    425   typename sub_group_elements,
    426   typename elements,
    427   typename generators,
    428   int sub_group_size,
    429   int rep_pos
    430 >
    431 struct dimino_add_all_coset_spaces<Multiply, Equality, id, sub_group_elements, elements, generators, sub_group_size, rep_pos, true>
    432 {
    433   typedef elements type;
    434   constexpr static int global_flags = 0;
    435 };
    436 
    437 /** \internal
    438   *
    439   * \class dimino_add_generator
    440   * \ingroup CXX11_TensorSymmetry_Module
    441   *
    442   * \brief Enlarge the group by adding a new generator.
    443   *
    444   * It accepts a boolean parameter that determines if the generator is redundant,
    445   * i.e. was already seen in the group. In that case, it reduces to a no-op.
    446   *
    447   * \sa enumerate_group_elements, dimino_add_all_coset_spaces
    448   */
    449 template<
    450   template<typename, typename> class Multiply,
    451   template<typename, typename> class Equality,
    452   typename id,
    453   typename elements,
    454   typename generators_done,
    455   typename current_generator,
    456   bool redundant          // = false
    457 >
    458 struct dimino_add_generator
    459 {
    460   /* this template is only called if the generator is not redundant
    461    * => all elements of the group multiplied with the new generator
    462    *    are going to be new elements of the most trivial coset space
    463    */
    464   typedef typename apply_op_from_right<Multiply, current_generator, elements>::type multiplied_elements;
    465   typedef typename concat<elements, multiplied_elements>::type new_elements;
    466 
    467   constexpr static int rep_pos = elements::count;
    468 
    469   typedef dimino_add_all_coset_spaces<
    470     Multiply,
    471     Equality,
    472     id,
    473     elements, // elements of previous subgroup
    474     new_elements,
    475     typename concat<generators_done, type_list<current_generator>>::type,
    476     elements::count, // size of previous subgroup
    477     rep_pos,
    478     false // don't stop (because rep_pos >= new_elements::count is always false at this point)
    479   > _helper;
    480   typedef typename _helper::type type;
    481   constexpr static int global_flags = _helper::global_flags;
    482 };
    483 
    484 template<
    485   template<typename, typename> class Multiply,
    486   template<typename, typename> class Equality,
    487   typename id,
    488   typename elements,
    489   typename generators_done,
    490   typename current_generator
    491 >
    492 struct dimino_add_generator<Multiply, Equality, id, elements, generators_done, current_generator, true>
    493 {
    494   // redundant case
    495   typedef elements type;
    496   constexpr static int global_flags = 0;
    497 };
    498 
    499 /** \internal
    500   *
    501   * \class dimino_add_remaining_generators
    502   * \ingroup CXX11_TensorSymmetry_Module
    503   *
    504   * \brief Recursive template that adds all remaining generators to a group
    505   *
    506   * Loop through the list of generators that remain and successively
    507   * add them to the group.
    508   *
    509   * \sa enumerate_group_elements, dimino_add_generator
    510   */
    511 template<
    512   template<typename, typename> class Multiply,
    513   template<typename, typename> class Equality,
    514   typename id,
    515   typename generators_done,
    516   typename remaining_generators,
    517   typename elements
    518 >
    519 struct dimino_add_remaining_generators
    520 {
    521   typedef typename get<0, remaining_generators>::type first_generator;
    522   typedef typename skip<1, remaining_generators>::type next_generators;
    523 
    524   typedef contained_in_list_gf<Equality, first_generator, elements> _cil;
    525 
    526   typedef dimino_add_generator<
    527     Multiply,
    528     Equality,
    529     id,
    530     elements,
    531     generators_done,
    532     first_generator,
    533     _cil::value
    534   > _helper;
    535 
    536   typedef typename _helper::type new_elements;
    537 
    538   typedef dimino_add_remaining_generators<
    539     Multiply,
    540     Equality,
    541     id,
    542     typename concat<generators_done, type_list<first_generator>>::type,
    543     next_generators,
    544     new_elements
    545   > _next_iter;
    546 
    547   typedef typename _next_iter::type type;
    548   constexpr static int global_flags =
    549     _cil::global_flags |
    550     _helper::global_flags |
    551     _next_iter::global_flags;
    552 };
    553 
    554 template<
    555   template<typename, typename> class Multiply,
    556   template<typename, typename> class Equality,
    557   typename id,
    558   typename generators_done,
    559   typename elements
    560 >
    561 struct dimino_add_remaining_generators<Multiply, Equality, id, generators_done, type_list<>, elements>
    562 {
    563   typedef elements type;
    564   constexpr static int global_flags = 0;
    565 };
    566 
    567 /** \internal
    568   *
    569   * \class enumerate_group_elements_noid
    570   * \ingroup CXX11_TensorSymmetry_Module
    571   *
    572   * \brief Helper template that implements group element enumeration
    573   *
    574   * This is a helper template that implements the actual enumeration
    575   * of group elements. This has been split so that the list of
    576   * generators can be cleansed of the identity element before
    577   * performing the actual operation.
    578   *
    579   * \sa enumerate_group_elements
    580   */
    581 template<
    582   template<typename, typename> class Multiply,
    583   template<typename, typename> class Equality,
    584   typename id,
    585   typename generators,
    586   int initial_global_flags = 0
    587 >
    588 struct enumerate_group_elements_noid
    589 {
    590   typedef dimino_first_step_elements<Multiply, Equality, id, generators> first_step;
    591   typedef typename first_step::type first_step_elements;
    592 
    593   typedef dimino_add_remaining_generators<
    594     Multiply,
    595     Equality,
    596     id,
    597     typename first_step::generators_done,
    598     typename first_step::next_generators, // remaining_generators
    599     typename first_step::type // first_step elements
    600   > _helper;
    601 
    602   typedef typename _helper::type type;
    603   constexpr static int global_flags =
    604     initial_global_flags |
    605     first_step::global_flags |
    606     _helper::global_flags;
    607 };
    608 
    609 // in case when no generators are specified
    610 template<
    611   template<typename, typename> class Multiply,
    612   template<typename, typename> class Equality,
    613   typename id,
    614   int initial_global_flags
    615 >
    616 struct enumerate_group_elements_noid<Multiply, Equality, id, type_list<>, initial_global_flags>
    617 {
    618   typedef type_list<id> type;
    619   constexpr static int global_flags = initial_global_flags;
    620 };
    621 
    622 /** \internal
    623   *
    624   * \class enumerate_group_elements
    625   * \ingroup CXX11_TensorSymmetry_Module
    626   *
    627   * \brief Enumerate all elements in a finite group
    628   *
    629   * This template enumerates all elements in a finite group. It accepts
    630   * the following template parameters:
    631   *
    632   * \tparam Multiply      The multiplication operation that multiplies two group elements
    633   *                       with each other.
    634   * \tparam Equality      The equality check operation that checks if two group elements
    635   *                       are equal to another.
    636   * \tparam id            The identity element
    637   * \tparam _generators   A list of (possibly redundant) generators of the group
    638   */
    639 template<
    640   template<typename, typename> class Multiply,
    641   template<typename, typename> class Equality,
    642   typename id,
    643   typename _generators
    644 >
    645 struct enumerate_group_elements
    646   : public enumerate_group_elements_noid<
    647       Multiply,
    648       Equality,
    649       id,
    650       typename strip_identities<Equality, id, _generators>::type,
    651       strip_identities<Equality, id, _generators>::global_flags
    652     >
    653 {
    654 };
    655 
    656 } // end namespace group_theory
    657 
    658 } // end namespace internal
    659 
    660 } // end namespace Eigen
    661 
    662 #endif // EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H
    663 
    664 /*
    665  * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
    666  */
    667