Legendre Polynomials
Series
This page presents C++ implementations for computing Legendre and Associated Legendre polynomials using recurrence relations. These polynomials are fundamental in quantum mechanics, particularly for spherical harmonics.
Legendre Polynomials
Legendre polynomials satisfy the recurrence relation:
They are orthogonal on with weight function .
Associated Legendre Polynomials
Associated Legendre polynomials are computed using a more sophisticated recurrence relation that computes all polynomials up to degree simultaneously for efficiency.
C++ Implementation
The following code implements both Legendre and Associated Legendre polynomials:
#include <vector>
#include <cmath>
#include <numbers>
#include <iostream>
// Helper function: linspace
std::vector<double> linspace(double start, double end, size_t num) {
std::vector<double> result(num);
double dx = (end - start) / (num - 1);
for (size_t i = 0; i < num; ++i) {
result[i] = start + i * dx;
}
return result;
}
// Simple Legendre polynomial evaluator
namespace sp {
struct legendre {
// Evaluate P_n(x) for single x using recurrence
double operator()(std::size_t N, double x) const {
if (N == 0) return 1.0;
if (N == 1) return x;
double Pnm2 = 1.0; // P_0
double Pnm1 = x; // P_1
double Pn = 0.0;
for (std::size_t n = 2; n <= N; ++n) {
Pn = ((2*n-1) * x * Pnm1 - (n-1) * Pnm2) / n;
Pnm2 = Pnm1;
Pnm1 = Pn;
}
return Pn;
}
};
}
// Index helper for packed storage
inline std::size_t PT(std::size_t l, std::size_t m) {
return m + (l * (l + 1)) / 2;
}
// Compute recurrence coefficients A[l,m] and B[l,m]
void computeAB(std::size_t L, std::vector<double>& A, std::vector<double>& B) {
std::size_t maxIndex = PT(L, L) + 1;
A.assign(maxIndex, 0.0);
B.assign(maxIndex, 0.0);
for (std::size_t l = 2; l <= L; l++) {
double ls = static_cast<double>(l) * static_cast<double>(l);
double lm1s = static_cast<double>(l - 1) * static_cast<double>(l - 1);
for (std::size_t m = 0; m < l - 1; m++) {
double ms = static_cast<double>(m) * static_cast<double>(m);
A[PT(l, m)] = std::sqrt((4.0 * ls - 1.0) / (ls - ms));
B[PT(l, m)] = -std::sqrt((lm1s - ms) / (4.0 * lm1s - 1.0));
}
}
}
// Compute all P_lm(cos θ) up to degree L
// Returns vector indexed by PT(l, m)
std::vector<double> computeP(std::size_t L,
const std::vector<double>& A,
const std::vector<double>& B,
double x) {
std::vector<double> P(PT(L, L) + 1, 0.0);
double sintheta = std::sqrt(1.0 - x * x);
double temp = 0.39894228040143267794; // sqrt(0.5 / pi)
P[PT(0, 0)] = temp;
if (L > 0) {
const double SQRT3 = 1.7320508075688772935;
P[PT(1, 0)] = x * SQRT3 * temp;
const double SQRT3DIV2 = -1.2247448713915890491;
temp = SQRT3DIV2 * sintheta * temp;
P[PT(1, 1)] = temp;
for (std::size_t l = 2; l <= L; l++) {
for (std::size_t m = 0; m < l - 1; m++) {
P[PT(l, m)] = A[PT(l, m)] *
(x * P[PT(l - 1, m)] + B[PT(l, m)] * P[PT(l - 2, m)]);
}
P[PT(l, l - 1)] = x * std::sqrt(2.0 * (l - 1) + 3.0) * temp;
temp = -std::sqrt(1.0 + 0.5 / static_cast<double>(l)) *
sintheta * temp;
P[PT(l, l)] = temp;
}
}
return P;
}
// Example usage
int main() {
// Compute Legendre polynomials
sp::legendre leg;
std::vector<double> xs = linspace(-1.0, 1.0, 1000);
std::vector<double> P1(xs.size());
std::vector<double> P2(xs.size());
for(size_t i = 0; i < xs.size(); i++) {
P1[i] = leg(1, xs[i]); // P_1(x)
P2[i] = leg(2, xs[i]); // P_2(x)
}
std::cout << "P_1(0) = " << P1[500] << std::endl;
std::cout << "P_2(0) = " << P2[500] << std::endl;
// Compute Associated Legendre polynomials
std::size_t L = 10;
std::vector<double> A, B;
computeAB(L, A, B);
double cos_theta = 0.5;
std::vector<double> P_lm = computeP(L, A, B, cos_theta);
// Access P_lm using PT(l, m)
double P_2_1 = P_lm[PT(2, 1)];
double P_3_2 = P_lm[PT(3, 2)];
std::cout << "P_2^1(0.5) = " << P_2_1 << std::endl;
std::cout << "P_3^2(0.5) = " << P_3_2 << std::endl;
return 0;
} Key Features
- Efficient recurrence relation implementation
- Packed storage for Associated Legendre polynomials
- Computes all polynomials up to degree simultaneously
- Based on optimized algorithm from computational chemistry literature
Applications
- Spherical harmonics:
- Quantum mechanical angular momentum
- Multipole expansions
- Radial Schrödinger equation solutions