CASM  1.1.0
A Clusters Approach to Statistical Mechanics
PolynomialFunction.cc
Go to the documentation of this file.
2 
11 #include "casm/symmetry/SymOp.hh"
12 namespace CASM {
13 
15  const std::vector<std::shared_ptr<BasisSet> > &_args)
16  : Function(_args), m_coeffs(0) {
17  Index i;
18  // i counts over subspaces (i.e., BasisSets in init_args)
19  for (i = 0; i < _args.size(); i++) {
20  // m_subspaces.push_back(Array<Index>(init_args[i].size()));
21  // m_sub_sym_reps.push_back(init_args[i].basis_symrep_ID());
22  if ((_args[i]->basis_symrep_ID()).empty()) {
23  std::cerr << "WARNING: Initializing a PolynomialFunction without knowing "
24  "how to apply symmetry to it. \n"
25  << " Something bad will probably happen; consider this "
26  "your warning!\n";
27  }
28  if (!_args[i]->size()) {
29  std::cerr << "WARNING: In PolynomialFunction constructor, initial "
30  "arguments are ill-defined. Continuing..\n";
31  return;
32  }
33  }
34 
36 }
37 
38 //*******************************************************************************************
39 
41  const std::vector<std::shared_ptr<BasisSet> > &_args,
42  const PolyTrie<double> &_coeffs)
43  : Function(_args), m_coeffs(_coeffs) {
44  Index i;
45  // i counts over subspaces (i.e., BasisSets in init_args)
46  for (i = 0; i < _args.size(); i++) {
47  // m_subspaces.push_back(Array<Index>(init_args[i].size()));
48  // m_sub_sym_reps.push_back(init_args[i].basis_symrep_ID());
49  if ((_args[i]->basis_symrep_ID()).empty()) {
50  std::cerr << "WARNING: Initializing a PolynomialFunction without knowing "
51  "how to apply symmetry to it. \n"
52  << " Something bad will probably happen; consider this "
53  "your warning!\n";
54  }
55  if (!_args[i]->size()) {
56  std::cerr << "WARNING: In PolynomialFunction constructor, initial "
57  "arguments are ill-defined. Continuing..\n";
58  return;
59  }
60  }
61 
62  if (m_coeffs.depth() != num_args()) {
63  std::cerr << "CRITICAL ERROR: PolynomialFunction initialized with "
64  "coefficients that are incompatible with its argument list.\n"
65  << " Exiting...\n";
66  exit(1);
67  }
68 }
69 
70 //*******************************************************************************************
71 
73  const PolynomialFunction &RHS)
74  : m_coeffs(0) {
75  Index i, j;
76  // RHS_ind tracks how exponents of RHS map into resulting product
77  Array<Index> RHS_ind;
78  for (i = 0; i < LHS.m_argument.size(); i++) {
79  m_argument.push_back(LHS.m_argument[i]);
80  }
81  m_arg2sub = LHS.m_arg2sub;
82  m_arg2fun = LHS.m_arg2fun;
83  Index linear_ind;
84 
85  // check each argument set from RHS to see if it already exists in m_argument
86  for (j = 0; j < RHS.m_argument.size(); j++) {
87  bool add_subspace(true);
88  linear_ind = 0;
89  for (i = 0; i < LHS.m_argument.size() && add_subspace; i++) {
90  if (LHS.m_argument[i]->compare(*RHS.m_argument[j])) {
91  add_subspace = false;
92  break;
93  }
94  linear_ind += LHS.m_argument[i]->size();
95  }
96 
97  // RHS.m_argument[j] does not already exist in the produt, so we add it
98  if (add_subspace) {
99  m_argument.push_back(RHS.m_argument[j]);
100  for (i = 0; i < RHS.m_argument[j]->size(); i++) {
101  m_arg2sub.push_back(m_argument.size() - 1);
102  m_arg2fun.push_back(i);
103  }
104  }
105 
106  // linear_ind is the index in (*this) that corresponds to argument
107  // (*RHS.m_argument[j])[0]
109  linear_ind, linear_ind + RHS.m_argument[j]->size() - 1));
110  }
111 
113  Array<Index> LHS_ind(num_args()), tot_ind(num_args());
114 
116  LHS_end(LHS.m_coeffs.end());
117  double t_coeff;
118  for (; LHS_it != LHS_end; ++LHS_it) {
119  for (i = 0; i < LHS_it.key().size(); i++) {
120  LHS_ind[i] = LHS_it.key()[i];
121  }
123  RHS_end(RHS.m_coeffs.end());
124  for (; RHS_it != RHS_end; ++RHS_it) {
125  t_coeff = (*RHS_it) * (*LHS_it);
126  if (almost_zero(t_coeff)) continue;
127 
128  tot_ind = LHS_ind;
129  for (i = 0; i < RHS_it.key().size(); i++) {
130  tot_ind[RHS_ind[i]] += RHS_it.key()[i];
131  }
132  m_coeffs.at(tot_ind) += t_coeff;
133  }
134  }
135  return;
136 }
137 
138 //*******************************************************************************************
139 
141  : Function(RHS), m_coeffs(RHS.m_coeffs) {}
142 
143 //*******************************************************************************************
144 
146  const PolyTrie<double> &_coeffs)
147  : Function(RHS), m_coeffs(_coeffs) {
148  if (m_coeffs.depth() != RHS.m_coeffs.depth()) {
149  std::cerr << "WARNING: In PolynomialFunction::PolynomialFunction(const "
150  "PolynomialFunction&, const PolyTrie<double>&),\n"
151  << " the new PolyTrie is incompatible with with the "
152  "number of arguments. Initializing to zero instead.\n";
154  }
155 }
156 
157 //*******************************************************************************************
158 
160  return new PolynomialFunction(*this);
161 }
162 
163 //*******************************************************************************************
164 
166  return new PolynomialFunction(*this, new_coeffs);
167 }
168 
169 //*******************************************************************************************
170 
172  BasisSet const *home_basis_ptr /*=nullptr*/) {
173  return visitor.visit(*this, home_basis_ptr);
174 }
175 
176 //*******************************************************************************************
177 
179  const FunctionVisitor &visitor,
180  BasisSet const *home_basis_ptr /*=nullptr*/) const {
181  return visitor.visit(*this, home_basis_ptr);
182 }
183 
184 //*******************************************************************************************
185 bool PolynomialFunction::depends_on(const Function *test_func) const {
186  Index sub_ind(0), arg_ind(0), linear_ind(0);
187  for (sub_ind = 0; sub_ind < m_argument.size(); sub_ind++) {
188  arg_ind = m_argument[sub_ind]->find(const_cast<Function *const>(test_func));
189  linear_ind += arg_ind;
190  if (arg_ind < m_argument[sub_ind]->size()) {
191  break;
192  }
193  }
194  if (sub_ind == m_argument.size()) return false;
195 
197  for (; it != it_end; ++it) {
198  if (almost_zero(*it)) continue;
199 
200  if (it.key()[linear_ind]) return true;
201  }
202  return false;
203 }
204 //*******************************************************************************************
206  // Could check to see if arguments are zero. For now, assume this is done at
207  // time of construction
209  for (; it != it_end; ++it) {
210  if (!almost_zero(*it)) return false;
211  }
212  return true;
213 }
214 
215 //*******************************************************************************************
217  m_coeffs.prune_zeros(tol);
218 }
219 
220 //*******************************************************************************************
222  Index np(0);
224  for (; it != it_end; ++it) {
225  if (!almost_zero(*it)) np++;
226  }
227  return np;
228 }
229 
230 //*******************************************************************************************
231 
233  Index t_ind;
234  return leading_coefficient(t_ind);
235 }
236 
237 //*******************************************************************************************
238 
240  index = 0;
242  for (; it != it_end; ++it) {
243  if (!almost_zero(*it)) return *it;
244  index++;
245  }
246  return 0.0;
247 }
248 
249 //*******************************************************************************************
250 
252  Index index = 0;
254  for (; it != it_end; ++it) {
255  if (!almost_zero(*it)) {
256  if (index == i) return *it;
257 
258  index++;
259  }
260  }
261  return 0.0;
262 }
263 
264 //*******************************************************************************************
265 
267  PolyTrie<double> tcoeffs(m_coeffs);
269  m_formula.clear();
270  m_tex_formula.clear();
271  // std::cout << "Making PolynomialFunction Formula:\n";
272  // tcoeffs.print_sparse(std::cout);
273  // std::cout << std::endl;
274  std::stringstream tformula, ttex;
275  Index np;
276  bool is_zero(true);
277  Array<Array<Index> > unique_product;
278  Array<double> prefactor;
279 
280  PolyTrie<double>::const_iterator it(tcoeffs.begin()), it_end(tcoeffs.end());
281  for (; it != it_end; ++it) {
282  if (almost_zero(*it)) continue;
283 
284  unique_product.push_back(it.key());
285  prefactor.push_back(*it);
286  is_zero = false;
287  }
288 
289  // Comment out following block to turn off monomial sorting
290  // Array<Index> iperm;
291  // unique_product.sort(iperm);
292  // prefactor.permute(iperm);
293  // \end monomial sort
294 
295  if (is_zero) {
296  m_formula = "0";
297  m_tex_formula = "0";
298  return;
299  }
300 
301  double func_scale(prefactor[0]);
302  if (!almost_zero(func_scale - 1)) {
303  if (almost_zero(func_scale + 1)) {
304  ttex << '-';
305  } else {
306  ttex << irrational_to_tex_string(func_scale, num_args() * num_args());
307  }
308  }
309 
310  if (unique_product.size() > 1) {
311  tformula << '(';
312  ttex << '(';
313  }
314 
315  for (np = 0; np < unique_product.size(); np++) {
316  if (np > 0 && prefactor[np] > 0.0) {
317  tformula << '+';
318  }
319  if (almost_zero(prefactor[np] + 1)) {
320  tformula << '-';
321  } else if (!almost_zero(prefactor[np] - 1)) {
322  tformula << prefactor[np] << " * ";
323  }
324 
325  if (np > 0 && prefactor[np] / func_scale > 0.0) {
326  ttex << '+';
327  }
328  if (almost_zero(prefactor[np] / func_scale + 1)) {
329  ttex << '-';
330  } else if (!almost_zero(prefactor[np] / func_scale - 1)) {
331  ttex << irrational_to_tex_string(prefactor[np] / func_scale,
332  num_args() * num_args());
333  }
334 
335  // Loop over arguments of unique_product[np]
336  int tot_pow(0);
337  for (Index linear_ind = 0; linear_ind < unique_product[np].size();
338  linear_ind++) {
339  if (!unique_product[np][linear_ind]) continue;
340  if (tot_pow > 0) {
341  tformula << " * ";
342  }
343  tot_pow += unique_product[np][linear_ind];
344 
345  if (unique_product[np][linear_ind] > 1) {
346  tformula << "pow(" << _argument(linear_ind)->formula() << ", "
347  << unique_product[np][linear_ind] << ")";
348  ttex << _argument(linear_ind)->tex_formula() << "^{"
349  << unique_product[np][linear_ind] << "} ";
350  } else {
351  tformula << _argument(linear_ind)->formula();
352  ttex << _argument(linear_ind)->tex_formula();
353  }
354  }
355  if (tot_pow == 0 && almost_zero(std::abs(prefactor[np] / func_scale) - 1)) {
356  tformula << '1';
357  ttex << '1';
358  }
359  }
360 
361  if (unique_product.size() > 1) {
362  tformula << ')';
363  ttex << ')';
364  }
365  m_tex_formula = ttex.str();
366  m_formula = tformula.str();
367  // std::cout << "Formula is " << m_formula << '\n';
368  // std::cout << "TeX Formula is " << m_tex_formula << '\n';
369 }
370 
371 //*******************************************************************************************
372 
373 std::set<Index> PolynomialFunction::dof_IDs() const {
375 
376  if (it == it_end) return {};
377  std::vector<Index> check(m_coeffs.depth(), false);
378  for (; it != it_end; ++it) {
379  if (almost_zero(*it)) continue;
380 
381  for (Index i = 0; i < it.key().size(); i++)
382  check[i] = check[i] || it.key()[i];
383  }
384 
385  std::set<Index> result;
386  Index last = -1;
387  for (Index i = 0; i < check.size(); i++) {
388  if (check[i] && last != m_arg2sub[i]) {
389  last = m_arg2sub[i];
390  std::vector<Index> tres = argument_bases()[last]->dof_IDs();
391  result.insert(tres.begin(), tres.end());
392  }
393  }
394  return result;
395 }
396 
397 //*******************************************************************************************
398 
403 
404  // IMPORTANT: Do
405  // Function::operation_table[OTHER::sclass_ID()][sclass_ID()] = nullptr;
406  // Before
407  // Function::operation_table[sclass_ID()][OTHER::sclass_ID()] =
408  // Whatever;
409 
412  nullptr;
414  new PolyVarOperation();
416  new PolyOccOperation();
417 
418  // BasicPolyVarProduct does not yet exist
419  // Function::inner_prod_table[sclass_ID()][Variable::sclass_ID()]=new
420  // BasicPolyVarProduct();
421 }
422 
423 //*******************************************************************************************
424 
426  return nullptr;
427 }
428 
429 //*******************************************************************************************
430 
431 void PolynomialFunction::scale(double scale_factor) {
432  m_formula.clear();
433  m_tex_formula.clear();
434  refresh_ID();
435  m_coeffs *= scale_factor;
436 }
437 
438 //*******************************************************************************************
439 
441  const ArgumentContainer &new_arg,
442  std::vector<Index> const &compatibility_map) {
443  if (new_arg.size() < compatibility_map.size() ||
444  compatibility_map.size() != argument_bases().size())
445  throw std::runtime_error(
446  "In PolynomialFunction::_set_arguments called with incompatible "
447  "argument size");
448  if (new_arg.empty()) return;
449 
450  std::vector<Index> ind_perm(num_args());
451  std::vector<Index> new_offset;
452  std::vector<Index> old_offset(1, 0);
453 
454  Index new_depth = 0;
455  for (Index i = 0; i < new_arg.size(); i++) {
456  new_offset.push_back(new_depth);
457  new_depth += new_arg[i]->size();
458  }
459 
460  Index old_a = 0;
461  for (Index i = 0; i < m_argument.size(); i++) {
462  Index new_a = new_offset[compatibility_map[i]];
463  for (Index j = 0; j < m_argument[i]->size(); j++) {
464  ind_perm[old_a++] = new_a++;
465  }
466  }
467 
468  PolyTrie<double> new_coeffs(new_depth);
469  Array<Index> new_inds(new_depth, 0);
471  for (; it != it_end; ++it) {
472  for (Index i = 0; i < ind_perm.size(); ++i)
473  new_inds[ind_perm[i]] = it.key()[i];
474  new_coeffs(new_inds) = *it;
475  }
476  m_coeffs.swap(new_coeffs);
477 }
478 
479 //*******************************************************************************************
481  // std::cout << "Applying symmetry operation to coefficients:\n";
482  // m_coeffs.print_sparse(std::cout);
483  // m_coeffs.sort_leaves(ComparePTLeaf::CustomOrder());
484  m_formula.clear();
485  m_tex_formula.clear();
486  refresh_ID();
487  PolyTrie<double> t_trie(m_coeffs.depth());
488  m_coeffs.swap(t_trie);
489 
490  PolyTrie<double>::const_iterator it(t_trie.begin()), it_end(t_trie.end());
491  for (; it != it_end; ++it) transform_monomial_and_add(*it, it.key(), op);
492 
493  // std::cout << "\n\n And result is:\n";
494  // m_coeffs.print_sparse(std::cout);
495  return this;
496 }
497 
498 //*******************************************************************************************
500  const SymOp &op, const std::vector<bool> &transform_flags) {
501  // std::cout << "Applying symmetry operation to coefficients:\n";
502  // m_coeffs.print_sparse(std::cout);
503  // m_coeffs.sort_leaves(ComparePTLeaf::CustomOrder());
504  m_formula.clear();
505  m_tex_formula.clear();
506  refresh_ID();
507  PolyTrie<double> t_trie(m_coeffs.depth());
508  m_coeffs.swap(t_trie);
509 
510  PolyTrie<double>::const_iterator it(t_trie.begin()), it_end(t_trie.end());
511  for (; it != it_end; ++it)
512  transform_monomial_and_add_new(*it, it.key(), op, transform_flags);
513 
514  // std::cout << "\n\n And result is:\n";
515  // m_coeffs.print_sparse(std::cout);
516  return this;
517 }
518 
519 //*******************************************************************************************
521  double prefactor, const Array<Index> &ind, const SymOp &op) {
522  assert(ind.size() == m_coeffs.depth() &&
523  "\'ind\' Array is not compatible with PolynomialFunction in "
524  "PolynomialFunction::transform_monomial_and_add");
525 
527  Array<Array<Array<Index> > > exp_counter(m_argument.size(),
528  Array<Array<Index> >());
529  Array<Array<Array<Index> > > nz_terms(m_argument.size(),
530  Array<Array<Index> >());
531  Array<Array<Array<double> > > nz_coeffs(m_argument.size(),
532  Array<Array<double> >());
533 
534  // nz_terms and nz_coeffs keep track of how each individual variable
535  // transforms into a linear combination of vectors exp_counter will be used to
536  // expand the resulting multinomial expression by counting over the
537  // multinomial terms for example, if x^2 transforms to (x-y)^2/2, the end
538  // result will be a PolynomialFunction that encodes x^2/2-x*y+y^2/2
539  Index linear_offset(0);
540  for (Index ns = 0; ns < m_argument.size(); ns++) {
541  for (Index na1 = 0; na1 < m_argument[ns]->size(); na1++) {
542  nz_terms[ns].push_back(Array<Index>());
543  exp_counter[ns].push_back(Array<Index>());
544  nz_coeffs[ns].push_back(Array<double>());
545 
546  if (!ind[linear_offset + na1]) continue;
547 
548  for (Index na2 = 0; na2 < m_argument[ns]->size(); na2++) {
549  if (rep_mats[ns] && !almost_zero((*rep_mats[ns])(na2, na1))) {
550  nz_terms[ns][na1].push_back(linear_offset + na2);
551  exp_counter[ns][na1].push_back(0);
552  nz_coeffs[ns][na1].push_back((*rep_mats[ns])(na2, na1));
553  } else if (!rep_mats[ns] &&
554  na1 == na2) { // assume identity if no symrep exists
555  nz_terms[ns][na1].push_back(linear_offset + na2);
556  exp_counter[ns][na1].push_back(0);
557  nz_coeffs[ns][na1].push_back(1.0);
558  }
559  }
560  exp_counter[ns][na1][0] = ind[linear_offset + na1];
561  }
562  linear_offset += m_argument[ns]->size();
563  }
564  /*
565  for(int ns=0; ns<exp_counter.size(); ns++){
566  for(int na1=0; na1<exp_counter[ns].size(); na1++){
567  for(int na2=0; na2<exp_counter[ns][na1].size(); na2++){
568  //std::cout << "exp_counter[" << ns << "][" << na1 << "][" << na2 << "] = "
569  << exp_counter[ns][na1][na2] << '\n';
570  //std::cout << "nz_terms[" << ns << "][" << na1 << "][" << na2 << "] = " <<
571  nz_terms[ns][na1][na2] << '\n';
572  //std::cout << "nz_coeffs[" << ns << "][" << na1 << "][" << na2 << "] = " <<
573  nz_coeffs[ns][na1][na2] << '\n';
574  }
575  }
576  }
577  */
578  Array<Index> out_ind(ind.size(), 0);
579  double out_coeff;
580  Index ns, na1, na2;
581  bool cflag(true);
582  while (cflag) {
583  // std::cout << "Still inside while loop and exp_counter is " << exp_counter
584  // << '\n';
585  out_coeff = prefactor;
586  out_ind.resize(ind.size(), 0);
587  for (ns = 0; ns < exp_counter.size(); ns++) {
588  for (na1 = 0; na1 < exp_counter[ns].size(); na1++) {
589  for (na2 = 0; na2 < exp_counter[ns][na1].size(); na2++) {
590  out_ind[nz_terms[ns][na1][na2]] += exp_counter[ns][na1][na2];
591  out_coeff *= pow(nz_coeffs[ns][na1][na2], exp_counter[ns][na1][na2]);
592  }
593  out_coeff *= multinomial_coeff(exp_counter[ns][na1]);
594  }
595  }
596  if (out_ind.sum() != ind.sum()) {
597  std::cerr << "WARNING: Starting from " << ind
598  << " a portion of the result is at " << out_ind << '\n';
599  }
600  /*
601  if(ind != out_ind || !almost_equal(prefactor, out_coeff)) {
602  //std::cout << "Monomial term: " << ind << " : " << prefactor << "\n";
603  //std::cout << "Transforms to: " << out_ind << " : " << out_coeff << "
604  <--"; if(ind != out_ind || !almost_zero(prefactor + out_coeff))
605  //std::cout << "******";
606  //std::cout << "\n";
607  }*/
608 
609  // this is where the coefficient gets transforemd
610  m_coeffs.at(out_ind) += out_coeff;
611 
612  // Increment exponent counters
613  for (ns = 0; ns < exp_counter.size(); ns++) {
614  for (na1 = 0; na1 < exp_counter[ns].size(); na1++) {
615  if (exp_counter[ns][na1].size() <= 1) continue;
616 
617  for (na2 = 0; na2 < exp_counter[ns][na1].size() - 1; na2++) {
618  if (exp_counter[ns][na1][na2] == 0) continue;
619 
620  exp_counter[ns][na1][na2]--;
621  exp_counter[ns][na1][na2 + 1]++;
622  if (na2 > 0) {
623  exp_counter[ns][na1][0] = exp_counter[ns][na1][na2];
624  exp_counter[ns][na1][na2] = 0;
625  }
626  break;
627  }
628  if (na2 == exp_counter[ns][na1].size() - 1) {
629  exp_counter[ns][na1][0] = exp_counter[ns][na1][na2];
630  exp_counter[ns][na1][na2] = 0;
631  } else {
632  break;
633  }
634  }
635  if (na1 < exp_counter[ns].size()) break;
636  }
637  //\done incrementing exponent counters
638 
639  cflag = ns < exp_counter.size();
640  }
641 
642  // std::cout << "Transformed PolyTrie: \n";
643  // m_coeffs.print_sparse(std::cout);
644  // std::cout << '\n';
645  return this;
646 }
647 
648 //*******************************************************************************************
649 // Improved by incorporating MultiCounter and IsoCounter-- not yet tested
650 
652  double prefactor, const Array<Index> &ind, const SymOp &op,
653  const std::vector<bool> &transform_flags) {
654  assert(ind.size() == m_coeffs.depth() &&
655  "\'ind\' Array is not compatible with PolynomialFunction in "
656  "PolynomialFunction::transform_monomial_and_add");
657  typedef IsoCounter<Array<Index> > TermCounter;
658  typedef MultiCounter<TermCounter> SubspaceCounter;
659  typedef MultiCounter<SubspaceCounter> ExpCounter;
660 
661  assert(transform_flags.size() == m_argument.size());
663  for (Index i = 0; i < transform_flags.size(); i++) {
664  if (!transform_flags[i]) rep_mats[i] = nullptr;
665  }
666  ExpCounter exp_counter;
667  Array<Array<Array<Index> > > nz_terms(m_argument.size(),
668  Array<Array<Index> >());
669  Array<Array<Array<double> > > nz_coeffs(m_argument.size(),
670  Array<Array<double> >());
671 
672  // nz_terms and nz_coeffs keep track of how each individual variable
673  // transforms into a linear combination of vectors exp_counter will be used to
674  // expand the resulting multinomial expression by counting over the
675  // multinomial terms for example, if x^2 transforms to (x-y)^2/2, the end
676  // result will be a genericpolynomialfunction that encodes x^2/2-x*y+y^2/2
677 
678  // nz_terms and nz_coeffs is basically a sparse depiction of the symrep
679  // matrices. Instead of constructing them here, they should probably be
680  // stored in the symreps themselves and accessed via lazy evaluation.
681  Index linear_offset(0);
682  for (Index ns = 0; ns < m_argument.size(); ns++) {
683  exp_counter.push_back(SubspaceCounter());
684  for (Index na1 = 0; na1 < m_argument[ns]->size(); na1++) {
685  nz_terms[ns].push_back(Array<Index>());
686  nz_coeffs[ns].push_back(Array<double>());
687 
688  int pow_to_distribute(ind[linear_offset + na1]);
689 
690  if (pow_to_distribute == 0) {
691  exp_counter[ns].push_back(TermCounter());
692  continue;
693  }
694 
695  for (Index na2 = 0; na2 < m_argument[ns]->size(); na2++) {
696  if (rep_mats[ns] && !almost_zero((*rep_mats[ns])(na2, na1))) {
697  // nz_flag = true; // indicate that this variable can transform into
698  // something else
699  nz_terms[ns][na1].push_back(linear_offset + na2);
700  nz_coeffs[ns][na1].push_back((*rep_mats[ns])(na2, na1));
701  } else if (!rep_mats[ns] &&
702  na1 == na2) { // assume identity if no symrep exists
703  nz_terms[ns][na1].push_back(linear_offset + na2);
704  nz_coeffs[ns][na1].push_back(1.0);
705  }
706  }
707  exp_counter[ns].push_back(
708  TermCounter(Array<Index>(nz_terms[ns][na1].size(), 0),
709  Array<Index>(nz_terms[ns][na1].size(), pow_to_distribute),
710  1, pow_to_distribute));
711  }
712  linear_offset += m_argument[ns]->size();
713  }
714  /*
715  for(Index ns=0; ns<exp_counter.size(); ns++){
716  for(Index na1=0; na1<exp_counter[ns].size(); na1++){
717  for(Index na2=0; na2<exp_counter[ns][na1].size(); na2++){
718  //std::cout << "exp_counter[" << ns << "][" << na1 << "][" << na2 << "] = "
719  << exp_counter[ns][na1][na2] << '\n';
720  //std::cout << "nz_terms[" << ns << "][" << na1 << "][" << na2 << "] = " <<
721  nz_terms[ns][na1][na2] << '\n';
722  //std::cout << "nz_coeffs[" << ns << "][" << na1 << "][" << na2 << "] = " <<
723  nz_coeffs[ns][na1][na2] << '\n';
724  }
725  }
726  }
727  */
728  Array<Index> out_ind(ind.size(), 0);
729  double out_coeff;
730  Index ns, na1, na2;
731 
732  while (exp_counter.valid()) {
733  // std::cout << "Still inside while loop and exp_counter is " << exp_counter
734  // << '\n';
735  out_coeff = prefactor;
736  out_ind.resize(ind.size(), 0);
737  for (ns = 0; ns < exp_counter.size(); ns++) {
738  for (na1 = 0; na1 < exp_counter[ns].size(); na1++) {
739  for (na2 = 0; na2 < exp_counter[ns][na1].size(); na2++) {
740  out_ind[nz_terms[ns][na1][na2]] += exp_counter[ns][na1][na2];
741  out_coeff *= pow(nz_coeffs[ns][na1][na2], exp_counter[ns][na1][na2]);
742  }
743  out_coeff *= multinomial_coeff(exp_counter[ns][na1]());
744  }
745  }
746  m_coeffs.at(out_ind) += out_coeff;
747 
748  exp_counter++;
749  }
750  return this;
751 }
752 
753 //*******************************************************************************************
754 
756  double t_sum(0.0);
757  double t_prod;
758  Array<double> arg_states(num_args());
759 
760  for (Index i = 0; i < num_args(); i++)
761  arg_states[i] = _argument(i)->remote_eval();
762 
764  for (; it != it_end; ++it) {
765  t_prod = *it;
766 
767  for (Index i = 0; i < it.key().size(); i++) {
768  t_prod *= pow(arg_states[i], it.key()[i]);
769  }
770 
771  t_sum += t_prod;
772  }
773 
774  return t_sum;
775 }
776 
777 //*******************************************************************************************
778 
780  double t_sum(0.0);
781  double t_prod;
782 
783  // Array<bool> arg_calc(m_argument.size(), false);
784  Array<double> arg_states(num_args());
785  Array<double> arg_derivs(num_args());
786 
787  for (Index i = 0; i < num_args(); i++) {
788  arg_states[i] = _argument(i)->remote_eval();
789  arg_derivs[i] = _argument(i)->remote_deval(dvar);
790  }
791 
792  Index const *k_begin, *k_end;
793 
795  for (; it != it_end; ++it) {
796  if (almost_zero(*it)) continue;
797  k_begin = it.key().begin();
798  k_end = it.key().end();
799 
800  // calculate monomial derivative
801  for (Index const *i = k_begin; i < k_end; i++) {
802  if (*i == 0) continue;
803  t_prod = (*it) * arg_derivs[i - k_begin];
804 
805  for (Index const *j = k_begin; j < k_end; j++) {
806  for (Index p = 0; p < (*j) - int(i == j); p++)
807  t_prod *= arg_states[j - k_begin];
808  }
809 
810  t_sum += t_prod;
811  }
812  }
813 
814  return t_sum;
815 }
816 
817 //*******************************************************************************************
818 
820  double t_sum(0.0);
821  double t_prod;
822 
824  for (; it != it_end; ++it) {
825  t_prod = *it;
826 
827  for (Index i = 0; i < it.key().size(); i++) {
828  t_prod *= pow(_arg_eval_cache(i), it.key()[i]);
829  }
830 
831  t_sum += t_prod;
832  }
833 
834  return t_sum;
835 }
836 
837 //*******************************************************************************************
838 
840  double t_sum(0.0);
841  double t_prod;
842 
843  // Array<bool> arg_calc(m_argument.size(), false);
844  // Array<double> arg_states(num_args());
845  // Array<double> arg_derivs(num_args());
846 
847  // for(Index i = 0; i < num_args(); i++) {
848  // arg_states[i] = _argument(i)->remote_eval();
849  // arg_derivs[i] = _argument(i)->remote_deval(dvar);
850  //}
851 
852  Index const *k_begin, *k_end;
853 
855  for (; it != it_end; ++it) {
856  if (almost_zero(*it)) continue;
857  k_begin = it.key().begin();
858  k_end = it.key().end();
859 
860  // calculate monomial derivative
861  for (Index const *i = k_begin; i < k_end; i++) {
862  if (*i == 0) continue;
863  t_prod = (*it) * _arg_deval_cache(i - k_begin);
864 
865  for (Index const *j = k_begin; j < k_end; j++) {
866  for (Index p = 0; p < (*j) - int(i == j); p++)
867  t_prod *= _arg_eval_cache(j - k_begin);
868  }
869 
870  t_sum += t_prod;
871  }
872  }
873 
874  return t_sum;
875 }
876 
877 //*******************************************************************************************
878 
880  const PolynomialFunction &RHS) const {
881  // This assumes that all the arguments of *this and RHS are the same and
882  // mutually orthogonal This is not generally the case, but it is unclear how
883  // to resolve this in the case of the Frobenius product (unlike an inner
884  // product based on integration over some domain).
885  double prod_result(0.0), tprod(0.0);
886  Array<Index> texp;
887  // std::cout << "Scalar product of depth " << m_coeffs.depth() << " and depth
888  // " << RHS.m_coeffs.depth() << "\n"; std::cout << " arg_size "
889  // << num_args() << " and arg_size " << RHS.num_args() << "\n";
891  it_end(RHS.m_coeffs.end());
892  std::vector<std::vector<std::set<Index> > > indep;
893  indep.reserve(m_argument.size());
894  for (Index i = 0; i < m_argument.size(); i++)
895  indep.push_back(m_argument[i]->independent_sub_bases());
896 
897  for (; it != it_end; ++it) {
898  tprod = (*it) * m_coeffs.get(it.key());
899  if (almost_zero(tprod, TOL * TOL)) continue;
900  Index l = 0;
901  for (Index i = 0; i < indep.size(); i++) {
902  for (auto const &indep_set : indep[i]) {
903  texp.clear();
904  for (Index const &func_ind : indep_set) {
905  texp.push_back(it.key()[l + func_ind]);
906  }
907  tprod /= multinomial_coeff(texp);
908  }
909  l += m_argument[i]->size();
910  }
911  prod_result += tprod;
912  }
913  return prod_result;
914 }
915 
916 //*******************************************************************************************
917 
919  const PolynomialFunction &RHS, double edge_length) const {
920  // This assumes that all the arguments of *this and RHS are the same and
921  // mutually orthogonal This is not generally the case, and perhaps we should
922  // add a check
923 
924  // returns integral of (*this) x RHS using limits -edge_length to +edge_length
925  // (a box of specified edge_length centered at origin) divided by volume of
926  // box (so that '1' is always normalized)
927 
928  double tprod(0), tintegral(0);
929  int texp;
930  // volume of the box
931  double tvol(pow(edge_length, RHS.num_args()));
932 
933  if (m_coeffs.depth() != RHS.m_coeffs.depth()) {
934  std::cerr
935  << "WARNING!!! Attempting to get scalar_product between incompatible "
936  "PolynomialFunctions. Assuming that they are orthogonal...\n";
937  return 0;
938  }
939 
941  RHS_end(RHS.m_coeffs.end());
943  LHS_end(m_coeffs.end());
944  if (RHS_it == RHS_end || LHS_it == LHS_end) return 0;
945 
946  for (; RHS_it != RHS_end; ++RHS_it) {
947  if (almost_zero(*RHS_it)) continue;
948 
949  for (LHS_it = m_coeffs.begin(); LHS_it != LHS_end; ++LHS_it) {
950  tintegral = (*RHS_it) * (*LHS_it);
951  for (Index i = 0; i < LHS_it.key().size(); i++) {
952  texp = LHS_it.key()[i] + RHS_it.key()[i];
953 
954  // Check to see if texp is odd, in which case integral is zero
955  if (texp != 2 * (texp / 2)) {
956  tintegral = 0;
957  break;
958  }
959 
960  tintegral *= 2 * pow(edge_length / 2, texp + 1) / double(texp + 1);
961  }
962  tprod += tintegral;
963  }
964  }
965  return tprod / tvol;
966 }
967 
968 //*******************************************************************************************
969 
971  m_coeffs -= RHS->m_coeffs;
972  return this;
973 }
974 
975 //*******************************************************************************************
977  // Function::compare() checks that arguments are equivalent.
978 
979  // std::cout << " In compare ... " << std::endl;
980  // std::cout << " LHS " << std::endl;
981  // m_coeffs.print_sparse(std::cout);
982  // std::cout << " RHS " << std::endl;
983  //(RHS->m_coeffs).print_sparse(std::cout);
984  return m_coeffs.compare(RHS->m_coeffs, TOL);
985 }
986 //*******************************************************************************************
988 //*******************************************************************************************
990  m_coeffs += RHS->m_coeffs;
991  return this;
992 }
993 
994 //*******************************************************************************************
996  int dependency_layer) {
997  std::vector<bool> transform_flags(m_argument.size());
998  int tdep;
999  for (Index i = 0; i < m_argument.size(); i++) {
1000  tdep = (m_argument[i]->dependency_layer()) + 1;
1001  transform_flags[i] = (tdep == dependency_layer);
1002  if (dependency_layer < tdep) m_argument[i]->apply_sym(op, dependency_layer);
1003  }
1004  return _apply_sym(op, transform_flags);
1005 }
1006 
1007 //*******************************************************************************************
1008 
1010  Index i = 0;
1011  for (i = 0; i < num_args(); i++) {
1012  if (_argument(i)->compare(RHS)) break;
1013  }
1014  if (i == num_args()) {
1015  return nullptr;
1016  }
1017 
1018  PolynomialFunction *tpoly(
1020 
1021  Array<Index> new_key;
1022 
1024  for (; it != it_end; ++it) {
1025  if (!it.key()[i]) continue;
1026 
1027  new_key = it.key();
1028  new_key[i]--;
1029 
1030  (tpoly->m_coeffs).set(new_key, *it);
1031  }
1032 
1033  return tpoly;
1034 }
1035 
1036 //*******************************************************************************************
1037 
1039  Index i = 0;
1040  for (i = 0; i < num_args(); i++) {
1041  if (_argument(i)->compare(RHS)) break;
1042  }
1043  if (i == num_args()) {
1044  return copy();
1045  }
1046 
1047  PolynomialFunction *tpoly(
1049 
1051  for (; it != it_end; ++it) {
1052  if (it.key()[i]) continue;
1053 
1054  (tpoly->m_coeffs).set(it.key(), *it);
1055  }
1056 
1057  return tpoly;
1058 }
1059 
1060 //*******************************************************************************************
1061 
1063  Index i = 0;
1064  for (i = 0; i < num_args(); i++) {
1065  if (_argument(i)->compare(RHS)) break;
1066  }
1067  if (i == num_args()) {
1068  return nullptr;
1069  }
1070 
1071  PolynomialFunction *tpoly(
1073 
1074  Array<Index> new_key;
1076  for (; it != it_end; ++it) {
1077  if (!it.key()[i]) continue;
1078 
1079  new_key = it.key();
1080  new_key[i]--;
1081 
1082  (tpoly->m_coeffs).set(new_key, *it);
1083  }
1084 
1085  return tpoly;
1086 }
1087 
1088 //*******************************************************************************************
1089 
1091  const OccupantFunction *RHS) const {
1092  Index i = 0;
1093  for (i = 0; i < num_args(); i++) {
1094  if (_argument(i)->compare(RHS)) break;
1095  }
1096  if (i == num_args()) {
1097  return copy();
1098  }
1099 
1100  PolynomialFunction *tpoly(
1102 
1104  for (; it != it_end; ++it) {
1105  if (it.key()[i]) continue;
1106 
1107  (tpoly->m_coeffs).set(it.key(), *it);
1108  }
1109 
1110  return tpoly;
1111 }
1112 
1113 //*******************************************************************************************
1114 
1116  Function const *RHS) const {
1117  PolynomialFunction const *PLHS(static_cast<PolynomialFunction const *>(LHS)),
1118  *PRHS(static_cast<PolynomialFunction const *>(RHS));
1119 
1120  return PLHS->frobenius_scalar_prod(*PRHS);
1121 }
1122 
1123 //*******************************************************************************************
1125  Function const *RHS) const {
1126  PolynomialFunction const *PLHS(static_cast<PolynomialFunction const *>(LHS));
1127  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1128  return PLHS->compare(PRHS);
1129 }
1130 
1131 //*******************************************************************************************
1133  Function const *RHS) const {
1134  PolynomialFunction const *PLHS(static_cast<PolynomialFunction const *>(LHS));
1135  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1136 
1137  return new PolynomialFunction(*PLHS, *PRHS);
1138 }
1139 
1140 //*******************************************************************************************
1141 
1143  Function const *RHS) const {
1144  std::cerr << "WARNING: In-place multiplication of one PolynomialFunction "
1145  "with another is not yet implemented!!\n"
1146  << " Exiting...\n";
1147  exit(1);
1148  return nullptr;
1149 }
1150 
1151 //*******************************************************************************************
1153  Function const *RHS) const {
1154  PolynomialFunction *PLHS_copy(static_cast<PolynomialFunction *>(LHS->copy()));
1155  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1156  PLHS_copy->minus_equals(PRHS);
1157 
1158  PLHS_copy->refresh_ID();
1159 
1160  return PLHS_copy;
1161 }
1162 
1163 //*******************************************************************************************
1165  Function const *RHS) const {
1166  PolynomialFunction *PLHS(static_cast<PolynomialFunction *>(LHS));
1167  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1168  PLHS->minus_equals(PRHS);
1169 
1170  PLHS->refresh_ID();
1171 
1172  return PLHS;
1173 }
1174 
1175 //*******************************************************************************************
1177  Function const *RHS) const {
1178  PolynomialFunction *PLHS_copy(static_cast<PolynomialFunction *>(LHS->copy()));
1179  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1180  PLHS_copy->plus_equals(PRHS);
1181 
1182  PLHS_copy->refresh_ID();
1183 
1184  return PLHS_copy;
1185 }
1186 
1187 //*******************************************************************************************
1189  PolynomialFunction *PLHS(static_cast<PolynomialFunction *>(LHS));
1190  PolynomialFunction const *PRHS(static_cast<PolynomialFunction const *>(RHS));
1191  PLHS->plus_equals(PRHS);
1192 
1193  PLHS->refresh_ID();
1194 
1195  return PLHS;
1196 }
1197 
1198 //*******************************************************************************************
1199 
1201  Function const *RHS) const {
1202  return static_cast<PolynomialFunction const *>(LHS)->poly_quotient(
1203  static_cast<Variable const *>(RHS));
1204 }
1205 
1206 //*******************************************************************************************
1207 
1209  Function const *RHS) const {
1210  return static_cast<PolynomialFunction const *>(LHS)->poly_remainder(
1211  static_cast<Variable const *>(RHS));
1212 }
1213 
1214 //*******************************************************************************************
1215 
1217  Function const *RHS) const {
1218  return static_cast<PolynomialFunction const *>(LHS)->poly_quotient(
1219  static_cast<OccupantFunction const *>(RHS));
1220 }
1221 
1222 //*******************************************************************************************
1223 
1225  Function const *RHS) const {
1226  return static_cast<PolynomialFunction const *>(LHS)->poly_remainder(
1227  static_cast<OccupantFunction const *>(RHS));
1228 }
1229 
1230 } // namespace CASM
Index size() const
Definition: Array.hh:131
void clear()
Definition: Array.hh:182
double dot(Function const *LHS, Function const *RHS) const
std::string formula() const
std::string m_tex_formula
virtual Function * copy() const =0
ReturnArray< SymGroupRepID > _sub_sym_reps() const
virtual double remote_eval() const =0
ArgumentContainer m_argument
std::string m_formula
bool compare(Function const *RHS) const
double _arg_eval_cache(Index i) const
std::vector< std::shared_ptr< BasisSet > > ArgumentContainer
static Array< Array< InnerProduct * > > inner_prod_table
const ArgumentContainer & argument_bases() const
Function const * _argument(Index i) const
virtual double remote_deval(const DoF::RemoteHandle &dvar) const =0
Array< Index > m_arg2fun
Index num_args() const
double _arg_deval_cache(Index i) const
std::string tex_formula() const
static Array< Array< FunctionOperation * > > operation_table
Array< Index > m_arg2sub
virtual bool visit(Variable const &host, BasisSet const *bset_ptr) const
A IsoCounter allows looping over many incrementing variables in one loop.
Definition: IsoCounter.hh:96
Function * poly_quotient(Function const *LHS, Function const *RHS) const
Function * poly_remainder(Function const *LHS, Function const *RHS) const
Function * subtract(Function const *LHS, Function const *RHS) const
Function * add(Function const *LHS, Function const *RHS) const
Function * add_to(Function *LHS, Function const *RHS) const
Function * multiply(Function const *LHS, Function const *RHS) const
bool compare(Function const *LHS, Function const *RHS) const
Function * subtract_from(Function *LHS, Function const *RHS) const
Function * multiply_by(Function *LHS, Function const *RHS) const
iterator end()
Definition: PolyTrie.hh:241
Index depth() const
Definition: PolyTrie.hh:213
iterator begin()
Definition: PolyTrie.hh:238
Function * poly_remainder(Function const *LHS, Function const *RHS) const
Function * poly_quotient(Function const *LHS, Function const *RHS) const
void scale(double scale_factor) override
bool depends_on(const Function *test_func) const override
void make_formula() const override
double remote_deval(const DoF::RemoteHandle &dvar) const override
SparseTensor< double > const * get_coeffs() const override
std::set< Index > dof_IDs() const override
double cache_deval(const DoF::RemoteHandle &dvar) const override
Function * copy() const override
void _set_arguments(const ArgumentContainer &new_arg, std::vector< Index > const &compatibility_map) override
double frobenius_scalar_prod(const PolynomialFunction &RHS) const
Index num_terms() const override
Function * apply_sym_coeffs(const SymOp &op, int dependency_layer) override
double get_coefficient(Index i) const override
Function * poly_quotient(const Variable *RHS) const
double remote_eval() const override
double leading_coefficient() const override
double cache_eval() const override
double box_integral_scalar_prod(const PolynomialFunction &RHS, double edge_length) const
Function * _apply_sym(const SymOp &op) override
Function * transform_monomial_and_add(double prefactor, const Array< Index > &ind, const SymOp &op)
Function * poly_remainder(const Variable *RHS) const
Function * plus_equals(const PolynomialFunction *RHS)
bool compare(const PolynomialFunction *RHS) const
void small_to_zero(double tol=TOL) override
Function * minus_equals(const PolynomialFunction *RHS)
Function * transform_monomial_and_add_new(double prefactor, const Array< Index > &ind, const SymOp &op, const std::vector< bool > &transform_flags)
bool _accept(const FunctionVisitor &visitor, BasisSet const *home_basis_ptr=NULL) override
bool is_zero() const override
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
Array< Eigen::MatrixXd const * > get_matrix_reps(Array< SymGroupRepID > _rep_IDs) const
static int sclass_ID()
Definition: Variable.hh:81
T sum() const
Definition: Array.hh:552
void resize(Index new_N)
Definition: Array.hh:390
void push_back(const T &toPush)
Definition: Array.hh:431
Array & append(const Array &new_tail)
Definition: Array.hh:808
void swap(PolyTrie< T > &other)
Efficient swap of this PolyTrie with another.
Definition: PolyTrie.hh:624
bool prune_zeros(double tol=PTNode< T >::PT_TOL())
Definition: PolyTrie.hh:667
T get(const Array< Index > &ind) const
get() provides constant access does not change trie structure
Definition: PolyTrie.hh:503
void redefine(Index new_depth)
Clears all leaves and resets depth.
Definition: PolyTrie.hh:616
bool compare(const PolyTrie< T > &RHS, double tol=2 *PTNode< T >::PT_TOL()) const
Definition: PolyTrie.hh:747
void sort_leaves(const CompareType &compare)
Definition: PolyTrie.hh:774
T & at(const Array< Index > &ind)
Definition: PolyTrie.hh:545
bool check(const Lattice &lat)
Main CASM namespace.
Definition: APICommand.hh:8
const double TOL
Definition: definitions.hh:30
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
std::string irrational_to_tex_string(double val, int lim, int max_pow=2)
Definition: CASM_math.cc:199
IntType multinomial_coeff(const Array< IntType > &exponents)
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
ProjectSettings & set
Definition: settings.cc:137