001    /*
002     * $Id: CartesianProductLong.java 3308 2010-09-01 11:12:11Z 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.NoSuchElementException;
012    
013    
014    /**
015     * Cartesian product for Long with iterator.
016     * Similar to CartesianProduct but returns only tuples of given total degree.
017     * @author Heinz Kredel
018     */
019    public class CartesianProductLong implements Iterable<List<Long>> {
020    
021    
022        /**
023         * data structure.
024         */
025        public final List<LongIterable> comps; 
026    
027    
028        public final long upperBound; 
029    
030    
031        /**
032         * CartesianProduct constructor.
033         * @param comps components of the cartesian product.
034         * @param ub an upper bound for the total degree of the elements.
035         */
036        public CartesianProductLong(List<LongIterable> comps, long ub) {
037            if (comps == null) {
038                throw new IllegalArgumentException("null components not allowed");
039            }
040            this.comps = comps;
041            this.upperBound = ub;
042        }
043    
044    
045        /**
046         * Get an iterator over subsets.
047         * @return an iterator.
048         */
049        public Iterator<List<Long>> iterator() {
050            return new CartesianProductLongIterator(comps,upperBound);
051        }
052    
053    }
054    
055    
056    /**
057     * Cartesian product iterator for Longs.
058     * Similar to CartesianProductIterator but returns only tuples of given total degree.
059     * @author Heinz Kredel
060     */
061    class CartesianProductLongIterator implements Iterator<List<Long>> {
062    
063    
064        /**
065         * data structure.
066         */
067        final List<LongIterable> comps;
068    
069    
070        final List<LongIterator> compit;
071    
072    
073        List<Long> current;
074    
075    
076        boolean empty;
077    
078    
079        public final long upperBound; 
080    
081    
082        /**
083         * CartesianProduct iterator constructor.
084         * @param comps components of the cartesian product.
085         * @param un an upper bound for the total degree of the elements.
086         */
087        public CartesianProductLongIterator(List<LongIterable> comps, long ub) {
088            if (comps == null) {
089                throw new IllegalArgumentException("null comps not allowed");
090            }
091            this.comps = comps;
092            this.upperBound = ub;
093            current = new ArrayList<Long>(comps.size());
094            compit = new ArrayList<LongIterator>(comps.size());
095            empty = false;
096            for (LongIterable ci : comps) {
097                LongIterator it = (LongIterator) ci.iterator();
098                if ( it.getUpperBound() < this.upperBound ) {
099                    throw new IllegalArgumentException("each iterator (" + it.getUpperBound() 
100                                                  + ") must be able to reach total upper bound " + upperBound);
101                }
102                if (!it.hasNext()) {
103                    empty = true;
104                    current.clear();
105                    return;
106                }
107                current.add(it.next());
108                compit.add(it);
109            }
110            // start with last component equal to upper bound
111            LongIterator it = compit.get(compit.size()-1);
112            long d = -1L;
113            while ( it.hasNext() ) {
114                d = it.next();
115                if ( d >= upperBound ) {
116                    break;
117                }
118            }
119            if ( d >= 0L ) {
120                current.set(current.size()-1,d);
121            }
122            if ( totalDegree(current) != upperBound ) {
123                empty = true;
124                current.clear();
125            }
126            //System.out.println("current = " + current);
127        }
128    
129    
130        /**
131         * Test for availability of a next tuple.
132         * @return true if the iteration has more tuples, else false.
133         */
134        public synchronized boolean hasNext() {
135            return !empty;
136        }
137    
138    
139        /**
140         * Get next tuple.
141         * @return next tuple.
142         */
143        public synchronized List<Long> next() {
144            if (empty) {
145                throw new NoSuchElementException("invalid call of next()");
146            }
147            List<Long> res = new ArrayList<Long>(current);
148            //int waist = 0;
149            while ( true ) {
150                // search iterator which hasNext
151                int i = compit.size() - 1;
152                for (; i >= 0; i--) {
153                    LongIterator iter = compit.get(i);
154                    if (iter.hasNext()) {
155                        break;
156                    }
157                }
158                if (i < 0) {
159                    empty = true;
160                    //System.out.println("inner waist = " + waist);
161                    return res;
162                }
163                long pd = 0L;
164                for (int j = 0; j < i; j++) {
165                    pd += current.get(j);
166                }        
167                if ( pd >= upperBound ) {
168                    if ( current.get(0) == upperBound ) {
169                        empty = true;
170                        //System.out.println("inner waist = " + waist);
171                        return res;
172                    }
173                    pd = upperBound;
174                }
175                long rd = upperBound - pd;
176                // update iterators
177                for (int j = i + 1; j < compit.size(); j++) {
178                    LongIterator iter = (LongIterator) comps.get(j).iterator();
179                    iter.setUpperBound(rd);
180                    compit.set(j, iter);
181                }
182                // update current
183                for (int j = i; j < compit.size(); j++) {
184                    LongIterator iter = compit.get(j);
185                    Long el = iter.next();
186                    current.set(j, el);
187                }
188                long td = totalDegree(current);
189                if ( td == upperBound ) {
190                    //System.out.println("inner waist = " + waist);
191                    return res;
192                }
193                //System.out.println("current = " + current + ", td = " + td);
194                if ( td > upperBound ) {
195                    //waist++;
196                    continue;
197                }
198                // adjust last component to total degree
199                LongIterator it = compit.get(compit.size()-1);
200                long d = -1L;
201                while ( td < upperBound && it.hasNext() ) {
202                    td++;
203                    d = it.next();
204                }
205                //System.out.println("d = " + d);
206                if ( d >= 0L ) {
207                    current.set(current.size()-1,d);
208                }
209                if ( td == upperBound ) {
210                    //System.out.println("inner waist = " + waist);
211                    return res;
212                }
213                //waist++;
214                // continue search
215            }
216            //return res;
217        }
218    
219    
220        /**
221         * Total degree of a tuple.
222         * @param e list of Longs.
223         * @return sum of all elements in e.
224         */
225        public long totalDegree(List<Long> e) {
226            long d = 0L;
227            for (Long i : e) {
228                d += i;
229            }        
230            return d;
231        }
232    
233    
234        /**
235         * Remove a tuple if allowed.
236         */
237        public void remove() {
238            throw new UnsupportedOperationException("cannnot remove tuples");
239        }
240    
241    }