CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
BasisSet.cc
Go to the documentation of this file.
2 
3 #include <algorithm>
4 
5 #include "casm/misc/CASM_math.hh"
6 
11 
16 
21 
22 namespace CASM {
23 
24  //*******************************************************************************************
25 
26  BasisSet::BasisSet(const BasisSet &init_basis) :
27  Array<Function * >(0),
28  m_basis_symrep_ID(init_basis.basis_symrep_ID()),
29  m_name(init_basis.name()),
30  m_basis_ID(init_basis.m_basis_ID),
31  m_min_poly_order(init_basis.m_min_poly_order),
32  m_max_poly_order(init_basis.m_max_poly_order),
33  //m_eval_cache & m_deval_cache are taken care of by BasisSet::push_back
34  //m_eval_cache(init_basis.m_eval_cache),
35  //m_deval_cache(init_basis.m_deval_cache),
36  m_dof_IDs(init_basis.m_dof_IDs),
37  m_dof_subbases(init_basis.m_dof_subbases),
38  m_min_poly_constraints(init_basis.min_poly_constraints()),
39  m_max_poly_constraints(init_basis.max_poly_constraints()) {
40 
41  for(Index i = 0; i < init_basis.m_argument.size(); i++) {
42  m_argument.push_back(init_basis.m_argument[i]->shared_copy());
43  }
44 
45  for(Index i = 0; i < init_basis.size(); i++) {
46  if(!init_basis[i])
47  push_back(nullptr);
48  else {
49  push_back(init_basis[i]->copy());
51  }
52  }
53 
54  }
55 
56  //*******************************************************************************************
57 
58  const BasisSet &BasisSet::operator=(const BasisSet &RHS) {
59  if(this == &RHS) {
60  return *this;
61  }
62  clear();
66  //m_eval_cache & m_deval_cache are taken care of by BasisSet::push_back
67  //m_eval_cache = RHS.m_eval_cache;
68  //m_deval_cache = RHS.m_deval_cache;
69  m_eval_cache.clear();
70  m_deval_cache.clear();
71  m_name = RHS.name();
72  m_dof_IDs = RHS.m_dof_IDs;
76 
77  m_argument.clear();
78  for(Index i = 0; i < RHS.m_argument.size(); i++) {
79  m_argument.push_back(RHS.m_argument[i]->shared_copy());
80  }
81  for(Index i = 0; i < RHS.size(); i++) {
82  if(!RHS[i])
83  push_back(nullptr);
84  else {
85  push_back(RHS[i]->copy());
87  }
88  }
89  return *this;
90  }
91 
92 
93  //*******************************************************************************************
94 
96  clear();
97  }
98 
99  //*******************************************************************************************
100 
102  for(Index i = 0; i < size(); i++) {
103  if(at(i))
104  delete at(i);
105  }
107  _refresh_ID();
108  }
109 
110  //*******************************************************************************************
111 
112  void BasisSet::append(const BasisSet &RHS) {
113  //Before appending functions, copy over DoF IDs and subbasis info
114  for(Index i = 0; i < RHS.m_dof_IDs.size(); i++) {
115  Index ID_ind = m_dof_IDs.find(RHS.m_dof_IDs[i]);
116  if(ID_ind == m_dof_IDs.size()) {
117  assert(0 && "In BasisSet::append(), it is unsafe to append a BasisSet whose dependencies differ from (this).");
118  m_dof_IDs.push_back(RHS.m_dof_IDs[i]);
119  m_dof_subbases.push_back(SubBasis());
120  }
121 
122  for(Index j = 0; j < RHS.m_dof_subbases[i].size(); j++) {
123  //std::cout << "*** Push back " << j << " to subbases " << ID_ind << " value " << RHS.m_dof_subbases[i][j] + size() << "\n\n";
124  m_dof_subbases[ID_ind].push_back(RHS.m_dof_subbases[i][j] + size());
125  }
126  }
127 
128  //Convert polynomial constraints
130  for(Index i = 0; i < RHS.min_poly_constraints().size(); i++) {
132  for(Index j = 0; j < min_poly_constraints().back().first.size(); j++)
133  _min_poly_constraints().back().first[i] += size();
134  }
135 
137  for(Index i = 0; i < RHS.max_poly_constraints().size(); i++) {
139  for(Index j = 0; j < max_poly_constraints().back().first.size(); j++)
140  _max_poly_constraints().back().first[i] += size();
141  }
142 
143  //Convert RHS.min_poly_order() and RHS.max_poly_order into polynomial constraints
144  if(RHS.min_poly_order() > 0) {
146  }
147  if(valid_index(RHS.max_poly_order())) {
149  }
150  for(Index i = 0; i < RHS.size(); i++) {
151  if(!RHS[i])
152  push_back(nullptr);
153  else {
154  push_back(RHS[i]->copy());
156  }
157  }
158  _refresh_ID();
159  }
160 
161  //*******************************************************************************************
162 
164  BasisSet new_set;
165  for(Index i = 0; i < size(); i++) {
166  if(!at(i))
167  new_set.push_back(nullptr);
168  else
169  new_set.push_back(at(i)->poly_quotient(divisor));
170  }
171  return new_set;
172  }
173 
174  //*******************************************************************************************
175 
177  Index exp_sum;
178  for(Index i = 0; i < max_poly_constraints().size(); i++) {
179  exp_sum = 0;
180  for(Index j = 0; j < max_poly_constraints()[i].first.size(); j++) {
181  exp_sum += expons[max_poly_constraints()[i].first[j]];
182  }
183  if(max_poly_constraints()[i].second < exp_sum)
184  return false;
185  }
186  for(Index i = 0; i < min_poly_constraints().size(); i++) {
187  exp_sum = 0;
188  for(Index j = 0; j < min_poly_constraints()[i].first.size(); j++) {
189  exp_sum += expons[min_poly_constraints()[i].first[j]];
190  }
191  if(exp_sum < min_poly_constraints()[i].second)
192  return false;
193  }
194  exp_sum = expons.sum();
195  if(valid_index(min_poly_order()) && exp_sum < min_poly_order())
196  return false;
197  if(valid_index(max_poly_order()) && max_poly_order() < exp_sum)
198  return false;
199  return true;
200  }
201  //*******************************************************************************************
202  bool BasisSet::accept(const FunctionVisitor &visitor) {
203  bool is_changed(false), tchanged;
204  //std::cout << "Accepting visitor of type " << visitor.type_name() << "... \n";
205  for(Index i = 0; i < m_argument.size(); i++) {
206  tchanged = m_argument[i]->accept(visitor);
207  is_changed = tchanged || is_changed;
208  }
209  //std::cout << "BasisSet " << name() << " (" << this << ") and is_changed is " << is_changed << "\n";
210 
211  for(Index i = 0; i < size(); i++) {
212  if(at(i)) {
213  if(is_changed)
214  at(i)->clear_formula();
215  tchanged = at(i)->accept(visitor, this);
216  is_changed = tchanged || is_changed;
217  }
218  }
219  //if(is_changed)_refresh_ID(); //should we do this here?
220  return is_changed;
221  }
222 
223  //*******************************************************************************************
226  assert(size() == cumulant.size());
227  for(Index i = 0; i < m_argument.size(); i++)
229 
230  for(Index i = 0; i < size(); i++) {
231  if(at(i))
232  cumulant[i] += at(i)->cache_eval();
233  }
234  }
235 
236  //*******************************************************************************************
239  assert(size() == cumulant.size());
240  for(Index i = 0; i < m_argument.size(); i++)
241  m_argument[i]->_deval_to_cache(dvar);
242 
243  for(Index i = 0; i < size(); i++) {
244  if(at(i))
245  cumulant[i] += at(i)->cache_deval(dvar);
246  }
247  }
248 
249  //*******************************************************************************************
250 
251  bool BasisSet::compare(const BasisSet &RHS)const {
252  if(m_argument.size() != RHS.m_argument.size() || size() != RHS.size())
253  return false;
254 
255  for(Index i = 0; i < m_argument.size(); i++) {
256  if(!m_argument[i]->compare(*(RHS.m_argument[i])))
257  return false;
258  }
259 
260  for(Index i = 0; i < size(); i++) {
261  if(!(at(i)->shallow_compare(RHS[i])))
262  return false;
263  }
264  return true;
265  }
266 
267  //*******************************************************************************************
268 
270  int result = -1;
271  for(Index i = 0; i < m_argument.size(); i++)
272  result = CASM::max(result, m_argument[i]->dependency_layer());
273  return ++result;
274  }
275  //*******************************************************************************************
278  remote_eval_to(m_eval_cache.begin(), m_eval_cache.end());
279  }
280  //*******************************************************************************************
283  remote_eval_to(m_eval_cache.begin(), m_eval_cache.end());
284  remote_deval_to(m_deval_cache.begin(), m_deval_cache.end(), dvar);
285  //std::cout << "eval_cache: " << m_eval_cache << "\ndeval_cache: " << m_deval_cache << "\n\n";
286 
287  }
288  //*******************************************************************************************
289  void BasisSet::set_variable_basis(const Array<ContinuousDoF> &tvar_compon, SymGroupRepID _var_sym_rep_ID) {
290  m_argument.clear();
291  m_basis_symrep_ID = _var_sym_rep_ID;
292  Array<Index> tdof_IDs;
293  for(Index i = 0; i < tvar_compon.size(); i++) {
294  if(!tvar_compon[i].is_locked() && !tdof_IDs.contains(tvar_compon[i].ID()))
295  tdof_IDs.push_back(tvar_compon[i].ID());
296  }
297  set_dof_IDs(tdof_IDs);
298  for(Index i = 0; i < tvar_compon.size(); i++) {
299  push_back(new Variable(tvar_compon, i, _var_sym_rep_ID));
300  }
301  _refresh_ID();
302  }
303  //*******************************************************************************************
304  void BasisSet::set_dof_IDs(const Array<Index> &new_IDs) {
305  _update_dof_IDs(m_dof_IDs, new_IDs);
306  }
307  //*******************************************************************************************
308  // Pass before_IDs by value to avoid aliasing issues when called from BasisSet::set_dof_IDs()
309  void BasisSet::_update_dof_IDs(const Array<Index> before_IDs, const Array<Index> &after_IDs) {
310  //std::cout << "BasisSet " << this << " --> m_dof_IDs is " << m_dof_IDs << "; before_IDs: " << before_IDs << "; after_ID: " << after_IDs << "\n" << std::endl;
311  if(before_IDs.size() != after_IDs.size() && size() > 0) {
312  std::cerr << "CRITICAL ERROR: In BasisSet::update_dof_IDs(), new IDs are incompatible with current IDs.\n"
313  << " Exiting...\n";
314  assert(0);
315  exit(1);
316  }
317 
318  //update m_dof_IDs after the other stuff, for easier debugging
319  if(m_dof_IDs.size() == 0) {
320  m_dof_IDs = after_IDs;
321  m_dof_subbases.resize(after_IDs.size());
322  }
323  else {
324  Index m;
325  for(Index i = 0; i < m_dof_IDs.size(); i++) {
326  m = before_IDs.find(m_dof_IDs[i]);
327  if(m == before_IDs.size()) {
328  std::cerr << "CRITICAL ERROR: In BasisSet::update_dof_IDs(), new IDs are incompatible with current IDs.\n"
329  << " Exiting...\n";
330  assert(0);
331  exit(1);
332  }
333  m_dof_IDs[i] = after_IDs[m];
334  }
335  }
336 
337  for(Index i = 0; i < m_argument.size(); i++)
338  m_argument[i]->_update_dof_IDs(before_IDs, after_IDs);
339 
340  for(Index i = 0; i < size(); i++) {
341  if(at(i))
342  at(i)->update_dof_IDs(before_IDs, after_IDs);
343  }
344 
345 
346  return;
347  }
348 
349  //*******************************************************************************************
350 
351  std::vector< std::set<Index> > BasisSet::independent_sub_bases() const {
352  std::vector< std::set<Index> > result;
353  std::vector<bool> unclaimed(size(), true);
354  for(Index i = 0; i < dof_sub_bases().size(); i++) {
355  if(dof_sub_basis(i).size() == 0)
356  continue;
357  Index j = 0;
358  for(j = 0; j < result.size(); j++) {
359  if(result[j].find(dof_sub_basis(i)[0]) != result[j].end()) {
360  break;
361  }
362  }
363  if(j == result.size())
364  result.emplace_back();
365  for(Index k = 0; k < dof_sub_basis(i).size(); k++) {
366  unclaimed[dof_sub_basis(i)[k]] = false;
367  result[j].insert(dof_sub_basis(i)[k]);
368  }
369  }
370  bool has_unclaimed = false;
371  for(Index i = 0; i < unclaimed.size(); i++) {
372  if(unclaimed[i]) {
373  if(!has_unclaimed) {
374  result.emplace_back();
375  has_unclaimed = true;
376  }
377  result.back().insert(i);
378  }
379  }
380  return result;
381  }
382 
383  //*******************************************************************************************
384 
385  int BasisSet::register_remotes(const std::string &dof_name, const Array<DoF::RemoteHandle> &remote_handles) {
386  int sum(0);
387  for(Index i = 0; i < size(); i++)
388  sum += at(i)->register_remotes(dof_name, remote_handles);
389 
390  for(Index i = 0; i < m_argument.size(); i++)
391  sum += m_argument[i]->register_remotes(dof_name, remote_handles);
392 
393  return sum;
394  }
395 
396  //*******************************************************************************************
397 
399 
400 
401  _set_arguments(tsubs);
402  //Array<BasisSet const *> abset(m_argument);
404  Array<Index> curr_expon(tpoly.poly_coeffs().depth(), 0);
405 
406  IsoCounter<Array<Index> > exp_count(Array<Index>(tsubs[0]->size(), 0), Array<Index>(tsubs[0]->size(), order), 1, order);
407 
408  do {
409  for(int i = 0; i < exp_count.size(); i++) {
410  //std::cout << exp_count()[i] << " ";
411  curr_expon[i] = exp_count()[i];
412  }
413  PolyTrie<double> new_trie(curr_expon.size());
414  new_trie(curr_expon) = 1.0;
415  push_back(tpoly.copy(new_trie));
416  //std::cout << std::endl;
417  }
418  while(++exp_count);
419 
420 
421  }
422 
423  //*******************************************************************************************
424 
425  void BasisSet::construct_invariant_polynomials(const Array<BasisSet const *> &tsubs, const SymGroup &head_group, Index order, Index min_dof_order) {
426 
427  _set_arguments(tsubs);
428  //std::cout << "Constructing invariant polynomials from DoFs:\n";
429  for(Index i = 0; i < tsubs.size(); ++i) {
430  if((tsubs[i]->basis_symrep_ID()).empty()) {
431  tsubs[i]->get_symmetry_representation(head_group);
432  }
433  //std::cout << tsubs[i]->name() << " ";
434  }
435 
436  if(tsubs.size() == 0 && min_poly_order() < 1) {
437  PolyTrie<double> ttrie(0);
438  ttrie(Array<Index>(0)) = 1.0;
440  return;
441  }
442  //std::cout << "\n\n";
443  //std::cout << "dof_IDs are: " << dof_IDs() << "\n\n";
444  //std::cout << "dof_sub_bases are: " << dof_sub_bases() << "\n\n";
445  PolynomialFunction *tpoly;
446  Array<Index> curr_exp;
448  typedef IsoCounter<Array<Index> > OrderCount;
449  typedef MultiCounter<OrderCount> ExpCount;
450 
451  // Add constraints that set a minimum combined order for each local dofset
452  for(Index i = 0; i < dof_IDs().size() && min_dof_order >= 0; i++) {
453  SubBasis big_sub_basis;
454  Index offset = 0;
455  for(Index j = 0; j < tsubs.size(); j++) {
456  //std::cout << "dof_IDs of tsub " << j << " are " << tsubs[j]->dof_IDs() << "\n";
457  Index ID_ind = (tsubs[j]->dof_IDs()).find(dof_IDs()[i]);
458  if(ID_ind == (tsubs[j]->dof_IDs()).size())
459  continue;
460  const SubBasis &sub_basis(tsubs[j]->dof_sub_basis(ID_ind));
461  for(Index b = 0; b < sub_basis.size(); b++) {
462  big_sub_basis.push_back(sub_basis[b] + offset);
463  }
464  offset += tsubs[j]->size();
465  }
466  //std::cout << "Adding min constraint: " << big_sub_basis << ": " << min_dof_order << "\n";
467  add_min_poly_constraint(big_sub_basis, min_dof_order);
468  }
469  //\ end DoFset constraints
470 
471  OrderCount::Container initial_order(tsubs.size(), 0), final_order(tsubs.size(), order);
472  for(Index i = 0; i < tsubs.size(); i++) {
473  if(valid_index(tsubs[i]->min_poly_order()))
474  initial_order[i] = tsubs[i]->min_poly_order();
475  if(valid_index(tsubs[i]->max_poly_order()))
476  final_order[i] = tsubs[i]->max_poly_order();
477  }
478  //std::cout << "order_count from: " << initial_order << " to final order: " << final_order << "\n\n";
479  OrderCount order_count(initial_order, final_order, 1, order);
480 
481  ExpCount exp_count;
482  for(Index i = 0; i < tsubs.size(); i++) {
483  exp_count.push_back(OrderCount(Array<Index>(tsubs[i]->size(), 0), Array<Index>(tsubs[i]->size(), order), 1, order_count[i]));
484  curr_exp.append(exp_count.back());
485  }
486 
487  for(; order_count.valid(); ++order_count) {
488  for(Index i = 0; i < exp_count.size(); i++)
489  exp_count[i].set_sum_constraint(order_count[i]);
490  for(; exp_count.valid(); ++exp_count) {
491  bool valid_expon = true;
492  for(Index i = 0; i < exp_count.size() && valid_expon; i++)
493  valid_expon = tsubs[i]->satisfies_exponent_constraints(exp_count[i]());
494 
495  if(!valid_expon)
496  continue;
497 
498  Index ne = 0;
499  ExpCount::const_value_iterator it(exp_count.value_begin()), it_end(exp_count.value_end());
500  for(; it != it_end; ++it) {
501  curr_exp[ne++] = *it;
502  }
503  if(!satisfies_exponent_constraints(curr_exp))
504  continue;
505  //else:
506  //std::cout << "Adding exponent " << curr_exp << "\n\n";
507 
508  tpoly = new PolynomialFunction(m_argument);
509  for(Index i = 0; i < head_group.size(); i++) {
510  tpoly->transform_monomial_and_add(1, curr_exp, head_group[i]);
511  }
512  push_back(tpoly);
513  }
514  }
515  Gram_Schmidt();
516 
517  //std::cout << "Result, with " << size() << " invariant functions:\n";
518  //for(Index i = 0; i < size(); i++)
519  //std::cout << "F_" << i << " = " << at(i)->tex_formula() << "\n\n";
520  return;
521  }
522 
523  //*******************************************************************************************
524  // Construct generalized occupant functions that is orthonormal with respect to
525  // the inner product defined by gram_mat.
526  // - gram_mat should look like a covariance matrix of random vectors, of dimension
527  // allowed_occs.size(). This means that gram_mat should be positive-definite
528  // and symmetric. Additionally, the variance of the vector of all ones
529  // (i.e., v={1,1,...,1}) should have variance = 1, which indicates the constraint
530  // of conservation of number of occupants.
531  //
532  // The goal is to find a matrix 'B' of column vectors such that
533  // B.transpose()*gram_mat*B = Identity
534  // and such that the first column of 'B' is the vector of all ones (i.e., v={1,1,...,1})
535  // The first property is general solved by the matrix
536  // B = gram_mat^(-1/2)*W
537  // where gram_mat^(-1/2) is the inverse matrix square root of gram_mat, and 'W' is an arbitrary orthogonal matrix
538  // The second property places constraints on 'W'. We attempt to find a 'B' that is similar to the Chebychev
539  // basis in certain limiting cases.
540 
542  const Eigen::MatrixXd &gram_mat,
543  Index basis_ind,
544  const SymGroup &symgroup) {
545 
546  m_argument.clear();
547  m_max_poly_order = 1;
548  Index N = allowed_occs.size();
549  if(N <= 1) {
551  return;
552  }
553 
554  if(!allowed_occs.is_locked()) {
555  set_dof_IDs(Array<Index>(1, allowed_occs.ID()));
556  m_dof_subbases[0] = Array<Index>::sequence(0, N - 2);
557  }
558  //std::cout << "INSIDE construct_orthonormal_discrete_functions and gram_mat is \n";
559  //std::cout << gram_mat << "\n\n";
560  if(!almost_zero(Eigen::MatrixXd(gram_mat - gram_mat.transpose()))) {
561  // we could 'fix' gram_mat, but that could cause mysterious behavior - leave it to the user
562  std::cerr << "CRITICAL ERROR: Passed a Gram Matrix to BasisSet::construct_orthonormal_discrete_functions that is not symmetric.\n"
563  << " Gram Matrix is:\n" << gram_mat << "\nExiting...\n";
564  exit(1);
565  }
566 
567  Eigen::VectorXd conc_vec(gram_mat * Eigen::MatrixXd::Ones(N, 1));
568 
569  if(!almost_equal(1.0, conc_vec.sum())) {
570  // we could 'fix' gram_mat, but that could cause mysterious behavior - leave it to the user
571  std::cerr << "CRITICAL ERROR: Passed ill-conditioned Gram Matrix to BasisSet::construct_orthonormal_discrete_functions.\n"
572  << " The sum of the elements of the Gram matrix must be equal to 1.\n"
573  << " Gram Matrix is:\n" << gram_mat << "\nExiting...\n";
574  exit(1);
575  }
576 
577 
578  // ** step 1: find a generic 'B' matrix
579 
580  //Use SVD instead of eigendecomposition so that 'U' and 'V' matrices are orthogonal
581  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> teig(gram_mat, Eigen::ComputeEigenvectors);
582  if(teig.eigenvalues().minCoeff() < TOL) {
583  // we could 'fix' gram_mat, but that could cause mysterious behavior - leave it to the user
584  std::cerr << "CRITICAL ERROR: Passed a Gram Matrix to BasisSet::construct_orthonormal_discrete_functions that is not positive-definite.\n"
585  << " Gram Matrix is:\n" << gram_mat << "\nSmallest Eigenvalue = " << teig.eigenvalues().minCoeff() << "; Exiting...\n";
586  exit(1);
587  }
588 
589  // B matrix is matrix square root of gram_mat.inverse(). Its columns form an orthonormal basis wrt gram_mat
590  // In other words,
591  // B = V*(1.0/sqrt(D))*V.inverse()
592  // where V is matrix of eigenvectors (as columns) of gram_mat and D is diagonal matrix of eigenvalues of gram_mat
593  // B is not ideally oriented for our purposes, so the rest of the algorithm will be focused on fixing the orientation
594  Eigen::MatrixXd B = teig.eigenvectors() * (teig.eigenvalues().array().cwiseInverse().cwiseSqrt().matrix().asDiagonal()) * teig.eigenvectors().inverse();
595 
596 
597  // ** step 2: Make seed basis. This will be used to seed optimized orientation of 'B'
598  Eigen::MatrixXd tseed(Eigen::MatrixXd::Zero(N, N));
599  Eigen::MatrixXd::Index max_ind(0);
600  if(conc_vec.maxCoeff(&max_ind) < 0.75) {
601  // no "outlier" probabilities-> Use Chebychev polynomials as seed
602  //Fill cosine table -- columns contain powers of x from 0 to N-1
603  Eigen::MatrixXd tcos_table(N, N);
604  for(Index i = 0; i < N; i++) {
605  tcos_table(i, 0) = 1.0;
606  double x = -cos(M_PI * (i + 0.5) / double(N));
607  for(Index j = 1; j < N; j++) {
608  tcos_table(i, j) = x * tcos_table(i, j - 1);
609  }
610  }
611 
612  // QR decomposition of tcos_table yields Q matrix that holds chebychev basis
613  tseed = tcos_table.householderQr().householderQ();
614  }
615  else {
616  // there is an outlier probability --> set seed matrix to occupation basis, with specis 'i==max_ind' as solvent
617  Eigen::MatrixXd::Index curr_i(0);
618  for(Eigen::MatrixXd::Index i = 0; i < B.rows(); i++) {
619  tseed(i, 0) = 1;
620  if(i == max_ind)
621  continue;
622  for(Eigen::MatrixXd::Index j = 1; j < B.cols(); j++) {
623  if(curr_i + 1 == j)
624  tseed(i, j) = 1;
625  }
626  curr_i++;
627  }
628  }
629 
630  // ** step 3: use seed matric to find a unitary matrix that rotates 'B' a more optimal form
631  // Assume: tseed = B * Q, with unitary Q
632  // approximate Q by finding QR decomposition of (B.inverse() * tseed)
633  Eigen::MatrixXd Q = (B.inverse() * tseed).householderQr().householderQ();
634 
635  // Rotate 'B' by multiplication with 'W'
636  // eigen matrix multiplication doesn't alias
637 
638  B = B * Q;
639 
640  // Columns of B are our basis functions, orthonormal wrt gram_mat
641  for(Index i = 1; i < N; i++) {
642  int sign_change = 1;
643  double max_abs(0.0);
644  // The sign of each OccupantFunction is ambiguous, so we use a convention
645  // Force sign convention max(function(occupation))=max(abs(function(occupation)))
646  // If multiple occupations evaluate to the same abs(phi) and it is the maximal abs(phi),
647  // then use convention that the last occurence is positive
648  // It IS confusing, but here's a simple example:
649  //
650  // phi(occ) = {-1, 0, 1} is always preferred over phi_alt(occ) = {1, 0, -1}
651  //
652  // even though they are otherwise both equally valid basis functions
653  for(Index j = 0; j < B.rows(); j++) {
654  if(std::abs(B(j, i)) > (max_abs - TOL)) {
655  max_abs = std::abs(B(j, i));
656  sign_change = float_sgn(B(j, i));
657  }
658  }
659  OccupantFunction tOF(allowed_occs, double(sign_change)*B.col(i), size(), basis_ind, allowed_occs.sym_rep_ID());
660 
661  push_back(tOF.copy());
662  }
663 
664  // ** step 4: Calculate BasisSet symmetry representation, based on allowed_occs.sym_rep_ID() && B matrix
665  // Q*B.T=B.T*S, where we know S (how to transform a column vector), and we want Q (how to transform row vector)
666  // so Q=B.T*S*inv(B.T)
667  if(allowed_occs.sym_rep_ID().is_identity())
669  else
670  m_basis_symrep_ID = symgroup.master_group().add_transformed_rep(allowed_occs.sym_rep_ID(), Eigen::MatrixXd(B.transpose()));
671 
672  }
673 
674  //*******************************************************************************************
675  // Construct orthonormal basis set of OccupantFunctions for degree of freedom 'allowed_occs'
676  // - 'occ_probs' is an array of probabilities; occ_prob[i] is the probability of allowed_occs
677  // taking on value allowed_occs[i].
678  // These are equivalent ot composition, but we make a distinction to avoid confusion
679  // with global "parameterized compositions"
680  //
681  // This method finds a Gram matrix that is consistent with the probabilities and then passes it on to
682  // the overloaded version that takes a Gram matrix.
683  // The convention we use for the gram matrix is kind of arbitrary. Its limiting cases should yield orthonormality
684  // of the Chebychev polynomials when the probabilities are equal, and orthonormality of the occupation basis when
685  // only one probability is non-zero.
686 
688  const Array<double> &occ_probs,
689  Index basis_ind,
690  const SymGroup &symgroup) {
691 
692  Index N = allowed_occs.size();
693  if(allowed_occs.size() != occ_probs.size()) {
694  std::cerr << "CRITICAL ERROR: In BasiSet::construct_orthonormal_discrete_functions(), occ_probs and allowed_occs are incompatible!\nExiting...\n";
695  assert(0);
696  exit(1);
697  }
698 
699  if(!almost_equal(1.0, occ_probs.sum())) {
700  std::cerr << "CRITICAL ERROR: In BasiSet::construct_orthonormal_discrete_functions(), occ_probs must sum to 1 (they specify a probability distributation).\n"
701  << " occ_probs is: " << occ_probs << "\nExiting...\n";
702  assert(0);
703  exit(1);
704  }
705 
706  // Build a matrix with N-1 non-zero eigenvalues equal to 1/N.
707  // Remaining eigenvalue is zero, and corresponds to vector of all ones
708  Eigen::MatrixXd gram_mat(Eigen::MatrixXd::Zero(N, N));
709 
710  for(Index i = 0; i < N; i++) {
711  gram_mat(i, i) += occ_probs[i] - occ_probs[i] * occ_probs[i];
712  for(Index j = 0; j < N; j++) {
713  if(i == j) continue;
714 
715  gram_mat(i, i) += (occ_probs[i] - occ_probs[j]) * (occ_probs[i] - occ_probs[j]);
716 
717  gram_mat(i, j) -= occ_probs[i] * occ_probs[j] + (occ_probs[i] - occ_probs[j]) * (occ_probs[i] - occ_probs[j]);
718  }
719  }
720 
721 
722  // Add in the component corresponding to vector of all ones
723  // this is the uncorrelated part of the covariance
724  for(Index i = 0; i < N; i++) {
725  for(Index j = 0; j < N; j++) {
726  gram_mat(i, j) += occ_probs[i] * occ_probs[j];
727  }
728  }
729  construct_orthonormal_discrete_functions(allowed_occs, gram_mat, basis_ind, symgroup);
730  }
731 
732 
733  //*******************************************************************************************
735  Function *tfunc, *trans_func;
736  for(Index nf = 0; nf < size(); nf++) {
737  //std::cout << "trying function " << nf << " of " << size() << ": ";
738  //at(nf)->print(std::cout);
739  //std::cout << "\n";
740  tfunc = at(nf)->copy();
741  at(nf)->scale(0.0);
742  for(Index ng = 0; ng < head_group.size(); ng++) {
743  trans_func = tfunc->sym_copy_coeffs(head_group[ng]);
744  at(nf)->plus_in_place(trans_func);
745  delete trans_func;
746  }
747  //std::cout << "Result of Reynold's operator is ";
748  //at(nf)->print(std::cout);
749  //std::cout << "\n";
750  delete tfunc;
751  }
752  Gram_Schmidt();
753  return;
754  }
755 
756  //*******************************************************************************************
757  // Checks block_shape_matrix of BasisSet symmetry representation to see that there are
758  // as many blocks as there are irreducible representations
759 
760  bool BasisSet::is_normal_basis_for(const SymGroup &head_group) {
761  //First do some basic checks to ensure problem is well-defined
762  if(m_basis_symrep_ID.empty()) {
763  get_symmetry_representation(head_group);
764  }
765  if(m_basis_symrep_ID.empty()) {
766  std::cerr << "CRITICAL ERROR: Inside BasisSet::is_normal_basis_for() and cannot calculate a valid SymGroup representation. Exiting...\n";
767  exit(1);
768  }
769  if(!head_group.size())
770  return true;
771 
772  SymGroupRep const &t_rep(head_group[0].master_group().representation(m_basis_symrep_ID));
773 
774  //Check that block-diagonalization matches number of irreps
775  return t_rep.num_blocks(head_group) == (t_rep.num_each_real_irrep(head_group)).sum();
776 
777  }
778 
779  //*******************************************************************************************
780 
781  BasisSet BasisSet::calc_normal_basis(const SymGroup &head_group, Eigen::MatrixXd &trans_mat) const {
782  if(m_basis_symrep_ID.empty()) {
783  get_symmetry_representation(head_group);
784  }
785  if(m_basis_symrep_ID.empty()) {
786  std::cerr << "CRITICAL ERROR: Inside BasisSet::calc_normal_basis() and cannot calculate a valid SymGroup representation. Exiting...\n";
787  exit(1);
788  }
789  if(!head_group.size()) {
790  std::cerr << "CRITICAL ERROR: Inside BasisSet::calc_normal_basis() and and passed empty SymGroup. Exiting...\n";
791  }
792 
793 
794  SymGroupRep const &t_rep(head_group[0].master_group().representation(m_basis_symrep_ID));
795  trans_mat = t_rep.get_irrep_trans_mat(head_group);
796  BasisSet normal_basis(transform_copy(trans_mat));
797  normal_basis.m_basis_symrep_ID = (t_rep.coord_transformed_copy(trans_mat)).add_copy_to_master();
798  return normal_basis;
799  }
800 
801  //*******************************************************************************************
802 
803  void BasisSet::push_back(Function *new_func) {
805  m_eval_cache.push_back(0.0);
806  m_deval_cache.push_back(0.0);
807  if(m_argument.size() == 0 && new_func != nullptr) {
808  _set_arguments(new_func->argument_bases());
809  }
810  }
811 
812  //*******************************************************************************************
813 
815  if(!size()) return nullptr;
816  if(size() != coeffs.size()) {
817  std::cerr << "FATAL ERROR: In BasisSet::_linear_combination, the number of basis functions \n"
818  << "does not match the size of the coefficient vector. Exiting...\n";
819  exit(1);
820  }
821 
822  Function *combfunc(nullptr), *tfunc(nullptr);
823 
824  for(EigenIndex i = 0; i < coeffs.size(); i++) {
825  if(almost_zero(coeffs[i])) continue;
826  if(!combfunc) {
827  combfunc = at(i)->copy();
828  combfunc->scale(coeffs[i]);
829  continue;
830  }
831  tfunc = at(i)->copy();
832  tfunc->scale(coeffs[i]);
833  combfunc->plus_in_place(tfunc);
834  delete tfunc;
835  }
836  if(!combfunc) {
837  combfunc = at(0)->copy();
838  combfunc->scale(0.0);
839  }
840  return combfunc;
841  }
842 
843  //*******************************************************************************************
844 
848 
850  BasisSet copy_basis;
851  if(trans_mat.cols() != size()) {
852  std::cerr << "In BasisSet::transform_copy(), attempting to transform basis with a transformation\n"
853  << "matrix that has incompatible number of columns (has " << trans_mat.cols() << " and needs " << size() << ").\n"
854  << "Exiting...\n";
855  exit(1);
856  }
857  for(EigenIndex nc = 0; nc < trans_mat.rows(); nc++) {
858  copy_basis.push_back(_linear_combination(trans_mat.row(nc)));
859  }
860 
861  // We should also transform the SymGroupRep, but we only have the ID, not the MasterSymGroup
862 
863  return copy_basis;
864  }
865 
866  //*******************************************************************************************
867  //TODO: Transform functions with mixed dependency layers
868  BasisSet &BasisSet::apply_sym(const SymOp &op, int _dependency_layer /* = 1 */) {
869  int this_dep_layer = dependency_layer();
870  if(this_dep_layer == _dependency_layer) {
871  for(Index i = 0; i < size(); i++)
872  at(i)->apply_sym_coeffs(op);
873  }
874  else {
875  for(Index i = 0; i < m_argument.size(); i++) {
876  m_argument[i]->apply_sym(op, _dependency_layer);
877  }
878  }
879  return *this;
880  }
881 
882  //*******************************************************************************************
883 
885  if(m_argument.size()) {
886  std::cerr << "CRITICAL ERROR: In BasisSet::_set_arguments(), cannot reset arguments of already-initialized BasisSet.\n"
887  << " Exiting...\n";
888  exit(1);
889  }
890  m_argument.reserve(new_args.size());
891  for(Index i = 0; i < new_args.size(); i++)
892  m_argument.push_back(new_args[i]->shared_copy());
893  }
894 
895  //*******************************************************************************************
896  // Does modified Gram-Schmidt procedure, using tolerance checking for increased speed and stability
897  // In worst case, this requires N*(N-1)/2 binary operations
898 
899  // In future, may wish to use alternative approach: 1) find Gram matrix G, where G(i,j)=at(i)->dot(at(j));
900  // 2) find orthonormal eigenvectors of G, forming columns of the matrix V
901  // 3) take the linear combination V.transpose()*(*this)
902  // This alternate approach may be more numerically stable, but probably results in less sparse representations, unless there
903  // is a way to compute an optimally sparse V matrix
904 
906  bool is_unchanged(true);
907  Index i, j;
908  double tcoeff;
909  Function *tfunc(nullptr);
910 
911  // loop over functions
912  for(i = 0; i < size(); i++) {
913  at(i)->small_to_zero(2 * TOL);
914 
915  tcoeff = sqrt(at(i)->dot(at(i)));
916 
917  if(tcoeff < TOL) {
918  is_unchanged = false;
919  delete at(i);
920  remove(i);
921  i--;
922  continue;
923  }
924  else if(!almost_zero(tcoeff - 1.0)) {
925  is_unchanged = false;
926  at(i)->scale(1.0 / tcoeff);
927  }
928 
929  // loop from i+1 to end and subtract projection of Function i onto Function j
930  for(j = i + 1; j < size(); j++) {
931  tcoeff = (at(i)->dot(at(j)));
932  if(almost_zero(tcoeff)) {
933  continue;
934  }
935 
936  is_unchanged = false;
937 
938  tfunc = at(i)->copy();
939 
940 
941  if(!almost_zero(tcoeff - 1)) {
942  tfunc->scale(tcoeff);
943  }
944 
945  at(j)->minus_in_place(tfunc);
946 
947  delete tfunc;
948  }
949 
950  }
951  if(!is_unchanged) m_basis_symrep_ID = SymGroupRepID();
952  return is_unchanged;
953 
954  }
955 
956  //*******************************************************************************************
957 
959  bool is_unchanged(true);
960  Index i(0), j(0);
961  Index j_min, i_min, i_temp;
962  double tcoeff, min_coeff;
963  Function *tfunc;
964  while(i < size()) {
965  j_min = Index(-1);
966  for(i_temp = i; i_temp < size(); i_temp++) {
967  tcoeff = at(i_temp)->leading_coefficient(j);
968  if(almost_zero(tcoeff)) {
969  delete at(i_temp);
970  remove(i_temp);
971  i_temp--;
972  is_unchanged = false;
973  continue;
974  }
975  if(!valid_index(j_min) || j < j_min || (j == j_min && std::abs(tcoeff) > std::abs(min_coeff))) {
976  j_min = j;
977  i_min = i_temp;
978  min_coeff = tcoeff;
979  }
980  }
981  if(i >= size()) break;
982 
983  j = j_min;
984  if(i != i_min) {
985  is_unchanged = false;
986  swap_elem(i, i_min);
987  }
988  if(!almost_zero(min_coeff - 1)) {
989  at(i)->scale(1.0 / min_coeff);
990  }
991 
992  for(i_temp = 0; i_temp < size(); i_temp++) {
993  if(i_temp == i) continue;
994  tcoeff = at(i_temp)->get_coefficient(j);
995  if(almost_zero(tcoeff)) continue;
996  is_unchanged = false;
997  if(almost_zero(tcoeff - 1)) {
998  at(i_temp)->minus_in_place(at(i));
999  continue;
1000  }
1001  tfunc = at(i)->copy();
1002  tfunc->scale(tcoeff);
1003  at(i_temp)->minus_in_place(tfunc);
1004  delete tfunc;
1005  }
1006  i++;
1007  }
1008  for(i = 0; i < size(); i++) {
1009  at(i)->small_to_zero(2 * TOL);
1010  }
1011 
1012  if(!is_unchanged) m_basis_symrep_ID = SymGroupRepID();
1013 
1014  return is_unchanged;
1015 
1016  }
1017  //*******************************************************************************************
1018  void BasisSet::get_symmetry_representation(const SymGroup &head_group) const {
1019  if(!head_group.size() || !head_group[0].has_valid_master()) return;
1020 
1022  Function *tfunct(nullptr);
1023  Eigen::MatrixXd tRep(size(), size());
1024 
1025  for(Index ng = 0; ng < head_group.size(); ng++) {
1026  //Get representation for operation head_group[ng]
1027  //store it in matrix tRep
1028  for(Index nb1 = 0; nb1 < size(); nb1++) {
1029 
1030  tfunct = at(nb1)->sym_copy_coeffs(head_group[ng]);
1031  for(Index nb2 = 0; nb2 < size(); nb2++) {
1032  tRep(nb2, nb1) = tfunct->dot(at(nb2));
1033  }
1034  delete tfunct;
1035  }
1036 
1037  //We have the representation of operation head_group[ng]
1038  //Make a new SymOpRepresentation out of it and push it back
1039  head_group[ng].set_rep(m_basis_symrep_ID, SymMatrixXd(tRep));
1040  }
1041 
1042  }
1043 
1044  //*******************************************************************************************
1045 
1046  bool BasisSet::make_orthogonal_to(const BasisSet &ortho_basis) {
1047  bool ortho_flag(true);
1048  for(Index i = 0; i < ortho_basis.size(); i++) {
1049  ortho_flag = make_orthogonal_to(ortho_basis[i]) && ortho_flag;
1050 
1051  }
1052  return ortho_flag;
1053  }
1054 
1055  //*******************************************************************************************
1056 
1057  bool BasisSet::make_orthogonal_to(Function const *ortho_func) {
1058 
1059  bool ortho_flag(true);
1060  if(!size()) {
1061  return ortho_flag;
1062  }
1063 
1064  double tcoeff;
1065  Function *tfunc(ortho_func->copy());
1066 
1067  //std::cout << "Ortho_func: " << tfunc->tex_formula() << "\n\n";
1068  tcoeff = tfunc->dot(tfunc);
1069  //std::cout << "Squared magnitude is " << tcoeff << "\n";
1070 
1071  if(almost_zero(tcoeff)) {
1072  delete tfunc;
1073  return ortho_flag;
1074  }
1075 
1076  if(!almost_zero(tcoeff - 1.0)) {
1077  tfunc->scale(1.0 / sqrt(tcoeff));
1078  }
1079  for(Index i = 0; i < size(); i++) {
1080  //std::cout << "Func " << i << ": " << at(i)->tex_formula() << "\n\n";
1081  tcoeff = (at(i)->dot(tfunc));
1082  //std::cout << "Projection: " << tcoeff << "\n\n";
1083  if(almost_zero(tcoeff)) {
1084  continue;
1085  }
1086  ortho_flag = false;
1087  //You're changing the BasisSet, so the representation is no longer useable!
1089 
1090  tfunc->scale(tcoeff);
1091  at(i)->minus_in_place(tfunc);
1092  tfunc->scale(1.0 / tcoeff);
1093  at(i)->normalize();
1094 
1095  //std::cout << "Result is " << at(i)->tex_formula() << "\n\n";
1096  }
1097 
1098  delete tfunc;
1099 
1100 
1101  return ortho_flag;
1102  }
1103 
1104 
1105  //*******************************************************************************************
1106  //** jsonParser stuff - BasisSet
1107  //*******************************************************************************************
1108 
1110 
1111  json.put_obj();
1112 
1113  // class BasisSet: public Array<Function *>
1114  json["basis_functions"].put_array();
1115  for(Index i = 0; i < size(); i++) {
1116  json["basis_functions"].push_back(at(i));
1117  }
1118 
1119  // mutable int m_basis_symrep_ID;
1120  json["m_basis_symrep_ID"] = m_basis_symrep_ID;
1121 
1122  // Array<BasisSet> subspaces;
1123  //json["subspaces"] = m_subspaces;
1124 
1125  return json;
1126  }
1127 
1128  //*******************************************************************************************
1129 
1130  /*
1131  void BasisSet::from_json(const jsonParser &json) {
1132 
1133  // no reading BasisSet for now
1134 
1135  }
1136  */
1137 
1138 
1139  //*******************************************************************************************
1140 
1142  return bset.to_json(json);
1143  }
1144 
1145  //*******************************************************************************************
1146  /*
1147  // No reading functions for now
1148  void from_json(BasisSet &bset, const jsonParser &json) {
1149  return bset.from_json(json);
1150  }
1151  */
1152 
1153  //*******************************************************************************************
1154  BasisSet operator*(const SymOp &LHS, const BasisSet &RHS) {
1155  return BasisSet(RHS).apply_sym(LHS);
1156  }
1157 
1158 }
1159 
Eigen::MatrixXd MatrixXd
bool make_orthogonal_to(Function const *ortho_func)
Definition: BasisSet.cc:1057
void _set_arguments(const Array< BasisSet const * > &new_args)
Definition: BasisSet.cc:884
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
std::pair< SubBasis, Index > PolyConstraint
Definition: BasisSet.hh:29
void get_symmetry_representation(const SymGroup &head_sym_group) const
Definition: BasisSet.cc:1018
bool update_dof_IDs(const Array< Index > &before_IDs, const Array< Index > &after_IDs)
Index ID() const
Definition: DoF.hh:71
bool contains(const T &test_elem) const
Definition: Array.hh:281
void _deval_to_cache(const DoF::RemoteHandle &_dvar) const
Remotely evaluate each basis function and add it to the respective value in cumulant.
Definition: BasisSet.cc:282
Index size() const
Definition: Array.hh:145
Index depth() const
Definition: PolyTrie.hh:234
const MasterSymGroup & master_group() const
Definition: SymGroup.hh:56
Type-safe ID object for communicating and accessing Symmetry representation info. ...
bool empty() const
Returns true if SymGroupRepID has not been initialized with valid group_index or rep_index.
bool accept(const FunctionVisitor &visitor, BasisSet const *home_basis_ptr=NULL)
void construct_polynomials_by_order(const Array< BasisSet const * > &tsubs, Index order)
Definition: BasisSet.cc:398
virtual Function * apply_sym_coeffs(const SymOp &op, int dependency_layer=1)
void calc_invariant_functions(const SymGroup &head_sym_group)
Definition: BasisSet.cc:734
void push_back(const T &toPush)
Definition: Array.hh:513
SymGroupRepID add_transformed_rep(SymGroupRepID orig_ID, const Eigen::MatrixXd &trans_mat) const
Definition: SymGroup.cc:344
const Array< PolyConstraint > & max_poly_constraints() const
Definition: BasisSet.hh:63
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
Function * minus_in_place(Function const *RHS)
bool is_identity() const
Returns true if SymGroupRepID corresponds to an Identity representation.
BasisSet transform_copy(const Eigen::MatrixXd &trans_mat) const
Definition: BasisSet.cc:849
Index m_min_poly_order
Definition: BasisSet.hh:228
virtual int register_remotes(const std::string &dof_name, const Array< DoF::RemoteHandle > &remote_handles)
void construct_invariant_polynomials(const Array< BasisSet const * > &tsubs, const SymGroup &head_sym_group, Index order, Index min_dof_order=1)
Definition: BasisSet.cc:425
void add_min_poly_constraint(const Array< Index > &expons, Index expon_sum)
Definition: BasisSet.hh:108
void push_back(Function *new_func)
Definition: BasisSet.cc:803
std::string m_name
Definition: BasisSet.hh:215
const std::string & name() const
Definition: BasisSet.hh:45
bool Gram_Schmidt()
Definition: BasisSet.cc:905
Array< PolyConstraint > & _min_poly_constraints()
Definition: BasisSet.hh:273
Main CASM namespace.
Definition: complete.cpp:8
bool compare(const BasisSet &RHS) const
Definition: BasisSet.cc:251
virtual double get_coefficient(Index i) const =0
void set_arguments(const ArgumentContainer &new_arg)
void remote_eval_and_add_to(Array< double > &cumulant) const
Remotely evaluate each basis function and add it to the respective value in cumulant.
Definition: BasisSet.cc:225
const double TOL
static ReturnArray< T > sequence(const T &initial, const T &final)
Returns an array with the sequence (initial, ++initial, ..., final), inclusive.
Definition: Array.hh:343
BasisSet poly_quotient_set(const Function *divisor) const
Definition: BasisSet.cc:163
Eigen::MatrixXd get_irrep_trans_mat(const SymGroup &head_group) const
BasisSet calc_normal_basis(const SymGroup &head_sym_group, Eigen::MatrixXd &trans_mat) const
Definition: BasisSet.cc:781
std::vector< double > m_deval_cache
Definition: BasisSet.hh:235
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
Array< SubBasis > m_dof_subbases
Definition: BasisSet.hh:231
void append(const BasisSet &RHS)
Definition: BasisSet.cc:112
virtual void scale(double scale_factor)=0
void clear()
Definition: Array.hh:216
jsonParser & to_json(jsonParser &json) const
Definition: BasisSet.cc:1109
SymGroupRepID sym_rep_ID() const
Definition: DoF.hh:132
Eigen::MatrixXd::Index EigenIndex
For integer indexing:
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
BasisSet operator*(const SymOp &LHS, const BasisSet &RHS)
Definition: BasisSet.cc:1154
virtual void small_to_zero(double tol=TOL)=0
virtual Function * copy() const =0
int dependency_layer() const
Definition: BasisSet.cc:269
std::vector< std::shared_ptr< BasisSet > > m_argument
Definition: BasisSet.hh:218
EigenIndex Index
For long integer indexing:
void construct_orthonormal_discrete_functions(const DiscreteDoF &allowed_occs, const Eigen::MatrixXd &gram_mat, Index basis_ind, const SymGroup &symgroup)
Definition: BasisSet.cc:541
bool accept(const FunctionVisitor &visitor)
Definition: BasisSet.cc:202
const PolyTrie< double > & poly_coeffs() const
int float_sgn(T val, double compare_tol=TOL)
Definition: CASM_math.hh:130
SymGroupRepID m_basis_symrep_ID
Definition: BasisSet.hh:213
Array< Index > SubBasis
Definition: BasisSet.hh:28
Index num_blocks() const
Definition: SymGroupRep.cc:207
const Array< PolyConstraint > & min_poly_constraints() const
Definition: BasisSet.hh:60
Eigen::VectorXd VectorXd
bool is_normal_basis_for(const SymGroup &head_sym_group)
Definition: BasisSet.cc:760
bool is_locked() const
Definition: DoF.hh:82
std::vector< double > m_eval_cache
Definition: BasisSet.hh:234
virtual Index size() const =0
T sum() const
Definition: Array.hh:641
Index m_max_poly_order
Definition: BasisSet.hh:228
Function * transform_monomial_and_add(double prefactor, const Array< Index > &ind, const SymOp &op)
void _refresh_ID()
Definition: BasisSet.hh:256
Array< Index > m_dof_IDs
Definition: BasisSet.hh:230
T max(const T &A, const T &B)
Definition: CASM_math.hh:32
Function * sym_copy_coeffs(const SymOp &op, int dependency_layer=1) const
Function *& at(Index ind)
Definition: Array.hh:157
T dot(const Tensor< T > &LHS, const Tensor< T > &RHS)
Definition: Tensor.hh:961
void swap_elem(Index i, Index j)
Definition: Array.hh:231
BasisSet(const std::string &name="")
Definition: BasisSet.hh:35
Index find(const T &test_elem) const
Definition: Array.hh:707
int register_remotes(const std::string &dof_name, const Array< DoF::RemoteHandle > &remote_handles)
Definition: BasisSet.cc:385
Array & append(const Array &new_tail)
Definition: Array.hh:897
Generalized symmetry matrix representation for arbitrary dimension Can be used to describe applicatio...
Definition: SymMatrixXd.hh:22
A IsoCounter allows looping over many incrementing variables in one loop.
Definition: IsoCounter.hh:63
double dot(Function const *RHS) const
bool Gaussian_Elim()
Definition: BasisSet.cc:958
void remote_eval_to(IteratorType result_begin, IteratorType result_end) const
Remotely evaluate each basis function and add it to the respective value in cumulant.
Definition: BasisSet.hh:293
SymGroupRepID basis_symrep_ID() const
Definition: BasisSet.hh:49
ReturnArray< Index > num_each_real_irrep(const SymGroup &subgroup, bool verbose=false) const
Definition: SymGroupRep.cc:668
Function * _back()
Definition: BasisSet.hh:242
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:276
void reserve(Index new_max)
Definition: Array.hh:491
void _update_dof_IDs(const Array< Index > before_IDs, const Array< Index > &after_IDs)
Definition: BasisSet.cc:309
void clear()
Definition: BasisSet.cc:101
jsonParser & push_back(const T &value)
Puts new valued element at end of array of any type T for which 'jsonParser& to_json( const T &value...
Definition: jsonParser.hh:696
BasisSet & apply_sym(const SymOp &op, int dependency_layer=1)
Definition: BasisSet.cc:868
SymGroupRep coord_transformed_copy(const Eigen::MatrixXd &trans_mat) const
Definition: SymGroupRep.cc:280
Function * _linear_combination(const Eigen::VectorXd &coeffs) const
Definition: BasisSet.cc:814
SymGroupRep is an alternative representation of a SymGroup for something other than real space...
Definition: SymGroupRep.hh:30
void set_variable_basis(const Array< ContinuousDoF > &tvar_compon, SymGroupRepID _sym_rep_ID)
Define the basis set to contain only variables (e.g., x,y,z)
Definition: BasisSet.cc:289
const SubBasis & dof_sub_basis(Index i) const
Definition: BasisSet.hh:143
void remote_deval_to(IteratorType result_begin, IteratorType result_end, const DoF::RemoteHandle &dvar) const
Remotely evaluate derivative of each basis function (w.r.t. dvar) and add it to the respective value ...
Definition: BasisSet.hh:309
virtual double leading_coefficient() const =0
Function * plus_in_place(Function const *RHS)
void set_dof_IDs(const Array< Index > &new_IDs)
Definition: BasisSet.cc:304
virtual double cache_deval(const DoF::RemoteHandle &dvar) const =0
Index max_poly_order() const
Definition: BasisSet.hh:53
const ArgumentContainer & argument_bases() const
void remote_deval_and_add_to(Array< double > &cumulant, const DoF::RemoteHandle &dvar) const
Remotely evaluate derivative of each basis function (w.r.t. dvar) and add it to the respective value ...
Definition: BasisSet.cc:238
const BasisSet & operator=(const BasisSet &RHS)
Definition: BasisSet.cc:58
Index min_poly_order() const
Definition: BasisSet.hh:56
pair_type bset
Definition: settings.cc:111
T & back()
Definition: Array.hh:177
Array< PolyConstraint > & _max_poly_constraints()
Definition: BasisSet.hh:276
bool satisfies_exponent_constraints(const Array< Index > &expons) const
Definition: BasisSet.cc:176
std::vector< std::set< Index > > independent_sub_bases() const
Definition: BasisSet.cc:351
SymGroupRepID add_empty_representation() const
Add a new empty representation.
Definition: SymGroup.cc:3109
Basic std::vector like container (deprecated)
virtual double cache_eval() const =0
jsonParser & put_array()
Puts new empty JSON array.
Definition: jsonParser.hh:285
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
void _eval_to_cache() const
Remotely evaluate each basis function and add it to the respective value in cumulant.
Definition: BasisSet.cc:277
const Array< SubBasis > & dof_sub_bases() const
Definition: BasisSet.hh:147
const Array< Index > & dof_IDs() const
Definition: BasisSet.hh:139
static SymGroupRepID identity(Index dim)
Static function to construct an ID for identity representations.
void clear_formula()
bool valid_index(Index i)