ComposedArray.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package gnu.lists;
  2. import gnu.mapping.Lazy;
  3. import gnu.mapping.Promise;
  4. import java.util.List;
  5. import gnu.math.IntNum;
  6. /** Indexing "composes" with a set of indexing arrays. */
  7. public class ComposedArray<E> extends TransformedArray<E> {
  8. Array<Integer>[] mappers;
  9. int rank;
  10. int[] dims;
  11. int[] lowBounds;
  12. public ComposedArray(Array base, int rank, int[] dims, int[] lowBounds, Array<Integer>[] mappers) {
  13. super(base);
  14. this.rank = rank;
  15. this.dims = dims;
  16. this.lowBounds = lowBounds;
  17. this.mappers = mappers;
  18. }
  19. @Override public int rank() { return rank; }
  20. @Override
  21. public int getLowBound(int dim) { return lowBounds[dim]; }
  22. @Override
  23. public int getSize(int dim) { return dims[dim]; }
  24. @Override
  25. public final int effectiveIndex() {
  26. return resolve(0, 0, 0, noInts);
  27. }
  28. public final int effectiveIndex(int i) {
  29. return resolve(i, 0, 0, noInts);
  30. }
  31. public final int effectiveIndex(int i, int j) {
  32. return resolve(i, j, 0, noInts);
  33. }
  34. public final int effectiveIndex(int i, int j, int k, int... rest) {
  35. return resolve(i, j, k, rest);
  36. }
  37. private int resolve(int x, int y, int z, int... rest) {
  38. int brank = base.rank(); // must be same as mappers.length
  39. int rlen = rest.length;
  40. // The output arguments (which will be used to index into base)
  41. // are in the "virtual array" [b0 b1 b2 @brest]
  42. int b0 = 0, b1 = 0, b2 = 0;
  43. int[] brest = brank > 3 ? new int[brank-3] : noInts;
  44. // bpos is the next unwritten position in [b0 b1 b2 @brest]
  45. int bpos = 0;
  46. // mpos is the index of next available value in [x y z @rest]
  47. int mpos = 0;
  48. for (int i = 0; i < brank; i++) {
  49. Array<Integer> mapper = mappers[i];
  50. int mrank = mapper.rank();
  51. int bval;
  52. // The current value of x is mpos index in the original value
  53. // of [x y z @rest]. Similarly for y at mpos+1,
  54. // and z at mpos+2.
  55. switch (mrank) {
  56. case 0:
  57. bval = mapper.getInt();
  58. break;
  59. case 1:
  60. bval = mapper.getInt(x);
  61. x = y;
  62. y = z;
  63. if (mpos >= 3 && mpos-3 < rlen)
  64. z = rest[mpos-3];
  65. break;
  66. case 2:
  67. bval = mapper.getInt(x, y);
  68. x = z;
  69. if (mpos >= 3 && mpos-3 < rlen) {
  70. y = rest[mpos-3];
  71. if (mpos >= 2 && mpos-2 < rlen)
  72. z = rest[mpos-2];
  73. }
  74. break;
  75. default:
  76. int[] tmp;
  77. if (mrank == 3)
  78. tmp = noInts;
  79. else {
  80. tmp = new int[mrank-3];
  81. System.arraycopy(rest, mpos-3, tmp, 0, mrank-3);
  82. }
  83. bval = mapper.getInt(x, y, z, tmp);
  84. if (mpos >= 3 && mpos-3 < rlen) {
  85. x = rest[mpos-3];
  86. if (mpos >= 2 && mpos-2 < rlen)
  87. y = rest[mpos-2];
  88. if (mpos >= 1 && mpos-1 < rlen)
  89. z = rest[mpos-1];
  90. }
  91. }
  92. mpos += mrank;
  93. switch (bpos) {
  94. case 0: b0 = bval; break;
  95. case 1: b1 = bval; break;
  96. case 2: b2 = bval; break;
  97. default: brest[bpos-3] = bval; break;
  98. }
  99. bpos++;
  100. }
  101. switch (bpos) {
  102. case 0: return base.effectiveIndex();
  103. case 1: return base.effectiveIndex(b0);
  104. case 2: return base.effectiveIndex(b0, b1);
  105. default: return base.effectiveIndex(b0, b1, b2, brest);
  106. }
  107. }
  108. public static Object generalIndex(Array arr, boolean shared,
  109. Object... indexes) {
  110. return generalIndex(arr, shared, 0, indexes.length, indexes);
  111. }
  112. public static Object generalIndex(Array arr, boolean shared,
  113. int start, int nindexes,
  114. Object[] indexes) {
  115. boolean allInts = true;
  116. for (int i = 0; i < nindexes; i++) {
  117. Object index = indexes[start+i];
  118. if (index instanceof Number) {
  119. // simple
  120. } else if (index instanceof Lazy) {
  121. index = Promise.force(index);
  122. indexes[start+i] = index;
  123. if (! (index instanceof Number))
  124. allInts = false;
  125. } else {
  126. allInts = false;
  127. }
  128. }
  129. boolean linear = true;
  130. if (allInts && ! shared) {
  131. switch (nindexes) {
  132. case 0:
  133. return arr.get();
  134. case 1:
  135. return arr.get(((Number) indexes[start]).intValue());
  136. case 2:
  137. return arr.get(((Number) indexes[start]).intValue(),
  138. ((Number) indexes[start+1]).intValue());
  139. default:
  140. int[] rest = nindexes == 3 ? AbstractSequence.noInts
  141. : new int[nindexes];
  142. for (int i = 3; i < nindexes; i++)
  143. rest[i-3] = ((Number) indexes[start+i]).intValue();
  144. return arr.get(((Number) indexes[start]).intValue(),
  145. ((Number) indexes[start+1]).intValue(),
  146. ((Number) indexes[start+2]).intValue(),
  147. rest);
  148. }
  149. } else {
  150. Array<Integer>[] aindexes = (Array<Integer>[]) new Array[nindexes];
  151. int rank = 0;
  152. for(int i = 0; i < nindexes; i++) {
  153. Array<Integer> iarr = Arrays.asIntArrayOrNull(indexes[start+i]);
  154. if (iarr == null)
  155. throw new ClassCastException("index is not an integer or integer array "+indexes[start+i].getClass().getName());
  156. aindexes[i] = iarr;
  157. int irank = iarr.rank();
  158. if (irank != 0) {
  159. if (! (iarr instanceof Range.IntRange))
  160. linear = false;
  161. else {
  162. Range.IntRange r = (Range.IntRange) iarr;
  163. if (r.isUnbounded()) {
  164. int ilow = arr.getLowBound(i);
  165. int idim = arr.getSize(i);
  166. IntNum istart =
  167. IntNum.valueOf(r.size != -2 ? r.istart
  168. : r.istep >= 0 ? ilow
  169. : ilow+idim-1);
  170. IntNum istep = IntNum.valueOf(r.istep);
  171. if (r.istep >= 0)
  172. iarr = Range.upto(istart, istep, IntNum.valueOf(ilow+idim), false);
  173. else
  174. iarr = Range.downto(istart, istep, IntNum.valueOf(ilow), true);
  175. aindexes[i] = iarr;
  176. }
  177. }
  178. }
  179. rank += irank;
  180. }
  181. if (! shared && arr instanceof SimpleVector) {
  182. if (linear && rank == 1 && nindexes == 1) {
  183. SimpleVector svec = (SimpleVector) arr;
  184. Range.IntRange range = (Range.IntRange) aindexes[0];
  185. return Sequences.copy(svec, range, false);
  186. }
  187. arr = ((SimpleVector) arr).asImmutable();
  188. shared = true;
  189. }
  190. int[] dimensions = new int[rank];
  191. int[] lowBounds = new int[rank];
  192. int k = 0;
  193. for(int i = 0; i < nindexes; i++) {
  194. Array<Integer> iarr = aindexes[i];
  195. int irank = iarr.rank();
  196. int ilow = arr.getLowBound(i);
  197. int idim = arr.getSize(i);
  198. if (irank == 0) {
  199. int j = iarr.getInt();
  200. j -= ilow;
  201. if (j < 0 || (idim >= 0 && j >= idim)) {
  202. throwBoundException(i, nindexes, arr,
  203. "value "+(j+ilow));
  204. }
  205. } else if (iarr instanceof Range.IntRange) {
  206. Range.IntRange r = (Range.IntRange) iarr;
  207. int ihigh = ilow + idim - 1;
  208. int rsize = r.size();
  209. int rstep = r.getStepInt();
  210. int istart = r.getStartInt();
  211. int ilast = r.getLastInt();
  212. if (rsize != 0 && idim != 0
  213. && (istart < ilow || (idim >= 0 && istart > ihigh)
  214. || ilast < ilow || (idim >= 0 && ilast > ihigh))) {
  215. String msg = "range [" + istart + " <=: " + ilast + "]";
  216. throwBoundException(i, nindexes, arr, msg);
  217. }
  218. } else {
  219. // FIXME should we check that every element in iarr
  220. // is in [ilow by: 1 size: idim] ?
  221. }
  222. for (int j = 0; j < irank; j++) {
  223. dimensions[k] = iarr.getSize(j);
  224. lowBounds[k] = iarr.getLowBound(j);
  225. k++;
  226. }
  227. }
  228. // FIXME: replace 'shared' by '(shared || arr.isImmutable())' ?
  229. if (linear && shared && arr instanceof GeneralArray) {
  230. GeneralArray garr = (GeneralArray) arr;
  231. int offset = garr.offset;
  232. int[] strides = new int[rank];
  233. k = 0;
  234. for(int i = 0; i < nindexes; i++) {
  235. Array<Integer> iarr = aindexes[i];
  236. int irank = iarr.rank();
  237. int istride = garr.strides[i];
  238. int ilow = garr.lowBounds[i];
  239. int idim = garr.dimensions[i];
  240. if (iarr.rank() == 0) {
  241. int j = iarr.getInt();
  242. offset += istride * (j - ilow);
  243. } else { // iarr instanceof Range.IntRange
  244. Range.IntRange r = (Range.IntRange) iarr;
  245. int sz = r.size();
  246. int j = r.getStartInt();
  247. strides[k] = r.getStepInt() * istride;
  248. offset += istride * (j - ilow);
  249. k++;
  250. }
  251. }
  252. return GeneralArray.make(garr.getBase(), dimensions, lowBounds,
  253. strides, offset);
  254. }
  255. if (shared && rank == 1 && lowBounds[0] == 0) {
  256. if (arr instanceof List && aindexes.length == 1
  257. && aindexes[0] instanceof IntSequence)
  258. return new IndirectIndexedSeq((List) arr,
  259. (IntSequence) aindexes[0]);
  260. return new ComposedArray.AsSequence(arr, rank, dimensions,
  261. lowBounds, aindexes);
  262. }
  263. ComposedArray carr = new ComposedArray(arr, rank, dimensions,
  264. lowBounds, aindexes);
  265. if (shared)
  266. return carr;
  267. else
  268. return Arrays.simpleCopy(carr, false);
  269. }
  270. }
  271. private static void throwBoundException(int i, int nindexes,
  272. Array oldMapper,
  273. String index) {
  274. int ilow = oldMapper.getLowBound(i);
  275. int idim = oldMapper.getSize(i);
  276. StringBuilder sbuf = new StringBuilder();
  277. if (nindexes == 0)
  278. sbuf.append("index " );
  279. else {
  280. sbuf.append("index (");
  281. sbuf.append(i);
  282. sbuf.append(" of ");
  283. sbuf.append(nindexes);
  284. sbuf.append(") ");
  285. }
  286. sbuf.append(index);
  287. sbuf.append(" out of bounds [");
  288. sbuf.append(ilow);
  289. sbuf.append(" <: ");
  290. sbuf.append(idim+ilow);
  291. sbuf.append("]");
  292. throw new IndexOutOfBoundsException(sbuf.toString());
  293. }
  294. /** Same as ComposedArray but also implements AVector. */
  295. public static class AsSequence<E>
  296. extends ComposedArray<E> implements AVector<E> {
  297. public AsSequence(Array base, int rank, int[] dims, int[] lowBounds, Array<Integer>[] mappers) {
  298. super(base, rank, dims, lowBounds, mappers);
  299. }
  300. }
  301. }