Révision 3763

TXM/trunk/bundles/org.txm.statsengine.r.core.linux/res/linux64/library/RcppEigen/include/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h (revision 3763)
1
// This file is part of Eigen, a lightweight C++ template library
2
// for linear algebra.
3
//
4
// Copyright (C) 2013 Christian Seiler <christian@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/src/TensorSymmetry/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
#ifndef EIGEN_PARSED_BY_DOXYGEN
172
  : // recursive inheritance is too difficult for Doxygen
173
  public dimino_first_step_elements_helper<
174
    Multiply,
175
    Equality,
176
    id,
177
    g,
178
    typename Multiply<current_element, g>::type,
179
    typename concat<elements, type_list<current_element>>::type,
180
    Equality<typename Multiply<current_element, g>::type, id>::value
181
  > {};
182

  
183
template<
184
  template<typename, typename> class Multiply,
185
  template<typename, typename> class Equality,
186
  typename id,
187
  typename g,
188
  typename current_element,
189
  typename elements
190
>
191
struct dimino_first_step_elements_helper<Multiply, Equality, id, g, current_element, elements, true>
192
#endif // EIGEN_PARSED_BY_DOXYGEN
193
{
194
  typedef elements type;
195
  constexpr static int global_flags = Equality<current_element, id>::global_flags;
196
};
197

  
198
/** \internal
199
  *
200
  * \class dimino_first_step_elements
201
  * \ingroup CXX11_TensorSymmetry_Module
202
  *
203
  * \brief Add all powers of the first generator to the list of group elements
204
  *
205
  * This template takes the first non-identity generator and generates the initial
206
  * list of elements which consists of all powers of that generator. For a group
207
  * with just one generated, it would be enumerated after this.
208
  *
209
  * \sa enumerate_group_elements
210
  */
211
template<
212
  template<typename, typename> class Multiply,
213
  template<typename, typename> class Equality,
214
  typename id,
215
  typename generators
216
>
217
struct dimino_first_step_elements
218
{
219
  typedef typename get<0, generators>::type first_generator;
220
  typedef typename skip<1, generators>::type next_generators;
221
  typedef type_list<first_generator> generators_done;
222

  
223
  typedef dimino_first_step_elements_helper<
224
    Multiply,
225
    Equality,
226
    id,
227
    first_generator,
228
    first_generator,
229
    type_list<id>,
230
    false
231
  > helper;
232
  typedef typename helper::type type;
233
  constexpr static int global_flags = helper::global_flags;
234
};
235

  
236
/** \internal
237
  *
238
  * \class dimino_get_coset_elements
239
  * \ingroup CXX11_TensorSymmetry_Module
240
  *
241
  * \brief Generate all elements of a specific coset
242
  *
243
  * This template generates all the elements of a specific coset by
244
  * multiplying all elements in the given subgroup with the new
245
  * coset representative. Note that the first element of the
246
  * subgroup is always the identity element, so the first element of
247
  * ther result of this template is going to be the coset
248
  * representative itself.
249
  *
250
  * Note that this template accepts an additional boolean parameter
251
  * that specifies whether to actually generate the coset (true) or
252
  * just return an empty list (false).
253
  *
254
  * \sa enumerate_group_elements, dimino_add_cosets_for_rep
255
  */
256
template<
257
  template<typename, typename> class Multiply,
258
  typename sub_group_elements,
259
  typename new_coset_rep,
260
  bool generate_coset      // = true
261
>
262
struct dimino_get_coset_elements
263
{
264
  typedef typename apply_op_from_right<Multiply, new_coset_rep, sub_group_elements>::type type;
265
};
266

  
267
template<
268
  template<typename, typename> class Multiply,
269
  typename sub_group_elements,
270
  typename new_coset_rep
271
>
272
struct dimino_get_coset_elements<Multiply, sub_group_elements, new_coset_rep, false>
273
{
274
  typedef type_list<> type;
275
};
276

  
277
/** \internal
278
  *
279
  * \class dimino_add_cosets_for_rep
280
  * \ingroup CXX11_TensorSymmetry_Module
281
  *
282
  * \brief Recursive template for adding coset spaces
283
  *
284
  * This template multiplies the coset representative with a generator
285
  * from the list of previous generators. If the new element is not in
286
  * the group already, it adds the corresponding coset. Finally it
287
  * proceeds to call itself with the next generator from the list.
288
  *
289
  * \sa enumerate_group_elements, dimino_add_all_coset_spaces
290
  */
291
template<
292
  template<typename, typename> class Multiply,
293
  template<typename, typename> class Equality,
294
  typename id,
295
  typename sub_group_elements,
296
  typename elements,
297
  typename generators,
298
  typename rep_element,
299
  int sub_group_size
300
>
301
struct dimino_add_cosets_for_rep;
302

  
303
template<
304
  template<typename, typename> class Multiply,
305
  template<typename, typename> class Equality,
306
  typename id,
307
  typename sub_group_elements,
308
  typename elements,
309
  typename g,
310
  typename... gs,
311
  typename rep_element,
312
  int sub_group_size
313
>
314
struct dimino_add_cosets_for_rep<Multiply, Equality, id, sub_group_elements, elements, type_list<g, gs...>, rep_element, sub_group_size>
315
{
316
  typedef typename Multiply<rep_element, g>::type new_coset_rep;
317
  typedef contained_in_list_gf<Equality, new_coset_rep, elements> _cil;
318
  constexpr static bool add_coset = !_cil::value;
319

  
320
  typedef typename dimino_get_coset_elements<
321
    Multiply,
322
    sub_group_elements,
323
    new_coset_rep,
324
    add_coset
325
  >::type coset_elements;
326

  
327
  typedef dimino_add_cosets_for_rep<
328
    Multiply,
329
    Equality,
330
    id,
331
    sub_group_elements,
332
    typename concat<elements, coset_elements>::type,
333
    type_list<gs...>,
334
    rep_element,
335
    sub_group_size
336
  > _helper;
337

  
338
  typedef typename _helper::type type;
339
  constexpr static int global_flags = _cil::global_flags | _helper::global_flags;
340

  
341
  /* Note that we don't have to update global flags here, since
342
   * we will only add these elements if they are not part of
343
   * the group already. But that only happens if the coset rep
344
   * is not already in the group, so the check for the coset rep
345
   * will catch this.
346
   */
347
};
348

  
349
template<
350
  template<typename, typename> class Multiply,
