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