BuiltInFunctions

© 2013 Anna M. Bigatti

GNU Free Documentation License, Version 1.2

CoCoALib Documentation Index

Examples

  • BuiltInFunctions.C and BuiltInOneLiners.C ;-)

User documentation

(Very rough set of notes about adding new functions to CoCoA-5)

Typical situation: I have a function FooFunc implemented in CoCoALib and want to make it a CoCoA-5 function (called FooFunc). There are these possible scenarios I might want in CoCoA-5:

  1. a simple function (not overloaded) with CoCoA-5 data types
  2. a simple function (not overloaded) with almost CoCoA-5 data types
  3. an overloaded function (same name, works on different types)
  4. a function with variable number of arguments
  5. full flexibility

Examples:

  1. IsInvertible (takes a RINGELEM returns a BOOL), LinSolve (takes two MAT returns a MAT).
  2. CoeffOfTerm (takes two RINGELEM returns a RINGELEM, but in CoCoALib takes a PPMonoidElem and a RingElem), RingQQt (takes an INT -- a BigInt for CoCoALib -- but in CoCoALib takes a long).
  3. GBasis (takes an IDEAL or MODULE)
  4. indets (takes a RING or a RING and a STRING)
  5. VersionInfo (returns a RECORD)

1 one-liner: DECLARE_COCOALIB_FUNCTION

This is the easiest case: the porting is implemented in just one line specifying:

  • number of arguments
  • name of the function
  • input types

the return type is deduced by the omonymous CoCoALib function

Example: from BuiltInOneLiners.C

DECLARE_COCOALIB_FUNCTION1(IsInvertible, RINGELEM)
DECLARE_COCOALIB_FUNCTION2(LinSolve, MAT, MAT)

2 one-liner: DECLARE_COCOALIBFORC5_FUNCTION

CoCoA-5 has a simpler (less structured) hierarchy of types, so, for example, PPMonoidElems are represented by RingElems, and machine integers (like long) are represented by BigInt.

So a function taking a non-existing type in CoCoA-5 has a intermediate implementation, FooFunc_forC5, in CoCoALibSupplement.C with the CoCoA-5 datatypes. This should also mean that there is a good reason not to have such implementation available in CoCoALib itself (e.g. not mathematically clean, or inefficient).

Example: from BuiltInOneLiners.C

DECLARE_COCOALIBFORC5_FUNCTION1(RingQQt, INT)
DECLARE_COCOALIBFORC5_FUNCTION2(CoeffOfTerm, RINGELEM, RINGELEM)

3 overloading

Allowing different types in input (with fixed number of arguments)

Example: from BuiltInFunctions.C (NB: END_STD_BUILTIN_FUNCTION)

In CoCoA-5 GBasis takes an IDEAL or a MODULE

DECLARE_STD_BUILTIN_FUNCTION(GBasis, 1) {
  int which;
  intrusive_ptr<RightValue> x = runtimeEnv->evalArgAsT1orT2<IDEAL, MODULE>(ARG(0), which);
  switch (which) {
  case 1: return Value::from(GBasis(RefTo<ideal>(x)));
  default:return Value::from(TidyGens(RefTo<module>(x)));
  }
}
END_STD_BUILTIN_FUNCTION

In CoCoA-5 LT takes an IDEAL, a MODULE, a RINGELEM, or a MODULEELEM

DECLARE_STD_BUILTIN_FUNCTION(LT, 1) { // AMB
  int which;
  intrusive_ptr<RightValue> v = runtimeEnv->evalArgAsT1orT2orT3orT4<RINGELEM,
                                                                    MODULEELEM,
                                                                    IDEAL,
                                                                    MODULE>
                                                                (ARG(0), which);
  switch (which) {
  case 1: return Value::from(LT_forC5(RefTo<RingElem>(v)));
  case 2: return Value::from(LT_forC5(RefTo<ModuleElem>(v)));
  case 3: return Value::from(LT(RefTo<ideal>(v)));
  case 4: return Value::from(LT(RefTo<module>(v)));
  default: throw RuntimeException(ERRORMissingCode(v),invocationExpression);
  }
}
END_STD_BUILTIN_FUNCTION

4 variable number of arguments

