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


next up previous
Next: Optimizations Up: NOTE 216 - Lattice Expression Language Implementation Previous: Data Type Conversions

Scalar Results

So far, we have assumed that the result of all expressions is of the same shape. For example, adding two Lattices together where the Lattices have the same shape. However, we need to also handle expressions where the resultant of the operation on a Lattice is a scalar. For example, min(a) where the minimum value of the Lattice a is returned, must also be handled.

This is done in two places. Firstly, when any of the derived LEL* classes are constructed, it is known whether the result of the operation for which that class exists is a scalar or not. For example, the class LELUnaryConst, which exists to handle an expression like 2.0 knows that its result, after evaluation, is a scalar. Similarly, class LELFunction1D, when it is handling functions min, max, mean and sum (which take one argument) knows that it returns a scalar. Otherwise, and for all other classes, it is seen whether the result of evaluating the tree below is a scalar or not. If the former, then the result is also a scalar. Storage of the knowledge about whether the result is a scalar or not is handled by the attribute class, LELAttribute.

Secondly, the knowledge that the result of the evaluation of the tree below the current location is scalar or not is used to optimize the computation (we could just replicate scalars into arrays of course).

For example, consider the expression b+min(c) where b and c are Lattices. The result of min(c) is a scalar (we will discuss the optimization of only evaluating this once later). Evaluating b+min(c) means that scalar is added to each element of b so the final result is not a scalar.

The tree looks like

      +
   b    min
         c

The code handling the binary operator + needs to know whether the result of the left and right expressions are scalars or not. For example, if they were both scalars, it would just add those scalars together and pass them on up the tree (noting at tree construction time that its result was scalar). This operation is handled in the LELBinary class, and the relevant code for the + operation is

   template <class T>
   void LELBinary<T>::eval(Array<T>& result,
                           const PixelRegion& region) const
  {
      switch(op_p) {
      case LELBinaryEnums::ADD :
          if (pLeftExpr_p->isScalar()) {
             pRightExpr_p->eval(result, region);
             result += pLeftExpr_p->getScalar();
          } else if (pRightExpr_p->isScalar()) {
             pLeftExpr_p->eval(result, region);
             result += pRightExpr_p->getScalar();
          } else {
             Array<T> temp(result.shape());
             pLeftExpr_p->eval(result, region);
             pRightExpr_p->eval(temp, region);
             result += temp;
          }
          break;

Here you can see that it checks the left and right arguments to see if they are scalar and acts optimally accordingly, using the getScalar function (rather than the eval function) to return the scalar result. But notice that the case of both right and left being scalar is missing. What happens is that the eval function is only called by the next object up the tree if the result of that current operation is NOT scalar. If the result is a scalar, then eval is not called, but getScalar is called. For LELBinary the piece relevant to operator + looks like

   template <class T>
   T LELBinary<T>::getScalar() const
   {
      switch(op_p) {
      case LELBinaryEnums::ADD :
         return pLeftExpr_p->getScalar() + pRightExpr_p->getScalar();

So if we had asked for 2.0 + min(c) then both the arguments would be scalars; the tree would be

      +
  2.0   min
         c

and LELBinary::getScalar would have been called to evaluate the sum rather than LELBinary::eval. Now if this expression was being used like

   a.copyData(2+min(c));

then the Lattice a will have all of its pixels assigned the same scalar value that resulted from the expression evaluation. This final assignment decision is handled in the LatticeExprNode eval functions.


next up previous
Next: Optimizations Up: NOTE 216 - Lattice Expression Language Implementation Previous: Data Type Conversions
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