CGAL 6.1 - Algebraic Kernel
|
Real solving of polynomials is a fundamental problem with a wide application range. This package provides black-box implementations of algorithms to determine, compare, and approximate real roots of univariate polynomials and bivariate polynomial systems. Such a black-box is called an Algebraic Kernel. Since this package is aimed at providing more than one implementation, the interface of the algebraic kernels is expressed in concepts. The main concepts provided by this package are the AlgebraicKernel_d_1
for univariate polynomial systems and AlgebraicKernel_d_2
for bivariate polynomial systems, the latter being a refinement of the first.
First of all, the univariate algebraic kernel provides construction, comparison and approximation of real roots of univariate polynomials. Thus, the major public types the AlgebraicKernel_d_1
provides are:
AlgebraicKernel_d_1::Polynomial_1
- the type representing univariate polynomials,
AlgebraicKernel_d_1::Coefficient
- the coefficient type of these polynomials,
AlgebraicKernel_d_1::Algebraic_real_1
- the type representing real roots,
AlgebraicKernel_d_1::Bound
- the type which is used to approximate these algebraic reals, in particular, it is used to represent the boundaries of isolating intervals.
The kernel provides two different function objects to construct an AlgebraicKernel_d_1::Algebraic_real_1
. The most general way is to use AlgebraicKernel_d_1::Isolate_1
; The function object takes a univariate polynomial and writes all real roots into a given output iterator. It is also possible to retrieve the multiplicity of each root. The second option is to construct one particular algebraic real using AlgebraicKernel_d_1::Construct_algebraic_real_1
. This function object provides construction from the native int type, the coefficient type as well as the bound type. Moreover, it is possible to construct an algebraic real by giving a polynomial and either an isolating interval or the index of the root. A related function object is AlgebraicKernel_d_1::Number_of_solutions_1
computing the number of real roots of a polynomial.
An AlgebraicKernel_d_1::Algebraic_real_1
is model of RealEmbeddable
, for instance, it is possible to compare two algebraic reals, to determine the sign of an algebraic real or to ask for its double approximation, see also section secRealEmbeddable. Moreover, AlgebraicKernel_d_1::Compare_1
provides comparison with int, the coefficient type and the bound type.
There are several ways to approximate an AlgebraicKernel_d_1::Algebraic_real_1
:
AlgebraicKernel_d_1::Approximate_absolute_1
- provides an approximation that is better than the passed absolute error bound,
AlgebraicKernel_d_1::Approximate_relative_1
- provides an approximation that is better than the passed relative error bound,
AlgebraicKernel_d_1::Isolate_1
- returns an isolating interval with respect to a given univariate polynomial,
A related function object is AlgebraicKernel_d_1::Bound_between_1
, which computes a number that isolates two algebraic real numbers.
It is also possible to retrieve a representing polynomial from an algebraic real using AlgebraicKernel_d_1::Compute_polynomial_1
, which guarantees that the algebraic real is a root of the returned polynomial. As the name already indicates, this operation may be very costly since the polynomial may not be computed yet. Moreover, it is not guaranteed that the returned polynomial is the minimal polynomial of the number. Together with AlgebraicKernel_d_1::Isolate_1
, it is possible to retrieve the traditional representation of an algebraic real as a square free polynomial and an isolating interval.
Though the AlgebraicKernel_d_1
does not provide arithmetic operations on AlgebraicKernel_d_1::Algebraic_real_1
, it is possible to compute the sign of a polynomial at a given algebraic real using AlgebraicKernel_d_1::Sign_at_1
. Or alternatively, just compute whether the polynomial is zero at an algebraic real number using AlgebraicKernel_d_1::Is_zero_at_1
. Note that this operation can be significantly less expensive, in particular if the polynomial is not zero at the given algebraic real.
First of all the type AlgebraicKernel_d_1::Polynomial_1
is required to be a model of the concept Polynomial_1
, which is defined in the Polynomial package (see chapter Chapter_Polynomial). This implies that all essential functionality is provided via Polynomial_traits_d
. However, the algebraic kernel also provides several function objects to handle polynomials:
AlgebraicKernel_d_1::Is_square_free_1
- determines whether a polynomial is square free,
AlgebraicKernel_d_1::Make_square_free_1
- computes the square free part of a polynomial,
AlgebraicKernel_d_1::Square_free_factorize_1
- computes a square free factorization of a polynomial,
AlgebraicKernel_d_1::Is_coprime_1
- computes whether a pair of polynomials is square free,
AlgebraicKernel_d_1::Make_coprime_1
- decomposes two polynomials into the coprime factors and their common factor.
Though the polynomial package provides similar functionality we suggest to use the function objects provided by the kernel, since the design of the algebraic kernel allows for instance internal caching by the kernel.
Also note that AlgebraicKernel_d_1::Square_free_factorize_1
only computes the square free factorization up to a constant factor. This is a slight modification with respect to its counterpart in Polynomial_traits_d
. In this way it was possible that the concepts just require the coefficient type to be a model of IntegralDomain
, instead of Field
or UniqueFactorizationDomain
. For more details see also:
Most implementations of an AlgebraicKernel_d_1
will represent an algebraic real number by the root of a square free polynomial and an isolating interval, that is, the number is defined as the only root of the polynomial within the interval. Usually, one will refrain from computing the minimal polynomial since the computation of the minimal polynomial is much more expensive and does not pay of. However, besides the representation by a polynomial and an isolating interval one can also imagine the representation by a polynomial and the index of the root, e.g., as the \( i\)th real root when enumerated from minus to plus infinity. Moreover, it may very well be that the kernel just computes an approximation of the number, whereas the representing polynomial is not computed yet. This is in particular relevant in relation to the AlgebraicKernel_d_2
, where AlgebraicKernel_d_1::Algebraic_real_1
is used to represent coordinates of solutions of bivariate systems. Hence, the design does not allow a direct access to any, seemingly obvious, members of an AlgebraicKernel_d_1::Algebraic_real_1
. Instead there is, e.g., AlgebraicKernel_d_1::Compute_polynomial_1
which emphasizes that the requested polynomial may not be computed yet. Similarly, there is no way to directly ask for the refinement of the current isolating interval since this would impose a state to every object of an AlgebraicKernel_d_1::Algebraic_real_1
.
The concept AlgebraicKernel_d_2
is a refinement of AlgebraicKernel_d_1
, that is, a model of AlgebraicKernel_d_2
is also a model of AlgebraicKernel_d_1
. Hence, the AlgebraicKernel_d_2
concept is designed such that occurring names and functionalities are as similar as possible to those in the AlgebraicKernel_d_1
concept. The following are a direct generalization of their univariate counterparts:
AlgebraicKernel_d_2::Polynomial_2
,
AlgebraicKernel_d_2::Algebraic_real_2
,
AlgebraicKernel_d_2::Construct_algebraic_real_2
,
AlgebraicKernel_d_2::Isolate_2
,
AlgebraicKernel_d_2::Is_square_free_2
,
AlgebraicKernel_d_2::Make_square_free_2
,
AlgebraicKernel_d_2::Square_free_factorize_2
,
AlgebraicKernel_d_2::Is_coprime_2
,
AlgebraicKernel_d_2::Make_coprime_2
,
AlgebraicKernel_d_2::Number_of_solutions_2
,
AlgebraicKernel_d_2::Compare_xy_2
,
AlgebraicKernel_d_2::Sign_at_2
,
AlgebraicKernel_d_2::Is_zero_at_2
.
For instance, AlgebraicKernel_d_2::Solve_2
provides the solution for a bivariate polynomial system. However, it is also possible to obtain the coordinates of these solutions with the additional functors:
AlgebraicKernel_d_2::Compute_x_2
,
AlgebraicKernel_d_2::Compute_y_2
.
In principal this would be sufficient generalization, since functions such as isolating, approximating algebraic real numbers could be implemented using these access functions ant the corresponding functionalities in the univariate algebraic kernel. However, one should be aware that an AlgebraicKernel_d_2::Algebraic_real_2
is not necessarily represented as a pair of univariate solutions, that is, using AlgebraicKernel_d_2::Compute_y_2
may entail considerable computations. Therefore, the concept also requires the following additional functors that may allow a model to bypass this issue:
AlgebraicKernel_d_2::Compute_polynomial_x_2
,
AlgebraicKernel_d_2::Compute_polynomial_y_2
,
AlgebraicKernel_d_2::Isolate_x_2
,
AlgebraicKernel_d_2::Isolate_y_2
,
AlgebraicKernel_d_2::Compare_x_2
,
AlgebraicKernel_d_2::Compare_y_2
,
AlgebraicKernel_d_2::Approximate_absolute_x_2
,
AlgebraicKernel_d_2::Approximate_relative_x_2
,
AlgebraicKernel_d_2::Approximate_absolute_y_2
,
AlgebraicKernel_d_2::Approximate_relative_y_2
,
AlgebraicKernel_d_2::Bound_between_x_2
,
AlgebraicKernel_d_2::Bound_between_y_2
.
The package provides generic models of the univariate and bivariate algebraic kernel, namely Algebraic_kernel_d_1<Coeff>
and Algebraic_kernel_d_2<Coeff>
, respectively. Both kernels support a large set of number types as their template argument, which defines the supported coefficient type. The supported types are, for instance, Gmpz
and Gmpq
as well as the corresponding types of LEDA and CORE.
The Algebraic_kernel_d_1<Coeff>
represents an algebraic real root by a square free polynomial and an isolating interval that uniquely defines the root. The current method to isolate roots is the Bitstream Descartes method [6]. The used method to refine the approximation of an algebraic real root is a slightly modified (filtered) version of the one presented in [1]. The method has quadratic convergence.
Algebraic_kernel_d_2<Coeff>
is based on an algorithm computing a geometric-topological analysis of a single curve [5] and of a pair of curves [4]. The main idea behind both analyses is to compute the critical x-coordinates of curves and curve pairs by projection (resultants), and compute additional information about the critical fibers using subresultants and Sturm-Habicht sequences [7]. With that information, the fiber at critical x-coordinates is computed by a variant of the Bitstream Descartes method. See also [8] for a comprehensive description of these techniques. Almost all functors in the class that take a Polynomial_2
object as argument trigger such an analysis as a main computation step. For efficiency, these analyses (of single curves and curve pairs) are therefore cached internally for efficiency. For instance, computing the pairwise solutions of 10 Polynomial_2
objects requires 10 curve analyses and 45 curve pair analyses to be computed internally.
A point \( p\) of type Algebraic_real_2
is represented by its \( x\)-coordinate \( x_0\) (as described in the Algebraic_kernel_d_1
paragraph above), an algebraic curve where \( p\) lies on, and an integer \( i\), denoting that \( p\) is the \( i\)th point in the fiber at \( x_0\), counted from the bottom (ignoring a possible vertical line at \( x_0\)). Note that this determines the point uniquely, but the \( y\)-coordinate is not stored internally in terms of an Algebraic_real_1
object. Querying such a representation by calling Compute_y_2
is a time-consuming step, and should be avoided for efficiency reasons if possible.
The following example illustrates the construction of AlgebraicKernel_d_1::Algebraic_real_1
using AlgebraicKernel_d_1::Construct_algebraic_real_1
:
File Algebraic_kernel_d/Construct_algebraic_real_1.cpp
The following example illustrates the construction of AlgebraicKernel_d_1::Algebraic_real_1
using AlgebraicKernel_d_1::Solve_1
:
File Algebraic_kernel_d/Solve_1.cpp
The following example illustrates the comparison of AlgebraicKernel_d_1::Algebraic_real_1
numbers:
File Algebraic_kernel_d/Compare_1.cpp
The following example illustrates the isolation of AlgebraicKernel_d_1::Algebraic_real_1
numbers:
File Algebraic_kernel_d/Isolate_1.cpp
The following example illustrates the sign evaluation of AlgebraicKernel_d_1::Algebraic_real_1
numbers in polynomials:
File Algebraic_kernel_d/Sign_at_1.cpp
This package is clearly split into a univariate and bivariate kernel. However, with respect to its history the package splits into a design part and an implementation part.
The concepts, which make up the design part, were written by Eric Berberich, Michael Hemmer, and Monique Teillaud. The design history of the package is fairly old and several ideas that influenced this package can already be found in [3]. Since then, the initial design underwent considerable changes. For instance, it was decided that the algebraic numbers should be under the control of the algebraic kernel. On the other hand the initial support for polynomials was extended to a separate and independent package that is not restricted to a certain number of variables. Thus, the authors want to thank for all the useful feedback and ideas that was brought to them throughout the last years. In particular, they want to thank Menelaos Karavelas and Elias Tsigaridas for their initial contributions.
The two generic models where initially developed as part of the Exacus [2] project. However, the models are now fully integrated into the CGAL library, since also the relevant layers of Exacus are now part of CGAL. The main authors for Algebraic_kernel_d_1<Coeff>
and Algebraic_kernel_d_2<Coeff>
are Michael Hemmer and Michael Kerber, respectively. Notwithstanding, the authors also want to emphasize the contribution of all authors of the Exacus project, particularly the contribution of Arno Eigenwillig, Sebastian Limbach and Pavel Emeliyanenko.
In 2010, two univariate kernels that interface the library RS [10] were written by Luis Peñaranda and Sylvain Lazard [9]. Both models interface the library RS [10] by Fabrice Rouillier. The authors want to thank Fabrice Rouillier and Elias Tsigaridas for strong support and many useful discussions that lead to the integration of RS. Due to lack of maintenance, these kernels have been removed in 2024.