CASM  1.1.0
A Clusters Approach to Statistical Mechanics
Orbit_impl.hh
Go to the documentation of this file.
1 #ifndef CASM_Orbit_impl
2 #define CASM_Orbit_impl
3 
4 #include <boost/iterator/transform_iterator.hpp>
5 #include <set>
6 
8 #include "casm/global/errors.hh"
9 #include "casm/misc/algorithm.hh"
10 #include "casm/symmetry/Orbit.hh"
12 
13 // #include "casm/casm_io/Log.hh"
14 // #include "casm/casm_io/json/jsonParser.hh"
15 // #include "casm/casm_io/container/json_io.hh"
16 
17 namespace CASM {
18 
19 namespace Orbit_impl {
20 
21 // -- Sort using indices ---
22 
23 struct EqMapRow {
32 
34  const std::vector<std::vector<Index>> &tmp_eq_map, const SymGroup &g)
35  : a(_a), b(_b) {
36  try {
37  Index a2proto = g.ind_inverse(tmp_eq_map[a][0]);
38  for (Index j = 0; j < tmp_eq_map[b].size(); ++j) {
39  values.emplace(g.ind_prod(tmp_eq_map[b][j], a2proto));
40  }
41  } catch (const std::exception &e) {
43  "Error in Orbit constructor: Failed constructing EqMapRow.");
44  }
45  };
46 
47  Index a; // 'a' in tmp_eq_map[a][j]
48  Index b; // 'b' in tmp_eq_map[b][j]
49  std::set<Index> values; // equivalence_map for b, relative to a
50 
51  bool operator<(const EqMapRow &other) const {
52  return this->values < other.values;
53  }
54 };
55 
56 struct RelEqMap {
58  RelEqMap(Index _a, const std::vector<std::vector<Index>> &tmp_eq_map,
59  const SymGroup &g)
60  : a(_a) {
61  try {
62  for (Index b = 0; b < tmp_eq_map.size(); ++b) {
63  map.emplace(a, b, tmp_eq_map, g);
64  }
65  } catch (const std::exception &e) {
67  "Error in Orbit constructor: Failed constructing RelEqMap.");
68  }
69  }
70 
71  Index a; // 'a' in tmp_eq_map[a]
72  std::set<EqMapRow> map; // equivalence_map for b, relative to a
73 
74  bool operator<(const RelEqMap &other) const { return this->map < other.map; }
75 };
76 
77 std::ostream &operator<<(std::ostream &sout, const RelEqMap &map);
78 
79 } // namespace Orbit_impl
80 
81 /* -- Orbit Definitions ------------------------------------- */
82 
90 template <typename _SymCompareType>
92  const SymGroup &generating_group,
93  const SymCompareType &sym_compare)
94  : m_generating_group(generating_group),
95  m_sym_compare(sym_compare),
96  m_invariants(sym_compare.make_invariants(generating_element)) {
97  // element(i) compares equivalent to
98  // prototype().copy_apply(equivalence_map[i][j]) for all j
99 
100  // X : op(0) op(1) ...
101  // proto: 0 ? ? (<-- proto.invariant_subgroup(g,
102  // sym_compare)) el(1): (the element generated by the first op that doesn't
103  // result in proto) el(2): (the element generated by the first op that
104  // doesn't result in proto or el(1))
105  // ... : ( etc. )
106 
107  // get tmp_elements w/ generating_element & g+sym_compare
108  // get tmp_equivalence_map from tmp_elements...
109  // use tmp_equivalence_map to generate equivalence_maps using the other
110  // elements as the prototype
111  // use the element with the 'lowest' equivalence_map as the prototype
112 
113  const SymGroup &g = generating_group;
114 
115  auto compare = [&](const Element &A, const Element &B) {
116  return m_sym_compare.compare(A, B);
117  };
118 
119  // generate equivalents using std::map to remove duplicates
120  // store ordered symop indices corresponding to transformations for each
121  // equivalent
122  std::map<Element, std::set<Index>, decltype(compare)> t_equiv(compare);
123  try {
124  for (Index i = 0; i < g.size(); i++) {
125  t_equiv[m_sym_compare.prepare(
126  m_sym_compare.copy_apply(g[i], generating_element))]
127  .insert(i); // not g[i].index()!!;
128  }
129  } catch (const std::exception &e) {
130  throw libcasm_runtime_error(
131  "Error in Orbit constructor: Failed generating unique equivalents.");
132  }
133 
134  // generate equivalence_map w/ tmp ordering
135  std::vector<Element> tmp_element;
136  std::vector<std::vector<Index>> tmp_equivalence_map;
137  try {
138  Index first2proto = g.ind_inverse(*(t_equiv.begin()->second.begin()));
139 
140  for (auto const &_equiv : t_equiv) {
141  tmp_element.push_back(_equiv.first);
142  tmp_equivalence_map.emplace_back();
143  for (Index op_i : _equiv.second) {
144  tmp_equivalence_map.back().push_back(g.ind_prod(op_i, first2proto));
145  }
146  }
147 
148  // sanity check that equivalence_map is rectangular
149  for (Index j = 1; j < tmp_equivalence_map.size(); ++j) {
150  if (tmp_equivalence_map[0].size() != tmp_equivalence_map[j].size()) {
151  throw libcasm_runtime_error(
152  "Error in Orbit constructor: equivalence map is not rectangular");
153  }
154  }
155  } catch (const std::exception &e) {
156  throw libcasm_runtime_error(
157  std::string("Error in Orbit constructor: ") +
158  "Failed generating initial equivalence map: " + e.what());
159  }
160 
165  Index best_a = 0;
166  Orbit_impl::RelEqMap best(best_a, tmp_equivalence_map, g);
167  try {
168  for (Index a = 1; a < tmp_equivalence_map.size(); ++a) {
169  Orbit_impl::RelEqMap test(a, tmp_equivalence_map, g);
170 
171  if (test < best) {
172  best_a = a;
173  best = std::move(test);
174  }
175  }
176  } catch (const std::exception &e) {
177  throw libcasm_runtime_error(
178  "Error in Orbit constructor: Failed generating sorted equivalence "
179  "map.");
180  }
181 
183  try {
184  Index newproto_i = best.map.begin()->b;
185 
186  // Loop over equivalents 'i'
187  for (const auto &row : best.map) {
188  // Index of group element that maps proto to equiv 'i'
189  Index proto2i = *(row.values.begin());
190 
191  Element tequiv = m_sym_compare.prepare(
192  m_sym_compare.copy_apply(g[proto2i], tmp_element[newproto_i]));
193  SymOp ttrans = m_sym_compare.spatial_transform();
194 
195  m_element.push_back(m_sym_compare.copy_apply(ttrans * g[proto2i],
196  tmp_element[newproto_i]));
197  m_equivalence_map.emplace_back();
198  // Loop over elements 'j' of new, sorted clust_group (0 row of best.map)
199  for (const auto &cg_j : best.map.begin()->values) {
200  Index value = g.ind_prod(proto2i, cg_j);
201 
202  tequiv = m_sym_compare.prepare(
203  m_sym_compare.copy_apply(g[value], tmp_element[newproto_i]));
204  ttrans = m_sym_compare.spatial_transform();
205 
206  m_equivalence_map.back().push_back(ttrans * g[value]);
207  }
208  }
209  } catch (const std::exception &e) {
210  throw libcasm_runtime_error(
211  "Error in Orbit constructor: Failed copying sorted elements and "
212  "equivalence map.");
213  }
214 
215  if (m_equivalence_map[0][0].index() != 0) {
216  throw libcasm_runtime_error(
217  "Error in Orbit constructor: First equivalence map element is not "
218  "identity.");
219  }
220 }
221 
223 template <typename _SymCompareType>
225  // transform elements
226  for (auto it = m_element.begin(); it != m_element.end(); ++it) {
227  *it = m_sym_compare.copy_apply(op, *it);
228  }
229 
230  // transform equivalence map: std::vector<std::vector<SymOp> >
231  for (auto it = m_equivalence_map.begin(); it != m_equivalence_map.end();
232  ++it) {
233  for (auto op_it = it->begin(); op_it != it->end(); ++op_it) {
234  op_it->apply_sym(op);
235  }
236  }
237 
238  // transform sym_compare functor
239  m_sym_compare.apply_sym(op);
240 
241  return *this;
242 }
243 
245 template <typename _SymCompareType>
247  return m_sym_compare.inter_orbit_compare(prototype(), invariants(),
248  B.prototype(), B.invariants());
249 }
250 
251 template <typename _SymCompareType>
253  if (equivalence_map().size() == 0)
254  throw libcasm_runtime_error(
255  "In Orbit::_construct_canonization_rep(), equivalence_map is "
256  "uninitialized or empty! Cannot continue.");
257 
258  if (size() == 0) {
259  m_canonization_rep_ID = SymGroupRepID::identity(0);
260  return;
261  }
262 
263  m_canonization_rep_ID =
264  equivalence_map()[0][0].master_group().allocate_representation();
265 
266  for (Index j = 0; j < equivalence_map()[0].size(); j++) {
267  std::unique_ptr<SymOpRepresentation> new_rep =
268  m_sym_compare
269  .canonical_transform(
270  m_sym_compare.copy_apply(equivalence_map()[0][j], prototype()))
271  ->inverse();
272 
273  for (Index i = 0; i < equivalence_map().size(); i++) {
274  equivalence_map()[i][j].set_rep(m_canonization_rep_ID, *new_rep);
275  }
276  }
277  return;
278 }
279 
294 template <typename OrbitIterator, typename Element>
295 OrbitIterator find_orbit(OrbitIterator begin, OrbitIterator end, Element e) {
296  typedef typename std::iterator_traits<OrbitIterator>::value_type orbit_type;
297  typedef typename orbit_type::InvariantsType InvariantsType;
298  const auto &sym_compare = begin->sym_compare();
299  auto e_invariants = sym_compare.make_invariants(e);
300 
301  // first find range of possible orbit by checking invariants
302  auto compare = [&](const InvariantsType &A, const InvariantsType &B) {
303  return sym_compare.invariants_compare(A, B);
304  };
305  auto _range =
306  std::equal_range(invariants_iterator(begin), invariants_iterator(end),
307  e_invariants, compare);
308 
309  // find if any of the orbits in range [_range.first, _range.second) contain
310  // equivalent
311  auto contains = [&](const orbit_type &orbit) { return orbit.contains(e); };
312  auto res = std::find_if(_range.first.base(), _range.second.base(), contains);
313  if (res == _range.second.base()) {
314  return end;
315  }
316  return res;
317 }
318 
319 } // namespace CASM
320 
321 #endif
An Orbit of Element.
Definition: Orbit.hh:43
InvariantsType const & invariants() const
Definition: Orbit.hh:134
Orbit(Element generating_element, SymGroup const &generating_group, SymCompareType const &sym_compare)
Construct an Orbit from a generating_element Element, using provided symmetry group.
Definition: Orbit_impl.hh:91
std::vector< Element > m_element
All symmetrically equivalent elements (excluding those that SymCompare equivalent)
Definition: Orbit.hh:154
void _construct_canonization_rep() const
Definition: Orbit_impl.hh:252
Orbit & apply_sym(const SymOp &op)
Apply symmetry to Orbit.
Definition: Orbit_impl.hh:224
const Element & prototype() const
Identical to element(0)
Definition: Orbit.hh:68
size_type size() const
Definition: Orbit.hh:65
multivector< SymOp >::X< 2 > m_equivalence_map
element(i) compares equivalent to prototype().copy_apply(m_equivalence_map[i][j]) for all j
Definition: Orbit.hh:158
const SymGroup & generating_group() const
Return the generating SymGroup.
Definition: Orbit.hh:127
bool operator<(const Orbit &B) const
Compare orbits, using SymCompareType::inter_orbit_compare.
Definition: Orbit_impl.hh:246
typename _SymCompareType::Element Element
Definition: Orbit.hh:46
SymCompareType m_sym_compare
Functor used to check compare Element, including symmetry rules, and make canonical forms.
Definition: Orbit.hh:169
_SymCompareType SymCompareType
Definition: Orbit.hh:48
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:42
Index ind_inverse(Index i) const
Get index of operation that is inverse of operation at(i)
Definition: SymGroup.cc:1540
Index ind_prod(Index i, Index j) const
Get index of operation that is result of multiplication of at(i)*at(j)
Definition: SymGroup.cc:1550
static SymGroupRepID identity(Index dim)
Static function to construct an ID for identity representations.
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > inverse(const Eigen::MatrixBase< Derived > &M)
Return the integer inverse matrix of an invertible integer matrix.
std::ostream & operator<<(std::ostream &sout, const RelEqMap &map)
Definition: Orbit.cc:6
Main CASM namespace.
Definition: APICommand.hh:8
bool compare(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Compare ClusterInvariants.
OrbitIterator find_orbit(OrbitIterator begin, OrbitIterator end, Element e)
Find orbit containing an element in a range of Orbit.
Definition: Orbit_impl.hh:295
InvariantsIterator< OrbitIterator > invariants_iterator(OrbitIterator orbit_it)
Convert an Orbit iterator to an invariants iterator.
Definition: Orbit.hh:228
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value)
Definition: algorithm.hh:83
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
bool operator<(const EqMapRow &other) const
Definition: Orbit_impl.hh:51
EqMapRow(Index _a, Index _b, const std::vector< std::vector< Index >> &tmp_eq_map, const SymGroup &g)
Definition: Orbit_impl.hh:33
std::set< Index > values
Definition: Orbit_impl.hh:49
std::set< EqMapRow > map
Definition: Orbit_impl.hh:72
RelEqMap(Index _a, const std::vector< std::vector< Index >> &tmp_eq_map, const SymGroup &g)
generate eq_map row for tmp_element[b] relative to tmp_element[a]
Definition: Orbit_impl.hh:58
bool operator<(const RelEqMap &other) const
Definition: Orbit_impl.hh:74