001 /* 002 * $Id: CartesianProductInfinite.java 3297 2010-08-26 19:09:03Z kredel $ 003 */ 004 005 package edu.jas.util; 006 007 008 import java.util.ArrayList; 009 import java.util.Iterator; 010 import java.util.List; 011 import java.util.Collections; 012 import java.util.NoSuchElementException; 013 014 015 /** 016 * Cartesian product of infinite components with iterator. 017 * Works also for finite iterables. 018 * @author Heinz Kredel 019 */ 020 public class CartesianProductInfinite<E> implements Iterable<List<E>> { 021 022 023 /** 024 * data structure. 025 */ 026 public final List<Iterable<E>> comps; 027 028 029 /** 030 * CartesianProduct constructor. 031 * @param comps components of the cartesian product. 032 */ 033 public CartesianProductInfinite(List<Iterable<E>> comps) { 034 if (comps == null || comps.size() == 0) { 035 throw new IllegalArgumentException("null components not allowed"); 036 } 037 this.comps = comps; 038 } 039 040 041 /** 042 * Get an iterator over subsets. 043 * @return an iterator. 044 */ 045 public Iterator<List<E>> iterator() { 046 if ( comps.size() == 1 ) { 047 return new CartesianOneProductInfiniteIterator<E>(comps.get(0)); 048 } 049 // if ( comps.size() == 2 ) { // this part is not realy required 050 // return new CartesianTwoProductInfiniteIterator<E>(comps.get(0),comps.get(1)); 051 // } 052 int n = comps.size(); 053 int k = n / 2 + n % 2; // ceiling 054 Iterable<List<E>> c0 = new CartesianProductInfinite<E>( comps.subList(0,k) ); 055 Iterable<List<E>> c1 = new CartesianProductInfinite<E>( comps.subList(k,n) ); 056 return new CartesianTwoProductInfiniteIteratorList<E>(c0,c1); 057 } 058 059 } 060 061 062 /** 063 * Cartesian product infinite iterator, one factor. 064 * @author Heinz Kredel 065 */ 066 class CartesianOneProductInfiniteIterator<E> implements Iterator<List<E>> { 067 068 069 /** 070 * data structure. 071 */ 072 final Iterator<E> compit; 073 074 075 /** 076 * CartesianProduct iterator constructor. 077 * @param comps components of the cartesian product. 078 */ 079 public CartesianOneProductInfiniteIterator(Iterable<E> comps) { 080 if (comps == null) { 081 throw new IllegalArgumentException("null comps not allowed"); 082 } 083 compit = comps.iterator(); 084 } 085 086 087 /** 088 * Test for availability of a next tuple. 089 * @return true if the iteration has more tuples, else false. 090 */ 091 public synchronized boolean hasNext() { 092 return compit.hasNext(); 093 } 094 095 096 /** 097 * Get next tuple. 098 * @return next tuple. 099 */ 100 public synchronized List<E> next() { 101 List<E> res = new ArrayList<E>(1); 102 res.add( compit.next() ); 103 return res; 104 } 105 106 107 /** 108 * Remove a tuple if allowed. 109 */ 110 public void remove() { 111 throw new UnsupportedOperationException("cannnot remove tuples"); 112 } 113 114 } 115 116 117 /** 118 * Cartesian product infinite iterator, two factors. 119 * @author Heinz Kredel 120 */ 121 class CartesianTwoProductInfiniteIterator<E> implements Iterator<List<E>> { 122 123 124 /** 125 * data structure. 126 */ 127 final Iterator<E> compit0; 128 final Iterator<E> compit1; 129 130 131 final List<E> fincomps0; 132 final List<E> fincomps1; 133 134 135 Iterator<E> fincompit0; 136 Iterator<E> fincompit1; 137 138 139 List<E> current; 140 141 142 boolean empty; 143 144 145 long level; 146 147 148 /** 149 * CartesianProduct iterator constructor. 150 * @param comps components of the cartesian product. 151 */ 152 public CartesianTwoProductInfiniteIterator(Iterable<E> comps0, Iterable<E> comps1) { 153 if (comps0 == null || comps1 == null) { 154 throw new IllegalArgumentException("null comps not allowed"); 155 } 156 empty = false; 157 level = 0; 158 current = new ArrayList<E>(2); 159 160 compit0 = comps0.iterator(); 161 E e = compit0.next(); 162 current.add(e); 163 fincomps0 = new ArrayList<E>(); 164 fincomps0.add(e); 165 fincompit0 = fincomps0.iterator(); 166 E d = fincompit0.next(); // remove current 167 168 compit1 = comps1.iterator(); 169 e = compit1.next(); 170 current.add(e); 171 fincomps1 = new ArrayList<E>(); 172 fincomps1.add(e); 173 fincompit1 = fincomps1.iterator(); 174 d = fincompit1.next(); // remove current 175 //System.out.println("current = " + current); 176 } 177 178 179 /** 180 * Test for availability of a next tuple. 181 * @return true if the iteration has more tuples, else false. 182 */ 183 public synchronized boolean hasNext() { 184 return !empty; 185 } 186 187 188 /** 189 * Get next tuple. 190 * @return next tuple. 191 */ 192 public synchronized List<E> next() { 193 if (empty) { 194 throw new NoSuchElementException("invalid call of next()"); 195 } 196 List<E> res = current; // new ArrayList<E>(current); // copy 197 if ( fincompit0.hasNext() && fincompit1.hasNext() ) { 198 E e0 = fincompit0.next(); 199 E e1 = fincompit1.next(); 200 current = new ArrayList<E>(); 201 current.add(e0); 202 current.add(e1); 203 return res; 204 } 205 level++; 206 if ( level % 2 == 1 ) { 207 Collections.reverse(fincomps0); 208 } else { 209 Collections.reverse(fincomps1); 210 } 211 if ( compit0.hasNext() && compit1.hasNext() ) { 212 fincomps0.add( compit0.next() ); 213 fincomps1.add( compit1.next() ); 214 } else { 215 empty = true; 216 return res; 217 } 218 if ( level % 2 == 0 ) { 219 Collections.reverse(fincomps0); 220 } else { 221 Collections.reverse(fincomps1); 222 } 223 //System.out.println("list(0) = " + fincomps0); 224 //System.out.println("list(1) = " + fincomps1); 225 fincompit0 = fincomps0.iterator(); 226 fincompit1 = fincomps1.iterator(); 227 E e0 = fincompit0.next(); 228 E e1 = fincompit1.next(); 229 current = new ArrayList<E>(); 230 current.add(e0); 231 current.add(e1); 232 return res; 233 } 234 235 236 /** 237 * Remove a tuple if allowed. 238 */ 239 public void remove() { 240 throw new UnsupportedOperationException("cannnot remove tuples"); 241 } 242 243 } 244 245 246 /** 247 * Cartesian product infinite iterator, two factors list version. 248 * @author Heinz Kredel 249 */ 250 class CartesianTwoProductInfiniteIteratorList<E> implements Iterator<List<E>> { 251 252 253 /** 254 * data structure. 255 */ 256 final Iterator<List<E>> compit0; 257 final Iterator<List<E>> compit1; 258 259 260 final List<List<E>> fincomps0; 261 final List<List<E>> fincomps1; 262 263 264 Iterator<List<E>> fincompit0; 265 Iterator<List<E>> fincompit1; 266 267 268 List<E> current; 269 270 271 boolean empty; 272 273 274 long level; 275 276 277 /** 278 * CartesianProduct iterator constructor. 279 * @param comps components of the cartesian product. 280 */ 281 public CartesianTwoProductInfiniteIteratorList(Iterable<List<E>> comps0, Iterable<List<E>> comps1) { 282 if (comps0 == null || comps1 == null) { 283 throw new IllegalArgumentException("null comps not allowed"); 284 } 285 current = new ArrayList<E>(); 286 empty = false; 287 level = 0; 288 289 compit0 = comps0.iterator(); 290 List<E> e = compit0.next(); 291 current.addAll(e); 292 fincomps0 = new ArrayList<List<E>>(); 293 fincomps0.add(e); 294 fincompit0 = fincomps0.iterator(); 295 List<E> d = fincompit0.next(); // remove current 296 297 compit1 = comps1.iterator(); 298 e = compit1.next(); 299 current.addAll(e); 300 fincomps1 = new ArrayList<List<E>>(); 301 fincomps1.add(e); 302 fincompit1 = fincomps1.iterator(); 303 d = fincompit1.next(); // remove current 304 //System.out.println("current = " + current); 305 } 306 307 308 /** 309 * Test for availability of a next tuple. 310 * @return true if the iteration has more tuples, else false. 311 */ 312 public synchronized boolean hasNext() { 313 return !empty; 314 } 315 316 317 /** 318 * Get next tuple. 319 * @return next tuple. 320 */ 321 public synchronized List<E> next() { 322 if (empty) { 323 throw new NoSuchElementException("invalid call of next()"); 324 } 325 List<E> res = current; // new ArrayList<E>(current); 326 if ( fincompit0.hasNext() && fincompit1.hasNext() ) { 327 List<E> e0 = fincompit0.next(); 328 List<E> e1 = fincompit1.next(); 329 current = new ArrayList<E>(); 330 current.addAll(e0); 331 current.addAll(e1); 332 return res; 333 } 334 level++; 335 if ( level % 2 == 1 ) { 336 Collections.reverse(fincomps0); 337 } else { 338 Collections.reverse(fincomps1); 339 } 340 if ( compit0.hasNext() && compit1.hasNext() ) { 341 fincomps0.add( compit0.next() ); 342 fincomps1.add( compit1.next() ); 343 } else { 344 empty = true; 345 return res; 346 } 347 if ( level % 2 == 0 ) { 348 Collections.reverse(fincomps0); 349 } else { 350 Collections.reverse(fincomps1); 351 } 352 //System.out.println("list(0) = " + fincomps0); 353 //System.out.println("list(1) = " + fincomps1); 354 fincompit0 = fincomps0.iterator(); 355 fincompit1 = fincomps1.iterator(); 356 List<E> e0 = fincompit0.next(); 357 List<E> e1 = fincompit1.next(); 358 current = new ArrayList<E>(); 359 current.addAll(e0); 360 current.addAll(e1); 361 return res; 362 } 363 364 365 /** 366 * Remove a tuple if allowed. 367 */ 368 public void remove() { 369 throw new UnsupportedOperationException("cannnot remove tuples"); 370 } 371 372 }