[gnumeric] EIGEN: change to use GnmMatrix.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] EIGEN: change to use GnmMatrix.
- Date: Fri, 18 Jan 2013 20:21:37 +0000 (UTC)
commit 7e60229a8b22a2d511281e8ce28eba256727bff4
Author: Morten Welinder <terra gnome org>
Date: Fri Jan 18 15:21:19 2013 -0500
EIGEN: change to use GnmMatrix.
ChangeLog | 1 +
plugins/fn-math/ChangeLog | 1 +
plugins/fn-math/functions.c | 131 +++++++++++++++++++++----------------------
src/mathfunc.c | 16 ++++-
src/mathfunc.h | 3 +-
5 files changed, 80 insertions(+), 72 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 71b5d38..b915085 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@
(gnm_matrix_is_empty, gnm_matrix_from_value, gnm_matrix_to_value):
New matrix support.
(gnm_matrix_multiply): Renamed from mmult and changed to use above.
+ (gnm_matrix_eigen): Change to take GnmMatrix arguments.
2013-01-15 Morten Welinder <terra gnome org>
diff --git a/plugins/fn-math/ChangeLog b/plugins/fn-math/ChangeLog
index f501fcb..9ecb33e 100644
--- a/plugins/fn-math/ChangeLog
+++ b/plugins/fn-math/ChangeLog
@@ -3,6 +3,7 @@
* functions.c (gnumeric_minverse, gnumeric_mmult)
(gnumeric_leverage, gnumeric_linsolve, gnumeric_mdeterm): Simplify
using new matrix support.
+ (compare_gnumeric_eigen_ev): Sort first by absolute value.
2013-01-17 Morten Welinder <terra gnome org>
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index cd0bf1e..bdb76ad 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -3141,18 +3141,6 @@ static GnmFuncHelp const help_eigen[] = {
};
-static gnm_float **
-new_matrix (int cols, int rows)
-{
- gnm_float **res = g_new (gnm_float *, rows);
- int r;
-
- for (r = 0; r < rows; r++)
- res[r] = g_new0 (gnm_float, cols);
-
- return res;
-}
-
typedef struct {
gnm_float val;
int index;
@@ -3161,81 +3149,92 @@ typedef struct {
static int
compare_gnumeric_eigen_ev (const void *a, const void *b)
{
- const gnumeric_eigen_ev_t *da = a;
- const gnumeric_eigen_ev_t *db = b;
+ const gnumeric_eigen_ev_t *da = a;
+ const gnumeric_eigen_ev_t *db = b;
+ gnm_float ea = da->val;
+ gnm_float eb = db->val;
+
+ /* Compare first by magnitude (descending). */
+ if (gnm_abs (ea) > gnm_abs (eb))
+ return -1;
+ else if (gnm_abs (ea) < gnm_abs (eb))
+ return +1;
+
+ /* Then by value (still descending. */
+ if (ea > eb)
+ return -1;
+ else if (ea < eb)
+ return +1;
+ else
+ return 0;
+}
- if (da->val > db->val)
- return -1;
- else if (da->val == db->val)
- return 0;
- else
- return 1;
+static gboolean
+symmetric (GnmMatrix const *m)
+{
+ int c, r;
+
+ if (m->cols != m->rows)
+ return FALSE;
+
+ for (c = 0; c < m->cols; ++c)
+ for (r = c + 1; r < m->rows; ++r)
+ if (m->data[r][c] != m->data[c][r])
+ return FALSE;
+
+ return TRUE;
}
static GnmValue *
gnumeric_eigen (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- GnmEvalPos const * const ep = ei->pos;
-
- int r, rows;
- int c, cols;
- GnmValue *res;
- GnmValue const *values = argv[0];
- gnm_float **matrix;
- gnm_float **eigenvectors;
- gnm_float *eigenvalues;
- GnmStdError err;
+ GnmMatrix *A = NULL;
+ GnmMatrix *EIG = NULL;
+ gnm_float *eigenvalues = NULL;
+ GnmValue *res = NULL;
+ int i, c, r;
gnumeric_eigen_ev_t *ev_sort;
- if (validate_range_numeric_matrix (ep, values, &rows, &cols, &err))
- return value_new_error_std (ei->pos, err);
-
- /* Guarantee shape and non-zero size */
- if (cols != rows || !rows || !cols)
- return value_new_error_VALUE (ei->pos);
-
- matrix = value_to_matrix (values, cols, rows, ep);
+ A = gnm_matrix_from_value (argv[0], &res, ei->pos);
+ if (!A) goto out;
- /* Check for symmetry */
- for (c = 0; c < cols; ++c)
- for (r = c + 1; r < rows; ++r)
- if (matrix[r][c] != matrix[c][r]) {
- free_matrix (matrix, cols, rows);
- return value_new_error_NUM (ei->pos);
- }
+ if (A->cols != A->rows || gnm_matrix_is_empty (A) || !symmetric (A)) {
+ res = value_new_error_VALUE (ei->pos);
+ goto out;
+ }
- eigenvectors = new_matrix (rows, cols);
- eigenvalues = g_new0 (gnm_float, cols);
+ EIG = gnm_matrix_new (A->rows, A->cols);
+ eigenvalues = g_new0 (gnm_float, A->cols);
- if (!gnm_matrix_eigen (matrix, eigenvectors, eigenvalues, cols)) {
- free_matrix (matrix, cols, rows);
- free_matrix (eigenvectors, cols, rows);
- g_free (eigenvalues);
- return value_new_error_NUM (ei->pos);
+ if (!gnm_matrix_eigen (A, EIG, eigenvalues)) {
+ res = value_new_error_NUM (ei->pos);
+ goto out;
}
/* Sorting eigenvalues */
- ev_sort = g_new (gnumeric_eigen_ev_t, cols);
- for (c = 0; c < cols; ++c) {
- ev_sort[c].val = eigenvalues[c];
- ev_sort[c].index = c;
+ ev_sort = g_new (gnumeric_eigen_ev_t, A->cols);
+ for (i = 0; i < A->cols; i++) {
+ ev_sort[i].val = eigenvalues[i];
+ ev_sort[i].index = i;
}
- qsort (ev_sort, cols, sizeof (gnumeric_eigen_ev_t), compare_gnumeric_eigen_ev);
+ qsort (ev_sort, A->cols, sizeof (gnumeric_eigen_ev_t), compare_gnumeric_eigen_ev);
- res = value_new_array_non_init (cols, rows + 1);
- for (c = 0; c < cols; ++c) {
- res->v_array.vals[c] = g_new (GnmValue *, rows + 1);
+ res = value_new_array_non_init (A->cols, A->rows + 1);
+ for (c = 0; c < A->cols; ++c) {
+ res->v_array.vals[c] = g_new (GnmValue *, A->rows + 1);
res->v_array.vals[c][0] = value_new_float (eigenvalues[ev_sort[c].index]);
- for (r = 0; r < rows; ++r) {
- gnm_float tmp = eigenvectors[r][ev_sort[c].index];
- res->v_array.vals[c][r+1] = value_new_float (tmp);
+ for (r = 0; r < A->rows; ++r) {
+ gnm_float tmp = EIG->data[r][ev_sort[c].index];
+ res->v_array.vals[c][r + 1] = value_new_float (tmp);
}
}
- free_matrix (matrix, cols, rows);
- free_matrix (eigenvectors, cols, rows);
- g_free (eigenvalues);
+
g_free (ev_sort);
+out:
+ if (A) gnm_matrix_free (A);
+ if (EIG) gnm_matrix_free (EIG);
+ g_free (eigenvalues);
return res;
}
diff --git a/src/mathfunc.c b/src/mathfunc.c
index e2d48f7..2829649 100644
--- a/src/mathfunc.c
+++ b/src/mathfunc.c
@@ -6631,16 +6631,24 @@ gnm_matrix_eigen_update (guint k, gnm_float t, gnm_float *eigenvalues, gboolean
* magnitude of off-diagonal elements while preserving eigenvalues.
*/
gboolean
-gnm_matrix_eigen (gnm_float **matrix, gnm_float **eigenvectors, gnm_float *eigenvalues, int size)
+gnm_matrix_eigen (GnmMatrix const *m, GnmMatrix *EIG, gnm_float *eigenvalues)
{
guint i, state, usize, *ind;
gboolean *changed;
guint counter = 0;
+ gnm_float **matrix;
+ gnm_float **eigenvectors;
- if (size < 1)
- return FALSE;
+ g_return_val_if_fail (m != NULL, FALSE);
+ g_return_val_if_fail (m->rows == m->cols, FALSE);
+ g_return_val_if_fail (EIG != NULL, FALSE);
+ g_return_val_if_fail (EIG->rows == EIG->cols, FALSE);
+ g_return_val_if_fail (EIG->rows == m->rows, FALSE);
+
+ matrix = m->data;
+ eigenvectors = EIG->data;
+ usize = m->rows;
- usize = (guint) size;
state = usize;
ind = g_new (guint, usize);
diff --git a/src/mathfunc.h b/src/mathfunc.h
index 075d926..d737b3f 100644
--- a/src/mathfunc.h
+++ b/src/mathfunc.h
@@ -161,8 +161,7 @@ gboolean gnm_matrix_is_empty (GnmMatrix const *m);
void gnm_matrix_multiply (GnmMatrix *C, const GnmMatrix *A, const GnmMatrix *B);
-gboolean gnm_matrix_eigen (gnm_float **matrix, gnm_float **eigenvectors,
- gnm_float *eigenvalues, int size);
+gboolean gnm_matrix_eigen (GnmMatrix const *m, GnmMatrix *EIG, gnm_float *eigenvalues);
/* ------------------------------------------------------------------------- */
gnm_float combin (gnm_float n, gnm_float k);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]