transpose.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include "mpdecimal.h"
  28. #include <assert.h>
  29. #include <limits.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include "bits.h"
  34. #include "constants.h"
  35. #include "transpose.h"
  36. #include "typearith.h"
  37. #define BUFSIZE 4096
  38. #define SIDE 128
  39. /* Bignum: The transpose functions are used for very large transforms
  40. in sixstep.c and fourstep.c. */
  41. /* Definition of the matrix transpose */
  42. void
  43. std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols)
  44. {
  45. mpd_size_t idest, isrc;
  46. mpd_size_t r, c;
  47. for (r = 0; r < rows; r++) {
  48. isrc = r * cols;
  49. idest = r;
  50. for (c = 0; c < cols; c++) {
  51. dest[idest] = src[isrc];
  52. isrc += 1;
  53. idest += rows;
  54. }
  55. }
  56. }
  57. /*
  58. * Swap half-rows of 2^n * (2*2^n) matrix.
  59. * FORWARD_CYCLE: even/odd permutation of the halfrows.
  60. * BACKWARD_CYCLE: reverse the even/odd permutation.
  61. */
  62. static int
  63. swap_halfrows_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols, int dir)
  64. {
  65. mpd_uint_t buf1[BUFSIZE];
  66. mpd_uint_t buf2[BUFSIZE];
  67. mpd_uint_t *readbuf, *writebuf, *hp;
  68. mpd_size_t *done, dbits;
  69. mpd_size_t b = BUFSIZE, stride;
  70. mpd_size_t hn, hmax; /* halfrow number */
  71. mpd_size_t m, r=0;
  72. mpd_size_t offset;
  73. mpd_size_t next;
  74. assert(cols == mul_size_t(2, rows));
  75. if (dir == FORWARD_CYCLE) {
  76. r = rows;
  77. }
  78. else if (dir == BACKWARD_CYCLE) {
  79. r = 2;
  80. }
  81. else {
  82. abort(); /* GCOV_NOT_REACHED */
  83. }
  84. m = cols - 1;
  85. hmax = rows; /* cycles start at odd halfrows */
  86. dbits = 8 * sizeof *done;
  87. if ((done = mpd_calloc(hmax/(sizeof *done) + 1, sizeof *done)) == NULL) {
  88. return 0;
  89. }
  90. for (hn = 1; hn <= hmax; hn += 2) {
  91. if (done[hn/dbits] & mpd_bits[hn%dbits]) {
  92. continue;
  93. }
  94. readbuf = buf1; writebuf = buf2;
  95. for (offset = 0; offset < cols/2; offset += b) {
  96. stride = (offset + b < cols/2) ? b : cols/2-offset;
  97. hp = matrix + hn*cols/2;
  98. memcpy(readbuf, hp+offset, stride*(sizeof *readbuf));
  99. pointerswap(&readbuf, &writebuf);
  100. next = mulmod_size_t(hn, r, m);
  101. hp = matrix + next*cols/2;
  102. while (next != hn) {
  103. memcpy(readbuf, hp+offset, stride*(sizeof *readbuf));
  104. memcpy(hp+offset, writebuf, stride*(sizeof *writebuf));
  105. pointerswap(&readbuf, &writebuf);
  106. done[next/dbits] |= mpd_bits[next%dbits];
  107. next = mulmod_size_t(next, r, m);
  108. hp = matrix + next*cols/2;
  109. }
  110. memcpy(hp+offset, writebuf, stride*(sizeof *writebuf));
  111. done[hn/dbits] |= mpd_bits[hn%dbits];
  112. }
  113. }
  114. mpd_free(done);
  115. return 1;
  116. }
  117. /* In-place transpose of a square matrix */
  118. static inline void
  119. squaretrans(mpd_uint_t *buf, mpd_size_t cols)
  120. {
  121. mpd_uint_t tmp;
  122. mpd_size_t idest, isrc;
  123. mpd_size_t r, c;
  124. for (r = 0; r < cols; r++) {
  125. c = r+1;
  126. isrc = r*cols + c;
  127. idest = c*cols + r;
  128. for (c = r+1; c < cols; c++) {
  129. tmp = buf[isrc];
  130. buf[isrc] = buf[idest];
  131. buf[idest] = tmp;
  132. isrc += 1;
  133. idest += cols;
  134. }
  135. }
  136. }
  137. /*
  138. * Transpose 2^n * 2^n matrix. For cache efficiency, the matrix is split into
  139. * square blocks with side length 'SIDE'. First, the blocks are transposed,
  140. * then a square transposition is done on each individual block.
  141. */
  142. static void
  143. squaretrans_pow2(mpd_uint_t *matrix, mpd_size_t size)
  144. {
  145. mpd_uint_t buf1[SIDE*SIDE];
  146. mpd_uint_t buf2[SIDE*SIDE];
  147. mpd_uint_t *to, *from;
  148. mpd_size_t b = size;
  149. mpd_size_t r, c;
  150. mpd_size_t i;
  151. while (b > SIDE) b >>= 1;
  152. for (r = 0; r < size; r += b) {
  153. for (c = r; c < size; c += b) {
  154. from = matrix + r*size + c;
  155. to = buf1;
  156. for (i = 0; i < b; i++) {
  157. memcpy(to, from, b*(sizeof *to));
  158. from += size;
  159. to += b;
  160. }
  161. squaretrans(buf1, b);
  162. if (r == c) {
  163. to = matrix + r*size + c;
  164. from = buf1;
  165. for (i = 0; i < b; i++) {
  166. memcpy(to, from, b*(sizeof *to));
  167. from += b;
  168. to += size;
  169. }
  170. continue;
  171. }
  172. else {
  173. from = matrix + c*size + r;
  174. to = buf2;
  175. for (i = 0; i < b; i++) {
  176. memcpy(to, from, b*(sizeof *to));
  177. from += size;
  178. to += b;
  179. }
  180. squaretrans(buf2, b);
  181. to = matrix + c*size + r;
  182. from = buf1;
  183. for (i = 0; i < b; i++) {
  184. memcpy(to, from, b*(sizeof *to));
  185. from += b;
  186. to += size;
  187. }
  188. to = matrix + r*size + c;
  189. from = buf2;
  190. for (i = 0; i < b; i++) {
  191. memcpy(to, from, b*(sizeof *to));
  192. from += b;
  193. to += size;
  194. }
  195. }
  196. }
  197. }
  198. }
  199. /*
  200. * In-place transposition of a 2^n x 2^n or a 2^n x (2*2^n)
  201. * or a (2*2^n) x 2^n matrix.
  202. */
  203. int
  204. transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols)
  205. {
  206. mpd_size_t size = mul_size_t(rows, cols);
  207. assert(ispower2(rows));
  208. assert(ispower2(cols));
  209. if (cols == rows) {
  210. squaretrans_pow2(matrix, rows);
  211. }
  212. else if (cols == mul_size_t(2, rows)) {
  213. if (!swap_halfrows_pow2(matrix, rows, cols, FORWARD_CYCLE)) {
  214. return 0;
  215. }
  216. squaretrans_pow2(matrix, rows);
  217. squaretrans_pow2(matrix+(size/2), rows);
  218. }
  219. else if (rows == mul_size_t(2, cols)) {
  220. squaretrans_pow2(matrix, cols);
  221. squaretrans_pow2(matrix+(size/2), cols);
  222. if (!swap_halfrows_pow2(matrix, cols, rows, BACKWARD_CYCLE)) {
  223. return 0;
  224. }
  225. }
  226. else {
  227. abort(); /* GCOV_NOT_REACHED */
  228. }
  229. return 1;
  230. }