Skip to content

Commit

Permalink
Rabin root finding (#78)
Browse files Browse the repository at this point in the history
* extended assertion in berlekamp factorization

* some code cleanup (made functions static, added assertions)

* Added lp_upolynomial_roots_find_Zp and

* Added comment with reference

* Added todos and comments

* Added C++ code for find_roots_Zp

* Added python lib and test for root_finding_Zp

* Revert changes to libpoly0.symbols

* Removed (already fixed) TODO

* Fixed typo

* Fixed comment

* added missing comments

---------

Co-authored-by: Thomas Hader <[email protected]>
  • Loading branch information
Ovascos and Thomas Hader authored Mar 8, 2024
1 parent fd1a354 commit 7a4dedc
Show file tree
Hide file tree
Showing 18 changed files with 637 additions and 43 deletions.
2 changes: 1 addition & 1 deletion include/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ int lp_integer_sgn(const lp_int_ring_t* K, const lp_integer_t* c);
int lp_integer_cmp(const lp_int_ring_t* K, const lp_integer_t* c, const lp_integer_t* to);

/**
* Compare the two integers in the ring. Same as for sgn.
* Compare the two integers in the ring. Same as for cmp.
*/
int lp_integer_cmp_int(const lp_int_ring_t* K, const lp_integer_t* c, long to);

Expand Down
5 changes: 5 additions & 0 deletions include/polyxx/upolynomial.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,9 @@ namespace poly {
*/
std::vector<AlgebraicNumber> isolate_real_roots(const UPolynomial& p);

/**
* Finds the roots for a polynomial mod p using rabin root finding.
*/
std::vector<Integer> find_roots_Zp(const UPolynomial& p);

} // namespace poly
21 changes: 19 additions & 2 deletions include/upolynomial.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,20 @@ void lp_upolynomial_subst_x_pow_in_place(lp_upolynomial_t* f, size_t n);
lp_upolynomial_t* lp_upolynomial_neg(const lp_upolynomial_t* p);

/**
* Negates p in place.
* Negates p in-place.
*/
void lp_upolynomial_neg_in_place(lp_upolynomial_t* p);

/**
* Makes the polynomial monic.
*/
lp_upolynomial_t* lp_upolynomial_make_monic(const lp_upolynomial_t* p);

/**
* Makes the polynomial monic in-place.
*/
void lp_upolynomial_make_monic_in_place(lp_upolynomial_t* p);

/**
* Add two polynomials (all operations in the same ring).
*/
Expand Down Expand Up @@ -365,7 +375,14 @@ int lp_upolynomial_roots_count(const lp_upolynomial_t* p, const lp_rational_inte
void lp_upolynomial_roots_isolate(const lp_upolynomial_t* p, lp_algebraic_number_t* roots, size_t* roots_size);

/**
* Reverses the coefficient of p in place. The result polynomial is
* Finds the root for an univariate polynomial in Zp. The array roots will be allocated,
* and the user should de-allocate it. The size parameter will be updated with the size
* of the array.
*/
void lp_upolynomial_roots_find_Zp(const lp_upolynomial_t* f, lp_integer_t** roots, size_t* roots_size);

/**
* Reverses the coefficient of p in-place. The result polynomial is
* p'(x) = x^n * p(1/x) = a_n + ... + a_0 * x^n
*/
void lp_upolynomial_reverse_in_place(lp_upolynomial_t* p);
Expand Down
34 changes: 34 additions & 0 deletions python/polypyUPolynomial3.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ UPolynomial_roots_isolate(PyObject* self);
static PyObject*
UPolynomial_sturm_sequence(PyObject* self);

static PyObject*
UPolynomial_roots_find_Zp(PyObject* self);

static PyObject*
UPolynomial_evaluate(PyObject* self, PyObject* args);

Expand Down Expand Up @@ -120,6 +123,7 @@ PyMethodDef UPolynomial_methods[] = {
{"roots_count", (PyCFunction)UPolynomial_roots_count, METH_VARARGS, "Returns the number of real roots in the given interval"},
{"roots_isolate", (PyCFunction)UPolynomial_roots_isolate, METH_NOARGS, "Returns the list of real roots"},
{"sturm_sequence", (PyCFunction)UPolynomial_sturm_sequence, METH_NOARGS, "Returns the Sturm sequence"},
{"roots_find_Zp", (PyCFunction)UPolynomial_roots_find_Zp, METH_NOARGS, "Returns the roots of the polynomial in Zp"},
{"derivative", (PyCFunction)UPolynomial_derivative, METH_NOARGS, "Returns the derivative of the polynomial"},
{"evaluate", (PyCFunction)UPolynomial_evaluate, METH_VARARGS, "Returns the value of the polynomial at the given point"},
{NULL} /* Sentinel */
Expand Down Expand Up @@ -863,6 +867,36 @@ UPolynomial_sturm_sequence(PyObject* self) {
return result;
}

static PyObject* integer_list_to_PyList(lp_integer_t *list, size_t size) {
// Construct the result
PyObject* pylist = PyList_New(size);

// Copy over the integers
size_t i;
for (i = 0; i < size; ++ i) {
PyObject* pylist_i = integer_to_PyLong(&list[i]);
Py_INCREF(pylist_i);
PyList_SetItem(pylist, i, pylist_i);
}

// Return the list
return pylist;
}

static PyObject*
UPolynomial_roots_find_Zp(PyObject* self) {
lp_upolynomial_t* p = ((UPolynomialObject*) self)->p;
lp_integer_t* roots;
size_t roots_size;
lp_upolynomial_roots_find_Zp(p, &roots, &roots_size);
PyObject* result = integer_list_to_PyList(roots, roots_size);
for (size_t i = 0; i < roots_size; ++i) {
lp_integer_destruct(&roots[i]);
}
free(roots);
return result;
}

static PyObject*
UPolynomial_evaluate(PyObject* self, PyObject* args) {
if (PyTuple_Check(args) && PyTuple_Size(args) == 1) {
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(poly_SOURCES
upolynomial/factors.c
upolynomial/factorization.c
upolynomial/root_finding.c
upolynomial/upolynomial_vector.c
polynomial/monomial.c
polynomial/coefficient.c
polynomial/output.c
Expand Down
10 changes: 10 additions & 0 deletions src/number/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ int integer_is_zero(const lp_int_ring_t* K, const lp_integer_t* c) {
}
}

static inline
int integer_is_odd(const lp_integer_t* c) {
return mpz_odd_p(c);
}

static inline
int integer_is_even(const lp_integer_t* c) {
return mpz_even_p(c);
}

static inline
int integer_sgn(const lp_int_ring_t* K, const lp_integer_t* c) {
if (K) {
Expand Down
2 changes: 2 additions & 0 deletions src/polynomial/polynomial.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ int lp_polynomial_is_univariate(const lp_polynomial_t* A) {
return coefficient_is_univariate(&A->data);
}

// TODO is a constant polynomial univariate?
int lp_polynomial_is_univariate_m(const lp_polynomial_t* A, const lp_assignment_t* m) {
if (lp_polynomial_is_constant(A)) {
return 0;
Expand All @@ -286,6 +287,7 @@ int lp_polynomial_is_univariate_m(const lp_polynomial_t* A, const lp_assignment_
}

lp_upolynomial_t* lp_polynomial_to_univariate(const lp_polynomial_t* A) {
lp_polynomial_external_clean(A);
if (!(coefficient_is_constant(&A->data) || coefficient_is_univariate(&A->data))) {
return NULL;
} else {
Expand Down
14 changes: 14 additions & 0 deletions src/polyxx/upolynomial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,19 @@ namespace poly {
return res;
}

std::vector<Integer> find_roots_Zp(const UPolynomial& p) {
lp_integer_t *roots;
std::size_t roots_size;
lp_upolynomial_roots_find_Zp(p.get_internal(), &roots, &roots_size);
std::vector<Integer> res;
for (std::size_t i = 0; i < roots_size; ++i) {
res.emplace_back(&roots[i]);
}
for (std::size_t i = 0; i < roots_size; ++i) {
lp_integer_destruct(&roots[i]);
}
free(roots);
return res;
}

} // namespace poly
Loading

0 comments on commit 7a4dedc

Please sign in to comment.