diff --git a/src/soap/functions.cpp b/src/soap/functions.cpp
index d80c846e1fbe8770dfe62d7a0b23e49f973bc539..59f8ec5290ab4105d9ac474ddc1cec09c8a2d0fd 100644
--- a/src/soap/functions.cpp
+++ b/src/soap/functions.cpp
@@ -247,14 +247,15 @@ std::complex<double> pow_nnan(std::complex<double> z, double a) {
     }
 }
 
-const int FACTORIAL_CACHE_SIZE = 16;
+const int FACTORIAL_CACHE_SIZE = 19;
 const long int FACTORIAL_CACHE[] = {
   1,
   1, 2, 6,
   24, 120, 720,
   5040, 40320, 362880,
   3628800, 39916800, 479001600,
-  6227020800, 87178291200, 1307674368000 };
+  6227020800, 87178291200, 1307674368000,
+  20922789888000, 355687428096000, 6402373705728000};
 
 long int factorial(int x) {
     if (x < FACTORIAL_CACHE_SIZE) {
@@ -270,14 +271,15 @@ long int factorial(int x) {
     }
 }
 
-const int FACTORIAL2_CACHE_SIZE = 16;
+const int FACTORIAL2_CACHE_SIZE = 19;
 const long int FACTORIAL2_CACHE[] = {
     1,
     1, 2, 3,
     8, 15, 48,
     105, 384, 945,
     3840, 10395, 46080,
-    135135, 645120, 2027025 };
+    135135, 645120, 2027025,
+    10321920, 34459425, 185794560};
 
 long int factorial2(int x) {
     if (x < 0) {
diff --git a/src/soap/linalg/wigner.cpp b/src/soap/linalg/wigner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..efe2bbcd2458ba6d326e2b860c017c1e748610ab
--- /dev/null
+++ b/src/soap/linalg/wigner.cpp
@@ -0,0 +1,505 @@
+/*******************************************************-/
+ * This source code is subject to the terms of the GNU  -/
+ * Lesser Public License. If a copy of the LGPL was not -/
+ * distributed with this file, you can obtain one at    -/
+ * https://www.gnu.org/licenses/lgpl.html.              -/
+ ********************************************************/
+
+#include "soap/linalg/wigner.hpp"
+
+namespace WignerSymbols {
+std::vector<double> wigner3j(double l2, double l3,
+			     double m1, double m2, double m3)
+{
+	// We compute the numeric limits of double precision.
+	double huge = sqrt(std::numeric_limits<double>::max()/20.0);
+	double srhuge = sqrt(huge);
+	double tiny = std::numeric_limits<double>::min();
+	double srtiny = sqrt(tiny);
+	double eps = std::numeric_limits<double>::epsilon();
+
+	// We enforce the selection rules.
+	bool select(true);
+	select = (
+		   std::fabs(m1+m2+m3)<eps
+		&& std::fabs(m2) <= l2+eps
+		&& std::fabs(m3) <= l3+eps
+		);
+
+	if (!select) return std::vector<double>(1,0.0);
+
+	// We compute the limits of l1.
+	double l1min = std::max(std::fabs(l2-l3),std::fabs(m1));
+	double l1max = l2+l3;
+
+	// We compute the size of the resulting array.
+	int size = (int)std::floor(l1max-l1min+1.0+eps);
+	std::vector<double> thrcof(size,0.0);
+
+	// If l1min=l1max, we have an analytical formula.
+	if (size==1)
+	{
+		thrcof[0] = pow(-1.0,std::floor(std::fabs(l2+m2-l3+m3)))/sqrt(l1min+l2+l3+1.0);
+	}
+
+	// Another special case where the recursion relation fails.
+	else
+	{
+		// We start with an arbitrary value.
+		thrcof[0] = srtiny;
+
+		// From now on, we check the variation of |alpha(l1)|.
+		double alphaNew, l1(l1min);
+		if (l1min==0.0)
+			alphaNew = -(m3-m2+2.0*wigner3j_auxB(l1,l2,l3,m1,m2,m3))/wigner3j_auxA(1.0,l2,l3,m1,m2,m3);
+		else
+			alphaNew = -wigner3j_auxB(l1min,l2,l3,m1,m2,m3)
+							/(l1min*wigner3j_auxA(l1min+1.0,l2,l3,m1,m2,m3));
+
+		// We compute the two-term recursion.
+		thrcof[1] = alphaNew*thrcof[0];
+
+		// If size > 2, we start the forward recursion.
+		if (size>2)
+		{
+			// We start with an arbitrary value.
+			thrcof[0] = srtiny;
+
+			// From now on, we check the variation of |alpha(l1)|.
+			double alphaOld, alphaNew, beta, l1(l1min);
+			if (l1min==0.0)
+				alphaNew = -(m3-m2+2.0*wigner3j_auxB(l1,l2,l3,m1,m2,m3))/wigner3j_auxA(1.0,l2,l3,m1,m2,m3);
+			else
+				alphaNew = -wigner3j_auxB(l1min,l2,l3,m1,m2,m3)
+							/(l1min*wigner3j_auxA(l1min+1.0,l2,l3,m1,m2,m3));
+
+			// We compute the two-term recursion.
+			thrcof[1] = alphaNew*thrcof[0];
+
+			// We compute the rest of the recursion.
+			int i = 1;
+			bool alphaVar = false;
+			do
+			{
+				// Bookkeeping:
+				i++;					// Next term in recursion
+				alphaOld = alphaNew;	// Monitoring of |alpha(l1)|.
+				l1 += 1.0;				// l1 = l1+1
+
+				// New coefficients in recursion.
+				alphaNew = -wigner3j_auxB(l1,l2,l3,m1,m2,m3)
+							/(l1*wigner3j_auxA(l1+1.0,l2,l3,m1,m2,m3));
+
+				beta = -(l1+1.0)*wigner3j_auxA(l1,l2,l3,m1,m2,m3)
+						/(l1*wigner3j_auxA(l1+1.0,l2,l3,m1,m2,m3));
+
+				// Application of the recursion.
+				thrcof[i] = alphaNew*thrcof[i-1]+beta*thrcof[i-2];
+
+				// We check if we are overflowing.
+				if (std::fabs(thrcof[i])>srhuge)
+				{
+					std::cout << "We renormalized the forward recursion." << std::endl;
+					for (std::vector<double>::iterator it = thrcof.begin(); it != thrcof.begin()+i; ++it)
+					{
+						//if (std::fabs(*it) < srtiny) *it = 0;
+						//else
+						*it /= srhuge;
+					}
+				}
+
+				// This piece of code checks whether we have reached
+				// the classical region. If we have, the second if
+				// sets alphaVar to true and we break this loop at the
+				// next iteration because we need thrcof(l1mid+1) to
+				// compute the scalar lambda.
+				if (alphaVar) break;
+
+				if (std::fabs(alphaNew)-std::fabs(alphaOld)>0.0)
+					alphaVar=true;
+
+			}	while (i<(size-1));	// Loop stops when we have computed all values.
+
+			// If this is the case, we have stumbled upon a classical region.
+			// We start the backwards recursion.
+			if (i!=size-1)
+			{
+				// We keep the two terms around l1mid to compute the factor later.
+				double l1midm1(thrcof[i-2]),l1mid(thrcof[i-1]),l1midp1(thrcof[i]);
+
+				// We compute the backward recursion by providing an arbitrary
+				// startint value.
+				thrcof[size-1] = srtiny;
+
+				// We compute the two-term recursion.
+				l1 = l1max;
+				alphaNew = -wigner3j_auxB(l1,l2,l3,m1,m2,m3)
+								/((l1+1.0)*wigner3j_auxA(l1,l2,l3,m1,m2,m3));
+				thrcof[size-2] = alphaNew*thrcof[size-1];
+
+				// We compute the rest of the backward recursion.
+				int j = size-2;
+				do
+				{
+					// Bookkeeping
+					j--;			// Previous term in recursion.
+					l1 -= 1.0;		// l1 = l1-1
+
+					// New coefficients in recursion.
+					alphaNew = -wigner3j_auxB(l1,l2,l3,m1,m2,m3)
+								/((l1+1.0)*wigner3j_auxA(l1,l2,l3,m1,m2,m3));
+					beta = -l1*wigner3j_auxA(l1+1.0,l2,l3,m1,m2,m3)
+									/((l1+1.0)*wigner3j_auxA(l1,l2,l3,m1,m2,m3));
+
+					// Application of the recursion.
+					thrcof[j] = alphaNew*thrcof[j+1]+beta*thrcof[j+2];
+
+					// We check if we are overflowing.
+					if (std::fabs(thrcof[j]>srhuge))
+					{
+						std::cout << "We renormalized the backward recursion." << std::endl;
+						for (std::vector<double>::iterator it = thrcof.begin()+j; it != thrcof.end(); ++it)
+						{
+							//if (std::fabs(*it) < srtiny) *it = 0;
+							//else
+							*it /= srhuge;
+						}
+					}
+
+				} while (j>(i-2)); // Loop stops when we are at l1=l1mid-1.
+
+				// We now compute the scaling factor for the forward recursion.
+				double lambda = (l1midp1*thrcof[j+2]+l1mid*thrcof[j+1]+l1midm1*thrcof[j])
+										/(l1midp1*l1midp1+l1mid*l1mid+l1midm1*l1midm1);
+
+				// We scale the forward recursion.
+				for (std::vector<double>::iterator it = thrcof.begin(); it != thrcof.begin()+j; ++it)
+				{
+					*it *= lambda;
+				}
+			}
+		}
+	}
+
+	// We compute the overall factor.
+	double sum = 0.0;
+	for (int k=0;k<size;k++)
+	{
+		sum += (2.0*(l1min+k)+1.0)*thrcof[k]*thrcof[k];
+	}
+	//std::cout << sum << std::endl;
+
+	//std::cout << "(-1)^(l2-l3-m1): " << pow(-1.0,l2-l3-m1) << " sgn:" << sgn(thrcof[size-1]) << std::endl;
+	double c1 = pow(-1.0,l2-l3-m1)*sgn(thrcof[size-1]);
+	//std::cout << "c1: " << c1 << std::endl;
+	for (std::vector<double>::iterator it = thrcof.begin(); it != thrcof.end(); ++it)
+	{
+		//std::cout << *it << ", " << c1 << ", ";
+		*it *= c1/sqrt(sum);
+		//std::cout << *it << std::endl;
+	}
+	return thrcof;
+}
+
+double wigner3j(double l1, double l2, double l3,
+					double m1, double m2, double m3)
+{
+	// We enforce the selection rules.
+	bool select(true);
+	select = (
+		   std::fabs(m1+m2+m3)<1.0e-10
+		&& std::floor(l1+l2+l3)==(l1+l2+l3)
+		&& l3 >= std::fabs(l1-l2)
+		&& l3 <= l1+l2
+		&& std::fabs(m1) <= l1
+		&& std::fabs(m2) <= l2
+		&& std::fabs(m3) <= l3
+		);
+
+	if (!select) return 0.0;
+
+	// We compute l1min and the position of the array we will want.
+	double l1min = std::max(std::fabs(l2-l3),std::fabs(m1));
+
+	// We fetch the proper value in the array.
+	int index = (int)(l1-l1min);
+
+	return wigner3j(l2,l3,m1,m2,m3)[index];
+}
+
+std::vector<double> wigner6j(double l2, double l3,
+					double l4, double l5, double l6)
+{
+	// We compute the numeric limits of double precision.
+	double huge = std::numeric_limits<double>::max();
+	double srhuge = sqrt(huge);
+	double tiny = std::numeric_limits<double>::min();
+	double srtiny = sqrt(tiny);
+	double eps = std::numeric_limits<double>::epsilon();
+
+	// We enforce the selection rules.
+	bool select(true);
+
+	// Triangle relations for the four tryads
+	select = (
+		std::fabs(l4-l2) <= l6 && l6 <= l4+l2
+		&& std::fabs(l4-l5) <= l3 && l3 <= l4+l5
+		);
+
+	// Sum rule of the tryads
+	select = (
+		std::floor(l4+l2+l6)==(l4+l2+l6)
+		&& std::floor(l4+l5+l3)==(l4+l5+l3)
+		);
+
+	if (!select) return std::vector<double>(1,0.0);
+
+	// We compute the limits of l1.
+	double l1min = std::max(std::fabs(l2-l3),std::fabs(l5-l6));
+	double l1max = std::min(l2+l3,l5+l6);
+
+	// We compute the size of the resulting array.
+	unsigned int size = (int)std::floor(l1max-l1min+1.0+eps);
+	std::vector<double> sixcof(size,0.0);
+
+	// If l1min=l1max, we have an analytical formula.
+	if (size==1)
+	{
+		sixcof[0] = 1.0/sqrt((l1min+l1min+1.0)*(l4+l4+1.0));
+		sixcof[0] *= ((int)std::floor(l2+l3+l5+l6+eps) & 1 ? -1.0 : 1.0);
+	}
+
+	// Otherwise, we start the forward recursion.
+	else
+	{
+		// We start with an arbitrary value.
+		sixcof[0] = srtiny;
+
+		// From now on, we check the variation of |alpha(l1)|.
+		double alphaNew, l1(l1min);
+
+		if (l1min==0)
+			alphaNew = -(l2*(l2+1.0)+l3*(l3+1.0)+l5*(l5+1.0)+l6*(l6+1.0)-2.0*l4*(l4+1.0))/wigner6j_auxA(1.0,l2,l3,l4,l5,l6);
+
+		else
+			alphaNew = -wigner6j_auxB(l1,l2,l3,l4,l5,l6)
+							/(l1min*wigner6j_auxA(l1+1.0,l2,l3,l4,l5,l6));
+
+		// We compute the two-term recursion.
+		sixcof[1] = alphaNew*sixcof[0];
+
+		if (size>2)
+		{
+			// We start with an arbitrary value.
+			sixcof[0] = srtiny;
+
+			// From now on, we check the variation of |alpha(l1)|.
+			double alphaOld, alphaNew, beta, l1(l1min);
+			if (l1min==0)
+				alphaNew = -(l2*(l2+1.0)+l3*(l3+1.0)+l5*(l5+1.0)+l6*(l6+1.0)-2.0*l4*(l4+1.0))/wigner6j_auxA(1.0,l2,l3,l4,l5,l6);
+
+			else
+				alphaNew = -wigner6j_auxB(l1,l2,l3,l4,l5,l6)
+							/(l1min*wigner6j_auxA(l1+1.0,l2,l3,l4,l5,l6));
+
+			// We compute the two-term recursion.
+			sixcof[1] = alphaNew*sixcof[0];
+
+			// We compute the rest of the recursion.
+			unsigned int i = 1;
+			bool alphaVar = false;
+			do
+			{
+				// Bookkeeping:
+				i++;					// Next term in recursion
+				alphaOld = alphaNew;	// Monitoring of |alpha(l1)|.
+				l1 += 1.0;				// l1 = l1+1
+
+				// New coefficients in recursion.
+				alphaNew = -wigner6j_auxB(l1,l2,l3,l4,l5,l6)
+							/(l1*wigner6j_auxA(l1+1.0,l2,l3,l4,l5,l6));
+
+				beta = -(l1+1.0)*wigner6j_auxA(l1,l2,l3,l4,l5,l6)
+						/(l1*wigner6j_auxA(l1+1.0,l2,l3,l4,l5,l6));
+
+				// Application of the recursion.
+				sixcof[i] = alphaNew*sixcof[i-1]+beta*sixcof[i-2];
+
+				// We check if we are overflowing.
+				if (std::fabs(sixcof[i]>srhuge))
+				{
+					std::cout << "We renormalized the forward recursion." << std::endl;
+					for (std::vector<double>::iterator it = sixcof.begin(); it != sixcof.begin()+i; ++it)
+					{
+						*it /= srhuge;
+					}
+				}
+
+				// This piece of code checks whether we have reached
+				// the classical region. If we have, the second if
+				// sets alphaVar to true and we break this loop at the
+				// next iteration because we need sixcof(l1mid+1) to
+				// compute the scalar.
+				if (alphaVar) break;
+
+				if (std::fabs(alphaNew)-std::fabs(alphaOld)>0.0)
+					alphaVar=true;
+
+			}	while (i<(size-1));	// Loop stops when we have computed all values.
+
+			// If this is the case, we have stumbled upon a classical region.
+			// We start the backwards recursion.
+			if (i!=size-1)
+			{
+				// We keep the two terms around l1mid to compute the factor later.
+				double l1midm1(sixcof[i-2]),l1mid(sixcof[i-1]),l1midp1(sixcof[i]);
+
+				// We compute the backward recursion by providing an arbitrary
+				// startint value.
+				sixcof[size-1] = srtiny;
+
+				// We compute the two-term recursion.
+				l1 = l1max;
+				alphaNew = -wigner6j_auxB(l1,l2,l3,l4,l5,l6)
+								/((l1+1.0)*wigner6j_auxA(l1,l2,l3,l4,l5,l6));
+				sixcof[size-2] = alphaNew*sixcof[size-1];
+
+				// We compute the rest of the backward recursion.
+				unsigned int j = size-2;
+				do
+				{
+					// Bookkeeping
+					j--;			// Previous term in recursion.
+					l1 -= 1.0;		// l1 = l1-1
+
+					// New coefficients in recursion.
+					alphaNew = -wigner6j_auxB(l1,l2,l3,l4,l5,l6)
+								/((l1+1.0)*wigner6j_auxA(l1,l2,l3,l4,l5,l6));
+					beta = -l1*wigner6j_auxA(l1+1.0,l2,l3,l4,l5,l6)
+								/((l1+1.0)*wigner6j_auxA(l1,l2,l3,l4,l5,l6));
+
+					// Application of the recursion.
+					sixcof[j] = alphaNew*sixcof[j+1]+beta*sixcof[j+2];
+
+					// We check if we are overflowing.
+					if (std::fabs(sixcof[j]>srhuge))
+					{
+						std::cout << "We renormalized the backward recursion." << std::endl;
+						for (std::vector<double>::iterator it = sixcof.begin()+j; it != sixcof.end(); ++it)
+						{
+							*it /= srhuge;
+						}
+					}
+
+				} while (j>(i-2)); // Loop stops when we are at l1=l1mid-1.
+
+				// We now compute the scaling factor for the forward recursion.
+				double lambda = (l1midp1*sixcof[j+2]+l1mid*sixcof[j+1]+l1midm1*sixcof[j])
+									/(l1midp1*l1midp1+l1mid*l1mid+l1midm1*l1midm1);
+
+				// We scale the forward recursion.
+				for (std::vector<double>::iterator it = sixcof.begin(); it != sixcof.begin()+j; ++it)
+				{
+					*it *= lambda;
+				}
+			}
+		}
+	}
+
+	// We compute the overall factor.
+	double sum = 0.0;
+	for (unsigned int k=0;k<size;k++)
+	{
+		sum += (2.0*(l1min+k)+1.0)*(2.0*l4+1.0)*sixcof[k]*sixcof[k];
+	}
+	double c1 = pow(-1.0,std::floor(l2+l3+l5+l6+eps))*sgn(sixcof[size-1])/sqrt(sum);
+
+	for (std::vector<double>::iterator it = sixcof.begin(); it != sixcof.end(); ++it)
+	{
+		*it *= c1;
+	}
+	return sixcof;
+}
+
+double wigner6j(double l1, double l2, double l3,
+					double l4, double l5, double l6)
+{
+	// We enforce the selection rules.
+	bool select(true);
+
+	// Triangle relations for the four tryads
+	select = (
+		   std::fabs(l1-l2) <= l3 && l3 <= l1+l2
+		&& std::fabs(l1-l5) <= l6 && l6 <= l1+l5
+		&& std::fabs(l4-l2) <= l6 && l6 <= l4+l2
+		&& std::fabs(l4-l5) <= l3 && l3 <= l4+l5
+		);
+
+	// Sum rule of the tryads
+	select = (
+		   std::floor(l1+l2+l3)==(l1+l2+l3)
+		&& std::floor(l1+l5+l6)==(l1+l5+l6)
+		&& std::floor(l4+l2+l6)==(l4+l2+l6)
+		&& std::floor(l4+l5+l3)==(l4+l5+l3)
+		);
+
+	if (!select) return 0.0;
+
+	// We compute l1min and the position of the array we will want.
+	double l1min = std::max(std::fabs(l2-l3),std::fabs(l5-l6));
+	int index = (int)(l1-l1min);
+
+	return wigner6j(l2,l3,l4,l5,l6)[index];
+}
+
+double wigner3j_auxA(double l1, double l2, double l3,
+						double m1, double m2, double m3)
+{
+	double T1 = l1*l1-pow(l2-l3,2.0);
+	double T2 = pow(l2+l3+1.0,2.0)-l1*l1;
+	double T3 = l1*l1-m1*m1;
+
+	return sqrt(T1*T2*T3);
+}
+
+double wigner3j_auxB(double l1, double l2, double l3,
+						double m1, double m2, double m3)
+{
+	double T1 = -(2.0*l1+1.0);
+	double T2 = l2*(l2+1.0)*m1;
+	double T3 = l3*(l3+1.0)*m1;
+	double T4 = l1*(l1+1.0)*(m3-m2);
+
+	return T1*(T2-T3-T4);
+}
+
+double wigner6j_auxA(double l1, double l2, double l3,
+						double l4, double l5, double l6)
+{
+	double T1 = l1*l1-pow(l2-l3,2.0);
+	double T2 = pow(l2+l3+1.0,2.0)-l1*l1;
+	double T3 = l1*l1-pow(l5-l6,2.0);
+	double T4 = pow(l5+l6+1.0,2.0)-l1*l1;
+
+	return sqrt(T1*T2*T3*T4);
+}
+
+double wigner6j_auxB(double l1, double l2, double l3,
+						double l4, double l5, double l6)
+{
+	double T0 = 2.0*l1+1.0;
+
+	double T1 = l1*(l1+1.0);
+	double T2 = -l1*(l1+1.0)+l2*(l2+1.0)+l3*(l3+1.0);
+
+	double T3 = l5*(l5+1.0);
+	double T4 = l1*(l1+1.0)+l2*(l2+1.0)-l3*(l3+1.0);
+
+	double T5 = l6*(l6+1.0);
+	double T6 = l1*(l1+1.0)-l2*(l2+1.0)+l3*(l3+1.0);
+
+	double T7 = 2.0*l1*(l1+1.0)*l4*(l4+1.0);
+
+	return (T0*(T1*T2+T3*T4+T5*T6-T7));
+}
+}
diff --git a/src/soap/linalg/wigner.hpp b/src/soap/linalg/wigner.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb90d534379b0261a7a2f33811e71e54c06ae3a6
--- /dev/null
+++ b/src/soap/linalg/wigner.hpp
@@ -0,0 +1,87 @@
+/*******************************************************-/
+ * This source code is subject to the terms of the GNU  -/
+ * Lesser Public License. If a copy of the LGPL was not -/
+ * distributed with this file, you can obtain one at    -/
+ * https://www.gnu.org/licenses/lgpl.html.              -/
+ ********************************************************/
+
+#ifndef WIGNER_SYMBOLS_CPP_H
+#define WIGNER_SYMBOLS_CPP_H
+
+/** \file wignerSymbols-cpp.h
+ *
+ * 	\author Joey Dumont <joey.dumont@gmail.com>
+ *
+ * 	\since 2013-08-16
+ *
+ * 	\brief Defines utility functions for the evaluation of Wigner-3j and -6j symbols.
+ *
+ * We compute the Wigner-3j and -6j symbols
+ * f(L1) = (  L1   L2 L3)
+ *         (-M2-M3 M2 M3)
+ * for all allowed values of L1, the other parameters
+ * being held fixed. The algorithm is based on the work
+ * by Schulten and Gordon.
+ * 	K. Schulten, "Exact recursive evaluation of 3j- and 6j-coefficients for quantum-mechanical coupling of angular momenta," 
+ *		J. Math. Phys. 16, 1961 (1975).
+ *  K. Schulten and R. G. Gordon, "Recursive evaluation of 3j and 6j coefficients,"
+ *		Comput. Phys. Commun. 11, 269–278 (1976).
+ */
+
+#include <cmath>
+#include <limits>
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+namespace WignerSymbols {
+
+template <typename T>
+double sgn(T val)
+{
+    int sgn = (T(0) < val) - (val < T(0));
+    if (sgn == 0)
+        return 1.0;
+    else
+        return (double)sgn;
+}
+
+/*! @name Evaluation of Wigner-3j and -6j symbols.
+ * We implement Schulten's algorithm in C++.
+ */
+///@{
+std::vector<double> wigner3j(double l2, double l3,
+						double m1, double m2, double m3);
+
+double wigner3j(double l1, double l2, double l3,
+					double m1, double m2, double m3);
+
+double wigner3j_auxA(double l1, double l2, double l3,
+						double m1, double m2, double m3);
+double wigner3j_auxB(double l1, double l2, double l3,
+						double m1, double m2, double m3);
+
+std::vector<double> wigner6j(double l2, double l3,
+						double l4, double l5, double l6);
+
+double wigner6j(double l1, double l2, double l3,
+					double l4, double l5, double l6);
+
+double wigner6j_auxA(double l1, double l2, double l3,
+						double l4, double l5, double l6);
+
+double wigner6j_auxB(double l1, double l2, double l3,
+						double l4, double l5, double l6);
+
+/*! Computes the Clebsch-Gordan coefficient by relating it to the
+ * Wigner 3j symbol. It sometimes eases the notation to use the
+ * Clebsch-Gordan coefficients directly. */
+inline double clebschGordan(double l1, double l2, double l3,
+							double m1, double m2, double m3)
+{
+	// We simply compute it via the 3j symbol.
+	return (pow(-1.0,l1-l2+m3)*sqrt(2.0*l3+1.0)*wigner3j(l1,l2,l3,m1,m2,-m3));
+}
+}
+
+#endif  // WIGNER_SYMBOLS_CPP_H