351
  template<typename, typename> class Equality,
352
  typename id,
353
  typename sub_group_elements,
354
  typename elements
355
  EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, empty),
356
  typename rep_element,
357
  int sub_group_size
358
>
359
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>
360
{
361
  typedef elements type;
362
  constexpr static int global_flags = 0;
363
};
364

  
365
/** \internal
366
  *
367
  * \class dimino_add_all_coset_spaces
368
  * \ingroup CXX11_TensorSymmetry_Module
369
  *
370
  * \brief Recursive template for adding all coset spaces for a new generator
371
  *
372
  * This template tries to go through the list of generators (with
373
  * the help of the dimino_add_cosets_for_rep template) as long as
374
  * it still finds elements that are not part of the group and add
375
  * the corresponding cosets.
376
  *
377
  * \sa enumerate_group_elements, dimino_add_cosets_for_rep
378
  */
379
template<
380
  template<typename, typename> class Multiply,
381
  template<typename, typename> class Equality,
382
  typename id,
383
  typename sub_group_elements,
384
  typename elements,
385
  typename generators,
386
  int sub_group_size,
387
  int rep_pos,
388
  bool stop_condition        // = false
389
>
390
struct dimino_add_all_coset_spaces
391
{
392
  typedef typename get<rep_pos, elements>::type rep_element;
393
  typedef dimino_add_cosets_for_rep<
394
    Multiply,
395
    Equality,
396
    id,
397
    sub_group_elements,
398
    elements,
399
    generators,
400
    rep_element,
401
    sub_group_elements::count
402
  > _ac4r;
403
  typedef typename _ac4r::type new_elements;
404
  
405
  constexpr static int new_rep_pos = rep_pos + sub_group_elements::count;
406
  constexpr static bool new_stop_condition = new_rep_pos >= new_elements::count;
407

  
408
  typedef dimino_add_all_coset_spaces<
409
    Multiply,
410
    Equality,
411
    id,
412
    sub_group_elements,
413
    new_elements,
414
    generators,
415
    sub_group_size,
416
    new_rep_pos,
417
    new_stop_condition
418
  > _helper;
419

  
420
  typedef typename _helper::type type;
421
  constexpr static int global_flags = _helper::global_flags | _ac4r::global_flags;
422
};
423

  
424
template<
425
  template<typename, typename> class Multiply,
426
  template<typename, typename> class Equality,
427
  typename id,
428
  typename sub_group_elements,
429
  typename elements,
430
  typename generators,
431
  int sub_group_size,
432
  int rep_pos
433
>
434
struct dimino_add_all_coset_spaces<Multiply, Equality, id, sub_group_elements, elements, generators, sub_group_size, rep_pos, true>
435
{
436
  typedef elements type;
437
  constexpr static int global_flags = 0;
438
};
439

  
440
/** \internal
441
  *
442
  * \class dimino_add_generator
443
  * \ingroup CXX11_TensorSymmetry_Module
444
  *
445
  * \brief Enlarge the group by adding a new generator.
446
  *
447
  * It accepts a boolean parameter that determines if the generator is redundant,
448
  * i.e. was already seen in the group. In that case, it reduces to a no-op.
449
  *
450
  * \sa enumerate_group_elements, dimino_add_all_coset_spaces
451
  */
452
template<
453
  template<typename, typename> class Multiply,
454
  template<typename, typename> class Equality,
455
  typename id,
456
  typename elements,
457
  typename generators_done,
458
  typename current_generator,
459
  bool redundant          // = false
460
>
461
struct dimino_add_generator
462
{
463
  /* this template is only called if the generator is not redundant
464
   * => all elements of the group multiplied with the new generator
465
   *    are going to be new elements of the most trivial coset space
466
   */
467
  typedef typename apply_op_from_right<Multiply, current_generator, elements>::type multiplied_elements;
468
  typedef typename concat<elements, multiplied_elements>::type new_elements;
469

  
470
  constexpr static int rep_pos = elements::count;
471

  
472
  typedef dimino_add_all_coset_spaces<
473
    Multiply,
474
    Equality,
475
    id,
476
    elements, // elements of previous subgroup
477
    new_elements,
478
    typename concat<generators_done, type_list<current_generator>>::type,
479
    elements::count, // size of previous subgroup
480
    rep_pos,
481
    false // don't stop (because rep_pos >= new_elements::count is always false at this point)
482
  > _helper;
483
  typedef typename _helper::type type;
484
  constexpr static int global_flags = _helper::global_flags;
485
};
486

  
487
template<
488
  template<typename, typename> class Multiply,
489
  template<typename, typename> class Equality,
490
  typename id,
491
  typename elements,
492
  typename generators_done,
493
  typename current_generator
494
>
495
struct dimino_add_generator<Multiply, Equality, id, elements, generators_done, current_generator, true>
496
{
497
  // redundant case
498
  typedef elements type;
499
  constexpr static int global_flags = 0;
500
};
501

  
502
/** \internal
503
  *
504
  * \class dimino_add_remaining_generators
505
  * \ingroup CXX11_TensorSymmetry_Module
506
  *
507
  * \brief Recursive template that adds all remaining generators to a group
508
  *
509
  * Loop through the list of generators that remain and successively
510
  * add them to the group.
511
  *
512
  * \sa enumerate_group_elements, dimino_add_generator
513
  */
514
template<
515
  template<typename, typename> class Multiply,
516
  template<typename, typename> class Equality,
517
  typename id,
518
  typename generators_done,
519
  typename remaining_generators,
520
  typename elements
