All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.redberry.rings.poly.univar.UnivariatePolynomialArithmetic Maven / Gradle / Ivy

There is a newer version: 2.5.8
Show newest version
package cc.redberry.rings.poly.univar;


import cc.redberry.rings.bigint.BigInteger;
import cc.redberry.rings.poly.MachineArithmetic;

/**
 * Helper methods for univariate polynomial arithmetic.
 *
 * @since 1.0
 */
public final class UnivariatePolynomialArithmetic {
    private UnivariatePolynomialArithmetic() {}

    /**
     * Returns the remainder of {@code dividend} and {@code polyModulus}.
     *
     * @param dividend    the polynomial
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code dividend}; if not, the result will be placed directly to {@code
     *                    dividend} and the original {@code dividend} data will be lost
     * @return {@code dividend % polyModulus}
     */
    public static > T polyMod(T dividend, T polyModulus, boolean copy) {
        return UnivariateDivision.remainder(dividend, polyModulus, copy);
    }

    /**
     * Returns the remainder of {@code dividend} and {@code polyModulus} using fast algorithm for pre-conditioned
     * modulus.
     *
     * @param dividend    the polynomial
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code dividend}; if not, the result will be placed directly to {@code
     *                    dividend} and the original {@code dividend} data will be lost
     * @return {@code dividend % polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyMod(T dividend, T polyModulus,
                                                                 UnivariateDivision.InverseModMonomial invMod, boolean copy) {
        return UnivariateDivision.remainderFast(dividend, polyModulus, invMod, copy);
    }

    /**
     * Returns the remainder of the product {@code (m1 * m2)} and {@code polyModulus}.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 * m2) % polyModulus}
     */
    public static > T polyMultiplyMod(T m1, T m2, T polyModulus, boolean copy) {
        return polyMod((copy ? m1.clone() : m1).multiply(m2), polyModulus, false);
    }

    /**
     * Returns the remainder of the product {@code (m1 * m2)} and {@code polyModulus} using fast algorithm for
     * pre-conditioned modulus.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 * m2) % polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyMultiplyMod(T m1, T m2,
                                                                         T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                         boolean copy) {
        return polyMod((copy ? m1.clone() : m1).multiply(m2), polyModulus, invMod, false);
    }

    /**
     * Returns the remainder of the sum {@code (m1 + m2)} and {@code polyModulus} using fast algorithm for
     * pre-conditioned modulus.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 + m2) % polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyAddMod(T m1, T m2,
                                                                    T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                    boolean copy) {
        return polyMod((copy ? m1.clone() : m1).add(m2), polyModulus, invMod, false);
    }

    /**
     * Returns the remainder of the sum {@code (m1 + m2)} and {@code polyModulus}.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 + m2) % polyModulus}
     */
    public static > T polyAddMod(T m1, T m2, T polyModulus, boolean copy) {
        return polyMod((copy ? m1.clone() : m1).add(m2), polyModulus, false);
    }

    /**
     * Returns the remainder of the difference {@code (m1 - m2)} and {@code polyModulus} using fast algorithm for
     * pre-conditioned modulus.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 - m2) % polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polySubtractMod(T m1, T m2,
                                                                         T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                         boolean copy) {
        return polyMod((copy ? m1.clone() : m1).subtract(m2), polyModulus, invMod, false);
    }

    /**
     * Returns the remainder of the difference {@code (m1 - m2)} and {@code polyModulus}.
     *
     * @param m1          the first multiplier
     * @param m2          the second multiplier
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of the first multiplier {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (m1 - m2) % polyModulus}
     */
    public static > T polySubtractMod(T m1, T m2, T polyModulus, boolean copy) {
        return polyMod((copy ? m1.clone() : m1).subtract(m2), polyModulus, false);
    }

    /**
     * Returns the remainder of the negated poly {@code -m1} and {@code polyModulus} using fast algorithm for
     * pre-conditioned modulus.
     *
     * @param m1          the polynomial
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (-m1) % polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyNegateMod(T m1,
                                                                       T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                       boolean copy) {
        // fixme: better implementation possible ?
        return polyMod((copy ? m1.clone() : m1).negate(), polyModulus, invMod, false);
    }

    /**
     * Returns the remainder of the negated poly {@code -m1} and {@code polyModulus}.
     *
     * @param m1          the polynomial
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code m1}; if not, the result will be placed directly to the data structure
     *                    of {@code m1} and the original data of {@code m1} will be lost
     * @return {@code (-m1) % polyModulus}
     */
    public static > T polyNegateMod(T m1, T polyModulus, boolean copy) {
        return polyMod((copy ? m1.clone() : m1).negate(), polyModulus, false);
    }

