/*
 *  $Id: gsl.c,v 1.1 2000/07/08 15:21:24 danny Exp $
 *
 *  This file is part of Oleo, the GNU spreadsheet.
 *
 *  Copyright © 2000 by the Free Software Foundation, Inc.
 *  Written by Danny Backx <danny@gnu.org>.
 *
 *  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.
 */

/*
 * This file defines some GSL access functions for Oleo
 */

static char rcsid[] = "$Id: gsl.c,v 1.1 2000/07/08 15:21:24 danny Exp $";

#ifdef	HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef	WITH_DMALLOC
#include <dstdlib.h>
#endif

#include "funcdef.h"
#include "sysdef.h"

#include "global.h"
#include "cell.h"
#include "eval.h"
#include "errors.h"
#include "ref.h"

/*
 * Declarations necessary for defining an Oleo function
 */
struct value
  {
    int type;
    union vals x;
  };

#define Float   x.c_d
#define String  x.c_s
#define Int     x.c_l
#define Value   x.c_i
#define Rng     x.c_r

#ifdef	HAVE_GSL
#include <gsl/gsl_math.h>
#include <gsl/gsl_statistics_double.h>
#include <gsl/gsl_poly.h>

typedef double (*GSL_F_A)(const double data[], size_t stride, size_t n);
typedef double (*GSL_F_AF)(const double data[], size_t stride, size_t n, double d);
typedef double (*GSL_F_AFF)(const double data[], size_t stride, size_t n, double d, double e);

/*
 * This internal function does the dirty work of grabbing an Oleo range
 * and putting the numbers into an array of doubles.
 * Then it calls the GSL function in its second argument, and returns the result.
 */
static double
oleo_gsl_call_array(struct value *p, GSL_F_A f)
{
	double		*data, r;
	int		n;
	struct rng	rngx = p->Rng;
	CELL		*cp;

	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range()))
		if (GET_TYP(cp) == TYP_FLT)
			n++;

	data = (double *)calloc(n, sizeof(double));
	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range())) {
		if (GET_TYP(cp) == TYP_FLT) {
			data[n] = cp->cell_flt;
			n++;
		}
	}

	r = (*f)(data, 1, n);

	free(data);

	return r;
}

static double
oleo_gsl_call_array_double(struct value *p, GSL_F_AF f)
{
	double		*data, r,
			d = (p+1)->Float;
	int		n;
	struct rng	rngx = p->Rng;
	CELL		*cp;

	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range()))
		if (GET_TYP(cp) == TYP_FLT)
			n++;

	data = (double *)calloc(n, sizeof(double));
	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range())) {
		if (GET_TYP(cp) == TYP_FLT) {
			data[n] = cp->cell_flt;
			n++;
		}
	}

	r = (*f)(data, 1, n, d);

	free(data);

	return r;
}

static double
oleo_gsl_call_array_double_double(struct value *p, GSL_F_AFF f)
{
	double		*data, r,
			d = (p+1)->Float,
			e = (p+2)->Float;
	int		n;
	struct rng	rngx = p->Rng;
	CELL		*cp;

	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range()))
		if (GET_TYP(cp) == TYP_FLT)
			n++;

	data = (double *)calloc(n, sizeof(double));
	n = 0;
	make_cells_in_range(&rngx);
        while ((cp = next_cell_in_range())) {
		if (GET_TYP(cp) == TYP_FLT) {
			data[n] = cp->cell_flt;
			n++;
		}
	}

	r = (*f)(data, 1, n, d, e);

	free(data);

	return r;
}

/*
 * Statistical functions
 */
