/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
package com.analog.lyric.dimple.factorfunctions.core;
import java.io.Serializable;
import java.util.BitSet;
import org.eclipse.jdt.annotation.Nullable;
import com.analog.lyric.dimple.exceptions.DimpleException;
import com.analog.lyric.dimple.model.domains.JointDomainIndexer;
import com.analog.lyric.dimple.model.domains.JointDomainReindexer;
import com.analog.lyric.dimple.model.values.Value;
public interface IFactorTableBase extends Cloneable, Serializable, Iterable<FactorTableEntry>
{
/*------------------
* Iterator methods
*/
/**
* Returns an iterator over the non-zero entries in the table in increasing order
* of sparse/joint index.
* @see #fullIterator()
*/
@Override
public abstract IFactorTableIterator iterator();
/**
* Returns an iterator over the joint indexes in the table in increasing order.
* @see #iterator()
*/
public abstract IFactorTableIterator fullIterator();
/*-------------
* New methods
*/
/**
* Returns a deep copy of this factor table.
*/
public abstract IFactorTableBase clone();
/**
* Computes the number of entries in the table with non-zero weight (or non-infinite energy).
*/
public int countNonZeroWeights();
/**
* Returns a new factor table converted from this one using the specified converter.
*/
public IFactorTableBase convert(JointDomainReindexer converter);
/**
* That ratio of non-zero weights to {@link #jointSize()}. Will be 1.0 if table contains
* no entries with zero weight.
*/
public double density();
/**
* Deterministically compute output arguments from input arguments.
* <p>
* If table {@link #isDeterministicDirected()}, this method looks at the input arguments
* designated by the set bits of {@link #getInputSet()} and sets the remaining output arguments
* from them.
* @throws DimpleException not {@link #isDeterministicDirected()}.
*/
public abstract void evalDeterministic(Value[] arguments);
/**
* The number of dimensions in the table.
* <p>
* The same as {@link #getDomainIndexer()}.size().
*/
public abstract int getDimensions();
/**
* Returns energy for given set of indices assuming that the table has a dense
* representation for energies. This provides the fastest possible lookup for energies.
* <p>
* @throws ArrayIndexOutOfBoundsException may throw if {@code indices} are out of bound
* or table does not have dense energies.
* @see #hasDenseEnergies()
* @see #getEnergyForIndices(int...)
* @see #getWeightForIndicesDense(int...)
*/
public double getEnergyForIndicesDense(int ... indices);
public double getEnergyForValuesDense(Value ... values);
/**
* Returns weight for given set of indices assuming that the table has a dense
* representation for weights. This provides the fastest possible lookup for weights.
* <p>
* @throws ArrayIndexOutOfBoundsException may throw if {@code indices} are out of bound
* or table does not have dense weights.
* @see #hasDenseWeights()
* @see #getWeightForIndices(int...)
* @see #getEnergyForIndicesDense(int...)
*/
public double getWeightForIndicesDense(int ... indices);
public double getWeightForValuesDense(Value ... values);
/**
* The domain indexer for the table represents the domains of the table dimensions and denotes the
* directionality of the table dimensions if table is directed.
* <p>
* It is used to map between different
* representations identifying a table entry: i.e. array of elements of each respective domain,
* array of discrete domain indices of each respective domain, or a single integer representing
* the location of the entry in the dense representation of the table.
*/
public abstract JointDomainIndexer getDomainIndexer();
/**
* Returns energy of factor table entry for given {@code elements}.
* <p>
* @see #getEnergyForIndices(int...)
* @see #getWeightForElements(Object...)
*/
public abstract double getEnergyForElements(Object ... elements);
/**
* Returns energy of factor table entry for given {@code jointIndex}.
* <p>
* @see #getWeightForJointIndex(int)
*/
public abstract double getEnergyForJointIndex(int jointIndex);
/**
* Returns energy of factor table entry at given {@code sparseIndex}.
* <p>
* The energy is the same as the negative log of the weight for the same {@code sparseIndex}.
* <p>
* @param sparseIndex should be value less than {@link #sparseSize()} specifying which
* table entry to access.
* @throws ArrayIndexOutOfBoundsException if {@code sparseIndex} is not in range [0,{@link #sparseSize}).
* @see #getEnergyForIndices(int...)
* @see #getWeightForSparseIndex(int)
*/
public abstract double getEnergyForSparseIndex(int sparseIndex);
/**
* Returns the energy of factor table entry with given {@code indices}.
* <p>
* @see #getEnergyForElements(Object...)
* @see #getEnergyForSparseIndex(int)
* @see #getWeightForIndices(int...)
*/
public abstract double getEnergyForIndices(int ... indices);
public abstract double getEnergyForValues(Value ... values);
/**
* If {@link #isDirected()} returns object indicating the indices of the subset of dimensions/domains
* that represent inputs or the "from" size of the directionality. Returns null if table is not
* directed. The output set is simply the inverse of the input set (i.e. represented by the clear
* bits instead of the set bits).
* @see #getOutputSet
*/
public @Nullable BitSet getInputSet();
/**
* If {@link #isDirected()} returns object indicating the indices of the subset of dimensions/domains
* that represent outputs or the "to" size of the directionality. Returns null if table is not
* directed. The input set is simply the inverse of the output set (i.e. represented by the clear
* bits instead of the set bits).
* @see #getInputSet()
*/
public @Nullable BitSet getOutputSet();
/**
* Returns weight of factor table entry for given {@code elements}.
* <p>
* @see #getWeightForIndices(int...)
* @see #getEnergyForElements(Object...)
*/
public abstract double getWeightForElements(Object ... elements);
/**
* Returns weight of factor table entry for given {@code jointIndex}.
* <p>
* @see #getEnergyForJointIndex(int)
*/
public abstract double getWeightForJointIndex(int jointIndex);
/**
* Returns weight of factor table entry at given {@code sparseIndex}.
* <p>
* @param sparseIndex should be value less than {@link #sparseSize()} specifying which
* table entry to access.
* @throws ArrayIndexOutOfBoundsException if {@code sparseIndex} is not in range [0, {@link #sparseSize}).
* @see #getWeightForIndices(int...)
* @see #getEnergyForSparseIndex(int)
*/
public abstract double getWeightForSparseIndex(int sparseIndex);
/**
* Returns the weight of factor table entry with given {@code indices}.
* <p>
* @see #getWeightForElements(Object[])
* @see #getWeightForSparseIndex(int)
* @see #getEnergyForIndices(int[])
*/
public abstract double getWeightForIndices(int ... indices);
public abstract double getWeightForValues(Value ... values);
/**
* True if either {@link #hasDenseEnergies()} or {@link #hasDenseWeights()} is true.
*/
public abstract boolean hasDenseRepresentation();
/**
* True if underlying representation of table values includes an array of energies
* indexed by joint index.
* <p>
* This is the optimal representation for methods that get/set energy by joint index
* or combined element indices.
* <p>
* @see #hasDenseWeights()
* @see #hasSparseEnergies()
*/
public abstract boolean hasDenseEnergies();
/**
* True if underlying representation of table values includes an array of weights
* indexed by joint index.
* <p>
* This is the optimal representation for methods that get/set weight by joint index
* or combined element indices.
* <p>
* @see #hasDenseEnergies()
* @see #hasSparseWeights()
*/
public abstract boolean hasDenseWeights();
/**
* True if table has {@link #density()} is 1.0 and there are no zero weights.
*
* @since 0.05
*/
public abstract boolean hasMaximumDensity();
/**
* True if underlying representation contains a sparse representation of non-zero weights.
* <p>
* True if {@link #hasSparseEnergies()}, {@link #hasSparseWeights()} or {@link #isDeterministicDirected()}.
*/
public abstract boolean hasSparseRepresentation();
/**
* True if underlying representation of table values includes an array of energies
* indexed by a sparse index and a second array that maps sparse indices to joint indices.
* <p>
* This is the optimal representation for methods that get/set energy by sparse index.
* <p>
* @see #hasSparseWeights()
* @see #hasDenseEnergies()
*/
public abstract boolean hasSparseEnergies();
/**
* True if underlying representation of table values includes an array of weights
* indexed by a sparse index and a second array that maps sparse indices to joint indices.
* <p>
* This is the optimal representation for methods that get/set weight by sparse index.
* <p>
* @see #hasSparseEnergies()
* @see #hasDenseWeights()
*/
public abstract boolean hasSparseWeights();
/**
* True if table {@link #isDirected()} and has exactly one entry for each combination of
* input indices with a non-zero weight.
* @see #evalDeterministic(Value[])
*/
public abstract boolean isDeterministicDirected();
/**
* True if table is in form appropriate for conditional distribution, i.e. if it is directed and the
* sum of the weights of entries for any given combination of input elements is a constant.
* <p>
* @see #isDirected()
* @see #normalizeConditional()
*/
public abstract boolean isConditional();
/**
* True if table has designated input/output domains directed, in which case
* {@link #getInputSet()} will be non-null.
* <p>
* For most applications the table should have weights normalized so that {@link #isConditional()}
* also is true.
*/
public abstract boolean isDirected();
/**
* True if the table is not directed and its weights add up to 1.0
* <p>
* @see #isDirected()
*/
public abstract boolean isNormalized();
/**
* The number of possible combinations of the values of all the domains in this table.
* Same as {@link JointDomainIndexer#getCardinality()} of {@link #getDomainIndexer()}.
* @see #sparseSize()
*/
public abstract int jointSize();
/**
* Computes sparse index for the table entry associated with the specified arguments.
* <p>
* @param elements must have length equal to {@link #getDimensions()} and each argument must
* be an element of the corresponding domain.
* @see #sparseIndexFromIndices(int[])
* @see #sparseIndexFromElements(Object[])
*/
public abstract int sparseIndexFromElements(Object ... elements);
/**
* Computes a sparse index for the table entry associated with the specified {@code indices}.
*
* @param indices must have length equal to {@link #getDimensions()} and each index must be a non-negative
* value less than the corresponding domain size otherwise the function could return an
* incorrect result.
* @see #sparseIndexFromElements
* @see #sparseIndexToIndices
* @return sparse index for table entry with given set of indices. Returns negative value if there is no such
* entry.
*/
public abstract int sparseIndexFromIndices(int... indices);
public abstract int sparseIndexFromValues(Value ... values);
/**
* Converts joint index (oner per valid combination of domain indices) to sparse index.
* <p>
* @return if {@code joint} has a corresponding table entry its location is returned as
* a number in the range [0,{@link #sparseSize}), otherwise it returns -1-{@code location} where
* {@code location} is the location where the entry would be if it were in the table.
* @see #sparseIndexToJointIndex
*/
public abstract int sparseIndexFromJointIndex(int joint);
/**
* Computes domain values corresponding to given joint index.
* <p>
* @param sparseIndex index in the range [0,{@link #sparseSize}).
* @param elements if this is an array of length {@link #getDimensions()}, the computed values will
* be placed in this array, otherwise a new array will be allocated.
* @see #sparseIndexToIndices(int, int[])
* @see #sparseIndexFromElements(Object...)
*/
public abstract Object[] sparseIndexToElements(int sparseIndex, @Nullable Object[] elements);
/**
* Converts sparse index (one per table entry) to joint index (one per valid combination
* of domain indices).
* <p>
* The sparse and joint index values should have the same ordering relationship, so that
* <pre>
* sparse1 < sparse2</pre>
* implies that
* <pre>
* t.sparseIndexToJointIndex(sparse1) < t.sparseIndexToJointIndex(sparse2)
* </pre>
* <p>
* @return joint index in range [0,{@link #jointSize}).
* @see #sparseIndexFromJointIndex(int)
*/
public abstract int sparseIndexToJointIndex(int sparseIndex);
/**
* Computes domain indices corresponding to given sparse index.
*
* @param sparseIndex index in range [0,{@link #sparseSize}).
* @param indices if this is an array of length {@link #getDimensions()}, the computed values will
* be placed in this array, otherwise a new array will be allocated.
* @see #sparseIndexToElements(int, Object[])
* @see #sparseIndexFromIndices(int...)
*/
public abstract int[] sparseIndexToIndices(int sparseIndex, @Nullable int[] indices);
public abstract int[] sparseIndexToIndices(int sparseIndex);
/**
* Normalizes the weights/energies of the table by dividing by a constant to ensure that
* weights add up to one.
* <p>
* @throws UnsupportedOperationException if {@link #isDirected()}, use {@link #normalizeConditional()} instead.
* <p>
* @see #isNormalized()
*/
public abstract void normalize();
/**
* Normalizes the weights/energies of directed table to ensure that weights applicable to any
* combination of input elements add up to one.
* <p>
* @throws UnsupportedOperationException if not {@link #isDirected()}, use {@link #normalize()} instead.
* <p>
* @see #isConditional()
* @see #normalizeConditional()
*/
public abstract void normalizeConditional();
/**
* Normalizes the weights/energies of directed table to ensure that weights applicable to any
* combination of input elements add up to one.
* <p>
* @param ignoreZeroWeightInputs if true, then any input whose entries adds up to zero will not
* be normalized, if false a {@link DimpleException} will be thrown.
* @return number of inputs that were not normalized (always zero if {@code ignoreZeroWeightInputs} is false.
* @since 0.08
* @see #normalizeConditional()
*/
public abstract int normalizeConditional(boolean ignoreZeroWeightInputs);
/**
* Sets the table value indexed by the specified {@code elements} to the given {@code energy} value.
* <p>
* @see #getEnergyForElements(Object...)
* @see #setEnergyForIndices(double, int...)
* @see #setEnergyForJointIndex(double, int)
* @see #setWeightForElements(double, Object...)
*/
public void setEnergyForElements(double energy, Object ... elements);
/**
* Sets the table value indexed by the specified {@code indices} to the given {@code energy} value.
* <p>
* @see #getEnergyForJointIndex(int jointIndex)
* @see #setEnergyForSparseIndex(double, int)
* @see #setWeightForJointIndex(double, int)
*/
public void setEnergyForIndices(double energy, int ... indices);
/**
* Sets the table value indexed by the specified {@code values} to the given {@code energy} value.
* <p>
* @see #getEnergyForJointIndex(int jointIndex)
* @see #setEnergyForSparseIndex(double, int)
* @see #setWeightForJointIndex(double, int)
*/
public void setEnergyForValues(double energy, Value ... values);
/**
* Sets the table value indexed by the specified {@code sparseIndex} to the given {@code energy} value.
* <p>
* @see #getEnergyForJointIndex(int jointIndex)
* @see #setEnergyForSparseIndex(double, int)
* @see #setWeightForJointIndex(double, int)
*/
public void setEnergyForSparseIndex(double energy, int sparseIndex);
/**
* Sets the table value indexed by the specified {@code jointIndex} to the given {@code energy} value.
* <p>
* @see #getEnergyForJointIndex(int jointIndex)
* @see #setEnergyForSparseIndex(double, int)
* @see #setWeightForJointIndex(double, int)
*/
public void setEnergyForJointIndex(double energy, int jointIndex);
/**
* Sets the table value indexed by the specified {@code elements} to the given {@code weight} value.
* <p>
* @see #getWeightForElements(Object...)
* @see #setWeightForIndices(double, int...)
* @see #setWeightForJointIndex(double, int)
* @see #setEnergyForElements(double, Object...)
*/
public void setWeightForElements(double weight, Object ... elements);
/**
* Sets the table value indexed by the specified {@code indices} to the given {@code weight} value.
* <p>
* @see #getWeightForJointIndex(int jointIndex)
* @see #setWeightForSparseIndex(double, int)
* @see #setEnergyForJointIndex(double, int)
*/
public void setWeightForIndices(double weight, int ... indices);
/**
* Sets the table value indexed by the specified {@code values} to the given {@code weight} value.
* <p>
* @see #getWeightForJointIndex(int jointIndex)
* @see #setWeightForSparseIndex(double, int)
* @see #setEnergyForJointIndex(double, int)
*/
public void setWeightForValues(double weight, Value ... values);
/**
* Sets the table value indexed by the specified {@code sparseIndex} to the given {@code weight} value.
* <p>
* @see #getWeightForJointIndex(int jointIndex)
* @see #setWeightForSparseIndex(double, int)
* @see #setEnergyForJointIndex(double, int)
*/
public void setWeightForSparseIndex(double weight, int sparseIndex);
/**
* Sets the table value indexed by the specified {@code jointIndex} to the given {@code energy} value.
* <p>
* @see #getEnergyForJointIndex(int jointIndex)
* @see #setEnergyForSparseIndex(double, int)
* @see #setWeightForJointIndex(double, int)
*/
public void setWeightForJointIndex(double weight, int jointIndex);
/**
* The number of entries in the table that can be accessed by a sparse index.
* This can be no larger than {@link #jointSize()} and if smaller, indicates that
* the table has a sparse representation that does not include combinations with
* zero weight/infinite energy. The actual number of non-zero weight entries may
* be less than the sparse size.
*/
public abstract int sparseSize();
/**
* True if table supports operations involving {@code jointIndex} values or dense representation. If false,
* then methods that return or use such arguments will throw an {@link UnsupportedOperationException}.
*/
public boolean supportsJointIndexing();
}