521
>
522
struct dimino_add_remaining_generators
523
{
524
  typedef typename get<0, remaining_generators>::type first_generator;
525
  typedef typename skip<1, remaining_generators>::type next_generators;
526

  
527
  typedef contained_in_list_gf<Equality, first_generator, elements> _cil;
528

  
529
  typedef dimino_add_generator<
530
    Multiply,
531
    Equality,
532
    id,
533
    elements,
534
    generators_done,
535
    first_generator,
536
    _cil::value
537
  > _helper;
538

  
539
  typedef typename _helper::type new_elements;
540

  
541
  typedef dimino_add_remaining_generators<
542
    Multiply,
543
    Equality,
544
    id,
545
    typename concat<generators_done, type_list<first_generator>>::type,
546
    next_generators,
547
    new_elements
548
  > _next_iter;
549

  
550
  typedef typename _next_iter::type type;
551
  constexpr static int global_flags =
552
    _cil::global_flags |
553
    _helper::global_flags |
554
    _next_iter::global_flags;
555
};
556

  
557
template<
558
  template<typename, typename> class Multiply,
559
  template<typename, typename> class Equality,
560
  typename id,
561
  typename generators_done,
562
  typename elements
563
>
564
struct dimino_add_remaining_generators<Multiply, Equality, id, generators_done, type_list<>, elements>
565
{
566
  typedef elements type;
567
  constexpr static int global_flags = 0;
568
};
569

  
570
/** \internal
571
  *
572
  * \class enumerate_group_elements_noid
573
  * \ingroup CXX11_TensorSymmetry_Module
574
  *
575
  * \brief Helper template that implements group element enumeration
576
  *
577
  * This is a helper template that implements the actual enumeration
578
  * of group elements. This has been split so that the list of
579
  * generators can be cleansed of the identity element before
580
  * performing the actual operation.
581
  *
582
  * \sa enumerate_group_elements
583
  */
584
template<
585
  template<typename, typename> class Multiply,
586
  template<typename, typename> class Equality,
587
  typename id,
588
  typename generators,
589
  int initial_global_flags = 0
590
>
591
struct enumerate_group_elements_noid
592
{
593
  typedef dimino_first_step_elements<Multiply, Equality, id, generators> first_step;
594
  typedef typename first_step::type first_step_elements;
595

  
596
  typedef dimino_add_remaining_generators<
597
    Multiply,
598
    Equality,
599
    id,
600
    typename first_step::generators_done,
601
    typename first_step::next_generators, // remaining_generators
602
    typename first_step::type // first_step elements
603
  > _helper;
604

  
605
  typedef typename _helper::type type;
606
  constexpr static int global_flags =
607
    initial_global_flags |
608
    first_step::global_flags |
609
    _helper::global_flags;
610
};
611

  
612
// in case when no generators are specified
613
template<
614
  template<typename, typename> class Multiply,
615
  template<typename, typename> class Equality,
616
  typename id,
617
  int initial_global_flags
618
>
619
struct enumerate_group_elements_noid<Multiply, Equality, id, type_list<>, initial_global_flags>
620
{
621
  typedef type_list<id> type;
622
  constexpr static int global_flags = initial_global_flags;
623
};
624

  
625
/** \internal
626
  *
627
  * \class enumerate_group_elements
628
  * \ingroup CXX11_TensorSymmetry_Module
629
  *
630
  * \brief Enumerate all elements in a finite group
631
  *
632
  * This template enumerates all elements in a finite group. It accepts
633
  * the following template parameters:
634
  *
635
  * \tparam Multiply      The multiplication operation that multiplies two group elements
636
  *                       with each other.
637
  * \tparam Equality      The equality check operation that checks if two group elements
638
  *                       are equal to another.
639
  * \tparam id            The identity element
640
  * \tparam _generators   A list of (possibly redundant) generators of the group
641
  */
642
template<
643
  template<typename, typename> class Multiply,
644
  template<typename, typename> class Equality,
645
  typename id,
646
  typename _generators
647
>
648
struct enumerate_group_elements
649
  : public enumerate_group_elements_noid<
650
      Multiply,
651
      Equality,
652
      id,
653
      typename strip_identities<Equality, id, _generators>::type,
654
      strip_identities<Equality, id, _generators>::global_flags
655
    >
656
{
657
};
658

  
659
} // end namespace group_theory
660

  
661
} // end namespace internal
662

  
663
} // end namespace Eigen
664

  
665
#endif // EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H
666

  
667
/*
668
 * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
669
 */
