/******************************************************************************* * 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.solvers.optimizedupdate; import com.analog.lyric.collect.ArrayUtil; import com.analog.lyric.dimple.factorfunctions.core.IFactorTable; import com.analog.lyric.dimple.model.domains.JointDomainIndexer; import com.analog.lyric.util.misc.Internal; /** * Similar to the {@link TableWrapper} class, but for the purpose of estimating the cost of * employing the optimized update algorithm. Instead of storing a factor table's data, this * implementation only stores information about its dimensions and its density. * * @since 0.07 * @author jking */ @Internal public final class CostEstimationTableWrapper { /** * The density of the represented factor table. A value between 0.0 and 1.0. */ private final double _density; /** * The dimensions of the represented factor table. */ private final int[] _dimensions; /** * True if the represented factor table is sparse. */ private final boolean _isSparse; /** * Provides solver-specific facilities. */ private final ISFactorGraphToOptimizedUpdateAdapter _sFactorGraphAdapter; /** * The quantity of entries in the represented factor table. */ private final double _size; /** * Density threshold below which a sparse representation should be preferred over a dense * representation. A value between 0.0 and 1.0. */ private final double _sparseThreshold; public CostEstimationTableWrapper(final IFactorTable factorTable, ISFactorGraphToOptimizedUpdateAdapter sFactorGraphAdapter, final double sparseThreshold) { this(getFactorTableDimensions(factorTable), factorTable.density(), sFactorGraphAdapter, sparseThreshold); } public CostEstimationTableWrapper(final int[] dimensions, final double density, ISFactorGraphToOptimizedUpdateAdapter sFactorGraphAdapter, double sparseThreshold) { _dimensions = dimensions; _density = density; _sFactorGraphAdapter = sFactorGraphAdapter; _sparseThreshold = sparseThreshold; _isSparse = _density < _sparseThreshold; double cardinality = 1.0; for (int i = 0; i < dimensions.length; i++) { cardinality *= dimensions[i]; } _size = cardinality * density; } public IMarginalizationStepEstimator createMarginalizationStep(final int inPortNum, final int dimension) { final int[] g_dimensions = ArrayUtil.removeIntArrayEntry(getDimensions(), dimension); final double g_density = 1.0 - Math.pow(1 - _density, getDimensions()[dimension]); CostEstimationTableWrapper g = new CostEstimationTableWrapper(g_dimensions, g_density, _sFactorGraphAdapter, _sparseThreshold); if (_isSparse) { return _sFactorGraphAdapter.createSparseMarginalizationStepEstimator(this, inPortNum, dimension, g); } else { return _sFactorGraphAdapter.createDenseMarginalizationStepEstimator(this, inPortNum, dimension, g); } } public IUpdateStepEstimator createOutputStep(final int outPortNum) { if (_isSparse) { return _sFactorGraphAdapter.createSparseOutputStepEstimator(this); } else { return _sFactorGraphAdapter.createDenseOutputStepEstimator(this); } } /** * Estimates costs associated with the table. The costs include the memory required to store * the table. * * @since 0.07 */ public Costs estimateCosts() { final double allocations; final double _tableData = _size * 8; if (_isSparse) { final double sparseToJointIndices = _size * 4; final double sparseIndices = _size * _dimensions.length * 4; allocations = _tableData + sparseToJointIndices + sparseIndices; } else { allocations = _tableData; } Costs result = new Costs(); result.put(CostType.MEMORY, allocations / 1024.0 / 1024.0 / 1024.0); return result; } public int[] getDimensions() { return _dimensions; } public double getSize() { return _size; } /* * A helper function for a constructor that calls another constructor. */ private static int[] getFactorTableDimensions(final IFactorTable factorTable) { JointDomainIndexer indexer = factorTable.getDomainIndexer(); int[] dimensions = new int[factorTable.getDimensions()]; for (int i = 0; i < dimensions.length; i++) { dimensions[i] = indexer.getDomainSize(i); } return dimensions; } }