15 const std::vector<std::shared_ptr<BasisSet> > &_args)
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 "
24 "how to apply symmetry to it. \n"
25 <<
" Something bad will probably happen; consider this "
28 if (!_args[i]->size()) {
29 std::cerr <<
"WARNING: In PolynomialFunction constructor, initial "
30 "arguments are ill-defined. Continuing..\n";
41 const std::vector<std::shared_ptr<BasisSet> > &_args,
43 :
Function(_args), m_coeffs(_coeffs) {
46 for (i = 0; i < _args.size(); i++) {
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 "
55 if (!_args[i]->size()) {
56 std::cerr <<
"WARNING: In PolynomialFunction constructor, initial "
57 "arguments are ill-defined. Continuing..\n";
63 std::cerr <<
"CRITICAL ERROR: PolynomialFunction initialized with "
64 "coefficients that are incompatible with its argument list.\n"
87 bool add_subspace(
true);
89 for (i = 0; i < LHS.
m_argument.size() && add_subspace; i++) {
100 for (i = 0; i < RHS.
m_argument[j]->size(); i++) {
109 linear_ind, linear_ind + RHS.
m_argument[j]->size() - 1));
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];
124 for (; RHS_it != RHS_end; ++RHS_it) {
125 t_coeff = (*RHS_it) * (*LHS_it);
129 for (i = 0; i < RHS_it.key().size(); i++) {
130 tot_ind[RHS_ind[i]] += RHS_it.key()[i];
141 :
Function(RHS), m_coeffs(RHS.m_coeffs) {}
147 :
Function(RHS), m_coeffs(_coeffs) {
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";
173 return visitor.
visit(*
this, home_basis_ptr);
180 BasisSet const *home_basis_ptr )
const {
181 return visitor.
visit(*
this, home_basis_ptr);
186 Index sub_ind(0), arg_ind(0), linear_ind(0);
187 for (sub_ind = 0; sub_ind <
m_argument.size(); sub_ind++) {
189 linear_ind += arg_ind;
194 if (sub_ind ==
m_argument.size())
return false;
197 for (; it != it_end; ++it) {
200 if (it.key()[linear_ind])
return true;
209 for (; it != it_end; ++it) {
224 for (; it != it_end; ++it) {
242 for (; it != it_end; ++it) {
254 for (; it != it_end; ++it) {
256 if (index == i)
return *it;
274 std::stringstream tformula, ttex;
281 for (; it != it_end; ++it) {
301 double func_scale(prefactor[0]);
310 if (unique_product.
size() > 1) {
315 for (np = 0; np < unique_product.
size(); np++) {
316 if (np > 0 && prefactor[np] > 0.0) {
322 tformula << prefactor[np] <<
" * ";
325 if (np > 0 && prefactor[np] / func_scale > 0.0) {
330 }
else if (!
almost_zero(prefactor[np] / func_scale - 1)) {
337 for (
Index linear_ind = 0; linear_ind < unique_product[np].
size();
339 if (!unique_product[np][linear_ind])
continue;
343 tot_pow += unique_product[np][linear_ind];
345 if (unique_product[np][linear_ind] > 1) {
347 << unique_product[np][linear_ind] <<
")";
349 << unique_product[np][linear_ind] <<
"} ";
355 if (tot_pow == 0 &&
almost_zero(std::abs(prefactor[np] / func_scale) - 1)) {
361 if (unique_product.
size() > 1) {
376 if (it == it_end)
return {};
378 for (; it != it_end; ++it) {
381 for (
Index i = 0; i < it.key().size(); i++)
385 std::set<Index> result;
391 result.insert(tres.begin(), tres.end());
442 std::vector<Index>
const &compatibility_map) {
443 if (new_arg.size() < compatibility_map.size() ||
445 throw std::runtime_error(
446 "In PolynomialFunction::_set_arguments called with incompatible "
448 if (new_arg.empty())
return;
450 std::vector<Index> ind_perm(
num_args());
451 std::vector<Index> new_offset;
452 std::vector<Index> old_offset(1, 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();
462 Index new_a = new_offset[compatibility_map[i]];
464 ind_perm[old_a++] = new_a++;
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;
500 const SymOp &op,
const std::vector<bool> &transform_flags) {
511 for (; it != it_end; ++it)
523 "\'ind\' Array is not compatible with PolynomialFunction in "
524 "PolynomialFunction::transform_monomial_and_add");
539 Index linear_offset(0);
546 if (!ind[linear_offset + na1])
continue;
549 if (rep_mats[ns] && !
almost_zero((*rep_mats[ns])(na2, na1))) {
550 nz_terms[ns][na1].
push_back(linear_offset + na2);
552 nz_coeffs[ns][na1].
push_back((*rep_mats[ns])(na2, na1));
553 }
else if (!rep_mats[ns] &&
555 nz_terms[ns][na1].
push_back(linear_offset + na2);
560 exp_counter[ns][na1][0] = ind[linear_offset + na1];
585 out_coeff = prefactor;
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]);
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';
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;
617 for (na2 = 0; na2 < exp_counter[ns][na1].
size() - 1; na2++) {
618 if (exp_counter[ns][na1][na2] == 0)
continue;
620 exp_counter[ns][na1][na2]--;
621 exp_counter[ns][na1][na2 + 1]++;
623 exp_counter[ns][na1][0] = exp_counter[ns][na1][na2];
624 exp_counter[ns][na1][na2] = 0;
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;
635 if (na1 < exp_counter[ns].size())
break;
639 cflag = ns < exp_counter.
size();
653 const std::vector<bool> &transform_flags) {
655 "\'ind\' Array is not compatible with PolynomialFunction in "
656 "PolynomialFunction::transform_monomial_and_add");
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;
666 ExpCounter exp_counter;
681 Index linear_offset(0);
683 exp_counter.push_back(SubspaceCounter());
688 int pow_to_distribute(ind[linear_offset + na1]);
690 if (pow_to_distribute == 0) {
691 exp_counter[ns].push_back(TermCounter());
696 if (rep_mats[ns] && !
almost_zero((*rep_mats[ns])(na2, na1))) {
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] &&
703 nz_terms[ns][na1].
push_back(linear_offset + na2);
707 exp_counter[ns].push_back(
709 Array<Index>(nz_terms[ns][na1].size(), pow_to_distribute),
710 1, pow_to_distribute));
732 while (exp_counter.valid()) {
735 out_coeff = prefactor;
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]);
764 for (; it != it_end; ++it) {
767 for (
Index i = 0; i < it.key().size(); i++) {
768 t_prod *= pow(arg_states[i], it.key()[i]);
792 Index const *k_begin, *k_end;
795 for (; it != it_end; ++it) {
797 k_begin = it.key().begin();
798 k_end = it.key().end();
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];
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];
824 for (; it != it_end; ++it) {
827 for (
Index i = 0; i < it.key().size(); i++) {
852 Index const *k_begin, *k_end;
855 for (; it != it_end; ++it) {
857 k_begin = it.key().begin();
858 k_end = it.key().end();
861 for (
Index const *i = k_begin; i < k_end; i++) {
862 if (*i == 0)
continue;
865 for (
Index const *j = k_begin; j < k_end; j++) {
866 for (
Index p = 0; p < (*j) - int(i == j); p++)
885 double prod_result(0.0), tprod(0.0);
892 std::vector<std::vector<std::set<Index> > > indep;
895 indep.push_back(
m_argument[i]->independent_sub_bases());
897 for (; it != it_end; ++it) {
901 for (
Index i = 0; i < indep.size(); i++) {
902 for (
auto const &indep_set : indep[i]) {
904 for (
Index const &func_ind : indep_set) {
911 prod_result += tprod;
928 double tprod(0), tintegral(0);
931 double tvol(pow(edge_length, RHS.
num_args()));
935 <<
"WARNING!!! Attempting to get scalar_product between incompatible "
936 "PolynomialFunctions. Assuming that they are orthogonal...\n";
944 if (RHS_it == RHS_end || LHS_it == LHS_end)
return 0;
946 for (; RHS_it != RHS_end; ++RHS_it) {
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];
955 if (texp != 2 * (texp / 2)) {
960 tintegral *= 2 * pow(edge_length / 2, texp + 1) / double(texp + 1);
996 int dependency_layer) {
997 std::vector<bool> transform_flags(
m_argument.size());
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);
1024 for (; it != it_end; ++it) {
1025 if (!it.key()[i])
continue;
1051 for (; it != it_end; ++it) {
1052 if (it.key()[i])
continue;
1076 for (; it != it_end; ++it) {
1077 if (!it.key()[i])
continue;
1104 for (; it != it_end; ++it) {
1105 if (it.key()[i])
continue;
1120 return PLHS->frobenius_scalar_prod(*PRHS);
1144 std::cerr <<
"WARNING: In-place multiplication of one PolynomialFunction "
1145 "with another is not yet implemented!!\n"
1203 static_cast<Variable const *
>(RHS));
1211 static_cast<Variable const *
>(RHS));
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
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
double _arg_deval_cache(Index i) const
std::string tex_formula() const
static Array< Array< FunctionOperation * > > operation_table
virtual bool visit(Variable const &host, BasisSet const *bset_ptr) const
A IsoCounter allows looping over many incrementing variables in one loop.
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
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
PolyTrie< double > m_coeffs
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
static void fill_dispatch_table()
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...
Array< Eigen::MatrixXd const * > get_matrix_reps(Array< SymGroupRepID > _rep_IDs) const
void push_back(const T &toPush)
Array & append(const Array &new_tail)
void swap(PolyTrie< T > &other)
Efficient swap of this PolyTrie with another.
bool prune_zeros(double tol=PTNode< T >::PT_TOL())
T get(const Array< Index > &ind) const
get() provides constant access does not change trie structure
void redefine(Index new_depth)
Clears all leaves and resets depth.
bool compare(const PolyTrie< T > &RHS, double tol=2 *PTNode< T >::PT_TOL()) const
void sort_leaves(const CompareType &compare)
T & at(const Array< Index > &ind)
bool check(const Lattice &lat)
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
std::string irrational_to_tex_string(double val, int lim, int max_pow=2)
IntType multinomial_coeff(const Array< IntType > &exponents)
INDEX_TYPE Index
For long integer indexing: