void EvaluatableExpr::setupEval(const EvalContext& context) const { Tabs tabs0(0); int verb = context.evalSetupVerbosity(); SUNDANCE_MSG1(verb, tabs0 << "setupEval() for " << this->toString()); if (!evaluators_.containsKey(context)) { Tabs tabs; SUNDANCE_MSG2(verb, tabs << "creating new evaluator..."); SUNDANCE_MSG2(verb, tabs << "my sparsity superset = " << std::endl << *sparsitySuperset(context)); RCP<Evaluator> eval; if (sparsitySuperset(context)->numDerivs()>0) { SUNDANCE_MSG2(verb, tabs << "calling createEvaluator()"); eval = rcp(createEvaluator(this, context)); } else { SUNDANCE_MSG2(verb, tabs << "EE: no results needed... creating null evaluator"); eval = rcp(new NullEvaluator()); } evaluators_.put(context, eval); } else { Tabs tabs; SUNDANCE_MSG2(verb, tabs << "reusing existing evaluator..."); } }
ProductEvaluator::ProductEvaluator(const ProductExpr* expr, const EvalContext& context) : BinaryEvaluator<ProductExpr>(expr, context), maxOrder_(this->sparsity()->maxOrder()), resultIndex_(maxOrder_+1), resultIsConstant_(maxOrder_+1), hasWorkspace_(maxOrder_+1), workspaceIsLeft_(maxOrder_+1), workspaceIndex_(maxOrder_+1), workspaceCoeffIndex_(maxOrder_+1), workspaceCoeffIsConstant_(maxOrder_+1), ccTerms_(maxOrder_+1), cvTerms_(maxOrder_+1), vcTerms_(maxOrder_+1), vvTerms_(maxOrder_+1), startingVectors_(maxOrder_+1), startingParities_(maxOrder_+1) { int verb = context.evalSetupVerbosity(); try { Tabs tabs(0); { Tabs tab; Tabs tabz; SUNDANCE_MSG1(verb, tabs << "initializing product evaluator for " << expr->toString()); SUNDANCE_MSG2(verb, tab << "return sparsity " << std::endl << tabz << *(this->sparsity)()); SUNDANCE_MSG2(verb, tab << "left sparsity " << std::endl << tabz << *(leftSparsity()) << std::endl << tabz << "right sparsity " << std::endl << tabz << *(rightSparsity())); SUNDANCE_MSG3(verb, tab << "left vector index map " << leftEval()->vectorIndexMap() << std::endl << tabz << "right vector index map " << rightEval()->vectorIndexMap() << std::endl << tabz << "left constant index map " << leftEval()->constantIndexMap() << std::endl << tabz << "right constant index map " << rightEval()->constantIndexMap()); } int vecResultIndex = 0; int constResultIndex = 0; for (int i=0; i<this->sparsity()->numDerivs(); i++) { Tabs tab0; const MultipleDeriv& d = this->sparsity()->deriv(i); SUNDANCE_MSG2(verb, tabs << std::endl << tabs << "finding rules for deriv " << d); int order = d.order(); /* Determine the index into which the result will be written */ bool resultIsConstant = this->sparsity()->state(i)==ConstantDeriv; resultIsConstant_[order].append(resultIsConstant); if (resultIsConstant) { SUNDANCE_MSG3(verb, tab0 << std::endl << tab0 << "result will be in constant index " << constResultIndex); resultIndex_[order].append(constResultIndex); addConstantIndex(i, constResultIndex); constResultIndex++; } else { SUNDANCE_MSG3(verb, tab0 << std::endl << tab0 << "result will be in constant index " << vecResultIndex); resultIndex_[order].append(vecResultIndex); addVectorIndex(i, vecResultIndex); vecResultIndex++; } /* If possible, we want to do the calculations in-place, writing into * one of the two operand's results vectors for the same derivative. * Provided that we process derivatives in descending order, it is * safe to destroy the operands' result vectors. */ int dnLeftIndex = leftSparsity()->getIndex(d); int dnRightIndex = rightSparsity()->getIndex(d); bool hasVectorWorkspace = false; bool workspaceIsLeft = false; int workspaceIndex = -1; int workspaceCoeffIndex = -1; bool workspaceCoeffIsConstant = false; bool dnLeftIsConst = false; if (dnLeftIndex != -1) { dnLeftIsConst = leftSparsity()->state(dnLeftIndex)==ConstantDeriv; } bool dnRightIsConst = false; if (dnRightIndex != -1) { dnRightIsConst = rightSparsity()->state(dnRightIndex)==ConstantDeriv; } /* First try to use the left result as a workspace */ if (dnLeftIndex != -1 && !dnLeftIsConst && rightSparsity()->containsDeriv(MultipleDeriv())) { /* We can write onto left vector */ hasVectorWorkspace = true; workspaceIndex = leftEval()->vectorIndexMap().get(dnLeftIndex); SUNDANCE_MSG3(verb, tab0 << "using left as workspace"); workspaceIsLeft = true; int d0RightIndex = rightSparsity()->getIndex(MultipleDeriv()); bool d0RightIsConst = rightSparsity()->state(d0RightIndex)==ConstantDeriv; workspaceCoeffIsConstant = d0RightIsConst; if (d0RightIsConst) { workspaceCoeffIndex = rightEval()->constantIndexMap().get(d0RightIndex); } else { workspaceCoeffIndex = rightEval()->vectorIndexMap().get(d0RightIndex); } } /* If the left didn't provide a workspace, try the right */ if (!hasVectorWorkspace && dnRightIndex != -1 && !dnRightIsConst && leftSparsity()->containsDeriv(MultipleDeriv())) { /* We can write onto right vector */ hasVectorWorkspace = true; workspaceIndex = rightEval()->vectorIndexMap().get(dnRightIndex); workspaceIsLeft = false; SUNDANCE_MSG3(verb, tab0 << "using right as workspace"); int d0LeftIndex = leftSparsity()->getIndex(MultipleDeriv()); bool d0LeftIsConst = leftSparsity()->state(d0LeftIndex)==ConstantDeriv; workspaceCoeffIsConstant = d0LeftIsConst; if (d0LeftIsConst) { workspaceCoeffIndex = leftEval()->constantIndexMap().get(d0LeftIndex); } else { workspaceCoeffIndex = leftEval()->vectorIndexMap().get(d0LeftIndex); } } if (hasVectorWorkspace && verb > 2) { std::string wSide = "right"; MultipleDeriv wsDeriv; if (workspaceIsLeft) { wSide = "left"; wsDeriv = leftSparsity()->deriv(dnLeftIndex); } else { wsDeriv = rightSparsity()->deriv(dnRightIndex); } SUNDANCE_MSG2(verb, tab0 << "has workspace vector: " << wSide << " deriv= " << wsDeriv << ", coeff index= " << workspaceCoeffIndex); } else { SUNDANCE_MSG2(verb, tab0 << "has no workspace vector"); } hasWorkspace_[order].append(hasVectorWorkspace); workspaceIsLeft_[order].append(workspaceIsLeft); workspaceIndex_[order].append(workspaceIndex); workspaceCoeffIndex_[order].append(workspaceCoeffIndex); workspaceCoeffIsConstant_[order].append(workspaceCoeffIsConstant); ProductRulePerms perms; d.productRulePermutations(perms); SUNDANCE_MSG4(verb, tabs << "product rule permutations " << perms); Array<Array<int> > ccTerms; Array<Array<int> > cvTerms; Array<Array<int> > vcTerms; Array<Array<int> > vvTerms; Array<int> startingVector; ProductParity startingParity; bool hasStartingVector = false; for (ProductRulePerms::const_iterator iter = perms.begin(); iter != perms.end(); iter++) { Tabs tab1; MultipleDeriv dLeft = iter->first.first(); MultipleDeriv dRight = iter->first.second(); int multiplicity = iter->second; /* skip this combination if we've already pulled it out * for workspace */ if (hasVectorWorkspace && workspaceIsLeft && dLeft.order()==order) continue; if (hasVectorWorkspace && !workspaceIsLeft && dRight.order()==order) continue; if (!leftSparsity()->containsDeriv(dLeft) || !rightSparsity()->containsDeriv(dRight)) continue; int iLeft = leftSparsity()->getIndex(dLeft); int iRight = rightSparsity()->getIndex(dRight); if (iLeft==-1 || iRight==-1) continue; SUNDANCE_MSG4(verb, tab1 << "left deriv=" << dLeft); SUNDANCE_MSG4(verb, tab1 << "right deriv=" << dRight); bool leftIsConst = leftSparsity()->state(iLeft)==ConstantDeriv; bool rightIsConst = rightSparsity()->state(iRight)==ConstantDeriv; if (leftIsConst) { Tabs tab2; SUNDANCE_MSG4(verb, tab2 << "left is const"); int leftIndex = leftEval()->constantIndexMap().get(iLeft); if (rightIsConst) { SUNDANCE_MSG4(verb, tab2 << "right is const"); int rightIndex = rightEval()->constantIndexMap().get(iRight); ccTerms.append(tuple(leftIndex, rightIndex, multiplicity)); } else { SUNDANCE_MSG4(verb, tab2 << "right is vec"); int rightIndex = rightEval()->vectorIndexMap().get(iRight); if (!hasVectorWorkspace && !hasStartingVector) { SUNDANCE_MSG4(verb, tab1 << "found c-v starting vec"); startingVector = tuple(leftIndex, rightIndex, multiplicity); hasStartingVector = true; startingParity = ConstVec; } else { SUNDANCE_MSG4(verb, tab1 << "found c-v term"); cvTerms.append(tuple(leftIndex, rightIndex, multiplicity)); } } } else { Tabs tab2; SUNDANCE_MSG4(verb, tab2 << "left is vec"); int leftIndex = leftEval()->vectorIndexMap().get(iLeft); if (rightIsConst) { SUNDANCE_MSG4(verb, tab2 << "right is const"); int rightIndex = rightEval()->constantIndexMap().get(iRight); if (!hasVectorWorkspace && !hasStartingVector) { SUNDANCE_MSG4(verb, tab1 << "found v-c starting vec"); startingVector = tuple(leftIndex, rightIndex, multiplicity); hasStartingVector = true; startingParity = VecConst; } else { SUNDANCE_MSG4(verb, tab1 << "found v-c term"); vcTerms.append(tuple(leftIndex, rightIndex, multiplicity)); } } else { SUNDANCE_MSG4(verb, tab2 << "right is vec"); int rightIndex = rightEval()->vectorIndexMap().get(iRight); if (!hasVectorWorkspace && !hasStartingVector) { SUNDANCE_MSG4(verb, tab1 << "found v-v starting vec"); startingVector = tuple(leftIndex, rightIndex, multiplicity); hasStartingVector = true; startingParity = VecVec; } else { SUNDANCE_MSG4(verb, tab1 << "found v-v term"); vvTerms.append(tuple(leftIndex, rightIndex, multiplicity)); } } } } ccTerms_[order].append(ccTerms); cvTerms_[order].append(cvTerms); vcTerms_[order].append(vcTerms); vvTerms_[order].append(vvTerms); startingVectors_[order].append(startingVector); startingParities_[order].append(startingParity); if (verb > 2) { Tabs tab0; Out::os() << tab0 << "deriv " << i << " order=" << order ; if (resultIsConstant) { Out::os() << " constant result, index= "; } else { Out::os() << " vector result, index= "; } Out::os() << resultIndex_[order] << std::endl; { Tabs tab1; if (hasStartingVector) { Out::os() << tab1 << "starting vector " << startingVector << std::endl; } Out::os() << tab1 << "c-c terms " << ccTerms << std::endl; Out::os() << tab1 << "c-v terms " << cvTerms << std::endl; Out::os() << tab1 << "v-c terms " << vcTerms << std::endl; Out::os() << tab1 << "v-v terms " << vvTerms << std::endl; } } } if (verb > 2) { Out::os() << tabs << "maps: " << std::endl; Out::os() << tabs << "vector index map " << vectorIndexMap() << std::endl; Out::os() << tabs << "constant index map " << constantIndexMap() << std::endl; } } catch(std::exception& e) { TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "exception detected in ProductEvaluator: expr=" << expr->toString() << std::endl << "exception=" << e.what()); } }