All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sri.ai.util.functionalsequence.AbstractFunctionalSequence Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * 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