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

/**
 *
 * @file 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 "cf_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 ()
 *
 *
 * 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 )
 *
 *
 * 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 )
 *
 *
 * 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 )
 *
 *
 * 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 )
 *
 *
 * 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 )
 *
 *
 * 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 ()
 *
 *
 * ~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 )
 *
 *
 * 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;
}

/**
 *
 * operator =() - assign long `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
 *
 *
 * 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.
 *
 * @sa CanonicalForm::isZero()
**/
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 );
}

/**
 * @sa CanonicalForm::isOne()
**/
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 )
 *
 *
 * 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()'.
 *
 * @sa CanonicalForm::operator -=()
**/
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 )
 *
 *
 * 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.
 *
 * @sa CanonicalForm::operator +=()
**/
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

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

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

/**
 * @sa CanonicalForm::operator %=()
**/
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 )
 * @sa mod(), operator/(), CanonicalForm::operator /=()
**/
CF_INLINE CanonicalForm
div ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result.div( rhs );
    return result;
}

/**
 * @sa div(), operator%(), CanonicalForm::operator %=()
**/
CF_INLINE CanonicalForm
mod ( const CanonicalForm & lhs, const CanonicalForm & rhs )
{
    CanonicalForm result( lhs );
    result.mod( rhs );
    return result;
}
#endif
