001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.units;
006
007import java.util.Objects;
008
009@FunctionalInterface
010public interface UnaryFunction {
011  /**
012   * Applies this function to the input value and returns the result.
013   *
014   * @param input the input value to the function
015   * @return the result
016   */
017  double apply(double input);
018
019  /**
020   * Constructs a new function that first calls this function, then passes the result to another as
021   * input.
022   *
023   * <pre>
024   * f = x -&gt; x + 1 // f(x) = x + 1
025   * g = x -&gt; 2 * x // g(x) = 2x
026   *
027   * h = f.pipeTo(g) // h(x) = g(f(x))
028   * </pre>
029   *
030   * @param next the next operation to pipe to
031   * @return the composite function g(f(x))
032   */
033  default UnaryFunction pipeTo(UnaryFunction next) {
034    Objects.requireNonNull(next, "The next operation in the chain must be provided");
035
036    return x -> next.apply(this.apply(x));
037  }
038
039  /**
040   * Creates a composite function h(x) such that h(x) = f(x) * g(x).
041   *
042   * @param multiplier the function to multiply this one by
043   * @return the composite function f(x) * g(x)
044   */
045  default UnaryFunction mult(UnaryFunction multiplier) {
046    Objects.requireNonNull(multiplier, "A multiplier function must be provided");
047
048    return x -> this.apply(x) * multiplier.apply(x);
049  }
050
051  /**
052   * Creates a composite function h(x) such that h(x) = k * f(x).
053   *
054   * @param multiplier the constant value to multiply this function's results by
055   * @return the composite function k * f(x)
056   */
057  default UnaryFunction mult(double multiplier) {
058    return x -> this.apply(x) * multiplier;
059  }
060
061  /**
062   * Creates a composite function h(x) such that h(x) = f(x) / g(x).
063   *
064   * @param divisor the function to divide this one by
065   * @return the composite function f(x) / g(x)
066   */
067  default UnaryFunction div(UnaryFunction divisor) {
068    Objects.requireNonNull(divisor, "A divisor function must be provided");
069
070    return x -> {
071      double numerator = this.apply(x);
072
073      // fast-track to avoid another function call
074      // avoids returning NaN if divisor is also zero
075      if (numerator == 0) {
076        return 0;
077      }
078
079      double div = divisor.apply(x);
080      return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero
081    };
082  }
083
084  /**
085   * Creates a composite function h(x) such that h(x) = 1/k * f(x).
086   *
087   * @param divisor the constant value to divide this function's results by
088   * @return the composite function 1/k * f(x)
089   */
090  default UnaryFunction div(double divisor) {
091    return x -> this.apply(x) / divisor;
092  }
093
094  /**
095   * Creates a composite function h(x) such that h(x) = f(x) ^ g(x).
096   *
097   * @param exponent the function to exponentiate this function's results by
098   * @return the composite function f(x) ^ g(x)
099   */
100  default UnaryFunction exp(UnaryFunction exponent) {
101    Objects.requireNonNull(exponent, "An exponent function must be provided");
102
103    return x -> Math.pow(this.apply(x), exponent.apply(x));
104  }
105
106  /**
107   * Creates a composite function h(x) such that h(x) = f(x) ^ k.
108   *
109   * @param exponent the constant value to exponentiate this function's results by
110   * @return the composite function f(x) ^ k
111   */
112  default UnaryFunction exp(double exponent) {
113    return x -> Math.pow(this.apply(x), exponent);
114  }
115}