coriolis/kite/doc/SegmentFsm.dox

475 lines
25 KiB
C++

// -*- C++ -*-
namespace Kite {
// -------------------------------------------------------------------
// Class : "SegmentAction".
/*! \class SegmentAction
* \brief Store request for an event to be generated on a TrackElement
*
* When an event on a Kite::TrackElement is being processed (with the
* SegmentFsm helper), it may generate events on TrackElement already
* placed and belonging either to the same net or other ones.
* Those events are not generated and queued immediatly but
* instead SegmentAction, requesting the event generation are created
* and stored into a simple vector in SegmentFsm. The last operation of
* the SegmentFsm object is to call the SegmentAction::doAction() method
* on all the action to actually generate and queue the events.
*/
//! \enum SegmentAction::Type
//! Indicates the kind of action to be performed on the segment. In the following
//! \b flags and \b masks descriptions, we uses the term <em>reference segment</em>
//! for the TrackElement which is associated with the currently processed RoutingEvent
//! (also referenced in SegmentFsm).
//!
//! Here is the list of the availables actions that can be performed when (re)scheduling
//! a RoutingEvent. It is here that we uses the RoutingEvent level feature to perform
//! a local reordering of the top of the queue. Reordering is used to allows
//! perpandiculars to be routed \e before the reference segment (instead of after)
//! or \e other segments in conflict.
//!
//! - SegmentAction::SelfInsert<br>
//! <b>Action:</b> The reference segment is to be inserted in a Track (placed).<br>
//! <b>Event Level:</b> Unchanged.
//!
//! - SegmentAction::SelfRipup<br>
//! <b>Action:</b> The reference segment is to be ripped up.<br>
//! <b>Event Level:</b> Unchanged.
//!
//! - SegmentAction::SelfRipupPerpand<br>
//! <b>Action:</b> Ripup a segment which is a perpandicular to the reference
//! segment. Ordering considerations: this perpandicular will be put back into
//! the RoutingEvent queue with a lower level (priority) than the reference
//! segment, so it will be processed again \e after the reference segment.<br>
//! <b>Event Level:</b> Unchanged.
//!
//! - SegmentAction::SelfRipupPerpandWithAxisHint<br>
//! <b>Action:</b> Ripup a segment which is a perpandicular to the reference
//! segment, supplies an axis hint and put it back into the RoutingEvent queue so
//! that it will be processed \e before the reference segment.<br>
//! <b>Event Level:</b> Increased to SegmentAction::EventLevel4.
//!
//! - SegmentAction::OtherRipup<br>
//! <b>Action:</b> Ripping up a segment from another net and in the same direction
//! as the reference segment.<br>
//! <b>Event Level:</b> Unchanged.
//!
//! - SegmentAction::OtherRipupPerpandAndPushAside<br>
//! <b>Action:</b> Ripping up a segment from another net and in perpandicular
//! direction. The level is elevated so it's priority is greater than the
//! reference segment this it will be reprocessed first. An axis hint is also
//! supplied in order to make room for the reference segment.<br>
//! <b>Event Level:</b> Increased to SegmentAction::EventLevel3.
//!
//! - SegmentAction::OtherRipupPerpandAndPacking<br>
//! <b>Action:</b> Ripping up a segment from another net and in perpandicular
//! direction. The level is elevated so it's priority is greater than the
//! reference segment this it will be reprocessed first. The generated event
//! is in packing mode only.<br>
//! <b>Event Level:</b> Increased to SegmentAction::EventLevel4.
//! \var SegmentAction::Self
//! <b>[Flag]</b> The segment associated to the action is the reference segment
//! <em>or segments from the same net</em>.
//! \var SegmentAction::Other
//! <b>[Flag]</b> The segment associated to the action is \b not from the same
//! net as the reference segment.
//! \var SegmentAction::Perpandicular
//! <b>[Flag]</b> The action concern a perpandicular to the reference segment.
//! \var SegmentAction::Ripup
//! <b>[Flag]</b> Request that the segment is to be ripped up.
//! \var SegmentAction::RipedByLocal
//! <b>[Flag]</b> Indicate that the segment has been ripped up by a local one.
//! \var SegmentAction::ResetRipup
//! <b>[Flag]</b> The ripup count is to be reset.
//! \var SegmentAction::ToRipupLimit
//! <b>[Flag]</b> The ripup count is directly increased to the ripup limit,
//! triggering a state change the next time the segment will be processed.
//! \var SegmentAction::Insert
//! <b>[Flag]</b> Request that the segment is to be inserted in the given track.
//! It is the task of SegmentFsm to determine that there is sufficent space to do so.
//! \var SegmentAction::AxisHint
//! <b>[Flag]</b> An axis hint has been supplied, and is to be passed to
//! the generated RoutingEvent.
//! \var SegmentAction::PackingMode
//! <b>[Flag]</b> Whether the RoutingEvent should be processed in \e packing
//! mode or \e negociated mode (transmitted to the RoutingEvent).
//! \var SegmentAction::ToState
//! <b>[Flag]</b> Force the change of state of the RoutingEvent
//! (i.e. DataNegociate). Normally the state change is done through the
//! increase of the ripup count in DataNegociate.
//! \var SegmentAction::EventLevel1
//! <b>[Flag]</b> Increase the level to <em>at least</em> \b 1.
//! \var SegmentAction::EventLevel2
//! <b>[Flag]</b> Increase the level to <em>at least</em> \b 2.
//! \var SegmentAction::EventLevel3
//! <b>[Flag]</b> Increase the level to <em>at least</em> \b 3.
//! \var SegmentAction::EventLevel4
//! <b>[Flag]</b> Increase the level to <em>at least</em> \b 4.
//! \var SegmentAction::EventLevel5
//! <b>[Flag]</b> Increase the level to <em>at least</em> \b 5.
//! \var SegmentAction::SelfInsert
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::SelfRipup
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::SelfRipupPerpand
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::SelfRipupPerpandWithAxisHint
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::OtherRipup
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::OtherRipupPerpandAndPushAside
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \var SegmentAction::OtherRipupPerpandAndPacking
//! <b>[Mask]</b>, see SegmentAction::Type.
//! \function SegmentAction::SegmentAction ( TrackElement* segment, unsigned int type, DbU::Unit axisHint=0, unsigned int toState =0 );
//! \param segment On what the action is to be performed.
//! \param type Defines the type of action, see SegmentAction::Type.
//! \param axisHint Specifies a preferred axis.
//! \param toState The DataNegociate::SlackState into which the segment is to be set.
//!
//! Create segment action.
//! \function TrackElement* SegmentAction::getSegment () const;
//! \sreturn The associated \c segment.
//! \function SegmentAction::Type SegmentAction::getType () const;
//! \sreturn The action to be performed.
//! \function void SegmentAction::setAxisHint ( DbU::Unit axis );
//! The axis preferred position to be transmitted to the generated event.
//! The transmition will be effective \e only if the SegmentAction::Type::AxisHint
//! flag is set.
//! \function unsigned int SegmentAction::setFlag ( unsigned int flags );
//! Allow to change the action type by indivually setting up the flags.
//! \function void SegmentAction::doAction ( RoutingEventQueue& queue );
//! Actually perform the action. That is, build and queue the appropriate
//! event for the segment.
// -------------------------------------------------------------------
// Class : "SegmentFsm".
/*! \class SegmentFsm
* \brief Pseudo-decorator to process a RoutingEvent
*
* The SegmentFsm class actually perform the placement of the Kite::TrackElement
* of the Kite::RoutingEvent. It structured around three goals:
* - Implement the finite state machine for the Kite::DataNegociate state.
* - Provide a kind of decoration on the RoutingEvent/TrackElement
* (it do not abide by the definition from Design Patterns).
* - Cache a lot of on-the-fly computed datas needed during the
* SegmentFsm lifetime and the Manipulator(s) it may uses.
*
*
* \section secUpdate Update Mechanism
*
* The constructor of SegmentFsm triggers the update of the RoutingEvent
* and through it DataNegociate.
*
*
* \section secSlackening Slackening / FSM Transitions
*
* A transition occurs in the FSM whenener all the availables ripup methods
* for a segment have failed. Failure means that the topology of the net
* itself must be altered to allow a greater level of flexibility.
* Modifying the net topology means to give the current segment some
* more slack.
*
* Availables slackening operations:
* -# DataNegociate::RipupPerpandiculars (Manipulator) place the segments before any of
* it's perpandiculars are placed to allow a maximum track choice.
* -# DataNegociate::Minimize (Manipulator) try to fit the segment in a hole in a track,
* perform a hole detection.
* -# DataNegociate::Dogleg (Manipulator) create a dogleg matching <em>the first track
* candidate</em> with a non-nul overlap.
* -# DataNegociate::Slacken (Manipulator) \red{to be reviewed.}
* -# DataNegociate::ConflictSolveByHistory (SegmentFsm) try to find a break point on
* the segment, based on the ripup history.
* -# DataNegociate::ConflictSolveByPlaceds (SegmentFsm) try to find a break point on
* the segment, based on the current position of segments on the
* candidate tracks.
* -# DataNegociate::MoveUp (Manipulator) try to move up the segment.
*
* Simple slackening operations are defined in Manipulator and complex ones
* directly in SegmentFsm.
*
*
* \section secNonSlackening Non-Slackening Operations
*
* In addition, some operation that do not modifies the topology are
* availables:
* -# Manipulator::forceOverLocals() mostly for global segments to ripup
* a track from all it's locals.
* -# SegmentFsm::insertInTrack() automates the three subsequent ripup
* trials.
*/
//! \enum SegmentFsm::State
//! Indicates what the SegmentFsm has done the processed TrackElement,
//! possible values are:
//! - SegmentFsm::MissingData, this is an error condition, the TrackElement
//! do not have associated DataNegociate structure. Nothing is done.
//!
//! - SegmentFsm::EmptyTrackList, no Track is available for placement
//! (free or used).
//!
//! - SegmentFsm::SelfInserted, the TrackElement can be successfully
//! inserted in a Track (i.e. without overlap).
//!
//! - SegmentFsm::SelfMaximumSlack, nothing can be done to further slacken
//! the TrackElement, it is at maximum ripup of the last possible state
//! (no more topological modifications are possibles).
//!
//! - SegmentFsm::OtherRipup, the TrackElement can be inserted but it
//! needs the ripup of some others.
//! \var SegmentFsm::MissingData
//! <b>[Flag]</b>, see SegmentFsm::SegmentFsmValue.
//! \var SegmentFsm::EmptyTrackList
//! <b>[Flag]</b>, see SegmentFsm::SegmentFsmValue.
//! \var SegmentFsm::Inserted
//! <b>[Flag]</b>, the TrackElement can be inserted in a Track.
//! \var SegmentFsm::Self
//! <b>[Flag]</b>, the action is related to the processed TrackSegment.
//! \var SegmentFsm::Other
//! <b>[Flag]</b>, the action is \b not related to the processed TrackSegment,
//! that is, others are being topologically modificated or riped up.
//! \var SegmentFsm::Ripup
//! <b>[Flag]</b>, segement, that are not the processed one are being ripped up.
//! \var SegmentFsm::MaximumSlack
//! <b>[Flag]</b>, the processed segment as reached it's maximum ripup count on
//! the last possible slackening state.
//! \var SegmentFsm::SelfInserted
//! <b>[Mask]</b>, see SegmentFsm::SegmentFsmValue.
//! \var SegmentFsm::OtherRipup
//! <b>[Mask]</b>, see SegmentFsm::SegmentFsmValue.
//! \var SegmentFsm::SelfMaximumSlack
//! <b>[Mask]</b>, see SegmentFsm::SegmentFsmValue.
//! \function SegmentFsm::SegmentFsm ( RoutingEvent* event, RoutingEventQueue& queue, RoutingEventHistory& history );
//! \param event The RoutingEvent to be processed.
//! \param queue The RoutingEvent queue.
//! \param history The complete history of RoutingEvent.
//!
//! Construct a SegmentFsm from a RoutingEvent. The constructor is in charge of
//! computing all the cached values.
//! \function bool SegmentFsm::isFullBlocked () const;
//! \sreturn \true if there are Tracks avalaibles but the constraints are such that none
//! is actually usable.
//! \function RoutingEvent* SegmentFsm::getEvent () const;
//! \sreturn The currently processed RoutingEvent (\e cached).
//! \function RoutingEventQueue& SegmentFsm::getQueue () const;
//! \sreturn The RoutingEvent queue (\e cached).
//! \function RoutingEventHistory& SegmentFsm::getHistory () const;
//! \sreturn The RoutingEvent history (\e cached).
//! \function DataNegociate* SegmentFsm::getData ();
//! \sreturn The DataNegociate of the TrackElement (\e cached).
//! \function unsigned int SegmentFsm::getState () const;
//! \sreturn The state (SegmentFsm::SegmentFsmValues) which the SegmentFsm has computed for the
//! RoutingEvent. This is \b not the state of the DataNegociate
//! \function Interval& SegmentFsm::getConstraint ();
//! \sreturn The interval into which the segment axis can be set (computed from
//! the topological constraints and the placement constraints on the
//! already placed perpandiculars).
//! \function Interval& SegmentFsm::getOptimal ();
//! \sreturn The interval for an optimal placement of the segment axis.
//! \function vector<TrackCost>& SegmentFsm::getCosts ();
//! \sreturn The table of cost for all the candidates Tracks of the segment.
//! The table is sorted in increasing cost order (see TrackCost).
//! \function TrackCost& SegmentFsm::getCost ( size_t i );
//! \sreturn The cost at index \c i in the table.
//! \function Track* SegmentFsm::getTrack ( size_t i );
//! \sreturn The Track for cost at index \c i in the table.
//! \function size_t SegmentFsm::getBegin ( size_t i );
//! \sreturn The overlapping \e begin index in Track for cost at index \c i in the table.
//! \function size_t SegmentFsm::getEnd ( size_t i );
//! \sreturn The overlapping \e end index in Track for cost at index \c i in the table.
//! \function vector<SegmentAction*>& SegmentFsm::getActions ();
//! \sreturn The table of SegmentAction, that is the delayed requests for RoutingEvent
//! creation.
//! \function unsigned int SegmentFsm::setState ( unsigned int state );
//! \sreturn Sets the state of the state...
//! \function void SegmentFsm::addAction ( TrackElement* segment, unsigned int type, DbU::Unit axisHint=0, unsigned int toState=0 );
//! Request the creation of a new delayed RoutingEvent, for the meaning of
//! the parameters, see SegmentAction::SegmentAction.
//! \function bool SegmentFsm::doActions ();
//! Actually generate RoutingEvent(s) from the SegmentAction(s).
//! \function void SegmentFsm::clearActions ();
//! Clear the the table of requested actions, whithout generating them.
//! \function void SegmentFsm::clearActions ();
//! Clear the the table of requested actions, whithout generating them.
//! \function bool SegmentFsm::insertInTrack ( size_t i );
//! Try to insert the TrackElement in the Track at index \c i (in the
//! cost table). Return \true if the insertion is possible.
//!
//! The insertion is not done at this stage, but a set of ripup actions is
//! emitted to allow insertion the next time the segment will be processed.
//!
//! Three subsequent trials are done before giving up on inserting
//! the segment:
//! -# Manipulator::insertInTrack(), try to push asides the neighbors.
//! -# Manipulator::shrinkToTrack(), try squeeze the segment in an existing
//! free space.
//! -# Manipulator::forceToTrack(), perform a complete ripup of all the
//! neighbors and their perpandiculars.
//!
//! The event keeps track of the insertion attempt step (see RoutingEvent::getInsertState()).
//! \function bool SegmentFsm::conflictSolveByHistory ();
//! \sreturn \true if a suitable dogleg has been created in the segment.
//!
//! Initially, global segments may be very long, and a placement solution
//! in which each one is placed on a track of it's own may not be realisable.
//! In that case, at least one of the global segment must be broken.
//! The figure below illustrate the case: <b>(a)</b>, <b>(b)</b>, <b>(c)</b> form a
//! first cluster and <b>(d)</b>, <b>(e)</b>, <b>(f)</b> form a second one. Due to the
//! constraints of the segments the remaining free track cannot be the same
//! in both clusters. The only solution to place <b>(g)</b> is to break it into
//! two sub-globals. The whole point of the conflict solve is to correctly
//! detect the cluster and choose the breaking point.
//!
//! \image html ConflictSolve-1.png "Conflict Between Globals"
//!
//! This variant of the conflict solve method try to guess the track span
//! for which there is a conflict by looking at the event history.
//!
//! \image html ConflictSolveByHistory-1.png "Building Conflicting Intervals"
//!
//! <b>Dislodger Definition:</b>
//!
//! A segment is said to be a dislodger if it matches the two following criterions:
//! - It's span intersect the to be inserted segment span.
//! - It has been placed on a track inside the perpandicular span of the
//! to be placed segment.
//!
//! For the time beeing we limit the search to the last three dislodgers, to not
//! waste too much time looking back the event history. We merge overlapping
//! intervals into one (see the undocumented class \c UnionIntervals and
//! \c RipupHistory in \c SegmentFsm.cpp).
//!
//! \red{For the time beeing we only look on the track into which}
//! \red{the to be inserted segment wants to be placed.}
//!
//! Then we try to break the to be placed segment, first under the lower bound
//! (source) of the conflicting interval then, in case of failure under
//! the upper bound (target).
//!
//! \image html ConflictSolveByHistory-2.png "Interval Breaking"
//! \function bool SegmentFsm::conflictSolveByPlaceds ();
//! \sreturn \true if a suitable dogleg has been created in the segment \e or a
//! dislodger has been moved up.
//!
//! This methods achieve the same goal as SegmentFsm::conflictSolveByHistory()
//! but uses a different strategy.
//!
//! Instead of looking through the history to find dislodgers it analyses
//! the placed segments in all the candidates tracks for the to be placed
//! segment. Unlike it's sibling method, which creates only one dogleg, as
//! it uses the Manipulator::relax() method, it may creates up to two doglegs.
//!
//! <b>Synthetic Description</b>
//!
//! -# For each track, find the dislodgers, merge the overlaps into one
//! interval and store the length of the longuest overlap (aka conflict).
//! -# Sort the tracks according to decreasing longuest overlap/confict.
//! -# For each track in the sorted list, look for a dislodger under the middle
//! of the to be placed segment. If no dislodger is present at this place
//! go to the next track. Otherwise:
//! - <em>The dislodger is local</em>, then try to relax the to placed
//! segment around the dislodger.
//! - <em>The dislodger is global</em>, try to move it up, if it is not
//! possible, fallback to the relax approach.
//! -# Quit on the first successful move up or relax.
//! -# If there is no candidate tracks, this means the vertical constraints
//! are too tight, in that case, ripup the perpandiculars (fallback plan).
//!
//! <b>Interval Accounting</b>
//!
//! Only global conflicting segments are took into account. Local segments
//! may be took into account if they overlap global ones (all part of the
//! same net). All overlapping segments are merged into one big conflict
//! interval. The whole length of a conflict interval is took into account
//! event if it's overlap with the to be placed segment is only partial.
//!
//! <b>Track Ordering (lexicographic)</b>
//!
//! -# The longuest (in one interval) conflict length.
//! -# The longuest cumulative conflict length (all interval summed up).
//!
//! Interval accounting and Track ordering is managed through the undocumented
//! \c Cs1Candidate class implemented in \c SegmentFsm.cpp.
//!
//! \image html ConflictSolveByPlaceds-1.png "Candidates Track Ordering"
//! \function bool SegmentFsm::desaturate ();
//! Try to create a suitable empty space in a cost Track by moving up
//! TrackElement in conflict.
//! \function bool SegmentFsm::slackenTopology ( unsigned int flags=0 );
//! Modificate the topology of the TrackElement to slacken it.
//! It is the implementation of the slakening finite state machine.
//! \function bool SegmentFsm::solveFullBlockages ();
//! Try to solve a fully blocked configuration.
}