/*
* SwapParameterOperator.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.operators;
import dr.inference.model.Bounds;
import dr.inference.model.Parameter;
import dr.inferencexml.operators.SwapOperatorParser;
import dr.math.MathUtils;
import java.util.List;
/**
* A generic operator swapping all values (dimensions) between two or more parameters
*
* @author Marc A. Suchard
*/
public class SwapParameterOperator extends SimpleMCMCOperator {
public SwapParameterOperator(List<Parameter> parameterList, double weight) {
this.parameterList = parameterList;
if (parameterList.size() < 2) {
throw new IllegalArgumentException("More than 1 parameter is needed");
}
int size = parameterList.get(0).getDimension();
for (int i = 1; i < parameterList.size(); ++i) {
if (size != parameterList.get(i).getDimension()) {
throw new IllegalArgumentException("All parameters most be the same size");
}
}
setWeight(weight);
}
/**
* swap all values in two random parameters.
*/
public final double doOperation() {
int i = MathUtils.nextInt(parameterList.size());
int j = i;
while (j == i) {
j = MathUtils.nextInt(parameterList.size());
}
final Parameter a = parameterList.get(i);
final Parameter b = parameterList.get(j);
Bounds<Double> aBounds = a.getBounds();
Bounds<Double> bBounds = b.getBounds();
for (int k = 0; k < a.getDimension(); ++k) {
final double ak = a.getParameterValue(k);
final double bk = b.getParameterValue(k);
// Check bk outside of aBounds or ak outside of bBounds
if (isOutside(aBounds, bk, k) || isOutside(bBounds, ak, k)) {
// throw new OperatorFailedException("proposed value outside boundaries");
return Double.NEGATIVE_INFINITY;
}
// Swap
a.setParameterValueQuietly(k, bk);
b.setParameterValueQuietly(k, ak);
}
a.fireParameterChangedEvent();
b.fireParameterChangedEvent();
return 0.0;
}
private boolean isOutside(final Bounds<Double> bounds, final double x, final int index) {
return (x < bounds.getLowerLimit(index) || x > bounds.getUpperLimit(index));
}
private String getParameterNames() {
if (parameterNames == null) {
StringBuilder sb = new StringBuilder();
for (Parameter p : parameterList) {
sb.append(p.getParameterName()).append(".");
}
parameterNames = sb.toString();
}
return parameterNames;
}
public String getOperatorName() {
return SwapOperatorParser.SWAP_OPERATOR + "(" + getParameterNames() + "swap)";
}
public String getPerformanceSuggestion() {
return "No suggestions";
}
private final List<Parameter> parameterList;
private String parameterNames = null;
}