/******************************************************************************* * 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; } }