/* emacs edit mode for this file is -*- C++ -*- */

//{{{ docu
//
// cf_inline.cc - definition of configurable inline
//   `CanonicalForm' methods.
//
// Hierarchy: canonicalform
//
// Header file: canonicalform.h
//
// Developers note:
// ----------------
// The central class in Factory is, of course, `CanonicalForm'.
// Hence it is a quiet reasonable to assume that inlining its
// most important methods will improve execution speed.  The same
// holds for some methods of the `CFIterator' class.  Everything
// on configurable inline `CanonicalForm' methods explained here
// applies mutatis mutandis to the `CFIterator' methods.
//
// However, inlining `CanonicalForm' methods has two major
// drawbacks:
//
// o If `CanonicalForm' methods simply would have been declared
//   `inline' it would have been necessary to include the
//   definition of `InternalCF' in `factory.h'.  This would have
//   been quite a contradiction to the internal nature of the
//   class.
//   Hence it seemed desirable to introduce a mechanism to have
//   both the inlined versions for internal use and compiled
//   versions for the library.
//
// o Second, inlining in most cases leads to larger object code.
//   E.g., inlining `CanonicalForm::~CanonicalForm()' increases the
//   object code by approx. 15% without any effect on computation
//   speed.
//   Thus another design aim was to keep things configurable.
//   That is why the methods defined here are called
//   "configurable inline methods".
//
// The low level solution to both problems is the macro
// `CF_INLINE' which either expands to `inline' or nothing.  The
// counterpart `CF_NO_INLINE' exists only for convenience, it
// always expands to nothing.  `CF_INLINE' is set immediately
// before defining resp. declaring the methods to exclude any
// esoteric influences from included files.
//
// The high level interface is the macro `CF_USE_INLINE'.  If it
// is defined any header file that uses configurable inline
// methods defines them to be `inline', otherwise they are
// defined as ordinary methods.  `CF_USE_INLINE' is defined in
// `config.h' only.
//
// To switch on (off) all configurable inline methods, it is
// sufficient to define (undefine) `CF_USE_INLINE' in `config.h'.
// To switch off separate configurable inline methods it is
// necessary to prefix their declaration in `canonicalform.h' by
// `CF_NO_INLINE' instead of `CF_INLINE'.  Furthermore, to avoid
// duplicate symbols at link time, their definition in this file
// has to be wrapped by an `#ifndef INCL_CF_INLINE_CC'.
//
// It turned out that inlining the following methods (and only
// them) results in the best time to size ratio on Linux and HP
// machines:
// o all `CanonicalForm' constructors
// o the binary `CanonicalForm' operators `+' and `*'
//
//}}}

// check whether we are included or translated and
// define `INCL_CF_INLINE_CC' if we are included
#ifdef INCL_CANONICALFORM_H
#define INCL_CF_INLINE_CC
#endif

#include <config.h>

#include "assert.h"

// temporarily switch off `CF_USE_INLINE' and include
// `canonicalform.h' if we are being translated.
// `CF_USE_INLINE_SAVE' is used to save the state of
// `CF_USE_INLINE'.  It is unset after use.
#ifndef INCL_CF_INLINE_CC
#ifdef CF_USE_INLINE
#define CF_USE_INLINE_SAVE
#undef CF_USE_INLINE
#endif
#include "canonicalform.h"
#ifdef CF_USE_INLINE_SAVE
#define CF_USE_INLINE
#undef CF_USE_INLINE_SAVE
#endif
#endif /* ! INCL_CF_INLINE_CC */

// regular include files
#include "int_cf.h"
#include "imm.h"
#include "cf_factory.h"

// set the value of `CF_INLINE' for the following methods and
// functions
#if defined( CF_USE_INLINE ) && defined( INCL_CF_INLINE_CC )
#undef CF_INLINE
#define CF_INLINE inline
#else
#undef CF_INLINE
#define CF_INLINE
#endif /* ! defined( CF_USE_INLINE ) && defined( INCL_CF_INLINE_CC ) */

// constructors, destructors, assignment
//{{{ CF_INLINE CanonicalForm::CanonicalForm ()
//{{{ docu
//
// CanonicalForm() - create the default canonical form.
//
// The canonical form is initialized to zero from the current
// domain.
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ()
    : value( CFFactory::basic( (long)0 ) )
{
}
//}}}

//{{{ CF_INLINE CanonicalForm::CanonicalForm ( const int i )
//{{{ docu
//
// CanonicalForm() - create a canonical form from an integer.
//
// The canonical form is initialized to the "canonical image" of
// `i' in the current domain.  This is `i' itself for
// characteristic zero, `i' mod p for finite fields of
// characteristic p, and `i' mod p^n for prime power domains with
// p^n elements.
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ( const int i )
    : value( CFFactory::basic( (long)i ) )
{
}

CF_INLINE
CanonicalForm::CanonicalForm ( const long i )
    : value( CFFactory::basic( i ) )
{
}
//}}}

