package beast.evolution.tree.coalescent;

import beast.core.Description;
import beast.core.Input;
import beast.core.Operator;
import beast.core.parameter.BooleanParameter;
import beast.core.parameter.RealParameter;
import beast.math.distributions.ParametricDistribution;
import beast.util.Randomizer;

/**
 * @author Joseph Heled
 *         Date: 2/03/2011
 */
@Description("Sample values from a distribution")
public class SampleOffValues extends Operator {
    public Input<RealParameter> valuesInput = new Input<RealParameter>("values", "vector of target values", Input.Validate.REQUIRED);

    public Input<BooleanParameter> indicatorsInput = new Input<BooleanParameter>("indicators", "Sample only entries which are 'off'");

    public Input<ParametricDistribution> distInput = new Input<ParametricDistribution>("dist",
            "distribution to sample from.", Input.Validate.REQUIRED);

    public void initAndValidate() {
    }

    @Override
    public double proposal() {
        final BooleanParameter indicators = indicatorsInput.get(this);
        final RealParameter data = valuesInput.get(this);
        final ParametricDistribution distribution = distInput.get();

        final int idim = indicators.getDimension();

        final int offset = (data.getDimension() - 1) == idim ? 1 : 0;
        assert offset == 1 || data.getDimension() == idim : "" + idim + " (?+1) != " + data.getDimension();

        // available locations for direct sampling
        int[] loc = new int[idim];
        int nLoc = 0;

        for (int i = 0; i < idim; ++i) {
            if (!indicators.getValue(i)) {
                loc[nLoc] = i + offset;
                ++nLoc;
            }
        }

        if (nLoc > 0) {
            final int index = loc[Randomizer.nextInt(nLoc)];
            try {
                final double val = distribution.inverseCumulativeProbability(Randomizer.nextDouble());
                data.setValue(index, val);
            } catch (Exception e) {
                // some distributions fail on extreme values - currently gamma
                return Double.NEGATIVE_INFINITY;
                //throw new OperatorFailedException(e.getMessage());
            }
        } else {
            // no non-active indicators
            return Double.NEGATIVE_INFINITY;
        }
        return 0;
    }
}

@@ -881,32 +881,167 @@
 ate.REQUIRED);%0A%0A
+    public final Input%3CBoolean%3E scaleAll =%0A            new Input%3CBoolean%3E(%22all%22, %22if true, sample all off values in one go.%22, false);%0A%0A
     public void 
@@ -1535,32 +1535,736 @@
 etDimension();%0A%0A
+        double hr = Double.NEGATIVE_INFINITY;%0A%0A        if( scaleAll.get() ) %7B%0A            for (int i = offset; i %3C idim; ++i) %7B%0A                if( !indicators.getValue(i-offset) ) %7B%0A                    try %7B%0A                        final double val = distribution.inverseCumulativeProbability(Randomizer.nextDouble());%0A                        hr += distribution.logDensity(data.getValue(i));%0A                        data.setValue(i, val);%0A                    %7D catch (Exception e) %7B%0A                        // some distributions fail on extreme values - currently gamma%0A                        return Double.NEGATIVE_INFINITY;%0A                    %7D%0A                %7D%0A            %7D%0A        %7D else %7B%0A%0A    
         // avail
@@ -2306,16 +2306,20 @@
         
+  
+  
 int%5B%5D lo
@@ -2345,16 +2345,20 @@
         
+    
 int nLoc
@@ -2364,32 +2364,36 @@
 c = 0;%0A%0A        
+ 
+   
 for (int i = 0; 
@@ -2401,32 +2401,36 @@
  %3C idim; ++i) %7B%0A
+    
             if (
@@ -2427,18 +2427,18 @@
       if
- 
 (
+ 
 !indicat
@@ -2452,20 +2452,25 @@
 Value(i)
+ 
 ) %7B%0A
+    
         
@@ -2517,16 +2517,20 @@
         
+    
 ++nLoc;%0A
@@ -2533,34 +2533,42 @@
 oc;%0A            
+   
+ 
 %7D%0A
+    
         %7D%0A%0A     
@@ -2574,20 +2574,24 @@
     
+  
-if (
+  if( 
 nLoc %3E 0
 ) %7B%0A
@@ -2586,16 +2586,17 @@
 nLoc %3E 0
+ 
 ) %7B%0A    
@@ -2595,32 +2595,36 @@
 ) %7B%0A            
+  
+  
 final int index 
@@ -2660,38 +2660,46 @@
 )%5D;%0A            
+    
 try %7B%0A
+    
                 
@@ -2777,32 +2777,108 @@
 .nextDouble());%0A
+                    hr = distribution.logDensity(data.getValue(index));%0A    
                 
@@ -2896,32 +2896,36 @@
 ue(index, val);%0A
+    
             %7D ca
@@ -2936,32 +2936,36 @@
 (Exception e) %7B%0A
+    
                 
@@ -3035,32 +3035,36 @@
                 
+  
+  
 return Double.NE
@@ -3072,32 +3072,36 @@
 ATIVE_INFINITY;%0A
+    
                 
@@ -3157,34 +3157,42 @@
 ));%0A            
-%7D%0A
+    %7D%0A    
         %7D else %7B
@@ -3204,16 +3204,20 @@
         
+    
 // no no
@@ -3240,32 +3240,38 @@
 ors%0A            
+   
+ //
 return Double.NE
@@ -3279,32 +3279,36 @@
 ATIVE_INFINITY;%0A
+    
         %7D%0A      
@@ -3293,32 +3293,42 @@
 ;%0A            %7D%0A
+        %7D%0A
         return 0
@@ -3326,17 +3326,18 @@
  return 
-0
+hr
 ;%0A    %7D%0A

Add scale all flag. Fix incorrect hastings ratio