summaryrefslogtreecommitdiff
path: root/gsl-1.9/specfunc/mathieu_workspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/specfunc/mathieu_workspace.c')
-rw-r--r--gsl-1.9/specfunc/mathieu_workspace.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/gsl-1.9/specfunc/mathieu_workspace.c b/gsl-1.9/specfunc/mathieu_workspace.c
new file mode 100644
index 0000000..4b99180
--- /dev/null
+++ b/gsl-1.9/specfunc/mathieu_workspace.c
@@ -0,0 +1,202 @@
+/* specfunc/mathieu_workspace.c
+ *
+ * Copyright (C) 2003 Lowell Johnson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Author: L. Johnson */
+
+#include <config.h>
+#include <stdlib.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_sf_mathieu.h>
+
+
+gsl_sf_mathieu_workspace *gsl_sf_mathieu_alloc(const size_t nn,
+ const double qq)
+{
+ gsl_sf_mathieu_workspace *workspace;
+ unsigned int even_order = nn/2 + 1, odd_order = (nn + 1)/2,
+ extra_values;
+
+ /* Compute the maximum number of extra terms required for 10^-18 root
+ accuracy for a given value of q (contributed by Brian Gladman). */
+ extra_values = (int)(2.1*pow(fabs(qq), 0.37)) + 9;
+
+ if (nn + 1 == 0)
+ {
+ GSL_ERROR_NULL("matrix dimension must be positive integer", GSL_EINVAL);
+ }
+
+ workspace =
+ (gsl_sf_mathieu_workspace *)malloc(sizeof(gsl_sf_mathieu_workspace));
+ if (workspace == NULL)
+ {
+ GSL_ERROR_NULL("failed to allocate space for workspace", GSL_ENOMEM);
+ }
+
+ /* Extend matrices to ensure accuracy. */
+ even_order += extra_values;
+ odd_order += extra_values;
+
+ workspace->size = nn;
+ workspace->even_order = even_order;
+ workspace->odd_order = odd_order;
+ workspace->extra_values = extra_values;
+
+ /* Allocate space for the characteristic values. */
+ workspace->aa = (double *)malloc((nn+1)*sizeof(double));
+ if (workspace->aa == NULL)
+ {
+ free(workspace);
+ GSL_ERROR_NULL("Error allocating memory for characteristic a values",
+ GSL_ENOMEM);
+ }
+
+ workspace->bb = (double *)malloc((nn+1)*sizeof(double));
+ if (workspace->bb == NULL)
+ {
+ free(workspace->aa);
+ free(workspace);
+ GSL_ERROR_NULL("Error allocating memory for characteristic b values",
+ GSL_ENOMEM);
+ }
+
+ /* Since even_order is always >= odd_order, dimension the arrays for
+ even_order. */
+
+ workspace->dd = (double *)malloc(even_order*sizeof(double));
+ if (workspace->dd == NULL)
+ {
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for diagonal", GSL_ENOMEM);
+ }
+
+ workspace->ee = (double *)malloc(even_order*sizeof(double));
+ if (workspace->ee == NULL)
+ {
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for diagonal", GSL_ENOMEM);
+ }
+
+ workspace->tt = (double *)malloc(3*even_order*sizeof(double));
+ if (workspace->tt == NULL)
+ {
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for diagonal", GSL_ENOMEM);
+ }
+
+ workspace->e2 = (double *)malloc(even_order*sizeof(double));
+ if (workspace->e2 == NULL)
+ {
+ free(workspace->tt);
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for diagonal", GSL_ENOMEM);
+ }
+
+ workspace->zz = (double *)malloc(even_order*even_order*sizeof(double));
+ if (workspace->zz == NULL)
+ {
+ free(workspace->e2);
+ free(workspace->tt);
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for diagonal", GSL_ENOMEM);
+ }
+
+ workspace->eval = gsl_vector_alloc(even_order);
+
+ if (workspace->eval == NULL)
+ {
+ free(workspace->zz);
+ free(workspace->e2);
+ free(workspace->tt);
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for eval", GSL_ENOMEM);
+ }
+
+ workspace->evec = gsl_matrix_alloc(even_order, even_order);
+
+ if (workspace->evec == NULL)
+ {
+ gsl_vector_free (workspace->eval);
+ free(workspace->zz);
+ free(workspace->e2);
+ free(workspace->tt);
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for evec", GSL_ENOMEM);
+ }
+
+ workspace->wmat = gsl_eigen_symmv_alloc(even_order);
+
+ if (workspace->wmat == NULL)
+ {
+ gsl_matrix_free (workspace->evec);
+ gsl_vector_free (workspace->eval);
+ free(workspace->zz);
+ free(workspace->e2);
+ free(workspace->tt);
+ free(workspace->ee);
+ free(workspace->dd);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace);
+ GSL_ERROR_NULL("failed to allocate space for wmat", GSL_ENOMEM);
+ }
+
+ return workspace;
+}
+
+
+void gsl_sf_mathieu_free(gsl_sf_mathieu_workspace *workspace)
+{
+ gsl_vector_free(workspace->eval);
+ gsl_matrix_free(workspace->evec);
+ gsl_eigen_symmv_free(workspace->wmat);
+ free(workspace->aa);
+ free(workspace->bb);
+ free(workspace->dd);
+ free(workspace->ee);
+ free(workspace->tt);
+ free(workspace->e2);
+ free(workspace->zz);
+ free(workspace);
+}