47 STORM_LOG_THROW(formula->isRewardOperatorFormula() || formula->isProbabilityOperatorFormula(), storm::exceptions::NotSupportedException,
48 "We only support reward- and probability operator formulas.");
49 STORM_LOG_THROW(regions.size() <= 1, storm::exceptions::NotSupportedException,
"Storm only supports one or zero regions.");
51 std::shared_ptr<storm::logic::Formula const> formulaNoBound;
52 if (formula->asOperatorFormula().hasBound()) {
53 std::shared_ptr<storm::logic::Formula> formulaWithoutBounds = formula->clone();
54 formulaWithoutBounds->asOperatorFormula().removeBound();
55 formulaNoBound = formulaWithoutBounds->asSharedPointer();
57 formulaNoBound = formula;
63 if (formula->asOperatorFormula().hasBound()) {
64 t.
setBound(formula->asOperatorFormula().getBound());
66 STORM_LOG_THROW(!feasibilitySettings.isParameterDirectionSet(), storm::exceptions::NotSupportedException,
67 "With a bound, the direction for the parameters is inferred from the bound.");
68 STORM_LOG_THROW(!feasibilitySettings.hasOptimalValueGuaranteeBeenSet(), storm::exceptions::NotSupportedException,
69 "When a bound is given, the guarantee is that this bound will be satisfied by a solution.");
71 if (feasibilitySettings.hasOptimalValueGuaranteeBeenSet()) {
75 STORM_LOG_THROW(feasibilitySettings.isParameterDirectionSet(), storm::exceptions::NotSupportedException,
76 "Without a bound, the direction for the parameters must be explicitly given.");
79 if (regions.size() == 1) {
82 return std::make_shared<FeasibilitySynthesisTask const>(std::move(t));
87 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
92 if (task->isRegionSet()) {
106 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"SCP is not yet implemented.");
112 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
117 "Gradient descent is currently only supported for DTMCs.");
118 std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
119 STORM_LOG_THROW(task->getFormula().isProbabilityOperatorFormula() || task->getFormula().isRewardOperatorFormula(), storm::exceptions::NotSupportedException,
120 "Input formula needs to be either a probability operator formula or a reward operator formula.");
121 STORM_LOG_THROW(task->isBoundSet(), storm::exceptions::NotImplementedException,
"GD (right now) requires an explicitly given bound.");
122 STORM_LOG_THROW(task->getMaximalAllowedGap() == std::nullopt, storm::exceptions::NotSupportedException,
123 "GD cannot provide guarantees on the optimality of the solution..");
125 if (omittedParameters && !omittedParameters->empty()) {
127 std::cout <<
"Parameters ";
128 for (
auto const& entry : *omittedParameters) {
129 std::cout << entry <<
" ";
131 std::cout <<
"are inconsequential.";
132 if (derSettings.areInconsequentialParametersOmitted()) {
133 std::cout <<
" They will be omitted in the found instantiation.\n";
135 std::cout <<
" They will be set to 0.5 in the found instantiation. To omit them, set the flag --omit-inconsequential-params.\n";
139 boost::optional<derivative::GradientDescentConstraintMethod> constraintMethod = derSettings.getConstraintMethod();
140 if (!constraintMethod) {
141 STORM_LOG_ERROR(
"Unknown Gradient Descent Constraint method: " << derSettings.getConstraintMethodAsString());
145 boost::optional<derivative::GradientDescentMethod> method = derSettings.getGradientDescentMethod();
147 STORM_LOG_ERROR(
"Unknown Gradient Descent method: " << derSettings.getGradientDescentMethodAsString());
154 std::optional<storage::ParameterRegion<storm::RationalFunction>> region;
155 if (task->isRegionSet()) {
156 region = task->getRegion();
158 bool hasZeroBound =
false;
159 for (
auto const& var : region->getVariables()) {
160 auto lowerBound = region->getLowerBoundary(var);
161 auto upperBound = region->getUpperBoundary(var);
169 "The region includes bounds at 0 or 1, which is not supported by Gradient Descent. Continuing anyway, but results may be incorrect.");
173 STORM_PRINT(
"Finding an extremum using Gradient Descent\n");
176 *dtmc, *method, derSettings.getLearningRate(), derSettings.getAverageDecay(), derSettings.getSquaredAverageDecay(), derSettings.getMiniBatchSize(),
177 derSettings.getTerminationEpsilon(), startPoint, *constraintMethod, region, derSettings.isPrintJsonSet());
182 if (!derSettings.areInconsequentialParametersOmitted() && omittedParameters) {
185 instantiationAndValue.first[param] = startPoint->at(param);
191 derivativeWatch.
stop();
194 std::pair<double, typename storm::storage::ParameterRegion<ValueType>::Valuation> valueValuationPair;
195 valueValuationPair.first = instantiationAndValue.second;
196 valueValuationPair.second = instantiationAndValue.first;
198 if (derSettings.isPrintJsonSet()) {
202 if (task->isBoundSet()) {
203 printFeasibilityResult(task->getBound().isSatisfied(valueValuationPair.first), valueValuationPair, derivativeWatch);
211 std::shared_ptr<storm::pars::FeasibilitySynthesisTask const>
const& task,
213 STORM_LOG_THROW(task->isRegionSet(), storm::exceptions::NotSupportedException,
"PLA requires an explicitly given region.");
218 auto engine = regionVerificationSettings.getRegionCheckEngine();
222 regionSplittingStrategy.heuristic = regionVerificationSettings.getRegionSplittingHeuristic();
223 regionSplittingStrategy.estimateKind = regionVerificationSettings.getRegionSplittingEstimateMethod();
224 if (regionVerificationSettings.isSplittingThresholdSet()) {
225 regionSplittingStrategy.maxSplitDimensions = regionVerificationSettings.getSplittingThreshold();
228 if (task->isBoundSet()) {
231 engine, regionSplittingStrategy};
233 !task->isMaxGapRelative(), task->getBound().getInvertedBound());
238 STORM_LOG_THROW(task->getMaximalAllowedGap() != std::nullopt, storm::exceptions::NotSupportedException,
239 "Without a bound, PLA requires an explicit target in form of a guarantee.");
244 engine, regionSplittingStrategy};
246 !task->isMaxGapRelative(), std::nullopt);