MADNESS  0.10.1
polynomial.h
Go to the documentation of this file.
1 /* This file is a part of Slymer, which is distributed under the Creative
2  Commons Attribution-NonCommercial 4.0 International Public License.
3 
4  (c) 2017 Stony Brook University. */
5 
6 /**
7  * \file Basis/polynomial.h
8  * \brief API and helper functions for describing polynomial functions of
9  * three variables.
10  *
11  * The array is indexed by the polyIndex function. Each element of the array
12  * is a coefficient on the polynomial.
13  */
14 
15 #ifndef __Basis_polynomial_h__
16 #define __Basis_polynomial_h__
17 
18 #include <array>
19 #include <vector>
20 
21 namespace slymer {
22 
23 /**
24  * \brief Array for storing coefficients of a polynomial of three variables
25  * with specified degree.
26  *
27  * The general polynomial of three variables is written as
28  * \f[ \sum_{i,j,k} c_{i,j,k} x^i y^j z^k, \f]
29  * where \f$0\le i+j+k\le N\f$. This data structure stores the coefficients
30  * in a vector and provides access routines in terms of the exponents \f$i\f$,
31  * \f$j\f$, and \f$k\f$.
32  *
33  * \note This class is not designed for polynomials with a large degree.
34  */
36 
37 protected:
38  /// The degree of the polynomial.
39  unsigned degree;
40 
41  /**
42  * \brief Array storing the coefficients.
43  *
44  * For a given degree n, there are \f$(n+1)(n+2)/2\f$ monomials. The total
45  * array thus has \f$(n+1)*(n+2)*(n+3)/6\f$ terms. The array stores all terms
46  * with degree 0, then degree 1, then degree 2, etc.
47  */
48  std::vector<double> coeffs;
49 
50  /**
51  * \brief Gets the array index for the coefficient of a particular term.
52  *
53  * Terms of degree 0 are stored before those of degree 1, etc.
54  *
55  * Within a particular degree, think of the problem in the combinatorial "stars
56  * and bars" idea: there are n stars and two bars dividing them into three
57  * parts. (Each part corresponds to the number of x, y, or z factors.) The first
58  * array element will be bars in the 0 and 1 positions, then 0 and 2, ..., 0 and
59  * n+1, then 1 and 2, etc.
60  *
61  * \param[in] pows The powers of x, y, and z for this term.
62  * \return The array offset, as described above.
63  */
64  static inline unsigned polyIndex(const std::array<unsigned, 3> &pows) {
65  const unsigned n = pows[0] + pows[1] + pows[2];
66 
67  // calculate the offset within the level of the degree...
68  // x-y offset. All terms with pows[0] == 0 are first; there are n+1 of them.
69  // Then pows[0] == 1; there are n, etc.
70  unsigned ret = (n+1)*pows[0] - (pows[0]-1)*pows[0] / 2;
71  // y-z offset. how many y factors are there? pows[1]. This value being 0
72  // comes first, then 1, then 2, etc.
73  ret += pows[1];
74 
75  // calculate the offset for smaller degrees. There are (n+1)(n+2)/2 elements
76  // for degree n; add up all the smaller degrees.
77  ret += n*(n+1)*(n+2)/6;
78 
79  return ret;
80  }
81 
82 public:
83  /**
84  * \brief Get the degree of the polynomial.
85  *
86  * \return The degree of the polynomial.
87  */
88  unsigned get_degree() const {
89  return degree;
90  }
91 
92  PolynomialCoeffs() = delete;
93 
94  /**
95  * \brief Create a linear function with the specified coefficients.
96  *
97  * \param[in] constant The constant term.
98  * \param[in] x The coefficient on x.
99  * \param[in] y The coefficient on y.
100  * \param[in] z The coefficient on z.
101  */
102  PolynomialCoeffs(const double constant, const double x, const double y,
103  const double z) : degree(1), coeffs(4) {
104 
105  coeffs[polyIndex({{0,0,0}})] = constant;
106  coeffs[polyIndex({{1,0,0}})] = x;
107  coeffs[polyIndex({{0,1,0}})] = y;
108  coeffs[polyIndex({{0,0,1}})] = z;
109  }
110 
111  /**
112  * \brief Create a polynomial of degree N.
113  *
114  * \param[in] N The degree of the polynomial.
115  */
116  PolynomialCoeffs(const unsigned N)
117  : degree(N), coeffs((N+1)*(N+2)*(N+3)/6) {
118 
119  for(double &coeff : coeffs)
120  coeff = 0.;
121  }
122 
123  /**
124  * \brief Access the coefficient for the specified term.
125  *
126  * \param[in] pows The powers of x, y, and z for this term.
127  * \return Reference to the array term.
128  */
129  double &operator[] (const std::array<unsigned, 3> &pows) {
130  return coeffs[polyIndex(pows)];
131  }
132 
133  /**
134  * \brief Access the coefficient for the specified term.
135  *
136  * \param[in] pows The powers of x, y, and z for this term.
137  * \return The array term.
138  */
139  double operator[] (const std::array<unsigned, 3> &pows) const {
140  return coeffs[polyIndex(pows)];
141  }
142 
143  /**
144  * \brief Evaluate the polynomial at the specified point.
145  *
146  * \note This implemention is a bit naive; it is not intended for
147  * polynomials with a large degree.
148  *
149  * \param[in] pt The point at which the polynomial is evaluated.
150  * \return The value of the polynomial at the point.
151  */
152  double operator() (const std::array<double, 3> &pt) const;
153 
154  /**
155  * \brief Add two polynomials together.
156  *
157  * *this is one of the polynomials.
158  *
159  * \param[in] rhs The other polynomial.
160  * \return The sum of *this and rhs.
161  */
162  PolynomialCoeffs operator+ (const PolynomialCoeffs &rhs) const;
163 
164  /**
165  * \brief Adds another polynomial to this one.
166  *
167  * \param[in] rhs The other polynomial.
168  * \return The sum of *this and rhs, in *this.
169  */
171 
172  /**
173  * \brief Multiply a polynomial by a constant value.
174  *
175  * *this is one of the polynomials.
176  *
177  * \param[in] c The constant value.
178  * \return The product of c and the polynomial.
179  */
180  PolynomialCoeffs operator* (const double c) const;
181 
182  /**
183  * \brief Scale the polynomial by a constant.
184  *
185  * \param[in] c The scale factor.
186  * \return The scaled polynomial (*this).
187  */
188  PolynomialCoeffs &operator*= (const double c);
189 
190  /**
191  * \brief Multiply two polynomials together.
192  *
193  * *this is one of the polynomials.
194  *
195  * \param[in] rhs The other polynomial.
196  * \return The product of *this and rhs.
197  */
198  PolynomialCoeffs operator* (const PolynomialCoeffs &rhs) const;
199 
200  /**
201  * \brief Expands a linear polynomial raised to a power.
202  *
203  * Essentially expands the polynomial
204  * \f[ (coeffs[0] + coeffs[1]*x + coeffs[2]*y + coeffs[3]*z)^j \f]
205  * into a new PolynomialCoeffs object. That is, output[{{p,q,r}}] is the
206  * coefficient on the \f$x^p y^q z^r\f$ term.
207  *
208  * This function requires multinomial coefficients, which involve
209  * factorials. We assume that the arguments to the factorials will not
210  * be large and hard-code small values. An error will be thrown if
211  * the maximum value is exceeded.
212  *
213  * \throw std::runtime_error if the polynomial does not have degree 1.
214  *
215  * \param[in] j The exponent of the expansion.
216  * \return The polynomial, ordered using the polyIndex scheme.
217  */
218  PolynomialCoeffs pow(const unsigned j) const;
219 
220 }; // class PolynomialCoeffs
221 
222 /**
223  * \brief Multiply a polynomial by a constant value.
224  *
225  * \param[in] c The constant value.
226  * \param[in] poly The polynomial.
227  * \return The product of c and the polynomial.
228  */
229 inline PolynomialCoeffs operator* (const double c, const PolynomialCoeffs &poly) {
230  return poly * c;
231 }
232 
233 } // namespace slymer
234 
235 #endif
Array for storing coefficients of a polynomial of three variables with specified degree.
Definition: polynomial.h:35
double operator()(const std::array< double, 3 > &pt) const
Evaluate the polynomial at the specified point.
Definition: polynomial.cc:18
PolynomialCoeffs(const double constant, const double x, const double y, const double z)
Create a linear function with the specified coefficients.
Definition: polynomial.h:102
PolynomialCoeffs & operator*=(const double c)
Scale the polynomial by a constant.
Definition: polynomial.cc:90
PolynomialCoeffs operator*(const double c) const
Multiply a polynomial by a constant value.
Definition: polynomial.cc:81
PolynomialCoeffs pow(const unsigned j) const
Expands a linear polynomial raised to a power.
Definition: polynomial.cc:119
static unsigned polyIndex(const std::array< unsigned, 3 > &pows)
Gets the array index for the coefficient of a particular term.
Definition: polynomial.h:64
unsigned get_degree() const
Get the degree of the polynomial.
Definition: polynomial.h:88
PolynomialCoeffs operator+(const PolynomialCoeffs &rhs) const
Add two polynomials together.
Definition: polynomial.cc:30
std::vector< double > coeffs
Array storing the coefficients.
Definition: polynomial.h:48
PolynomialCoeffs & operator+=(const PolynomialCoeffs &rhs)
Adds another polynomial to this one.
Definition: polynomial.cc:58
unsigned degree
The degree of the polynomial.
Definition: polynomial.h:39
PolynomialCoeffs(const unsigned N)
Create a polynomial of degree N.
Definition: polynomial.h:116
double & operator[](const std::array< unsigned, 3 > &pows)
Access the coefficient for the specified term.
Definition: polynomial.h:129
Definition: basis.h:22
GaussianFunction operator*(const double lhs, const GaussianFunction &rhs)
Multiply a GaussianFunction by a scalar.
Definition: gaussian.h:372
static const double c
Definition: relops.cc:10
#define N
Definition: testconv.cc:37
double constant(const coordT &x)
Definition: testper.cc:46