00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "SundanceDiffOpEvaluator.hpp"
00032 #include "SundanceEvalManager.hpp"
00033 #include "SundanceDiffOp.hpp"
00034
00035
00036 #include "PlayaTabs.hpp"
00037 #include "SundanceOut.hpp"
00038 #include "SundanceUnknownFuncElement.hpp"
00039 #include "SundanceTestFuncElement.hpp"
00040 #include "SundanceDiscreteFuncElement.hpp"
00041 #include "SundanceDiscreteFuncEvaluator.hpp"
00042 #include "SundanceEvaluatableExpr.hpp"
00043 #include "SundanceZeroExpr.hpp"
00044
00045 using namespace Sundance;
00046 using namespace Sundance;
00047 using namespace Sundance;
00048 using namespace Teuchos;
00049
00050
00051
00052
00053
00054 DiffOpEvaluator
00055 ::DiffOpEvaluator(const DiffOp* expr,
00056 const EvalContext& context)
00057 : UnaryEvaluator<DiffOp>(expr, context),
00058 isConstant_(this->sparsity()->numDerivs()),
00059 resultIndices_(this->sparsity()->numDerivs()),
00060 constantMonomials_(this->sparsity()->numDerivs()),
00061 vectorMonomials_(this->sparsity()->numDerivs()),
00062 constantFuncCoeffs_(this->sparsity()->numDerivs()),
00063 vectorFuncCoeffs_(this->sparsity()->numDerivs()),
00064 funcEvaluators_(),
00065 constantCoeffFuncIndices_(this->sparsity()->numDerivs()),
00066 constantCoeffFuncMi_(this->sparsity()->numDerivs()),
00067 vectorCoeffFuncIndices_(this->sparsity()->numDerivs()),
00068 vectorCoeffFuncMi_(this->sparsity()->numDerivs())
00069 {
00070 int verb = context.setupVerbosity();
00071 Tabs tabs;
00072 SUNDANCE_MSG1(verb, tabs << "initializing diff op evaluator for "
00073 << expr->toString());
00074
00075 {
00076 Tabs tab0;
00077
00078 SUNDANCE_MSG2(verb, tab0 << "return sparsity " << std::endl << *(this->sparsity)());
00079
00080 SUNDANCE_MSG2(verb, tab0 << "argument sparsity subset " << std::endl
00081 << *(argSparsitySuperset()));
00082
00083 Map<const DiscreteFuncElementEvaluator*, int> funcToIndexMap;
00084
00085 int vecResultIndex = 0;
00086 int constResultIndex = 0;
00087
00088 for (int i=0; i<this->sparsity()->numDerivs(); i++)
00089 {
00090 Tabs tab1;
00091 const MultipleDeriv& resultDeriv = this->sparsity()->deriv(i);
00092 SUNDANCE_MSG3(verb, tab0 << "working out procedure for computing "
00093 << resultDeriv);
00094
00095 if (this->sparsity()->state(i)==ConstantDeriv)
00096 {
00097 Tabs tab2;
00098 addConstantIndex(i, constResultIndex);
00099 resultIndices_[i] = constResultIndex++;
00100 isConstant_[i] = true;
00101 SUNDANCE_MSG3(verb, tab2 << "deriv is constant, will be stored at index "
00102 << resultIndices_[i] << " in the const result array");
00103 }
00104 else
00105 {
00106 Tabs tab2;
00107 addVectorIndex(i, vecResultIndex);
00108 resultIndices_[i] = vecResultIndex++;
00109 isConstant_[i] = false;
00110 SUNDANCE_MSG3(verb, tab2 << "deriv is variable, will be stored at index "
00111 << resultIndices_[i] << " in the var result array");
00112 }
00113
00114 int order = resultDeriv.order();
00115 const Set<MultipleDeriv>& RArg
00116 = argExpr()->findR(order, context);
00117 const Set<MultipleDeriv>& RArgPlus
00118 = argExpr()->findR(order+1, context);
00119 const Set<MultipleDeriv>& W1Arg
00120 = argExpr()->findW(1, context);
00121
00122
00123 SUNDANCE_MSG3(verb, tab1 << "RArg = " << RArg);
00124 SUNDANCE_MSG3(verb, tab1 << "RArgPlus = " << RArgPlus);
00125 SUNDANCE_MSG3(verb, tab1 << "W1Arg = " << W1Arg);
00126
00127 Set<MultipleDeriv> funcTermCoeffs
00128 = RArgPlus.intersection(increasedDerivs(resultDeriv, W1Arg, verb));
00129 SUNDANCE_MSG3(verb, tab1 << "function term coeffs = " << funcTermCoeffs);
00130
00131
00132 if (funcTermCoeffs.size()==0)
00133 {
00134 SUNDANCE_MSG3(verb, tab1 << "no direct chain rule terms");
00135 }
00136 else
00137 {
00138 SUNDANCE_MSG3(verb, tab1 << "getting direct chain rule terms");
00139 }
00140
00141
00142 for (Set<MultipleDeriv>::const_iterator
00143 j=funcTermCoeffs.begin(); j != funcTermCoeffs.end(); j++)
00144 {
00145 Tabs tab2;
00146 SUNDANCE_MSG3(verb, tab2 << "getting coefficient of " << *j);
00147
00148 int argIndex = argSparsitySuperset()->getIndex(*j);
00149 TEUCHOS_TEST_FOR_EXCEPTION(argIndex==-1, std::runtime_error,
00150 "Derivative " << *j << " expected in argument "
00151 "but not found");
00152
00153 Deriv lambda = remainder(*j, resultDeriv, verb);
00154
00155 if (lambda.isCoordDeriv())
00156 {
00157 Tabs tab3;
00158 SUNDANCE_MSG3(verb, tab2 << "detected coordinate deriv");
00159 if (lambda.coordDerivDir()!=expr->mi().firstOrderDirection())
00160 {
00161 SUNDANCE_MSG3(verb, tab2 << "direction mismatch, skipping");
00162 continue;
00163 }
00164 const DerivState& argState = argSparsitySuperset()->state(argIndex);
00165 if (argState==ConstantDeriv)
00166 {
00167 int constArgIndex = argEval()->constantIndexMap().get(argIndex);
00168 constantMonomials_[i].append(constArgIndex);
00169 }
00170 else
00171 {
00172 int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex);
00173 vectorMonomials_[i].append(vectorArgIndex);
00174 }
00175 }
00176 else if (lambda.opOnFunc().isPartial() || lambda.opOnFunc().isIdentity())
00177 {
00178 Tabs tab3;
00179 SUNDANCE_MSG3(verb, tab3 << "detected functional deriv " << lambda);
00180 const SymbolicFuncElement* f = lambda.symbFuncElem();
00181 const MultiIndex& mi = expr->mi() + lambda.opOnFunc().mi();
00182 SUNDANCE_MSG3(verb, tab3 << "modified multiIndex is " << mi);
00183
00184 const TestFuncElement* t
00185 = dynamic_cast<const TestFuncElement*>(f);
00186 if (t != 0) continue;
00187
00188 const UnknownFuncElement* u
00189 = dynamic_cast<const UnknownFuncElement*>(f);
00190 TEUCHOS_TEST_FOR_EXCEPTION(u==0, std::logic_error,
00191 "Non-unknown function detected where an unknown "
00192 "function was expected in "
00193 "DiffOpEvaluator ctor");
00194
00195
00196 const EvaluatableExpr* evalPt = u->evalPt();
00197 const ZeroExpr* z = dynamic_cast<const ZeroExpr*>(evalPt);
00198 if (z != 0) continue;
00199 TEUCHOS_TEST_FOR_EXCEPTION(z != 0, std::logic_error,
00200 "DiffOpEvaluator detected identically zero "
00201 "function");
00202
00203 const DiscreteFuncElement* df
00204 = dynamic_cast<const DiscreteFuncElement*>(evalPt);
00205
00206 TEUCHOS_TEST_FOR_EXCEPTION(df==0, std::logic_error,
00207 "DiffOpEvaluator ctor: evaluation point of "
00208 "unknown function " << u->toString()
00209 << " is not a discrete function");
00210
00211 const SymbolicFuncElementEvaluator* uEval
00212 = dynamic_cast<const SymbolicFuncElementEvaluator*>(u->evaluator(context).get());
00213
00214 const DiscreteFuncElementEvaluator* dfEval = uEval->dfEval();
00215
00216
00217 TEUCHOS_TEST_FOR_EXCEPTION(dfEval==0, std::logic_error,
00218 "DiffOpEvaluator ctor: evaluator for "
00219 "evaluation point is not a "
00220 "DiscreteFuncElementEvaluator");
00221
00222 TEUCHOS_TEST_FOR_EXCEPTION(!dfEval->hasMultiIndex(mi), std::logic_error,
00223 "DiffOpEvaluator ctor: evaluator for "
00224 "discrete function " << df->toString()
00225 << " does not know about multiindex "
00226 << mi.toString());
00227
00228 int fIndex;
00229 int miIndex = dfEval->miIndex(mi);
00230
00231 if (funcToIndexMap.containsKey(dfEval))
00232 {
00233 fIndex = funcToIndexMap.get(dfEval);
00234 }
00235 else
00236 {
00237 fIndex = funcEvaluators_.size();
00238 funcEvaluators_.append(dfEval);
00239 funcToIndexMap.put(dfEval, fIndex);
00240 }
00241
00242
00243 const DerivState& argState = argSparsitySuperset()->state(argIndex);
00244 if (argState==ConstantDeriv)
00245 {
00246 int constArgIndex = argEval()->constantIndexMap().get(argIndex);
00247 constantCoeffFuncIndices_[i].append(fIndex);
00248 constantCoeffFuncMi_[i].append(miIndex);
00249 constantFuncCoeffs_[i].append(constArgIndex);
00250 }
00251 else
00252 {
00253 int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex);
00254 vectorCoeffFuncIndices_[i].append(fIndex);
00255 vectorCoeffFuncMi_[i].append(miIndex);
00256 vectorFuncCoeffs_[i].append(vectorArgIndex);
00257 }
00258 }
00259 else
00260 {
00261 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00262 "DiffOpEvaluator has been asked to preprocess a Deriv that "
00263 "is not a simple partial derivative. The problem child is: "
00264 << lambda);
00265 }
00266 }
00267
00268
00269 Set<MultipleDeriv> isolatedTerms
00270 = RArg.intersection(backedDerivs(resultDeriv, W1Arg, verb));
00271
00272 if (isolatedTerms.size()==0)
00273 {
00274 SUNDANCE_MSG3(verb, tab1 << "no indirect chain rule terms");
00275 }
00276 else
00277 {
00278 SUNDANCE_MSG3(verb, tab1 << "getting indirect chain rule terms");
00279 SUNDANCE_MSG3(verb, tab1 << "isolated terms = " << isolatedTerms);
00280 }
00281
00282 for (Set<MultipleDeriv>::const_iterator
00283 j=isolatedTerms.begin(); j != isolatedTerms.end(); j++)
00284 {
00285 int argIndex = argSparsitySuperset()->getIndex(*j);
00286 TEUCHOS_TEST_FOR_EXCEPTION(argIndex==-1, std::runtime_error,
00287 "Derivative " << *j << " expected in argument "
00288 "but not found");
00289 const DerivState& argState = argSparsitySuperset()->state(argIndex);
00290 if (argState==ConstantDeriv)
00291 {
00292 int constArgIndex = argEval()->constantIndexMap().get(argIndex);
00293 constantMonomials_[i].append(constArgIndex);
00294 }
00295 else
00296 {
00297 int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex);
00298 vectorMonomials_[i].append(vectorArgIndex);
00299 }
00300 }
00301 }
00302 }
00303
00304 if (verb > 2)
00305 {
00306 Out::os() << tabs << "instruction tables for summing spatial/functional chain rule" << std::endl;
00307 for (int i=0; i<this->sparsity()->numDerivs(); i++)
00308 {
00309 Tabs tab1;
00310 Out::os() << tab1 << "deriv " << sparsity()->deriv(i) << std::endl;
00311 {
00312 Tabs tab2;
00313 Out::os() << tab2 << "constant monomials: " << constantMonomials_[i]
00314 << std::endl;
00315 Out::os() << tab2 << "vector monomials: " << vectorMonomials_[i]
00316 << std::endl;
00317
00318 Out::os() << tab2 << "constant coeff functions: " << std::endl;
00319 for (int j=0; j<constantFuncCoeffs_[i].size(); j++)
00320 {
00321 Tabs tab3;
00322 Out::os() << tab3 << "func=" << constantCoeffFuncIndices_[i][j]
00323 << " mi=" << constantCoeffFuncMi_[i][j] << std::endl;
00324 }
00325 Out::os() << tab2 << "vector coeff functions: " << std::endl;
00326 for (int j=0; j<vectorFuncCoeffs_[i].size(); j++)
00327 {
00328 Tabs tab3;
00329 Out::os() << tab3 << "func=" << vectorCoeffFuncIndices_[i][j]
00330 << " mi=" << vectorCoeffFuncMi_[i][j] << std::endl;
00331 }
00332
00333 }
00334 }
00335 }
00336 }
00337
00338
00339 Deriv DiffOpEvaluator::remainder(const MultipleDeriv& big,
00340 const MultipleDeriv& little, int verb) const
00341 {
00342 Tabs tab;
00343 SUNDANCE_MSG5(verb, tab << "computing remainder: big=" << big << ", little="
00344 << little);
00345 TEUCHOS_TEST_FOR_EXCEPT(big.order()-little.order() != 1);
00346
00347 MultipleDeriv r;
00348 if (little.order()==0) r = big;
00349 else r = big.factorOutDeriv(little);
00350
00351 SUNDANCE_MSG5(verb, tab << "remainder = " << r);
00352
00353 TEUCHOS_TEST_FOR_EXCEPT(r.order() != 1);
00354
00355 return *(r.begin());
00356 }
00357
00358 Set<MultipleDeriv> DiffOpEvaluator
00359 ::increasedDerivs(const MultipleDeriv& mu,
00360 const Set<MultipleDeriv>& W1, int verb) const
00361 {
00362 Tabs tabs;
00363 SUNDANCE_MSG3(verb, tabs << "computing increased derivs");
00364 Set<MultipleDeriv> rtn;
00365 for (Set<MultipleDeriv>::const_iterator i=W1.begin(); i!=W1.end(); i++)
00366 {
00367 MultipleDeriv md = *i;
00368 TEUCHOS_TEST_FOR_EXCEPT(md.order() != 1);
00369 Deriv lambda = *(md.begin());
00370 MultipleDeriv lambdaMu = mu;
00371 lambdaMu.put(lambda);
00372 rtn.put(lambdaMu);
00373 }
00374 SUNDANCE_MSG3(verb, tabs << "increased derivs = " << rtn);
00375 return rtn;
00376 }
00377
00378 Set<MultipleDeriv> DiffOpEvaluator
00379 ::backedDerivs(const MultipleDeriv& mu,
00380 const Set<MultipleDeriv>& W1, int verb) const
00381 {
00382 Tabs tabs;
00383 SUNDANCE_MSG3(verb, tabs << "computing backed-out derivs for mu= " << mu
00384 << ", W1=" << W1);
00385 Set<MultipleDeriv> rtn;
00386 if (mu.order() != 0)
00387 {
00388 const MultiIndex& alpha = expr()->mi();
00389
00390 for (Set<MultipleDeriv>::const_iterator i=W1.begin(); i!=W1.end(); i++)
00391 {
00392 const MultipleDeriv& md = *i;
00393 TEUCHOS_TEST_FOR_EXCEPT(md.order() != 1);
00394 Deriv lambda = *(md.begin());
00395 if (lambda.isCoordDeriv()) continue;
00396 TEUCHOS_TEST_FOR_EXCEPT(!lambda.isFunctionalDeriv());
00397 FunctionIdentifier lambda_fid = lambda.fid();
00398 const MultiIndex& lambda_mi = lambda.opOnFunc().mi();
00399 for (MultipleDeriv::const_iterator j=mu.begin(); j!=mu.end(); j++)
00400 {
00401 const Deriv& d = *j;
00402 if (d.isCoordDeriv()) continue;
00403 FunctionIdentifier d_fid = d.fid();
00404 const MultiIndex& d_mi = d.opOnFunc().mi();
00405 if (d_fid != lambda_fid) continue;
00406 if (!(alpha + lambda_mi == d_mi)) continue;
00407 MultipleDeriv z = mu.factorOutDeriv(d);
00408 z.put(lambda);
00409 rtn.put(z);
00410 }
00411 }
00412 }
00413 SUNDANCE_MSG3(verb, tabs << "backed-out derivs = " << rtn);
00414 return rtn;
00415 }
00416
00417
00418
00419 void DiffOpEvaluator::internalEval(const EvalManager& mgr,
00420 Array<double>& constantResults,
00421 Array<RCP<EvalVector> >& vectorResults) const
00422 {
00423 Tabs tabs;
00424 SUNDANCE_MSG1(mgr.verb(), tabs << "DiffOpEvaluator::eval() expr="
00425 << expr()->toString());
00426
00427
00428 Array<RCP<EvalVector> > argVectorResults;
00429 Array<double> argConstantResults;
00430
00431 SUNDANCE_MSG2(mgr.verb(), tabs << "evaluating operand");
00432 evalOperand(mgr, argConstantResults, argVectorResults);
00433
00434
00435 if (mgr.verb() > 2)
00436 {
00437 Tabs tab1;
00438 Out::os() << tabs << "DiffOp operand results" << std::endl;
00439 mgr.showResults(Out::os(), argSparsitySuperset(), argVectorResults,
00440 argConstantResults);
00441 }
00442
00443
00444
00445
00446 SUNDANCE_MSG2(mgr.verb(), tabs << "evaluating discrete functions, num funcs= " << funcEvaluators_.size());
00447
00448 Array<Array<RCP<EvalVector> > > funcVectorResults(funcEvaluators_.size());
00449 Array<double> funcConstantResults;
00450 for (int i=0; i<funcEvaluators_.size(); i++)
00451 {
00452 funcEvaluators_[i]->eval(mgr, funcConstantResults, funcVectorResults[i]);
00453 }
00454
00455 constantResults.resize(this->sparsity()->numConstantDerivs());
00456 vectorResults.resize(this->sparsity()->numVectorDerivs());
00457
00458 SUNDANCE_MSG3(mgr.verb(), tabs << "summing spatial/functional chain rule");
00459
00460 for (int i=0; i<this->sparsity()->numDerivs(); i++)
00461 {
00462 Tabs tab1;
00463 SUNDANCE_MSG4(mgr.verb(), tab1 << "working on deriv "
00464 << this->sparsity()->deriv(i));
00465
00466
00467 SUNDANCE_MSG4(mgr.verb(), tab1 << "have " << constantMonomials_[i].size()
00468 << " constant monomials");
00469 double constantVal = 0.0;
00470 for (int j=0; j<constantMonomials_[i].size(); j++)
00471 {
00472 SUNDANCE_MSG4(mgr.verb(), tab1 << "adding in constant monomial (index "
00473 << constantMonomials_[i][j]
00474 << " in arg results)");
00475 constantVal += argConstantResults[constantMonomials_[i][j]];
00476 }
00477 if (isConstant_[i])
00478 {
00479 constantResults[resultIndices_[i]] = constantVal;
00480 SUNDANCE_MSG4(mgr.verb(), tab1 << "result is constant: value="
00481 << constantVal);
00482 continue;
00483 }
00484
00485 RCP<EvalVector> result;
00486 bool vecHasBeenAllocated = false;
00487
00488
00489 const Array<int>& vm = vectorMonomials_[i];
00490 SUNDANCE_MSG4(mgr.verb(), tab1 << "have " << vm.size()
00491 << " vector monomials");
00492 for (int j=0; j<vm.size(); j++)
00493 {
00494 Tabs tab2;
00495
00496 const RCP<EvalVector>& v = argVectorResults[vm[j]];
00497
00498 SUNDANCE_MSG4(mgr.verb(), tab2 << "found vec monomial term " << v->str());
00499
00500
00501
00502 if (!vecHasBeenAllocated)
00503 {
00504 SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
00505 result = mgr.popVector();
00506 vecHasBeenAllocated = true;
00507 if (isZero(constantVal))
00508 {
00509 result->setTo_V(v.get());
00510 }
00511 else
00512 {
00513 result->setTo_S_add_V(constantVal, v.get());
00514 }
00515 }
00516 else
00517 {
00518 result->add_V(v.get());
00519 }
00520 SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
00521 }
00522
00523
00524 const Array<int>& cf = constantFuncCoeffs_[i];
00525 SUNDANCE_MSG4(mgr.verb(), tab1 << "adding " << cf.size()
00526 << " func terms with constant coeffs");
00527 for (int j=0; j<cf.size(); j++)
00528 {
00529 Tabs tab2;
00530 const double& coeff = argConstantResults[cf[j]];
00531 int fIndex = constantCoeffFuncIndices_[i][j];
00532 int miIndex = constantCoeffFuncMi_[i][j];
00533 const RCP<EvalVector>& fValue
00534 = funcVectorResults[fIndex][miIndex];
00535
00536 SUNDANCE_MSG4(mgr.verb(), tab2 << "found term: coeff= "
00537 << coeff << ", func value=" << fValue->str());
00538
00539
00540
00541 if (!vecHasBeenAllocated)
00542 {
00543 SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
00544 result = mgr.popVector();
00545 vecHasBeenAllocated = true;
00546 if (isOne(coeff))
00547 {
00548 if (isZero(constantVal))
00549 {
00550 result->setTo_V(fValue.get());
00551 }
00552 else
00553 {
00554 result->setTo_S_add_V(constantVal, fValue.get());
00555 }
00556 }
00557 else
00558 {
00559 if (isZero(constantVal))
00560 {
00561 result->setTo_SV(coeff, fValue.get());
00562 }
00563 else
00564 {
00565 result->setTo_S_add_SV(constantVal, coeff, fValue.get());
00566 }
00567 }
00568 }
00569 else
00570 {
00571 if (isOne(coeff))
00572 {
00573 result->add_V(fValue.get());
00574 }
00575 else
00576 {
00577 result->add_SV(coeff, fValue.get());
00578 }
00579 }
00580 SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
00581 }
00582
00583
00584
00585 const Array<int>& vf = vectorFuncCoeffs_[i];
00586 SUNDANCE_MSG4(mgr.verb(), tab1 << "adding " << vf.size()
00587 << " func terms with vector coeffs");
00588 for (int j=0; j<vf.size(); j++)
00589 {
00590 Tabs tab2;
00591
00592 const RCP<EvalVector>& coeff = argVectorResults[vf[j]];
00593 int fIndex = vectorCoeffFuncIndices_[i][j];
00594 int miIndex = vectorCoeffFuncMi_[i][j];
00595 const RCP<EvalVector>& fValue
00596 = funcVectorResults[fIndex][miIndex];
00597
00598 SUNDANCE_MSG4(mgr.verb(), tab2 << "found term: coeff= "
00599 << coeff->str() << ", func value="
00600 << fValue->str());
00601
00602
00603
00604 if (!vecHasBeenAllocated)
00605 {
00606 SUNDANCE_MSG4(mgr.verb(), tab2 << "allocated result vector");
00607 result = mgr.popVector();
00608 vecHasBeenAllocated = true;
00609 result->setTo_VV(coeff.get(), fValue.get());
00610 }
00611 else
00612 {
00613 result->add_VV(coeff.get(), fValue.get());
00614 }
00615 SUNDANCE_MSG4(mgr.verb(), tab2 << "result is " << result->str());
00616 }
00617
00618 TEUCHOS_TEST_FOR_EXCEPTION(!vecHasBeenAllocated, std::logic_error,
00619 "created empty vector in DiffOpEvaluator::internalEval");
00620 vectorResults[resultIndices_[i]] = result;
00621 }
00622
00623 if (mgr.verb() > 1)
00624 {
00625 Out::os() << tabs << "diff op results" << std::endl;
00626 mgr.showResults(Out::os(), sparsity(), vectorResults,
00627 constantResults);
00628 }
00629 SUNDANCE_MSG1(mgr.verb(), tabs << "done spatial/functional chain rule");
00630 }
00631
00632
00633
00634 void DiffOpEvaluator::resetNumCalls() const
00635 {
00636 argEval()->resetNumCalls();
00637 for (int i=0; i<funcEvaluators_.size(); i++)
00638 {
00639 funcEvaluators_[i]->resetNumCalls();
00640 }
00641 Evaluator::resetNumCalls();
00642 }