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/**
010 * A function that accepts a single {@code double} and returns a {@code double} result. This is used
011 * to represent arbitrary mapping functions for converting units to and from a base unit
012 * representation. Temperature units, in particular, typically have an offset from a value in Kelvin
013 * and may have a multiplication factor added in, which means that units cannot always be
014 * represented as simple ratios of their base units.
015 */
016@FunctionalInterface
017public interface UnaryFunction {
018  /** The identity function that simply returns the input value. */
019  UnaryFunction IDENTITY = x -> x;
020
021  /**
022   * Applies this function to the input value and returns the result.
023   *
024   * @param input the input value to the function
025   * @return the result
026   */
027  double apply(double input);
028
029  /**
030   * Constructs a new function that first calls this function, then passes the result to another as
031   * input.
032   *
033   * <pre>
034   * f = x -&gt; x + 1 // f(x) = x + 1
035   * g = x -&gt; 2 * x // g(x) = 2x
036   *
037   * h = f.pipeTo(g) // h(x) = g(f(x))
038   * </pre>
039   *
040   * @param next the next operation to pipe to
041   * @return the composite function g(f(x))
042   */
043  default UnaryFunction pipeTo(UnaryFunction next) {
044    Objects.requireNonNull(next, "The next operation in the chain must be provided");
045
046    return x -> next.apply(this.apply(x));
047  }
048
049  /**
050   * Creates a composite function h(x) such that h(x) = f(x) * g(x).
051   *
052   * @param multiplier the function to multiply this one by
053   * @return the composite function f(x) * g(x)
054   */
055  default UnaryFunction mult(UnaryFunction multiplier) {
056    Objects.requireNonNull(multiplier, "A multiplier function must be provided");
057
058    return x -> this.apply(x) * multiplier.apply(x);
059  }
060
061  /**
062   * Creates a composite function h(x) such that h(x) = k * f(x).
063   *
064   * @param multiplier the constant value to multiply this function's results by
065   * @return the composite function k * f(x)
066   */
067  default UnaryFunction mult(double multiplier) {
068    return x -> this.apply(x) * multiplier;
069  }
070
071  /**
072   * Creates a composite function h(x) such that h(x) = f(x) / g(x).
073   *
074   * @param divisor the function to divide this one by
075   * @return the composite function f(x) / g(x)
076   */
077  default UnaryFunction div(UnaryFunction divisor) {
078    Objects.requireNonNull(divisor, "A divisor function must be provided");
079
080    return x -> {
081      double numerator = this.apply(x);
082
083      // fast-track to avoid another function call
084      // avoids returning NaN if divisor is also zero
085      if (numerator == 0) {
086        return 0;
087      }
088
089      double div = divisor.apply(x);
090      return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero
091    };
092  }
093
094  /**
095   * Creates a composite function h(x) such that h(x) = 1/k * f(x).
096   *
097   * @param divisor the constant value to divide this function's results by
098   * @return the composite function 1/k * f(x)
099   */
100  default UnaryFunction div(double divisor) {
101    return x -> this.apply(x) / divisor;
102  }
103
104  /**
105   * Creates a composite function h(x) such that h(x) = f(x) ^ g(x).
106   *
107   * @param exponent the function to exponentiate this function's results by
108   * @return the composite function f(x) ^ g(x)
109   */
110  default UnaryFunction exp(UnaryFunction exponent) {
111    Objects.requireNonNull(exponent, "An exponent function must be provided");
112
113    return x -> Math.pow(this.apply(x), exponent.apply(x));
114  }
115
116  /**
117   * Creates a composite function h(x) such that h(x) = f(x) ^ k.
118   *
119   * @param exponent the constant value to exponentiate this function's results by
120   * @return the composite function f(x) ^ k
121   */
122  default UnaryFunction exp(double exponent) {
123    return x -> Math.pow(this.apply(x), exponent);
124  }
125}