/*******************************************************************************
* 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.core.parameterizedMessages;
import static java.lang.String.*;
import java.io.PrintStream;
import org.eclipse.jdt.annotation.Nullable;
import com.analog.lyric.dimple.data.DataRepresentationType;
import com.analog.lyric.dimple.model.domains.Domain;
import com.analog.lyric.dimple.model.values.Value;
import com.analog.lyric.util.misc.IPrintable;
import com.analog.lyric.util.misc.Matlab;
/**
* Base implementation of {@link IParameterizedMessage}
*
* @since 0.06
* @author Christopher Barber
*/
public abstract class ParameterizedMessageBase implements IParameterizedMessage
{
private static final long serialVersionUID = 2L;
/*-------
* State
*/
/**
* Cached value of {@link #getNormalizationEnergy()}, valid if not {@code NaN}.
*/
protected double _normalizationEnergy = Double.NaN;
/*--------------
* Construction
*/
protected ParameterizedMessageBase()
{
}
protected ParameterizedMessageBase(ParameterizedMessageBase other)
{
_normalizationEnergy = other._normalizationEnergy;
}
@Override
public abstract ParameterizedMessageBase clone();
/*----------------
* Object methods
*/
@Override
public String toString()
{
return toString(0);
}
/*---------
* IEquals
*/
@Override
public boolean objectEquals(@Nullable Object other)
{
if (other instanceof ParameterizedMessageBase)
{
ParameterizedMessageBase that = (ParameterizedMessageBase)other;
// Unlike regular ==, this is true if both values are NaN:
return Double.doubleToLongBits(_normalizationEnergy) == Double.doubleToLongBits(that._normalizationEnergy);
}
return false;
}
/*--------------------
* IPrintable methods
*/
@Override
public final void println(PrintStream out, int verbosity)
{
IPrintable.Methods.println(this, out, verbosity);
}
@Override
public String toString(int verbosity)
{
return IPrintable.Methods.toString(this, verbosity);
}
/*----------------
* IDatum methods
*/
/**
* {@inheritDoc}
* <p>
* Returns {@link DataRepresentationType#MESSAGE}.
*/
@Override
public DataRepresentationType representationType()
{
return DataRepresentationType.MESSAGE;
}
/*------------------------------
* IUnaryFactorFunction methods
*/
@Override
@Matlab
public double evalEnergy(Object value)
{
final double energy = evalEnergy(Value.create(value));
return energy == energy ? energy : Double.POSITIVE_INFINITY;
}
public double evalNormalizedEnergy(Value[] values, int startIndex)
{
final int n = values.length;
double energy = (n - startIndex) * -getNormalizationEnergy();
for (int i = startIndex; i < n; ++i)
{
energy += evalEnergy(values[i]);
}
return energy;
}
/*-------------------------------
* IParameterizedMessage methods
*/
@Override
public void addFrom(IParameterizedMessage other)
{
throw new UnsupportedOperationException(format("%s does not support addFrom method",
getClass().getSimpleName()));
}
@Override
public double addNormalizationEnergy(double additionalEnergy)
{
final double energy = getNormalizationEnergy() + additionalEnergy;
_normalizationEnergy = energy;
return energy;
}
@Override
public final double getNormalizationEnergy()
{
double energy = _normalizationEnergy;
if (energy != energy) // NaN
{
_normalizationEnergy = energy = computeNormalizationEnergy();
}
return energy;
}
@Override
public boolean hasDeterministicValue()
{
return false;
}
@Override
public void setDeterministic(Value value)
{
throw new UnsupportedOperationException(format("%s does not support deterministic parameterization",
getClass().getSimpleName()));
}
@Override
public void setNormalizationEnergy(double energy)
{
_normalizationEnergy = energy;
}
@Override
public void setNull()
{
setUniform();
}
@Override
public @Nullable Value toDeterministicValue(Domain domain)
{
return null;
}
/*-------------------
* Protected methods
*/
/**
* Invoked by {@link #getNormalizationEnergy()} to compute the energy based on parameters.
* <p>
* Must not return {@link Double#NaN}.
* @since 0.08
*/
protected abstract double computeNormalizationEnergy();
/**
* Copies normalization energy value from {@code other} message.
* @since 0.08
*/
protected void copyNormalizationEnergy(ParameterizedMessageBase other)
{
_normalizationEnergy = other._normalizationEnergy;
}
/**
* Forget current normalization energy setting, forcing it to be recomputed by {@link #getNormalizationEnergy()}.
* <p>
* Simply sets the stored energy to {@link Double#NaN}.
* @since 0.08
*/
protected void forgetNormalizationEnergy()
{
_normalizationEnergy = Double.NaN;
}
}