Segmentation: code up the algorithm according to spec
...derive the implementation mostly by logical reasoning ...indicate positions by Iterators of a random-access list
This commit is contained in:
parent
bf978fcda1
commit
2378be5d86
2 changed files with 233 additions and 31 deletions
|
|
@ -31,7 +31,7 @@
|
|||
//#include "steam/mobject/builder/fixture-change-detector.hpp" ///////////TODO
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
|
||||
namespace steam {
|
||||
|
|
@ -53,6 +53,7 @@ namespace fixture {
|
|||
namespace {// Implementation of Split-Splice algorithm
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::time::TimeVar;
|
||||
using OptTime = std::optional<Time>;
|
||||
using Iter = typename list<Segment>::iterator;
|
||||
|
||||
|
|
@ -74,14 +75,11 @@ namespace fixture {
|
|||
, SEAMLESS
|
||||
};
|
||||
|
||||
Verb opPred = NIL,
|
||||
opSucc = NIL;
|
||||
Verb opPred_ = NIL,
|
||||
opSucc_ = NIL;
|
||||
|
||||
Iter pred{};
|
||||
Iter succ{};
|
||||
|
||||
Time start = Time::NEVER,
|
||||
after = Time::NEVER;
|
||||
Iter pred_, succ_;
|
||||
Time start_, after_;
|
||||
|
||||
/* ======= elementary operations ======= */
|
||||
|
||||
|
|
@ -89,37 +87,197 @@ namespace fixture {
|
|||
Time getAfter (Iter elm) { return elm->after(); }
|
||||
|
||||
Iter
|
||||
createElm (Time start, Time after)
|
||||
createSeg (Iter pos, Time start, Time after)
|
||||
{
|
||||
UNIMPLEMENTED ("create new Segment");
|
||||
}
|
||||
|
||||
Iter
|
||||
cloneElm (Iter elm, Time start, Time after)
|
||||
emptySeg (Iter pos, Time start, Time after)
|
||||
{
|
||||
UNIMPLEMENTED ("create new Segment");
|
||||
}
|
||||
|
||||
Iter
|
||||
cloneSeg (Iter pos, Time start, Time after, Iter src)
|
||||
{
|
||||
UNIMPLEMENTED ("clone Segment and modify time");
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
establishSplitPoint (Iter startAll, Iter afterAll
|
||||
,OptTime start, OptTime after)
|
||||
Iter
|
||||
discard (Iter start, Iter after)
|
||||
{
|
||||
UNIMPLEMENTED ("Stage-1 and Stage-2");
|
||||
UNIMPLEMENTED ("discard Segments");
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param startAll (forward) iterator pointing at the overall Segmentation begin
|
||||
* @param afterAll (forward) iterator indicating point-after-end of Segmentation
|
||||
* @param start (optional) specification of new segment's start point
|
||||
* @param after (optional) specification of new segment's end point
|
||||
*/
|
||||
SplitSpliceAlgo (Iter startAll, Iter afterAll
|
||||
,OptTime start, OptTime after)
|
||||
{
|
||||
auto [start_,after_] = establishSplitPoint (startAll,afterAll, start,after);
|
||||
|
||||
// Postcondition: ordered start and end times
|
||||
ENSURE (pred_ != afterAll);
|
||||
ENSURE (succ_ != afterAll);
|
||||
ENSURE (start_ < after_);
|
||||
ENSURE (getStart(pred_) <= start_);
|
||||
ENSURE (start_ <= getStart(succ_) or pred_ == succ_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stage-1 and Stage-2 of the algorithm determine the insert point
|
||||
* and establish the actual start and end point of the new segment
|
||||
* @return
|
||||
*/
|
||||
std::pair<Time,Time>
|
||||
establishSplitPoint (Iter startAll, Iter afterAll
|
||||
,OptTime start, OptTime after)
|
||||
{ // nominal break point
|
||||
Time sep = start? *start
|
||||
: after? *after
|
||||
: Time::NEVER;
|
||||
|
||||
// find largest Predecessor with start before separator
|
||||
for (succ_ = startAll, pred_ = afterAll
|
||||
;succ_ != afterAll and getStart(succ_) < sep
|
||||
;++succ_)
|
||||
{
|
||||
pred_ = succ_;
|
||||
}
|
||||
REQUIRE (pred_ != succ_, "non-empty segmentation required");
|
||||
if (succ_ == afterAll) succ_=pred_;
|
||||
if (pred_ == afterAll) pred_=succ_; // separator touches bounds
|
||||
|
||||
// Stage-2 : establish start and end point of new segment
|
||||
|
||||
Time startSeg = start? *start
|
||||
: getAfter(pred_) < sep? getAfter(pred_)
|
||||
: getStart(pred_);
|
||||
Time afterSeg = after? *after
|
||||
: getStart(succ_) > sep? getStart(succ_)
|
||||
: getAfter(succ_);
|
||||
ENSURE (startSeg != afterSeg);
|
||||
if (startSeg < afterSeg)
|
||||
return {startSeg,afterSeg};
|
||||
else
|
||||
return {afterSeg,startSeg};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stage-3 of the algorithm works out the precise relation of the
|
||||
* predecessor and successor segments to determine necessary adjustments
|
||||
*/
|
||||
void
|
||||
determineRelations()
|
||||
{
|
||||
UNIMPLEMENTED ("Stage-3");
|
||||
Time startPred = getStart (pred_),
|
||||
afterPred = getAfter (pred_);
|
||||
|
||||
if (startPred < start_)
|
||||
{
|
||||
if (afterPred < start_) opPred_ = INS_NOP;
|
||||
else
|
||||
if (afterPred == start_) opPred_ = SEAMLESS;
|
||||
else
|
||||
{
|
||||
opPred_ = TRUNC;
|
||||
if (afterPred > after_)
|
||||
{ // predecessor actually spans the new segment
|
||||
// thus use it also as successor and truncate both (=SPLIT)
|
||||
succ_ = pred_;
|
||||
opSucc_ = TRUNC;
|
||||
return;
|
||||
} } }
|
||||
else
|
||||
{
|
||||
REQUIRE (startPred == start_, "predecessor does not precede start point");
|
||||
opPred_ = DROP;
|
||||
if (after_ < afterPred )
|
||||
{ // predecessor coincides with start of new segment
|
||||
// thus use it rather as successor and truncate at start
|
||||
succ_ = pred_;
|
||||
opSucc_ = TRUNC;
|
||||
return;
|
||||
} }
|
||||
|
||||
TimeVar startSucc = getStart (succ_),
|
||||
afterSucc = getAfter (succ_);
|
||||
|
||||
if (startSucc < after_)
|
||||
{
|
||||
while (afterSucc < after_)
|
||||
{
|
||||
++succ_;
|
||||
startSucc = getStart (succ_);
|
||||
afterSucc = getAfter (succ_);
|
||||
}
|
||||
ASSERT (startSucc < after_ // in case we dropped a successor completely spanned,
|
||||
,"seamless segmentation"); // even the next one must start within the new segment
|
||||
|
||||
if (after_ == afterSucc) opSucc_ = DROP;
|
||||
else
|
||||
if (after_ < afterSucc) opSucc_ = TRUNC;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (after_ == startSucc) opSucc_ = SEAMLESS;
|
||||
else opSucc_ = INS_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Iter, Iter>
|
||||
|
||||
/**
|
||||
* Stage-4 of the algorithm performs the actual insert and deleting of segments
|
||||
* @return `(s,n,e)` to indicate where changes happened
|
||||
* - s the first changed element
|
||||
* - n the new main segment (may be identical to s)
|
||||
* - e the first unaltered element after the changed range (may be `end()`)
|
||||
*/
|
||||
std::array<Iter, 3>
|
||||
performSplitSplice()
|
||||
{
|
||||
UNIMPLEMENTED ("Stage-4 - doIT");
|
||||
Iter refPred = pred_, refSucc = succ_;
|
||||
REQUIRE (opPred_ != NIL and opSucc_ != NIL);
|
||||
|
||||
// deletions are done by skipping the complete range around the insertion point;
|
||||
// thus to retain a predecessor or successor, this range has to be reduced
|
||||
if (opPred_ == INS_NOP or opPred_ == SEAMLESS)
|
||||
++pred_;
|
||||
if (opSucc_ == DROP or opSucc_ == TRUNC)
|
||||
++succ_;
|
||||
|
||||
// insert the new elements /before/ the range to be dropped, i.e. at pred_
|
||||
Iter n = createSeg (pred_, start_, after_);
|
||||
Iter s = n;
|
||||
//
|
||||
// possibly adapt the predecessor
|
||||
if (opPred_ == INS_NOP)
|
||||
s = emptySeg (n, getAfter(refPred), start_);
|
||||
else
|
||||
if (opPred_ == TRUNC)
|
||||
s = cloneSeg (n, getStart(refPred), start_, refPred);
|
||||
//
|
||||
// possibly adapt the successor
|
||||
if (opSucc_ == INS_NOP)
|
||||
emptySeg (pred_, after_, getStart(refSucc));
|
||||
else
|
||||
if (opPred_ == TRUNC)
|
||||
cloneSeg (pred_, after_, getAfter(refSucc), refSucc);
|
||||
|
||||
// finally discard superseded segments
|
||||
Iter e = discard (pred_, succ_);
|
||||
|
||||
// indicate the range where changes happened
|
||||
return {s,n,e};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}//(End)SlitSplice impl
|
||||
|
|
@ -148,10 +306,10 @@ namespace fixture {
|
|||
Segment const&
|
||||
Segmentation::splitSplice (OptTime start, OptTime after, const engine::JobTicket* jobTicket)
|
||||
{
|
||||
SplitSpliceAlgo splicr;
|
||||
splicr.establishSplitPoint (segments_.begin(),segments_.end(), start,after);
|
||||
SplitSpliceAlgo splicr{segments_.begin(),segments_.end(), start,after};
|
||||
splicr.determineRelations();
|
||||
splicr.performSplitSplice();
|
||||
auto [s,n,e] = splicr.performSplitSplice();
|
||||
return *n;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -70022,7 +70022,7 @@
|
|||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1682627110771" ID="ID_183754275" MODIFIED="1682627133820" TEXT="Invariante: lückenlose Abdeckung">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1682985654543" ID="ID_433290925" MODIFIED="1682993072525" TEXT="Algorithmus">
|
||||
<node COLOR="#435e98" CREATED="1682985654543" ID="ID_433290925" MODIFIED="1683076777480" TEXT="Algorithmus">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1682987424458" ID="ID_419424512" MODIFIED="1682987433683" TEXT="Invariante">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
|
|
@ -70145,11 +70145,11 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682993086565" ID="ID_469257294" MODIFIED="1682993090645" TEXT="Implementierung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1683042576253" ID="ID_1878728765" MODIFIED="1683042587092" TEXT="Konzept">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1682993086565" ID="ID_469257294" MODIFIED="1683076810216" TEXT="Implementierung">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#435e98" CREATED="1683042576253" ID="ID_1878728765" MODIFIED="1683076796339" TEXT="Konzept">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1683042638127" ID="ID_1570983964" MODIFIED="1683042656744" TEXT="Deskriptor SpliceAct">
|
||||
<node COLOR="#435e98" CREATED="1683042638127" ID="ID_1570983964" MODIFIED="1683076788355" TEXT="Deskriptor SpliceAct">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1683042697806" ID="ID_1462476322" MODIFIED="1683043770315" TEXT="Task-Record">
|
||||
|
|
@ -70164,7 +70164,7 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1683043806248" ID="ID_358437836" MODIFIED="1683043811748" TEXT="Enum als verb">
|
||||
<node COLOR="#435e98" CREATED="1683043806248" ID="ID_358437836" MODIFIED="1683076789875" TEXT="Enum als verb">
|
||||
<node CREATED="1683043814387" ID="ID_312010971" MODIFIED="1683043834772" TEXT="jeweils separat für pred und succ"/>
|
||||
<node CREATED="1683043835634" ID="ID_1729162283" MODIFIED="1683043837062" TEXT="Fälle">
|
||||
<node CREATED="1683043887635" ID="ID_1329437740" MODIFIED="1683043891434" TEXT="SEAMLESS"/>
|
||||
|
|
@ -70183,14 +70183,58 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1683045976036" ID="ID_1600965970" MODIFIED="1683045990086" TEXT="Predecessor und Successor per Iterator referenzieren"/>
|
||||
<node COLOR="#338800" CREATED="1683045976036" ID="ID_1600965970" MODIFIED="1683076793754" TEXT="Predecessor und Successor per Iterator referenzieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1683046583116" ID="ID_133574091" MODIFIED="1683046722114" TEXT="lokale Umsetzung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1683046583116" ID="ID_133574091" MODIFIED="1683076802821" TEXT="lokale Umsetzung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1683046618535" ID="ID_545931815" MODIFIED="1683046633053" TEXT="den Deskriptor als lokale/anonyme Klasse"/>
|
||||
<node CREATED="1683046633701" ID="ID_1909003590" MODIFIED="1683046644503" TEXT="die Schritte des Algo als Methoden"/>
|
||||
<node CREATED="1683046648011" ID="ID_884620601" MODIFIED="1683046664621" TEXT="Arbeitsdaten als Member"/>
|
||||
<node CREATED="1683046711054" ID="ID_815326523" MODIFIED="1683046719941" TEXT="Integration als statische Funktion"/>
|
||||
<node COLOR="#435e98" CREATED="1683076903128" ID="ID_1277889001" MODIFIED="1683077356643" TEXT="einige Vereinfachungen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Nach logischer Analyse der spezifiziereten Fälle lassen sich einige Verzweigungen verkürzen
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
die Suche nach dem Split-Punkt und das Festsetzen der Start/Endpunkte fasse ich zusammen in den Konstruktor; danach sind Start/Endzeit <i>immutable</i>
|
||||
</li>
|
||||
<li>
|
||||
sichere die Verkürzungen möglichst durch Assertions ab
|
||||
</li>
|
||||
<li>
|
||||
der SPLIT und SWAP-Fall wird dargestellt, indem ich den Predecessor auch als Successor verwende, und lediglich für beide verschiedene Operationen codiere
|
||||
</li>
|
||||
<li>
|
||||
sofern für beide bereits eine Operation definiert wurde, kann man die gesamte Untersuchung des Successors überspringen
|
||||
</li>
|
||||
<li>
|
||||
in dem Fall, in dem ggfs. mehrere überdeckte Successoren übersprungen werden, schiebe ich lediglich die Variablen
|
||||
</li>
|
||||
<li>
|
||||
den Umstand, daß Predecessor/Successor verworfen werden, oder eben nicht, setze ich direkt durch Justieren des Iterator-Bereichs um
|
||||
</li>
|
||||
<li>
|
||||
anschließend werden <i>zuerst</i> die neuen Elemente <i>davorgehängt</i> und dann der zu verwerfende Bereich gelöscht
|
||||
</li>
|
||||
<li>
|
||||
als Ergebnis gebe ich die bezeichneten Iterator-Positionen zurück
|
||||
</li>
|
||||
<li>
|
||||
alle Mutator-Operationen arbeiten auf Iteratoren (d.h. setzen eine nicht-invalidierende random-access-Liste vorraus)
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1683046722945" ID="ID_113209914" MODIFIED="1683046727395" TEXT="Generalisierung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue