TreeExplorer: decide upon the steps towards implementation

Here, the tricky question remains, how to relate this evalutaion scheme
to the well known monadic handling of collections and iterators.

It seems, we can not yet decide upon that question, rather we should
first try to build a concrete implementation of the envisioned algorithm
and then reconsider the question later, to what extent this is "monadic"
This commit is contained in:
Fischlurch 2017-11-18 03:00:59 +01:00
parent 782b4f949f
commit c3b04af76f
3 changed files with 83 additions and 1108 deletions

View file

@ -46,49 +46,20 @@
** monad and produce a modified new monad instance. In the simple case of a list, "binding" a function ** monad and produce a modified new monad instance. In the simple case of a list, "binding" a function
** basically means to map the function onto the elements in the list. ** basically means to map the function onto the elements in the list.
** **
** \par Rationale ** ## Rationale
** The primary benefit of using the monad pattern is to separate the transforming operation completely from ** The primary benefit of using the monad pattern is to separate the transforming operation completely from
** the mechanics of applying that operation and combining the results. More specifically, we rely on an iterator ** the mechanics of applying that operation and combining the results. More specifically, we rely on an iterator
** to represent an abstracted source of data and we expose the combined and transformed results again as such ** to represent an abstracted source of data and we expose the combined and transformed results again as such
** an abstracted data sequence. The transformation to apply can be selected at runtime (as a functor), and ** an abstracted data sequence. While the transformation to apply can be selected at runtime (as a functor),
** also the logic how to combine elements can be implemented elsewhere. The monad pattern defines a sane ** the monad pattern defines a sane way to represent partial evaluation state without requiring a container
** way of representing this partial evaluation state without requiring a container for intermediary ** for intermediary results. This is especially helpful when
** results. This is especially helpful when
** - a flexible and unspecific source data structure needs to be processed ** - a flexible and unspecific source data structure needs to be processed
** - and this evaluation needs to be done asynchronously and in parallel (no locking, immutable data) ** - and this evaluation needs to be done asynchronously and in parallel (no locking, immutable data)
** - and a partial evaluation needs to be stored as continuation (not relying on the stack for partial results) ** - and a partial evaluation needs to be stored as continuation (not relying on the stack for partial results)
** **
** \par preconfigured solutions ** @todo WIP-WIP-WIP initial draft as of 11/2017
** This header provides some preconfigured applications of this pattern
** - the DefaultCombinator processes the source elements on demand, feeding them through
** the given functor and using the resulting iterator to deliver the result elements
** - Chained iterator uses similar building blocks just to get the "flattening" of
** a sequence of iterators into a single result iterator
** - the RecursiveExhaustingEvaluation is another kind of combination strategy,
** which recursively evaluates the given function and combines the results
** such as to produce classical depth-first and breadth-first search orders.
** - the more low-level RecursiveSelfIntegration combinator strategy actually
** delegates to the result set iterator implementation to perform the collecting
** and re-integrating of intermediary results. This approach is what we actually
** use in the proc::engine::Dispatcher
** **
** Alternatively, just the basic IterExplorer template can be used together with a custom ** @see IterTreeExplorer_test
** "combinator strategy" and typically even a specific iterator or sequence to implement very specific
** and optimised data structure evaluation patterns. This strategy needs to define some way to hold onto
** the original source elements, feed them through the functor on demand and recombine the result sets
** into a new sequence to be delivered on demand.
** Actually this is what we utilise for the continuous render job generation within the scheduler.
** All the other preconfigured variants defined here where created as proof-of-concept, to document
** and verify this implementation technique as such.
**
** @warning preferably use value semantics for the elements to be processed. Recall, C++ is not
** really a functional programming language, and there is no garbage collector. It might be
** tempting just to pass pointers through a whole evaluation chain. Indeed, you can do so,
** but make sure you understand the precise timing of the evaluation, expansion and
** re-integration steps with regards to memory management; an "explorer function"
** may pass a reference or pointer to some transient source, which is gone after
** incrementing the source iterator.
** @see IterExplorer_test
** @see iter-adapter.hpp ** @see iter-adapter.hpp
** @see itertools.hpp ** @see itertools.hpp
** @see IterSource (completely opaque iterator) ** @see IterSource (completely opaque iterator)
@ -116,8 +87,7 @@ namespace lib {
namespace iter_explorer { namespace iter_explorer {
template<class SRC, class FUN> ////////////TODO
class DefaultCombinator;
} }
@ -131,9 +101,8 @@ namespace lib {
* @todo WIP -- preliminary draft as of 11/2017 * @todo WIP -- preliminary draft as of 11/2017
*/ */
template<class SRC template<class SRC
,template<class,class> class _COM_ = iter_explorer::DefaultCombinator
> >
class IterExplorer class IterTreeExplorer
: public IterStateWrapper<typename SRC::value_type, SRC> : public IterStateWrapper<typename SRC::value_type, SRC>
{ {
@ -143,19 +112,9 @@ namespace lib {
typedef typename SRC::reference reference; typedef typename SRC::reference reference;
typedef typename SRC::pointer pointer; typedef typename SRC::pointer pointer;
/** Metafunction: the resulting type when binding ("flat mapping")
* a functor of type FUN. Basically the result of binding a function
* is again an IterExplorer (with an "expanded" state core type) */
template<class FUN>
struct FlatMapped
{
typedef IterExplorer<_COM_<IterExplorer,FUN>, _COM_> Type;
};
/** by default create an empty iterator */ /** by default create an empty iterator */
IterExplorer() { } IterTreeExplorer() { }
/** wrap an iterator-like state representation /** wrap an iterator-like state representation
@ -164,41 +123,12 @@ namespace lib {
* by the core, and it provides the (monad) bind operator. * by the core, and it provides the (monad) bind operator.
*/ */
explicit explicit
IterExplorer (SRC const& iterStateCore) IterTreeExplorer (SRC const& iterStateCore)
: IterStateWrapper<value_type, SRC> (iterStateCore) : IterStateWrapper<value_type, SRC> (iterStateCore)
{ } { }
/** monad bind ("flat map") operator.
* Using a specific function to explore and work
* on the "contents" of this IterExplorer, with the goal
* to build a new IterExplorer combining the results of this
* function application. The enclosing IterExplorer instance
* provides a Strategy template _COM_, which defines how those
* results are actually to be combined. An instantiation of
* this "Combinator" strategy becomes the state core
* of the result iterator.
*/
template<class FUN>
typename FlatMapped<FUN>::Type
operator >>= (FUN explorer)
{
typedef _COM_<IterExplorer,FUN> Combinator; // instantiation of the combinator strategy
typedef typename FlatMapped<FUN>::Type ResultsIter; // result IterExplorer using that instance as state core
return ResultsIter (
Combinator (explorer // build a new iteration state core
,accessRemainingElements())); // based on a copy of this iterator / sequence
}
private: private:
IterExplorer const&
accessRemainingElements()
{
return *this;
}
}; };
@ -210,7 +140,9 @@ namespace lib {
namespace iter_explorer { ///< predefined "exploration strategies", policies and configurations namespace iter_explorer {
/////TODO RLY?
using util::unConst; using util::unConst;
using lib::meta::enable_if; using lib::meta::enable_if;
@ -218,673 +150,6 @@ namespace lib {
using std::function; using std::function;
using meta::_Fun; using meta::_Fun;
/**
* Building block: just evaluate source elements.
* This strategy will be tied into a "Combinator"
* to hold the actual functor bound into the enclosing
* IterExplorer monad to work on the contained elements.
*/
template<class SIG>
struct ExploreByFunction
: function<SIG>
{
template<typename FUN>
ExploreByFunction(FUN explorationFunctionDefinition)
: function<SIG>(explorationFunctionDefinition)
{ }
ExploreByFunction() { } ///< by default initialised to bottom function
};
/**
* Support for a special use case: an Iterator of Iterators, joining results.
* In this case, already the source produces a sequence of Iterators, which
* just need to be passed through to the output buffer unaltered. Using this
* within the DefaultCombinator strategy creates a combined, flattened iterator
* of all the source iterator's contents.
*/
template<class SIG>
struct UnalteredPassThrough;
template<class IT>
struct UnalteredPassThrough<IT(IT)>
{
IT operator() (IT elm) const { return elm; }
bool operator! () const { return false; } ///< identity function is always valid
};
/**
* Building block: evaluate and combine a sequence of iterators.
* This implementation helper provides two kinds of "buffers" (actually implemented
* as iterators): A result buffer (iterator) which holds a sequence of already prepared
* result elements, which can be retrieved through iteration right away. And a supply buffer
* (iterator) holding raw source elements. When the result buffer is exhausted, the next source
* element will be pulled from there and fed through the "evaluation strategy", which typically
* is a function processing the source element and producing a new result buffer (iterator).
*/
template<class SRC, class FUN
,template<class> class _EXP_ = ExploreByFunction ///< Strategy: how to store and evaluate the function to apply on each element
>
class CombinedIteratorEvaluation
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename SRC::value_type SrcElement;
typedef _EXP_<ResultIter(SrcElement)> Explorer;
SRC srcSeq_;
ResultIter results_;
Explorer explorer_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
CombinedIteratorEvaluation() { }
CombinedIteratorEvaluation(FUN explorerFunction)
: srcSeq_()
, results_()
, explorer_(explorerFunction)
{ }
// using standard copy operations
void
setSourceSequence (SRC const& followUpSourceElements)
{
REQUIRE (explorer_);
srcSeq_ = followUpSourceElements;
}
private:
bool
findNextResultElement()
{
while (!results_ && srcSeq_)
{
results_ = explorer_(*srcSeq_);
++srcSeq_;
}
return bool(results_);
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (CombinedIteratorEvaluation const& seq)
{
return unConst(seq).findNextResultElement();
}
friend reference
yield (CombinedIteratorEvaluation const& seq)
{
return *(seq.results_);
}
friend void
iterNext (CombinedIteratorEvaluation & seq)
{
++(seq.results_);
}
};
/**
* a generic "Combinator strategy" for IterExplorer.
* This default / fallback solution doesn't assume anything beyond the
* source and the intermediary result(s) to be Lumiera Forward Iterators.
* @note the implementation stores the functor into a std::function object,
* which might cause heap allocations, depending on the function given.
* Besides, the implementation holds one instance of the (intermediary)
* result iterator (yielded by invoking the function) and a copy of the
* original IterExplorer source sequence, to get the further elements
* when the initial results are exhausted.
*/
template<class SRC, class FUN>
class DefaultCombinator
: public CombinedIteratorEvaluation<SRC,FUN>
{
typedef typename _Fun<FUN>::Ret ResultIter;
public:
DefaultCombinator() { }
DefaultCombinator(FUN explorerFunction, SRC const& sourceElements)
: CombinedIteratorEvaluation<SRC,FUN>(explorerFunction)
{
this->setSourceSequence (sourceElements);
}
};
/** Metafunction to detect an iterator yielding an iterator sequence */
template<class IT>
struct _is_iterator_of_iterators
{
typedef typename IT::value_type IteratorElementType;
enum{ value = meta::can_IterForEach<IteratorElementType>::value };
};
template<class ITI, class SEQ>
class ChainedIteratorImpl
: public CombinedIteratorEvaluation<ITI, SEQ(SEQ)
, UnalteredPassThrough
>
{ };
/**
* Special iterator configuration for combining / flattening the
* results of a sequence of iterators. This sequence of source iterators
* is assumed to be available as "Iterator yielding Iterators".
* The resulting class is a Lumiera Forward Iterator, delivering all the
* elements of all source iterators in sequence.
* @remarks this is quite similar to the IterExplorer monad, but without
* binding an exploration function to produce the result sequences.
* Rather, the result sequences are directly pulled from the source
* sequence, which thus needs to be an "Iterator of Iterators".
* Beyond that, the implementation relies on the same building
* blocks as used for the full-blown IterExplorer.
* @param ITI iterator of iterators
* @param SEQ type of the individual sequence (iterator).
* The value_type of this sequence will be the overall
* resulting value type of the flattened sequence
*/
template<class ITI, class SEL = void>
class ChainedIters;
template<class ITI>
class ChainedIters<ITI, enable_if< _is_iterator_of_iterators<ITI>>
>
: public IterStateWrapper<typename ITI::value_type::value_type
,ChainedIteratorImpl<ITI, typename ITI::value_type>
>
{
public:
ChainedIters(ITI const& iteratorOfIterators)
{ // note: default ctor on parent -> empty sequences
this->stateCore().setSourceSequence (iteratorOfIterators);
}
};
/**
* Convenience specialisation: manage the sequence of iterators automatically.
* @note in this case the \em first template parameter denotes the \em element sequence type;
* we use a IterStack to hold the sequence-of-iterators in heap storage.
* @warning this specialisation will not be picked, if the \em value-type
* of the given iterator is itself an iterator
*/
template<class SEQ>
class ChainedIters<SEQ, disable_if< _is_iterator_of_iterators<SEQ>>
>
: public IterStateWrapper<typename SEQ::value_type
,ChainedIteratorImpl<IterStack<SEQ>, SEQ>
>
{
public:
typedef IterStack<SEQ> IteratorIterator;
ChainedIters(IteratorIterator const& iteratorOfIterators)
{
this->stateCore().setSourceSequence (iteratorOfIterators);
}
/** empty result sequence by default */
ChainedIters() { }
};
/**
* A "Combinator strategy" allowing to expand and evaluate a
* (functional) data structure successively and recursively.
* Contrary to the DefaultCombinator, here the explorer is evaluated
* repeatedly, feeding back the results until exhaustion. The concrete
* exploration function needs to embody some kind of termination condition,
* e.g. by returning an empty sequence at some point, otherwise infinite
* recursion might happen. Another consequence of this repeated re-evaluation
* is the requirement of the source sequence's element type to be compatible
* to the result sequence's element type -- we can't \em transform the contents
* of the source sequence into another data type, just explore and expand those
* contents into sub-sequences based on the same data type. (While this contradicts
* the full requirements for building a Monad, we can always work around that kind
* of restriction by producing the element type of the target sequence by implicit
* type conversion)
*
* \par strategy requirements
* To build a concrete combinator a special strategy template is required to define
* the actual implementation logic how to proceed with the evaluation (i.e. how to
* find the feed of the "next elements" and how to re-integrate the results of an
* evaluation step into the already expanded sequence of intermediary results.
* Moreover, this implementation strategy pattern is used as a data buffer
* to hold those intermediary results. Together, this allows to create
* various expansion patterns, e.g. depth-first or breadth-first.
* - \c Strategy::getFeed() accesses the point from where
* to pull the next element to be expanded. This function <i>must not</i>
* yield an empty sequence, \em unless the overall exploration is exhausted
* - \c Strategy::feedBack() re-integrates the results of an expansion step
*
* @warning beware, when tempted to pass elements by reference (or pointer)
* through the explorer function, make sure you really understand the
* working mode of the #iterate function with regards to memory management.
* When ResultIter attempts just to store a pointer, after incrementing
* \c ++feed(), depending on the internals of the actual src iterator,
* this pointer might end up dangling. Recommendation is to let the
* Explorer either take arguments or return results by value (copy).
*/
template<class SRC, class FUN
,template<class> class _BUF_
>
class RecursiveExhaustingEvaluation
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename _Fun<FUN>::Sig Sig;
typedef function<Sig> Explorer;
typedef _BUF_<ResultIter> Buffer;
Buffer resultBuf_;
Explorer explore_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
RecursiveExhaustingEvaluation (Explorer fun, SRC const& src)
: resultBuf_()
, explore_(fun)
{
resultBuf_.feedBack(
initEvaluation (src));
}
RecursiveExhaustingEvaluation() { };
// standard copy operations
private:
/** Extension point: build the initial evaluation state
* based on the source sequence (typically an IterExplorer).
* This is a tricky problem, since the source sequence is not
* necessarily assignment compatible to the ResultIter type
* and there is no general method to build a ResultIter.
* The solution is to rely on a "builder trait", which
* needs to be defined alongside with the concrete
* ResultIter type. The actual builder trait will
* be picked up through a free function (ADL). */
ResultIter
initEvaluation (SRC const& initialElements)
{
ResultIter startSet;
return build(startSet).usingSequence(initialElements);
} // extension point: free function build (...)
/** @note \c _BUF_::getFeed is required to yield a non-empty sequence,
* until everything is exhausted. Basically the buffer- and re-integrated
* result sequences can be expected to be pulled until finding the next
* non-empty supply. This is considered hidden internal state and thus
* concealed within this \em const and \em idempotent function.
*/
ResultIter &
feed() const
{
return unConst(this)->resultBuf_.getFeed();
}
void
iterate ()
{
REQUIRE (feed());
ResultIter nextStep = explore_(*feed());
++ feed();
resultBuf_.feedBack (nextStep);
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (RecursiveExhaustingEvaluation const& seq)
{
return bool(seq.feed());
}
friend reference
yield (RecursiveExhaustingEvaluation const& seq)
{
reference result = *(seq.feed());
return result;
}
friend void
iterNext (RecursiveExhaustingEvaluation & seq)
{
seq.iterate();
}
};
/**
* Strategy building block for recursive exhausting evaluation.
* Allows to create depth-fist or breadth-first evaluation patterns, just
* by using a suitably intermediary storage container to hold the partially
* evaluated iterators created at each evaluation step. Using a stack and
* pushing results will create a depth-first pattern, while using a queue
* will evaluate in layers (breadth-first). In both cases, the next
* evaluation step will happen at the iterator returned by #getFeed.
* @warning uses an empty-iterator marker object to signal exhaustion
* - this marker \c IT() may be re-initialised concurrently
* - accessing this marker during app shutdown might access
* an already defunct object
*/
template< class IT
, template<class> class _QUEUE_ ///< the actual container to use for storage of intermediary results
>
class EvaluationBufferStrategy
{
_QUEUE_<IT> intermediaryResults_;
/** @return default constructed (=empty) iterator
* @remarks casting away const is safe here, since all
* you can do with an NIL iterator is to test for emptiness.
*/
IT &
emptySequence()
{
return unConst(NullValue<IT>::get());
} // unsafe during shutdown
public:
IT &
getFeed ()
{
// fast forward to find the next non-empty result sequence
while (intermediaryResults_ && ! *intermediaryResults_)
++intermediaryResults_;
if (intermediaryResults_)
return *intermediaryResults_;
else
return emptySequence();
}
void
feedBack (IT const& newEvaluationResults)
{
intermediaryResults_.insert (newEvaluationResults);
}
};
/**
* concrete strategy for recursive \em depth-first evaluation.
* Using heap allocated storage in a STL Deque (used stack-like)
*/
template<class IT>
struct DepthFirstEvaluationBuffer
: EvaluationBufferStrategy<IT, IterStack>
{ };
/**
* concrete strategy for recursive \em breadth-first evaluation.
* Using heap allocated storage in a STL Deque (used queue-like)
*/
template<class IT>
struct BreadthFirstEvaluationBuffer
: EvaluationBufferStrategy<IT, IterQueue>
{ };
/**
* preconfigured IterExplorer "state core" resulting in
* depth-first exhaustive evaluation
*/
template<class SRC, class FUN>
struct DepthFirstEvaluationCombinator
: RecursiveExhaustingEvaluation<SRC, FUN, DepthFirstEvaluationBuffer>
{
DepthFirstEvaluationCombinator() { }
DepthFirstEvaluationCombinator(FUN explorerFunction, SRC const& sourceElements)
: RecursiveExhaustingEvaluation<SRC, FUN, DepthFirstEvaluationBuffer> (explorerFunction,sourceElements)
{ }
};
/**
* preconfigured IterExplorer "state core" resulting in
* breadth-first exhaustive evaluation
*/
template<class SRC, class FUN>
struct BreadthFirstEvaluationCombinator
: RecursiveExhaustingEvaluation<SRC, FUN, BreadthFirstEvaluationBuffer>
{
BreadthFirstEvaluationCombinator() { }
BreadthFirstEvaluationCombinator(FUN explorerFunction, SRC const& sourceElements)
: RecursiveExhaustingEvaluation<SRC, FUN, BreadthFirstEvaluationBuffer> (explorerFunction,sourceElements)
{ }
};
/**
* IterExplorer "state core" for progressively expanding
* an initial result set. This initial set can be conceived to hold the seed
* or starting points of evaluation. Elements are consumed by an iterator, at
* the front. Each element is fed to the "explorer function". This exploration
* returns an expanded result sequence, which is immediately integrated into the
* overall result sequence, followed by further exploration of the then-to-be first
* element of the result sequence. All this exploration is driven on-demand, by
* consuming the result sequence. Exploration will proceed until exhaustion,
* in which case the exploration function will yield an empty result set.
*
* This strategy is intended for use with the IterExplorer -- most prominently
* in use for discovering render prerequisites and creating new render jobs for
* the engine. The RecursiveSelfIntegration strategy is a partially reduced
* and hard-coded variation on the #RecursiveExhaustingEvaluation in depth-first
* configuration.
* This setup works in conjunction with a <i>special result sequence</i> type,
* with the ability to re-integrate results yielded by partial evaluation.
* But the working pattern is more similar to the #CombinedIteratorEvaluation,
* where the focal point of further expansion is always at the front end of
* further items yet to be consumed and expanded; thus the evaluation is
* bound to proceed depth-first (i.e. it is \em not possible to "integrate"
* any intermediary result with the \em whole result set, only with the part
* reachable immediately at the evaluation front)
*
* \par usage considerations
* There needs to be a specific sequence or iterator type, which is used to
* hold the result set(s). This custom type together with the Explorer function
* are performing the actual expansion and re-integration steps. The latter is
* accessed through the free function \c build(sequence) -- which is expected
* to return a "builder trait" for manipulating the element set yielded by
* the custom iterator type returned by the Explorer function.
*
* @param SRC the initial result set sequence; this iterator needs to yield
* values of the special ResultIter type, which are then expanded
* until exhaustion by repeated calls to the Explorer function
* @param FUN the Explorer function of type ResultIter -> ResultIter
* @note the ResultIter type is defined implicitly through the result type
* of the Explorer function. Similarly the result value type
* is defined through the typedef \c ResultIter::value_type
* @warning beware of dangling references; make sure you never pass a
* reference or pointer through the Explorer function unaltered.
* Because some source iterator might expose a reference to a
* transient object just for the purpose of expanding it.
* The very reason of building iterator pipelines is to
* avoid heap allocation and to produce intermediaries
* on demand. So make sure in such a case that there is
* at least one real copy operation in the pipeline.
*/
template<class SRC, class FUN>
class RecursiveSelfIntegration
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename _Fun<FUN>::Sig Sig;
typedef typename SRC::value_type Val;
typedef function<Sig> Explorer;
SRC srcSeq_;
ResultIter outSeq_;
Explorer explore_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
RecursiveSelfIntegration (Explorer fun, SRC const& src)
: srcSeq_(src)
, outSeq_()
, explore_(fun)
{ }
RecursiveSelfIntegration() { };
// standard copy operations
private:
/** ensure the next elements to be processed
* will appear at outSeq_ head. When outSeq_
* is still empty after this function,
* we're done.
* @note \em not calling this function after
* construction, because the typical user
* of this template will do that implicitly
* through invocation of #checkPoint */
bool
findNextResultElement()
{
while (!outSeq_ && srcSeq_)
{
Val& nextElement(*srcSeq_);
build(outSeq_).wrapping(nextElement); // extension point: free function build(...).wrapping(...)
++srcSeq_;
}
return bool(outSeq_);
}
void
iterate ()
{
REQUIRE (outSeq_);
ResultIter nextSteps = explore_(*outSeq_);
++ outSeq_;
build(outSeq_).usingSequence(nextSteps); // extension point: free function build(...).usingSequence(...)
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (RecursiveSelfIntegration const& seq)
{
return unConst(seq).findNextResultElement();
}
friend reference
yield (RecursiveSelfIntegration const& seq)
{
return *(seq.outSeq_);
}
friend void
iterNext (RecursiveSelfIntegration & seq)
{
seq.iterate();
}
};
/**
* Helper template to bootstrap a chain of IterExplorers.
* This is a "state core", which basically just wraps a given
* source iterator and provides the necessary free functions
* (iteration control API) to use this as iteration state
* within IterExplorer.
* @note to ease building such an initial version of the Iterator Monad,
* use the free function \link #exploreIter \endlink
*/
template<class IT>
class WrappedSequence
: public IT
{
public:
WrappedSequence()
: IT()
{ }
WrappedSequence(IT const& srcIter)
: IT(srcIter)
{ }
/* === Iteration control API for IterStateWrapper == */
friend bool
checkPoint (WrappedSequence const& sequence)
{
return bool(sequence);
}
friend typename IT::reference
yield (WrappedSequence const& sequence)
{
return *sequence;
}
friend void
iterNext (WrappedSequence & sequence)
{
++sequence;
}
};
template<class SRC>
struct DepthFirst
: IterExplorer<WrappedSequence<SRC>, DepthFirstEvaluationCombinator>
{
DepthFirst() { };
DepthFirst(SRC const& srcSeq)
: IterExplorer<WrappedSequence<SRC>, DepthFirstEvaluationCombinator> (srcSeq)
{ }
};
template<class SRC>
struct BreadthFirst
: IterExplorer<WrappedSequence<SRC>, BreadthFirstEvaluationCombinator>
{
BreadthFirst() { };
BreadthFirst(SRC const& srcSeq)
: IterExplorer<WrappedSequence<SRC>, BreadthFirstEvaluationCombinator> (srcSeq)
{ }
};
}//(End) namespace iter_explorer : predefined policies and configurations }//(End) namespace iter_explorer : predefined policies and configurations
@ -892,6 +157,7 @@ namespace lib {
/* ==== convenient builder free functions ==== */ /* ==== convenient builder free functions ==== */
/*
template<class IT> template<class IT>
inline IterExplorer<iter_explorer::WrappedSequence<IT>> inline IterExplorer<iter_explorer::WrappedSequence<IT>>
exploreIter (IT const& srcSeq) exploreIter (IT const& srcSeq)
@ -915,69 +181,7 @@ namespace lib {
return iter_explorer::BreadthFirst<IT> (srcSeq); return iter_explorer::BreadthFirst<IT> (srcSeq);
} }
*/
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq4);
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4, IT const& seq5)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq5);
sequenceOfIterators.push (seq4);
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
} // namespace lib } // namespace lib

View file

@ -75,7 +75,6 @@ namespace test{
using util::isnil; using util::isnil;
using util::isSameObject; using util::isSameObject;
using lib::iter_stl::eachElm; using lib::iter_stl::eachElm;
using lib::iter_explorer::ChainedIters;
using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST;
using std::string; using std::string;
@ -134,10 +133,6 @@ namespace test{
NumberSequence(uint start, uint end) NumberSequence(uint start, uint end)
: IterStateWrapper<uint,State> (State(start,end)) : IterStateWrapper<uint,State> (State(start,end))
{ } { }
/** allow using NumberSequence in LinkedElements
* (intrusive single linked list) */
NumberSequence* next =nullptr;
}; };
inline NumberSequence inline NumberSequence
@ -155,14 +150,6 @@ namespace test{
NumberSequence NIL_Sequence; NumberSequence NIL_Sequence;
/**
* an arbitrary series of numbers
* @note deliberately this is another type
* and not equivalent to a NumberSequence,
* while both do share the same value type
*/
typedef IterQueue<int> NumberSeries;
/** Diagnostic helper: "squeeze out" the given iterator /** Diagnostic helper: "squeeze out" the given iterator
* and join all the elements yielded into a string * and join all the elements yielded into a string
@ -241,32 +228,23 @@ namespace test{
virtual void virtual void
run (Arg) run (Arg)
{ {
verifyStateAdapter(); verify_wrappedIterator();
verifyMonadOperator (); verify_mapOperation();
verifyChainedIterators(); verify_expandOperation();
verifyRawChainedIterators(); verify_expandMapCombination();
verifyDepthFirstExploration(); verify_depthFirstExploration();
verifyBreadthFirstExploration(); demonstrate_LayeredEvaluation();
verifyRecursiveSelfIntegration();
} }
/** @test demonstrate the underlying solution approach of IterExplorer. /** @test without using any extra functionality,
* All of the following IterExplorer flavours are built on top of a * TreeExplorer just wraps an iterable state.
* special iterator adapter, centred at the notion of an iterable state
* element type. The actual iterator just embodies one element of this
* state representation, and typically this element alone holds all the
* relevant state and information. Essentially this means the iterator is
* _self contained_. Contrast this to the more conventional approach of
* iterator implementation, where the iterator entity actually maintains
* a hidden back-link to some kind of container, which in turn is the one
* in charge of the elements yielded by the iterator.
*/ */
void void
verifyStateAdapter () verify_wrappedIterator()
{ {
NumberSequence ii = seq(9); NumberSequence ii = seq(9);
CHECK (!isnil (ii)); CHECK (!isnil (ii));
@ -292,266 +270,49 @@ namespace test{
/** @test verify a helper to chain a series of iterators into a "flat" result sequence. /** @test pipe each result through a transformation function
* This convenience helper is built using IterExplorer building blocks. The resulting
* iterator _combines_ and _flattens_ a sequence of source iterators, resulting in a
* simple sequence accessible as iterator again. Here we verify the convenience
* implementation; this uses a STL container (actually std:deque) behind the scenes
* to keep track of all added source iterators.
*/ */
void void
verifyChainedIterators () verify_mapOperation()
{ {
typedef ChainedIters<NumberSequence> Chain; UNIMPLEMENTED("map function onto the results");
Chain ci = iterChain (seq(5),seq(7),seq(9));
CHECK (!isnil (ci));
pullOut (ci);
CHECK ( isnil (ci));
VERIFY_ERROR (ITER_EXHAUST, *ci );
VERIFY_ERROR (ITER_EXHAUST, ++ci );
CHECK (isnil(Chain()));
CHECK (!iterChain (NIL_Sequence));
// Iterator chaining "flattens" one level of packaging
NumberSequence s9 = seq(9);
ci = iterChain (s9);
for ( ; s9 && ci; ++s9, ++ci )
CHECK (*s9 == *ci);
CHECK (isnil(s9));
CHECK (isnil(ci));
// Note: Iterator chain is created based on (shallow) copy
// of the source sequences. In case these have an independent
// per-instance state (like e.g. NumberSequence used for this test),
// then the created chain is independent from the source iterators.
s9 = seq(9);
ci = iterChain (s9);
CHECK (0 == *s9);
CHECK (0 == *ci);
pullOut (ci);
CHECK (isnil(ci));
CHECK (0 == *s9);
pullOut (s9);
CHECK (isnil(s9));
} }
/** @test variation of the iterator chaining facility. /** @test use a preconfigured "expand" functor to recurse into children
* This is the "raw" version without any convenience shortcuts.
* The source iterators are provided as iterator yielding other iterators.
*/ */
void void
verifyRawChainedIterators () verify_expandOperation()
{ {
typedef std::vector<NumberSequence> IterContainer; UNIMPLEMENTED("expand children");
typedef RangeIter<IterContainer::iterator> IterIter;
typedef ChainedIters<IterIter> Chain;
NumberSequence s5 (1,5);
NumberSequence s7 (5,8);
NumberSequence s9 (8,10);
CHECK (1 == *s5);
CHECK (5 == *s7);
CHECK (8 == *s9);
IterContainer srcIters;
srcIters.push_back (s5);
srcIters.push_back (s7);
srcIters.push_back (s9);
IterIter iti = eachElm(srcIters);
CHECK (!isnil (iti));
// note: iterator has been copied
CHECK ( isSameObject (srcIters[0], *iti));
CHECK (!isSameObject (s5, *iti));
Chain chain(iti);
CHECK (!isnil (iti));
CHECK (1 == *chain);
++chain;
CHECK (2 == *chain);
CHECK (1 == *s5); // unaffected of course...
CHECK (5 == *s7);
CHECK (8 == *s9);
++++chain;
CHECK (4 == *chain);
++chain;
CHECK (5 == *chain); // switch over to contents of 2nd iterator
++++++++chain;
CHECK (9 == *chain);
++chain;
CHECK (isnil(chain));
VERIFY_ERROR (ITER_EXHAUST, *chain );
VERIFY_ERROR (ITER_EXHAUST, ++chain );
} }
/** @test combie the recursion into children with a tail mapping operation
/** @test a depth-first visiting and exploration scheme of a tree like system,
* built on top of the IterExplorer monad.
*
* ## Test data structure
* We build a functional datastructure here, on the fly, while exploring it.
* The `exploreChildren(m)` function generates this tree like datastructure:
* For a given number, it tries to divide by 5, 3 and 2 respectively, possibly
* generating multiple decimation sequences.
*
* If we start such a tree structure e.g. with a root node 30, this scheme yields:
* \code
* ( 30 )
* ( 6 10 15 )
* ( 2 3 2 5 3 5 )
* ( 1 1 1 1 1 1 )
* \endcode
* This tree has no meaning in itself, beyond being an easy testbed for tree exploration schemes.
*
* ## How the exploration works
* We use a pre defined Template \ref DepthFirstExplorer, which is built on top of IterExplorer.
* It contains the depth-first exploration strategy in a hardwired fashion. Actually this effect is
* achieved by defining a specific way how to _combine the results of an exploration_ -- the latter
* being the function which generates the data structure. To yield a depth-first exploration, all we
* have to do is to delve down immediately into the children, right after visiting the node itself.
*
* Now, when creating such a DepthFirstExplorer by wrapping a given source iterator, the result is again
* an iterator, but a specific iterator which at the same time is a Monad: It supports the `>>=` operation
* (also known as _bind_ operator or _flatMap_ operator). This operator takes as second argument a function,
* which in our case is the function to generate or explore the data structure.
*
* The result of applying this monadic `>>=` operation is a _transformed_ version of the source iterator,
* i.e. it is again an iterator, which yields the results of the exploration function, combined together
* in the order as defined by the built-in exploration strategy (here: depth first)
*
* @note technical detail: the result type of the exploration function (here `exploreChildren()`) determines
* the iterator type used within IterExplorer and to drive the evaluation. The source sequence used to
* seed the evaluation process can actually be any iterator yielding assignment compatible values: The
* second example uses a NumberSequence with unsigned int values 0..6, while the actual expansion and
* evaluation is based on NumberSeries using signed int values.
*/ */
void void
verifyDepthFirstExploration () verify_expandMapCombination()
{ {
NumberSeries root = elements(30); UNIMPLEMENTED("combine child expansion and result mapping");
string explorationResult = materialise (depthFirst(root) >>= exploreChildren);
CHECK (explorationResult == "30-6-2-1-3-1-10-2-1-5-1-15-3-1-5-1");
NumberSequence to7 = seq(7);
explorationResult = materialise (depthFirst(to7) >>= exploreChildren);
CHECK (explorationResult == "0-1-2-1-3-1-4-2-1-5-1-6-2-1-3-1");
} }
/** @test use a preconfigured exploration scheme to expand depth-first until exhaustion
/** @test a breadth-first visiting and exploration scheme of a tree like system,
* built on top of the IterExplorer monad.
* Here, an internal queue is used to explore the hierarchy in layers.
* The (functional) datastructure is the same, just we're visiting it
* in a different way here, namely in rows or layers.
*/ */
void void
verifyBreadthFirstExploration () verify_depthFirstExploration()
{ {
NumberSeries root = elements(30); UNIMPLEMENTED("preconfigured repeated depth-first expansion");
string explorationResult = materialise (breadthFirst(root) >>= exploreChildren);
CHECK (explorationResult == "30-6-10-15-2-3-2-5-3-5-1-1-1-1-1-1");
} }
/** @test Demonstration how to build complex algorithms by layered tree expanding iteration
/** @test verify a variation of recursive exploration, this time to rely * @remarks this is the actual use case which inspired the design of TreeExplorer
* directly on the result set iterator type to provide the re-integration
* of intermediary results. Since our `exploreChildren()` function returns
* a NumberSeries, which basically is a IterQueue, the re-integration of expanded
* elements will happen at the end, resulting in breadth-first visitation order --
* but contrary to the dedicated `breadthFirst(..)` explorer, this expansion is done
* separately for each element in the initial seed sequence. Note for example how the
* expansion series for number 30, which is also generated in verifyBreadthFirstExploration(),
* appears here at the end of the explorationResult sequence
* @remarks this "combinator strategy" is really intended for use with custom sequences,
* where the "Explorer" function works together with a specific implementation
* and exploits knowledge about specifically tailored additional properties of
* the input sequence elements, in order to yield the desired overall effect.
* Actually this is what we use in the proc::engine::Dispatcher to generate
* a series of frame render jobs, including all prerequisite jobs
*/ */
void void
verifyRecursiveSelfIntegration () demonstrate_LayeredEvaluation()
{ {
typedef IterExplorer<iter_explorer::WrappedSequence<NumberSeries> UNIMPLEMENTED("build algorithm by layering iterator evaluation");
,iter_explorer::RecursiveSelfIntegration> SelfIntegratingExploration;
NumberSeries root = elements(10,20,30);
SelfIntegratingExploration exploration(root);
string explorationResult = materialise (exploration >>= exploreChildren);
CHECK (explorationResult == "10-2-5-1-1-20-4-10-2-2-5-1-1-1-30-6-10-15-2-3-2-5-3-5-1-1-1-1-1-1");
}
/** @test cover the basic monad bind operator,
* which is used to build all the specialised Iterator flavours.
* The default implementation ("Combinator strategy") just joins and flattens the result sequences
* created by the functor bound into the monad. For this test, we use a functor `explode(top)`,
* which returns the sequence 0...top.
*/
void
verifyMonadOperator ()
{
auto explode = [](uint top) { return seq(0,top); };
// IterExplorer as such is an iterator wrapping the source sequence
string result = materialise (exploreIter(seq(5)));
CHECK (result == "0-1-2-3-4");
// now, if the source sequence yields exactly one element 5...
result = materialise (exploreIter(seq(5,6)));
CHECK (result == "5");
// then binding the explode()-Function yields just the result of invoking explode(5)
result = materialise (exploreIter(seq(5,6)) >>= explode);
CHECK (result == "0-1-2-3-4");
// binding anything into an empty sequence still results in an empty sequence
result = materialise (exploreIter(seq(0)) >>= explode);
CHECK (result == "");
// also, in case the bound function yields an empty sequence, the result remains empty
result = materialise (exploreIter(seq(1)) >>= explode);
CHECK (result == "");
// combining an empty sequence and the one element sequence (seq(0,1)) results in just one element
result = materialise (exploreIter(seq(2)) >>= explode);
CHECK (result == "0");
// multiple result sequences will be joined (flattened) into one sequence
result = materialise (exploreIter(seq(5)) >>= explode);
CHECK (result == "0-0-1-0-1-2-0-1-2-3");
// since the result is a monad, we can again bind yet another function
result = materialise((exploreIter(seq(5)) >>= explode) >>= explode);
CHECK (result == "0-0-0-1-0-0-1-0-1-2");
// Explanation:
// 0 -> empty sequence, gets dropped
// 1 -> 1-element sequence {0}
// 2 -> {0,1}
// 3 -> {0,1,2}
// Note: when cascading multiple >>= the parentheses are necessary, since in C++ unfortunately
// the ">>=" associates to the right, while the proper monad bind operator should associate to the left
} }
}; };

View file

@ -4721,8 +4721,7 @@
<i>echte</i>&#160;Expand-Funktion notwendig <i>echte</i>&#160;Expand-Funktion notwendig
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
</node> </node>
<node CREATED="1510340942183" ID="ID_1468499222" MODIFIED="1510340946922" TEXT="tree expansion"/> <node CREATED="1510340942183" ID="ID_1468499222" MODIFIED="1510340946922" TEXT="tree expansion"/>
@ -4757,8 +4756,7 @@
also mehr als blo&#223; parametrisierte Typen (Templates)! also mehr als blo&#223; parametrisierte Typen (Templates)!
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1510341461168" ID="ID_862729714" MODIFIED="1510341472426" TEXT="Insofern Iterator == Monade"/> <node CREATED="1510341461168" ID="ID_862729714" MODIFIED="1510341472426" TEXT="Insofern Iterator == Monade"/>
<node CREATED="1510342283759" ID="ID_196604339" MODIFIED="1510342289707" TEXT="als Pipeline realisieren?"> <node CREATED="1510342283759" ID="ID_196604339" MODIFIED="1510342289707" TEXT="als Pipeline realisieren?">
@ -4782,8 +4780,7 @@
alles mit <i>einer</i>&#160;Form des IterExplorer machbar ist alles mit <i>einer</i>&#160;Form des IterExplorer machbar ist
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head>
@ -4802,8 +4799,7 @@
...was nicht grade zur Verst&#228;ndlichkeit des Ganzen beitr&#228;gt ...was nicht grade zur Verst&#228;ndlichkeit des Ganzen beitr&#228;gt
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1510342763622" ID="ID_1851343313" MODIFIED="1510357653178"> <node CREATED="1510342763622" ID="ID_1851343313" MODIFIED="1510357653178">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
@ -4815,8 +4811,7 @@
das <i>Fortschreiten der Berechnung</i>&#160;dargestellt werden kann das <i>Fortschreiten der Berechnung</i>&#160;dargestellt werden kann
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1510357676862" ID="ID_1057287927" MODIFIED="1510357682690" TEXT="das hei&#xdf;t..."> <node CREATED="1510357676862" ID="ID_1057287927" MODIFIED="1510357682690" TEXT="das hei&#xdf;t...">
<node CREATED="1510357692028" ID="ID_42511341" MODIFIED="1510357698567" TEXT="wie werden aus einem a mehrere b?"/> <node CREATED="1510357692028" ID="ID_42511341" MODIFIED="1510357698567" TEXT="wie werden aus einem a mehrere b?"/>
@ -4839,8 +4834,7 @@
Problem: Layer sind <i>verkoppelt</i> Problem: Layer sind <i>verkoppelt</i>
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
</node> </node>
</node> </node>
@ -4856,8 +4850,7 @@
dann aber als <b>State Monad</b> dann aber als <b>State Monad</b>
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1510365950652" ID="ID_978128618" MODIFIED="1510365959420" TEXT="State Monad"> <node CREATED="1510365950652" ID="ID_978128618" MODIFIED="1510365959420" TEXT="State Monad">
<icon BUILTIN="info"/> <icon BUILTIN="info"/>
@ -4875,8 +4868,7 @@
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;in (f x) s &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;in (f x) s
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<node CREATED="1510366044023" ID="ID_72536689" MODIFIED="1510366073855" TEXT="Argument: ein State r"/> <node CREATED="1510366044023" ID="ID_72536689" MODIFIED="1510366073855" TEXT="Argument: ein State r"/>
<node CREATED="1510366074110" ID="ID_689602412" MODIFIED="1510366201735" TEXT="wende Basis-Monade auf r an"> <node CREATED="1510366074110" ID="ID_689602412" MODIFIED="1510366201735" TEXT="wende Basis-Monade auf r an">
<icon BUILTIN="full-1"/> <icon BUILTIN="full-1"/>
@ -4897,8 +4889,7 @@
auf den Zwischenzustand x aus (1) an auf den Zwischenzustand x aus (1) an
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="full-3"/> <icon BUILTIN="full-3"/>
</node> </node>
</node> </node>
@ -4926,8 +4917,7 @@
wirklich hilfreich? wirklich hilfreich?
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
<node CREATED="1510446351987" ID="ID_1280916101" MODIFIED="1510446355022" TEXT="steile These"> <node CREATED="1510446351987" ID="ID_1280916101" MODIFIED="1510446355022" TEXT="steile These">
<node CREATED="1510446304314" ID="ID_628535706" MODIFIED="1510446320689" TEXT="Zustand ist ein Ph&#xe4;nomen der wirklichen Welt"/> <node CREATED="1510446304314" ID="ID_628535706" MODIFIED="1510446320689" TEXT="Zustand ist ein Ph&#xe4;nomen der wirklichen Welt"/>
@ -4972,7 +4962,7 @@
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510540265979" ID="ID_1160853986" MODIFIED="1510940473230"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510540265979" HGAP="17" ID="ID_1160853986" MODIFIED="1510970236631" VSHIFT="26">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head>
@ -4985,8 +4975,7 @@
brauche... brauche...
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="pencil"/> <icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510540282280" ID="ID_304955672" MODIFIED="1510940463183" TEXT="Baum-Explorer"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510540282280" ID="ID_304955672" MODIFIED="1510940463183" TEXT="Baum-Explorer">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="flag-yellow"/>
@ -5008,8 +4997,7 @@
das impliziert <i>grunds&#228;tzlich</i>&#160;einen <b>Stack</b> das impliziert <i>grunds&#228;tzlich</i>&#160;einen <b>Stack</b>
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
</node> </node>
</node> </node>
@ -5021,7 +5009,8 @@
</node> </node>
<node CREATED="1510939495862" ID="ID_1918069733" MODIFIED="1510939511038" TEXT="Monade?"> <node CREATED="1510939495862" ID="ID_1918069733" MODIFIED="1510939511038" TEXT="Monade?">
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
<node CREATED="1510939532689" ID="ID_608280633" MODIFIED="1510939562048" TEXT="konventionelle L&#xf6;sung"> <node CREATED="1510939532689" ID="ID_608280633" MODIFIED="1510970210061" TEXT="konventionelle L&#xf6;sung">
<icon BUILTIN="button_cancel"/>
<node CREATED="1510939567867" ID="ID_1799788775" MODIFIED="1510939832540" TEXT="expand: S -&gt; S"/> <node CREATED="1510939567867" ID="ID_1799788775" MODIFIED="1510939832540" TEXT="expand: S -&gt; S"/>
<node CREATED="1510939642250" ID="ID_456598029" MODIFIED="1510939827820" TEXT="S = opaque state"/> <node CREATED="1510939642250" ID="ID_456598029" MODIFIED="1510939827820" TEXT="S = opaque state"/>
<node CREATED="1510939675821" ID="ID_71307720" MODIFIED="1510939825173" TEXT="eigentliche Erweiterung ist in S implementiert"/> <node CREATED="1510939675821" ID="ID_71307720" MODIFIED="1510939825173" TEXT="eigentliche Erweiterung ist in S implementiert"/>
@ -5030,7 +5019,8 @@
<node CREATED="1510939778231" ID="ID_763925317" MODIFIED="1510939816118" TEXT="S mu&#xdf; auf die Verwendung im Baum-Explorer vorbereitet sein"/> <node CREATED="1510939778231" ID="ID_763925317" MODIFIED="1510939816118" TEXT="S mu&#xdf; auf die Verwendung im Baum-Explorer vorbereitet sein"/>
<node CREATED="1510940187687" ID="ID_349334428" MODIFIED="1510940196762" TEXT="triviale Implementierung kan sehr effizient sein"/> <node CREATED="1510940187687" ID="ID_349334428" MODIFIED="1510940196762" TEXT="triviale Implementierung kan sehr effizient sein"/>
</node> </node>
<node CREATED="1510939552942" ID="ID_510344823" MODIFIED="1510939566616" TEXT="modadische L&#xf6;sung"> <node CREATED="1510939552942" ID="ID_510344823" MODIFIED="1510970213063" TEXT="modadische L&#xf6;sung">
<icon BUILTIN="button_ok"/>
<node CREATED="1510939598175" ID="ID_1272498716" MODIFIED="1510939839411" TEXT="expand: S -&gt; BaumExplorer&lt;S&gt;"/> <node CREATED="1510939598175" ID="ID_1272498716" MODIFIED="1510939839411" TEXT="expand: S -&gt; BaumExplorer&lt;S&gt;"/>
<node CREATED="1510939845662" ID="ID_581825327" MODIFIED="1510939852465" TEXT="S = opaque State"/> <node CREATED="1510939845662" ID="ID_581825327" MODIFIED="1510939852465" TEXT="S = opaque State"/>
<node CREATED="1510939856845" ID="ID_1492383135" MODIFIED="1510939877062" TEXT="Erweiterungs-Mechanismus im Baum-Explorer implementiert"/> <node CREATED="1510939856845" ID="ID_1492383135" MODIFIED="1510939877062" TEXT="Erweiterungs-Mechanismus im Baum-Explorer implementiert"/>
@ -5047,8 +5037,7 @@
&#160;f&#252;r diesen Expand-Mechanismus auf &#160;f&#252;r diesen Expand-Mechanismus auf
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1510940053626" ID="ID_865181855" MODIFIED="1510940069076" TEXT="S kann Wertsemantik (aber auch Referenz-Semantik) haben"/> <node CREATED="1510940053626" ID="ID_865181855" MODIFIED="1510940069076" TEXT="S kann Wertsemantik (aber auch Referenz-Semantik) haben"/>
<node CREATED="1510940088149" ID="ID_791410014" MODIFIED="1510940110614" TEXT="S mu&#xdf; nicht speziell vorbereitet sein (nur konstruierbar)"/> <node CREATED="1510940088149" ID="ID_791410014" MODIFIED="1510940110614" TEXT="S mu&#xdf; nicht speziell vorbereitet sein (nur konstruierbar)"/>
@ -5074,8 +5063,7 @@
indem man einen speziellen <i>Inline-Stack mit Heap-Overflow</i>&#160;nutzt indem man einen speziellen <i>Inline-Stack mit Heap-Overflow</i>&#160;nutzt
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510939517499" ID="ID_1100296394" MODIFIED="1510940150893" TEXT="das ist eine Weichenstellung"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510939517499" ID="ID_1100296394" MODIFIED="1510940150893" TEXT="das ist eine Weichenstellung">
@ -5086,6 +5074,10 @@
</node> </node>
<node CREATED="1510540333481" ID="ID_1605100271" MODIFIED="1510540361801" TEXT="Rekursive Zustandsauswertung"> <node CREATED="1510540333481" ID="ID_1605100271" MODIFIED="1510540361801" TEXT="Rekursive Zustandsauswertung">
<node CREATED="1510541206810" ID="ID_1795866831" MODIFIED="1510541211885" TEXT="bindet Schritt-Funktion"/> <node CREATED="1510541206810" ID="ID_1795866831" MODIFIED="1510541211885" TEXT="bindet Schritt-Funktion"/>
<node CREATED="1510970252162" ID="ID_1591961626" MODIFIED="1510970261786" TEXT="Layered Iterator Evaluation"/>
<node CREATED="1510970268485" ID="ID_1500401518" MODIFIED="1510970288103" TEXT="m&#xf6;glicherweise fest vorkonfigurierbarer Builder hierf&#xfc;r">
<icon BUILTIN="idea"/>
</node>
</node> </node>
<node CREATED="1510540399304" ID="ID_300971395" MODIFIED="1510540401532" TEXT="Filter"> <node CREATED="1510540399304" ID="ID_300971395" MODIFIED="1510540401532" TEXT="Filter">
<node CREATED="1510541335201" ID="ID_1717169058" MODIFIED="1510541339780" TEXT="fischt nach L&#xf6;sungen"/> <node CREATED="1510541335201" ID="ID_1717169058" MODIFIED="1510541339780" TEXT="fischt nach L&#xf6;sungen"/>
@ -5108,6 +5100,24 @@
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510941467586" ID="ID_381928532" MODIFIED="1510941523722" TEXT="TreeExplorer_test"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510941467586" ID="ID_381928532" MODIFIED="1510941523722" TEXT="TreeExplorer_test">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031378" ID="ID_1678287752" MODIFIED="1510969040176" TEXT="verify_wrappedIterator();">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031379" ID="ID_358406634" MODIFIED="1510969041003" TEXT="verify_mapOperation();">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031379" ID="ID_1298407683" MODIFIED="1510969041717" TEXT="verify_expandOperation();">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031379" ID="ID_722056043" MODIFIED="1510969042406" TEXT="verify_expandMapCombination();">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031379" ID="ID_1327871737" MODIFIED="1510969042972" TEXT="verify_depthFirstExploration();">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1510969031379" ID="ID_842384656" MODIFIED="1510969043561" TEXT="demonstrate_LayeredEvaluation();">
<icon BUILTIN="flag-yellow"/>
</node>
</node> </node>
</node> </node>
</node> </node>