Program Listing for File hierarchicalOptimization.h¶
↰ Return to documentation for file (include/parpeamici/hierarchicalOptimization.h
)
#ifndef HIERARCHICALOPTIMIZATION_H
#define HIERARCHICALOPTIMIZATION_H
#include <parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h>
#include <parpeamici/multiConditionProblem.h>
#include <parpeoptimization/optimizationProblem.h>
#include <gsl/gsl-lite.hpp>
#include <cmath>
#include <memory>
#include <numeric>
namespace parpe {
enum class ErrorModel
{
normal
}; // TODO logNormal, Laplace
class AnalyticalParameterProvider;
class AnalyticalParameterHdf5Reader;
class HierarchicalOptimizationProblemWrapper;
class HierarchicalOptimizationWrapper;
class HierarchicalOptimizationWrapper : public GradientFunction
{
public:
HierarchicalOptimizationWrapper(
AmiciSummedGradientFunction *wrapped_function,
int numConditions = 0,
int numObservables = 0);
HierarchicalOptimizationWrapper(
AmiciSummedGradientFunction *wrapped_function,
const H5::H5File& file,
const std::string& hdf5RootPath,
int numConditions,
int numObservables,
ErrorModel errorModel);
HierarchicalOptimizationWrapper(
AmiciSummedGradientFunction *wrapped_function,
std::unique_ptr<AnalyticalParameterProvider> scalingReader,
std::unique_ptr<AnalyticalParameterProvider> offsetReader,
std::unique_ptr<AnalyticalParameterProvider> sigmaReader,
int numConditions,
int numObservables,
ErrorModel errorModel);
using GradientFunction::evaluate;
FunctionEvaluationStatus evaluate(gsl::span<double const> parameters,
double& fval,
gsl::span<double> gradient,
Logger* logger,
double* cpuTime) const override;
FunctionEvaluationStatus evaluate(gsl::span<double const> reducedParameters,
double& fval,
gsl::span<double> gradient,
std::vector<double>& fullParameters,
std::vector<double>& fullGradient,
Logger* logger,
double* cpuTime) const;
[[nodiscard]] std::vector<double> getDefaultScalingFactors() const;
[[nodiscard]] std::vector<double> getDefaultOffsetParameters() const;
[[nodiscard]] std::vector<double> getDefaultSigmaParameters() const;
[[nodiscard]] std::tuple<std::vector<std::vector<double>>,
std::vector<std::vector<double>>>
getUnscaledModelOutputsAndSigmas(
const gsl::span<double const> reducedParameters,
Logger* logger,
double* cpuTime) const;
[[nodiscard]] std::vector<double> computeAnalyticalScalings(
std::vector<std::vector<double>> const& measurements,
std::vector<std::vector<double>> const& modelOutputsUnscaled) const;
void applyOptimalScalings(
std::vector<double> const& proportionalityFactors,
std::vector<std::vector<double>>& modelOutputs) const;
[[nodiscard]] std::vector<double> computeAnalyticalOffsets(
const std::vector<std::vector<double>>& measurements,
std::vector<std::vector<double>>& modelOutputsUnscaled) const;
[[nodiscard]] std::vector<double> computeAnalyticalSigmas(
std::vector<std::vector<double>> const& measurements,
const std::vector<std::vector<double>>& modelOutputsScaled) const;
void applyOptimalOffsets(
std::vector<double> const& offsetParameters,
std::vector<std::vector<double>>& modelOutputs) const;
void fillInAnalyticalSigmas(
std::vector<std::vector<double>>& allSigmas,
const std::vector<double>& analyticalSigmas) const;
virtual FunctionEvaluationStatus evaluateWithOptimalParameters(
std::vector<double> const& fullParameters,
std::vector<double> const& sigmas,
std::vector<std::vector<double>> const& measurements,
std::vector<std::vector<double>> const& modelOutputsScaled,
std::vector<std::vector<double> > &fullSigmaMatrices,
double& fval,
const gsl::span<double> gradient,
std::vector<double>& fullGradient,
Logger* logger,
double* cpuTime) const;
[[nodiscard]] int numParameters() const override;
[[nodiscard]] int numProportionalityFactors() const;
[[nodiscard]] std::vector<int> const& getProportionalityFactorIndices() const;
[[nodiscard]] int numOffsetParameters() const;
[[nodiscard]] int numSigmaParameters() const;
[[nodiscard]] std::vector<int> const& getOffsetParameterIndices() const;
[[nodiscard]] std::vector<int> const& getSigmaParameterIndices() const;
[[nodiscard]] std::vector<int> getAnalyticalParameterIndices() const;
[[nodiscard]] AmiciSummedGradientFunction* getWrappedFunction() const;
[[nodiscard]] std::vector<std::string> getParameterIds() const override;
private:
void init();
AmiciSummedGradientFunction *wrapped_function_;
std::unique_ptr<AnalyticalParameterProvider> scalingReader;
std::unique_ptr<AnalyticalParameterProvider> offsetReader;
std::unique_ptr<AnalyticalParameterProvider> sigmaReader;
std::vector<int> proportionalityFactorIndices;
std::vector<int> offsetParameterIndices;
std::vector<int> sigmaParameterIndices;
int numConditions;
int numObservables;
ErrorModel errorModel = ErrorModel::normal;
};
class HierarchicalOptimizationProblemWrapper : public OptimizationProblem
{
public:
HierarchicalOptimizationProblemWrapper() = default;
HierarchicalOptimizationProblemWrapper(
std::unique_ptr<OptimizationProblem> problemToWrap,
const MultiConditionDataProviderHDF5* dataProvider);
HierarchicalOptimizationProblemWrapper(
std::unique_ptr<OptimizationProblem> problemToWrap,
std::unique_ptr<HierarchicalOptimizationWrapper> costFun,
std::unique_ptr<Logger> logger);
HierarchicalOptimizationProblemWrapper(
HierarchicalOptimizationProblemWrapper const& other) = delete;
virtual void fillInitialParameters(gsl::span<double> buffer) const override;
virtual void fillParametersMin(gsl::span<double> buffer) const override;
virtual void fillParametersMax(gsl::span<double> buffer) const override;
void fillFilteredParams(std::vector<double> const& fullParams,
gsl::span<double> buffer) const;
OptimizationOptions const& getOptimizationOptions() const override
{
return wrapped_problem_->getOptimizationOptions();
}
void setOptimizationOptions(OptimizationOptions const& options) override
{
wrapped_problem_->setOptimizationOptions(options);
}
// TODO: need to ensure that this will work with the reduced number of
// parameters
virtual std::unique_ptr<OptimizationReporter> getReporter() const override;
private:
std::unique_ptr<OptimizationProblem> wrapped_problem_;
};
class HierarchicalOptimizationReporter : public OptimizationReporter
{
public:
HierarchicalOptimizationReporter(
HierarchicalOptimizationWrapper* gradFun,
std::unique_ptr<OptimizationResultWriter> rw,
std::unique_ptr<Logger> logger);
using GradientFunction::evaluate;
FunctionEvaluationStatus evaluate(gsl::span<const double> parameters,
double& fval,
gsl::span<double> gradient,
Logger* logger = nullptr,
double* cpuTime = nullptr) const override;
// bool starting(gsl::span<const double> initialParameters) const override;
// TODO: always update final parameters
virtual bool iterationFinished(
gsl::span<const double> parameters,
double objectiveFunctionValue,
gsl::span<const double> objectiveFunctionGradient) const override;
virtual bool afterCostFunctionCall(
gsl::span<const double> parameters,
double objectiveFunctionValue,
gsl::span<double const> objectiveFunctionGradient) const override;
void finished(double optimalCost,
gsl::span<const double> parameters,
int exitStatus) const override;
std::vector<double> const& getFinalParameters() const override;
HierarchicalOptimizationWrapper* hierarchical_wrapper_ = nullptr;
/* In addition to the vectors for the outer optimization problem,
* we also keep the complete ones.
*/
mutable std::vector<double> cached_full_parameters_;
mutable std::vector<double> cached_full_gradient_;
// TODO should override other functions as well
// TODO: in all functions, we need to check of the provided parameters or
// function values match To cached ones, if we want to provide all together
// to downstream
};
void
fillFilteredParams(std::vector<double> const& valuesToFilter,
const std::vector<int>& sortedIndicesToExclude,
gsl::span<double> result);
double
getDefaultScalingFactor(amici::ParameterScaling scaling);
double
getDefaultOffsetParameter(amici::ParameterScaling scaling);
double
computeAnalyticalScalings(
int scalingIdx,
const std::vector<std::vector<double>>& modelOutputsUnscaled,
const std::vector<std::vector<double>>& measurements,
const AnalyticalParameterProvider& scalingReader,
int numObservables);
double
computeAnalyticalOffsets(
int offsetIdx,
const std::vector<std::vector<double>>& modelOutputsUnscaled,
const std::vector<std::vector<double>>& measurements,
AnalyticalParameterProvider& offsetReader,
int numObservables);
double
computeAnalyticalSigmas(
int sigmaIdx,
const std::vector<std::vector<double>>& modelOutputsScaled,
const std::vector<std::vector<double>>& measurements,
const AnalyticalParameterProvider& sigmaReader,
int numObservables,
double epsilonAbs = 1e-12,
double epsilonRel = 0.01);
void
applyOptimalScaling(int scalingIdx,
double scalingLin,
std::vector<std::vector<double>>& modelOutputs,
AnalyticalParameterProvider const& scalingReader,
int numObservables);
void
applyOptimalOffset(int offsetIdx,
double offsetLin,
std::vector<std::vector<double>>& modelOutputs,
AnalyticalParameterProvider const& offsetReader,
int numObservables);
std::vector<double>
spliceParameters(const gsl::span<double const> reducedParameters,
const std::vector<int>& proportionalityFactorIndices,
const std::vector<int>& offsetParameterIndices,
const std::vector<int>& sigmaParameterIndices,
const std::vector<double>& scalingFactors,
const std::vector<double>& offsetParameters,
const std::vector<double>& sigmaParameters);
template <typename T>
std::vector<T>
removeInnerParameters(const gsl::span<T const> allParameters,
const std::vector<int>& proportionalityFactorIndices,
const std::vector<int>& offsetParameterIndices,
const std::vector<int>& sigmaParameterIndices)
{
std::vector<T> outerParameters(
allParameters.size() - proportionalityFactorIndices.size() -
offsetParameterIndices.size() - sigmaParameterIndices.size());
int nextOuterIdx = 0;
for(int idxFull = 0; idxFull < static_cast<int>(allParameters.size());
++idxFull) {
// skip if current parameter is scaling/offset/sigma
if(std::find(proportionalityFactorIndices.begin(),
proportionalityFactorIndices.end(), idxFull)
!= std::end(proportionalityFactorIndices))
continue;
if(std::find(offsetParameterIndices.begin(),
offsetParameterIndices.end(), idxFull)
!= std::end(offsetParameterIndices))
continue;
if(std::find(sigmaParameterIndices.begin(),
sigmaParameterIndices.end(), idxFull)
!= std::end(sigmaParameterIndices))
continue;
// otherwise copy
outerParameters[nextOuterIdx] = allParameters[idxFull];
++nextOuterIdx;
}
Ensures(nextOuterIdx == static_cast<int>(outerParameters.size()));
return outerParameters;
}
std::vector<double>
getOuterParameters(std::vector<double> const& fullParameters,
H5::H5File const& parameterFile,
std::string const& parameterPath);
double
computeNegLogLikelihood(
std::vector<std::vector<double>> const& measurements,
std::vector<std::vector<double>> const& modelOutputsScaled,
const std::vector<std::vector<double>>& sigmas);
double
computeNegLogLikelihood(std::vector<double> const& measurements,
std::vector<double> const& modelOutputsScaled,
const std::vector<double>& sigmas);
void
checkGradientForAnalyticalParameters(std::vector<double> const& gradient,
std::vector<int> const& analyticalIndices,
double threshold);
} // namespace parpe
#endif // HIERARCHICALOPTIMIZATION_H