46 STORM_LOG_THROW(formula->isRewardOperatorFormula() || formula->isProbabilityOperatorFormula(), storm::exceptions::NotSupportedException,
47 "We only support reward- and probability operator formulas.");
48 STORM_LOG_THROW(regions.size() <= 1, storm::exceptions::NotSupportedException,
"Storm only supports one or zero regions.");
50 std::shared_ptr<storm::logic::Formula const> formulaNoBound;
51 if (formula->asOperatorFormula().hasBound()) {
52 std::shared_ptr<storm::logic::Formula> formulaWithoutBounds = formula->clone();
53 formulaWithoutBounds->asOperatorFormula().removeBound();
54 formulaNoBound = formulaWithoutBounds->asSharedPointer();
56 formulaNoBound = formula;
60 auto const& feasibilitySettings = storm::settings::getModule<storm::settings::modules::FeasibilitySettings>();
62 if (formula->asOperatorFormula().hasBound()) {
63 t.
setBound(formula->asOperatorFormula().getBound());
65 STORM_LOG_THROW(!feasibilitySettings.isParameterDirectionSet(), storm::exceptions::NotSupportedException,
66 "With a bound, the direction for the parameters is inferred from the bound.");
67 STORM_LOG_THROW(!feasibilitySettings.hasOptimalValueGuaranteeBeenSet(), storm::exceptions::NotSupportedException,
68 "When a bound is given, the guarantee is that this bound will be satisfied by a solution.");
70 if (feasibilitySettings.hasOptimalValueGuaranteeBeenSet()) {
71 t.
setMaximalAllowedGap(storm::utility::convertNumber<storm::RationalNumber>(feasibilitySettings.getOptimalValueGuarantee()));
74 STORM_LOG_THROW(feasibilitySettings.isParameterDirectionSet(), storm::exceptions::NotSupportedException,
75 "Without a bound, the direction for the parameters must be explicitly given.");
78 if (regions.size() == 1) {
81 return std::make_shared<FeasibilitySynthesisTask const>(std::move(t));
86 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
88 auto const& feasibilitySettings = storm::settings::getModule<storm::settings::modules::FeasibilitySettings>();
91 if (task->isRegionSet()) {
105 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"SCP is not yet implemented.");
111 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
113 auto derSettings = storm::settings::getModule<storm::settings::modules::DerivativeSettings>();
116 "Gradient descent is currently only supported for DTMCs.");
117 std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
118 STORM_LOG_THROW(task->getFormula().isProbabilityOperatorFormula() || task->getFormula().isRewardOperatorFormula(), storm::exceptions::NotSupportedException,
119 "Input formula needs to be either a probability operator formula or a reward operator formula.");
120 STORM_LOG_THROW(task->isBoundSet(), storm::exceptions::NotImplementedException,
"GD (right now) requires an explicitly given bound.");
121 STORM_LOG_THROW(task->getMaximalAllowedGap() == std::nullopt, storm::exceptions::NotSupportedException,
122 "GD cannot provide guarantees on the optimality of the solution..");
124 if (omittedParameters && !omittedParameters->empty()) {
126 std::cout <<
"Parameters ";
127 for (
auto const& entry : *omittedParameters) {
128 std::cout << entry <<
" ";
130 std::cout <<
"are inconsequential.";
131 if (derSettings.areInconsequentialParametersOmitted()) {
132 std::cout <<
" They will be omitted in the found instantiation.\n";
134 std::cout <<
" They will be set to 0.5 in the found instantiation. To omit them, set the flag --omit-inconsequential-params.\n";
138 boost::optional<derivative::GradientDescentConstraintMethod> constraintMethod = derSettings.getConstraintMethod();
139 if (!constraintMethod) {
140 STORM_LOG_ERROR(
"Unknown Gradient Descent Constraint method: " << derSettings.getConstraintMethodAsString());
144 boost::optional<derivative::GradientDescentMethod> method = derSettings.getGradientDescentMethod();
146 STORM_LOG_ERROR(
"Unknown Gradient Descent method: " << derSettings.getGradientDescentMethodAsString());
153 std::optional<storage::ParameterRegion<storm::RationalFunction>> region;
154 if (task->isRegionSet()) {
155 region = task->getRegion();
157 bool hasZeroBound =
false;
158 for (
auto const& var : region->getVariables()) {
159 auto lowerBound = region->getLowerBoundary(var);
160 auto upperBound = region->getUpperBoundary(var);
168 "The region includes bounds at 0 or 1, which is not supported by Gradient Descent. Continuing anyway, but results may be incorrect.");
172 STORM_PRINT(
"Finding an extremum using Gradient Descent\n");
175 *dtmc, *method, derSettings.getLearningRate(), derSettings.getAverageDecay(), derSettings.getSquaredAverageDecay(), derSettings.getMiniBatchSize(),
176 derSettings.getTerminationEpsilon(), startPoint, *constraintMethod, region, derSettings.isPrintJsonSet());
181 if (!derSettings.areInconsequentialParametersOmitted() && omittedParameters) {
184 instantiationAndValue.first[param] = startPoint->at(param);
186 instantiationAndValue.first[param] = utility::convertNumber<RationalFunction::CoeffType>(0.5);
190 derivativeWatch.
stop();
193 std::pair<double, typename storm::storage::ParameterRegion<ValueType>::Valuation> valueValuationPair;
194 valueValuationPair.first = instantiationAndValue.second;
195 valueValuationPair.second = instantiationAndValue.first;
197 if (derSettings.isPrintJsonSet()) {
201 if (task->isBoundSet()) {
202 printFeasibilityResult(task->getBound().isSatisfied(valueValuationPair.first), valueValuationPair, derivativeWatch);
210 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
212 STORM_LOG_THROW(task->isRegionSet(), storm::exceptions::NotSupportedException,
"PLA requires an explicitly given region.");
216 auto regionVerificationSettings = storm::settings::getModule<storm::settings::modules::RegionVerificationSettings>();
217 auto engine = regionVerificationSettings.getRegionCheckEngine();
221 regionSplittingStrategy.heuristic = regionVerificationSettings.getRegionSplittingHeuristic();
222 regionSplittingStrategy.estimateKind = regionVerificationSettings.getRegionSplittingEstimateMethod();
223 if (regionVerificationSettings.isSplittingThresholdSet()) {
224 regionSplittingStrategy.maxSplitDimensions = regionVerificationSettings.getSplittingThreshold();
227 if (task->isBoundSet()) {
230 engine, regionSplittingStrategy};
231 auto valueValuation = storm::api::computeExtremalValue<ValueType>(settings, task->getRegion(), direction, storm::utility::zero<ValueType>(),
232 !task->isMaxGapRelative(), task->getBound().getInvertedBound());
237 STORM_LOG_THROW(task->getMaximalAllowedGap() != std::nullopt, storm::exceptions::NotSupportedException,
238 "Without a bound, PLA requires an explicit target in form of a guarantee.");
240 ValueType precision = storm::utility::convertNumber<ValueType>(task->getMaximalAllowedGap().value());
243 engine, regionSplittingStrategy};
244 auto valueValuation = storm::api::computeExtremalValue<ValueType>(settings, task->getRegion(), direction, storm::utility::zero<ValueType>(),
245 !task->isMaxGapRelative(), std::nullopt);