texperm.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
  3. * http://www.trevorwishart.co.uk
  4. * http://www.composersdesktop.com
  5. *
  6. This file is part of the CDP System.
  7. The CDP System is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  11. The CDP System is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with the CDP System; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307 USA
  19. *
  20. */
  21. /* floatsam version: no changes */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <structures.h>
  25. #include <tkglobals.h>
  26. #include <texture.h>
  27. #include <globcon.h>
  28. #include <arrays.h>
  29. #include <osbind.h>
  30. static void rndpermm(int k,int pindex,int **permm,dataptr dz);
  31. static void insert(int m,int t,int pindex,int **permm,dataptr dz);
  32. static void prefix(int m,int pindex,int **permm,dataptr dz);
  33. static void shuflup(int k,int pindex, int **permm,dataptr dz);
  34. /******************************** DOPERM *********************************
  35. *
  36. * Either deliver next item in a permuted set, or (if set exhausted)
  37. * generate a randon permutation of the set and deliver its first
  38. * element.
  39. *
  40. * (1) If this permset does not have the same length as the last...
  41. * (2) Set a new permset length.
  42. * (3) If a permset already exists (i.e. this is not first)
  43. * Free the permset space, and malloc a new space of correct size,
  44. * (4) Create a random permutation of elements into the permset.
  45. * (5) Set the pointer-to-the-set to 0.
  46. * (6) Set the size of the previous perm (which will be this one,
  47. * next time!) to this permset size.
  48. * (6a) Whether or not a new perm set has been set up...
  49. * (7) Get the value of the next item in the current permset,
  50. * incrementing the set pointer in the process.
  51. * (8) If this has the same value as the previous-one-output-from-doperm
  52. * increment the repetition counter.
  53. * (9) Otherwise set the repetition counter to 1.
  54. * (10) If the set pointer has run beyond the permset.
  55. * (11) reset the pointer to 0.
  56. * (12) generate a new random perm (of same length).
  57. * (13) Continue this process if the number of permissible repetitions
  58. * is exceeded.
  59. * (14) Set the value for lastpermval, for next call.
  60. * (15) Return the value.
  61. */
  62. int doperm(int k,int pindex,int *val,dataptr dz)
  63. {
  64. int i, OK;
  65. int **permm = dz->tex->perm;
  66. if(pindex >= PERMCNT) {
  67. sprintf(errstr,"doperm(): Perm index %d too big (max = %d)\n",pindex,PERMCNT);
  68. return(PROGRAM_ERROR);
  69. }
  70. if(k <= 1) {
  71. if(k>=0) {
  72. *val = 0;
  73. return(FINISHED);
  74. } else {
  75. sprintf(errstr,"doperm(): Invalid perm count %d\n",k);
  76. return(PROGRAM_ERROR);
  77. }
  78. }
  79. if((k*dz->iparray[TXRPT][pindex])!=dz->iparray[TXLASTPERMLEN][pindex]) { /* 1 */
  80. dz->iparray[TXPERMLEN][pindex] = (int)(k * dz->iparray[TXRPT][pindex]); /* 2 */
  81. if(permm[pindex] != (int *)0) /* 3 */
  82. free(permm[pindex]);
  83. if((permm[pindex] = (int *)malloc(dz->iparray[TXPERMLEN][pindex] * sizeof(int)))==NULL) {
  84. sprintf(errstr,"INSUFFICIENT MEMORY for permutation %d\n",pindex+1);
  85. return(MEMORY_ERROR);
  86. }
  87. rndpermm(k,pindex,permm,dz); /* 4 */
  88. dz->iparray[TXPERMINDEX][pindex] = 0; /* 5 */
  89. dz->iparray[TXLASTPERMLEN][pindex] = dz->iparray[TXPERMLEN][pindex]; /* 6 */
  90. }
  91. do { /* 6a */
  92. OK = 1;
  93. i = *(permm[pindex] + (dz->iparray[TXPERMINDEX][pindex]++)); /* 7 */
  94. if(i==dz->iparray[TXLASTPERMVAL][pindex]) { /* 8 */
  95. dz->iparray[TXREPETCNT][pindex]++;
  96. if(dz->iparray[TXREPETCNT][pindex]>dz->iparray[TXRPT][pindex]) {
  97. dz->iparray[TXREPETCNT][pindex] = dz->iparray[TXRPT][pindex];
  98. OK = 0;
  99. }
  100. } else {
  101. dz->iparray[TXREPETCNT][pindex]=1;
  102. }
  103. if(dz->iparray[TXPERMINDEX][pindex]>=dz->iparray[TXPERMLEN][pindex]) { /* 10 */
  104. dz->iparray[TXPERMINDEX][pindex] = 0; /* 11 */
  105. rndpermm(k,pindex,permm,dz); /* 12 */
  106. }
  107. }while(!OK); /* 13 */
  108. dz->iparray[TXLASTPERMVAL][pindex] = i; /* 14 */
  109. *val = i;
  110. return(FINISHED); /* 15 */
  111. }
  112. /*************************** RNDPERMM *******************************
  113. *
  114. * Produce a permutation of k objects and store it in permutation-store
  115. * number 'pindex'.
  116. *
  117. * (1) permlen is the number of objects (k) times the number of repetitions
  118. * permitted (rpt[pindex]) = N.
  119. * (2) This is the efficient algorithm for distributing N objects into
  120. * a random perm.
  121. * (3) As we really only have k objects, we take the value%rpt in each
  122. * permutation location.
  123. * e.g. 3 objects repeated 3 times would give us a random perm of
  124. * nine objects such as
  125. * 5 6 2 8 3 0 1 7 4
  126. * applying %3 to this we get
  127. * 2 0 2 2 0 0 1 1 1
  128. * i.e. a perm of 3 objects with no more than 3 consecutive repets
  129. * of any one object!!
  130. */
  131. void rndpermm(int k,int pindex,int **permm,dataptr dz)
  132. {
  133. int n, t;
  134. for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++) { /* 1 */
  135. t = (int)(drand48() * (double)(n+1)); /* 2 */
  136. if(t==n) {
  137. prefix(n,pindex,permm,dz);
  138. } else {
  139. insert(n,t,pindex,permm,dz);
  140. }
  141. }
  142. for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++) /* 3 */
  143. *(permm[pindex]+n) = (int)(*(permm[pindex]+n) % k);
  144. }
  145. /***************************** INSERT **********************************
  146. *
  147. * Insert the value m AFTER the T-th element in permm[pindex].
  148. */
  149. void insert(int m,int t,int pindex,int **permm,dataptr dz)
  150. {
  151. shuflup(t+1,pindex,permm,dz);
  152. *(permm[pindex]+t+1) = m;
  153. }
  154. /***************************** PREFIX ************************************
  155. *
  156. * Insert the value m at start of the permutation permm[pindex].
  157. */
  158. void prefix(int m,int pindex,int **permm,dataptr dz)
  159. {
  160. shuflup(0,pindex,permm,dz);
  161. *permm[pindex] = m;
  162. }
  163. /****************************** SHUFLUP ***********************************
  164. *
  165. * move set members in permm[pindex] upwards, starting from element k.
  166. */
  167. void shuflup(int k,int pindex, int **permm,dataptr dz)
  168. {
  169. int n, *i;
  170. int z = dz->iparray[TXPERMLEN][pindex] - 1;
  171. i = permm[pindex] + z;
  172. for(n = z;n > k;n--) {
  173. *i = *(i-1);
  174. i--;
  175. }
  176. }