package beast.evolution.operators;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import beast.core.Description;
import beast.core.Input;
import beast.core.Input.Validate;
import beast.core.Operator;
import beast.core.parameter.IntegerParameter;
import beast.core.parameter.Parameter;
import beast.core.parameter.RealParameter;
import beast.util.Randomizer;
@Description("A generic operator swapping a one or more pairs in a multi-dimensional parameter")
public class SwapOperator extends Operator {
final public Input<RealParameter> parameterInput = new Input<>("parameter", "a real parameter to swap individual values for");
final public Input<IntegerParameter> intparameterInput = new Input<>("intparameter", "an integer parameter to swap individual values for", Validate.XOR, parameterInput);
final public Input<Integer> howManyInput = new Input<>("howMany", "number of items to swap, default 1, must be less than half the dimension of the parameter", 1);
int howMany;
Parameter<?> parameter;
private List<Integer> masterList = null;
@Override
public void initAndValidate() {
if (parameterInput.get() != null) {
parameter = parameterInput.get();
} else {
parameter = intparameterInput.get();
}
howMany = howManyInput.get();
if (howMany * 2 > parameter.getDimension()) {
throw new IllegalArgumentException("howMany it too large: must be less than half the dimension of the parameter");
}
List<Integer> list = new ArrayList<>();
for (int i = 0; i < parameter.getDimension(); i++) {
list.add(i);
}
masterList = Collections.unmodifiableList(list);
}
@Override
public double proposal() {
List<Integer> allIndices = new ArrayList<>(masterList);
int left, right;
for (int i = 0; i < howMany; i++) {
left = allIndices.remove(Randomizer.nextInt(allIndices.size()));
right = allIndices.remove(Randomizer.nextInt(allIndices.size()));
parameter.swap(left, right);
}
return 0.0;
}
}