    /**
     * Returns {@code base} in a power of non-negative {@code exponent}
     *
     * @param base     the base
     * @param exponent the non-negative exponent
     * @param copy     whether to clone {@code base}; if not the data of {@code base} will be lost
     * @return {@code base} in a power of {@code e}
     */
    public static > T polyPow(final T base, long exponent, boolean copy) {
        if (exponent < 0)
            throw new IllegalArgumentException();

        T result = base.createOne();
        T k2p = copy ? base.clone() : base;
        for (; ; ) {
            if ((exponent & 1) != 0)
                result = result.multiply(k2p);
            exponent = exponent >> 1;
            if (exponent == 0)
                return result;
            k2p = k2p.multiply(k2p);
        }
    }

    /**
     * Returns {@code base} in a power of non-negative {@code exponent} modulo {@code polyModulus}
     *
     * @param base        the base
     * @param exponent    the non-negative exponent
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code base}; if not the data of {@code base} will be lost
     * @return {@code base} in a power of {@code e} modulo {@code polyModulus}
     */
    public static > T polyPowMod(final T base, long exponent,
                                                                    T polyModulus,
                                                                    boolean copy) {
        return polyPowMod(base, exponent, polyModulus, UnivariateDivision.fastDivisionPreConditioning(polyModulus), copy);
    }

    /**
     * Returns {@code base} in a power of non-negative {@code exponent} modulo {@code polyModulus}
     *
     * @param base        the base
     * @param exponent    the non-negative exponent
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code base}; if not the data of {@code base} will be lost
     * @return {@code base} in a power of {@code e} modulo {@code polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyPowMod(final T base, long exponent,
                                                                    T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                    boolean copy) {
        if (exponent < 0)
            throw new IllegalArgumentException();
        if (exponent == 0)
            return base.createOne();

        T result = base.createOne();
        T k2p = polyMod(base, polyModulus, invMod, copy); // this will copy the base
        for (; ; ) {
            if ((exponent & 1) != 0)
                result = polyMod(result.multiply(k2p), polyModulus, invMod, false);
            exponent = exponent >> 1;
            if (exponent == 0)
                return result;
            k2p = polyMod(k2p.multiply(k2p), polyModulus, invMod, false);
        }
    }

    /**
     * Returns {@code base} in a power of non-negative {@code exponent} modulo {@code polyModulus}
     *
     * @param base        the base
     * @param exponent    the non-negative exponent
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @param copy        whether to clone {@code base}; if not the data of {@code base} will be lost
     * @return {@code base} in a power of {@code e} modulo {@code polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyPowMod(final T base, BigInteger exponent,
                                                                    T polyModulus, UnivariateDivision.InverseModMonomial invMod,
                                                                    boolean copy) {
        if (exponent.signum() < 0)
            throw new IllegalArgumentException();
        if (exponent.isZero())
            return base.createOne();


        T result = base.createOne();
        T k2p = polyMod(base, polyModulus, invMod, copy); // this will copy the base
        for (; ; ) {
            if (exponent.testBit(0))
                result = polyMod(result.multiply(k2p), polyModulus, invMod, false);
            exponent = exponent.shiftRight(1);
            if (exponent.isZero())
                return result;
            k2p = polyMod(k2p.multiply(k2p), polyModulus, invMod, false);
        }
    }

    /**
     * Returns {@code base} in a power of non-negative {@code exponent} modulo {@code polyModulus}
     *
     * @param base        the base
     * @param exponent    the non-negative exponent
     * @param polyModulus the modulus
     * @param copy        whether to clone {@code base}; if not the data of {@code base} will be lost
     * @return {@code base} in a power of {@code e} modulo {@code polyModulus}
     * @see UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)
     */
    public static > T polyPowMod(final T base, BigInteger exponent,
                                                                    T polyModulus,
                                                                    boolean copy) {
       return polyPowMod(base, exponent, polyModulus, UnivariateDivision.fastDivisionPreConditioning(polyModulus), copy);
    }

