/*******************************************************************************
* 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.solvers.core;
import java.util.List;
import org.eclipse.jdt.annotation.Nullable;
import com.analog.lyric.dimple.data.IDatum;
import com.analog.lyric.dimple.environment.DimpleEnvironment;
import com.analog.lyric.dimple.exceptions.DimpleException;
import com.analog.lyric.dimple.model.domains.DiscreteDomain;
import com.analog.lyric.dimple.model.values.Value;
import com.analog.lyric.dimple.model.variables.Discrete;
import com.analog.lyric.dimple.solvers.core.parameterizedMessages.DiscreteEnergyMessage;
import com.analog.lyric.dimple.solvers.core.parameterizedMessages.DiscreteMessage;
import com.analog.lyric.dimple.solvers.interfaces.IDiscreteSolverVariable;
import com.analog.lyric.dimple.solvers.interfaces.ISolverFactorGraph;
import com.analog.lyric.util.misc.Internal;
public abstract class SDiscreteVariableBase extends SVariableBase<Discrete> implements IDiscreteSolverVariable
{
protected int _guessIndex = -1;
protected boolean _guessWasSet = false;
protected SDiscreteVariableBase(Discrete var, ISolverFactorGraph parent)
{
super(var, parent);
}
@Override
public void initialize()
{
super.initialize();
setGuess(null);
}
/*-------------------------
* ISolverVariable methods
*/
@Override
public abstract double[] getBelief();
@Override
public DiscreteDomain getDomain()
{
return getModelObject().getDomain();
}
@Override
public Object getValue()
{
int index = getValueIndex();
return _model.getDiscreteDomain().getElement(index);
}
@Override
public int getValueIndex()
{
PriorAndCondition known = getPriorAndCondition();
final Value value = known.value();
known = known.release();
if (value != null)
{
return value.getIndex();
}
double[] belief = getBelief();
int numValues = belief.length;
double maxBelief = Double.NEGATIVE_INFINITY;
int maxBeliefIndex = -1;
for (int i = 0; i < numValues; i++)
{
double b = belief[i];
if (b > maxBelief)
{
maxBelief = b;
maxBeliefIndex = i;
}
}
return maxBeliefIndex;
}
@Override
public boolean guessWasSet()
{
return _guessWasSet;
}
@Override
public Object getGuess()
{
int index = getGuessIndex();
return _model.getDomain().getElement(index);
}
@Override
public void setGuess(@Nullable Object guess)
{
if (guess == null)
{
_guessWasSet = false;
_guessIndex = -1;
}
else
{
DiscreteDomain domain = _model.getDomain();
setGuessIndex(domain.getIndexOrThrow(guess));
}
}
@Override
public int getGuessIndex()
{
int index = 0;
if (_guessWasSet)
index = _guessIndex;
else
index = getValueIndex();
return index;
}
@Override
public void setGuessIndex(int index)
{
if (index < 0 || index >= _model.getDomain().size())
throw new DimpleException("illegal index");
_guessWasSet = true;
_guessIndex = index;
}
/*------------------
* Internal methods
*/
/**
* Gets prior from model as a {@link DiscreteMessage}
* <p>
* Returns null if prior is not a {@link DiscreteMessage}. Logs error if prior
* is not a {@link Value} or {@link DiscreteMessage}.
* @since 0.08
* @category internal
*/
@Deprecated
@Internal
public @Nullable DiscreteMessage getPrior()
{
IDatum prior = _model.getPrior();
if (prior instanceof DiscreteMessage || prior == null)
return (DiscreteMessage)prior;
if (!(prior instanceof Value))
{
DimpleEnvironment.logError("Prior %s ignored on %s: type not supported", prior, _model);
}
return null;
}
/**
* Converts data for variable to a single {@link DiscreteEnergyMessage}
* <p>
* Simply calls {@link DiscreteEnergyMessage#convertFrom(DiscreteDomain, List)} with
* this variable's {@linkplain #getDomain domain}.
* <p>
* @param data is any list of data compatible with this variable, but is typically expected to be
* a {@link PriorAndCondition} instance.
* @since 0.08
* @see #getPriorAndCondition()
*/
protected @Nullable DiscreteEnergyMessage toEnergyMessage(List<IDatum> data)
{
return DiscreteEnergyMessage.convertFrom(getDomain(),data);
}
protected @Nullable DiscreteEnergyMessage knownEnergyMessage()
{
final PriorAndCondition known = getPriorAndCondition();
final DiscreteEnergyMessage msg = toEnergyMessage(known);
known.release();
return msg;
}
}