Example: from BuiltInFunctions.C (NB: without END_STD_BUILTIN_FUNCTION)

// variable number of args
DECLARE_ARITYCHECK_FUNCTION(indets) { return (1<=nArg) && (nArg<=2); }
DECLARE_BUILTIN_FUNCTION(indets) { // AMB+JAA
  invocationExpression->checkNumberOfArgs(1,2);
  intrusive_ptr<RING> R = runtimeEnv->evalArgAs<RING>(ARG(0));
  if (invocationExpression->args.size()==1)
    return Value::from(indets((runtimeEnv->evalArgAs<RING>(ARG(0)))->theRing));
  return Value::from(indets((runtimeEnv->evalArgAs<RING>(ARG(0)))->theRing,
                            runtimeEnv->evalArgAs<STRING>(ARG(1))->theString));
}

5 other

VersionInfo (returns a RECORD)

Let TTTT (T1, T2, ..) be a CoCoA-5 type with corresponding CoCoALib type tttt.

  • runtimeEnv->evalArgAs<TTTT>(ARG(0)); returns a pointer intrusive_ptr<TTTT> which will be accessed as x->theTttt of CoCoALib type tttt.

  • runtimeEnv->evalArgAsListOf<TTTT>(ARG(1)); -- all elements must be of type TTTT and returns vector<tttt>

  • runtimeEnv->evalArgAsListOfRingElem(ARG(2), R->theRing); -- all elements must be in the same ring (accepts also INT and RAT).
  • runtimeEnv->evalArgAsListOfRingElem(ARG(0)); -- guesses the ring
  • runtimeEnv->evalArgAsT1orT2<T1,T2>(ARG(0), n) or
    • runtimeEnv->evalArgAsT1orT2orT3<T1,T2,T3>(ARG(0), n)
    • ... or ...
    • runtimeEnv->evalArgAsT1orT2orT3orT4orT5orT6orT7<T1,T2,T3,T4,T5,T6,T7>(ARG(0), n) returns a pointer intrusive_ptr<RightValue> and puts in n the index of the type found. Throws a meaningful error is the type found is not in the list.
  • RefTo<tttt>(v) where v is a intrusive_ptr<RightValue> (generic right value): casts the pointer to specific type and call the reference ->theTttt of CoCoALib type tttt. (Defined in BuiltinFunctions.H)

    DECLARE_STD_BUILTIN_FUNCTION(IsOne, 1) {
      int which;
      intrusive_ptr<RightValue> v = runtimeEnv->evalArgAsT1orT2orT3<INT,
                                                                    RAT,
                                                                    RINGELEM>
                                                                 (ARG(0), which);
      switch (which) {
      case 1: return Value::from(IsOne(RefTo<BigInt>(v)));
      case 2: return Value::from(IsOne(RefTo<BigRat>(v)));
      case 3: return Value::from(IsOne(RefTo<RingElem>(v)));
      default: throw RuntimeException(ERRORMissingCode(v),invocationExpression);
      }
    }
    END_STD_BUILTIN_FUNCTION
    

Maintainer documentation

*For overloaded functions explicitely*: Explicitely define all cases and make an extra default case for safety (gives protection in development when one type has been forgotten)

DECLARE_STD_BUILTIN_FUNCTION(LT, 1) {
  int which;
  intrusive_ptr<RightValue> v = runtimeEnv->evalArgAsT1orT2orT3orT4<.....>
                                                                (ARG(0), which);
  switch (which) {
  case 1: ...
  case 2: ...
  case 3: ...
  case 4: ...
  default: throw RuntimeException(ERRORMissingCode(v),invocationExpression);
  }
}
END_STD_BUILTIN_FUNCTION

Bugs, shortcomings and other ideas

  • Can we make it even simpler?
  • Should RefTo<tttt> work also for intrusive_ptr<TTTT>?

Main changes

2014

  • July (before ICMS in Seoul)
    • Type names have been changed from TtttValue to TTTT (e.g. IdealValue to IDEAL).
    • For overloaded functions: PtrCastTttt has been changed into RefTo<tttt> (e.g. PtrCastBigInt to RefTo<BigInt>, and PtrCastIdeal to RefTo<ideal>).
    • member field theInteger/theRational have been changed into theBigInt/theBigRat