PaddingStrategy.java

package com.morphiqlabs.wavelet.padding;

import com.morphiqlabs.wavelet.exception.InvalidArgumentException;

/**
 * Strategy for padding non-power-of-2 signals to the required length.
 *
 * <p>Each strategy defines how to extend a signal and optionally trim results.
 * This enables wavelet transforms on signals of arbitrary length by automatically
 * padding to the next power of 2.</p>
 *
 * <p>Common padding strategies:</p>
 * <ul>
 *   <li><b>Zero</b>: Extends with zeros (minimal spectral leakage)</li>
 *   <li><b>Symmetric</b>: Mirrors signal with boundary duplication (smooth extension)</li>
 *   <li><b>Reflect</b>: Mirrors signal without boundary duplication</li>
 *   <li><b>Periodic</b>: Wraps signal periodically (assumes cyclic data)</li>
 * </ul>
 */
public sealed interface PaddingStrategy
        permits ZeroPaddingStrategy, SymmetricPaddingStrategy,
        ReflectPaddingStrategy, PeriodicPaddingStrategy,
        ConstantPaddingStrategy, LinearExtrapolationStrategy, 
        AntisymmetricPaddingStrategy, PolynomialExtrapolationStrategy,
        StatisticalPaddingStrategy, AdaptivePaddingStrategy,
        CompositePaddingStrategy {

    /**
     * Pads the input signal to the target length.
     *
     * @param signal       the input signal (must not be null or empty)
     * @param targetLength the desired length (must be >= signal.length)
     * @return the padded signal of length targetLength
     * @throws IllegalArgumentException if targetLength {@literal <} signal.length
     */
    double[] pad(double[] signal, int targetLength);

    /**
     * Trims the result back to original length after inverse transform.
     *
     * <p>The default implementation simply truncates to the original length.
     * Strategies may override this to implement more sophisticated trimming.</p>
     *
     * @param result         the inverse transform result
     * @param originalLength the original signal length before padding
     * @return the trimmed result of length originalLength
     */
    default double[] trim(double[] result, int originalLength) {
        if (result.length == originalLength) {
            return result;
        }
        if (originalLength > result.length) {
            throw new InvalidArgumentException(
                    "Original length " + originalLength + " exceeds result length " + result.length);
        }
        double[] trimmed = new double[originalLength];
        System.arraycopy(result, 0, trimmed, 0, originalLength);
        return trimmed;
    }

    /**
     * Returns the name of this padding strategy.
     *
     * @return strategy name for display/configuration
     */
    String name();

    /**
     * Returns a human-readable description of this padding strategy.
     *
     * @return strategy description
     */
    default String description() {
        return name() + " padding";
    }
}