/******************************************************************************* * Copyright 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.factorfunctions; import com.analog.lyric.dimple.exceptions.DimpleException; import com.analog.lyric.dimple.factorfunctions.core.FactorFunction; import com.analog.lyric.dimple.factorfunctions.core.FactorFunctionUtilities; import com.analog.lyric.dimple.model.values.Value; /** * Binomial distribution. * <p> * Corresponds to p(x | N, p), * where x is a count of the number of ones, N is the total count (ones and zeros), * and p is the probability parameter. * <p> * The conjugate prior for p is a Beta distribution. * Depending on the solver, it may or may not be necessary to use a * conjugate prior (for the Gibbs solver, for example, it is not). * <p> * The variables in the argument list are ordered as follows: * <ol> * <li>N: Parameter indicating the total count (ones and zeros) * <li> p: Probability parameter * <li>x: Count of ones * </ol> * N parameter may optionally be specified as constants in the constructor. * In this case, N is not included in the list of arguments. */ public class Binomial extends FactorFunction { protected int _N; protected double _negativeLogFactorialN; protected boolean _NParameterConstant = false; private int _firstDirectedToIndex = 2; public Binomial() {super((String)null);} // Variable N public Binomial(int N) // Fixed N { this(); _N = N; if (_N < 0) throw new DimpleException("N must be a non-negative value."); _negativeLogFactorialN = -org.apache.commons.math3.special.Gamma.logGamma(_N + 1); _NParameterConstant = true; _firstDirectedToIndex = 1; } @Override public final double evalEnergy(Value[] arguments) { int index = 0; if (!_NParameterConstant) { _N = arguments[index++].getInt(); // First argument is N parameter if (_N < 0) return Double.POSITIVE_INFINITY; _negativeLogFactorialN = -org.apache.commons.math3.special.Gamma.logGamma(_N + 1); } final double p = arguments[index++].getDouble(); // Next argument is the probability parameter if (p < 0 || p > 1) return Double.POSITIVE_INFINITY; final int numOnes = arguments[index++].getInt(); // Next argument is the one-count if (numOnes < 0 || numOnes > _N) return Double.POSITIVE_INFINITY; int numZeros = _N - numOnes; if (p == 0) if (numOnes > 0) return Double.POSITIVE_INFINITY; else return 0; else if (p == 1) if (numZeros > 0) return Double.POSITIVE_INFINITY; else return 0; else return -(numOnes * Math.log(p) + numZeros * Math.log(1-p)) + _negativeLogFactorialN + org.apache.commons.math3.special.Gamma.logGamma(numOnes + 1) + org.apache.commons.math3.special.Gamma.logGamma(numZeros + 1); } @Override public final boolean isDirected() {return true;} @Override public final int[] getDirectedToIndices(int numEdges) { // All edges except the parameter edges (if present) are directed-to edges return FactorFunctionUtilities.getListOfIndices(_firstDirectedToIndex, numEdges-1); } // Factor-specific methods public final boolean hasConstantNParameter() { return _NParameterConstant; } public final int getN() { return _N; } }