    /** switch between plain and log2 algorithms */
    private static final long MONOMIAL_MOD_EXPONENT_THRESHOLD = 64;

    /**
     * Creates {@code x^exponent mod polyModulus}.
     *
     * @param exponent    the monomial exponent
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @return {@code x^exponent mod polyModulus}
     */
    public static > T createMonomialMod(long exponent,
                                                                           T polyModulus,
                                                                           UnivariateDivision.InverseModMonomial invMod) {
        if (exponent < 0)
            throw new IllegalArgumentException("Negative exponent: " + exponent);

        if (exponent == 0)
            return polyModulus.createOne();

        if (exponent < MONOMIAL_MOD_EXPONENT_THRESHOLD)
            return smallMonomial(exponent, polyModulus, invMod);
        else
            return largeMonomial(exponent, polyModulus, invMod);
    }

    /**
     * Creates {@code x^exponent mod polyModulus}.
     *
     * @param exponent    the monomial exponent
     * @param polyModulus the modulus
     * @param invMod      pre-conditioned modulus ({@link UnivariateDivision#fastDivisionPreConditioning(IUnivariatePolynomial)})
     * @return {@code x^exponent mod polyModulus}
     */
    public static > T createMonomialMod(BigInteger exponent,
                                                                           T polyModulus,
                                                                           UnivariateDivision.InverseModMonomial invMod) {
        if (exponent.signum() < 0)
            throw new IllegalArgumentException("Negative exponent: " + exponent);

        if (exponent.isZero())
            return polyModulus.createOne();

        if (exponent.isLong())
            return createMonomialMod(exponent.longValueExact(), polyModulus, invMod);
        else
            return largeMonomial(exponent, polyModulus, invMod);
    }

    /** plain create and reduce */
    static > T smallMonomial(long exponent, T polyModulus, UnivariateDivision.InverseModMonomial invMod) {
        return UnivariatePolynomialArithmetic.polyMod(polyModulus.createMonomial(MachineArithmetic.safeToInt(exponent)), polyModulus, invMod, false);
    }

    /** repeated squaring */
    static > T largeMonomial(long exponent, T polyModulus, UnivariateDivision.InverseModMonomial invMod) {
        return polyPowMod(polyModulus.createMonomial(1), exponent, polyModulus, invMod, false);
//        T base = UnivariatePolynomialArithmetic.polyMod(
//                polyModulus.monomial(MachineArithmetic.safeToInt(MONOMIAL_MOD_EXPONENT_THRESHOLD)),
//                polyModulus, invMod, false);
//
//        T result = base.clone();
//        long exp = MONOMIAL_MOD_EXPONENT_THRESHOLD;
//        for (; ; ) {
//            if (MachineArithmetic.isOverflowAdd(exp, exp) || exp + exp > exponent)
//                break;
//            result = UnivariatePolynomialArithmetic.polyMultiplyMod(result, result, polyModulus, invMod, false);
//            exp += exp;
//        }
//
//        T rest = createMonomialMod(exponent - exp, polyModulus, invMod);
//        return UnivariatePolynomialArithmetic.polyMultiplyMod(result, rest, polyModulus, invMod, false);
    }

    /** repeated squaring */
    static > T largeMonomial(BigInteger exponent, T polyModulus, UnivariateDivision.InverseModMonomial invMod) {
        return polyPowMod(polyModulus.createMonomial(1), exponent, polyModulus, invMod, false);
//        T base = UnivariatePolynomialArithmetic.polyMod(
//                polyModulus.monomial(MachineArithmetic.safeToInt(MONOMIAL_MOD_EXPONENT_THRESHOLD)),
//                polyModulus, invMod, false);
//
//        T result = base.clone();
//        BigInteger exp = BigInteger.valueOf(MONOMIAL_MOD_EXPONENT_THRESHOLD);
//        for (; ; ) {
//            if (exp.shiftLeft(1).compareTo(exponent) > 0)
//                break;
//            result = UnivariatePolynomialArithmetic.polyMultiplyMod(result, result, polyModulus, invMod, false);
//            exp = exp.shiftLeft(1);
//        }
//
//        T rest = createMonomialMod(exponent.subtract(exp), polyModulus, invMod);
//        return UnivariatePolynomialArithmetic.polyMultiplyMod(result, rest, polyModulus, invMod, false);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy