/*******************************************************************************
* Copyright 2012-2013 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.solvers.core;
import static java.util.Objects.*;
import org.eclipse.jdt.annotation.Nullable;
import com.analog.lyric.dimple.exceptions.DimpleException;
import com.analog.lyric.dimple.factorfunctions.core.IFactorTable;
import com.analog.lyric.dimple.model.domains.DomainList;
import com.analog.lyric.dimple.model.domains.JointDomainIndexer;
import com.analog.lyric.dimple.model.factors.Factor;
import com.analog.lyric.dimple.options.SolverOptions;
import com.analog.lyric.dimple.solvers.interfaces.ISolverFactorGraph;
public abstract class STableFactorBase extends SFactorBase
{
/*-------
* State
*/
private @Nullable IFactorTable _factorTable = null;
/*--------------
* Construction
*/
protected STableFactorBase(Factor factor, ISolverFactorGraph parent)
{
super(factor, parent);
if (!factor.isDiscrete())
throw new DimpleException("only discrete factors supported");
}
/*---------------------
* SFactorBase methods
*/
@Override
public int [][] getPossibleBeliefIndices()
{
return getFactorTable().getIndicesSparseUnsafe();
}
@Override
public void initialize()
{
super.initialize();
if (createFactorTableOnInit())
{
getFactorTable();
}
}
/*--------------------------
* STableFactorBase methods
*/
/**
* Removes current factor table instance.
* <p>
* After invoking this, {@link #getFactorTableIfComputed()} will return null.
* <p>
* The factor table can be recreated by calling {@link #getFactorTable()}.
* <p>
* @since 0.08
*/
public void clearFactorTable()
{
_factorTable = null;
}
/**
* Indicate whether {@link #initialize()} should call {@link #getFactorTable()} to
* force factor table creation (e.g. to avoid lazy initialization for multithreading
* solvers.
* <p>
* The default implementation returns true if the <em>cardinality</em> of the factor is no greater than
* {@link SolverOptions#maxAutomaticFactorTableSize}, where the <em>cardinality</em> is computed by multiplying
* the dimensions of the independent domains of the factor, i.e. the input domains if the factor is
* deterministic directed and otherwise all of the domains.
*/
protected boolean createFactorTableOnInit()
{
final DomainList<?> domains = getFactor().getDomainList();
final JointDomainIndexer indexer = domains.asJointDomainIndexer();
if (indexer == null || !indexer.supportsJointIndexing())
{
return false;
}
int maxSize = getOptionOrDefault(SolverOptions.maxAutomaticFactorTableSize);
if (maxSize <= 0)
{
return false;
}
final int cardinality = indexer.isDirected() && getFactor().getFactorFunction().isDeterministicDirected() ?
indexer.getInputCardinality() : indexer.getCardinality();
return cardinality <= getOptionOrDefault(SolverOptions.maxAutomaticFactorTableSize);
}
/**
* Returns factor table for this factor, creating it if necessary.
* <p>
* Note that creation can be expensive for large joint cardinality of domains since the
* factor function must be evaluated for all possible combinations of values!
*
* @see #getFactorTableIfComputed()
*/
public final IFactorTable getFactorTable()
{
IFactorTable factorTable = _factorTable;
if (factorTable==null)
{
factorTable = _factorTable = getFactor().getFactorTable();
setTableRepresentation(factorTable);
}
return factorTable;
}
/**
* Returns factor table for this factor if it has been created, else null.
* <p>
* @see #getFactorTable()
* @since 0.08
*/
public final @Nullable IFactorTable getFactorTableIfComputed()
{
return _factorTable;
}
/**
* Returns the dimension of the ith variable, assumed to be discrete
* @since 0.08
*/
protected int getSiblingDimension(int i)
{
return requireNonNull(getSibling(i).getDomain().asDiscrete()).size();
}
/**
* Sets representation of {@code table} for optimal performance for particular
* solver implementation.
* <p>
* Called by {@link STableFactorBase#getFactorTable()} the first time it is called
* on this object, and is also called by {@link STableFactorBase#initialize()}.
* <p>
* @param table
*/
protected abstract void setTableRepresentation(IFactorTable table);
}