content: /**
   * 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 org.apache.aurora.common.stats;
  
  import com.google.common.base.Preconditions;
  import com.google.common.base.Supplier;
  
  /**
   * Function to compute the ratio of two time series.
   * The first argument is the numerator, and the second is the denominator.  Assumes that the
   * timestamps of the two arguments are suitably synchronized (i.e. the ith point in the numerator
   * time series corresponds with the ith point of the denominator time series).
   *
   * @author William Farner
   */
  public class Ratio extends SampledStat<Double> {
  
    private final Supplier<Number> numeratorAccessor;
    private final Supplier<Number> denominatorAccessor;
  
    private Ratio(String name, Supplier<Number> numeratorAccessor,
        Supplier<Number> denominatorAccessor) {
      super(name, 0d);
      this.numeratorAccessor = Preconditions.checkNotNull(numeratorAccessor);
      this.denominatorAccessor = Preconditions.checkNotNull(denominatorAccessor);
    }
  
    public static <T extends Number> Ratio of(Stat<T> numerator, Stat<T> denominator) {
      Preconditions.checkNotNull(numerator);
      Preconditions.checkNotNull(denominator);
  
      String name = String.format("%s_per_%s", numerator.getName(), denominator.getName());
      return Ratio.of(name, numerator, denominator);
    }
  
    public static <T extends Number> Ratio of(String name, final Stat<T> numerator,
        final Stat<T> denominator) {
      Preconditions.checkNotNull(numerator);
      Preconditions.checkNotNull(denominator);
  
      Stats.export(numerator);
      Stats.export(denominator);
  
      return new Ratio(name,
          numerator::read,
          denominator::read);
    }
  
    public static Ratio of(String name, final Number numerator, final Number denominator) {
      Preconditions.checkNotNull(numerator);
      Preconditions.checkNotNull(denominator);
  
      return new Ratio(name,
          () -> numerator,
          () -> denominator);
    }
  
    @Override
    public Double doSample() {
      double numeratorValue = numeratorAccessor.get().doubleValue();
      double denominatorValue = denominatorAccessor.get().doubleValue();
  
      if ((denominatorValue == 0)
          || (denominatorValue == Double.NaN)
          || (numeratorValue == Double.NaN)) {
        return 0d;
      }
  
      return numeratorValue / denominatorValue;
    }
  }
  