示例#1
0
void doit(const Expr& e, 
          const Expr& tests,
          const Expr& unks,
          const Expr& u0, 
          const Expr& unkParams,
          const Expr& paramVals, 
          const EvalContext& region)
{
  TimeMonitor t0(doitTimer());
  EvalManager mgr;
  mgr.setRegion(region);
  mgr.setVerb(5);

  static RCP<AbstractEvalMediator> mediator 
    = rcp(new StringEvalMediator());

  mgr.setMediator(mediator);

  const EvaluatableExpr* ev 
    = dynamic_cast<const EvaluatableExpr*>(e[0].ptr().get());

  Expr fixed;
  Expr fixed0;

  Out::os() << "params = " << unkParams << std::endl;
  Out::os() << "param vals = " << paramVals << std::endl;

  DerivSet d = SymbPreprocessor::setupSensitivities(e[0], 
                                                    tests,
                                                    unks,
                                                    u0,
                                                    unkParams,
                                                    paramVals,
                                                    fixed,
                                                    fixed0,
                                                    fixed0,
                                                    fixed0,
    region,
    Sensitivities);

  Tabs tab;
  Out::os() << tab << "done setup" << std::endl;
  Out::os() << tab << *ev->sparsitySuperset(region) << std::endl;
  //  ev->showSparsity(Out::os(), region);

  // RCP<EvalVectorArray> results;

  Array<double> constantResults;
  Array<RCP<EvalVector> > vectorResults;

  Out::os() << tab << "starting eval" << std::endl;
  ev->evaluate(mgr, constantResults, vectorResults);

  ev->sparsitySuperset(region)->print(Out::os(), vectorResults, constantResults);

  
  // results->print(Out::os(), ev->sparsitySuperset(region).get());
}
示例#2
0
void EFDEEvaluator::internalEval(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults) const 
{
  TimeMonitor timer(efdeEvalTimer());
  Tabs tabs;

  SUNDANCE_MSG1(mgr.verb(), tabs << "EFDEEvaluator::eval() expr=" 
    << expr()->toString());

  SUNDANCE_MSG2(mgr.verb(), tabs << "sparsity = " << std::endl 
    << *(this->sparsity)());

  constantResults.resize(constValIndexToArgIndexMap_.size());
  vectorResults.resize(varValIndexToArgIndexMap_.size());

  /* evaluate the argument */
  Array<RCP<EvalVector> > argVectorResults;
  Array<double> argConstantResults;

  evalOperand(mgr, argConstantResults, argVectorResults);


  if (mgr.verb() > 2)
    {
      Tabs tab1;
      Out::os() << tab1 << "EFDE operand results" << std::endl;
      argSparsitySuperset()->print(Out::os(), argVectorResults,
                                   argConstantResults);
    }


  for (int i=0; i<constantResults.size(); i++)
  {
    constantResults[i] = argConstantResults[constValIndexToArgIndexMap_[i]];
  }

  
  for (int i=0; i<vectorResults.size(); i++)
  {
    vectorResults[i] = mgr.popVector();
    const RCP<EvalVector>& v = argVectorResults[varValIndexToArgIndexMap_[i]];
    vectorResults[i]->setTo_V(v.get());
  }

  
  

  if (mgr.verb() > 2)
  {
    Tabs tab1;
    Out::os() << tab1 << "results " << std::endl;
    this->sparsity()->print(Out::os(), vectorResults,
      constantResults);
  }
}
void DiscreteFuncElementEvaluator
::internalEval(const EvalManager& mgr,
               Array<double>& constantResults,
               Array<RCP<EvalVector> >& vectorResults) const 
{
  Tabs tabs(0);
  SUNDANCE_MSG1(mgr.verb(),
    tabs << "DiscreteFuncElementEvaluator::eval: expr=" 
    << expr()->toString());

  vectorResults.resize(mi_.size());
  for (int i=0; i<mi_.size(); i++)
    {
      Tabs tab2;
      vectorResults[i] = mgr.popVector();
      TEUCHOS_TEST_FOR_EXCEPTION(!vectorResults[i]->isValid(), 
                         std::logic_error,
                         "invalid evaluation vector allocated in "
                         "DiscreteFuncElementEvaluator::internalEval()");
      SUNDANCE_MSG2(mgr.verb(),tab2<< "setting string rep " << stringReps_[i]);
      vectorResults[i]->setString(stringReps_[i]);
    }
  mgr.evalDiscreteFuncElement(expr(), mi_, vectorResults);
  mgr.stack().setVecSize(vectorResults[0]->length());
  
  if (mgr.verb() > 1)
    {
      Out::os() << tabs << "results " << std::endl;
      mgr.showResults(Out::os(), sparsity(), vectorResults,
                            constantResults);
    }
  SUNDANCE_MSG1(mgr.verb(), tabs << "DiscreteFuncEvaluator::eval() done"); 
}
void CurveNormEvaluator::internalEval(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults) const 
{
  Tabs tabs(0);

  SUNDANCE_MSG2(mgr.verb(), tabs << "CurveNormEvaluator::eval() expr="
    << expr()->toString());

  if (mgr.verb() > 2)
    {
      Out::os() << tabs << "sparsity = " 
                << std::endl << tabs << *(this->sparsity)() << std::endl;
    }

  if (this->sparsity()->numDerivs() > 0)
    {
      vectorResults.resize(1);
      vectorResults[0] = mgr.popVector();
      SUNDANCE_MSG3(mgr.verb(), tabs << "forwarding to evaluation manager");

      mgr.evalCurveNormExpr(expr(), vectorResults[0]);

      mgr.stack().setVecSize(vectorResults[0]->length());
      if (EvalVector::shadowOps()) vectorResults[0]->setString(stringRep_);
    }

  if (mgr.verb() > 1)
    {
      Out::os() << tabs << "results " << std::endl;
      mgr.showResults(Out::os(), this->sparsity(), vectorResults,
                            constantResults);
    }
}
示例#5
0
void doVariations(const Expr& e, 
  const Expr& vars,
  const Expr& varEvalPt,
  const Expr& unks,
  const Expr& unkEvalPt, 
  const Expr& unkParams,
  const Expr& unkParamEvalPts,
  const Expr& fixed,
  const Expr& fixedEvalPt, 
  const Expr& fixedParams,
  const Expr& fixedParamEvalPts, 
  const EvalContext& region)
{
  TimeMonitor t0(doitTimer());
  EvalManager mgr;
  mgr.setRegion(region);

  static RCP<AbstractEvalMediator> mediator 
    = rcp(new StringEvalMediator());

  mgr.setMediator(mediator);

  const EvaluatableExpr* ev 
    = dynamic_cast<const EvaluatableExpr*>(e[0].ptr().get());

  DerivSet d = SymbPreprocessor::setupVariations(e[0], 
    vars,
    varEvalPt,
    unks,
    unkEvalPt,
    unkParams,
    unkParamEvalPts,
    fixed,
    fixedEvalPt,
    fixedParams,
    fixedParamEvalPts,
    region,
    MatrixAndVector);

  Tabs tab;

  Array<double> constantResults;
  Array<RCP<EvalVector> > vectorResults;

  ev->evaluate(mgr, constantResults, vectorResults);

  ev->sparsitySuperset(region)->print(cerr, vectorResults, constantResults);
}
void EvaluatableExpr::evaluate(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults) const
{
  TimeMonitor timer(evalTimer());
  evaluator(mgr.getRegion())->eval(mgr, constantResults, vectorResults);
}
void NullEvaluator::internalEval(const EvalManager& mgr,
                                 Array<double>& constantResults,
                                 Array<RCP<EvalVector> >& vectorResults) const 
{
  Tabs tab;
  SUNDANCE_MSG1(mgr.verb(), tab << "doing null evaluation... nothing to do");
}
示例#8
0
void doGradient(const Expr& e, 
  const Expr& vars,
  const Expr& varEvalPt,
  const Expr& fixedParams,
  const Expr& fixedParamEvalPts,
  const Expr& fixed,
  const Expr& fixedEvalPts, 
  const EvalContext& region)
{
  TimeMonitor t0(doitTimer());
  EvalManager mgr;
  mgr.setRegion(region);

  static RCP<AbstractEvalMediator> mediator 
    = rcp(new StringEvalMediator());

  mgr.setMediator(mediator);

  const EvaluatableExpr* ev 
    = dynamic_cast<const EvaluatableExpr*>(e[0].ptr().get());

  DerivSet d = SymbPreprocessor::setupGradient(e[0], 
    vars,
    varEvalPt,
    fixedParams,
    fixedParamEvalPts,
    fixed,
    fixedEvalPts,
    region,
    FunctionalAndGradient);

  Tabs tab;
  //  std::cerr << tab << *ev->sparsitySuperset(region) << std::endl;
  //  ev->showSparsity(cerr, region);

  // RCP<EvalVectorArray> results;

  Array<double> constantResults;
  Array<RCP<EvalVector> > vectorResults;

  ev->evaluate(mgr, constantResults, vectorResults);

  ev->sparsitySuperset(region)->print(cerr, vectorResults, constantResults);

  
  // results->print(cerr, ev->sparsitySuperset(region).get());
}
void UnaryMinusEvaluator
::internalEval(const EvalManager& mgr,
               Array<double>& constantResults,
               Array<RCP<EvalVector> >& vectorResults) const
{
  Tabs tab;
  SUNDANCE_MSG1(mgr.verb(),
    tab << "UnaryMinusEvaluator::eval() expr=" << expr()->toString());


  /* evaluate the argument */
  evalOperand(mgr, constantResults, vectorResults);


  if (mgr.verb() > 2)
    {
      Out::os() << tab << "UnaryMinus operand results" << std::endl;
      argSparsitySuperset()->print(Out::os(), vectorResults,
                           constantResults);
    }

  for (int i=0; i<constantResults.size(); i++)
    {
      constantResults[i] *= -1;
    }

  for (int i=0; i<vectorResults.size(); i++)
    {
      vectorResults[i]->multiply_S(-1.0);
    }

  
  if (mgr.verb() > 1)
    {
      Out::os() << tab << "UnaryMinus results" << std::endl;
      sparsity()->print(Out::os(), vectorResults,
                           constantResults);
    }

  
}
void CoordExprEvaluator::internalEval(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults) const 
{
  Tabs tabs(0);

  SUNDANCE_MSG1(mgr.verb(), tabs << "CoordExprEvaluator::eval() expr=" << expr()->toString());

  SUNDANCE_MSG2(mgr.verb(), tabs << "sparsity = " << std::endl 
    << *(this->sparsity)())

  if (doValue_)
    {
      Tabs tab2;
      SUNDANCE_MSG3(mgr.verb(), tab2 << "computing value");
      vectorResults.resize(1);
      vectorResults[0] = mgr.popVector();
      mgr.evalCoordExpr(expr(), vectorResults[0]);
      mgr.stack().setVecSize(vectorResults[0]->length());
      vectorResults[0]->setString(stringRep_);
    }
  
  if (doDeriv_)
    {
      Tabs tab2;
      SUNDANCE_MSG3(mgr.verb(), tab2 << "computing derivative");
      constantResults.resize(1);
      constantResults[0] = 1.0;
    }

  if (mgr.verb() > 1)
    {
      Tabs tab1;
      Out::os() << tab1 << "results " << std::endl;
      mgr.showResults(Out::os(), this->sparsity(), vectorResults,
                            constantResults);
    }

}
示例#11
0
void ChainRuleSum
::evalVar(const EvalManager& mgr,
          const Array<RCP<Array<double> > >& constantArgResults,
          const Array<RCP<Array<RCP<EvalVector> > > > & vArgResults,
          const Array<double>& constantArgDerivs,
          const Array<RCP<EvalVector> >& varArgDerivs,
          RCP<EvalVector>& varResult) const
{
  Tabs tabs;
  SUNDANCE_VERB_HIGH(tabs << "ChainRuleSum::evalVar()");
  int vecSize=-1;
  for (int i=0; i<varArgDerivs.size(); i++)
    {
      int s = varArgDerivs[i]->length();
      TEST_FOR_EXCEPTION(vecSize != -1 && s != vecSize, InternalError,
                         "inconsistent vector sizes " << vecSize
                         << " and " << s);
      vecSize = s;
    } 
  for (int i=0; i<vArgResults.size(); i++)
    {
      for (int j=0; j<vArgResults[i]->size(); j++)
        {
          int s = (*(vArgResults[i]))[j]->length();
          TEST_FOR_EXCEPTION(vecSize != -1 && s != vecSize, InternalError,
                             "inconsistent vector sizes " << vecSize
                             << " and " << s);
          vecSize = s;
        }
    } 
  TEST_FOR_EXCEPT(vecSize==-1);
  
  varResult = mgr.popVector();
  varResult->resize(vecSize);
  varResult->setToConstant(0.0);

  for (int i=0; i<numTerms(); i++)
    {
      Tabs tab1;
      SUNDANCE_VERB_HIGH(tab1 << "term=" << i << " of " << numTerms());
      RCP<EvalVector> innerSum = mgr.popVector();
      innerSum->resize(vecSize);
      innerSum->setToConstant(0.0);
      const Array<DerivProduct>& sumOfDerivProducts = terms(i);

      SUNDANCE_VERB_HIGH(tab1 << "inner sum init = " << *innerSum
                         << ", num terms = " << terms(i).size());

      for (int j=0; j<sumOfDerivProducts.size(); j++)
        {
          Tabs tab2;
          SUNDANCE_VERB_HIGH(tab2 << "dp=" << j << " of " << sumOfDerivProducts.size());
          const DerivProduct& p = sumOfDerivProducts[j];
          double cc = p.coeff();
          SUNDANCE_VERB_HIGH(tab2 << "multiplicity=" << cc);
          for (int k=0; k<p.numConstants(); k++)
            {
              const IndexPair& ip = p.constant(k);
              cc *= (*(constantArgResults[ip.argIndex()]))[ip.valueIndex()];
            }
          if (p.numVariables()==0)
            {
              innerSum->add_S(cc);
            }
          else if (p.numVariables()==1)
            {
              const IndexPair& ip = p.variable(0);
              const EvalVector* v 
                = (*(vArgResults[ip.argIndex()]))[ip.valueIndex()].get();
              if (cc==1.0) innerSum->add_V(v);
              else innerSum->add_SV(cc, v);
            }
          else if (p.numVariables()==2)
            {
              const IndexPair& ip0 = p.variable(0);
              const EvalVector* v0 
                = (*(vArgResults[ip0.argIndex()]))[ip0.valueIndex()].get();
              const IndexPair& ip1 = p.variable(1);
              const EvalVector* v1
                = (*(vArgResults[ip1.argIndex()]))[ip1.valueIndex()].get();
              if (cc==1.0) innerSum->add_VV(v0, v1);
              else innerSum->add_SVV(cc, v0, v1);
            }
          else
            {
              const IndexPair& ip0 = p.variable(0);
              const EvalVector* v0 
                = (*(vArgResults[ip0.argIndex()]))[ip0.valueIndex()].get();
              RCP<EvalVector> tmp = v0->clone();
              for (int k=1; k<p.numVariables(); k++)
                {
                  const IndexPair& ip1 = p.variable(k);
                  const EvalVector* v1
                    = (*(vArgResults[ip1.argIndex()]))[ip1.valueIndex()].get();
                  tmp->multiply_V(v1);
                }
              if (cc==1.0) innerSum->add_V(tmp.get());
              else innerSum->add_SV(cc, tmp.get());
            }
          SUNDANCE_VERB_HIGH(tab2 << "inner sum=" << *innerSum);
        }

      int adi = argDerivIndex(i);
      if (argDerivIsConstant(i))
        {
          const double& df_dq = constantArgDerivs[adi];
          varResult->add_SV(df_dq, innerSum.get());
        }
      else
        {
          const EvalVector* df_dq = varArgDerivs[adi].get();
          SUNDANCE_VERB_HIGH(tab1 << "arg deriv=" << *df_dq);
          varResult->add_VV(df_dq, innerSum.get());
          SUNDANCE_VERB_HIGH(tab1 << "outer sum=" << *varResult);
        }
    }
}
void ProductEvaluator
::internalEval(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults) const
{
  Tabs tabs(0);

  SUNDANCE_MSG1(mgr.verb(),
    tabs << "ProductEvaluator::eval() expr=" 
    << expr()->toString());

  /* evaluate the children */
  Array<RCP<EvalVector> > leftVectorResults; 
  Array<RCP<EvalVector> > rightVectorResults; 
  Array<double> leftConstantResults;
  Array<double> rightConstantResults;
  evalChildren(mgr, leftConstantResults, leftVectorResults,
    rightConstantResults, rightVectorResults);

  if (mgr.verb() > 2)
  {
    Out::os() << tabs << "left operand results" << std::endl;
    mgr.showResults(Out::os(), leftSparsity(), leftVectorResults,
      leftConstantResults);
    Out::os() << tabs << "right operand results" << std::endl;
    mgr.showResults(Out::os(), rightSparsity(), rightVectorResults,
      rightConstantResults);
  }
  
  constantResults.resize(this->sparsity()->numConstantDerivs());
  vectorResults.resize(this->sparsity()->numVectorDerivs());

  /* Evaluate from high to low differentiation order. This is necessary
   * so that we can do in-place evaluation of derivatives, overwriting
   * one of the operands' vectors */

  for (int order=maxOrder_; order>=0; order--)
  {
    for (int i=0; i<resultIndex_[order].size(); i++)
    {
      double constantVal = 0.0;
      const Array<Array<int> >& ccTerms = ccTerms_[order][i];
      for (int j=0; j<ccTerms.size(); j++)
      {
        /* add L*R*multiplicity to result */
        constantVal += leftConstantResults[ccTerms[j][0]] 
          * rightConstantResults[ccTerms[j][1]] * ccTerms[j][2];
      }
      /* If this derivative is a constant, we're done. */
      if (resultIsConstant_[order][i]) 
      {
        constantResults[resultIndex_[order][i]] = constantVal;
        continue;
      }


      /* For the vector case, the first thing to do is get storage
       * for the result. If we can reuse one of the operands' results
       * as workspace, great. If not, we'll need to allocate a new
       * vector. */
      RCP<EvalVector> result;
      if (hasWorkspace_[order][i])
      {
        int index = workspaceIndex_[order][i];
        int coeffIndex = workspaceCoeffIndex_[order][i];
        bool coeffIsConstant = workspaceCoeffIsConstant_[order][i];
        if (workspaceIsLeft_[order][i])
        {
          result = leftVectorResults[index];
          if (coeffIsConstant)
          {
            const double& coeff = rightConstantResults[coeffIndex];
            if (!isOne(coeff)) result->multiply_S(coeff);
          }
          else
          {
            const RCP<EvalVector>& coeff 
              = rightVectorResults[coeffIndex];
            result->multiply_V(coeff.get());
          }
        }
        else
        {
          result = rightVectorResults[index];
          if (coeffIsConstant)
          {
            const double& coeff = leftConstantResults[coeffIndex];
            if (!isOne(coeff)) result->multiply_S(coeff);
          }
          else
          {
            const RCP<EvalVector>& coeff 
              = leftVectorResults[coeffIndex];
            result->multiply_V(coeff.get());
          }
        }
        SUNDANCE_MSG5(mgr.verb(), tabs << "workspace = " << result->str());
      }
      else
      {
        result = mgr.popVector();
        const Array<int>& sv = startingVectors_[order][i];
        int multiplicity = sv[2];
        switch(startingParities_[order][i])
        {
          case VecVec:
            if (!isZero(constantVal))
            {
              if (!isOne(multiplicity))
              {
                result->setTo_S_add_SVV(constantVal,
                  multiplicity,
                  leftVectorResults[sv[0]].get(),
                  rightVectorResults[sv[1]].get());
              }
              else
              {
                result->setTo_S_add_VV(constantVal,
                  leftVectorResults[sv[0]].get(),
                  rightVectorResults[sv[1]].get());
              }
            }
            else
            {
              if (!isOne(multiplicity))
              {
                result->setTo_SVV(multiplicity,
                  leftVectorResults[sv[0]].get(),
                  rightVectorResults[sv[1]].get());
              }
              else
              {
                result->setTo_VV(leftVectorResults[sv[0]].get(),
                  rightVectorResults[sv[1]].get());
              }
            }
            SUNDANCE_MSG5(mgr.verb(), tabs << "init to v-v prod, m="
              << multiplicity << ", left=" 
              << leftVectorResults[sv[0]]->str()
              << ", right=" 
              << rightVectorResults[sv[1]]->str()
              << ", result=" << result->str());
            break;
          case VecConst:
            if (!isZero(constantVal))
            {
              if (!isOne(multiplicity*rightConstantResults[sv[1]]))
              {
                result->setTo_S_add_SV(constantVal,
                  multiplicity
                  *rightConstantResults[sv[1]],  
                  leftVectorResults[sv[0]].get());
              }
              else
              {
                result->setTo_S_add_V(constantVal,
                  leftVectorResults[sv[0]].get());
              }
            }
            else
            {
              if (!isOne(multiplicity*rightConstantResults[sv[1]]))
              {
                result->setTo_SV(multiplicity
                  *rightConstantResults[sv[1]],  
                  leftVectorResults[sv[0]].get());
              }
              else
              {
                result->setTo_V(leftVectorResults[sv[0]].get());
              }
            }
            SUNDANCE_MSG5(mgr.verb(), tabs << "init to v-c prod, m="
              << multiplicity << ", left=" 
              << leftVectorResults[sv[0]]->str()
              << ", right=" 
              << rightConstantResults[sv[1]]
              << ", result=" << result->str());
            break;
          case ConstVec:
            if (!isZero(constantVal))
            {
              if (!isOne(multiplicity*leftConstantResults[sv[0]]))
              {
                result->setTo_S_add_SV(constantVal,
                  multiplicity
                  *leftConstantResults[sv[0]],  
                  rightVectorResults[sv[1]].get());
              }
              else
              {
                result->setTo_S_add_V(constantVal,  
                  rightVectorResults[sv[1]].get());
              }
            }
            else
            {
              if (!isOne(multiplicity*leftConstantResults[sv[0]]))
              {
                result->setTo_SV(multiplicity
                  *leftConstantResults[sv[0]],  
                  rightVectorResults[sv[1]].get());
              }
              else
              {
                result->setTo_V(rightVectorResults[sv[1]].get());
              }
            }
            SUNDANCE_MSG5(mgr.verb(), tabs << "init to c-v prod, m="
              << multiplicity << ", left=" 
              << leftConstantResults[sv[0]]
              << ", right=" 
              << rightVectorResults[sv[1]]->str()
              << ", result=" << result->str());
                  
        }
        SUNDANCE_MSG4(mgr.verb(), tabs << "starting value = " << result->str());
      }
      vectorResults[resultIndex_[order][i]] = result;

      const Array<Array<int> >& cvTerms = cvTerms_[order][i];
      const Array<Array<int> >& vcTerms = vcTerms_[order][i];
      const Array<Array<int> >& vvTerms = vvTerms_[order][i];

      for (int j=0; j<cvTerms.size(); j++)
      {
        SUNDANCE_MSG4(mgr.verb(), tabs << "adding c-v term " << cvTerms[j]);
              
        double multiplicity = cvTerms[j][2];
        double scalar = multiplicity*leftConstantResults[cvTerms[j][0]];
        const EvalVector* vec = rightVectorResults[cvTerms[j][1]].get();
        if (!isOne(scalar))
        {
          result->add_SV(scalar, vec);
        }
        else
        {
          result->add_V(vec);
        }
      } 

      for (int j=0; j<vcTerms.size(); j++)
      {
        SUNDANCE_MSG4(mgr.verb(), tabs << "adding v-c term " << vcTerms[j]);

        double multiplicity = vcTerms[j][2];
        double scalar = multiplicity*rightConstantResults[vcTerms[j][1]];
        const EvalVector* vec = leftVectorResults[vcTerms[j][0]].get();
        if (!isOne(scalar))
        {
          result->add_SV(scalar, vec);
        }
        else
        {
          result->add_V(vec);
        }
      }

      for (int j=0; j<vvTerms.size(); j++)
      {
        SUNDANCE_MSG4(mgr.verb(), tabs << "adding v-v term " << vvTerms[j]);

        double multiplicity = vvTerms[j][2];
        const EvalVector* vec1 = leftVectorResults[vvTerms[j][0]].get();
        const EvalVector* vec2 = rightVectorResults[vvTerms[j][1]].get();
        if (!isOne(multiplicity))
        {
          result->add_SVV(multiplicity, vec1, vec2);
        }
        else
        {
          result->add_VV(vec1, vec2);
        }
      }

          
    }
  }

  if (mgr.verb() > 1)
  {
    Out::os() << tabs << "product result " << std::endl;
    mgr.showResults(Out::os(), this->sparsity(), vectorResults,
      constantResults);
  }
}
void DiffOpEvaluator::internalEval(const EvalManager& mgr,
  Array<double>& constantResults,
  Array<RCP<EvalVector> >& vectorResults)  const
{
  Tabs tabs;
  SUNDANCE_MSG1(mgr.verb(), tabs << "DiffOpEvaluator::eval() expr=" 
    << expr()->toString());

  /* evaluate the argument */
  Array<RCP<EvalVector> > argVectorResults;
  Array<double> argConstantResults;

  SUNDANCE_MSG2(mgr.verb(), tabs << "evaluating operand");
  evalOperand(mgr, argConstantResults, argVectorResults);


  if (mgr.verb() > 2)
  {
    Tabs tab1;
    Out::os() << tabs << "DiffOp operand results" << std::endl;
    mgr.showResults(Out::os(), argSparsitySuperset(), argVectorResults,
      argConstantResults);
  }



  /* evaluate the required discrete functions */
  SUNDANCE_MSG2(mgr.verb(), tabs << "evaluating discrete functions, num funcs= " << funcEvaluators_.size());

  Array<Array<RCP<EvalVector> > > funcVectorResults(funcEvaluators_.size());
  Array<double> funcConstantResults;
  for (int i=0; i<funcEvaluators_.size(); i++)
  {
    funcEvaluators_[i]->eval(mgr, funcConstantResults, funcVectorResults[i]);
  }
  
  constantResults.resize(this->sparsity()->numConstantDerivs());
  vectorResults.resize(this->sparsity()->numVectorDerivs());
  
  SUNDANCE_MSG3(mgr.verb(), tabs << "summing spatial/functional chain rule");

  for (int i=0; i<this->sparsity()->numDerivs(); i++)
  {
    Tabs tab1;
    SUNDANCE_MSG4(mgr.verb(), tab1 << "working on deriv " 
      << this->sparsity()->deriv(i));

    /* add constant monomials */
    SUNDANCE_MSG4(mgr.verb(), tab1 << "have " <<  constantMonomials_[i].size()
      << " constant monomials");
    double constantVal = 0.0;
    for (int j=0; j<constantMonomials_[i].size(); j++)
    {
      SUNDANCE_MSG4(mgr.verb(), tab1 << "adding in constant monomial (index "
        << constantMonomials_[i][j] 
        << " in arg results)");
      constantVal += argConstantResults[constantMonomials_[i][j]];
    }
    if (isConstant_[i])
    {
      constantResults[resultIndices_[i]] = constantVal;
      SUNDANCE_MSG4(mgr.verb(), tab1 << "result is constant: value=" 
        << constantVal);
      continue;
    }

    RCP<EvalVector> result;
    bool vecHasBeenAllocated = false;

    /* add in the vector monomials */
    const Array<int>& vm = vectorMonomials_[i];
    SUNDANCE_MSG4(mgr.verb(), tab1 << "have " << vm.size() 
      << " vector monomials");
    for (int j=0; j<vm.size(); j++)
    {
      Tabs tab2;

      const RCP<EvalVector>& v = argVectorResults[vm[j]];

      SUNDANCE_MSG4(mgr.verb(), tab2 << "found vec monomial term " << v->str());

      /* if we've not yet allocated a vector for the results, 
       * do so now, and set it to the initial value */ 
      if (!vecHasBeenAllocated)
      {
        SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
        result = mgr.popVector();
        vecHasBeenAllocated = true;
        if (isZero(constantVal))
        {
          result->setTo_V(v.get());
        }
        else
        {
          result->setTo_S_add_V(constantVal, v.get());
        }
      }
      else
      {
        result->add_V(v.get());
      }
      SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
    }
      
    /* add in the function terms with constant coeffs */
    const Array<int>& cf = constantFuncCoeffs_[i];
    SUNDANCE_MSG4(mgr.verb(), tab1 << "adding " << cf.size()
      << " func terms with constant coeffs");
    for (int j=0; j<cf.size(); j++)
    {
      Tabs tab2;
      const double& coeff = argConstantResults[cf[j]];
      int fIndex = constantCoeffFuncIndices_[i][j];
      int miIndex = constantCoeffFuncMi_[i][j];
      const RCP<EvalVector>& fValue 
        = funcVectorResults[fIndex][miIndex];

      SUNDANCE_MSG4(mgr.verb(), tab2 << "found term: coeff= " 
        << coeff << ", func value=" << fValue->str());
          
      /* if we've not yet allocated a vector for the results, 
       * do so now, and set it to the initial value */ 
      if (!vecHasBeenAllocated)
      {
        SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
        result = mgr.popVector();
        vecHasBeenAllocated = true;
        if (isOne(coeff))
        {
          if (isZero(constantVal))
          {
            result->setTo_V(fValue.get());
          }
          else
          {
            result->setTo_S_add_V(constantVal, fValue.get());
          }
        }
        else
        {
          if (isZero(constantVal))
          {
            result->setTo_SV(coeff, fValue.get());
          }
          else
          {
            result->setTo_S_add_SV(constantVal, coeff, fValue.get());
          }
        }
      }
      else
      {
        if (isOne(coeff))
        {
          result->add_V(fValue.get());
        }
        else
        {
          result->add_SV(coeff, fValue.get());
        }
      }
      SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
    }

      
    /* add in the function terms with vector coeffs */
    const Array<int>& vf = vectorFuncCoeffs_[i];
    SUNDANCE_MSG4(mgr.verb(), tab1 << "adding " << vf.size()
      << " func terms with vector coeffs");
    for (int j=0; j<vf.size(); j++)
    {
      Tabs tab2;

      const RCP<EvalVector>& coeff = argVectorResults[vf[j]];
      int fIndex = vectorCoeffFuncIndices_[i][j];
      int miIndex = vectorCoeffFuncMi_[i][j];
      const RCP<EvalVector>& fValue 
        = funcVectorResults[fIndex][miIndex];

      SUNDANCE_MSG4(mgr.verb(), tab2 << "found term: coeff= " 
        << coeff->str() << ", func value=" 
        << fValue->str());
          
      /* if we've not yet allocated a vector for the results, 
       * do so now, and set it to the initial value */ 
      if (!vecHasBeenAllocated)
      {
        SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
        result = mgr.popVector();
        vecHasBeenAllocated = true;
        result->setTo_VV(coeff.get(), fValue.get());
      }
      else
      {
        result->add_VV(coeff.get(), fValue.get());
      }
      SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
    }

    TEUCHOS_TEST_FOR_EXCEPTION(!vecHasBeenAllocated, std::logic_error,
      "created empty vector in DiffOpEvaluator::internalEval");
    vectorResults[resultIndices_[i]] = result;
  }

  if (mgr.verb() > 1)
  {
    Out::os() << tabs << "diff op results" << std::endl;
    mgr.showResults(Out::os(), sparsity(), vectorResults,
      constantResults);
  }
  SUNDANCE_MSG1(mgr.verb(), tabs << "done spatial/functional chain rule");
}