/* permutation/permute_source.c * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough * * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* In-place Permutations permute: OUT[i] = IN[perm[i]] i = 0 .. N-1 invpermute: OUT[perm[i]] = IN[i] i = 0 .. N-1 PERM is an index map, i.e. a vector which contains a permutation of the integers 0 .. N-1. From Knuth "Sorting and Searching", Volume 3 (3rd ed), Section 5.2 Exercise 10 (answers), p 617 FIXME: these have not been fully tested. */ int TYPE (gsl_permute) (const size_t * p, ATOMIC * data, const size_t stride, const size_t n) { size_t i, k, pk; for (i = 0; i < n; i++) { k = p[i]; while (k > i) k = p[k]; if (k < i) continue ; /* Now have k == i, i.e the least in its cycle */ pk = p[k]; if (pk == i) continue ; /* shuffle the elements of the cycle */ { unsigned int a; ATOMIC t[MULTIPLICITY]; for (a = 0; a < MULTIPLICITY; a++) t[a] = data[i*stride*MULTIPLICITY + a]; while (pk != i) { for (a = 0; a < MULTIPLICITY; a++) { ATOMIC r1 = data[pk*stride*MULTIPLICITY + a]; data[k*stride*MULTIPLICITY + a] = r1; } k = pk; pk = p[k]; }; for (a = 0; a < MULTIPLICITY; a++) data[k*stride*MULTIPLICITY + a] = t[a]; } } return GSL_SUCCESS; } int FUNCTION (gsl_permute,inverse) (const size_t * p, ATOMIC * data, const size_t stride, const size_t n) { size_t i, k, pk; for (i = 0; i < n; i++) { k = p[i]; while (k > i) k = p[k]; if (k < i) continue ; /* Now have k == i, i.e the least in its cycle */ pk = p[k]; if (pk == i) continue ; /* shuffle the elements of the cycle in the inverse direction */ { unsigned int a; ATOMIC t[MULTIPLICITY]; for (a = 0; a < MULTIPLICITY; a++) t[a] = data[k*stride*MULTIPLICITY+a]; while (pk != i) { for (a = 0; a < MULTIPLICITY; a++) { ATOMIC r1 = data[pk*stride*MULTIPLICITY + a]; data[pk*stride*MULTIPLICITY + a] = t[a]; t[a] = r1; } k = pk; pk = p[k]; }; for (a = 0; a < MULTIPLICITY; a++) data[pk*stride*MULTIPLICITY+a] = t[a]; } } return GSL_SUCCESS; } int TYPE (gsl_permute_vector) (const gsl_permutation * p, TYPE (gsl_vector) * v) { if (v->size != p->size) { GSL_ERROR ("vector and permutation must be the same length", GSL_EBADLEN); } TYPE (gsl_permute) (p->data, v->data, v->stride, v->size) ; return GSL_SUCCESS; } int FUNCTION (gsl_permute_vector,inverse) (const gsl_permutation * p, TYPE (gsl_vector) * v) { if (v->size != p->size) { GSL_ERROR ("vector and permutation must be the same length", GSL_EBADLEN); } FUNCTION (gsl_permute,inverse) (p->data, v->data, v->stride, v->size) ; return GSL_SUCCESS; } int TYPE (gsl_permute_matrix) (const gsl_permutation * p, TYPE (gsl_matrix) * A) { if (A->size2 != p->size) { GSL_ERROR ("matrix columns and permutation must be the same length", GSL_EBADLEN); } else { size_t i; for (i = 0; i < A->size1; ++i) { QUALIFIED_VIEW (gsl_vector, view) r = FUNCTION (gsl_matrix, row) (A, i); TYPE (gsl_permute_vector) (p, &r.vector); } return GSL_SUCCESS; } }