/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.cursors.sources;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import xxl.core.cursors.AbstractCursor;
import xxl.core.functions.Function;
import xxl.core.predicates.FunctionPredicate;
import xxl.core.predicates.Predicate;
import xxl.core.predicates.Predicates;
/**
* Given a tuple of start values (<tt>a<sub>0</sub></tt> to
* <tt>a<sub>n</sub></tt>) the inductor incrementally computes the value
* <tt>a<sub>(n+1+i)</sub></tt> (<tt>i</tt> ≥ 0) by calling the function
* <code>next</code> with the parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt>. Optionally, the user can specify the predicate
* <code>hasNext</code> (called with parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt>) which determines whether a next value exists.
* With the help of an inductor a sequence of elements can be computed
* represented as an iteration.
*
* <p><b>Example usage (1): the <i>Fibonacci</i> sequence</b>
* <code><pre>
* Inductor<Integer> fibonacci = new Inductor<Integer>(
* new Function<Integer, Integer>() {
* public Integer invoke(Integer fib_1, Integer fib_2) {
* return fib_1 + fib_2;
* }
* },
* 1,
* 1
* );
*
* fibonacci.open();
*
* System.out.println(Cursors.nth(fibonacci, 7));
*
* fibonacci.close();
* </pre></code>
* This example computes the 7th number of the fibonacci sequence by
* initializing the inductor with two integer objects with value 1 (beginning
* of the induction sequence; <tt>n</tt> = 1, 2). All following elements are
* computed with the following function:
* <pre>
* fib(n) = fib(n-1) + fib(n-2);
* </pre>
* <b>Implemenation details:</b> If the next element is available, i.e., the
* flag <code>nextAvailable</code> is <code>true</code>, the function
* <code>next</code> is invoked on the list <code>objects</code>. This list is
* shifted left for one position by removing the first value. Then the returned
* object is added to this list as the last element with regard to the further
* computation of the inductor sequence. The first element of the list
* <code>objects</code> is returned, because this is the next element that has
* be returned in the inductor sequence. So this inductor would return the next
* number of the fibonacci sequence as long as the <code>next</code> method is
* called. In this case the static method <code>nth()</code> is used to return
* only the 7th number of the sequence, but also an other function
* <code>hasNext</code> can be specified in a constructor with the intention to
* terminate such an inductor sequence.</p>
*
* <p><b>Example usage (2): the factorial method</b>
* <code><pre>
* Inductor<Integer> factorial = new Inductor<Integer>(
* new Function<Integer, Integer>() {
* int factor = 1;
*
* public Integer invoke(Integer n) {
* return n * factor++;
* }
* },
* 1
* );
*
* factorial.open();
*
* System.out.println(Cursors.nth(factorial, 3));
*
* factorial.close();
* </pre></code>
* This example computes the 3rd number of the factorial method (3! = 6). The
* induction is initialized by one integer object with value 1
* (<tt>n</tt> = 0). Further elements are iteratively computed by invoking the
* above defined function:
* <pre>
* fac(n) = n * fac(n-1);
* </pre>
* But the factor, i.e., the next integer to multiply the next element
* <tt>fac(n-1)</tt> by, which is written back to the array, has to be stored
* (in the anonymous class). For further examples see
* {@link xxl.core.cursors.sources.Inductors}.</p>
*
* @param <E> the type of the elements returned by this iteration.
* @see java.util.Iterator
* @see xxl.core.cursors.Cursor
* @see xxl.core.cursors.AbstractCursor
* @see xxl.core.cursors.sources.Inductors
* @see xxl.core.predicates.Predicate
* @see xxl.core.functions.Function
*/
public class Inductor<E> extends AbstractCursor<E> {
/**
* The predicate that is used to determine an end of the inductor sequence.
*/
protected Predicate<? super E> hasNext;
/**
* The function that is used to compute the next element of the induction
* sequence.
*/
protected Function<? super E, ? extends E> next;
/**
* A list storing the parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt>] required for the computation of the value
* <tt>a<sub>(n+1+i)</sub></tt>.
*/
protected List<E> objects;
/**
* The number of values of the induction sequence that are available from
* the list <code>objects</code>.
*/
protected int available;
/**
* A flag to signal if the next element in the sequence is available. The
* implementation used to set this flag is as follows:
* <code><pre>
* nextAvailable = objects.size()==available-- && hasNext.invoke(objects);
* </pre></code>
* So the length of the <code>objects</code> list has to be the
* start-length, namely <code>available</code>, and the predicate
* <code>hasNext</code> must be <code>true</code>.
*/
protected boolean nextAvailable = false;
/**
* Creates a new inductor with a user defined predicate delivering the end
* of the induction sequence.
*
* @param hasNext the predicate which determines whether a next value
* exists.
* @param next the function using parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt> (<tt>i</tt> ≥ 0) to compute the
* result-value <tt>a<sub>(n+1+i)</sub></tt>.
* @param objects the start-values <tt>a<sub>0</sub></tt> to
* <tt>a<sub>n</sub></tt> of the induction sequence.
*/
public Inductor(Predicate<? super E> hasNext, Function<? super E, ? extends E> next, E... objects) {
this.hasNext = hasNext;
this.next = next;
this.objects = new LinkedList<E>();
this.available = objects.length;
Collections.addAll(this.objects, objects);
}
/**
* Creates a new inductor with a user defined boolean function delivering
* the end of the induction sequence. The boolean function
* <code>hasNext</code> is internally wrapped to a predicate.
*
* @param hasNext the boolean function which determines whether a next
* value exists.
* @param next the function using parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt> (<tt>i</tt> ≥ 0) to compute the
* result-value <tt>a<sub>(n+1+i)</sub></tt>.
* @param objects the start-values <tt>a<sub>0</sub></tt> to
* <tt>a<sub>n</sub></tt> of the induction sequence.
*/
public Inductor(Function<? super E, Boolean> hasNext, Function<? super E, ? extends E> next, E... objects) {
this(new FunctionPredicate<E>(hasNext), next, objects);
}
/**
* Creates a new inductor delivering an infinite induction sequence, i.e.,
* the predicate which determines whether a next value exists is given by
* {@link xxl.core.predicates.Predicates#TRUE}.
*
* @param next the function using parameters <tt>a<sub>i</sub></tt> to
* <tt>a<sub>(n+i)</sub></tt> (<tt>i</tt> ≥ 0) to compute the
* result-value <tt>a<sub>(n+1+i)</sub></tt>.
* @param objects the start-values <tt>a<sub>0</sub></tt> to
* <tt>a<sub>n</sub></tt> of the induction sequence.
*/
public Inductor(Function<? super E, ? extends E> next, E... objects) {
this(Predicates.TRUE, next, objects);
}
/**
* Returns <code>true</code> if the iteration has more elements. (In other
* words, returns <code>true</code> if <code>next</code> or
* <code>peek</code> would return an element rather than throwing an
* exception.)
*
* @return <code>true</code> if the inductor has more elements.
*/
@Override
protected boolean hasNextObject() {
return nextAvailable || available > 0;
}
/**
* Returns the next element in the iteration. This element will be
* accessible by some of the inductor's methods, e.g., <code>update</code>
* or <code>remove</code>, until a call to <code>next</code> or
* <code>peek</code> occurs. This is calling <code>next</code> or
* <code>peek</code> proceeds the iteration and therefore its previous
* element will not be accessible any more.
*
* @return the next element in the iteration.
*/
@Override
protected E nextObject() {
if (available < objects.size()) {
E nextObject = null;
if (nextAvailable)
nextObject = next.invoke(objects);
objects.remove(0);
if (nextAvailable) {
objects.add(nextObject);
available++;
}
}
nextAvailable = objects.size()==available-- && hasNext.invoke(objects);
return objects.get(0);
}
}