TXM/trunk/bundles/org.txm.statsengine.r.core.linux/res/linux64/library/RcppEigen/include/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h (revision 3763)
1
// This file is part of Eigen, a lightweight C++ template library
2
// for linear algebra.
3
//
4
// Copyright (C) 2013 Christian Seiler <christian@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_SYMMETRY_H
11
#define EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H
12

  
13
namespace Eigen {
14

  
15
enum {
16
  NegationFlag           = 0x01,
17
  ConjugationFlag        = 0x02
18
};
19

  
20
enum {
21
  GlobalRealFlag         = 0x01,
22
  GlobalImagFlag         = 0x02,
23
  GlobalZeroFlag         = 0x03
24
};
25

  
26
namespace internal {
27

  
28
template<std::size_t NumIndices, typename... Sym>                   struct tensor_symmetry_pre_analysis;
29
template<std::size_t NumIndices, typename... Sym>                   struct tensor_static_symgroup;
30
template<bool instantiate, std::size_t NumIndices, typename... Sym> struct tensor_static_symgroup_if;
31
template<typename Tensor_> struct tensor_symmetry_calculate_flags;
32
template<typename Tensor_> struct tensor_symmetry_assign_value;
33
template<typename... Sym> struct tensor_symmetry_num_indices;
34

  
35
} // end namespace internal
36

  
37
template<int One_, int Two_>
38
struct Symmetry
39
{
40
  static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
41
  constexpr static int One = One_;
42
  constexpr static int Two = Two_;
43
  constexpr static int Flags = 0;
44
};
45

  
46
template<int One_, int Two_>
47
struct AntiSymmetry
48
{
49
  static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
50
  constexpr static int One = One_;
51
  constexpr static int Two = Two_;
52
  constexpr static int Flags = NegationFlag;
53
};
54

  
55
template<int One_, int Two_>
56
struct Hermiticity
57
{
58
  static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
59
  constexpr static int One = One_;
60
  constexpr static int Two = Two_;
61
  constexpr static int Flags = ConjugationFlag;
62
};
63

  
64
template<int One_, int Two_>
65
struct AntiHermiticity
66
{
67
  static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
68
  constexpr static int One = One_;
69
  constexpr static int Two = Two_;
70
  constexpr static int Flags = ConjugationFlag | NegationFlag;
71
};
72

  
73
/** \class DynamicSGroup
74
  * \ingroup TensorSymmetry_Module
75
  *
76
  * \brief Dynamic symmetry group
77
  *
78
  * The %DynamicSGroup class represents a symmetry group that need not be known at
79
  * compile time. It is useful if one wants to support arbitrary run-time defineable
80
  * symmetries for tensors, but it is also instantiated if a symmetry group is defined
81
  * at compile time that would be either too large for the compiler to reasonably
82
  * generate (using templates to calculate this at compile time is very inefficient)
83
  * or that the compiler could generate the group but that it wouldn't make sense to
84
  * unroll the loop for setting coefficients anymore.
85
  */
86
class DynamicSGroup;
87

  
88
/** \internal
89
  *
90
  * \class DynamicSGroupFromTemplateArgs
91
  * \ingroup TensorSymmetry_Module
92
  *
93
  * \brief Dynamic symmetry group, initialized from template arguments
94
  *
95
  * This class is a child class of DynamicSGroup. It uses the template arguments
96
  * specified to initialize itself.
97
  */
98
template<typename... Gen>
99
class DynamicSGroupFromTemplateArgs;
100

  
101
/** \class StaticSGroup
102
  * \ingroup TensorSymmetry_Module
103
  *
104
  * \brief Static symmetry group
105
  *
106
  * This class represents a symmetry group that is known and resolved completely
107
  * at compile time. Ideally, no run-time penalty is incurred compared to the
108
  * manual unrolling of the symmetry.
109
  *
110
  * <b><i>CAUTION:</i></b>
111
  *
112
  * Do not use this class directly for large symmetry groups. The compiler
113
  * may run into a limit, or segfault or in the very least will take a very,
114
  * very, very long time to compile the code. Use the SGroup class instead
115
  * if you want a static group. That class contains logic that will
116
  * automatically select the DynamicSGroup class instead if the symmetry
117
  * group becomes too large. (In that case, unrolling may not even be
118
  * beneficial.)
119
  */
120
template<typename... Gen>
121
class StaticSGroup;
122

  
123
/** \class SGroup
124
  * \ingroup TensorSymmetry_Module
125
  *
126
  * \brief Symmetry group, initialized from template arguments
127
  *
128
  * This class represents a symmetry group whose generators are already
129
  * known at compile time. It may or may not be resolved at compile time,
130
  * depending on the estimated size of the group.
131
  *
132
  * \sa StaticSGroup
133
  * \sa DynamicSGroup
134
  */
135
template<typename... Gen>
136
class SGroup : public internal::tensor_symmetry_pre_analysis<internal::tensor_symmetry_num_indices<Gen...>::value, Gen...>::root_type
137
{
138
  public:
139
    constexpr static std::size_t NumIndices = internal::tensor_symmetry_num_indices<Gen...>::value;
140
    typedef typename internal::tensor_symmetry_pre_analysis<NumIndices, Gen...>::root_type Base;
141

  
142
    // make standard constructors + assignment operators public
143
    inline SGroup() : Base() { }
144
    inline SGroup(const SGroup<Gen...>& other) : Base(other) { }
145
    inline SGroup(SGroup<Gen...>&& other) : Base(other) { }
146
    inline SGroup<Gen...>& operator=(const SGroup<Gen...>& other) { Base::operator=(other); return *this; }
147
    inline SGroup<Gen...>& operator=(SGroup<Gen...>&& other) { Base::operator=(other); return *this; }
148

  
149
    // all else is defined in the base class
150
};
151

  
152
namespace internal {
153

  
154
template<typename... Sym> struct tensor_symmetry_num_indices
155
{
156
  constexpr static std::size_t value = 1;
157
};
158

  
159
template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...>
160
{
161
private:
162
  constexpr static std::size_t One = static_cast<std::size_t>(One_);
163
  constexpr static std::size_t Two = static_cast<std::size_t>(Two_);
164
  constexpr static std::size_t Three = tensor_symmetry_num_indices<Sym...>::value;
165

  
166
  // don't use std::max, since it's not constexpr until C++14...
167
  constexpr static std::size_t maxOneTwoPlusOne = ((One > Two) ? One : Two) + 1;
168
public:
169
  constexpr static std::size_t value = (maxOneTwoPlusOne > Three) ? maxOneTwoPlusOne : Three;
170
};
171

  
172
template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<AntiSymmetry<One_, Two_>, Sym...>
173
  : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
174
template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<Hermiticity<One_, Two_>, Sym...>
175
  : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
176
template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<AntiHermiticity<One_, Two_>, Sym...>
177
  : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
178

  
179
/** \internal
180
  *
181
  * \class tensor_symmetry_pre_analysis
182
  * \ingroup TensorSymmetry_Module
183
  *
184
  * \brief Pre-select whether to use a static or dynamic symmetry group
185
  *
186
  * When a symmetry group could in principle be determined at compile time,
187
  * this template implements the logic whether to actually do that or whether
188
  * to rather defer that to runtime.
189
  *
190
  * The logic is as follows:
191
  * <dl>
192
  * <dt><b>No generators (trivial symmetry):</b></dt>
193
  * <dd>Use a trivial static group. Ideally, this has no performance impact
194
  *     compared to not using symmetry at all. In practice, this might not
195
  *     be the case.</dd>
196
  * <dt><b>More than 4 generators:</b></dt>
197
  * <dd>Calculate the group at run time, it is likely far too large for the
198
  *     compiler to be able to properly generate it in a realistic time.</dd>
199
  * <dt><b>Up to and including 4 generators:</b></dt>
200
  * <dd>Actually enumerate all group elements, but then check how many there
201
  *     are. If there are more than 16, it is unlikely that unrolling the
202
  *     loop (as is done in the static compile-time case) is sensible, so
203
  *     use a dynamic group instead. If there are at most 16 elements, actually
204
  *     use that static group. Note that the largest group with 4 generators
205
  *     still compiles with reasonable resources.</dd>
206
  * </dl>
207
  *
208
  * Note: Example compile time performance with g++-4.6 on an Intenl Core i5-3470
209
  *       with 16 GiB RAM (all generators non-redundant and the subgroups don't
210
  *       factorize):
211
  *
212
  *          # Generators          -O0 -ggdb               -O2
213
  *          -------------------------------------------------------------------
214
  *          1                 0.5 s  /   250 MiB     0.45s /   230 MiB
215
  *          2                 0.5 s  /   260 MiB     0.5 s /   250 MiB
216
  *          3                 0.65s  /   310 MiB     0.62s /   310 MiB
217
  *          4                 2.2 s  /   860 MiB     1.7 s /   770 MiB
218
  *          5               130   s  / 13000 MiB   120   s / 11000 MiB
219
  *
220
  * It is clear that everything is still very efficient up to 4 generators, then
221
  * the memory and CPU requirements become unreasonable. Thus we only instantiate
222
  * the template group theory logic if the number of generators supplied is 4 or
223
  * lower, otherwise this will be forced to be done during runtime, where the
224
  * algorithm is reasonably fast.
225
  */
226
template<std::size_t NumIndices>
227
struct tensor_symmetry_pre_analysis<NumIndices>
228
{
229
  typedef StaticSGroup<> root_type;
230
};
231

  
232
template<std::size_t NumIndices, typename Gen_, typename... Gens_>
233
struct tensor_symmetry_pre_analysis<NumIndices, Gen_, Gens_...>
234
{
235
  constexpr static std::size_t max_static_generators = 4;
236
  constexpr static std::size_t max_static_elements = 16;
237
  typedef tensor_static_symgroup_if<(sizeof...(Gens_) + 1 <= max_static_generators), NumIndices, Gen_, Gens_...> helper;
238
  constexpr static std::size_t possible_size = helper::size;
239

  
240
  typedef typename conditional<
241
    possible_size == 0 || possible_size >= max_static_elements,
242
    DynamicSGroupFromTemplateArgs<Gen_, Gens_...>,
243
    typename helper::type
244
  >::type root_type;
245
};
246

  
247
template<bool instantiate, std::size_t NumIndices, typename... Gens>
248
struct tensor_static_symgroup_if
249
{
250
  constexpr static std::size_t size = 0;
251
  typedef void type;
252
};
253

  
254
template<std::size_t NumIndices, typename... Gens>
255
struct tensor_static_symgroup_if<true, NumIndices, Gens...> : tensor_static_symgroup<NumIndices, Gens...> {};
256

  
257
template<typename Tensor_>
258
struct tensor_symmetry_assign_value
259
{
260
  typedef typename Tensor_::Index Index;
261
  typedef typename Tensor_::Scalar Scalar;
262
  constexpr static std::size_t NumIndices = Tensor_::NumIndices;
263

  
264
  static inline int run(const std::array<Index, NumIndices>& transformed_indices, int transformation_flags, int dummy, Tensor_& tensor, const Scalar& value_)
265
  {
266
    Scalar value(value_);
267
    if (transformation_flags & ConjugationFlag)
268
      value = numext::conj(value);
269
    if (transformation_flags & NegationFlag)
270
      value = -value;
271
    tensor.coeffRef(transformed_indices) = value;
272
    return dummy;
273
  }
274
};
275

  
276
template<typename Tensor_>
277
struct tensor_symmetry_calculate_flags
278
{
279
  typedef typename Tensor_::Index Index;
280
  constexpr static std::size_t NumIndices = Tensor_::NumIndices;
281

  
282
  static inline int run(const std::array<Index, NumIndices>& transformed_indices, int transform_flags, int current_flags, const std::array<Index, NumIndices>& orig_indices)
283
  {
284
    if (transformed_indices == orig_indices) {
285
      if (transform_flags & (ConjugationFlag | NegationFlag))
286
        return current_flags | GlobalImagFlag; // anti-hermitian diagonal
287
      else if (transform_flags & ConjugationFlag)
288
        return current_flags | GlobalRealFlag; // hermitian diagonal
289
      else if (transform_flags & NegationFlag)
290
        return current_flags | GlobalZeroFlag; // anti-symmetric diagonal
291
    }
292
    return current_flags;
293
  }
294
};
295

  
296
template<typename Tensor_, typename Symmetry_, int Flags = 0>
297
class tensor_symmetry_value_setter
298
{
299
  public:
300
    typedef typename Tensor_::Index Index;
301
    typedef typename Tensor_::Scalar Scalar;
302
    constexpr static std::size_t NumIndices = Tensor_::NumIndices;
303

  
304
    inline tensor_symmetry_value_setter(Tensor_& tensor, Symmetry_ const& symmetry, std::array<Index, NumIndices> const& indices)
305
      : m_tensor(tensor), m_symmetry(symmetry), m_indices(indices) { }
306

  
307
    inline tensor_symmetry_value_setter<Tensor_, Symmetry_, Flags>& operator=(Scalar const& value)
308
    {
309
      doAssign(value);
310
      return *this;
311
    }
312
  private:
313
    Tensor_& m_tensor;
314
    Symmetry_ m_symmetry;
315
    std::array<Index, NumIndices> m_indices;
316

  
317
    inline void doAssign(Scalar const& value)
318
    {
319
      #ifdef EIGEN_TENSOR_SYMMETRY_CHECK_VALUES
320
        int value_flags = m_symmetry.template apply<internal::tensor_symmetry_calculate_flags<Tensor_>, int>(m_indices, m_symmetry.globalFlags(), m_indices);
321
        if (value_flags & GlobalRealFlag)
322
          eigen_assert(numext::imag(value) == 0);
323
        if (value_flags & GlobalImagFlag)
324
          eigen_assert(numext::real(value) == 0);
325
      #endif
326
      m_symmetry.template apply<internal::tensor_symmetry_assign_value<Tensor_>, int>(m_indices, 0, m_tensor, value);
327
    }
328
};
329

  
330
} // end namespace internal
331

  
332
} // end namespace Eigen
333

  
334
#endif // EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H
335

  
336
/*
337
 * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
338
 */
