pxop.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /**************************************************************************
  2. **
  3. ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
  4. **
  5. ** Meschach Library
  6. **
  7. ** This Meschach Library is provided "as is" without any express
  8. ** or implied warranty of any kind with respect to this software.
  9. ** In particular the authors shall not be liable for any direct,
  10. ** indirect, special, incidental or consequential damages arising
  11. ** in any way from use of the software.
  12. **
  13. ** Everyone is granted permission to copy, modify and redistribute this
  14. ** Meschach Library, provided:
  15. ** 1. All copies contain this copyright notice.
  16. ** 2. All modified copies shall carry a notice stating who
  17. ** made the last modification and the date of such modification.
  18. ** 3. No charge is made for this software or works derived from it.
  19. ** This clause shall not be construed as constraining other software
  20. ** distributed on the same medium as this software, nor is a
  21. ** distribution fee considered a charge.
  22. **
  23. ***************************************************************************/
  24. /* pxop.c 1.5 12/03/87 */
  25. #include <stdio.h>
  26. #include "matrix.h"
  27. static char rcsid[] = "$Id: pxop.c,v 1.6 1995/06/08 14:57:11 des Exp $";
  28. /**********************************************************************
  29. Note: A permutation is often interpreted as a matrix
  30. (i.e. a permutation matrix).
  31. A permutation px represents a permutation matrix P where
  32. P[i][j] == 1 if and only if px->pe[i] == j
  33. **********************************************************************/
  34. /* px_inv -- invert permutation -- in situ
  35. -- taken from ACM Collected Algorithms #250 */
  36. #ifndef ANSI_C
  37. PERM *px_inv(px,out)
  38. PERM *px, *out;
  39. #else
  40. PERM *px_inv(const PERM *px, PERM *out)
  41. #endif
  42. {
  43. int i, j, k, n, *p;
  44. out = px_copy(px, out);
  45. n = out->size;
  46. p = (int *)(out->pe);
  47. for ( n--; n>=0; n-- )
  48. {
  49. i = p[n];
  50. if ( i < 0 ) p[n] = -1 - i;
  51. else if ( i != n )
  52. {
  53. k = n;
  54. while (TRUE)
  55. {
  56. if ( i < 0 || i >= out->size )
  57. error(E_BOUNDS,"px_inv");
  58. j = p[i]; p[i] = -1 - k;
  59. if ( j == n )
  60. { p[n] = i; break; }
  61. k = i; i = j;
  62. }
  63. }
  64. }
  65. return out;
  66. }
  67. /* px_mlt -- permutation multiplication (composition) */
  68. #ifndef ANSI_C
  69. PERM *px_mlt(px1,px2,out)
  70. PERM *px1,*px2,*out;
  71. #else
  72. PERM *px_mlt(const PERM *px1, const PERM *px2, PERM *out)
  73. #endif
  74. {
  75. unsigned int i,size;
  76. if ( px1==(PERM *)NULL || px2==(PERM *)NULL )
  77. error(E_NULL,"px_mlt");
  78. if ( px1->size != px2->size )
  79. error(E_SIZES,"px_mlt");
  80. if ( px1 == out || px2 == out )
  81. error(E_INSITU,"px_mlt");
  82. if ( out==(PERM *)NULL || out->size < px1->size )
  83. out = px_resize(out,px1->size);
  84. size = px1->size;
  85. for ( i=0; i<size; i++ )
  86. if ( px2->pe[i] >= size )
  87. error(E_BOUNDS,"px_mlt");
  88. else
  89. out->pe[i] = px1->pe[px2->pe[i]];
  90. return out;
  91. }
  92. /* px_vec -- permute vector */
  93. #ifndef ANSI_C
  94. VEC *px_vec(px,vector,out)
  95. PERM *px;
  96. VEC *vector,*out;
  97. #else
  98. VEC *px_vec(PERM *px, const VEC *vector, VEC *out)
  99. #endif
  100. {
  101. unsigned int old_i, i, size, start;
  102. Real tmp;
  103. if ( px==PNULL || vector==VNULL )
  104. error(E_NULL,"px_vec");
  105. if ( px->size > vector->dim )
  106. error(E_SIZES,"px_vec");
  107. if ( out==VNULL || out->dim < vector->dim )
  108. out = v_resize(out,vector->dim);
  109. size = px->size;
  110. if ( size == 0 )
  111. return v_copy(vector,out);
  112. if ( out != vector )
  113. {
  114. for ( i=0; i<size; i++ )
  115. if ( px->pe[i] >= size )
  116. error(E_BOUNDS,"px_vec");
  117. else
  118. out->ve[i] = vector->ve[px->pe[i]];
  119. }
  120. else
  121. { /* in situ algorithm */
  122. start = 0;
  123. while ( start < size )
  124. {
  125. old_i = start;
  126. i = px->pe[old_i];
  127. if ( i >= size )
  128. {
  129. start++;
  130. continue;
  131. }
  132. tmp = vector->ve[start];
  133. while ( TRUE )
  134. {
  135. vector->ve[old_i] = vector->ve[i];
  136. px->pe[old_i] = i+size;
  137. old_i = i;
  138. i = px->pe[old_i];
  139. if ( i >= size )
  140. break;
  141. if ( i == start )
  142. {
  143. vector->ve[old_i] = tmp;
  144. px->pe[old_i] = i+size;
  145. break;
  146. }
  147. }
  148. start++;
  149. }
  150. for ( i = 0; i < size; i++ )
  151. if ( px->pe[i] < size )
  152. error(E_BOUNDS,"px_vec");
  153. else
  154. px->pe[i] = px->pe[i]-size;
  155. }
  156. return out;
  157. }
  158. /* pxinv_vec -- apply the inverse of px to x, returning the result in out */
  159. #ifndef ANSI_C
  160. VEC *pxinv_vec(px,x,out)
  161. PERM *px;
  162. VEC *x, *out;
  163. #else
  164. VEC *pxinv_vec(PERM *px, const VEC *x, VEC *out)
  165. #endif
  166. {
  167. unsigned int i, size;
  168. if ( ! px || ! x )
  169. error(E_NULL,"pxinv_vec");
  170. if ( px->size > x->dim )
  171. error(E_SIZES,"pxinv_vec");
  172. /* if ( x == out )
  173. error(E_INSITU,"pxinv_vec"); */
  174. if ( ! out || out->dim < x->dim )
  175. out = v_resize(out,x->dim);
  176. size = px->size;
  177. if ( size == 0 )
  178. return v_copy(x,out);
  179. if ( out != x )
  180. {
  181. for ( i=0; i<size; i++ )
  182. if ( px->pe[i] >= size )
  183. error(E_BOUNDS,"pxinv_vec");
  184. else
  185. out->ve[px->pe[i]] = x->ve[i];
  186. }
  187. else
  188. { /* in situ algorithm --- cheat's way out */
  189. px_inv(px,px);
  190. px_vec(px,x,out);
  191. px_inv(px,px);
  192. }
  193. return out;
  194. }
  195. /* px_transp -- transpose elements of permutation
  196. -- Really multiplying a permutation by a transposition */
  197. #ifndef ANSI_C
  198. PERM *px_transp(px,i1,i2)
  199. PERM *px; /* permutation to transpose */
  200. unsigned int i1,i2; /* elements to transpose */
  201. #else
  202. PERM *px_transp(PERM *px, unsigned int i1, unsigned int i2)
  203. #endif
  204. {
  205. unsigned int temp;
  206. if ( px==(PERM *)NULL )
  207. error(E_NULL,"px_transp");
  208. if ( i1 < px->size && i2 < px->size )
  209. {
  210. temp = px->pe[i1];
  211. px->pe[i1] = px->pe[i2];
  212. px->pe[i2] = temp;
  213. }
  214. return px;
  215. }
  216. /* myqsort -- a cheap implementation of Quicksort on integers
  217. -- returns number of swaps */
  218. #ifndef ANSI_C
  219. static int myqsort(a,num)
  220. int *a, num;
  221. #else
  222. static int myqsort(int *a, int num)
  223. #endif
  224. {
  225. int i, j, tmp, v;
  226. int numswaps;
  227. numswaps = 0;
  228. if ( num <= 1 )
  229. return 0;
  230. i = 0; j = num; v = a[0];
  231. for ( ; ; )
  232. {
  233. while ( a[++i] < v )
  234. ;
  235. while ( a[--j] > v )
  236. ;
  237. if ( i >= j ) break;
  238. tmp = a[i];
  239. a[i] = a[j];
  240. a[j] = tmp;
  241. numswaps++;
  242. }
  243. tmp = a[0];
  244. a[0] = a[j];
  245. a[j] = tmp;
  246. if ( j != 0 )
  247. numswaps++;
  248. numswaps += myqsort(&a[0],j);
  249. numswaps += myqsort(&a[j+1],num-(j+1));
  250. return numswaps;
  251. }
  252. /* px_sign -- compute the ``sign'' of a permutation = +/-1 where
  253. px is the product of an even/odd # transpositions */
  254. #ifndef ANSI_C
  255. int px_sign(px)
  256. PERM *px;
  257. #else
  258. int px_sign(const PERM *px)
  259. #endif
  260. {
  261. int numtransp;
  262. PERM *px2;
  263. if ( px==(PERM *)NULL )
  264. error(E_NULL,"px_sign");
  265. px2 = px_copy(px,PNULL);
  266. numtransp = myqsort((int *)px2->pe,px2->size);
  267. px_free(px2);
  268. return ( numtransp % 2 ) ? -1 : 1;
  269. }
  270. /* px_cols -- permute columns of matrix A; out = A.px'
  271. -- May NOT be in situ */
  272. #ifndef ANSI_C
  273. MAT *px_cols(px,A,out)
  274. PERM *px;
  275. MAT *A, *out;
  276. #else
  277. MAT *px_cols(const PERM *px, const MAT *A, MAT *out)
  278. #endif
  279. {
  280. int i, j, m, n, px_j;
  281. Real **A_me, **out_me;
  282. #ifdef ANSI_C
  283. MAT *m_get(int, int);
  284. #else
  285. extern MAT *m_get();
  286. #endif
  287. if ( ! A || ! px )
  288. error(E_NULL,"px_cols");
  289. if ( px->size != A->n )
  290. error(E_SIZES,"px_cols");
  291. if ( A == out )
  292. error(E_INSITU,"px_cols");
  293. m = A->m; n = A->n;
  294. if ( ! out || out->m != m || out->n != n )
  295. out = m_get(m,n);
  296. A_me = A->me; out_me = out->me;
  297. for ( j = 0; j < n; j++ )
  298. {
  299. px_j = px->pe[j];
  300. if ( px_j >= n )
  301. error(E_BOUNDS,"px_cols");
  302. for ( i = 0; i < m; i++ )
  303. out_me[i][px_j] = A_me[i][j];
  304. }
  305. return out;
  306. }
  307. /* px_rows -- permute columns of matrix A; out = px.A
  308. -- May NOT be in situ */
  309. #ifndef ANSI_C
  310. MAT *px_rows(px,A,out)
  311. PERM *px;
  312. MAT *A, *out;
  313. #else
  314. MAT *px_rows(const PERM *px, const MAT *A, MAT *out)
  315. #endif
  316. {
  317. int i, j, m, n, px_i;
  318. Real **A_me, **out_me;
  319. #ifdef ANSI_C
  320. MAT *m_get(int, int);
  321. #else
  322. extern MAT *m_get();
  323. #endif
  324. if ( ! A || ! px )
  325. error(E_NULL,"px_rows");
  326. if ( px->size != A->m )
  327. error(E_SIZES,"px_rows");
  328. if ( A == out )
  329. error(E_INSITU,"px_rows");
  330. m = A->m; n = A->n;
  331. if ( ! out || out->m != m || out->n != n )
  332. out = m_get(m,n);
  333. A_me = A->me; out_me = out->me;
  334. for ( i = 0; i < m; i++ )
  335. {
  336. px_i = px->pe[i];
  337. if ( px_i >= m )
  338. error(E_BOUNDS,"px_rows");
  339. for ( j = 0; j < n; j++ )
  340. out_me[i][j] = A_me[px_i][j];
  341. }
  342. return out;
  343. }