static void
oleo_gsl_stats_variance(struct value *p)
{
	GSL_F_A		f = gsl_stats_variance;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_variance_m(struct value *p)
{
	GSL_F_AF		f = gsl_stats_variance_m;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_variance_with_fixed_mean(struct value *p)
{
	GSL_F_AF		f = gsl_stats_variance_with_fixed_mean;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_mean(struct value *p)
{
	GSL_F_A		f = gsl_stats_mean;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_sd(struct value *p)
{
	GSL_F_A		f = gsl_stats_sd;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_sd_m(struct value *p)
{
	GSL_F_AF		f = gsl_stats_sd_m;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_sd_with_fixed_mean(struct value *p)
{
	GSL_F_AF		f = gsl_stats_sd_with_fixed_mean;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_absdev(struct value *p)
{
	GSL_F_A		f = gsl_stats_absdev;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_absdev_m(struct value *p)
{
	GSL_F_AF		f = gsl_stats_absdev_m;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_skew(struct value *p)
{
	GSL_F_A		f = gsl_stats_skew;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_skew_m_sd(struct value *p)
{
	GSL_F_AFF		f = gsl_stats_skew_m_sd;
	p->Float = oleo_gsl_call_array_double_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_kurtosis(struct value *p)
{
	GSL_F_A		f = gsl_stats_kurtosis;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_kurtosis_m_sd(struct value *p)
{
	GSL_F_AFF		f = gsl_stats_kurtosis_m_sd;
	p->Float = oleo_gsl_call_array_double_double(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_lag1_autocorrelation(struct value *p)
{
	GSL_F_A		f = gsl_stats_lag1_autocorrelation;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_median_from_sorted_data(struct value *p)
{
	GSL_F_A		f = gsl_stats_median_from_sorted_data;
	p->Float = oleo_gsl_call_array(p, f);
	p->type = TYP_FLT;
}

static void
oleo_gsl_stats_quantile_from_sorted_data(struct value *p)
{
	GSL_F_AF		f = gsl_stats_quantile_from_sorted_data;
	p->Float = oleo_gsl_call_array_double(p, f);
	p->type = TYP_FLT;
}

/*
 * Polynomial functions
 */
static void
oleo_gsl_poly_solve_quadratic(struct value *p)
{
	double	a = (p+0)->Float,
		b = (p+1)->Float,
		c = (p+2)->Float,
		d = 0.0,
		e = 0.0;
	struct rng	rg = (p+3)->Rng;
	char	*r, s;
	union vals	v;

	gsl_poly_solve_quadratic(a, b, c, &d, &e);

	/* lr, lc, hr, hc */
	v.c_d = d;
	r = set_new_value(rg.lr, rg.lc, TYP_FLT, &v);
	v.c_d = e;
	r = set_new_value(rg.lr, rg.lc, TYP_FLT, &v);
}

static void
oleo_gsl_poly_solve_quadratic1(struct value *p)
{
	double	a = p->Float,
		b = (p+1)->Float,
		c = (p+2)->Float,
		d, e;

	gsl_poly_solve_quadratic(a, b, c, &d, &e);

	p->Float = d;
}

static void
oleo_gsl_poly_solve_quadratic2(struct value *p)
{
	double	a = p->Float,
		b = (p+1)->Float,
		c = (p+2)->Float,
		d, e;

	gsl_poly_solve_quadratic(a, b, c, &d, &e);

	p->Float = e;
}
#endif

/*
 * Define Oleo functions
 *
 * This part must always be compiled and linked, the table gets rather empty
 * when building without GSL however.
 */
struct function gsl_functions[] = {
#ifdef	HAVE_GSL
/*
 * Statistics functions
 */
	{ C_FN1, X_A1, "R", oleo_gsl_stats_mean, "gsl_stats_mean" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_variance, "gsl_stats_variance" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_sd, "gsl_stats_sd" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_absdev, "gsl_stats_absdev" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_skew, "gsl_stats_skew" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_kurtosis, "gsl_stats_kurtosis" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_lag1_autocorrelation, "gsl_stats_lag1_autocorrelation" },
	{ C_FN1, X_A1, "R", oleo_gsl_stats_median_from_sorted_data, "gsl_stats_median_from_sorted_data" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_quantile_from_sorted_data, "gsl_stats_quantile_from_sorted_data" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_variance_m, "gsl_stats_variance_m" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_sd_m, "gsl_stats_sd_m" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_variance_with_fixed_mean, "gsl_stats_variance_with_fixed_mean" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_sd_with_fixed_mean, "gsl_stats_sd_with_fixed_mean" },
	{ C_FN2, X_A2, "RF", oleo_gsl_stats_absdev_m, "gsl_stats_absdev_m" },
	{ C_FN3, X_A3, "RFF", oleo_gsl_stats_skew_m_sd, "gsl_stats_skew_m_sd" },
	{ C_FN3, X_A3, "RFF", oleo_gsl_stats_kurtosis_m_sd, "gsl_stats_kurtosis_m_sd" },

/*
 * Polynomial functions
 */
	{ C_FN3, X_A3, "FFF", oleo_gsl_poly_solve_quadratic1, "gsl_poly_solve_quadratic1" },
	{ C_FN3, X_A3, "FFF", oleo_gsl_poly_solve_quadratic2, "gsl_poly_solve_quadratic2" },
/*	{ C_FN4, X_A4, "FFFR", oleo_gsl_poly_solve_quadratic, "gsl_poly_solve_quadratic" }, */

	/* Add new GSL functions here, not outside the #if/#endif pair. */
#endif
	{ 0, 0, "", 0, 0 }
};

int init_gsl_function_count(void) 
{
        return sizeof(gsl_functions) / sizeof(struct function) - 1;
}


syntax highlighted by Code2HTML, v. 0.9.1