TXM/trunk/bundles/org.txm.statsengine.r.core.linux/res/linux64/library/RcppEigen/include/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h (revision 3763)
1
// This file is part of Eigen, a lightweight C++ template library
2
// for linear algebra.
3
//
4
// Copyright (C) 2013 Christian Seiler <christian@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_DYNAMICSYMMETRY_H
11
#define EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H
12

  
13
namespace Eigen {
14

  
15
class DynamicSGroup
16
{
17
  public:
18
    inline explicit DynamicSGroup() : m_numIndices(1), m_elements(), m_generators(), m_globalFlags(0) { m_elements.push_back(ge(Generator(0, 0, 0))); }
19
    inline DynamicSGroup(const DynamicSGroup& o) : m_numIndices(o.m_numIndices), m_elements(o.m_elements), m_generators(o.m_generators), m_globalFlags(o.m_globalFlags) { }
20
    inline DynamicSGroup(DynamicSGroup&& o) : m_numIndices(o.m_numIndices), m_elements(), m_generators(o.m_generators), m_globalFlags(o.m_globalFlags) { std::swap(m_elements, o.m_elements); }
21
    inline DynamicSGroup& operator=(const DynamicSGroup& o) { m_numIndices = o.m_numIndices; m_elements = o.m_elements; m_generators = o.m_generators; m_globalFlags = o.m_globalFlags; return *this; }
22
    inline DynamicSGroup& operator=(DynamicSGroup&& o) { m_numIndices = o.m_numIndices; std::swap(m_elements, o.m_elements); m_generators = o.m_generators; m_globalFlags = o.m_globalFlags; return *this; }
23

  
24
    void add(int one, int two, int flags = 0);
25

  
26
    template<typename Gen_>
27
    inline void add(Gen_) { add(Gen_::One, Gen_::Two, Gen_::Flags); }
28
    inline void addSymmetry(int one, int two) { add(one, two, 0); }
29
    inline void addAntiSymmetry(int one, int two) { add(one, two, NegationFlag); }
30
    inline void addHermiticity(int one, int two) { add(one, two, ConjugationFlag); }
31
    inline void addAntiHermiticity(int one, int two) { add(one, two, NegationFlag | ConjugationFlag); }
32

  
33
    template<typename Op, typename RV, typename Index, std::size_t N, typename... Args>
34
    inline RV apply(const std::array<Index, N>& idx, RV initial, Args&&... args) const
35
    {
36
      eigen_assert(N >= m_numIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
37
      for (std::size_t i = 0; i < size(); i++)
38
        initial = Op::run(h_permute(i, idx, typename internal::gen_numeric_list<int, N>::type()), m_elements[i].flags, initial, std::forward<Args>(args)...);
39
      return initial;
40
    }
41

  
42
    template<typename Op, typename RV, typename Index, typename... Args>
43
    inline RV apply(const std::vector<Index>& idx, RV initial, Args&&... args) const
44
    {
45
      eigen_assert(idx.size() >= m_numIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
46
      for (std::size_t i = 0; i < size(); i++)
47
        initial = Op::run(h_permute(i, idx), m_elements[i].flags, initial, std::forward<Args>(args)...);
48
      return initial;
49
    }
50

  
51
    inline int globalFlags() const { return m_globalFlags; }
52
    inline std::size_t size() const { return m_elements.size(); }
53

  
54
    template<typename Tensor_, typename... IndexTypes>
55
    inline internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup> operator()(Tensor_& tensor, typename Tensor_::Index firstIndex, IndexTypes... otherIndices) const
56
    {
57
      static_assert(sizeof...(otherIndices) + 1 == Tensor_::NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
58
      return operator()(tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices>{{firstIndex, otherIndices...}});
59
    }
60

  
61
    template<typename Tensor_>
62
    inline internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup> operator()(Tensor_& tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices> const& indices) const
63
    {
64
      return internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup>(tensor, *this, indices);
65
    }
66
  private:
67
    struct GroupElement {
68
      std::vector<int> representation;
69
      int flags;
70
      bool isId() const
71
      {
72
        for (std::size_t i = 0; i < representation.size(); i++)
73
          if (i != (size_t)representation[i])
74
            return false;
75
        return true;
76
      }
77
    };
78
    struct Generator {
79
      int one;
80
      int two;
81
      int flags;
82
      constexpr inline Generator(int one_, int two_, int flags_) : one(one_), two(two_), flags(flags_) {}
83
    };
84

  
85
    std::size_t m_numIndices;
86
    std::vector<GroupElement> m_elements;
87
    std::vector<Generator> m_generators;
88
    int m_globalFlags;
89

  
90
    template<typename Index, std::size_t N, int... n>
91
    inline std::array<Index, N> h_permute(std::size_t which, const std::array<Index, N>& idx, internal::numeric_list<int, n...>) const
92
    {
93
      return std::array<Index, N>{{ idx[n >= m_numIndices ? n : m_elements[which].representation[n]]... }};
94
    }
95

  
96
    template<typename Index>
97
    inline std::vector<Index> h_permute(std::size_t which, std::vector<Index> idx) const
98
    {
99
      std::vector<Index> result;
100
      result.reserve(idx.size());
101
      for (auto k : m_elements[which].representation)
102
        result.push_back(idx[k]);
103
      for (std::size_t i = m_numIndices; i < idx.size(); i++)
104
        result.push_back(idx[i]);
105
      return result;
106
    }
107

  
108
    inline GroupElement ge(Generator const& g) const
109
    {
110
      GroupElement result;
111
      result.representation.reserve(m_numIndices);
112
      result.flags = g.flags;
113
      for (std::size_t k = 0; k < m_numIndices; k++) {
114
        if (k == (std::size_t)g.one)
115
          result.representation.push_back(g.two);
116
        else if (k == (std::size_t)g.two)
117
          result.representation.push_back(g.one);
118
        else
119
          result.representation.push_back(int(k));
120
      }
121
      return result;
122
    }
123

  
124
    GroupElement mul(GroupElement, GroupElement) const;
125
    inline GroupElement mul(Generator g1, GroupElement g2) const
126
    {
127
      return mul(ge(g1), g2);
128
    }
129

  
130
    inline GroupElement mul(GroupElement g1, Generator g2) const
131
    {
132
      return mul(g1, ge(g2));
133
    }
134

  
135
    inline GroupElement mul(Generator g1, Generator g2) const
136
    {
137
      return mul(ge(g1), ge(g2));
138
    }
139

  
140
    inline int findElement(GroupElement e) const
141
    {
142
      for (auto ee : m_elements) {
143
        if (ee.representation == e.representation)
144
          return ee.flags ^ e.flags;
145
      }
146
      return -1;
147
    }
148

  
149
    void updateGlobalFlags(int flagDiffOfSameGenerator);
150
};
151

  
152
// dynamic symmetry group that auto-adds the template parameters in the constructor
153
template<typename... Gen>
154
class DynamicSGroupFromTemplateArgs : public DynamicSGroup
155
{
156
  public:
157
    inline DynamicSGroupFromTemplateArgs() : DynamicSGroup()
158
    {
159
      add_all(internal::type_list<Gen...>());
160
    }
161
    inline DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs const& other) : DynamicSGroup(other) { }
162
    inline DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs&& other) : DynamicSGroup(other) { }
163
    inline DynamicSGroupFromTemplateArgs<Gen...>& operator=(const DynamicSGroupFromTemplateArgs<Gen...>& o) { DynamicSGroup::operator=(o); return *this; }
164
    inline DynamicSGroupFromTemplateArgs<Gen...>& operator=(DynamicSGroupFromTemplateArgs<Gen...>&& o) { DynamicSGroup::operator=(o); return *this; }
165
  
166
  private:
167
    template<typename Gen1, typename... GenNext>
168
    inline void add_all(internal::type_list<Gen1, GenNext...>)
169
    {
170
      add(Gen1());
171
      add_all(internal::type_list<GenNext...>());
172
    }
173

  
174
    inline void add_all(internal::type_list<>)
175
    {
176
    }
177
};
178

  
179
inline DynamicSGroup::GroupElement DynamicSGroup::mul(GroupElement g1, GroupElement g2) const
180
{
181
  eigen_internal_assert(g1.representation.size() == m_numIndices);
182
  eigen_internal_assert(g2.representation.size() == m_numIndices);
183

  
184
  GroupElement result;
185
  result.representation.reserve(m_numIndices);
186
  for (std::size_t i = 0; i < m_numIndices; i++) {
187
    int v = g2.representation[g1.representation[i]];
188
    eigen_assert(v >= 0);
189
    result.representation.push_back(v);
190
  }
191
  result.flags = g1.flags ^ g2.flags;
192
  return result;
193
}
194

  
195
inline void DynamicSGroup::add(int one, int two, int flags)
196
{
197
  eigen_assert(one >= 0);
198
  eigen_assert(two >= 0);
199
  eigen_assert(one != two);
200

  
201
  if ((std::size_t)one >= m_numIndices || (std::size_t)two >= m_numIndices) {
202
    std::size_t newNumIndices = (one > two) ? one : two + 1;
203
    for (auto& gelem : m_elements) {
204
      gelem.representation.reserve(newNumIndices);
205
      for (std::size_t i = m_numIndices; i < newNumIndices; i++)
206
        gelem.representation.push_back(i);
207
    }
208
    m_numIndices = newNumIndices;
209
  }
210

  
211
  Generator g{one, two, flags};
212
  GroupElement e = ge(g);
213

  
214
  /* special case for first generator */
215
  if (m_elements.size() == 1) {
216
    while (!e.isId()) {
217
      m_elements.push_back(e);
218
      e = mul(e, g);
219
    }
220

  
221
    if (e.flags > 0)
222
      updateGlobalFlags(e.flags);
223

  
224
    // only add in case we didn't have identity
225
    if (m_elements.size() > 1)
226
      m_generators.push_back(g);
227
    return;
228
  }
229

  
230
  int p = findElement(e);
231
  if (p >= 0) {
232
    updateGlobalFlags(p);
233
    return;
234
  }
235

  
236
  std::size_t coset_order = m_elements.size();
237
  m_elements.push_back(e);
238
  for (std::size_t i = 1; i < coset_order; i++)
239
    m_elements.push_back(mul(m_elements[i], e));
240
  m_generators.push_back(g);
241

  
242
  std::size_t coset_rep = coset_order;
243
  do {
244
    for (auto g : m_generators) {
245
      e = mul(m_elements[coset_rep], g);
246
      p = findElement(e);
247
      if (p < 0) {
248
        // element not yet in group
249
        m_elements.push_back(e);
250
        for (std::size_t i = 1; i < coset_order; i++)
251
          m_elements.push_back(mul(m_elements[i], e));
252
      } else if (p > 0) {
253
        updateGlobalFlags(p);
254
      }
255
    }
256
    coset_rep += coset_order;
257
  } while (coset_rep < m_elements.size());
258
}
259

  
260
inline void DynamicSGroup::updateGlobalFlags(int flagDiffOfSameGenerator)
261
{
262
    switch (flagDiffOfSameGenerator) {
263
      case 0:
264
      default:
265
        // nothing happened
266
        break;
267
      case NegationFlag:
268
        // every element is it's own negative => whole tensor is zero
269
        m_globalFlags |= GlobalZeroFlag;
270
        break;
271
      case ConjugationFlag:
272
        // every element is it's own conjugate => whole tensor is real
273
        m_globalFlags |= GlobalRealFlag;
274
        break;
275
      case (NegationFlag | ConjugationFlag):
276
        // every element is it's own negative conjugate => whole tensor is imaginary
277
        m_globalFlags |= GlobalImagFlag;
278
        break;
279
      /* NOTE:
280
       *   since GlobalZeroFlag == GlobalRealFlag | GlobalImagFlag, if one generator
281
       *   causes the tensor to be real and the next one to be imaginary, this will
282
       *   trivially give the correct result
283
       */
284
    }
285
}
286

  
287
} // end namespace Eigen
288

  
289
#endif // EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H
290

  
291
/*
292
 * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
293
 */
TXM/trunk/bundles/org.txm.statsengine.r.core.linux/res/linux64/library/RcppEigen/include/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h (revision 3763)
1
// This file is part of Eigen, a lightweight C++ template library
2
// for linear algebra.
3
//
4
// Copyright (C) 2013 Christian Seiler <christian@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_STATICSYMMETRY_H
11
#define EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H
12

  
13
namespace Eigen {
14

  
15
namespace internal {
16

  
17
template<typename list> struct tensor_static_symgroup_permutate;
18

  
19
template<int... nn>
20
struct tensor_static_symgroup_permutate<numeric_list<int, nn...>>
21
{
22
  constexpr static std::size_t N = sizeof...(nn);
23

  
24
  template<typename T>
25
  constexpr static inline std::array<T, N> run(const std::array<T, N>& indices)
26
  {
27
    return {{indices[nn]...}};
28
  }
29
};
30

  
31
template<typename indices_, int flags_>
32
struct tensor_static_symgroup_element
33
{
34
  typedef indices_ indices;
35
  constexpr static int flags = flags_;
36
};
37

  
38
template<typename Gen, int N>
39
struct tensor_static_symgroup_element_ctor
40
{
41
  typedef tensor_static_symgroup_element<
42
    typename gen_numeric_list_swapped_pair<int, N, Gen::One, Gen::Two>::type,
43
    Gen::Flags
44
  > type;
45
};
46

  
47
template<int N>
48
struct tensor_static_symgroup_identity_ctor
49
{
50
  typedef tensor_static_symgroup_element<
51
    typename gen_numeric_list<int, N>::type,
52
    0
53
  > type;
54
};
55

  
56
template<typename iib>
57
struct tensor_static_symgroup_multiply_helper
58
{
59
  template<int... iia>
60
  constexpr static inline numeric_list<int, get<iia, iib>::value...> helper(numeric_list<int, iia...>) {
61
    return numeric_list<int, get<iia, iib>::value...>();
62
  }
63
};
64

  
65
template<typename A, typename B>
66
struct tensor_static_symgroup_multiply
67
{
68
  private:
69
    typedef typename A::indices iia;
70
    typedef typename B::indices iib;
71
    constexpr static int ffa = A::flags;
72
    constexpr static int ffb = B::flags;
73
  
74
  public:
75
    static_assert(iia::count == iib::count, "Cannot multiply symmetry elements with different number of indices.");
76

  
77
    typedef tensor_static_symgroup_element<
78
      decltype(tensor_static_symgroup_multiply_helper<iib>::helper(iia())),
79
      ffa ^ ffb
80
    > type;
81
};
82

  
83
template<typename A, typename B>
84
struct tensor_static_symgroup_equality
85
{
86
    typedef typename A::indices iia;
87
    typedef typename B::indices iib;
88
    constexpr static int ffa = A::flags;
89
    constexpr static int ffb = B::flags;
90
    static_assert(iia::count == iib::count, "Cannot compare symmetry elements with different number of indices.");
91

  
92
    constexpr static bool value = is_same<iia, iib>::value;
93

  
94
  private:
95
    /* this should be zero if they are identical, or else the tensor
96
     * will be forced to be pure real, pure imaginary or even pure zero
97
     */
98
    constexpr static int flags_cmp_ = ffa ^ ffb;
99

  
100
    /* either they are not equal, then we don't care whether the flags
101
     * match, or they are equal, and then we have to check
102
     */
103
    constexpr static bool is_zero      = value && flags_cmp_ == NegationFlag;
104
    constexpr static bool is_real      = value && flags_cmp_ == ConjugationFlag;
105
    constexpr static bool is_imag      = value && flags_cmp_ == (NegationFlag | ConjugationFlag);
106

  
107
  public:
108
    constexpr static int global_flags = 
109
      (is_real ? GlobalRealFlag : 0) |
110
      (is_imag ? GlobalImagFlag : 0) |
111
      (is_zero ? GlobalZeroFlag : 0);
112
};
113

  
114
template<std::size_t NumIndices, typename... Gen>
115
struct tensor_static_symgroup
116
{
117
  typedef StaticSGroup<Gen...> type;
118
  constexpr static std::size_t size = type::static_size;
119
};
120

  
121
template<typename Index, std::size_t N, int... ii, int... jj>
122
constexpr static inline std::array<Index, N> tensor_static_symgroup_index_permute(std::array<Index, N> idx, internal::numeric_list<int, ii...>, internal::numeric_list<int, jj...>)
123
{
124
  return {{ idx[ii]..., idx[jj]... }};
125
}
126

  
127
template<typename Index, int... ii>
128
static inline std::vector<Index> tensor_static_symgroup_index_permute(std::vector<Index> idx, internal::numeric_list<int, ii...>)
129
{
130
  std::vector<Index> result{{ idx[ii]... }};
131
  std::size_t target_size = idx.size();
132
  for (std::size_t i = result.size(); i < target_size; i++)
133
    result.push_back(idx[i]);
134
  return result;
135
}
136

  
137
template<typename T> struct tensor_static_symgroup_do_apply;
138

  
139
template<typename first, typename... next>
140
struct tensor_static_symgroup_do_apply<internal::type_list<first, next...>>
141
{
142
  template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args>
143
  static inline RV run(const std::array<Index, NumIndices>& idx, RV initial, Args&&... args)
144
  {
145
    static_assert(NumIndices >= SGNumIndices, "Can only apply symmetry group to objects that have at least the required amount of indices.");
146
    typedef typename internal::gen_numeric_list<int, NumIndices - SGNumIndices, SGNumIndices>::type remaining_indices;
147
    initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices(), remaining_indices()), first::flags, initial, std::forward<Args>(args)...);
148
    return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...);
149
  }
150

  
151
  template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args>
152
  static inline RV run(const std::vector<Index>& idx, RV initial, Args&&... args)
153
  {
154
    eigen_assert(idx.size() >= SGNumIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
155
    initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices()), first::flags, initial, std::forward<Args>(args)...);
156
    return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...);
157
  }
158
};
159

  
160
template<EIGEN_TPL_PP_SPEC_HACK_DEF(typename, empty)>
161
struct tensor_static_symgroup_do_apply<internal::type_list<EIGEN_TPL_PP_SPEC_HACK_USE(empty)>>
162
{
163
  template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args>
164
  static inline RV run(const std::array<Index, NumIndices>&, RV initial, Args&&...)
165
  {
166
    // do nothing
167
    return initial;
168
  }
169

  
170
  template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args>
171
  static inline RV run(const std::vector<Index>&, RV initial, Args&&...)
172
  {
173
    // do nothing
174
    return initial;
175
  }
176
};
177

  
178
} // end namespace internal
179

  
180
template<typename... Gen>
181
class StaticSGroup
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff