/* * Variable.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.inference.model; import dr.inference.loggers.LogColumn; import dr.inference.loggers.Loggable; import dr.inference.loggers.NumberColumn; import dr.util.Identifiable; import java.util.ArrayList; import java.util.List; /** * A generic random variable. * * @author Alexei Drummond */ public interface Variable<V> extends Identifiable { public enum ChangeType { VALUE_CHANGED, REMOVED, ADDED, ALL_VALUES_CHANGED } /** * @return the name of this variable. */ public String getVariableName(); public V getValue(int index); public void setValue(int index, V value); public V[] getValues(); /** * @return the size of this variable - i.e. the length of the vector */ public int getSize(); /** * adds a parameter listener that is notified when this parameter changes. * * @param listener the listener */ void addVariableListener(VariableListener listener); /** * removes a parameter listener. * * @param listener the listener */ void removeVariableListener(VariableListener listener); /** * stores the state of this parameter for subsequent restore */ void storeVariableValues(); /** * restores the stored state of this parameter */ void restoreVariableValues(); /** * accepts the stored state of this parameter */ void acceptVariableValues(); /** * @return the bounds on this parameter */ Bounds<V> getBounds(); void addBounds(Bounds<V> bounds); public abstract class Base<V> implements Variable<V>, Loggable { Base(String id) { this.id = id; } protected void fireVariableChanged(int index) { for (VariableListener listener : listeners) { listener.variableChangedEvent(this, index, ChangeType.VALUE_CHANGED); } } public void addVariableListener(VariableListener listener) { listeners.add(listener); } public void removeVariableListener(VariableListener listener) { listeners.remove(listener); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getVariableName() { return id; } protected List<VariableListener> listeners = new ArrayList<VariableListener>(); protected String id; } public abstract class BaseNumerical<V extends Number> extends Base<V> { BaseNumerical(String id) { super(id); } class StatisticColumn extends NumberColumn { private final int dim; public StatisticColumn(String label, int dim) { super(label); this.dim = dim; } public double getDoubleValue() { return getValue(dim).doubleValue(); } } /** * @return the log columns. */ public LogColumn[] getColumns() { LogColumn[] columns = new LogColumn[getSize()]; if (getSize() == 1) { columns[0] = new StatisticColumn(this.getVariableName(), 0); } else { for (int i = 0; i < getSize(); i++) { columns[i] = new StatisticColumn(this.getVariableName() + "[" + i + "]", i); } } return columns; } } public class D implements Variable<Double>, Loggable { public D(double value, int size) { values = new double[size]; storedValues = new double[values.length]; for (int i = 0; i < size; i++) { values[i] = value; } } public D(double[] v) { values = new double[v.length]; System.arraycopy(v, 0, values, 0, v.length); storedValues = new double[values.length]; } public D(String name, double[] v) { this(v); setId(name); } public D(String name, double value) { this(name, new double[]{value}); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getVariableName() { return id; } public Double getValue(int index) { return values[index]; } public Double[] getValues() { Double[] copyOfValues = new Double[values.length]; for (int i = 0; i < values.length; i++) { copyOfValues[i] = values[i]; } return copyOfValues; } public void setValue(int index, Double value) { values[index] = value; fireVariableChanged(index); } private void fireVariableChanged(int index) { for (VariableListener listener : listeners) { listener.variableChangedEvent(this, index, ChangeType.VALUE_CHANGED); } } public int getSize() { return values.length; } public void addVariableListener(VariableListener listener) { listeners.add(listener); } public void removeVariableListener(VariableListener listener) { listeners.remove(listener); } public void storeVariableValues() { System.arraycopy(values, 0, storedValues, 0, storedValues.length); } public void restoreVariableValues() { double[] temp = storedValues; storedValues = values; values = temp; } public void acceptVariableValues() { } public Bounds<Double> getBounds() { if (bounds == null) { return new Bounds<Double>() { public Double getUpperLimit(int dimension) { return Double.MAX_VALUE; } public Double getLowerLimit(int dimension) { return -Double.MAX_VALUE; } public int getBoundsDimension() { return getSize(); } }; } else return bounds; } // ************************************************************** // Loggable IMPLEMENTATION // ************************************************************** /** * @return the log columns. */ public LogColumn[] getColumns() { LogColumn[] columns = new LogColumn[getSize()]; if (getSize() == 1) { columns[0] = new StatisticColumn(getVariableName(), 0); } else { for (int i = 0; i < getSize(); i++) { columns[i] = new StatisticColumn(getVariableName() + "[" + i + "]", i); } } return columns; } /** * Careful use! Do not write to the array provided!! * * @return the underlying array of doubles */ public double[] peekValues() { return values; } public void addBounds(Bounds<Double> b) { if (bounds == null) { bounds = new IntersectionBounds(getSize()); } bounds.addBounds(b); } private class StatisticColumn extends NumberColumn { private final int dim; public StatisticColumn(String label, int dim) { super(label); this.dim = dim; } public double getDoubleValue() { return getValue(dim); } } String id; double[] values; double[] storedValues; List<VariableListener> listeners = new ArrayList<VariableListener>(); private IntersectionBounds bounds = null; } public class DM implements Variable<double[]>, Loggable { public DM(double[][] v) { lower = new double[v.length]; upper = new double[v.length]; values = new double[v.length][v[0].length]; for (int i = 0; i < v.length; i++) { System.arraycopy(v[i], 0, values[i], 0, v[i].length); lower[i] = -Double.MAX_VALUE; upper[i] = Double.MAX_VALUE; } storedValues = new double[values.length][values[0].length]; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getVariableName() { return id; } public double[] getValue(int index) { return values[index]; } public double[][] getValues() { double[][] copyOfValues = new double[values.length][values[0].length]; for (int i = 0; i < values.length; i++) { System.arraycopy(values[i], 0, copyOfValues[i], 0, values[i].length); } return copyOfValues; } public void setValue(int index, double[] value) { System.arraycopy(value, 0, values[index], 0, values[index].length); fireVariableChanged(index); } private void fireVariableChanged(int index) { for (VariableListener listener : listeners) { listener.variableChangedEvent(this, index, ChangeType.VALUE_CHANGED); } } public int getSize() { return values.length; } public void addVariableListener(VariableListener listener) { listeners.add(listener); } public void removeVariableListener(VariableListener listener) { listeners.remove(listener); } public void storeVariableValues() { for (int i = 0; i < values.length; i++) { System.arraycopy(values[i], 0, storedValues[i], 0, storedValues[i].length); } } public void restoreVariableValues() { double[][] temp = storedValues; storedValues = values; values = temp; } public void acceptVariableValues() { } public Bounds<double[]> getBounds() { return new Bounds<double[]>() { public double[] getUpperLimit(int dimension) { return upper; } public double[] getLowerLimit(int dimension) { return lower; } public int getBoundsDimension() { return getSize(); } }; } public void addBounds(Bounds<double[]> bounds) { } // ************************************************************** // Loggable IMPLEMENTATION // ************************************************************** /** * @return the log columns. */ public LogColumn[] getColumns() { LogColumn[] columns = new LogColumn[getSize()]; for (int i = 0; i < getSize(); i++) { double[] values = getValue(i); for (int j = 0; j < values.length; j++) { if (getSize() == 1) { columns[i] = new StatisticColumn(getVariableName() + "[" + j + "]", i, j); } else { columns[i] = new StatisticColumn(getVariableName() + "[" + i + "," + j + "]", i, j); } } } return columns; } private class StatisticColumn extends NumberColumn { private final int i; private final int j; public StatisticColumn(String label, int i, int j) { super(label); this.i = i; this.j = j; } public double getDoubleValue() { return getValue(i)[j]; } } String id; double[][] values; double[][] storedValues; List<VariableListener> listeners = new ArrayList<VariableListener>(); double[] lower; double[] upper; } public class I implements Variable<Integer>, Loggable { public I(int value, int size) { values = new int[size]; storedValues = new int[values.length]; for (int i = 0; i < size; i++) { values[i] = value; } } public I(int[] v) { values = new int[v.length]; System.arraycopy(v, 0, values, 0, v.length); storedValues = new int[values.length]; } public I(String name, int[] v) { this(v); setId(name); } public I(String name, int value) { this(name, new int[]{value}); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getVariableName() { return id; } public Integer getValue(int index) { return values[index]; } public Integer[] getValues() { Integer[] copyOfValues = new Integer[values.length]; for (int i = 0; i < values.length; i++) { copyOfValues[i] = values[i]; } return copyOfValues; } public void setValue(int index, Integer value) { values[index] = value; fireVariableChanged(index); } private void fireVariableChanged(int index) { for (VariableListener listener : listeners) { listener.variableChangedEvent(this, index, ChangeType.VALUE_CHANGED); } } public int getSize() { return values.length; } public void addVariableListener(VariableListener listener) { listeners.add(listener); } public void removeVariableListener(VariableListener listener) { listeners.remove(listener); } public void storeVariableValues() { System.arraycopy(values, 0, storedValues, 0, storedValues.length); } public void restoreVariableValues() { int[] temp = storedValues; storedValues = values; values = temp; } public void acceptVariableValues() { } public Bounds<Integer> getBounds() { if (bounds == null) { return new Bounds<Integer>() { public Integer getUpperLimit(int dimension) { return Integer.MAX_VALUE; } public Integer getLowerLimit(int dimension) { return -Integer.MAX_VALUE; } public int getBoundsDimension() { return getSize(); } }; } else return bounds; } // ************************************************************** // Loggable IMPLEMENTATION // ************************************************************** /** * @return the log columns. */ public LogColumn[] getColumns() { LogColumn[] columns = new LogColumn[getSize()]; if (getSize() == 1) { columns[0] = new StatisticColumn(getVariableName(), 0); } else { for (int i = 0; i < getSize(); i++) { columns[i] = new StatisticColumn(getVariableName() + "[" + i + "]", i); } } return columns; } /** * Careful use! Do not write to the array provided!! * * @return the underlying array of doubles */ public int[] peekValues() { return values; } public void addBounds(Bounds<Integer> b) { if (bounds == null) { bounds = b; } else { if (!(bounds instanceof Bounds.Staircase)) { Bounds.Staircase newBounds = new Bounds.Staircase(getSize()); newBounds.addBounds(bounds); bounds = newBounds; } ((Bounds.Staircase) bounds).addBounds(b); } } private class StatisticColumn extends NumberColumn { private final int dim; public StatisticColumn(String label, int dim) { super(label); this.dim = dim; } public double getDoubleValue() { return getValue(dim); } } String id; int[] values; int[] storedValues; List<VariableListener> listeners = new ArrayList<VariableListener>(); private Bounds<Integer> bounds = null; } }