17 , enumeratedChoice(evaluator)
34 auto decision = std::make_shared<ChoiceDecision>(request->token, std::vector<number>{},
evaluator);
44 if ( systemState->currentTime >
timestamp ) {
50 auto request = request_ptr.lock();
55 addEvaluation( token_ptr, request_ptr, std::move(decision), decision->reward );
62 return event_ptr.lock();
70 auto token = request->token;
71 assert( token->
node );
75 assert( extensionElements->choices.size() );
77 if ( extensionElements->choices.size() > 1 ) {
83 auto& choice = extensionElements->choices[0];
85 if ( !choice->enumeration.empty() ) {
91 if ( !choice->lowerBound && !choice->upperBound ) {
92 throw std::runtime_error(
"BisectionalChoice: choice requires bounds");
96 if ( choice->multipleOf ) {
97 return discreteBisection(request, choice.get());
106BisectionalChoice::Candidate BisectionalChoice::evaluate(
size_t index) {
108 auto decision = std::make_shared<ChoiceDecision>(token, std::vector<number>{ values[index] },
evaluator);
109 decision->evaluate();
110 return { index, decision };
113std::tuple<size_t, BisectionalChoice::Candidate, size_t> BisectionalChoice::findFeasible(
size_t first,
size_t last) {
114 const size_t npos = std::numeric_limits<size_t>::max();
115 if ( first > last )
return { npos, { npos,
nullptr }, npos };
118 std::queue<std::pair<size_t, size_t>> intervals;
119 intervals.push({first, last});
121 while ( !intervals.empty() ) {
122 auto [l, r] = intervals.front();
125 size_t mid = l + (r - l) / 2;
126 auto candidate = evaluate(mid);
127 if ( candidate.isFeasible() ) {
129 size_t nearestLeft = (mid > first) ? l : npos;
130 size_t nearestRight = (mid < last) ? r : npos;
131 return { nearestLeft, candidate, nearestRight };
135 if ( mid > l ) intervals.push({l, mid - 1});
136 if ( mid < r ) intervals.push({mid + 1, r});
139 return { npos, { npos,
nullptr }, npos };
142void BisectionalChoice::findBetweenFeasibleAndFeasible(Candidate left, Candidate right) {
143 if ( right.index <= left.index + 1 )
return;
145 size_t mid = left.index + (right.index - left.index) / 2;
146 auto candidate = evaluate(mid);
148 if ( !candidate.isFeasible() ) {
150 findBetweenFeasibleAndInfeasible(left, mid);
151 findBetweenInfeasibleAndFeasible(mid, right);
155 if ( candidate.reward() > best.reward() ) {
159 if ( candidate.reward() <= left.reward() && candidate.reward() <= right.reward() ) {
163 if ( left.reward() >= right.reward() ) {
164 findBetweenFeasibleAndFeasible(left, candidate);
167 findBetweenFeasibleAndFeasible(candidate, right);
172void BisectionalChoice::findBetweenFeasibleAndInfeasible(Candidate feasible,
size_t infeasibleIndex) {
173 while ( infeasibleIndex > feasible.index + 1 ) {
174 size_t mid = feasible.index + (infeasibleIndex - feasible.index + 1) / 2;
175 auto candidate = evaluate(mid);
177 if ( !candidate.isFeasible() ) {
179 infeasibleIndex = mid;
181 else if ( candidate.reward() <= best.reward() ) {
188 feasible = candidate;
193void BisectionalChoice::findBetweenInfeasibleAndFeasible(
size_t infeasibleIndex, Candidate feasible) {
194 while ( feasible.index > infeasibleIndex + 1 ) {
195 size_t mid = infeasibleIndex + (feasible.index - infeasibleIndex) / 2;
196 auto candidate = evaluate(mid);
198 if ( !candidate.isFeasible() ) {
200 infeasibleIndex = mid;
202 else if ( candidate.reward() <= best.reward() ) {
209 feasible = candidate;
214std::shared_ptr<Decision> BisectionalChoice::discreteBisection(std::shared_ptr<const DecisionRequest> request,
const BPMNOS::Model::Choice* choice) {
215 const size_t npos = std::numeric_limits<size_t>::max();
218 token = request->token;
220 best = { npos,
nullptr };
222 if ( values.empty() ) {
227 auto left = evaluate(0);
228 auto right = (values.size() > 1) ? evaluate(values.size() - 1) : Candidate{ npos, nullptr };
231 if ( left.isFeasible() ) {
234 if ( right.isFeasible() && (!best.isFeasible() || right.reward() > best.reward()) ) {
238 if ( left.isFeasible() && right.isFeasible() ) {
240 findBetweenFeasibleAndFeasible(left, right);
242 else if ( left.isFeasible() && !right.isFeasible() ) {
244 findBetweenFeasibleAndInfeasible(left, values.size() - 1);
246 else if ( !left.isFeasible() && right.isFeasible() ) {
248 findBetweenInfeasibleAndFeasible(0, right);
252 if ( values.size() <= 2 ) {
255 auto [leftInfeasible, candidate, rightInfeasible] = findFeasible(1, values.size() - 2);
256 if ( !candidate.isFeasible() ) {
262 if ( leftInfeasible != npos ) {
263 findBetweenInfeasibleAndFeasible(leftInfeasible, best);
265 if ( rightInfeasible != npos ) {
266 findBetweenFeasibleAndInfeasible(best, rightInfeasible);
271 return best.decision;
std::shared_ptr< Decision > determineBestChoices(std::shared_ptr< const DecisionRequest > request)
std::shared_ptr< Decision > determineBestChoices(std::shared_ptr< const DecisionRequest > request)
BisectionalChoice(Evaluator *evaluator)
std::shared_ptr< Event > dispatchEvent(const SystemState *systemState) override
void notice(const Observable *observable) override
void connect(Mediator *mediator) override
Represents an abstract base class for an evaluator determining feasibility and reward of a decision.
Class for dispatching the event with the best evaluation.
void addEvaluation(WeakPtrs..., std::shared_ptr< Decision > decision, std::optional< double > reward)
void notice(const Observable *observable) override
void connect(Mediator *mediator) override
auto_set< double, WeakPtrs..., std::weak_ptr< Event > > evaluatedDecisions
auto_list< WeakPtrs..., std::shared_ptr< Decision > > decisionsWithoutEvaluation
void addSubscriber(Observer *subscriber, ObservableTypes... observableTypes)
A class representing the state that the execution or simulation of a given scenario is in.
const BPMN::FlowNode * node
SharedValues * data
Pointer to the data of the owner or owned state machine subprocesses)
Class representing a choice to be made within a BPMNOS::Model::DecisionTask.
std::vector< BPMNOS::number > getEnumeration(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
Returns the allowed values the attribute may take.
Class representing a task in which one or more choices have to be made.
Class holding extension elements representing execution data for nodes.
std::unique_ptr< ExtensionElements > extensionElements
T * represents()
Attempts to cast the element to the specified type T.
Represents a pending decision.
virtual constexpr Type getObservableType() const =0