19 for(i = 0; i < _args.size(); i++) {
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";
26 if(!_args[i]->size()) {
27 std::cerr <<
"WARNING: In PolynomialFunction constructor, initial arguments are ill-defined. Continuing..\n";
38 :
Function(_args), m_coeffs(_coeffs) {
41 for(i = 0; i < _args.size(); i++) {
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";
48 if(!_args[i]->size()) {
49 std::cerr <<
"WARNING: In PolynomialFunction constructor, initial arguments are ill-defined. Continuing..\n";
55 std::cerr <<
"CRITICAL ERROR: PolynomialFunction initialized with coefficients that are incompatible with its argument list.\n"
77 bool add_subspace(
true);
79 for(i = 0; i < LHS.
m_argument.size() && add_subspace; i++) {
90 for(i = 0; i < RHS.
m_argument[j]->size(); i++) {
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];
110 for(; RHS_it != RHS_end; ++RHS_it) {
111 t_coeff = (*RHS_it) * (*LHS_it);
116 for(i = 0; i < RHS_it.key().size(); i++) {
117 tot_ind[RHS_ind[i]] += RHS_it.key()[i];
128 Function(RHS), m_coeffs(RHS.m_coeffs) {
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";
157 return visitor.
visit(*
this, home_basis_ptr);
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;
174 for(; it != it_end; ++it) {
178 if(it.key()[linear_ind])
188 for(; it != it_end; ++it) {
204 for(; it != it_end; ++it) {
223 for(; it != it_end; ++it) {
236 for(; it != it_end; ++it) {
257 std::stringstream tformula, ttex;
264 for(; it != it_end; ++it) {
286 double func_scale(prefactor[0]);
296 if(unique_product.
size() > 1) {
301 for(np = 0; np < unique_product.
size(); np++) {
303 if(np > 0 && prefactor[np] > 0.0) {
310 tformula << prefactor[np] <<
'*';
313 if(np > 0 && prefactor[np] / func_scale > 0.0) {
319 else if(!
almost_zero(prefactor[np] / func_scale - 1)) {
326 for(
Index linear_ind = 0; linear_ind < unique_product[np].
size(); linear_ind++) {
327 if(!unique_product[np][linear_ind])
continue;
331 tot_pow += unique_product[np][linear_ind];
333 if(unique_product[np][linear_ind] > 1) {
334 tformula <<
"pow(" <<
_argument(linear_ind)->
formula() <<
", " << unique_product[np][linear_ind] <<
")";
342 if(tot_pow == 0 &&
almost_zero(std::abs(prefactor[np] / func_scale) - 1)) {
349 if(unique_product.
size() > 1) {
406 for(; it != it_end; ++it)
426 for(; it != it_end; ++it)
436 assert(ind.
size() ==
m_coeffs.
depth() &&
"\'ind\' Array is not compatible with PolynomialFunction in PolynomialFunction::transform_monomial_and_add");
449 Index linear_offset(0);
456 if(!ind[linear_offset + na1])
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));
465 else if(!rep_mats[ns] && na1 == na2) {
466 nz_terms[ns][na1].
push_back(linear_offset + na2);
467 exp_counter[ns][na1].push_back(0);
471 exp_counter[ns][na1][0] = ind[linear_offset + na1];
492 out_coeff = prefactor;
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]);
503 if(out_ind.sum() != ind.
sum()) {
504 std::cerr <<
"WARNING: Starting from " << ind <<
" a portion of the result is at " << out_ind <<
'\n';
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)
524 for(na2 = 0; na2 < exp_counter[ns][na1].size() - 1; na2++) {
525 if(exp_counter[ns][na1][na2] == 0)
528 exp_counter[ns][na1][na2]--;
529 exp_counter[ns][na1][na2 + 1]++;
531 exp_counter[ns][na1][0] = exp_counter[ns][na1][na2];
532 exp_counter[ns][na1][na2] = 0;
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;
544 if(na1 < exp_counter[ns].size())
549 cflag = ns < exp_counter.
size();
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");
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;
576 ExpCounter exp_counter;
589 Index linear_offset(0);
591 exp_counter.push_back(SubspaceCounter());
596 int pow_to_distribute(ind[linear_offset + na1]);
598 if(pow_to_distribute == 0) {
599 exp_counter[ns].push_back(TermCounter());
605 if(rep_mats[ns] && !
almost_zero((*rep_mats[ns])(na2, na1))) {
607 nz_terms[ns][na1].
push_back(linear_offset + na2);
608 nz_coeffs[ns][na1].
push_back((*rep_mats[ns])(na2, na1));
610 else if(!rep_mats[ns] && na1 == na2) {
611 nz_terms[ns][na1].
push_back(linear_offset + na2);
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));
636 while(exp_counter.valid()) {
638 out_coeff = prefactor;
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]);
667 for(; it != it_end; ++it) {
670 for(
Index i = 0; i < it.key().size(); i++) {
671 t_prod *= pow(arg_states[i], it.key()[i]);
695 Index const *k_begin, *k_end;
698 for(; it != it_end; ++it) {
701 k_begin = it.key().
begin();
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];
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];
728 for(; it != it_end; ++it) {
731 for(
Index i = 0; i < it.key().size(); i++) {
756 Index const *k_begin, *k_end;
759 for(; it != it_end; ++it) {
762 k_begin = it.key().
begin();
766 for(
Index const *i = k_begin; i < k_end; i++) {
767 if(*i == 0)
continue;
770 for(
Index const *j = k_begin; j < k_end; j++) {
771 for(
Index p = 0; p < (*j) - int(i == j); p++)
786 std::cerr <<
"WARNING: Evalaution error in PolynomialFunction::eval(). Argument list has\n"
787 <<
" incompatible number of variables for evaluation.\n";
802 std::cerr <<
"WARNING: Evalaution error in PolynomialFunction::eval(). Argument list has\n"
803 <<
" incompatible number of variables for evaluation.\n";
820 std::cerr <<
"WARNING: Evalaution error in PolynomialFunction::eval(). Argument list has\n"
821 <<
" incompatible number of variables for evaluation.\n";
829 for(; it != it_end; ++it) {
832 for(
Index i = 0; i < it.key().size(); i++) {
833 t_prod *= pow(arg_states[i], it.key()[i]);
848 double prod_result(0.0), tprod(0.0);
853 std::vector<std::vector<std::set<Index> > > indep;
858 for(; it != it_end; ++it) {
863 for(
Index i = 0; i < indep.
size(); i++) {
864 for(
auto const &indep_set : indep[i]) {
866 for(
Index const &func_ind : indep_set) {
873 prod_result += tprod;
890 double tprod(0), tintegral(0);
893 double tvol(pow(edge_length, RHS.
num_args()));
896 std::cerr <<
"WARNING!!! Attempting to get scalar_product between incompatible PolynomialFunctions. Assuming that they are orthogonal...\n";
902 if(RHS_it == RHS_end || LHS_it == LHS_end)
return 0;
904 for(; RHS_it != RHS_end; ++RHS_it) {
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];
914 if(texp != 2 * (texp / 2)) {
919 tintegral *= 2 * pow(edge_length / 2, texp + 1) / double(texp + 1);
959 std::vector<bool> transform_flags(
m_argument.size());
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);
987 for(; it != it_end; ++it) {
994 (tpoly->m_coeffs).
set(new_key, *it);
1016 for(; it != it_end; ++it) {
1020 (tpoly->m_coeffs).
set(it.key(), *it);
1043 for(; it != it_end; ++it) {
1050 (tpoly->m_coeffs).
set(new_key, *it);
1071 for(; it != it_end; ++it) {
1075 (tpoly->m_coeffs).
set(it.key(), *it);
1086 *PRHS(static_cast<PolynomialFunction const *>(RHS));
1088 return PLHS->frobenius_scalar_prod(*PRHS);
1112 std::cerr <<
"WARNING: In-place multiplication of one PolynomialFunction with another is not yet implemented!!\n"
void small_to_zero(double tol=TOL)
void scale(double scale_factor)
virtual double remote_eval() const =0
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;.
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)
Function * subtract(Function const *LHS, Function const *RHS) const
Function * poly_remainder(Function const *LHS, Function const *RHS) const
std::string formula() const
void push_back(const T &toPush)
T get(const Array< Index > &ind) const
get() provides constant access does not change trie structure
double cache_deval(const DoF::RemoteHandle &dvar) const
double dot(Function const *LHS, Function const *RHS) const
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
static void fill_dispatch_table()
bool prune_zeros(double tol=PTNode< T >::PT_TOL())
removes zero entries, if there are any, and returns true if entries were removed. ...
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
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)
void swap(PolyTrie< T > &other)
Efficient swap of this PolyTrie with another.
const Array< Index > & key()
void sort_leaves(const CompareType &compare)
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
void redefine(Index new_depth)
Clears all leaves and resets depth.
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
void make_formula() const
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)
Function * plus_equals(const PolynomialFunction *RHS)
Array & append(const Array &new_tail)
bool compare(const PolynomialFunction *RHS) const
A IsoCounter allows looping over many incrementing variables in one loop.
SparseTensor< double > const * get_coeffs() const
Function * poly_quotient(const Variable *RHS) const
PolyTrie< double > m_coeffs
bool compare(const PolyTrie< T > &RHS, double tol=2 *PTNode< T >::PT_TOL()) const
double poly_eval(const Array< double > &arg_states) const
static Array< Array< InnerProduct * > > inner_prod_table
void reserve(Index new_max)
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 ...
double cache_eval() const
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
double remote_eval() const
ReturnArray< SymGroupRepID > _sub_sym_reps() const
double _arg_eval_cache(Index i) const