SmoothStepFactory.java

  1. /*
  2.  * Licensed to the Hipparchus project under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.hipparchus.analysis.polynomials;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.exception.MathIllegalArgumentException;
  22. import org.hipparchus.exception.NullArgumentException;
  23. import org.hipparchus.util.MathArrays;

  24. /**
  25.  * Smoothstep function factory.
  26.  * <p>
  27.  * It allows for quick creation of common and generic smoothstep functions as defined
  28.  * <a href="https://en.wikipedia.org/wiki/Smoothstep">here</a>.
  29.  */
  30. public class SmoothStepFactory {

  31.     /**
  32.      * Private constructor.
  33.      * <p>
  34.      * This class is a utility class, it should neither have a public nor a default constructor. This private constructor
  35.      * prevents the compiler from generating one automatically.
  36.      */
  37.     private SmoothStepFactory() {
  38.         // Empty constructor
  39.     }

  40.     /**
  41.      * Get the {@link SmoothStepFunction clamping smoothstep function}.
  42.      *
  43.      * @return clamping smoothstep function
  44.      */
  45.     public static SmoothStepFunction getClamp() {
  46.         return getGeneralOrder(0);
  47.     }

  48.     /**
  49.      * Get the {@link SmoothStepFunction quadratic smoothstep function}.
  50.      *
  51.      * @return clamping smoothstep function
  52.      */
  53.     public static SmoothStepFunction getQuadratic() {
  54.         // Use a default double array as it will not matter anyway
  55.         return new QuadraticSmoothStepFunction(new double[] { 0 });
  56.     }

  57.     /**
  58.      * Get the {@link SmoothStepFunction cubic smoothstep function}.
  59.      *
  60.      * @return cubic smoothstep function
  61.      */
  62.     public static SmoothStepFunction getCubic() {
  63.         return getGeneralOrder(1);
  64.     }

  65.     /**
  66.      * Get the {@link SmoothStepFunction quintic smoothstep function}.
  67.      *
  68.      * @return quintic smoothstep function
  69.      */
  70.     public static SmoothStepFunction getQuintic() {
  71.         return getGeneralOrder(2);
  72.     }

  73.     /**
  74.      * Get the {@link SmoothStepFunction clamping smoothstep function}.
  75.      *
  76.      * @param <T> type of the field element
  77.      * @param field field of the element
  78.      *
  79.      * @return clamping smoothstep function
  80.      */
  81.     public static <T extends CalculusFieldElement<T>> FieldSmoothStepFunction<T> getClamp(final Field<T> field) {
  82.         return getFieldGeneralOrder(field, 0);
  83.     }

  84.     /**
  85.      * Get the {@link SmoothStepFunction quadratic smoothstep function}.
  86.      *
  87.      * @param <T> type of the field element
  88.      * @param field field of the element
  89.      *
  90.      * @return clamping smoothstep function
  91.      */
  92.     public static <T extends CalculusFieldElement<T>> FieldSmoothStepFunction<T> getQuadratic(final Field<T> field) {
  93.         final T[] tempArray = MathArrays.buildArray(field, 1);
  94.         return new FieldQuadraticSmoothStepFunction<>(tempArray);
  95.     }

  96.     /**
  97.      * Get the {@link SmoothStepFunction cubic smoothstep function}.
  98.      *
  99.      * @param <T> type of the field element
  100.      * @param field field of the element
  101.      *
  102.      * @return cubic smoothstep function
  103.      */
  104.     public static <T extends CalculusFieldElement<T>> FieldSmoothStepFunction<T> getCubic(final Field<T> field) {
  105.         return getFieldGeneralOrder(field, 1);
  106.     }

  107.     /**
  108.      * Get the {@link SmoothStepFunction quintic smoothstep function}.
  109.      *
  110.      * @param <T> type of the field element
  111.      * @param field field of the element
  112.      *
  113.      * @return quintic smoothstep function
  114.      */
  115.     public static <T extends CalculusFieldElement<T>> FieldSmoothStepFunction<T> getQuintic(final Field<T> field) {
  116.         return getFieldGeneralOrder(field, 2);
  117.     }

  118.     /**
  119.      * Create a {@link SmoothStepFunction smoothstep function} of order <b>2N + 1</b>.
  120.      * <p>
  121.      * It uses the general smoothstep equation presented <a href="https://en.wikipedia.org/wiki/Smoothstep">here</a> :
  122.      * $S_{N}(x) = \sum_{n=0}^{N} \begin{pmatrix} -N-1 \\ n \end{pmatrix} \begin{pmatrix} 2N+1 \\ N-n \end{pmatrix}
  123.      * x^{N+n+1}$
  124.      *
  125.      * @param N determines the order of the output smoothstep function (=2N + 1)
  126.      *
  127.      * @return smoothstep function of order <b>2N + 1</b>
  128.      */
  129.     public static SmoothStepFunction getGeneralOrder(final int N) {

  130.         final int twoNPlusOne = 2 * N + 1;

  131.         final double[] coefficients = new double[twoNPlusOne + 1];

  132.         int n = N;
  133.         for (int i = twoNPlusOne; i > N; i--) {
  134.             coefficients[i] = pascalTriangle(-N - 1, n) * pascalTriangle(2 * N + 1, N - n);
  135.             n--;
  136.         }

  137.         return new SmoothStepFunction(coefficients);
  138.     }

  139.     /**
  140.      * Create a {@link SmoothStepFunction smoothstep function} of order <b>2N + 1</b>.
  141.      * <p>
  142.      * It uses the general smoothstep equation presented <a href="https://en.wikipedia.org/wiki/Smoothstep">here</a> :
  143.      * $S_{N}(x) = \sum_{n=0}^{N} \begin{pmatrix} -N-1 \\ n \end{pmatrix} \begin{pmatrix} 2N+1 \\ N-n \end{pmatrix}
  144.      * x^{N+n+1}$
  145.      *
  146.      * @param <T> type of the field element
  147.      * @param field field of the element
  148.      * @param N determines the order of the output smoothstep function (=2N + 1)
  149.      *
  150.      * @return smoothstep function of order <b>2N + 1</b>
  151.      */
  152.     public static <T extends CalculusFieldElement<T>> FieldSmoothStepFunction<T> getFieldGeneralOrder(final Field<T> field,
  153.                                                                                                       final int N) {

  154.         final int twoNPlusOne = 2 * N + 1;

  155.         final T[] coefficients = MathArrays.buildArray(field, twoNPlusOne + 1);

  156.         final T one = field.getOne();
  157.         int     n   = N;
  158.         for (int i = twoNPlusOne; i > N; i--) {
  159.             coefficients[i] = one.newInstance(pascalTriangle(-N - 1, n) * pascalTriangle(2 * N + 1, N - n));
  160.             n--;
  161.         }

  162.         return new FieldSmoothStepFunction<>(coefficients);
  163.     }

  164.     /**
  165.      * Returns binomial coefficient without explicit use of factorials, which can't be used with negative integers
  166.      *
  167.      * @param k subset in set
  168.      * @param n set
  169.      *
  170.      * @return number of subset {@code k} in global set {@code n}
  171.      */
  172.     private static int pascalTriangle(final int k, final int n) {

  173.         int result = 1;
  174.         for (int i = 0; i < n; i++) {
  175.             result *= (k - i) / (i + 1);
  176.         }

  177.         return result;
  178.     }

  179.     /**
  180.      * Check that input is between [0:1].
  181.      *
  182.      * @param input input to be checked
  183.      *
  184.      * @throws MathIllegalArgumentException if input is not between [0:1]
  185.      */
  186.     public static void checkBetweenZeroAndOneIncluded(final double input) throws MathIllegalArgumentException {
  187.         if (input < 0 || input > 1) {
  188.             throw new MathIllegalArgumentException(
  189.                     LocalizedCoreFormats.INPUT_EXPECTED_BETWEEN_ZERO_AND_ONE_INCLUDED);
  190.         }
  191.     }

  192.     /**
  193.      * Smoothstep function as defined <a href="https://en.wikipedia.org/wiki/Smoothstep">here</a>.
  194.      * <p>
  195.      * It is used to do a smooth transition between the "left edge" and the "right edge" with left edge assumed to be smaller
  196.      * than right edge.
  197.      * <p>
  198.      * By definition, for order n greater than 1 and input x, a smoothstep function respects at least the following properties :
  199.      * <ul>
  200.      *     <li>f(x &lt;= leftEdge) = 0 and f(x &gt;= rightEdge) = 1</li>
  201.      *     <li>f'(leftEdge) = f'(rightEdge) = 0</li>
  202.      * </ul>
  203.      * If x is normalized between edges, we have at least :
  204.      * <ul>
  205.      *     <li>f(x &lt;= 0) = 0 and f(x &gt;= 1) = 1</li>
  206.      *     <li>f'(0) = f'(1) = 0</li>
  207.      * </ul>
  208.      * Smoothstep functions of higher order n will have their higher time derivatives also equal to zero at edges...
  209.      */
  210.     public static class SmoothStepFunction extends PolynomialFunction {

  211.         /** Serializable UID. */
  212.         private static final long serialVersionUID = 20230113L;

  213.         /**
  214.          * Construct a smoothstep with the given coefficients. The first element of the coefficients array is the constant
  215.          * term.  Higher degree coefficients follow in sequence.  The degree of the resulting polynomial is the index of the
  216.          * last non-null element of the array, or 0 if all elements are null.
  217.          * <p>
  218.          * The constructor makes a copy of the input array and assigns the copy to the coefficients property.</p>
  219.          *
  220.          * @param c Smoothstep polynomial coefficients.
  221.          *
  222.          * @throws NullArgumentException        if {@code c} is {@code null}.
  223.          * @throws MathIllegalArgumentException if {@code c} is empty.
  224.          */
  225.         private SmoothStepFunction(final double[] c) throws MathIllegalArgumentException, NullArgumentException {
  226.             super(c);
  227.         }

  228.         /**
  229.          * Compute the value of the smoothstep for the given argument normalized between edges.
  230.          *
  231.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  232.          * between [0:1] and will throw an exception otherwise.
  233.          *
  234.          * @return the value of the polynomial at the given point.
  235.          *
  236.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  237.          */
  238.         @Override
  239.         public double value(final double xNormalized) {
  240.             checkBetweenZeroAndOneIncluded(xNormalized);
  241.             return super.value(xNormalized);
  242.         }

  243.         /**
  244.          * Compute the value of the smoothstep function for the given edges and argument.
  245.          * <p>
  246.          * Note that right edge is expected to be greater than left edge. It will throw an exception otherwise.
  247.          *
  248.          * @param leftEdge left edge
  249.          * @param rightEdge right edge
  250.          * @param x Argument for which the function value should be computed
  251.          *
  252.          * @return the value of the polynomial at the given point
  253.          *
  254.          * @throws MathIllegalArgumentException if right edge is greater than left edge
  255.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  256.          */
  257.         public double value(final double leftEdge, final double rightEdge, final double x)
  258.                 throws MathIllegalArgumentException {

  259.             checkInputEdges(leftEdge, rightEdge);

  260.             final double xClamped = clampInput(leftEdge, rightEdge, x);

  261.             final double xNormalized = normalizeInput(leftEdge, rightEdge, xClamped);

  262.             return super.value(xNormalized);
  263.         }

  264.         /**
  265.          * Check that left edge is lower than right edge. Otherwise, throw an exception.
  266.          *
  267.          * @param leftEdge left edge
  268.          * @param rightEdge right edge
  269.          */
  270.         protected void checkInputEdges(final double leftEdge, final double rightEdge) {
  271.             if (leftEdge > rightEdge) {
  272.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.RIGHT_EDGE_GREATER_THAN_LEFT_EDGE,
  273.                                                        leftEdge, rightEdge);
  274.             }
  275.         }

  276.         /**
  277.          * Clamp input between edges.
  278.          *
  279.          * @param leftEdge left edge
  280.          * @param rightEdge right edge
  281.          * @param x input to clamp
  282.          *
  283.          * @return clamped input
  284.          */
  285.         protected double clampInput(final double leftEdge, final double rightEdge, final double x) {
  286.             if (x <= leftEdge) {
  287.                 return leftEdge;
  288.             }
  289.             if (x >= rightEdge) {
  290.                 return rightEdge;
  291.             }
  292.             return x;
  293.         }

  294.         /**
  295.          * Normalize input between left and right edges.
  296.          *
  297.          * @param leftEdge left edge
  298.          * @param rightEdge right edge
  299.          * @param x input to normalize
  300.          *
  301.          * @return normalized input
  302.          */
  303.         protected double normalizeInput(final double leftEdge, final double rightEdge, final double x) {
  304.             return (x - leftEdge) / (rightEdge - leftEdge);
  305.         }
  306.     }

  307.     /**
  308.      * Specific smoothstep function that cannot be built using the {@link #getGeneralOrder(int)}.
  309.      * <p>
  310.      * Methods inherited from {@link PolynomialFunction} <em>should not be used</em> as they will not be true to the actual
  311.      * function.
  312.      *
  313.      * @see PolynomialFunction
  314.      */
  315.     public static class QuadraticSmoothStepFunction extends SmoothStepFunction {

  316.         /** Serializable UID. */
  317.         private static final long serialVersionUID = 20230422L;

  318.         /**
  319.          * Construct a smoothstep with the given coefficients. The first element of the coefficients array is the constant
  320.          * term. Higher degree coefficients follow in sequence.  The degree of the resulting polynomial is the index of the
  321.          * last non-null element of the array, or 0 if all elements are null.
  322.          * <p>
  323.          * The constructor makes a copy of the input array and assigns the copy to the coefficients property.</p>
  324.          *
  325.          * @param c Smoothstep polynomial coefficients.
  326.          *
  327.          * @throws NullArgumentException        if {@code c} is {@code null}.
  328.          * @throws MathIllegalArgumentException if {@code c} is empty.
  329.          */
  330.         private QuadraticSmoothStepFunction(final double[] c) throws MathIllegalArgumentException, NullArgumentException {
  331.             super(c);
  332.         }

  333.         /**
  334.          * Compute the value of the smoothstep function for the given edges and argument.
  335.          * <p>
  336.          * Note that right edge is expected to be greater than left edge. It will throw an exception otherwise.
  337.          *
  338.          * @param leftEdge left edge
  339.          * @param rightEdge right edge
  340.          * @param x Argument for which the function value should be computed
  341.          *
  342.          * @return the value of the polynomial at the given point
  343.          *
  344.          * @throws MathIllegalArgumentException if right edge is greater than left edge
  345.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  346.          */
  347.         @Override
  348.         public double value(final double leftEdge, final double rightEdge, final double x)
  349.                 throws MathIllegalArgumentException {

  350.             checkInputEdges(leftEdge, rightEdge);

  351.             final double xClamped = clampInput(leftEdge, rightEdge, x);

  352.             final double xNormalized = normalizeInput(leftEdge, rightEdge, xClamped);

  353.             return value(xNormalized);
  354.         }

  355.         /**
  356.          * Compute the value of the quadratic smoothstep for the given argument normalized between edges.
  357.          *
  358.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  359.          * between [0:1] and will throw an exception otherwise.
  360.          *
  361.          * @return the value of the polynomial at the given point.
  362.          *
  363.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  364.          */
  365.         @Override
  366.         public double value(final double xNormalized) {
  367.             checkBetweenZeroAndOneIncluded(xNormalized);

  368.             if (xNormalized >= 0 && xNormalized <= 0.5) {
  369.                 return 2 * xNormalized * xNormalized;
  370.             }
  371.             else {
  372.                 return 4 * xNormalized - 2 * xNormalized * xNormalized - 1;
  373.             }
  374.         }
  375.     }

  376.     /**
  377.      * Smoothstep function as defined <a href="https://en.wikipedia.org/wiki/Smoothstep">here</a>.
  378.      * <p>
  379.      * It is used to do a smooth transition between the "left edge" and the "right edge" with left edge assumed to be smaller
  380.      * than right edge.
  381.      * <p>
  382.      * By definition, for order n greater than 1 and input x, a smoothstep function respects at least the following properties :
  383.      * <ul>
  384.      *     <li>f(x &lt;= leftEdge) = 0 and f(x &gt;= rightEdge) = 1</li>
  385.      *     <li>f'(leftEdge) = f'(rightEdge) = 0</li>
  386.      * </ul>
  387.      * If x is normalized between edges, we have at least :
  388.      * <ul>
  389.      *     <li>f(x &lt;= 0) = 0 and f(x &gt;= 1) = 1</li>
  390.      *     <li>f'(0) = f'(1) = 0</li>
  391.      * </ul>
  392.      * Smoothstep functions of higher order n will have their higher time derivatives also equal to zero at edges...
  393.      *
  394.      * @param <T> type of the field element
  395.      */
  396.     public static class FieldSmoothStepFunction<T extends CalculusFieldElement<T>> extends FieldPolynomialFunction<T> {

  397.         /**
  398.          * Construct a smoothstep with the given coefficients. The first element of the coefficients array is the constant
  399.          * term.  Higher degree coefficients follow in sequence.  The degree of the resulting polynomial is the index of the
  400.          * last non-null element of the array, or 0 if all elements are null.
  401.          * <p>
  402.          * The constructor makes a copy of the input array and assigns the copy to the coefficients property.</p>
  403.          *
  404.          * @param c Smoothstep polynomial coefficients.
  405.          *
  406.          * @throws NullArgumentException        if {@code c} is {@code null}.
  407.          * @throws MathIllegalArgumentException if {@code c} is empty.
  408.          */
  409.         private FieldSmoothStepFunction(final T[] c) throws MathIllegalArgumentException, NullArgumentException {
  410.             super(c);
  411.         }

  412.         /**
  413.          * Compute the value of the smoothstep for the given argument normalized between edges.
  414.          *
  415.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  416.          * between [0:1] and will throw an exception otherwise.
  417.          *
  418.          * @return the value of the polynomial at the given point.
  419.          *
  420.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  421.          */
  422.         @Override
  423.         public T value(final double xNormalized) {
  424.             checkBetweenZeroAndOneIncluded(xNormalized);
  425.             return super.value(xNormalized);
  426.         }

  427.         /**
  428.          * Compute the value of the smoothstep for the given argument normalized between edges.
  429.          *
  430.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  431.          * between [0:1] and will throw an exception otherwise.
  432.          *
  433.          * @return the value of the polynomial at the given point.
  434.          *
  435.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  436.          */
  437.         @Override
  438.         public T value(final T xNormalized) {
  439.             checkBetweenZeroAndOneIncluded(xNormalized.getReal());
  440.             return super.value(xNormalized);
  441.         }

  442.         /**
  443.          * Compute the value of the smoothstep function for the given edges and argument.
  444.          * <p>
  445.          * Note that right edge is expected to be greater than left edge. It will throw an exception otherwise.
  446.          *
  447.          * @param leftEdge left edge
  448.          * @param rightEdge right edge
  449.          * @param x Argument for which the function value should be computed
  450.          *
  451.          * @return the value of the polynomial at the given point
  452.          *
  453.          * @throws MathIllegalArgumentException if right edge is greater than left edge
  454.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  455.          */
  456.         public T value(final double leftEdge, final double rightEdge, final T x)
  457.                 throws MathIllegalArgumentException {

  458.             checkInputEdges(leftEdge, rightEdge);

  459.             final T xClamped = clampInput(leftEdge, rightEdge, x);

  460.             final T xNormalized = normalizeInput(leftEdge, rightEdge, xClamped);

  461.             return super.value(xNormalized);
  462.         }

  463.         /**
  464.          * Check that left edge is lower than right edge. Otherwise, throw an exception.
  465.          *
  466.          * @param leftEdge left edge
  467.          * @param rightEdge right edge
  468.          */
  469.         protected void checkInputEdges(final double leftEdge, final double rightEdge) {
  470.             if (leftEdge > rightEdge) {
  471.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.RIGHT_EDGE_GREATER_THAN_LEFT_EDGE,
  472.                                                        leftEdge, rightEdge);
  473.             }
  474.         }

  475.         /**
  476.          * Clamp input between edges.
  477.          *
  478.          * @param leftEdge left edge
  479.          * @param rightEdge right edge
  480.          * @param x input to clamp
  481.          *
  482.          * @return clamped input
  483.          */
  484.         protected T clampInput(final double leftEdge, final double rightEdge, final T x) {
  485.             if (x.getReal() <= leftEdge) {
  486.                 return x.getField().getOne().newInstance(leftEdge);
  487.             }
  488.             if (x.getReal() >= rightEdge) {
  489.                 return x.getField().getOne().newInstance(rightEdge);
  490.             }
  491.             return x;
  492.         }

  493.         /**
  494.          * Normalize input between left and right edges.
  495.          *
  496.          * @param leftEdge left edge
  497.          * @param rightEdge right edge
  498.          * @param x input to normalize
  499.          *
  500.          * @return normalized input
  501.          */
  502.         protected T normalizeInput(final double leftEdge, final double rightEdge, final T x) {
  503.             return x.subtract(leftEdge).divide(rightEdge - leftEdge);
  504.         }
  505.     }

  506.     /**
  507.      * Specific smoothstep function that cannot be built using the {@link #getGeneralOrder(int)}.
  508.      * <p>
  509.      * Methods inherited from {@link PolynomialFunction} <em>should not be used</em> as they will not be true to the actual
  510.      * function.
  511.      *
  512.      * @param <T> type of the field element
  513.      *
  514.      * @see PolynomialFunction
  515.      */
  516.     private static class FieldQuadraticSmoothStepFunction<T extends CalculusFieldElement<T>>
  517.             extends FieldSmoothStepFunction<T> {

  518.         /**
  519.          * Construct a smoothstep with the given coefficients. The first element of the coefficients array is the constant
  520.          * term. Higher degree coefficients follow in sequence.  The degree of the resulting polynomial is the index of the
  521.          * last non-null element of the array, or 0 if all elements are null.
  522.          * <p>
  523.          * The constructor makes a copy of the input array and assigns the copy to the coefficients property.</p>
  524.          *
  525.          * @param c Smoothstep polynomial coefficients.
  526.          *
  527.          * @throws NullArgumentException        if {@code c} is {@code null}.
  528.          * @throws MathIllegalArgumentException if {@code c} is empty.
  529.          */
  530.         private FieldQuadraticSmoothStepFunction(final T[] c) throws MathIllegalArgumentException, NullArgumentException {
  531.             super(c);
  532.         }

  533.         /**
  534.          * Compute the value of the smoothstep function for the given edges and argument.
  535.          * <p>
  536.          * Note that right edge is expected to be greater than left edge. It will throw an exception otherwise.
  537.          *
  538.          * @param leftEdge left edge
  539.          * @param rightEdge right edge
  540.          * @param x Argument for which the function value should be computed
  541.          *
  542.          * @return the value of the polynomial at the given point
  543.          *
  544.          * @throws MathIllegalArgumentException if right edge is greater than left edge
  545.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  546.          */
  547.         @Override
  548.         public T value(final double leftEdge, final double rightEdge, final T x)
  549.                 throws MathIllegalArgumentException {

  550.             checkInputEdges(leftEdge, rightEdge);

  551.             final T xClamped = clampInput(leftEdge, rightEdge, x);

  552.             final T xNormalized = normalizeInput(leftEdge, rightEdge, xClamped);

  553.             return value(xNormalized);
  554.         }

  555.         /**
  556.          * Compute the value of the quadratic smoothstep for the given argument normalized between edges.
  557.          * <p>
  558.          *
  559.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  560.          * between [0:1] and will throw an exception otherwise.
  561.          *
  562.          * @return the value of the polynomial at the given point.
  563.          *
  564.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  565.          */
  566.         @Override
  567.         public T value(final double xNormalized) {
  568.             checkBetweenZeroAndOneIncluded(xNormalized);

  569.             final Field<T> field = getField();
  570.             final T        one   = field.getOne();

  571.             if (xNormalized >= 0 && xNormalized <= 0.5) {
  572.                 return one.newInstance(2. * xNormalized * xNormalized);
  573.             }
  574.             else {
  575.                 return one.newInstance(4. * xNormalized - 2. * xNormalized * xNormalized - 1.);
  576.             }
  577.         }

  578.         /**
  579.          * Compute the value of the quadratic smoothstep for the given argument normalized between edges.
  580.          * <p>
  581.          *
  582.          * @param xNormalized Normalized argument for which the function value should be computed. It is expected to be
  583.          * between [0:1] and will throw an exception otherwise.
  584.          *
  585.          * @return the value of the polynomial at the given point.
  586.          *
  587.          * @see org.hipparchus.analysis.UnivariateFunction#value(double)
  588.          */
  589.         @Override
  590.         public T value(final T xNormalized) {
  591.             checkBetweenZeroAndOneIncluded(xNormalized.getReal());

  592.             if (xNormalized.getReal() >= 0 && xNormalized.getReal() <= 0.5) {
  593.                 return xNormalized.multiply(xNormalized).multiply(2.);
  594.             }
  595.             else {
  596.                 final T one = getField().getOne();
  597.                 return one.linearCombination(4., xNormalized, -2., xNormalized.multiply(xNormalized)).subtract(1.);
  598.             }
  599.         }
  600.     }

  601. }