GiNaCRA  0.6.4
MultivariatePolynomialMR.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 
00023 #include <list>
00024 #include <assert.h>
00025 #include <stdexcept>
00026 #include <locale>
00027 #include <vector>
00028 
00029 #include "MultivariatePolynomialMR.h"
00030 #include "MultivariateTermMR.h"
00031 #include "VariableListPool.h"
00032 
00033 using GiNaC::ex;
00034 using GiNaC::add;
00035 using GiNaC::const_iterator;
00036 using GiNaC::is_exactly_a;
00037 
00038 namespace GiNaCRA
00039 {
00040     bool operator !=( const MonomMRCompare& m1, const MonomMRCompare& m2 )
00041     {
00042         return m1.GetMonomOrdering() != m2.GetMonomOrdering();
00043     }
00044 
00045     MultivariatePolynomialMR::MultivariatePolynomialMR():
00046         mCmp(),
00047         mTerms()    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00048     {}
00049 
00050     MultivariatePolynomialMR::MultivariatePolynomialMR( const MonomMRCompare& comp ):
00051         mCmp( comp ),
00052         mTerms( comp )    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00053     {}
00054 
00055     MultivariatePolynomialMR::MultivariatePolynomialMR( const MultivariateTermMR& t1, const MonomMRCompare& comp ):
00056         mCmp( comp ),
00057         mTerms( mCmp )    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00058     {
00059         mTerms.insert( t1 );
00060     }
00061 
00062     MultivariatePolynomialMR::MultivariatePolynomialMR( const MultivariateTermMR& t1, const MultivariateTermMR& t2, const MonomMRCompare& comp ):
00063         mCmp( comp ),
00064         mTerms( mCmp )    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00065     {
00066         mTerms.insert( t1 );
00067         mTerms.insert( t2 );
00068     }
00069 
00070     MultivariatePolynomialMR::MultivariatePolynomialMR( sMT_It begin, sMT_It last, const MonomMRCompare& comp ):
00071         mCmp( comp ),
00072         mTerms( begin, last, comp )    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00073     {}
00074 
00075     MultivariatePolynomialMR::MultivariatePolynomialMR( sMT_It begin1, sMT_It last1, sMT_It begin2, sMT_It last2, const MonomMRCompare& comp ):
00076         mCmp( comp ),
00077         mTerms( comp )    /* , mpVarList(VariableListPool::getPtToStdVarList()), mpParList(VariableListPool::getPtToStdParList()) */
00078     {
00079         sMT_It inputIt       = mTerms.begin();
00080         MonomOrderingFc less = mCmp.GetMonomOrdering();
00081         while( begin1 != last1 )
00082         {
00083             if( begin2 == last2 )
00084             {
00085                 mTerms.insert( begin1, last1 );
00086             }
00087             if( less( *begin1, *begin2 ))
00088             {
00089                 inputIt = mTerms.insert( inputIt, *begin1 );
00090                 ++begin1;
00091                 continue;
00092             }    // else if
00093             if( less( *begin1, *begin2 ))
00094             {
00095                 inputIt = mTerms.insert( inputIt, *begin2 );
00096                 ++begin2;
00097                 continue;
00098             }    // else (equal)
00099             inputIt = mTerms.insert( inputIt, MultivariateTermMR( *begin1, begin1->getCoeffExpr() + begin2->getCoeffExpr() ));
00100             ++begin1;
00101             ++begin2;
00102         }
00103         mTerms.insert( begin2, last2 );
00104     }
00105 
00106     MultivariatePolynomialMR::MultivariatePolynomialMR( const GiNaC::ex& expr, const MonomMRCompare& cmp ):
00107         mCmp( cmp ),
00108         mTerms( cmp )
00109     {
00110         ex expression = expr.expand();
00111         GiNaC::lst          list = GiNaC::lst();
00112         std::vector<symbol> vars = VariableListPool::getVariables();
00113         for( std::vector<symbol>::const_iterator it = vars.begin(); it != vars.end(); ++it )
00114         {
00115             list.append( *it );
00116         }
00117         if( !expression.is_polynomial( list ))
00118             throw std::invalid_argument( "Argument is not a polynomial" );
00119         if( is_exactly_a<GiNaC::add>( expression ))    // GiNaC::add because of overriding the name "add" by the current function
00120         {
00121             for( const_iterator i = expression.begin(); i != expression.end(); ++i )    // iterate through the summands
00122             {
00123                 if( GiNaC::is_constant( *i, vars ))
00124                 {    // polynomial is constant in the current list of variables, so is a coefficient with the 1 monomial
00125                     mTerms.insert( MultivariateTermMR( *i ));
00126                 }
00127                 else if( GiNaC::is_exactly_a<GiNaC::mul>( *i ))    // GiNaC::mul because of overriding the name "mul" by the current function
00128                 {    // polynomial is just a product
00129                     GiNaC::ex                                   coeff = GiNaC::ex( 1 );
00130 
00131                     std::vector<std::pair<unsigned, unsigned> > mon   = std::vector<std::pair<unsigned, unsigned> >();
00132                     for( const_iterator j = i->begin(); j != i->end(); ++j )    // iterate through the possible powers
00133                     {
00134                         std::vector<symbol>::const_iterator s   = vars.begin();
00135                         unsigned                            ind = 0;
00136                         for( ; s != vars.end(); ++s )    // only tak)e symbols given in the list (all other things are coefficient)
00137                         {
00138                             if( j->degree( *s ) > 0 )
00139                             {
00140                                 mon.push_back( std::pair<unsigned, unsigned>( ind, j->degree( *s )));
00141                                 break;
00142                             }
00143                             ++ind;
00144                         }
00145                         if( s == vars.end() )
00146                         {    // current power is not build upon a variable, so it belongs to the coefficient
00147                             coeff = coeff * *j;
00148                             break;
00149                         }
00150                     }
00151                     mTerms.insert( MultivariateTermMR( MultivariateMonomialMR( mon.begin(), mon.end() ), coeff ));
00152                 }
00153                 else if( GiNaC::is_exactly_a<GiNaC::power>( *i ) || GiNaC::is_exactly_a<symbol>( *i ))
00154                 {
00155                     std::vector<symbol>::const_iterator s   = vars.begin();
00156                     unsigned                            ind = 0;
00157                     for( ; s != vars.end(); ++s )    // only take symbols given in the list (all other things are coefficient)
00158                     {
00159                         if( i->degree( *s ) > 0 )
00160                         {
00161                             mTerms.insert( MultivariateTermMR( MultivariateMonomialMR( ind, (unsigned)(i->degree( *s )))));
00162                             break;
00163                         }
00164                         ++ind;
00165                     }
00166                     if( s == vars.end() )
00167                     {
00168                         mTerms.insert( MultivariateTermMR( *i ));
00169                     }
00170                 }
00171                 else if( is_exactly_a<numeric>( *i ))
00172                     mTerms.insert( MultivariateTermMR( *i ));
00173 
00174                 else if( i->is_zero() )
00175                     ;
00176             }
00177 
00178         }
00179         else
00180         {
00181             if( GiNaC::is_constant( expr, vars ))
00182             {    // polynomial is constant in the current list of variables, so is a coefficient with the 1 monomial
00183                 mTerms.insert( MultivariateTermMR( expr ));
00184             }
00185             else if( GiNaC::is_exactly_a<GiNaC::mul>( expr ))    // GiNaC::mul because of overriding the name "mul" by the current function
00186             {    // polynomial is just a product
00187                 GiNaC::ex                                   coeff = GiNaC::ex( 1 );
00188 
00189                 std::vector<std::pair<unsigned, unsigned> > mon   = std::vector<std::pair<unsigned, unsigned> >();
00190                 for( const_iterator j = expr.begin(); j != expr.end(); ++j )    // iterate through the possible powers
00191                 {
00192                     std::vector<symbol>::const_iterator s   = vars.begin();
00193                     unsigned                            ind = 0;
00194                     for( ; s != vars.end(); ++s )    // only tak)e symbols given in the list (all other things are coefficient)
00195                     {
00196                         if( j->degree( *s ) > 0 )
00197                         {
00198                             mon.push_back( std::pair<unsigned, unsigned>( ind, j->degree( *s )));
00199                             break;
00200                         }
00201                         ++ind;
00202                     }
00203                     if( s == vars.end() )
00204                     {    // current power is not build upon a variable, so it belongs to the coefficient
00205                         coeff = coeff * *j;
00206                         break;
00207                     }
00208                 }
00209                 mTerms.insert( MultivariateTermMR( MultivariateMonomialMR( mon.begin(), mon.end() ), coeff ));
00210             }
00211             else if( GiNaC::is_exactly_a<GiNaC::power>( expr ) || GiNaC::is_exactly_a<symbol>( expr ))
00212             {
00213                 std::vector<symbol>::const_iterator s   = vars.begin();
00214                 unsigned                            ind = 0;
00215                 for( ; s != vars.end(); ++s )    // only take symbols given in the list (all other things are coefficient)
00216                 {
00217                     if( expr.degree( *s ) > 0 )
00218                     {
00219                         mTerms.insert( MultivariateTermMR( MultivariateMonomialMR( ind, (unsigned)(expr.degree( *s )))));
00220                         break;
00221                     }
00222                     ++ind;
00223                 }
00224                 if( s == vars.end() )
00225                 {
00226                     mTerms.insert( MultivariateTermMR( expr ));
00227                 }
00228             }
00229             else if( is_exactly_a<numeric>( expr ))
00230                 mTerms.insert( MultivariateTermMR( expr ));
00231 
00232             else if( expr.is_zero() )
00233                 ;
00234         }
00235 
00236         //if(expr.is_polynomial())
00237     }
00238 
00239     GiNaC::ex MultivariatePolynomialMR::toEx() const
00240     {
00241         GiNaC::ex expr = GiNaC::ex( 0 );
00242         for( sMT_cIt it = mTerms.begin(); it != mTerms.end(); ++it )
00243         {
00244             expr += it->toEx();
00245         }
00246         return expr;
00247     }
00248 
00249     bool operator ==( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00250     {
00251         //TODO what to do with different ordering?!
00252         if( p1.mTerms.size() != p2.mTerms.size() )
00253             return false;
00254         return std::equal( p1.mTerms.begin(), p1.mTerms.end(), p2.mTerms.begin() );
00255     }
00256 
00257     bool operator !=( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00258     {
00259         //TODO what to do with different ordering?!
00260         if( p1.mTerms.size() != p2.mTerms.size() )
00261             return true;
00262         return !std::equal( p1.mTerms.begin(), p1.mTerms.end(), p2.mTerms.begin() );
00263     }
00264 
00265     const MultivariatePolynomialMR operator +( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00266     {
00267         //TODO what if not equal polynomialordering! It is correct although very slow.
00268         //return MultivariatePolynomialMR(p1.mTerms.begin(), p1.mTerms.end(), p2.mTerms.begin(), p2.mTerms.end(), p1.mCmp);
00269         MultivariatePolynomialMR newPol( p1.mCmp );
00270         sMT_It inputIt       = newPol.mTerms.begin();
00271         MonomOrderingFc less = p1.mCmp.GetMonomOrdering();
00272 
00273         sMT_It p1it          = p1.mTerms.begin();
00274         sMT_It p2it          = p2.mTerms.begin();
00275         sMT_It p1end         = p1.mTerms.end();
00276         sMT_It p2end         = p2.mTerms.end();
00277 
00278         while( p1it != p1end )
00279         {
00280             if( p2it == p2end )
00281             {
00282                 newPol.mTerms.insert( p1it, p1end );
00283                 return newPol;
00284             }
00285             if( p1it->hasEqualExponents( *p2it ))
00286             {
00287                 ex newCoeff = p1it->getCoeffExpr() + p2it->getCoeffExpr();
00288                 if( newCoeff != 0 )
00289                 {
00290                     inputIt = newPol.mTerms.insert( inputIt, MultivariateTermMR( *p1it, newCoeff ));
00291                 }
00292                 ++p1it;
00293                 ++p2it;
00294                 continue;
00295             }
00296             if( less( *p1it, *p2it ))
00297             {
00298                 inputIt = newPol.mTerms.insert( inputIt, *(p1it++) );
00299                 //++p1it;
00300                 continue;
00301             }    // else if
00302             else
00303             {    // (less(*p1it, *p2it)) {
00304                 inputIt = newPol.mTerms.insert( inputIt, *(p2it++) );
00305                 //++p2it;
00306                 continue;
00307             }    // else (equal)
00308         }
00309         newPol.mTerms.insert( p2it, p2end );
00310         return newPol;
00311 
00312     }
00313 
00314     const MultivariatePolynomialMR operator +( const MultivariatePolynomialMR& p1, const MultivariateTermMR& t1 )
00315     {
00316         MultivariatePolynomialMR newPol = MultivariatePolynomialMR( p1 );
00317         std::pair<sMT_It, bool> ret = newPol.mTerms.insert( t1 );
00318         if( ret.second )
00319             return newPol;
00320             //the same monomial already exists.
00321             //we remove the old one and construct a new term.
00322 
00323         //prepare a pointer to the location where the next should be inserted after.
00324         sMT_It newIt = ret.first;
00325         --newIt;
00326 
00327         //calculate the coeff
00328         ex newCoeff = t1.getCoeffExpr() + ret.first->getCoeffExpr();
00329 
00330         newPol.mTerms.erase( ret.first );
00331 
00332         //If the new coefficient is zero, we do not add the term.
00333         if( newCoeff == 0 )
00334         {
00335             return newPol;
00336         }
00337 
00338         newPol.mTerms.insert( newIt, MultivariateTermMR( t1, newCoeff ));
00339         return newPol;
00340     }
00341 
00342     const MultivariatePolynomialMR operator +( const MultivariateTermMR& t1, MultivariatePolynomialMR& p1 )
00343     {
00344         return p1 + t1;
00345     }
00346 
00347     const MultivariatePolynomialMR operator +( const MultivariatePolynomialMR& p1, const MultivariateMonomialMR& m1 )
00348     {
00349         MultivariatePolynomialMR newPol = MultivariatePolynomialMR( p1 );
00350         std::pair<sMT_It, bool> ret = newPol.mTerms.insert( m1 );
00351         if( ret.second )
00352             return newPol;
00353             //the same monomial already exists.
00354             //we remove the old one and construct a new term.
00355 
00356         //prepare a pointer to the location where the next should be inserted after.
00357         sMT_It newIt = ret.first;
00358         --newIt;
00359 
00360         //the new term has coefficient 0?
00361         if( ret.first->getCoeffExpr() == -1 )
00362         {
00363             newPol.mTerms.erase( ret.first );
00364             return newPol;
00365         }
00366 
00367         //calculate the coefficient
00368         ex newCoeff = 1 + ret.first->getCoeffExpr();
00369 
00370         newPol.mTerms.erase( ret.first );
00371         newPol.mTerms.insert( newIt, MultivariateTermMR( m1, newCoeff ));
00372 
00373         return newPol;
00374     }
00375 
00376     const MultivariatePolynomialMR operator +( const MultivariateMonomialMR& m1, const MultivariatePolynomialMR& p1 )
00377     {
00378         return p1 + m1;
00379     }
00380 
00381     const MultivariatePolynomialMR operator -( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00382     {
00383         MultivariatePolynomialMR newPol( p1.mCmp );
00384         sMT_It inputIt       = newPol.mTerms.begin();
00385         MonomOrderingFc less = p1.mCmp.GetMonomOrdering();
00386 
00387         sMT_It p1it          = p1.mTerms.begin();
00388         sMT_It p2it          = p2.mTerms.begin();
00389         sMT_It p1end         = p1.mTerms.end();
00390         sMT_It p2end         = p2.mTerms.end();
00391 
00392         while( p1it != p1end )
00393         {
00394             if( p2it == p2end )
00395             {
00396                 newPol.mTerms.insert( p1it, p1end );
00397                 return newPol;
00398             }
00399 
00400             if( p1it->hasEqualExponents( *p2it ))
00401             {
00402                 ex newCoeff = p1it->getCoeffExpr() - p2it->getCoeffExpr();
00403                 if( newCoeff != 0 )
00404                 {
00405                     inputIt = newPol.mTerms.insert( inputIt, MultivariateTermMR( *p1it, newCoeff ));
00406                 }
00407                 ++p1it;
00408                 ++p2it;
00409                 continue;
00410             }
00411             if( less( *p1it, *p2it ))
00412             {
00413                 inputIt = newPol.mTerms.insert( inputIt, *(p1it) );
00414                 ++p1it;
00415                 continue;
00416             }    // else if
00417             else
00418             {    // if (less(*p2it, *p1it)) {
00419                 inputIt = newPol.mTerms.insert( inputIt, (p2it->negate()));
00420                 ++p2it;
00421                 continue;
00422             }    // else (equal)
00423 
00424         }
00425         for( ; p2it != p2end; ++p2it )
00426         {
00427             inputIt = newPol.mTerms.insert( inputIt, p2it->negate() );
00428         }
00429         return newPol;
00430     }
00431 
00432     const MultivariatePolynomialMR operator -( const MultivariatePolynomialMR& p1 )
00433     {
00434         MultivariatePolynomialMR newPol = MultivariatePolynomialMR( p1.mCmp );
00435         sMT_It inputloc                 = newPol.mTerms.begin();
00436         for( sMT_It it = p1.mTerms.begin(); it != p1.mTerms.end(); ++it )
00437         {
00438             inputloc = newPol.mTerms.insert( inputloc, it->negate() );
00439         }
00440         return newPol;
00441 
00442     }
00443     //
00444     //    const MultivariatePolynomialMR operator *( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00445     //    {
00446     //        // MultivariatePolynomialMR 
00447     //    }
00448 
00449     const MultivariatePolynomialMR operator *( const MultivariatePolynomialMR& p1, const MultivariateTermMR& t1 )
00450     {
00451         MultivariatePolynomialMR newPol( p1.mCmp );
00452         sMT_cIt end1    = p1.mTerms.end();
00453         sMT_It inputloc = newPol.mTerms.begin();
00454         for( sMT_cIt it = p1.mTerms.begin(); it != end1; ++it )
00455         {
00456             inputloc = newPol.mTerms.insert( inputloc, (*it) * t1 );
00457         }
00458         return newPol;
00459     }
00460 
00461     const MultivariatePolynomialMR operator *( const MultivariateTermMR& t1, MultivariatePolynomialMR& p1 )
00462     {
00463         return p1 * t1;
00464     }
00465 
00466     const MultivariatePolynomialMR operator *( const MultivariatePolynomialMR& p1, const MultivariateMonomialMR& m1 )
00467     {
00468         MultivariatePolynomialMR newPol( p1.mCmp );
00469         sMT_cIt end1    = p1.mTerms.end();
00470         sMT_It inputloc = newPol.mTerms.begin();
00471         for( sMT_cIt it = p1.mTerms.begin(); it != end1; ++it )
00472         {
00473             inputloc = newPol.mTerms.insert( inputloc, (*it) * m1 );
00474         }
00475         return newPol;
00476     }
00477 
00478     const MultivariatePolynomialMR operator *( const MultivariateMonomialMR& m1, const MultivariatePolynomialMR& p1 )
00479     {
00480         return p1 * m1;
00481     }
00482 
00483     std::ostream& operator <<( std::ostream& os, const MultivariatePolynomialMR& rhs )
00484     {
00485         for( sMT_rIt it = rhs.mTerms.rbegin(); it != rhs.mTerms.rend(); ++it )
00486         {
00487             os << *it << " ";
00488         }
00489         return os;
00490     }
00491 
00492     const MultivariatePolynomialMR MultivariatePolynomialMR::SPol( const MultivariatePolynomialMR& p1, const MultivariatePolynomialMR& p2 )
00493     {
00494         //std::cout << "p1:" << p1 << "\np2:" << p2 << std::endl; 
00495         if( p1.getMonomOrder() != p2.getMonomOrder() )
00496         {
00497             throw std::invalid_argument( "Different orderings are not yet supported" );
00498         }
00499         if( p1.nrOfTerms() == 1 && p2.nrOfTerms() == 1 )
00500         {
00501             return MultivariatePolynomialMR( p1.mCmp );
00502         }
00503         else if( p1.nrOfTerms() == 1 )
00504         {
00505             return -(p2.lterm().lcmdivt( p1.lmon() ) * p2.truncLT());
00506         }
00507         else if( p2.nrOfTerms() == 1 )
00508         {
00509             return (p1.lterm().lcmdivt( p2.lmon() ) * p1.truncLT());
00510         }
00511         //std::cout << p2.lterm().lcmdivt(p1.lmon()) << std::endl;
00512         //std::cout << p2.truncLT();
00513         //   std::cout << (p2.truncLT().multiply(p2.lterm().lcmdivt(p1.lmon()))) << std::endl;
00514         return p1.truncLT().multiply( p1.lterm().lcmdivt( p2.lmon() )) - (p2.truncLT().multiply( p2.lterm().lcmdivt( p1.lmon() )));
00515     }
00516 
00517     MultivariatePolynomialMR MultivariatePolynomialMR::CalculateRemainder( std::list<MultivariatePolynomialMR>::const_iterator ideallistBegin,
00518                                                                            std::list<MultivariatePolynomialMR>::const_iterator ideallistEnd ) const
00519     {
00520         MultivariatePolynomialMR* p = new MultivariatePolynomialMR( *this );
00521         MultivariatePolynomialMR* r = new MultivariatePolynomialMR( MonomMRCompare( mCmp ));
00522 
00523         while( !p->isZero() )
00524         {
00525             //std::cout << "a" << std::endl;
00526             std::list<MultivariatePolynomialMR>::const_iterator fIt        = ideallistBegin;
00527             bool                                                divOccured = false;
00528             while( !divOccured && fIt != ideallistEnd )
00529             {
00530                 //MultivariatePolynomialMR temp(*p);
00531                 std::pair<MultivariateTermMR, bool> red = p->lterm().divby( fIt->lterm() );
00532 
00533                 if( red.second )
00534                 {
00535                     *p         = (*p) - (fIt->multiply( red.first ));
00536                     divOccured = true;
00537                 }
00538                 else
00539                 {
00540                     ++fIt;
00541                 }
00542             }
00543             //std::cout << "b" << std::endl;
00544             if( !divOccured )
00545             {
00546                 r->mTerms.insert( p->lterm() );
00547                 p->mTerms.erase( p->lterm() );
00548             }
00549         }
00550         const MultivariatePolynomialMR ret = MultivariatePolynomialMR( *r );
00551         delete p;
00552         return ret;
00553     }
00554 
00555     MultivariatePolynomialMR MultivariatePolynomialMR::normalized()
00556     {
00557         MultivariatePolynomialMR n = MultivariatePolynomialMR( mCmp );
00558         ex lc                      = this->lcoeff();
00559         for( std::set<MultivariateTermMR, MonomMRCompare>::iterator i = mTerms.begin(); i != mTerms.end(); ++i )
00560             n.mTerms.insert( i->divide( lc ));
00561         return n;
00562     }
00563 }