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

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

/*
 * 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.LinkedHashSet;
import java.util.Set;

import com.google.common.annotations.Beta;
import com.google.common.base.Predicate;
import com.sri.ai.util.Util;

/**
 * An abstract class implementing a {@link Refiner} based on a function, the
 * arguments of which being provided by refiners as well. The specific function
 * and argument refiners are left for extensions to implement.
 * 

* The generic arguments T and V correspond to the type of value produced by the * functional refiner, and the type of argument values, respectively. *

* Intuitively, a functional refiner starts with an initial arbitrary value, and * more refined values are obtained by applying the function to more refined * values of its arguments than the ones used to compute the previous value. * When a refinement is requested, the functional refiner checks whether there * are more refined argument values available and, if so, uses them to compute a * more refined value. If the arguments do not have a more refined value for * free, then a rank of arguments is used to request refinements from each of * them, in rank order, until one is obtained. If no argument provides a more * refined value, the functional refiner indicates that no further refinement of * its own value is possible. *

* Here is a more precise definition: let f : V^n -> T be a n-ary function from * arguments of type V to a set T and s_1, ..., s_n be n (possibly infinite) * sequences, with s_{i,j} the j-th element of the sequence s_i. Let k be a * (possibly infinite) sequence of index arrays (k_{1,1} ... k_{1,n}), ..., * (k_{m,1}, ..., k_{m, n}), ..., where k_{t,i} is an integer greater than 0, * k_{1,i} = 1 for all i, and each array k_t differs from k_{t+1} in at least * one element, with k_{t+1,i} >= k_{t,i} for all i. (note that this means some * argument sequence values can be "skipped"; at the implementation level, this * happens when an argument's refiner performs more than one refinement at some * other client's request, in between requests from this functional refiner, * which never gets to see the intermediary ones -- this is ok because the * values are always better refinements). Let f0 be an initial value in T. Then * we define a functional refiner fr(f, f0, s, k) as a refiner with the * following sequence of refined values: f0, f(s_{1,k_{1,1}}, ..., * s_{n,k_{1,n}}), ..., f(s_{1,k_{t,1}}, ..., s_{n,k_{t,n}}), ... *

* Extensions of {@link AbstractFunctionalRefiner} implement a functional * refiner by implementing the parameters f, f0, and s. The parameter k is * implemented in the following way: if there are any argument sequences with * more refined values available for free, then they are the ones being updated. * Otherwise, the first one (in a given ranking) with a more refined value, even * if at a cost, is updated. The default ranking is undefined (it will typically * be the order of argument updated when the function is run for the first * time), but extensions can provide their own ranking. *

* An extending class must do at least the following: *

    *
  • have a constructor setting an initial value; *
  • define a method {@link #computeFunction()} providing an implementation * for f and identifying the argument sequences s. The identification of * argument sequences is achieved by {@link #computeFunction()}'s obligation to * access the value of its arguments through the method {@link * #getCurrentArgumentValue(Refiner)}. It is up to extension to * create these argument sequence refiners. *
*

* Optionally, an extending class may override * {@link #argumentUpdateRankingIterator()}, effectively implementing parameter * k. By default, this method picks the first argument with a more refined * value; * * @author braz */ @Beta public abstract class AbstractFunctionalRefiner extends AbstractRefiner { private Set> arguments = new LinkedHashSet>(); private boolean firstComputationDone = false; // Methods to be implemented or overridden public AbstractFunctionalRefiner(T initialValue) { super(initialValue); } /** * Computes the function from current argument values in {@link #arguments}, * being responsible for computing and storing the first value of an argument if it is not already there. * * @return the function from current argument values. */ abstract protected T computeFunction(); /** * Returns an iterator ranging over arguments in decreasing preference for refinement attempt. * Default implementation returns an arbitrary ranking, * typically in the order arguments are used the first time function is run. * * @return the argument update ranking iterator. */ protected Iterator> argumentUpdateRankingIterator() { return arguments.iterator(); } // End of methods to be implemented or overridden protected V getCurrentArgumentValue(Refiner argument) { if ( ! arguments.contains(argument)) { arguments.add(argument); } V result = argument.getCurrentValue(this); return result; } @Override protected T refineOrNull() { T result = null; if ( ! firstComputationDone) { // first computed value result = computeFunction(); firstComputationDone = true; } else { // incremental computation boolean hasMoreRefinedValue; if ( ! (hasMoreRefinedValue = Util.thereExists(arguments, new HasMoreRefinedValueSinceLastTimeAtNoCost()))) { hasMoreRefinedValue = tryToRefineSomeArgumentAccordingToRanking(); } if (hasMoreRefinedValue) { result = computeFunction(); } } return result; } private boolean tryToRefineSomeArgumentAccordingToRanking() { boolean result = false; Iterator> updateRankingIterator = argumentUpdateRankingIterator(); while ( ! result && updateRankingIterator.hasNext()) { Refiner argument = updateRankingIterator.next(); result = argument.refineIfPossible(); } return result; } private class HasMoreRefinedValueSinceLastTimeAtNoCost implements Predicate> { @Override public boolean apply(Refiner refiner) { return refiner.hasMoreRefinedValueSinceLastTimeAtNoCost(AbstractFunctionalRefiner.this); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy