/******************************************************************************* * 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.lp; import java.io.PrintStream; import java.util.Arrays; import java.util.Objects; import net.jcip.annotations.NotThreadSafe; import org.eclipse.jdt.annotation.Nullable; /** * Represents a linear equality describing the constraint that the marginal probability * of a particular value of a variable is equal to the sum of of the joint probabilities * that include that variable value. The equation is of the form: * <p> * -pv + pjv1 + pjv2 + ... + pjv2 = 0 * </p> * Unlike {@link LPVariableConstraint} the variable identifiers are not expected to * be contiguous, but the first variable identifier always refers to the variable * value's marginal probability. */ public final class LPFactorMarginalConstraint extends IntegerEquation { @NotThreadSafe public static class TermIterator implements IntegerEquation.TermIterator { private int _index; private @Nullable int[] _lpVars; TermIterator(@Nullable LPFactorMarginalConstraint constraint) { reset(constraint); } /** * Reset the iterator from a new variable constraint. */ public TermIterator reset(@Nullable LPFactorMarginalConstraint constraint) { _index = -1; _lpVars = constraint != null ? constraint._lpVars : null; return this; } @Override public boolean advance() { final int[] lpVars = _lpVars; return lpVars != null && ++_index < lpVars.length; } @Override public int getVariable() { return Objects.requireNonNull(_lpVars)[_index]; } @Override public int getCoefficient() { return _index == 0 ? -1 : 1; } } /*------- * State */ private final LPTableFactor _sfactor; private final int[] _lpVars; /*--------------- * Construction */ public LPFactorMarginalConstraint(LPTableFactor sfactor, int...lpVars) { _sfactor = sfactor; _lpVars = lpVars; } /*------------------------- * IntegerEquation methods */ /** * Returns non-null if this is a {@link LPFactorMarginalConstraint}. */ @Override public LPFactorMarginalConstraint asFactorConstraint() { return this; } @Override public int getCoefficient(int variable) { int i = Arrays.binarySearch(_lpVars, variable); if (i >= 0) { return i == 0 ? -1 : 1; } return 0; } @Override public int getRHS() { return 0; } @Override public TermIterator getTerms() { return new TermIterator(this); } @Override public int[] getVariables() { return _lpVars.clone(); } @Override public boolean hasCoefficient(int variable) { return Arrays.binarySearch(_lpVars, variable) >= 0; } @Override public void print(PrintStream out) { _sfactor.printConstraintEquation(out, _lpVars); } @Override public int size() { return _lpVars.length; } /** * Returns the Dimple solver factor for which this constraint was generated. */ public LPTableFactor getSolverFactor() { return _sfactor; } }