/****************************************************************************
**
*W  ariths.h                    GAP source                       Frank Celler
*W                                                         & Martin Schönert
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  This file declares the functions of the  arithmetic  operations  package.
*/

#ifndef libGAP_GAP_ARITHS_H
#define libGAP_GAP_ARITHS_H

/****************************************************************************
**

*T  CompaMethod . . . . . . . . . . type of methods for comparison operations
**
**  'CompaMethod'  is the type of methods  for comparison operations, i.e., a
**  function accepting two arguments of type 'Obj' and returning an 'Int'.
*/
typedef libGAP_Int (* libGAP_CompaMethod) ( libGAP_Obj opL, libGAP_Obj opR );


/****************************************************************************
**
*T  ArithMethod1  . . . . . . . . . type of methods for arithmetic operations
**
**  'ArithMethod1'  is the type of  methods  for unary arithmetic operations,
**  i.e.,  a function accepting  one argument of type  'Obj' and returning an
**  'Obj'.
*/
typedef libGAP_Obj (* libGAP_ArithMethod1) ( libGAP_Obj op );


/****************************************************************************
**
*T  ArithMethod2  . . . . . . . . . type of methods for arithmetic operations
**
**  'ArithMethod2' is the type  of methods for binary arithmetic  operations,
**  i.e., a function  accepting two arguments  of type 'Obj' and returning an
**  'Obj'.
*/
typedef libGAP_Obj (* libGAP_ArithMethod2) ( libGAP_Obj opL, libGAP_Obj opR );


/****************************************************************************
**

*F * * * * * * * * * * *  unary arithmetic operations * * * * * * * * * * * *
*/

/****************************************************************************
**
*F  ZERO( <op> )  . . . . . . . . . . . . . . . . . . . . . zero of an object
**
**  'ZERO' returns the zero of the object <op>.
*/
#define libGAP_ZERO(op)        ((*libGAP_ZeroFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_ZEROOp;


/****************************************************************************
**
*V  ZeroFuncs[<type>] . . . . . . . . . . . . . . . . . table of zero methods
*/
extern libGAP_ArithMethod1 libGAP_ZeroFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallZeroObject( <verb> )
*/
extern void libGAP_InstallZeroObject ( libGAP_Int );

/****************************************************************************
**
*F  ZERO_MUT( <op> )  . . . . . . . . . . . . . . . . . . . . . zero of an object
**
**  'ZERO_MUT' returns the mutable zero of the object <op>.
*/
#define libGAP_ZERO_MUT(op)        ((*libGAP_ZeroMutFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_ZeroOp;


/****************************************************************************
**
*V  ZeroMutFuncs[<type>] . . . . . . . . . . . . . . . . . table of zero methods
*/
extern libGAP_ArithMethod1 libGAP_ZeroMutFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallZeroMutObject( <verb> )
*/
extern void libGAP_InstallZeroMutObject ( libGAP_Int );


/****************************************************************************
**

*F  AINV( <op> )  . . . . . . . . . . . . . . . additive inverse of an object
**
**  'AINV' returns the additive inverse of the object <op>.
*/
#define libGAP_AINV(op) ((*libGAP_AInvFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_AInvOp;


/****************************************************************************
**
*V  AInvFuncs[<type>] . . . . . . . . . . . table of additive inverse methods
*/
extern libGAP_ArithMethod1 libGAP_AInvFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallAinvObject( <verb> )
*/
extern void libGAP_InstallAinvObject ( libGAP_Int );

/****************************************************************************
**
*F  AINV_MUT( <op> )  . . . . . . . . . . . . . additive inverse of an object
**
**  'AINV_MUT' returns the mutable additive inverse of the object <op>.
*/
#define libGAP_AINV_MUT(op) ((*libGAP_AInvMutFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_AdditiveInverseOp;


/****************************************************************************
**
*V  AInvMutFuncs[<type>] . . . . . . . . . . . table of additive inverse methods
*/
extern libGAP_ArithMethod1 libGAP_AInvMutFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallAinvMutObject( <verb> )
*/
extern void libGAP_InstallAinvMutObject ( libGAP_Int );


/****************************************************************************
**
*F  C_AINV( <val>, <left> ) . . . . . . . . . . . . . . . . . .  compute ainv
*/
#define libGAP_C_AINV(val,left) \
 val = libGAP_AINV_MUT( left );


/****************************************************************************
**
*F  C_AINV_FIA( <val>, <left> ) . . . . . . . . .  compute ainv, fast integer
*/
#define libGAP_C_AINV_FIA(val,left) \
 val = libGAP_AINV_MUT( left );


/****************************************************************************
**
*F  C_AINV_INTOBJS( <val>, <left> ) . . . . . . .  compute ainv of an integer
*/
#define libGAP_C_AINV_INTOBJS(val,left) \
 val = libGAP_AINV_MUT( left );


