// Copyright (c) 2006-2013 INRIA Nancy-Grand Est (France). All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // See the file LICENSE.LGPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // Author: Luis PeƱaranda #ifndef CGAL_RS_FUNCTORS_1_H #define CGAL_RS_FUNCTORS_1_H #include #include namespace CGAL{ namespace RS_AK1{ template struct Construct_algebraic_real_1{ typedef Polynomial_ Polynomial; typedef Algebraic_ Algebraic; typedef Bound_ Bound; typedef Coefficient_ Coefficient; typedef Isolator_ Isolator; typedef Algebraic result_type; template Algebraic operator()(const T &a)const{ return Algebraic(a); } Algebraic operator()(const Polynomial &p,size_t i)const{ Isolator isol(p); return Algebraic(p,isol.left_bound(i),isol.right_bound(i)); } Algebraic operator()(const Polynomial &p, const Bound &l, const Bound &r)const{ return Algebraic(p,l,r); } }; // struct Construct_algebraic_1 template struct Compute_polynomial_1: public CGAL::cpp98::unary_function{ typedef Polynomial_ Polynomial; typedef Algebraic_ Algebraic; Polynomial operator()(const Algebraic &x)const{ return x.get_pol(); } }; // struct Compute_polynomial_1 template struct Is_coprime_1: public CGAL::cpp98::binary_function{ typedef Polynomial_ Polynomial; typedef Ptraits_ Ptraits; typedef typename Ptraits::Gcd_up_to_constant_factor Gcd; typedef typename Ptraits::Degree Degree; inline bool operator()(const Polynomial &p1,const Polynomial &p2)const{ return Degree()(Gcd()(p1,p2))==0; } }; // struct Is_coprime_1 template struct Make_coprime_1{ typedef Polynomial_ Polynomial; typedef Ptraits_ Ptraits; typedef typename Ptraits::Gcd_up_to_constant_factor Gcd; typedef typename Ptraits::Degree Degree; typedef typename Ptraits::Integral_division_up_to_constant_factor IDiv; bool operator()(const Polynomial &p1, const Polynomial &p2, Polynomial &g, Polynomial &q1, Polynomial &q2)const{ g=Gcd()(p1,p2); q1=IDiv()(p1,g); q2=IDiv()(p2,g); return Degree()(Gcd()(p1,p2))==0; } }; // struct Make_coprime_1 template struct Solve_1{ typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Isolator_ Isolator; typedef Signat_ Signat; typedef Ptraits_ Ptraits; typedef typename Ptraits::Gcd_up_to_constant_factor Gcd; typedef typename Ptraits::Square_free_factorize_up_to_constant_factor Sqfr; typedef typename Ptraits::Degree Degree; typedef typename Ptraits::Make_square_free Sfpart; template OutputIterator operator()(const Polynomial_1 &p, OutputIterator res)const{ typedef std::pair polmult; typedef std::vector sqvec; Polynomial_1 sfp=Sfpart()(p); sqvec sfv; Sqfr()(p,std::back_inserter(sfv)); Isolator isol(sfp); int *m=(int*)calloc(isol.number_of_real_roots(),sizeof(int)); for(typename sqvec::iterator i=sfv.begin();i!=sfv.end();++i){ int k=Degree()(i->first); Signat signof(i->first); for(int j=0;k&&jsecond; --k; } } } } for(int l=0;l OutputIterator operator()(const Polynomial_1 &p, bool known_to_be_square_free, OutputIterator res)const{ Isolator isol(p); for(int l=0;l OutputIterator operator()(const Polynomial_1 &p, const Bound &l, const Bound &u, OutputIterator res)const{ typedef std::vector RV; typedef std::pair PM; typedef std::vector PMV; typedef typename PMV::iterator PMVI; CGAL_precondition_msg(l<=u, "left bound must be <= right bound"); RV roots; // all roots of the polynomial this->operator()(p,false,std::back_inserter(roots)); size_t nb_roots=roots.size(); // indices of the first and last roots to be reported: size_t index_l=0,index_u; while(index_l and match the // roots in the interval [index_l,index_u) for(PMVI i=sfv.begin();i!=sfv.end();++i){ int k=Degree()(i->first); Signat signof(i->first); for(size_t j=index_l;k&&jsecond; --k; } } } } for(size_t l=index_l;l OutputIterator operator()(const Polynomial_1 &p, bool known_to_be_square_free, const Bound &l, const Bound &u, OutputIterator res)const{ typedef std::vector RV; typedef typename RV::iterator RVI; CGAL_precondition_msg(l<=u, "left bound must be <= right bound"); RV roots; this->operator()(p, known_to_be_square_free, std::back_inserter(roots)); for(RVI it=roots.begin();it!=roots.end();it++) if(*it>=l&&*it<=u) *res++=*it; return res; } }; // struct Solve_1 template class Sign_at_1: public CGAL::cpp98::binary_function{ // This implementation will work with any polynomial type whose // coefficient type is explicit interoperable with Gmpfi. // TODO: Make this function generic. public: typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Refiner_ Refiner; typedef Signat_ Signat; typedef Ptraits_ Ptraits; private: CGAL::Uncertain eval_interv(const Polynomial_1 &p, const Bound &l, const Bound &r)const{ typedef typename Ptraits::Substitute Subst; std::vector substitutions; substitutions.push_back(CGAL::Gmpfi(l,r)); CGAL::Gmpfi eval=Subst()(p, substitutions.begin(), substitutions.end()); return eval.sign(); } // This function assumes that the sign of the evaluation is not zero, // it just refines x until having the correct sign. CGAL::Sign refine_and_return(const Polynomial_1 &p,Algebraic x)const{ CGAL::Gmpfr xl(x.get_left()); CGAL::Gmpfr xr(x.get_right()); CGAL::Uncertain s; for(;;){ Refiner()(x.get_pol(), xl, xr, 2*CGAL::max(xl.get_precision(), xr.get_precision())); s=eval_interv(p,xl,xr); if(!s.is_same(Uncertain::indeterminate())){ x.set_left(xl); x.set_right(xr); return s; } } } public: CGAL::Sign operator()(const Polynomial_1 &p,Algebraic x)const{ typedef typename Ptraits::Gcd_up_to_constant_factor Gcd; typedef typename Ptraits::Make_square_free Sfpart; typedef typename Ptraits::Degree Degree; typedef typename Ptraits::Differentiate Deriv; CGAL::Uncertain unknown= Uncertain::indeterminate(); CGAL::Uncertain s=eval_interv(p, x.get_left(), x.get_right()); if(!s.is_same(unknown)) return s; // We are not sure about the sign. We calculate the gcd in // order to know if both polynomials have common roots. Polynomial_1 sfpp=Sfpart()(p); Polynomial_1 gcd=Gcd()(sfpp,Sfpart()(x.get_pol())); if(Degree()(gcd)==0) return refine_and_return(p,x); // At this point, gcd is not 1; we proceed as follows: // -we refine x until having p monotonic in x's interval (to be // sure that p has at most one root on that interval), // -if the gcd has a root on this interval, both roots are // equal (we return 0), otherwise, we refine until having a // result. // How to assure that p is monotonic in an interval: when its // derivative is never zero in that interval. Polynomial_1 dsfpp=Deriv()(sfpp); CGAL::Gmpfr xl(x.get_left()); CGAL::Gmpfr xr(x.get_right()); while(eval_interv(dsfpp,xl,xr).is_same(unknown)){ Refiner()(x.get_pol(), xl, xr, 2*CGAL::max(xl.get_precision(), xr.get_precision())); } x.set_left(xl); x.set_right(xr); // How to know that the gcd has a root: evaluate endpoints. CGAL::Sign sleft,sright; Signat sign_at_gcd(gcd); if((sleft=sign_at_gcd(x.get_left()))==CGAL::ZERO|| (sright=sign_at_gcd(x.get_right()))==CGAL::ZERO|| (sleft!=sright)) return CGAL::ZERO; return refine_and_return(p,x); } }; // struct Sign_at_1 template class Is_zero_at_1: public CGAL::cpp98::binary_function{ // This implementation will work with any polynomial type whose // coefficient type is explicit interoperable with Gmpfi. // TODO: Make this function generic. public: typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Refiner_ Refiner; typedef Signat_ Signat; typedef Ptraits_ Ptraits; private: CGAL::Uncertain eval_interv(const Polynomial_1 &p, const Bound &l, const Bound &r)const{ typedef typename Ptraits::Substitute Subst; std::vector substitutions; substitutions.push_back(CGAL::Gmpfi(l,r)); CGAL::Gmpfi eval=Subst()(p, substitutions.begin(), substitutions.end()); return eval.sign(); } public: bool operator()(const Polynomial_1 &p,Algebraic x)const{ typedef typename Ptraits::Gcd_up_to_constant_factor Gcd; typedef typename Ptraits::Make_square_free Sfpart; typedef typename Ptraits::Degree Degree; typedef typename Ptraits::Differentiate Deriv; CGAL::Uncertain unknown= Uncertain::indeterminate(); CGAL::Uncertain s=eval_interv(p, x.get_left(), x.get_right()); if(!s.is_same(unknown)) return (s==CGAL::ZERO); // We are not sure about the sign. We calculate the gcd in // order to know if both polynomials have common roots. Polynomial_1 sfpp=Sfpart()(p); Polynomial_1 gcd=Gcd()(sfpp,Sfpart()(x.get_pol())); if(Degree()(gcd)==0) return false; // At this point, gcd is not 1; we proceed as follows: // -we refine x until having p monotonic in x's interval (to be // sure that p has at most one root on that interval), // -if the gcd has a root on this interval, both roots are // equal (we return 0), otherwise, we refine until having a // result. // How to assure that p is monotonic in an interval: when its // derivative is never zero in that interval. Polynomial_1 dsfpp=Deriv()(sfpp); CGAL::Gmpfr xl(x.get_left()); CGAL::Gmpfr xr(x.get_right()); while(eval_interv(dsfpp,xl,xr).is_same(unknown)){ Refiner()(x.get_pol(), xl, xr, 2*CGAL::max(xl.get_precision(), xr.get_precision())); } x.set_left(xl); x.set_right(xr); // How to know that the gcd has a root: evaluate endpoints. CGAL::Sign sleft,sright; Signat sign_at_gcd(gcd); return((sleft=sign_at_gcd(x.get_left()))==CGAL::ZERO|| (sright=sign_at_gcd(x.get_right()))==CGAL::ZERO|| (sleft!=sright)); } }; // class Is_zero_at_1 // TODO: it says in the manual that this should return a size_type, but test // programs assume that this is equal to int template struct Number_of_solutions_1: public CGAL::cpp98::unary_function{ typedef Polynomial_ Polynomial_1; typedef Isolator_ Isolator; size_t operator()(const Polynomial_1 &p)const{ // TODO: make sure that p is square free (precondition) Isolator isol(p); return isol.number_of_real_roots(); } }; // struct Number_of_solutions_1 // This functor not only compares two algebraic numbers. In case they are // different, it refines them until they do not overlap. template struct Compare_1: public CGAL::cpp98::binary_function{ typedef Algebraic_ Algebraic; typedef Bound_ Bound; typedef Comparator_ Comparator; CGAL::Comparison_result operator()(Algebraic a,Algebraic b)const{ Bound al=a.get_left(); Bound ar=a.get_right(); Bound bl=b.get_left(); Bound br=b.get_right(); CGAL::Comparison_result c=Comparator()(a.get_pol(),al,ar, b.get_pol(),bl,br); a.set_left(al); a.set_right(ar); b.set_left(bl); b.set_right(br); return c; } CGAL::Comparison_result operator()(Algebraic a,const Bound &b)const{ Bound al=a.get_left(); Bound ar=a.get_right(); Algebraic balg(b); CGAL::Comparison_result c=Comparator()(a.get_pol(),al,ar, balg.get_pol(),b,b); a.set_left(al); a.set_right(ar); return c; } template CGAL::Comparison_result operator()(Algebraic a,const T &b)const{ Bound al=a.get_left(); Bound ar=a.get_right(); Algebraic balg(b); CGAL::Comparison_result c=Comparator()(a.get_pol(), al, ar, balg.get_pol(), balg.get_left(), balg.get_right()); a.set_left(al); a.set_right(ar); return c; } }; // class Compare_1 template struct Bound_between_1: public CGAL::cpp98::binary_function{ typedef Algebraic_ Algebraic; typedef Bound_ Bound; typedef Comparator_ Comparator; Bound operator()(Algebraic a,Algebraic b)const{ typedef Compare_1 Compare; typename Bound::Precision_type prec; switch(Compare()(a,b)){ case CGAL::LARGER: CGAL_assertion(b.get_right() struct Isolate_1: public CGAL::cpp98::binary_function >{ typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Isolator_ Isolator; typedef Comparator_ Comparator; typedef Signat_ Signat; typedef Ptraits_ Ptraits; std::pair operator()(const Algebraic &a,const Polynomial_1 &p)const{ std::vector roots; std::back_insert_iterator > rit(roots); typedef Solve_1 Solve; typedef Compare_1 Compare; Solve()(p,false,rit); for(typename std::vector::size_type i=0; i struct Approximate_absolute_1: public CGAL::cpp98::binary_function >{ typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Refiner_ Refiner; // This implementation assumes that Bound is Gmpfr. // TODO: make generic. std::pair operator()(const Algebraic &x,const int &a)const{ Bound xl(x.get_left()),xr(x.get_right()); // refsteps=log2(xl-xr) mpfr_t temp; mpfr_init(temp); mpfr_sub(temp,xr.fr(),xl.fr(),GMP_RNDU); mpfr_log2(temp,temp,GMP_RNDU); long refsteps=mpfr_get_si(temp,GMP_RNDU); mpfr_clear(temp); Refiner()(x.get_pol(),xl,xr,CGAL::abs(refsteps+a)); x.set_left(xl); x.set_right(xr); CGAL_assertion(a>0? (xr-xl)*CGAL::ipower(Bound(2),a)<=Bound(1): (xr-xl)<=CGAL::ipower(Bound(2),-a)); return std::make_pair(xl,xr); } }; // struct Approximate_absolute_1 template struct Approximate_relative_1: public CGAL::cpp98::binary_function >{ typedef Polynomial_ Polynomial_1; typedef Bound_ Bound; typedef Algebraic_ Algebraic; typedef Refiner_ Refiner; std::pair operator()(const Algebraic &x,const int &a)const{ if(CGAL::is_zero(x)) return std::make_pair(Bound(0),Bound(0)); Bound error=CGAL::ipower(Bound(2),CGAL::abs(a)); Bound xl(x.get_left()),xr(x.get_right()); Bound max_b=(CGAL::max)(CGAL::abs(xr),CGAL::abs(xl)); while(a>0?(xr-xl)*error>max_b:(xr-xl)>error*max_b){ Refiner()(x.get_pol(), xl, xr, std::max( CGAL::abs(a), CGAL::max(xl.get_precision(), xr.get_precision()))); max_b=(CGAL::max)(CGAL::abs(xr),CGAL::abs(xl)); } x.set_left(xl); x.set_right(xr); CGAL_assertion( a>0? (xr-xl)*CGAL::ipower(Bound(2),a)<=max_b: (xr-xl)<=CGAL::ipower(Bound(2),-a)*max_b); return std::make_pair(xl,xr); } }; // struct Approximate_relative_1 } // namespace RS_AK1 } // namespace CGAL #endif // CGAL_RS_FUNCTORS_1_H