GiNaCRA  0.6.4
operators.cpp
Go to the documentation of this file.
00001 /*
00002  * GiNaCRA - GiNaC Real Algebra package
00003  * Copyright (C) 2010-2012  Ulrich Loup, Joachim Redies, Sebastian Junges
00004  *
00005  * This file is part of GiNaCRA.
00006  *
00007  * GiNaCRA is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation, either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * GiNaCRA is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GiNaCRA.  If not, see <http://www.gnu.org/licenses/>.
00019  *
00020  */
00021 
00022 
00033 #include <assert.h>
00034 
00035 #include "OpenInterval.h"
00036 #include "RealAlgebraicNumber.h"
00037 #include "RealAlgebraicNumberIR.h"
00038 #include "RealAlgebraicNumberNR.h"
00039 #include "RealAlgebraicNumberFactory.h"
00040 #include "UnivariatePolynomial.h"
00041 #include "UnivariatePolynomialSet.h"
00042 #include "Constraint.h"
00043 
00044 using GiNaC::ex_to;
00045 using GiNaC::is_exactly_a;
00046 using GiNaC::ZERO_SIGN;
00047 using GiNaC::POSITIVE_SIGN;
00048 using GiNaC::NEGATIVE_SIGN;
00049 
00050 namespace GiNaCRA
00051 {
00053     // Common //
00055 
00056     const GiNaC::numeric abs( const ex& lh )
00057     {
00058         if( GiNaC::is_exactly_a<numeric>( lh ))
00059             return GiNaC::abs( ex_to<numeric>( lh ));
00060         if( GiNaC::is_a<RealAlgebraicNumberIR>( lh ))
00061             return std::max<GiNaC::numeric>( GiNaC::abs( GiNaC::ex_to<RealAlgebraicNumberIR>( lh ).interval().left() ),
00062                                         GiNaC::abs( GiNaC::ex_to<RealAlgebraicNumberIR>( lh ).interval().right() ));
00063         return 0;
00064     }
00065 
00067     // OpenInterval //
00069 
00070     // binary arithmetic operators of OpenInterval
00071 
00072     const OpenInterval operator +( const OpenInterval& lh, const OpenInterval& rh )
00073     {
00074         return lh.add( rh );
00075     }
00076 
00077     const OpenInterval operator -( const OpenInterval& lh, const OpenInterval& rh )
00078     {
00079         return lh.add( rh.minus() );
00080     }
00081 
00082     const OpenInterval operator *( const OpenInterval& lh, const OpenInterval& rh )
00083     {
00084         return lh.mul( rh );
00085     }
00086 
00087     // unary arithmetic operators of OpenInterval
00088 
00089     const OpenInterval operator -( const OpenInterval& lh )
00090     {
00091         return lh.minus();
00092     }
00093 
00094     // relational operators
00095 
00096     const bool operator ==( const OpenInterval& lh, const OpenInterval& rh )
00097     {
00098         return lh.isEqual( rh );
00099     }
00100 
00101     const bool operator !=( const OpenInterval& lh, const OpenInterval& rh )
00102     {
00103         return !lh.isEqual( rh );
00104     }
00105 
00106     const bool operator <=( const OpenInterval& lh, const OpenInterval& rh )
00107     {
00108         return lh.isLess( rh );
00109     }
00110 
00111     const bool operator >=( const OpenInterval& lh, const OpenInterval& rh )
00112     {
00113         return lh.isGreater( rh );
00114     }
00115 
00116     // mixed arithmetic operators
00117 
00118     const OpenInterval operator +( const OpenInterval& lh, const GiNaC::numeric& rh )
00119     {
00120         return OpenInterval( lh.left() + rh, lh.right() + rh );
00121     }
00122 
00123     const OpenInterval operator +( const GiNaC::numeric& lh, const OpenInterval& rh )
00124     {
00125         return OpenInterval( rh.left() + lh, rh.right() + lh );
00126     }
00127 
00128     const OpenInterval operator -( const OpenInterval& lh, const GiNaC::numeric& rh )
00129     {
00130         return lh + (-rh);
00131     }
00132 
00133     const OpenInterval operator -( const GiNaC::numeric& lh, const OpenInterval& rh )
00134     {
00135         return (-lh) + rh;
00136     }
00137 
00138     const OpenInterval operator *( const OpenInterval& lh, const GiNaC::numeric& rh )
00139     {
00140         numeric l   = lh.left() * rh;
00141         numeric r   = lh.right() * rh;
00142         numeric min = std::min<numeric>( l, r );
00143         numeric max = std::max<numeric>( l, r );
00144         return OpenInterval( min, max );
00145     }
00146 
00147     const OpenInterval operator *( const GiNaC::numeric& lh, const OpenInterval& rh )
00148     {
00149         return rh * lh;
00150     }
00151 
00152     const OpenInterval operator /( const OpenInterval& lh, const GiNaC::numeric& rh ) throw ( overflow_error )
00153     {
00154         if( rh == 0 )
00155             throw (overflow_error( "Division by interval containing zero not allowed." ));
00156         numeric l   = lh.left() / rh;
00157         numeric r   = lh.right() / rh;
00158         numeric min = std::min<numeric>( l, r );
00159         numeric max = std::max<numeric>( l, r );
00160         return OpenInterval( min, max );
00161     }
00162 
00163     const OpenInterval operator /( const GiNaC::numeric& lh, const OpenInterval& rh ) throw ( overflow_error )
00164     {
00165         if( rh.contains( 0 ))
00166             throw (overflow_error( "Division by interval containing zero not allowed." ));
00167         numeric l   = lh / rh.left();
00168         numeric r   = lh / rh.right();
00169         numeric min = std::min<numeric>( l, r );
00170         numeric max = std::max<numeric>( l, r );
00171         return OpenInterval( min, max );
00172     }
00173 
00175     // UnivariatePolynomial //
00177 
00178     // binary arithmetic operators of UnivariatePolynomial
00179 
00180     const UnivariatePolynomial operator +( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00181     {
00182         return lh.add( rh );
00183     }
00184 
00185     const UnivariatePolynomial operator -( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00186     {
00187         return lh.sub( rh );
00188     }
00189 
00190     const UnivariatePolynomial operator *( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00191     {
00192         return lh.mul( rh );
00193     }
00194 
00195     const UnivariatePolynomial operator /( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00196     {
00197         return lh.quo( rh );
00198     }
00199 
00200     const UnivariatePolynomial operator %( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00201     {
00202         return lh.rem( rh );
00203     }
00204 
00205     // binary arithmetic operators of RationalUnivariatePolynomial
00206 
00207     const RationalUnivariatePolynomial operator +( const RationalUnivariatePolynomial& lh, const RationalUnivariatePolynomial& rh )
00208     {
00209         return RationalUnivariatePolynomial( static_cast<ex>(lh)+static_cast<ex>(rh), lh.variable() );
00210     }
00211 
00212     const RationalUnivariatePolynomial operator -( const RationalUnivariatePolynomial& lh, const RationalUnivariatePolynomial& rh )
00213     {
00214         return RationalUnivariatePolynomial( static_cast<ex>(lh)-static_cast<ex>(rh), lh.variable() );
00215     }
00216 
00217     const RationalUnivariatePolynomial operator *( const RationalUnivariatePolynomial& lh, const RationalUnivariatePolynomial& rh )
00218     {
00219         return RationalUnivariatePolynomial( static_cast<ex>(lh)*static_cast<ex>(rh), lh.variable() );
00220     }
00221 
00222     const RationalUnivariatePolynomial operator /( const RationalUnivariatePolynomial& lh, const RationalUnivariatePolynomial& rh )
00223     {
00224         return lh.quo( rh );
00225     }
00226 
00227     const RationalUnivariatePolynomial operator %( const RationalUnivariatePolynomial& lh, const RationalUnivariatePolynomial& rh )
00228     {
00229         return lh.rem( rh );
00230         //    return RationalUnivariatePolynomial( GiNaC::rem( *this, o, mVariable ), mVariable );
00231     }
00232 
00233     // unary arithmetic operators of UnivariatePolynomial
00234 
00235     const UnivariatePolynomial operator -( const UnivariatePolynomial& lh )
00236     {
00237         return UnivariatePolynomial( -static_cast<ex>(lh), lh.variable(), lh.enabledPolynomialCheck() );
00238     }
00239 
00240     const RationalUnivariatePolynomial operator -( const RationalUnivariatePolynomial& lh )
00241     {
00242         return RationalUnivariatePolynomial( -static_cast<ex>(lh), lh.variable() );
00243     }
00244 
00245     // relational operators of UnivariatePolynomial
00246 
00247     const bool operator ==( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00248     {
00249         return lh.isEqual( rh );
00250     }
00251 
00252     const bool operator !=( const UnivariatePolynomial& lh, const UnivariatePolynomial& rh )
00253     {
00254         return !lh.isEqual( rh );
00255     }
00256 
00258     // UnivariatePolynomialSet //
00260 
00261     std::ostream& operator <<( std::ostream& os, const UnivariatePolynomialSet& s )
00262     {
00263         os << "{";
00264         for( UnivariatePolynomialSet::const_iterator i = s.begin(); i != s.end(); ++i )
00265             os << " " << static_cast<UnivariatePolynomial>(*i);
00266         os << " }";
00267         return os;
00268     }
00269 
00271     // RealAlgebraicNumberIR //
00273 
00274     // binary arithmetic operators
00275 
00276     RealAlgebraicNumberIR& operator +( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00277     {
00278         return lh.add( rh );
00279     }
00280 
00281     RealAlgebraicNumberIR& operator -( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00282     {
00283         RealAlgebraicNumberIR rhMinus = rh.minus();
00284         return lh.add( rhMinus );
00285     }
00286 
00287     RealAlgebraicNumberIR& operator *( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00288     {
00289         return lh.mul( rh );
00290     }
00291 
00292     RealAlgebraicNumberIR& operator /( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00293     {
00294         RealAlgebraicNumberIR rhInverse = rh.inverse();
00295         return lh.mul( rhInverse );
00296     }
00297 
00298     RealAlgebraicNumberIR& operator ^( RealAlgebraicNumberIR& base, int exponent )
00299     {
00300         return base.pow( exponent );
00301     }
00302 
00303     // unary arithmetic operators
00304 
00305     RealAlgebraicNumberIR& operator -( RealAlgebraicNumberIR& lh )
00306     {
00307         return lh.minus();
00308     }
00309 
00310     // relational operators
00311 
00312     const bool operator ==( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00313     {
00314         return lh.isEqual( rh );
00315     }
00316 
00317     const bool operator ==( const RealAlgebraicNumberIR& lh, const RealAlgebraicNumberIR& rh )
00318     {
00319         RealAlgebraicNumberIR lhRef = lh;
00320         RealAlgebraicNumberIR rhRef = rh;
00321         return lhRef.isEqual( rhRef );
00322     }
00323 
00324     const bool operator !=( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00325     {
00326         return !lh.isEqual( rh );
00327     }
00328 
00329     const bool operator <( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00330     {
00331         return lh.isLess( rh );
00332     }
00333 
00334     const bool operator >( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00335     {
00336         return !lh.isEqual( rh ) &&!lh.isLessWhileUnequal( rh );
00337     }
00338 
00339     const bool operator <=( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00340     {
00341         return lh.isEqual( rh ) || lh.isLessWhileUnequal( rh );
00342     }
00343 
00344     const bool operator >=( RealAlgebraicNumberIR& lh, RealAlgebraicNumberIR& rh )
00345     {
00346         return !lh.isLess( rh );
00347     }
00348 
00349     // mixed arithmetic operators
00350 
00351     RealAlgebraicNumberIR& operator +( const GiNaC::numeric& lh, RealAlgebraicNumberIR& rh )
00352     {
00353         RationalUnivariatePolynomial p( rh.polynomial().subs( rh.polynomial().variable() == (rh.polynomial().variable() - lh) ),
00354                                         rh.polynomial().variable() );
00355         while( RationalUnivariatePolynomial::countRealRoots( p, rh.interval() + lh ) != 1 )    // refine rh until a unique number representation is found
00356             rh.refine();
00357         return *new RealAlgebraicNumberIR( p, rh.interval() + lh );
00358     }
00359 
00360     RealAlgebraicNumberIR& operator +( RealAlgebraicNumberIR& lh, const GiNaC::numeric& rh )
00361     {
00362         RationalUnivariatePolynomial p( lh.polynomial().subs( lh.polynomial().variable() == (lh.polynomial().variable() - rh) ),
00363                                         lh.polynomial().variable() );
00364         while( RationalUnivariatePolynomial::countRealRoots( p, rh + lh.interval() ) != 1 )    // refine rh until a unique number representation is found
00365             lh.refine();
00366         return *new RealAlgebraicNumberIR( p, rh + lh.interval() );
00367     }
00368 
00369     RealAlgebraicNumberIR& operator -( const GiNaC::numeric& lh, RealAlgebraicNumberIR& rh )
00370     {
00371         RationalUnivariatePolynomial p( rh.polynomial().subs( rh.polynomial().variable() == (rh.polynomial().variable() + lh) ),
00372                                         rh.polynomial().variable() );
00373         while( RationalUnivariatePolynomial::countRealRoots( p, rh.interval() - lh ) != 1 )    // refine rh until a unique number representation is found
00374             rh.refine();
00375         return *new RealAlgebraicNumberIR( p, rh.interval() - lh );
00376     }
00377 
00378     RealAlgebraicNumberIR& operator -( RealAlgebraicNumberIR& lh, const GiNaC::numeric& rh )
00379     {
00380         RationalUnivariatePolynomial p( lh.polynomial().subs( lh.polynomial().variable() == (lh.polynomial().variable() + rh) ),
00381                                         lh.polynomial().variable() );
00382         while( RationalUnivariatePolynomial::countRealRoots( p, rh - lh.interval() ) != 1 )    // refine rh until a unique number representation is found
00383             lh.refine();
00384         return *new RealAlgebraicNumberIR( p, rh - lh.interval() );
00385     }
00386 
00387     RealAlgebraicNumberIR& operator *( const GiNaC::numeric& lh, RealAlgebraicNumberIR& rh )
00388     {
00389         if( lh == 0 )
00390             return *RealAlgebraicNumberIR::zero( rh.polynomial().variable() );
00391         RationalUnivariatePolynomial p( rh.polynomial().subs( rh.polynomial().variable() == (rh.polynomial().variable() * lh.inverse())),
00392                                         rh.polynomial().variable() );
00393         while( RationalUnivariatePolynomial::countRealRoots( p, rh.interval() * lh ) != 1 )    // refine rh until a unique number representation is found
00394             rh.refine();
00395         return *new RealAlgebraicNumberIR( p, rh.interval() * lh );
00396     }
00397 
00398     RealAlgebraicNumberIR& operator *( RealAlgebraicNumberIR& lh, const GiNaC::numeric& rh )
00399     {
00400         if( rh == 0 )
00401             return *RealAlgebraicNumberIR::zero( lh.polynomial().variable() );
00402         RationalUnivariatePolynomial p( lh.polynomial().subs( lh.polynomial().variable() == (lh.polynomial().variable() * rh.inverse())),
00403                                         lh.polynomial().variable() );
00404         while( RationalUnivariatePolynomial::countRealRoots( p, rh * lh.interval() ) != 1 )    // refine rh until a unique number representation is found
00405             lh.refine();
00406         return *new RealAlgebraicNumberIR( p, rh * lh.interval() );
00407     }
00408 
00409     RealAlgebraicNumberIR& operator /( const GiNaC::numeric& lh, RealAlgebraicNumberIR& rh )
00410     {
00411         return lh * rh.inverse();
00412     }
00413 
00414     RealAlgebraicNumberIR& operator /( RealAlgebraicNumberIR& lh, const GiNaC::numeric& rh )
00415     {
00416         return lh * rh.inverse();
00417     }
00418 
00420     // RealAlgebraicNumber //
00422 
00423     // basic operator
00424 
00425     RealAlgebraicNumberPtr binaryOperator( const RealAlgebraicNumberPtr& lh, const RealAlgebraicNumberPtr& rh, RealAlgebraicNumberIR&( *opIRIR )( RealAlgebraicNumberIR&, RealAlgebraicNumberIR& ), RealAlgebraicNumberIR&( *opIRNR )( RealAlgebraicNumberIR&, const numeric&), const numeric( *opNRNR )(const numeric&, const numeric&) )
00426     {
00427         RealAlgebraicNumberIRPtr lhIR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberIR>( lh );
00428         RealAlgebraicNumberIRPtr rhIR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberIR>( rh );
00429         if( lhIR == 0 )
00430         {
00431             RealAlgebraicNumberNRPtr lhNR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( lh );
00432             if( rhIR == 0 )
00433             {
00434                 RealAlgebraicNumberNRPtr rhNR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( rh );
00435                 return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( (*opNRNR)( *lhNR, *rhNR )));
00436             }
00437             else
00438             {
00439                 RealAlgebraicNumberIR sum = (*opIRNR)( *rhIR, *lhNR );
00440                 if( sum.isNumeric() )
00441                     return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( sum.value() ));
00442                 return RealAlgebraicNumberPtr( new RealAlgebraicNumberIR( sum ));
00443             }
00444         }
00445         if( rhIR == 0 )
00446         {
00447             RealAlgebraicNumberNRPtr rhNR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( rh );
00448             RealAlgebraicNumberIR sum     = (*opIRNR)( *lhIR, *rhNR );
00449             if( sum.isNumeric() )
00450                 return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( sum.value() ));
00451             return RealAlgebraicNumberPtr( new RealAlgebraicNumberIR( sum ));
00452         }
00453         else
00454         {
00455             RealAlgebraicNumberIR sum = (*opIRIR)( *lhIR, *rhIR );
00456             if( sum.isNumeric() )
00457                 return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( sum.value() ));
00458             return RealAlgebraicNumberPtr( new RealAlgebraicNumberIR( sum ));
00459         }
00460     }
00461 
00462     // binary arithmetic operators
00463 
00464     RealAlgebraicNumberPtr operator +( const RealAlgebraicNumberPtr& lh, const RealAlgebraicNumberPtr& rh )
00465     {
00466         return binaryOperator( lh, rh, operator +, operator +, GiNaC::operator + );
00467     }
00468 
00469     RealAlgebraicNumberPtr operator -( const RealAlgebraicNumberPtr& lh, const RealAlgebraicNumberPtr& rh )
00470     {
00471         return binaryOperator( lh, -rh, operator +, operator +, GiNaC::operator + );
00472     }
00473 
00474     RealAlgebraicNumberPtr operator *( const RealAlgebraicNumberPtr& lh, const RealAlgebraicNumberPtr& rh )
00475     {
00476         return binaryOperator( lh, rh, operator *, operator *, GiNaC::operator * );
00477     }
00478 
00479     RealAlgebraicNumberPtr operator /( const RealAlgebraicNumberPtr& lh, const RealAlgebraicNumberPtr& rh )
00480     {
00481         return binaryOperator( lh, rh, operator /, operator /, GiNaC::operator / );
00482     }
00483 
00484     RealAlgebraicNumberPtr operator ^( const RealAlgebraicNumberPtr& base, int exponent )
00485     {
00486         RealAlgebraicNumberIRPtr baseIR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberIR>( base );
00487         if( baseIR == 0 )
00488             return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR(
00489                 std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( base )->power( exponent )));
00490         if( baseIR->isNumeric() )
00491             return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( baseIR->value().power( exponent )));
00492         return RealAlgebraicNumberPtr( new RealAlgebraicNumberIR( baseIR->pow( exponent )));
00493     }
00494 
00495     // unary arithmetic operators
00496 
00497     RealAlgebraicNumberPtr operator -( const RealAlgebraicNumberPtr& lh )
00498     {
00499         RealAlgebraicNumberIRPtr lhIR = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberIR>( lh );
00500         if( lhIR == 0 )
00501             return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( -*std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( lh )));
00502         if( lhIR->isNumeric() )
00503             return RealAlgebraicNumberPtr( new RealAlgebraicNumberNR( -lhIR->value() ));
00504         return RealAlgebraicNumberPtr( new RealAlgebraicNumberIR( -*lhIR ));
00505     }
00506 
00507     // relational operators
00508 
00509     const bool operator ==( const RealAlgebraicNumberPtr& a, const RealAlgebraicNumberPtr& b )
00510     {
00511         return RealAlgebraicNumberFactory::equal( a, b );
00512     }
00513 
00514     const bool operator !=( const RealAlgebraicNumberPtr& a, const RealAlgebraicNumberPtr& b )
00515     {
00516         return !RealAlgebraicNumberFactory::equal( a, b );
00517     }
00518 
00519     const bool operator <( const RealAlgebraicNumberPtr& a, const RealAlgebraicNumberPtr& b )
00520     {
00521         return RealAlgebraicNumberFactory::less( a, b );
00522     }
00523 
00524     std::ostream& operator <<( std::ostream& os, const RealAlgebraicNumberPtr& a )
00525     {
00526         print( a, os );
00527         return os;
00528     }
00529 
00530     // workaround until operator<< works
00531 
00532     void print( const RealAlgebraicNumberPtr& a, std::ostream& os )
00533     {
00534         RealAlgebraicNumberIRPtr irA = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberIR>( a );
00535         RealAlgebraicNumberNRPtr nrA = std::tr1::dynamic_pointer_cast<RealAlgebraicNumberNR>( a );
00536         if( irA != 0 )
00537             std::cout << *irA;
00538         else if( nrA != 0 )
00539             std::cout << static_cast<RealAlgebraicNumberNR>(*nrA);
00540 
00541         else
00542             std::cout << "NaN";
00543         //        assert( false ); // This case should never occur! If it still occurs, there might be a segfault somewhere.
00544     }
00545 
00547     // RealAlgebraicPoint //
00549 
00550     std::ostream& operator <<( std::ostream& os, const RealAlgebraicPoint& r )
00551     {
00552         os << "(";
00553         for( RealAlgebraicPoint::const_iterator i = r.begin(); i != r.end(); ++i )
00554             print( *i, os << " " );
00555         os << " )";
00556         return os;
00557     }
00558 
00560     // Constraint //
00562 
00563     // relational operators
00564 
00565     const bool operator ==( const Constraint& a, const Constraint& b )
00566     {
00567         return a.poly() == b.poly() && a.sign() == b.sign();    // Vriables do not need to be checked since they are uniquely defined in GiNaC and therefore checked by the ex check.
00568     }
00569 
00570     // streaming operators
00571 
00572     std::ostream& operator <<( std::ostream& os, const Constraint& a )
00573     {
00574         GiNaC::sign s = a.sign();
00575         os << a.poly() << (s == ZERO_SIGN ? " = 0" : s == POSITIVE_SIGN ? " > 0" : " < 0");
00576         vector<symbol> variables = a.variables();
00577         os << "(" << variables.front();
00578         for( unsigned i = 1; i != variables.size(); ++i )
00579             os << ", " << variables[i];
00580         return os << ")";
00581     }
00582 
00583 }    // namespace GiNaC
00584