Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


next up previous
Next: Static LatticeExprNode functions Up: NOTE 216 - Lattice Expression Language Implementation Previous: Relational and Logical Expressions

Subsections


Other Specializations

There are a few other specialized classes because not all possible data types can be handled by some functions. For example, LELFunctionReal1D is a specialized version of LELFunction1D. The former exists to handle functions such as asin, acos etc which only function with real data.

Similarly, the classes LELFunction{Float,Double,Complex,DComplex} exist to handle functions with an arbitrary number of arguments for each data type. Probably some of these could be combined into a templated class in the same way as the 1-argument LELFunction*1D classes, but there is enough difference between them to make this worthwhile.

Deserving of special mention for their cunning implementation are the functions, nelements, ntrue, and nfalse. These are implemented in LELFunctionDouble, which is not templated and it inherits from LELInterface<Double>.

Function nelements

Consider the expression

   Lattice<Bool> b;
   Lattice<Double> a;
   a.copyData(nelements(b));

Function nelements operates on a Lattice of any data type, and returns the number of elements in the Lattice in a Double. LELFunctionDouble is not templated, and yet this function handles Lattices of any type. It is implemented directly in LatticeExprNode

   LatticeExprNode nelements(const LatticeExprNode& expr)
   {
      Block<LatticeExprNode> arg(1, expr);
      return new LELFunctionDouble (LELFunctionEnums::NELEM, arg);
   }

The new statement creates a pointer to a LELFunctionDouble object, which inherits from LELInterface<Double>. This is then automatically converted to a LatticeExprNode by the constructor

   LatticeExprNode(LELInterface<Double>* expr);

Now, LELFunctionDouble knows that the result of function nelements is a scalar, so it is only implemented in getScalar. The implementation in LELFunctionDouble::getScalar is

   case LELFunctionEnums::NELEM :
       if (arg_p[0].isScalar()) {
          return 1;
       }
       return arg_p[0].shape().product();

arg_p[0] is the first element in a Block<LatticeExprNode>. In our example, it is a LatticeExprNode housing the LELLattice object that is needed to access the Lattice<Bool> (b). Now recall that LELLattice is fully templated, so it can of course handle any type of Lattice. But LELFunctionDouble doesn't know anything at all about the type of this Lattice in the path that is followed for this function; all type checking is bypassed. The statement arg_p[0].shape().product() invokes the appropriate LatticeExprNode function to return the shape attribute.

Functions ntrue and nfalse

These functions only work on Bool Lattices and count up the number of True or False values. Like nelements they are implemented directly from LatticeExprNode. E.g.

   LatticeExprNode ntrue (const LatticeExprNode& expr)   
   {
      AlwaysAssert (expr.dataType() == TpBool, AipsError);
      Block<LatticeExprNode> arg(1, expr);
      return new LELFunctionDouble(LELFunctionEnums::NTRUE, arg);
   }

Immediately though a test is made for the type of the expression that is having the function applied to it. If it's not a Bool, an exception is thrown. Otherwise we proceed into LELFunctionDouble again. Since the result is a scalar they are only implemented in LELFunctionDouble::getScalar For example, for ntrue

   switch (function_p) {
   case LELFunctionEnums::NTRUE :
   {
      uInt ntrue = 0;
      Bool deleteIt;
      LatticeExpr<Bool> latExpr(arg_p[0], 0);
      RO_LatticeIterator<Bool> iter(latExpr, latExpr.niceCursorShape());
      while (! iter.atEnd()) {
         const Array<Bool>& array = iter.cursor();
         const Bool* data = array.getStorage (deleteIt);
         uInt n = array.nelements();
         for (uInt i=0; i<n; i++) {
            if (data[i]) {
               ntrue++;
            }
         }
         array.freeStorage (data, deleteIt);
         iter++;
      }
      return ntrue; 
   }
A LatticeExpr<Bool> (which is a Lattice) is explicitly created from the LatticeExprNode via the constructor. This is then iterated through to get implement the function.


next up previous
Next: Static LatticeExprNode functions Up: NOTE 216 - Lattice Expression Language Implementation Previous: Relational and Logical Expressions
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15