/** * 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
/** * 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
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