/****************************************************************************
**
*F  ONE( <op> ) . . . . . . . . . . . . . . . . . . . . . .  one of an object
**
**  'ONE' returns the one of the object <op>.
*/
#define libGAP_ONE(op)         ((*libGAP_OneFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_OneOp;


/****************************************************************************
**
*V  OneFuncs[<type>]  . . . . . . . . . . . . . . . . .  table of one methods
*/
extern libGAP_ArithMethod1 libGAP_OneFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallOneObject( <verb> )
*/
extern void libGAP_InstallOneObject ( libGAP_Int );

/****************************************************************************
**
*F  ONE_MUT( <op> )    . . . . . . . .  one of an object retaining mutability
**
**  'ONE_MUT' returns the one of the object <op> with the same
**  mutability level as <op>.
*/
#define libGAP_ONE_MUT(op)         ((*libGAP_OneMutFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_OneMutOp;


/****************************************************************************
**
*V  OneMutFuncs[<type>]  . . . . . .table of mutability preservingone methods
*/
extern libGAP_ArithMethod1 libGAP_OneMutFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallOneMutObject( <verb> )
*/
extern void libGAP_InstallOneMutObject ( libGAP_Int );


/****************************************************************************
**
*F  INV( <op> ) . . . . . . . . . . . . . . . . . . . .  inverse of an object
**
**  'INV' returns the multiplicative inverse of the object <op>.
*/
#define libGAP_INV(op)         ((*libGAP_InvFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_InvOp;


/****************************************************************************
**
*V  InvFuncs[<type>]  . . . . . . . . . . . . . .  table of inverse functions
*/
extern libGAP_ArithMethod1 libGAP_InvFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallInvObject( <verb> )
*/
extern void libGAP_InstallInvObject ( libGAP_Int );


/****************************************************************************
**
*F  INV_MUT( <op> ) . . . . . . . . inverse of an object retaining mutability
**
**  'INV_MUT' returns the multiplicative inverse of the object <op>.
*/
#define libGAP_INV_MUT(op)         ((*libGAP_InvMutFuncs[libGAP_TNUM_OBJ(op)])(op))

extern libGAP_Obj libGAP_InvMutOp;


/****************************************************************************
**
*V  InvMutFuncs[<type>]  .. .table of mutability preserving inverse functions
*/
extern libGAP_ArithMethod1 libGAP_InvMutFuncs [libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallInvMutObject( <verb> )
*/
extern void libGAP_InstallInvMutObject ( libGAP_Int );


/****************************************************************************
**

*F * * * * * * * * * * * * * comparison operations  * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  EQ( <opL>, <opR> )  . . . . . . . . . . . . . . comparison of two objects
**
**  'EQ' returns a nonzero value  if the object <opL>  is equal to the object
**  <opR>, and zero otherwise.
*/
#define libGAP_EQ(opL,opR)     ((opL) == (opR) || \
                         (!libGAP_ARE_INTOBJS(opL,opR) && \
                          (*libGAP_EqFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR)))

#define libGAP_EQ2(opL,opR)    ((opL) == (opR) || \
                          (*libGAP_EqFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_EqOper;


/****************************************************************************
**
*V  EqFuncs[<typeL>][<typeR>] . . . . . . . . . . table of comparison methods
*/
extern libGAP_CompaMethod libGAP_EqFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallEqObject( <verb> )
*/
extern void libGAP_InstallEqObject ( libGAP_Int );


/****************************************************************************
**

*F  LT( <opL>, <opR> )  . . . . . . . . . . . . . . comparison of two objects
**
**  'LT' returns a nonzero value if the object <opL> is  less than the object
**  <opR>, and zero otherwise.
*/
#define libGAP_LT(opL,opR)     ((opL) == (opR) ? 0 : \
                         (libGAP_ARE_INTOBJS(opL,opR) ? (libGAP_Int)(opL) < (libGAP_Int)(opR) : \
                          (*libGAP_LtFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR)))

