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  /**
019   * Applies this function to the input value and returns the result.
020   *
021   * @param input the input value to the function
022   * @return the result
023   */
024  double apply(double input);
025
026  /**
027   * Constructs a new function that first calls this function, then passes the result to another as
028   * input.
029   *
030   * <pre>
031   * f = x -&gt; x + 1 // f(x) = x + 1
032   * g = x -&gt; 2 * x // g(x) = 2x
033   *
034   * h = f.pipeTo(g) // h(x) = g(f(x))
035   * </pre>
036   *
037   * @param next the next operation to pipe to
038   * @return the composite function g(f(x))
039   */
040  default UnaryFunction pipeTo(UnaryFunction next) {
041    Objects.requireNonNull(next, "The next operation in the chain must be provided");
042
043    return x -> next.apply(this.apply(x));
044  }
045
046  /**
047   * Creates a composite function h(x) such that h(x) = f(x) * g(x).
048   *
049   * @param multiplier the function to multiply this one by
050   * @return the composite function f(x) * g(x)
051   */
052  default UnaryFunction mult(UnaryFunction multiplier) {
053    Objects.requireNonNull(multiplier, "A multiplier function must be provided");
054
055    return x -> this.apply(x) * multiplier.apply(x);
056  }
057
058  /**
059   * Creates a composite function h(x) such that h(x) = k * f(x).
060   *
061   * @param multiplier the constant value to multiply this function's results by
062   * @return the composite function k * f(x)
063   */
064  default UnaryFunction mult(double multiplier) {
065    return x -> this.apply(x) * multiplier;
066  }
067
068  /**
069   * Creates a composite function h(x) such that h(x) = f(x) / g(x).
070   *
071   * @param divisor the function to divide this one by
072   * @return the composite function f(x) / g(x)
073   */
074  default UnaryFunction div(UnaryFunction divisor) {
075    Objects.requireNonNull(divisor, "A divisor function must be provided");
076
077    return x -> {
078      double numerator = this.apply(x);
079
080      // fast-track to avoid another function call
081      // avoids returning NaN if divisor is also zero
082      if (numerator == 0) {
083        return 0;
084      }
085
086      double div = divisor.apply(x);
087      return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero
088    };
089  }
090
091  /**
092   * Creates a composite function h(x) such that h(x) = 1/k * f(x).
093   *
094   * @param divisor the constant value to divide this function's results by
095   * @return the composite function 1/k * f(x)
096   */
097  default UnaryFunction div(double divisor) {
098    return x -> this.apply(x) / divisor;
099  }
100
101  /**
102   * Creates a composite function h(x) such that h(x) = f(x) ^ g(x).
103   *
104   * @param exponent the function to exponentiate this function's results by
105   * @return the composite function f(x) ^ g(x)
106   */
107  default UnaryFunction exp(UnaryFunction exponent) {
108    Objects.requireNonNull(exponent, "An exponent function must be provided");
109
110    return x -> Math.pow(this.apply(x), exponent.apply(x));
111  }
112
113  /**
114   * Creates a composite function h(x) such that h(x) = f(x) ^ k.
115   *
116   * @param exponent the constant value to exponentiate this function's results by
117   * @return the composite function f(x) ^ k
118   */
119  default UnaryFunction exp(double exponent) {
120    return x -> Math.pow(this.apply(x), exponent);
121  }
122}