/** * Update the cost function, derivatives and hessian by adding values calculated * on a domain. * @param function :: Function to use to calculate the value and the derivatives * @param domain :: The domain. * @param values :: The fit function values * @param evalFunction :: Flag to evaluate the function * @param evalDeriv :: Flag to evaluate the derivatives * @param evalHessian :: Flag to evaluate the Hessian */ void CostFuncLeastSquares::addValDerivHessian( API::IFunction_sptr function, API::FunctionDomain_sptr domain, API::FunctionValues_sptr values, bool evalFunction , bool evalDeriv, bool evalHessian) const { UNUSED_ARG(evalDeriv); size_t np = function->nParams(); // number of parameters size_t ny = domain->size(); // number of data points Jacobian jacobian(ny,np); if (evalFunction) { function->function(*domain,*values); } function->functionDeriv(*domain,jacobian); size_t iActiveP = 0; double fVal = 0.0; if (debug) { std::cerr << "Jacobian:\n"; for(size_t i = 0; i < ny; ++i) { for(size_t ip = 0; ip < np; ++ip) { if ( !m_function->isActive(ip) ) continue; std::cerr << jacobian.get(i,ip) << ' '; } std::cerr << std::endl; } } for(size_t ip = 0; ip < np; ++ip) { if ( !function->isActive(ip) ) continue; double d = 0.0; for(size_t i = 0; i < ny; ++i) { double calc = values->getCalculated(i); double obs = values->getFitData(i); double w = values->getFitWeight(i); double y = ( calc - obs ) * w; d += y * jacobian.get(i,ip) * w; if (iActiveP == 0 && evalFunction) { fVal += y * y; } } PARALLEL_CRITICAL(der_set) { double der = m_der.get(iActiveP); m_der.set(iActiveP, der + d); } //std::cerr << "der " << ip << ' ' << der[iActiveP] << std::endl; ++iActiveP; } if (evalFunction) { PARALLEL_ATOMIC m_value += 0.5 * fVal; } if (!evalHessian) return; //size_t na = m_der.size(); // number of active parameters size_t i1 = 0; // active parameter index for(size_t i = 0; i < np; ++i) // over parameters { if ( !function->isActive(i) ) continue; size_t i2 = 0; // active parameter index for(size_t j = 0; j <= i; ++j) // over ~ half of parameters { if ( !function->isActive(j) ) continue; double d = 0.0; for(size_t k = 0; k < ny; ++k) // over fitting data { double w = values->getFitWeight(k); d += jacobian.get(k,i) * jacobian.get(k,j) * w * w; } PARALLEL_CRITICAL(hessian_set) { double h = m_hessian.get(i1,i2); m_hessian.set(i1,i2, h + d); //std::cerr << "hess " << i1 << ' ' << i2 << std::endl; if (i1 != i2) { m_hessian.set(i2,i1,h + d); } } ++i2; } ++i1; } }
/** * Update the cost function, derivatives and hessian by adding values calculated * on a domain. * @param function :: Function to use to calculate the value and the derivatives * @param domain :: The domain. * @param values :: The fit function values * @param evalDeriv :: Flag to evaluate the derivatives * @param evalHessian :: Flag to evaluate the Hessian */ void CostFuncLeastSquares::addValDerivHessian(API::IFunction_sptr function, API::FunctionDomain_sptr domain, API::FunctionValues_sptr values, bool evalDeriv, bool evalHessian) const { UNUSED_ARG(evalDeriv); function->function(*domain, *values); size_t np = function->nParams(); // number of parameters size_t ny = values->size(); // number of data points Jacobian jacobian(ny, np); function->functionDeriv(*domain, jacobian); size_t iActiveP = 0; double fVal = 0.0; std::vector<double> weights = getFitWeights(values); for (size_t ip = 0; ip < np; ++ip) { if (!function->isActive(ip)) continue; double d = 0.0; for (size_t i = 0; i < ny; ++i) { double calc = values->getCalculated(i); double obs = values->getFitData(i); double w = weights[i]; double y = (calc - obs) * w; d += y * jacobian.get(i, ip) * w; if (iActiveP == 0) { fVal += y * y; } } PARALLEL_CRITICAL(der_set) { double der = m_der.get(iActiveP); m_der.set(iActiveP, der + d); } ++iActiveP; } PARALLEL_ATOMIC m_value += 0.5 * fVal; if (!evalHessian) return; size_t i1 = 0; // active parameter index for (size_t i = 0; i < np; ++i) // over parameters { if (!function->isActive(i)) continue; size_t i2 = 0; // active parameter index for (size_t j = 0; j <= i; ++j) // over ~ half of parameters { if (!function->isActive(j)) continue; double d = 0.0; for (size_t k = 0; k < ny; ++k) // over fitting data { double w = weights[k]; d += jacobian.get(k, i) * jacobian.get(k, j) * w * w; } PARALLEL_CRITICAL(hessian_set) { double h = m_hessian.get(i1, i2); m_hessian.set(i1, i2, h + d); if (i1 != i2) { m_hessian.set(i2, i1, h + d); } } ++i2; } ++i1; } }