/** * Marginalise a maxsum::DiscreteFunction by averaging. * This function reduces the domain of inFun to that of outFun by * averaging, and stores the result in outFun. * @pre variables in domain of outFun are a subset of variables in inFun. * @post previous content of outFun is overwritten. * @post The domains of outFun and inFun remain unchanged. * @param[in] inFun function to marginalise * @param[out] outFun maxsum::DiscreteFunction in which to store result. * @throws maxsum::BadDomainException is the domain of outFun is not a * subset of inFun. * @see maxsum::marginal() * @see maxsum::minMarginal() * @see maxsum::maxMarginal() */ void maxsum::meanMarginal ( const DiscreteFunction& inFun, DiscreteFunction& outFun ) { //************************************************************************** // Marginalise over free domain by summation //************************************************************************** marginal(inFun,add_m,outFun); //************************************************************************** // Now each element of the output is the sum over the relevant values // in the input function, so we need to normalise to get the average. // // Note: another way to do this would be to marginalise using a functor // class Mean, which is constructed using the size of the free domain, so // that it knows the number of values to average over. This might be // more numerically stable, and also only requires one pass rather than // two. However, its not clear that the extra complexity would be worth it. //************************************************************************** ValType w = outFun.domainSize(); w = w / inFun.domainSize(); for(int k=0; k<outFun.domainSize(); ++k) { outFun(k) *= w; } } // meanMarginal
/** * Check that two maxsum::DiscreteFunction objects are equal within a * specified tolerance. This function returns true if and only if, for all * <code>k</code>: * <p> * <code> * -tol < 1-f1(k)/f2(k) < tol * </code> * </p> * @param[in] f1 First function to compare * @param[in] f2 Second function to compare * @param[in] tol tolerance used for comparing values * @see maxsum::DEFAULT_VALUE_TOLERANCE */ bool maxsum::equalWithinTolerance ( const DiscreteFunction& f1, const DiscreteFunction& f2, ValType tol ) { //*************************************************************************** // Iterator over the combined domain of f1 and f2 //*************************************************************************** DomainIterator it(f1); it.addVars(f2.varBegin(),f2.varEnd()); while(it.hasNext()) { //************************************************************************ // Check that the difference in value for the current positions are // equal within tolerance. //************************************************************************ ValType diff = 1-f1(it)/f2(it); if( (diff > tol) || (diff < -tol) ) { return false; } ++it; } // for loop //*************************************************************************** // If we get to here, everything is equal within tolerance //*************************************************************************** return true; } // function equalWithinTolerance
void updateDiscreteFunction(const Expr& newVals, Expr old) { const DiscreteFunction* in = DiscreteFunction::discFunc(newVals); TEST_FOR_EXCEPT(in==0); DiscreteFunction* out = DiscreteFunction::discFunc(old); TEST_FOR_EXCEPT(out==0); Vector<double> vec = in->getVector(); out->setVector(vec); }
/** * Check that two maxsum::DiscreteFunction objects have the same domain. * Two functions have the same domain, if they depend on the same set of * variables. * @param[in] f1 First function to compare * @param[in] f2 Second functions to compare * @returns true if both function have the same domain. */ bool maxsum::sameDomain(const DiscreteFunction& f1, const DiscreteFunction& f2) { if(f1.noVars()!=f2.noVars()) { return false; } return std::equal(f1.varBegin(),f1.varEnd(),f2.varBegin()); } // function sameDomain
Precision Stencil::apply( const DiscreteFunction& u, const Position pos, const Index sx, const Index sy) const { const Index nx = u.getNx(); const Index ny = u.getNy(); const Precision hx = u.getHx(); const Precision hy = u.getHy(); const Point origin = u.getOrigin(); NumericArray opL = getL(pos,sx,sy,nx,ny,hx,hy,origin); PositionArray jX = getJx(pos,nx,ny); PositionArray jY = getJy(pos,nx,ny); Precision result = 0.0; for (Index i = 0; i<opL.size(); ++i) result+=opL[i]*u(sx+jX[i],sy+jY[i]); return result; }
/** * Construct Domain Iterator using domain of a given function. * This is more efficient that creating from sratch. * @param[in] fun Function whose domain should be copied. */ DomainIterator::DomainIterator(const DiscreteFunction& fun) : vars_i(fun.varBegin(),fun.varEnd()), // copy variables subInd_i(fun.noVars(),0), // set all subindices to zero ind_i(0), // set linear index to zero fixed_i(fun.noVars(),false), // all variables are initially free sizes_i(fun.sizeBegin(),fun.sizeEnd()), // copy variable sizes finished_i(false) // iterator is not done yet {} // nothing left to do in constructor body
/** * Returns the element-wise maximum of this function and a specified * scalar. That is, if M = N.max(s) then M(k)=max(N(k),s). * @param[in] s the scalar value to compare * @param[out] result the result of the operation. */ void DiscreteFunction::max(const ValType s, DiscreteFunction& result) { // If possible use eigen array op #if ((EIGEN_WORLD_VERSION == 3) && (EIGEN_MAJOR_VERSION >= 1)) || (EIGEN_WORLD_VERSION > 3) result.values_i = this->values_i.max(s); // Otherwise use basic implementation #else result = *this; for(int k=0; k<result.domainSize(); k++) { result(k) = (s > result(k)) ? s : result(k); } #endif } // max
/** * Make the domain of this function include the domain of another. * If necessary, the domain of this function is expanded to include the * domain of the parameter fun. * @param[in] fun function whose domain we want to expand to. * @todo Make this more efficient by using fun.size_i cache. * @post domain of this is union of its previous domain, with that of fun. */ void DiscreteFunction::expand(const DiscreteFunction& fun) { this->expand(fun.varBegin(),fun.varEnd()); }
int testMarginals(const DiscreteFunction inFun) { int errorCount = 0; //*************************************************************************** // Calculate aggregates over entire domain of input function //*************************************************************************** double mean=0; double max=-DBL_MAX; double maxnorm=-DBL_MAX; long argmax=-1; double domainSize = inFun.domainSize(); for(int k=0; k<inFun.domainSize(); ++k) { double val = inFun(k); double absVal = std::fabs(val); mean += val / domainSize; if(maxnorm<absVal) { maxnorm=absVal; } if(max<val) { max=val; argmax=k; } } // for loop //*************************************************************************** // Check results for consistency //*************************************************************************** const double funMean = inFun.mean(); const double funMax = inFun.max(); const double funMaxnorm = inFun.maxnorm(); const long funArgMax = inFun.argmax(); if(!nearlyEqual_m(max,funMax)) { std::cout << "max: " << funMax << " should be " << max << '\n'; ++errorCount; } if(!nearlyEqual_m(mean,funMean)) { std::cout << "mean: " << funMean << " should be " << mean << '\n'; ++errorCount; } if(!nearlyEqual_m(maxnorm,funMaxnorm)) { std::cout << "maxnorm: " << funMaxnorm << " should be " << maxnorm << '\n'; ++errorCount; } if(funArgMax!=argmax) { std::cout << "argmax: " << funArgMax << " should be " << argmax << '\n'; ++errorCount; } //*************************************************************************** // Return number of errors //*************************************************************************** return errorCount; } // testMarginals
double FunctionalEvaluator::fdGradientCheck(double h) const { bool showAll = false; Tabs tabs; double f0, fPlus, fMinus; Expr gradF0 = evalGradient(f0); FancyOStream& os = Out::os(); DiscreteFunction* df = DiscreteFunction::discFunc(varValues_); DiscreteFunction* dg = DiscreteFunction::discFunc(gradF0); Vector<double> x = df->getVector(); Vector<double> x0 = x.copy(); Vector<double> gf = dg->getVector(); RCP<GhostView<double> > xView = df->ghostView(); RCP<GhostView<double> > gradF0View = dg->ghostView(); TEUCHOS_TEST_FOR_EXCEPTION(xView.get() == 0, std::runtime_error, "bad pointer in FunctionalEvaluator::fdGradientCheck"); TEUCHOS_TEST_FOR_EXCEPTION(gradF0View.get() == 0, std::runtime_error, "bad pointer in FunctionalEvaluator::fdGradientCheck"); int nTot = x.space().dim(); int n = x.space().numLocalElements(); int lowestIndex = x.space().baseGlobalNaturalIndex(); os << tabs << "doing fd check: h=" << h << std::endl; Array<double> df_dx(n); int localIndex = 0; for (int globalIndex=0; globalIndex<nTot; globalIndex++) { double tmp=0.0; bool isLocal = globalIndex >= lowestIndex && globalIndex < (lowestIndex+n); if (isLocal) { tmp = xView->getElement(globalIndex); loadable(x)->setElement(globalIndex, tmp + h); } df->setVector(x); fPlus = evaluate(); if (isLocal) { loadable(x)->setElement(globalIndex, tmp - h); } df->setVector(x); fMinus = evaluate(); if (isLocal) { df_dx[localIndex] = (fPlus - fMinus)/2.0/h; os << "g=" << setw(5) << globalIndex << ", l=" << setw(5) << localIndex << " f0=" << setw(12) << f0 << " fPlus=" << setw(12) << fPlus << " fMinus=" << setw(12) << fMinus << " df_dx=" << setw(12) << df_dx[localIndex] << std::endl; if (showAll) { os << "i " << globalIndex << " x_i=" << tmp << " f(x)=" << f0 << " f(x+h)=" << fPlus << " f(x-h)=" << fMinus << std::endl; } loadable(x)->setElement(globalIndex, tmp); localIndex++; } df->setVector(x); } double localMaxErr = 0.0; showAll = true; VectorSpace<double> space = x.space(); for (int i=0; i<space.numLocalElements(); i++) { double num = fabs(df_dx[i]-gf[i]); double den = fabs(df_dx[i]) + fabs(gf[i]) + 1.0e-14; double r = 0.0; if (fabs(den) > 1.0e-16) r = num/den; else r = 1.0; if (showAll) { os << "i " << i; os << " FD=" << df_dx[i] << " grad=" << gf[i] << " r=" << r << std::endl; } if (localMaxErr < r) localMaxErr = r; } os << "local max error = " << localMaxErr << std::endl; double maxErr = localMaxErr; df->mesh().comm().allReduce((void*) &localMaxErr, (void*) &maxErr, 1, MPIDataType::doubleType(), MPIOp::maxOp()); os << tabs << "fd check: max error = " << maxErr << std::endl; return maxErr; }
/** * Accessor method for factor function. * @param[in] id the unique identifier of the desired factor. * @param[in] factor the function representing this factor. * @returns a reference to the function associated with the factor with * unique identifier <code>id</code>. * @post A copy of <code>factor</code> is stored internally by * this maxsum::MaxSumController and used to form part of a factor graph. * @post Any previous value of the specified factor is overwritten. */ void MaxSumController::setFactor(FactorID id, const DiscreteFunction& factor) { //*************************************************************************** // Set the specified factor. (Note: oldValue is created automatically if // necessary). //*************************************************************************** DiscreteFunction& oldValue = factors_i[id]; //*************************************************************************** // If this factor is currently related to any variables that it is no // longer related to, delete the appropriate edges. //*************************************************************************** std::vector<VarID> toRemove(oldValue.noVars()); std::set_difference(oldValue.varBegin(),oldValue.varEnd(), factor.varBegin(),factor.varEnd(),toRemove.begin()); for(std::vector<VarID>::const_iterator it=toRemove.begin(); it!=toRemove.end(); ++it) { //************************************************************************ // Remove the redundant edges from the postoffice graphs //************************************************************************ fac2varMsgs_i.removeEdge(id,*it); var2facMsgs_i.removeEdge(*it,id); //************************************************************************ // If the variable is no longer related to any factors, then we remove // it from the value list. //************************************************************************ if(!var2facMsgs_i.hasSender(*it)) { values_i.erase(*it); } } // for loop //*************************************************************************** // For each variable in this factor's domain //*************************************************************************** for(DiscreteFunction::VarIterator it=factor.varBegin(); it!=factor.varEnd(); ++it) { //************************************************************************ // Initialise input and output messages between the factor and // the current variable //************************************************************************ DiscreteFunction msgTemplate(*it,0); fac2varMsgs_i.addEdge(id,*it,msgTemplate); var2facMsgs_i.addEdge(*it,id,msgTemplate); //************************************************************************ // Touch the variable to ensure that it is in the value list. //************************************************************************ ValueMap::iterator pos = values_i.find(*it); if(values_i.end()==pos) { values_i[*it]=0; } } // for loop //*************************************************************************** // Set the specified factor to its new value. //*************************************************************************** factors_i[id] = factor; //*************************************************************************** // Tell everyone to recheck their mail. Telling everyone to recheck is the // safest option, because the factor graph may have changed. //*************************************************************************** var2facMsgs_i.notifyAll(); } // function setFactor