//{{{ CF_INLINE CanonicalForm::CanonicalForm ( const CanonicalForm & cf )
//{{{ docu
//
// CanonicalForm() - create a copy of a canonical form.
//
// Type info:
// ----------
// cf: Anything
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ( const CanonicalForm & cf )
    : value( is_imm( cf.value ) ? cf.value : cf.value->copyObject() )
{
}
//}}}

//{{{ CF_INLINE CanonicalForm::CanonicalForm ( InternalCF * cf )
//{{{ docu
//
// CanonicalForm() - create a canonical form from a pointer to an
//   internal canonical form.
//
// This constructor is reserved for internal usage.
//
// Developers note:
// ----------------
// The canonical form gets its value immediately from `cf'.
// `cf's reference counter is not incremented, so be careful with
// this constructor.
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ( InternalCF * cf )
    : value( cf )
{
}
//}}}

//{{{ CF_INLINE CanonicalForm::CanonicalForm ( const Variable & v )
//{{{ docu
//
// CanonicalForm() - create a canonical form from a variable.
//
// If `v' is a polynomial variable or an algebraic element the
// resulting polynomial (or algebraic element) is 1*`v'^1, the
// one being from the current domain.
//
// Variables of level `LEVELBASE' are transformed to one from the
// current domain.
//
// Type info:
// ----------
// v: Anything
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ( const Variable & v )
    : value( CFFactory::poly( v ) )
{
}
//}}}

//{{{ CF_INLINE CanonicalForm::CanonicalForm ( const Variable & v, int e )
//{{{ docu
//
// CanonicalForm() - create a canonical form from a power of a
//   variable.
//
// If `v' is a polynomial variable or an algebraic element the
// resulting polynomial (or algebraic element) is 1*`v'^`e', the
// one being from the current domain.  Algebraic elements are
// reduced modulo their minimal polynomial.
//
// Variables of level `LEVELBASE' are transformed to one from the
// current domain.
//
// Type info:
// ----------
// v: Anything
//
//}}}
CF_INLINE
CanonicalForm::CanonicalForm ( const Variable & v, int e )
    : value( CFFactory::poly( v, e ) )
{
    //ASSERT( e > 0, "math error: exponent has to be positive" );
}
//}}}

#ifndef INCL_CF_INLINE_CC
//{{{ CF_INLINE CanonicalForm::~CanonicalForm ()
//{{{ docu
//
// ~CanonicalForm() - delete CO.
//
// Type info:
// ----------
// CO: Anything
//
//}}}
CF_INLINE
CanonicalForm::~CanonicalForm ()
{
    if ( (! is_imm( value )) && value->deleteObject() )
        delete value;
}
//}}}
#endif

#ifndef INCL_CF_INLINE_CC
//{{{ CF_INLINE CanonicalForm & CanonicalForm::operator = ( const CanonicalForm & cf )
//{{{ docu
//
// operator =() - assign `cf' to CO.
//
// Type info:
// ----------
// CO, cf: Anything
//
//}}}
CF_INLINE CanonicalForm &
CanonicalForm::operator = ( const CanonicalForm & cf )
{
    if ( this != &cf ) {
        if ( (! is_imm( value )) && value->deleteObject() )
            delete value;
        value = (is_imm( cf.value )) ? cf.value : cf.value->copyObject();
    }
    return *this;
}
//}}}

//{{{ CF_INLINE CanonicalForm & CanonicalForm::operator = ( const int cf )
//{{{ docu
//
// operator =() - assign integer `cf' to CO.
//
// `cf' converted to a canonical form as described in the
// canonical form constructor which creates a canonical form from
// an integer.
//
// Type info:
// ----------
// CO: Anything
//
// Developers note:
// ----------------
// Strictly speaking, this operator is superfluous.  The ordinary
// assignment operator together with automatic conversion from
// `int' to `CanonicalForm' would do the job, too.  But this way
// the common operation of assigning an integer is faster.
//
//}}}
CF_INLINE CanonicalForm &
CanonicalForm::operator = ( const long cf )
{
    if ( (! is_imm( value )) && value->deleteObject() )
        delete value;
    value = CFFactory::basic( cf );
    return *this;
}
//}}}
#endif

// predicates
#ifndef INCL_CF_INLINE_CC
//{{{ CF_INLINE bool CanonicalForm::isOne, isZero () const
//{{{ docu
//
// isOne(), isZero() - test whether a `CanonicalForm' equals one
//   or zero, resp.
//
// The predicates `isOne()' and `isZero()' are much faster than
// the comparison operators.  Furthermore, a test `f.isZero()' is
// independent from the current domain, whereas an expression
// `f == 0' is not.
//
// Type info:
// ----------
// CO: Anything
//
// Internal implementation:
// ------------------------
// Note that only immediate objects and objects of class
// `InternalPrimePower' may equal one or zero, resp.
//
// imm_isone(), imm_iszero()
// Trivial.
//
// imm_isone_p(), imm_iszero_p()
// Trivial.
//
// imm_isone_gf(), imm_iszero_gf()
// Use `gf_isone()' and `gf_iszero()', resp., to test whether CO
// equals zero or one, resp.
//
// InternalCF::isOne(), isZero()
// Always return false.
//
// InternalPrimePower::isOne(), isZero()
// Use `mpz_cpm_ui()' resp. `mpz_sgn()' to check the underlying
// mpi.
//
//}}}
CF_INLINE bool
CanonicalForm::isOne () const
{
    int what = is_imm( value );

    if ( ! what )
        return value->isOne();
    else  if ( what == INTMARK )
        return imm_isone( value );
    else if ( what == FFMARK )
        return imm_isone_p( value );
    else
        return imm_isone_gf( value );
}

