com.sri.ai.util.functionalsequence.AbstractFunctionalSequence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aic-util Show documentation
Show all versions of aic-util Show documentation
SRI International's AIC Utility Library (for Java 1.6+)
/*
* Copyright (c) 2013, SRI International
* All rights reserved.
* Licensed under the The BSD 3-Clause License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://opensource.org/licenses/BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the aic-util nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sri.ai.util.functionalsequence;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.google.common.annotations.Beta;
import com.sri.ai.util.Util;
import com.sri.ai.util.collect.EZIterator;
import com.sri.ai.util.collect.HasNext;
/**
* An abstract class implementing basic functionality for a
* {@link FunctionalSequence}. In this class, sequences are represented by
* iterators.
*
* An extending class must define at least the following abstract methods:
*
* - {@link #initialValue()}
*
- {@link #computeFunction()}
*
*
* Optionally, an extending class may override following methods:
*
* - {@link #isFinalValue(Object)}, which indicates whether a given value
* indicates the end of the sequence (default always returns false).
*
- {@link #nextArgumentToUpdate()}, which in this class has a default
* implementation of picking the first argument with a next value;
*
- {@link #computeFunctionIncrementally(Object, Iterator, Object, Object)}, which in this class has a
* default implementation of running {@link #computeFunction()}.
*
*
* An extension must keep track of the argument iterators (that is, iterators
* ranging over the values of each argument sequence s_i).
* {@link #computeFunction()}, when defined by extensions, must obtain the
* current value of an argument sequence through the method
* {@link #getCurrentArgumentValue(Iterator)}, which takes the argument iterator
* as a parameter.
*
* @author braz
*
* @param
* the type of the elements to iterate.
* @param
* the type of the argument values.
*/
@Beta
public abstract class AbstractFunctionalSequence extends EZIterator
implements FunctionalSequence {
private Map, V> fromArgumentsToArgumentValues = new LinkedHashMap, V>();
private boolean initialValueReturned = false;
private boolean firstComputationDone = false;
private boolean finalValueFoundSoNoMoreElementsToBeComputed = false;
// Methods to be implemented or overridden
/**
* @return the initial value of the functional sequence. This must return
* null if we do not wish to include an arbitrary initial value, in
* which case the first value will be computed from applying the
* function to the first elements of the arguments sequences.
*/
abstract protected T initialValue();
/**
* @param value
* the value to test.
* @return whether provided value should indicate end of range for this
* rewriter functional sequence after being produced by it. Default
* implementation returns false every time.
*/
protected boolean isFinalValue(T value) {
return false;
}
/**
* @return Computes the function from current argument values in
* {@link #fromArgumentsToArgumentValues}, being responsible for
* computing and storing the first value of an argument if it is not
* already there.
*/
abstract protected T computeFunction();
/**
* @return Picks next argument to be updated, returning null
if
* no argument has a next value to be updated to. The default
* implementation picks the first argument used in the first
* execution of the function that has a next value.
*/
protected Iterator nextArgumentToUpdate() {
Set> arguments = fromArgumentsToArgumentValues.keySet();
Iterator result = Util.getFirstSatisfyingPredicateOrNull(arguments,
HAS_NEXT);
return result;
}
/**
* Optionally implements the function for after only one argument has been
* updated, that is, provides an incremental version of the function,
* assuming that all arguments values are in
* {@link #fromArgumentsToArgumentValues} (including the one just updated).
* The default implementation simply recomputes the function from the stored
* argument values.
*
* @param currentResult
* the current result
* @param argument
* an iterator over arguments.
* @param previousArgumentValue
* the previous argument value.
* @param newArgumentValue
* the new argument value.
* @return the incrementally computed value.
*/
protected T computeFunctionIncrementally(T currentResult,
Iterator argument, V previousArgumentValue, V newArgumentValue) {
T result = computeFunction();
return result;
}
// End of methods to be implemented or overridden
protected V getCurrentArgumentValue(Iterator argument) {
V result = fromArgumentsToArgumentValues.get(argument);
if (result == null) {
if (argument.hasNext()) {
result = argument.next();
fromArgumentsToArgumentValues.put(argument, result);
}
else {
throw new ArgumentWithNoValues();
}
}
return result;
}
@Override
protected T calculateNext() {
T result = null;
if (finalValueFoundSoNoMoreElementsToBeComputed) {
result = null; // end of sequence
}
else if (!initialValueReturned && initialValue() != null) { // arbitrary
// initial
// value,
// if
// any
result = initialValue();
initialValueReturned = true;
}
else if (!firstComputationDone) { // first computed value
try {
result = computeFunction();
firstComputationDone = true;
} catch (ArgumentWithNoValues e) {
result = null; // end of sequence
}
}
else { // incremental computation
Iterator nextArgumentToUpdate = nextArgumentToUpdate();
if (nextArgumentToUpdate != null) {
V previousArgumentValue = fromArgumentsToArgumentValues
.get(nextArgumentToUpdate);
V newArgumentValue = nextArgumentToUpdate.next();
fromArgumentsToArgumentValues.put(nextArgumentToUpdate,
newArgumentValue);
result = computeFunctionIncrementally(result,
nextArgumentToUpdate, previousArgumentValue,
newArgumentValue);
}
else {
result = null; // end of sequence
}
}
if (result != null && isFinalValue(result)) {
finalValueFoundSoNoMoreElementsToBeComputed = true;
}
return result;
}
@SuppressWarnings("serial")
public static class ArgumentWithNoValues extends Error {
}
private final HasNext HAS_NEXT = new HasNext();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy