// Copyright (c) 2006-2009 Max-Planck-Institute Saarbruecken (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Algebraic_kernel_d/include/CGAL/Algebraic_kernel_d_1.h $ // $Id: Algebraic_kernel_d_1.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Michael Hemmer // Sebastian Limbach // Michael Kerber // // ============================================================================ #ifndef CGAL_ALGEBRAIC_KERNEL_D_1_H #define CGAL_ALGEBRAIC_KERNEL_D_1_H #include #ifndef CGAL_AK_ENABLE_DEPRECATED_INTERFACE #define CGAL_AK_ENABLE_DEPRECATED_INTERFACE 0 #endif #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { namespace internal { template< class AlgebraicReal1, class Isolator_ > class Algebraic_kernel_d_1_base { public: typedef AlgebraicReal1 Algebraic_real_1; typedef Isolator_ Isolator; typedef typename Algebraic_real_1::Coefficient Coefficient; typedef typename Algebraic_real_1::Bound Bound; typedef typename Algebraic_real_1::Polynomial_1 Polynomial_1; // TODO: Other choice? typedef int size_type; typedef int Multiplicity_type; private: typedef CGAL::Polynomial_traits_d< Polynomial_1 > PT_1; protected: // Some functors used for STL calls template struct Pair_first : public CGAL::cpp98::unary_function,A> { A operator() (std::pair pair) const { return pair.first; } }; template struct Pair_second : public CGAL::cpp98::unary_function,B> { B operator() (std::pair pair) const { return pair.second; } }; public: class Algebraic_real_traits { public: typedef Algebraic_real_1 Type; struct Bound_between : public CGAL::cpp98::binary_function< Type, Type, Bound > { Bound operator()( const Type& t1, const Type& t2 ) const { #if CGAL_AK_DONT_USE_SIMPLE_BOUND_BETWEEN #warning uses deprecated bound_between_1 functor return t1.rational_between( t2 ); #else return internal::simple_bound_between(t1,t2); #endif } }; struct Lower_bound : public CGAL::cpp98::unary_function< Type, Bound > { Bound operator()( const Type& t ) const { return t.low(); } }; struct Upper_bound : public CGAL::cpp98::unary_function< Type, Bound > { Bound operator()( const Type& t ) const { return t.high(); } }; struct Refine : public CGAL::cpp98::unary_function< Type, void > { void operator()( const Type& t ) const { t.refine(); } void operator()( Type& t, int rel_prec ) const { // If t is zero, we can refine the interval to // infinite precission if( CGAL::is_zero( t ) ) { t = Type(0); } else { // Refine until both boundaries have the same sign while( CGAL::sign( t.high() ) != CGAL::sign( t.low() ) ) t.refine(); CGAL_assertion( CGAL::sign( t.high() ) != CGAL::ZERO && CGAL::sign( t.low() ) != CGAL::ZERO ); // Calculate the needed precision Bound prec = Bound(1) / CGAL::ipower( Bound(2), rel_prec ); // Refine until precision is reached while( CGAL::abs( t.high() - t.low() ) / (CGAL::max)( CGAL::abs( t.high() ), CGAL::abs( t.low() ) ) > prec ) { t.refine(); CGAL_assertion( CGAL::sign( t.high() ) != CGAL::ZERO && CGAL::sign( t.low() ) != CGAL::ZERO ); } } } }; struct Approximate_absolute_1: public CGAL::cpp98::binary_function >{ std::pair operator()(const Algebraic_real_1& x, int prec) const { Lower_bound lower; Upper_bound upper; Refine refine; Bound l = lower(x); Bound u = upper(x); Bound error = CGAL::ipower(Bound(2),CGAL::abs(prec)); while((prec>0)?((u-l)*error>Bound(1)):((u-l)>error)){ refine(x); u = upper(x); l = lower(x); } return std::make_pair(l,u); } }; struct Approximate_relative_1: public CGAL::cpp98::binary_function >{ std::pair operator()(const Algebraic_real_1& x, int prec) const { if(CGAL::is_zero(x)) return std::make_pair(Bound(0),Bound(0)); Lower_bound lower; Upper_bound upper; Refine refine; Bound l = lower(x); Bound u = upper(x); Bound error = CGAL::ipower(Bound(2),CGAL::abs(prec)); Bound min_b = (CGAL::min)(CGAL::abs(u),CGAL::abs(l)); while((prec>0)?((u-l)*error>min_b):((u-l)>error*min_b)){ refine(x); u = upper(x); l = lower(x); min_b = (CGAL::min)(CGAL::abs(u),CGAL::abs(l)); } return std::make_pair(l,u); } }; #if CGAL_AK_ENABLE_DEPRECATED_INTERFACE typedef Lower_bound Lower_boundary; typedef Upper_bound Upper_boundary; typedef Bound_between Boundary_between; #endif }; // class Algebraic_real_traits struct Construct_algebraic_real_1; // Functors of Algebraic_kernel_d_1 struct Solve_1 { public: template OutputIterator operator()(const Polynomial_1& p, OutputIterator oi) const { #if CGAL_AK_ENABLE_DEPRECATED_INTERFACE #else CGAL_precondition(!CGAL::is_zero(p)); #endif internal::Real_roots< Algebraic_real_1, Isolator > real_roots; std::list< int > mults; std::list< Algebraic_real_1 > roots; real_roots( p, std::back_inserter(roots), std::back_inserter( mults ) ); CGAL_assertion(roots.size()==mults.size()); std::list::iterator mit =mults.begin(); typename std::list< Algebraic_real_1 >::iterator rit = roots.begin(); while(rit != roots.end()) { //*oi++ = std::make_pair(*rit, (unsigned int)(*mit)); *oi++ = std::make_pair(*rit, *mit); rit++; mit++; } return oi; } #if 1 || CGAL_AK_ENABLE_DEPRECATED_INTERFACE template< class OutputIterator > OutputIterator operator()( const Polynomial_1& p, OutputIterator oi , bool known_to_be_square_free) const { return this->operator()(p,known_to_be_square_free,oi); } #endif template< class OutputIterator > OutputIterator operator()( const Polynomial_1& p, bool known_to_be_square_free, OutputIterator oi) const { internal::Real_roots< Algebraic_real_1, Isolator > real_roots; #if CGAL_AK_ENABLE_DEPRECATED_INTERFACE #else CGAL_precondition(!CGAL::is_zero(p)); #endif std::list roots; if( known_to_be_square_free ){ real_roots(p,std::back_inserter(roots)); }else{ std::list dummy; real_roots(p,std::back_inserter(roots),std::back_inserter(dummy)); } return std::copy(roots.begin(),roots.end(),oi); } #if CGAL_AK_ENABLE_DEPRECATED_INTERFACE template< class OutputIteratorRoots , class OutputIteratorMults > std::pair operator()( const Polynomial_1& p, OutputIteratorRoots roi, OutputIteratorMults moi) const { internal::Real_roots< Algebraic_real_1, Isolator > real_roots; real_roots(p,roi,moi); return std::make_pair(roi,moi); } #endif protected: /* // TODO: Can we avoid to use this? struct Greater_compare : public CGAL::cpp98::binary_function { bool operator() (const Algebraic_real_1& a, const Algebraic_real_1& b) const { return a>b; } }; */ public: template< class OutputIterator > OutputIterator operator()(const Polynomial_1& p, Bound l, Bound u, OutputIterator res) const { std::vector > roots; this->operator() (p,std::back_inserter(roots)); Algebraic_real_1 alg_l=Construct_algebraic_real_1()(l); Algebraic_real_1 alg_u=Construct_algebraic_real_1()(u); typedef typename std::vector >::iterator Iterator; Pair_first pair_first; Iterator it_start=std::lower_bound (::boost::make_transform_iterator(roots.begin(),pair_first), ::boost::make_transform_iterator(roots.end(),pair_first), alg_l).base(); Iterator it_end=std::upper_bound (::boost::make_transform_iterator(it_start,pair_first), ::boost::make_transform_iterator(roots.end(),pair_first), alg_u).base(); std::copy(it_start,it_end,res); return res; } template< class OutputIterator > OutputIterator operator()(const Polynomial_1& p, bool known_to_be_square_free, Bound l, Bound u, OutputIterator res) const { std::vector roots; this->operator() (p,known_to_be_square_free,std::back_inserter(roots)); Algebraic_real_1 alg_l=Construct_algebraic_real_1()(l); Algebraic_real_1 alg_u=Construct_algebraic_real_1()(u); typedef typename std::vector::iterator Iterator; Iterator it_start=std::lower_bound(roots.begin(),roots.end(),alg_l); Iterator it_end=std::upper_bound(it_start,roots.end(),alg_u); std::copy(it_start,it_end,res); return res; } }; class Number_of_solutions_1 : public CGAL::cpp98::unary_function { public: size_type operator() (const Polynomial_1& p) const { std::vector > roots; Solve_1()(p,std::back_inserter(roots)); return static_cast(roots.size()); } }; struct Sign_at_1 : public CGAL::cpp98::binary_function< Polynomial_1, Algebraic_real_1, CGAL::Sign > { CGAL::Sign operator()( const Polynomial_1& p, const Algebraic_real_1& ar ) const { if(CGAL::is_zero(p)) return ZERO; if(CGAL::degree(p)==0) return p.sign_at(0); if( ar.low() == ar.high() ) return p.sign_at( ar.low() ); if (p == ar.polynomial()) { return ZERO; } Polynomial_1 g = gcd_utcf(p,ar.polynomial()); if (g.sign_at(ar.low()) != g.sign_at(ar.high())) return ZERO; while(internal::descartes(p,ar.low(),ar.high()) > 0) ar.refine(); while( p.sign_at(ar.low()) == ZERO ) ar.refine(); while( p.sign_at(ar.high()) == ZERO ) ar.refine(); CGAL::Sign result = p.sign_at(ar.low()); CGAL_assertion(result == p.sign_at(ar.high())); return result; } }; struct Is_zero_at_1 : public CGAL::cpp98::binary_function< Polynomial_1, Algebraic_real_1, bool > { bool operator()( const Polynomial_1& p, const Algebraic_real_1& ar ) const { if(CGAL::is_zero(p)) return true; if( ar.low() == ar.high() ) return p.sign_at( ar.low() ) == ZERO; Polynomial_1 g = gcd_utcf(p,ar.polynomial()); return g.sign_at(ar.low()) != g.sign_at(ar.high()); } }; struct Is_square_free_1 : public CGAL::cpp98::unary_function< Polynomial_1, bool > { bool operator()( const Polynomial_1& p ) const { typename CGAL::Polynomial_traits_d< Polynomial_1 >::Is_square_free isf; return isf(p); } }; struct Is_coprime_1 : public CGAL::cpp98::binary_function< Polynomial_1, Polynomial_1, bool > { bool operator()( const Polynomial_1& p1, const Polynomial_1& p2 ) const { typename CGAL::Polynomial_traits_d< Polynomial_1 >::Total_degree total_degree; // TODO: Is GCD already filtered? return( total_degree( gcd_utcf( p1, p2 ) ) == 0 ); } }; struct Make_square_free_1 : public CGAL::cpp98::unary_function< Polynomial_1, Polynomial_1 > { Polynomial_1 operator()( const Polynomial_1& p ) const { return typename CGAL::Polynomial_traits_d< Polynomial_1 >::Make_square_free()( p ); } }; struct Make_coprime_1 { typedef bool result_type; typedef Polynomial_1 first_argument_type; typedef Polynomial_1 second_argument_type; typedef Polynomial_1 third_argument_type; typedef Polynomial_1 fourth_argument_type; typedef Polynomial_1 fifth_argument_type; bool operator()( const Polynomial_1& p1, const Polynomial_1& p2, Polynomial_1& g, // ggT utcf Polynomial_1& q1, // Rest utcf Polynomial_1& q2 ) const { g = typename CGAL::Polynomial_traits_d< Polynomial_1 >::Gcd_up_to_constant_factor()( p1, p2 ); q1 = p1 / g; q2 = p2 / g; return CGAL::is_one(g); } }; struct Square_free_factorize_1 { template< class OutputIterator> OutputIterator operator()( const Polynomial_1& p, OutputIterator it) const { typename PT_1::Square_free_factorize_up_to_constant_factor sqff; return sqff(p,it); } }; struct Compute_polynomial_1 : public CGAL::cpp98::unary_function { Polynomial_1 operator()(const Algebraic_real_1& x) const { return x.polynomial(); } }; struct Construct_algebraic_real_1 { public: typedef Algebraic_real_1 result_type; result_type operator() (int a) const { return Algebraic_real_1(a); } result_type operator() (Bound a) const { return Algebraic_real_1(a); } result_type operator() (typename CGAL::First_if_different::Type a) const { Coefficient coeffs[2] = {a,Coefficient(-1)}; Polynomial_1 p = typename PT_1::Construct_polynomial() (coeffs,coeffs+2); std::vector roots; Solve_1()(p,true,std::back_inserter(roots)); CGAL_assertion(roots.size() == size_type(1)); return roots[0]; } result_type operator() (Polynomial_1 p,size_type i) const { std::vector roots; Solve_1()(p,true,std::back_inserter(roots)); CGAL_assertion( size_type(roots.size()) > i); return roots[i]; } result_type operator() (Polynomial_1 p, Bound l, Bound u) const { CGAL_precondition(l{ typedef CGAL::Comparison_result result_type; result_type operator() (Algebraic_real_1 a,Algebraic_real_1 b) const { return typename Real_embeddable_traits ::Compare() (a,b); } result_type operator() (Algebraic_real_1 a,int b) const { return this->operator()(a,Construct_algebraic_real_1()(b)); } result_type operator() (Algebraic_real_1 a,Bound b) const { return this->operator()(a,Construct_algebraic_real_1()(b)); } result_type operator() (Algebraic_real_1 a, typename CGAL::First_if_different::Type b) const { return this->operator()(a,Construct_algebraic_real_1()(b)); } result_type operator() (int a, Algebraic_real_1 b) const { return this->operator()(Construct_algebraic_real_1()(a),b); } result_type operator() (Bound a,Algebraic_real_1 b) const { return this->operator()(Construct_algebraic_real_1()(a),b); } result_type operator() (typename CGAL::First_if_different::Type a, Algebraic_real_1 b) const { return this->operator()(Construct_algebraic_real_1()(a),b); } }; public: struct Isolate_1 : public CGAL::cpp98::binary_function < Algebraic_real_1,Polynomial_1,std::pair > { public: std::pair operator() (const Algebraic_real_1 a, const Polynomial_1 p) const { if(p == a.polynomial()) return std::make_pair(a.low(),a.high()); std::vector roots; // First isolate p... Solve_1()(p,false,std::back_inserter(roots)); typedef typename std::vector::iterator Iterator; // Binary search on the root to find a place where a could be inserted std::pair it_pair = equal_range(roots.begin(),roots.end(),a); CGAL_assertion(std::distance(it_pair.first,it_pair.second)==0 || std::distance(it_pair.first,it_pair.second)==1); // If we can insert a in two places, it must have been in roots already bool a_in_roots = std::distance(it_pair.first,it_pair.second)==1; if(a_in_roots) { // TODO: can we rely on the property that the isolating intervals // of the roots in p are isolating from each other. What // if p was factorized during isolation? Is that still // guaranteed? To be sure, we do it this way: if(it_pair.first!=roots.begin()) { it_pair.first->strong_refine(*(it_pair.first-1)); } if(it_pair.second!=roots.end()) { it_pair.first->strong_refine(*(it_pair.second)); } return std::make_pair(it_pair.first->low(),it_pair.first->high()); } else { // Refine a until disjoint from neighbors // This is probably not even necessary since the isolating // interval of a isolates against all roots of p thanks to the // comparisons. But to be sure... if(it_pair.first!=roots.begin()) { a.strong_refine(*(it_pair.first-1)); } if(it_pair.first!=roots.end()) { a.strong_refine(*(it_pair.first)); } return std::make_pair(a.low(),a.high()); } } }; typedef typename Algebraic_real_traits::Bound_between Bound_between_1; typedef typename Algebraic_real_traits::Approximate_absolute_1 Approximate_absolute_1; typedef typename Algebraic_real_traits::Approximate_relative_1 Approximate_relative_1; #define CGAL_ALGEBRAIC_KERNEL_1_PRED(Y,Z) Y Z() const { return Y(); } #define CGAL_ALGEBRAIC_KERNEL_1_PRED_WITH_KERNEL \ Y Z() const { return Y((const Algebraic_kernel_d_1*)this); } CGAL_ALGEBRAIC_KERNEL_1_PRED(Is_square_free_1, is_square_free_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Make_square_free_1, make_square_free_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Square_free_factorize_1, square_free_factorize_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Is_coprime_1, is_coprime_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Make_coprime_1, make_coprime_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Solve_1, solve_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Number_of_solutions_1, number_of_solutions_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Construct_algebraic_real_1, construct_algebraic_real_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Sign_at_1, sign_at_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Is_zero_at_1, is_zero_at_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Compare_1,compare_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Bound_between_1, bound_between_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Approximate_absolute_1, approximate_absolute_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Approximate_relative_1, approximate_relative_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Compute_polynomial_1, compute_polynomial_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Isolate_1, isolate_1_object); // Deprecated #if CGAL_AK_ENABLE_DEPRECATED_INTERFACE typedef Bound Boundary; typedef typename Algebraic_real_traits::Refine Refine_1; typedef typename Algebraic_real_traits::Lower_bound Lower_bound_1; typedef typename Algebraic_real_traits::Upper_bound Upper_bound_1; typedef typename Algebraic_real_traits::Lower_bound Lower_boundary_1; typedef typename Algebraic_real_traits::Upper_bound Upper_boundary_1; typedef Bound_between_1 Boundary_between_1; CGAL_ALGEBRAIC_KERNEL_1_PRED(Refine_1, refine_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Lower_bound_1, lower_bound_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Upper_bound_1, upper_bound_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Lower_boundary_1, lower_boundary_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Upper_boundary_1, upper_boundary_1_object); CGAL_ALGEBRAIC_KERNEL_1_PRED(Boundary_between_1, boundary_between_1_object); #endif #undef CGAL_ALGEBRAIC_KERNEL_1_PRED }; } // namespace internal template< class Coefficient, class Bound = typename CGAL::Get_arithmetic_kernel< Coefficient >::Arithmetic_kernel::Rational, class RepClass = internal::Algebraic_real_rep< Coefficient, Bound >, class Isolator = internal::Descartes< typename CGAL::Polynomial_type_generator::Type, Bound > > class Algebraic_kernel_d_1 : public internal::Algebraic_kernel_d_1_base< // Template argument #1 (AlgebraicReal1) internal::Algebraic_real_d_1< Coefficient, Bound, ::CGAL::Handle_policy_no_union, RepClass >, // Template argument #2 (Isolator_) Isolator > {}; } //namespace CGAL #include #endif // CGAL_ALGEBRAIC_KERNEL_D_1_H