CF_INLINE bool
CanonicalForm::isZero () const
{
    int what = is_imm( value );

    if ( what == 0 )
        return value->isZero();
    else  if ( what == INTMARK )
        return imm_iszero( value );
    else if ( what == FFMARK )
        return imm_iszero_p( value );
    else
        return imm_iszero_gf( value );
}
//}}}
#endif

// arithmetic operators
#ifndef INCL_CF_INLINE_CC
//{{{ CF_INLINE CanonicalForm operator - ( const CanonicalForm & cf )
//{{{ docu
//
// operator -() - return additive inverse of `cf'.
//
// Returns the additive inverse of `cf'.  One should keep in mind
// that to negate a canonical form a complete (deep) copy of it
// has to be created.
//
// Type info:
// ----------
// cf: CurrentPP
//
// In fact, the type is almost `Anything', but it is, e.g., not
// possible to invert an element from a finite field when the
// characteristic of the current domain has changed.
//
// Internal implementation:
// ------------------------
// All internal methods check whether the reference counter
// equals one.  If so CO is negated in-place.  Otherwise, a new
// copy of CO is created and negated.
//
// imm_neg()
// Trivial.
//
// imm_neg_p()
// Use `ff_neg()' to negate CO.
//
// imm_neg_gf()
// Use `gf_neg()' to negate CO.
//
// InternalInteger::neg()
// Use `mpz_neg()' to negate the underlying mpi.
//
// InternalRational::neg ()
// Use `mpz_neg()' to negate the denominator.
//
// InternalPrimePower::neg()
// Subtract CO from `primepow' using `mpz_sub'.
//
// InternalPoly::neg()
// If reference counter is one use `negateTermList()' to negate
// the terms, otherwise create a negated copy using
// `copyTermList()'.
//
//}}}
CF_INLINE CanonicalForm
operator - ( const CanonicalForm & cf )
{
    CanonicalForm result( cf );
    int what = is_imm( result.value );

    if ( ! what )
        result.value = result.value->neg();
    else  if ( what == INTMARK )
        result.value = imm_neg( result.value );
    else if ( what == FFMARK )
        result.value = imm_neg_p( result.value );
    else
        result.value = imm_neg_gf( result.value );

    return result;
}
//}}}
#endif

// binary arithmetic operators and functions
//{{{ CF_INLINE CanonicalForm operator +, -, *, /, % ( const CanonicalForm & lhs, const CanonicalForm & rhs )
//{{{ docu
//
// operators +, -, *, /, %(), div(), mod() - binary arithmetic
//   operators.
//
// The binary operators have their standard (mathematical)
// semantics.  As explained for the corresponding arithmetic
// assignment operators, the operators `/' and `%' return the
// quotient resp. remainder of (polynomial) division with
// remainder, whereas `div()' and `mod()' may be used for exact
// division and term-wise remaindering, resp.
//
// It is faster to use the arithmetic assignment operators (e.g.,
// `f += g;') instead of the binary operators (`f = f+g;' ).
//
// Type info:
// ----------
// lhs, rhs: CurrentPP
//
// There are weaker preconditions for some cases (e.g.,
// arithmetic operations with elements from Q or Z work in any
// domain), but type `CurrentPP' is the only one guaranteed to
// work for all cases.
//
// Developers note:
// ----------------
// All binary operators have their corresponding `CanonicalForm'
// assignment operators (e.g., `operator +()' corresponds to
// `CanonicalForm::operator +=()', `div()' corresponds to
// `CanonicalForm::div()).
//
// And that is how they are implemented, too: Each of the binary
// operators first creates a copy of `lhs', adds `rhs' to this
// copy using the assignment operator, and returns the result.
//
//}}}
CF_INLINE CanonicalForm
operator + ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result += rhs;
    return result;
}

#ifndef INCL_CF_INLINE_CC
CF_INLINE CanonicalForm
operator - ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result -= rhs;
    return result;
}
#endif

CF_INLINE CanonicalForm
operator * ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result *= rhs;
    return result;
}

#ifndef INCL_CF_INLINE_CC
CF_INLINE CanonicalForm
operator / ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result /= rhs;
    return result;
}

CF_INLINE CanonicalForm
operator % ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result %= rhs;
    return result;
}
#endif
//}}}

#ifndef INCL_CF_INLINE_CC
//{{{ CF_INLINE CanonicalForm div, mod ( const CanonicalForm & lhs, const CanonicalForm & rhs )
// docu: see binary operators above
CF_INLINE CanonicalForm
div ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result.div( rhs );
    return result;
}

CF_INLINE CanonicalForm
mod ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result.mod( rhs );
    return result;
}
//}}}
#endif