#define libGAP_LT2(opL,opR)    ((opL) == (opR) ? 0 : \
                          (*libGAP_LtFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_LtOper;


/****************************************************************************
**
*V  LtFuncs[<typeL>][<typeR>] . . . . . . . . . . table of comparison methods
*/
extern libGAP_CompaMethod libGAP_LtFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallLtObject( <verb> )
*/
extern void libGAP_InstallLtObject ( libGAP_Int );


/****************************************************************************
**

*F  IN( <opL>, <opR> )  . . . . . . . . . . .  membership test of two objects
**
**  'IN' returns a nonzero   value if the object  <opL>  is a member  of  the
**  object <opR>, and zero otherwise.
*/
#define libGAP_IN(opL,opR)     ((*libGAP_InFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_InOper;


/****************************************************************************
**
*V  InFuncs[<typeL>][<typeR>] . . . . . . . . . . table of membership methods
*/
extern libGAP_CompaMethod libGAP_InFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallInObject( <verb> )
*/
extern void libGAP_InstallInObject ( libGAP_Int );


/****************************************************************************
**

*F * * * * * * * * * * * binary arithmetic operations * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  SUM( <opL>, <opR> ) . . . . . . . . . . . . . . . . .  sum of two objects
**
**  'SUM' returns the sum of the two objects <opL> and <opR>.
**
**  At places where performance matters one should use the following code
**
**      if ( ! ARE_INTOBJS( <opL>, <opR> )
**        || ! SUM_INTOBJS( <res>, <opL>, <opR> ) )
**          <res> = SUM( <opL>, <opR> );
*/
#define libGAP_SUM(opL,opR)    ((*libGAP_SumFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_SumOper;


/****************************************************************************
**
*V  SumFuncs[<typeL>][<typeR>]  . . . . . . . . . . . .  table of sum methods
*/
extern libGAP_ArithMethod2 libGAP_SumFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallSumObject( <verb> )
*/
extern void libGAP_InstallSumObject ( libGAP_Int );


/****************************************************************************
**
*F  C_SUM( <val>, <left>, <right> ) . . . . . . . . . . . . . . . compute sum
*/
#define libGAP_C_SUM(val,left,right) \
 val = libGAP_SUM( left, right );


/****************************************************************************
**
*F  C_SUM_FIA( <val>, <left>, <right> ) . . . . .  compute sum, fast integers
*/
#define libGAP_C_SUM_FIA(val,left,right) \
 if ( ! libGAP_ARE_INTOBJS(left,right) || ! libGAP_SUM_INTOBJS(val,left,right) ) { \
  val = libGAP_SUM( left, right ); \
 }


/****************************************************************************
**
*F  C_SUM_INTOBJS( <val>, <left>, <right> ) . . . compute sum of two integers
*/
#define libGAP_C_SUM_INTOBJS(val,left,right) \
 if ( ! libGAP_SUM_INTOBJS(val,left,right) ) { \
  val = libGAP_SUM( left, right ); \
 }


/****************************************************************************
**

*F  DIFF( <opL>, <opR> )  . . . . . . . . . . . . . difference of two objects
**
**  'DIFF' returns the difference of the two objects <opL> and <opR>.
**
**  At places where performance matters one should use the following code
**
**      if ( ! ARE_INTOBJS( <opL>, <opR> )
**        || ! DIFF_INTOBJS( <res>, <opL>, <opR> ) )
**          <res> = DIFF( <opL>, <opR> );
*/
#define libGAP_DIFF(opL,opR)   ((*libGAP_DiffFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_DiffOper;


/****************************************************************************
**
*V  DiffFuncs[<typeL>][<typeR>] . . . . . . . . . table of difference methods
*/
extern libGAP_ArithMethod2 libGAP_DiffFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallDiffObject( <verb> )
*/
extern void libGAP_InstallDiffObject ( libGAP_Int );


/****************************************************************************
**
*F  C_DIFF( <val>, <left>, <right> )  . . . . . . . . . . . . .  compute diff
*/
#define libGAP_C_DIFF(val,left,right) \
 val = libGAP_DIFF( left, right );


/****************************************************************************
**
*F  C_DIFF_FIA( <val>, <left>, <right> )  . . . . compute diff, fast integers
*/
#define libGAP_C_DIFF_FIA(val,left,right) \
 if ( ! libGAP_ARE_INTOBJS(left,right) || ! libGAP_DIFF_INTOBJS(val,left,right) ) { \
  val = libGAP_DIFF( left, right ); \
 }


/****************************************************************************
**
*F  C_DIFF_INTOBJS( <val>, <left>, <right> )  .  compute diff of two integers
*/
#define libGAP_C_DIFF_INTOBJS(val,left,right) \
 if ( ! libGAP_DIFF_INTOBJS(val,left,right) ) { \
  val = libGAP_DIFF( left, right ); \
 }


/****************************************************************************
**

*F  PROD( <opL>, <opR> )  . . . . . . . . . . . . . .  product of two objects
**
**  'PROD' returns the product of the two objects <opL> and <opR>.
**
**  At places where performance matters one should use the following code
**
**      if ( ! ARE_INTOBJS( <opL>, <opR> )
**        || ! PROD_INTOBJS( <res>, <opL>, <opR> ) )
**          <res> = PROD( <opL>, <opR> );
*/
#define libGAP_PROD(opL,opR)   ((*libGAP_ProdFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_ProdOper;


/****************************************************************************
**
*V  ProdFuncs[<typeL>][<typeR>] . . . . . . . . . .  table of product methods
*/
extern  libGAP_ArithMethod2    libGAP_ProdFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallProdObject( <verb> )
*/
extern void libGAP_InstallProdObject ( libGAP_Int );


/****************************************************************************
**
*F  C_PROD( <val>, <left>, <right> )  . . . . . . . . . . . . compute product
*/
#define libGAP_C_PROD(val,left,right) \
 val = libGAP_PROD( left, right );


/****************************************************************************
**
*F  C_PROD_FIA( <val>, <left>, <right> )  . .  compute product, fast integers
*/
#define libGAP_C_PROD_FIA(val,left,right) \
 if ( ! libGAP_ARE_INTOBJS(left,right) || ! libGAP_PROD_INTOBJS(val,left,right) ) { \
  val = libGAP_PROD( left, right ); \
 }


/****************************************************************************
**
*F  C_PROD_INTOBJS( <val>, <left>, <right> )  compute product of two integers
*/
#define libGAP_C_PROD_INTOBJS(val,left,right) \
 if ( ! libGAP_PROD_INTOBJS(val,left,right) ) { \
  val = libGAP_PROD( left, right ); \
 }


/****************************************************************************
**

*F  QUO( <opL>, <opR> ) . . . . . . . . . . . . . . . quotient of two objects
**
**  'QUO' returns the quotient of the object <opL> by the object <opR>.
*/
#define libGAP_QUO(opL,opR)    ((*libGAP_QuoFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_QuoOper;


/****************************************************************************
**
*V  QuoFuncs[<typeL>][<typeR>]  . . . . . . . . . . table of quotient methods
*/
extern libGAP_ArithMethod2 libGAP_QuoFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallQuoObject( <verb> )
*/
extern void libGAP_InstallQuoObject ( libGAP_Int );


/****************************************************************************
**

*F  LQUO( <opL>, <opR> )  . . . . . . . . . . .  left quotient of two operand
**
**  'LQUO' returns the left quotient of the object <opL> by the object <opR>.
*/
#define libGAP_LQUO(opL,opR)   ((*libGAP_LQuoFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_LQuoOper;


/****************************************************************************
**
*V  LQuoFuncs[<typeL>][<typeR>] . . . . . . .  table of left quotient methods
*/
extern libGAP_ArithMethod2 libGAP_LQuoFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallLQuoObject( <verb> )
*/
extern void libGAP_InstallLQuoObject ( libGAP_Int );


/****************************************************************************
**

*F  POW( <opL>, <opR> ) . . . . . . . . . . . . . . . .  power of two objects
**
**  'POW' returns the power of the object <opL> by the object <opL>.
*/
#define libGAP_POW(opL,opR)    ((*libGAP_PowFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_PowOper;

extern libGAP_Obj libGAP_PowDefault ( libGAP_Obj opL, libGAP_Obj opR );


/****************************************************************************
**
*V  PowFuncs[<typeL>][<typeR>]  . . . . . . . . . . .  table of power methods
*/
extern libGAP_ArithMethod2 libGAP_PowFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallPowObject( <verb> )
*/
extern void libGAP_InstallPowObject ( libGAP_Int );


/****************************************************************************
**

*F  COMM( <opL>, <opR> )  . . . . . . . . . . . . . commutator of two objects
**
**  'COMM' returns the commutator of the two objects <opL> and <opR>.
*/
#define libGAP_COMM(opL,opR)   ((*libGAP_CommFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_CommOper;


/****************************************************************************
**
*V  CommFuncs[<typeL>][<typeR>] . . . . . . . . . table of commutator methods
*/
extern libGAP_ArithMethod2 libGAP_CommFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallCommObject( <verb> )
*/
extern void libGAP_InstallCommObject ( libGAP_Int );


/****************************************************************************
**

*F  MOD( <opL>, <opR> ) . . . . . . . . . . . . . .  remainder of two objects
**
**  'MOD' returns the remainder of the object <opL> by the object <opR>.
*/
#define libGAP_MOD(opL,opR)    ((*libGAP_ModFuncs[libGAP_TNUM_OBJ(opL)][libGAP_TNUM_OBJ(opR)])(opL,opR))

extern libGAP_Obj libGAP_ModOper;


/****************************************************************************
**
*V  ModFuncs[<typeL>][<typeR>]  . . . . . . . . .  table of remainder methods
*/
extern libGAP_ArithMethod2 libGAP_ModFuncs [libGAP_LAST_VIRTUAL_TNUM+1][libGAP_LAST_VIRTUAL_TNUM+1];


/****************************************************************************
**
*F  InstallModObject( <verb> )
*/
extern void libGAP_InstallModObject ( libGAP_Int );


/****************************************************************************
**

*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  InitInfoAriths()  . . . . . . . . . . . . . . . . table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoAriths ( void );


#endif // GAP_ARITHS_H

/****************************************************************************
**

*E  ariths.h  . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
