Hensel lifting
- Cost
- One quadratic step from to for a factorisation of a degree- polynomial into factors costs operations modulo ; lifting to costs a constant times the last step.
Hensel lifting turns a factorisation of modulo a prime into one modulo for any . It is the bridge between the cheap computations modulo a prime, such as factorisation over , and the integer answer: once exceeds twice a bound for the coefficients of a factor, the factor is determined by its image modulo (Bounds and precision). The method goes back to Hensel's -adic numbers [Hen1908]; Zassenhaus introduced quadratic lifting [Zas1969], and the factor tree for many factors is described in [GG2003, Ch. 15].
Lifting two factors#
The basic step lifts a factorisation into two coprime factors together with their Bézout cofactors. Below, and are moduli with (for example and with ), and congruences between polynomials hold coefficientwise.
Theorem 1 (Hensel step). Let with and monic, , , , and
Let , and let , be the remainders of modulo and of modulo , computed modulo . Then and are monic, congruent to and modulo , and
With , the polynomials and , computed modulo , satisfy .
Proof. All computations of and are modulo , where since . Write and . Then, modulo ,
Since and have the same degree and with monic, ; also . Hence has degree less than modulo , and since is monic, . So , and
because gives . For the cofactors, , so is integral, and . The same argument with in place of gives , and therefore .
The lifted factors are unique: if modulo with monic , modulo , and are coprime modulo , then and modulo [GG2003, Ch. 15]. Taking doubles the exponent at each step (quadratic lifting); taking gains one power of (linear lifting). Quadratic lifting reaches in steps, and since the cost of a step grows with the size of the modulus, the total cost is dominated by the last step.
Many factors: the factor tree#
For with monic, pairwise coprime , the factors are arranged in a binary tree whose leaves are the and whose inner nodes are the products of their two children; the root is . Each pair of siblings carries Bézout cofactors. One lifting step lifts the root pair, then the pairs below, using the lifted product at each node as the "" of its children. By Theorem 1, the factorisation lifts node by node. If the tree is balanced, the polynomials at each level have total degree at most , and a level costs operations, so a step costs operations modulo the new modulus [GG2003, Ch. 15].
Input: with , monic pairwise coprime with , a target .
Output: monic with .
- Build the tree: repeatedly multiply the two polynomials of smallest degree among the leaves and the products made so far. Compute the Bézout cofactors of each pair of siblings modulo with the extended Euclidean algorithm.
- Replace by , which is monic.
- Let with . For , lift the whole tree from to with Theorem 1 at every node, using and ; in the last step, do not lift the cofactors.
- Return the lifted leaves.
Choosing the two factors of smallest degree, as in Huffman coding, balances the tree by degree rather than by the number of leaves, which minimises the total degree of the products that have to be lifted.
Use in FLINT#
fmpz_poly_hensel_build_treebuilds the tree from annmod_poly_factor_t, storing the nodes in arraysv(factors and products),w(cofactors) andlink(the tree structure)._fmpz_poly_hensel_start_liftmakes monic modulo , builds the tree and runs the steps of Algorithm 1 withfmpz_poly_hensel_lift_tree; it returns the precision of the cofactors so that_fmpz_poly_hensel_continue_liftcan resume the lift later, which van Hoeij's algorithm uses to double the precision (Van Hoeij's algorithm).fmpz_poly_hensel_lift_oncelifts once to a fixed precision, as the Zassenhaus algorithm needs.fmpz_poly_hensel_lift,fmpz_poly_hensel_lift_without_inverseandfmpz_poly_hensel_lift_only_inverseimplement Theorem 1 directly, with the reductions modulo done infmpz_mod_poly.fmpz_poly_hensel_lift_tree_recursivelifts the tree. For nodes that are not tiny, it fuses the two halves of Theorem 1: since and modulo , the moduli and and their Newton preinverses (Newton iteration for power series and division) serve all four divisions, and when it computes modulo by exact division instead of lifting . The arithmetic runs ingrrings chosen by the size of the modulus:nmodfor one word,mpn_modfor a few words andfmpz_modabove; since quadratic lifting walks through the moduli , most levels are cheap even when the final precision is large.- The same technique lifts factorisations in other settings: multivariate Hensel lifting in
fmpz_mpoly_factorandnmod_mpoly_factor(Multivariate polynomials: representations and algorithms) and -adic root lifting infmpz_poly_roots_fmpq, which lifts roots instead of factors by Newton iteration.
void fmpz_poly_hensel_lift_once(fmpz_poly_factor_t lifted_fac, const fmpz_poly_t f, const nmod_poly_factor_t local_fac, slong N)slong _fmpz_poly_hensel_start_lift(fmpz_poly_factor_t lifted_fac, slong * link, fmpz_poly_t * v, fmpz_poly_t * w, const fmpz_poly_t f, const nmod_poly_factor_t local_fac, slong target_exp)slong _fmpz_poly_hensel_continue_lift(fmpz_poly_factor_t lifted_fac, slong * link, fmpz_poly_t * v, fmpz_poly_t * w, const fmpz_poly_t f, slong prev, slong curr, slong N, const fmpz_t p)void fmpz_poly_hensel_build_tree(slong * link, fmpz_poly_t * v, fmpz_poly_t * w, const nmod_poly_factor_t fac)void fmpz_poly_hensel_lift_tree(slong * link, fmpz_poly_t * v, fmpz_poly_t * w, fmpz_poly_t f, slong r, const fmpz_t p, slong e0, slong e1, slong inv)void fmpz_poly_hensel_lift_tree_recursive(slong * link, fmpz_poly_t * v, fmpz_poly_t * w, fmpz_poly_t f, slong j, slong inv, const fmpz_t p0, const fmpz_t p1)void fmpz_poly_hensel_lift(fmpz_poly_t Gout, fmpz_poly_t Hout, fmpz_poly_t Aout, fmpz_poly_t Bout, const fmpz_poly_t f, const fmpz_poly_t g, const fmpz_poly_t h, const fmpz_poly_t a, const fmpz_poly_t b, const fmpz_t p, const fmpz_t p1)Referenced from#
References#
- [Hen1908] K. Hensel. Theorie der algebraischen Zahlen. Teubner, Leipzig, 1908.
- [Zas1969] H. Zassenhaus. On Hensel factorization, I. Journal of Number Theory 1 (1969), 291–311. https://doi.org/10.1016/0022-314X(69)90047-X
- [GG2003] J. von zur Gathen and J. Gerhard, Modern Computer Algebra, second edition, Cambridge University Press (2003)
The FLINT team, “Hensel lifting,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/polynomials/hensel-lifting.html (generated 2026-11-02).
@misc{flint-doc-algorithms-polynomials-hensel-lifting,
author = {{The FLINT team}},
title = {{Hensel lifting}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/polynomials/hensel-lifting.html},
note = {Generated 2026-11-02}
}