CrystalSpace

Public API Reference

csutil/partialorder.h

Go to the documentation of this file.
00001 /* -*- Mode: C++; c-basic-offset: 2 -*-
00002    Copyright (C) 2005 by Adam D. Bradley <[email protected]>
00003    
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008    
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013    
00014    You should have received a copy of the GNU Library General Public
00015    License along with this library; if not, write to the Free
00016    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 #ifndef __CS_UTIL_PO_H__
00020 #define __CS_UTIL_PO_H__
00021 
00026 #include "csextern.h"
00027 #include "csutil/array.h"
00028 #include "csutil/comparator.h"
00029 #include "csutil/hash.h"
00030 #include "csutil/list.h"
00031 #include "csutil/ref.h"
00032 #include "csutil/util.h"
00033 
00034 #ifdef ADB_DEBUG
00035 #include "csutil/eventhandlers.h"
00036 #include <iostream>
00037 #endif /* ADB_DEBUG */
00038 
00051 template <class T>
00052 class CS_CRYSTALSPACE_EXPORT csPartialOrder
00053 {
00054 protected:
00055   class Node
00056   {
00057   public:
00058     Node(const Node &other) 
00059       : self(other.self), output(other.output),
00060         marked(other.marked),
00061         pre(other.pre), post(other.post)
00062     { }
00063     Node(const T &id)
00064       : self(id), output(false), marked(false),
00065         pre(), post()
00066     { }
00067     const T self;
00068     bool output;
00069     bool marked;
00070     csArray<size_t> pre;
00071     csArray<size_t> post;
00072   };
00073   csArray<Node> Nodes;
00074   csHash<size_t,const T> NodeMap;
00075         
00076 public:
00078   csPartialOrder ()
00079     : Nodes (), NodeMap()
00080   {
00081     return;
00082   }
00083 
00085   csPartialOrder(const csPartialOrder &other)
00086     : Nodes (other.Nodes), NodeMap (other.NodeMap)
00087   {
00088     return;
00089   }
00090 
00091 #ifdef ADB_DEBUG
00092   // This code is particular to the csHandlerID scheduler.
00093   void Dump (iObjectRegistry *objreg)
00094   {
00095     std::cerr << "Dumping PO Graph..." << std::endl;
00096     for (size_t i=0 ; i<Nodes.Length() ; i++)
00097     {
00098       std::cerr << "  NODE: " << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[i].self) << std::endl;
00099       std::cerr << "    pre: ";
00100       for (size_t j=0 ; j<Nodes[i].pre.Length() ; j++) 
00101       {
00102         std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[Nodes[i].pre[j]].self) << " ";
00103       }
00104       std::cerr << std::endl << "    post: ";
00105       for (size_t j=0 ; j<Nodes[i].post.Length() ; j++)
00106       {
00107         std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[Nodes[i].post[j]].self) << " ";
00108       }
00109       std::cerr << std::endl;
00110     }
00111     std::cerr << "End PO Graph, printing a solution..." << std::endl;
00112     csList<const T> Solution;
00113     Solve (Solution);
00114     while (!Solution.IsEmpty ())
00115     {
00116       std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Solution.Front()) << " ";
00117       Solution.PopFront();
00118     }
00119     std::cerr << std::endl << "Done." << std::endl << std::endl;
00120   }
00121 #endif /* ADB_DEBUG */
00122 
00124   csPartialOrder(const csPartialOrder *other)
00125     : Nodes (other->Nodes), NodeMap (other->NodeMap)
00126   {
00127     return;
00128   }
00129   
00131   void Add (const T& node)
00132   {
00133     SanityCheck();
00134     if (NodeMap.Get(node, csArrayItemNotFound) == csArrayItemNotFound) 
00135     {
00136       NodeMap.PutUnique(node, Nodes.Push(node));
00137     }
00138     SanityCheck();
00139   }
00140 
00142   bool Contains (const T& node)
00143   {
00144     return (NodeMap.Get(node, csArrayItemNotFound) != csArrayItemNotFound);
00145   }
00146 
00148   bool Contains (const T& pre, const T& post)
00149   {
00150     if (!Contains (pre) || !Contains (post))
00151       return false;
00152     size_t PreIdx = NodeMap.Get (pre, csArrayItemNotFound);
00153     size_t PostIdx = NodeMap.Get (post, csArrayItemNotFound);
00154     for (size_t i=0 ; i<Nodes[PreIdx].post.Length() ; i++)
00155     {
00156       if (Nodes[PreIdx].post[i] == PostIdx)
00157       {
00158         return true;
00159       }
00160     }
00161     return false;
00162   }
00163   
00165   void Delete (const T& node)
00166   {
00167     SanityCheck();
00168     size_t p = NodeMap.Get(node, csArrayItemNotFound);
00169     CS_ASSERT(p!=csArrayItemNotFound);
00170     CS_ASSERT(p < Nodes.Length());
00171     // delete all posts pointing to node
00172     for (size_t iter=0 ; iter<Nodes[p].pre.Length() ; iter++) 
00173     {
00174       Nodes[Nodes[p].pre[iter]].post.Delete(p);
00175     }
00176     // delete node's pre's
00177     Nodes[p].pre.DeleteAll();
00178     // delete all pres pointing to node
00179     for (size_t iter=0 ; iter<Nodes[p].post.Length() ; iter++) 
00180     {
00181       Nodes[Nodes[p].post[iter]].pre.Delete(p);
00182     }
00183     // delete node's post's
00184     Nodes[p].post.DeleteAll();
00185     // delete node p, move the node at the end of the csArray into its place...
00186     Nodes.DeleteIndexFast(p);
00187 
00188     // update NodeMap accordingly by killing the lookup for the deleted node
00189     // and updating the lookup for the node that moved into its place...
00190     NodeMap.Delete(node, p);
00191     if (Nodes.Length() > p)
00192     {
00193       // who got moved into "p"?
00194       size_t moved = NodeMap.Get(Nodes[p].self, csArrayItemNotFound);
00195       CS_ASSERT (moved != csArrayItemNotFound);
00196 
00197       // change references to "moved" to reference "p"
00198       for (size_t iter=0 ; iter<Nodes.Length() ; iter++)
00199       {
00200         for (size_t iter2=0 ; iter2<Nodes[iter].pre.Length() ; iter2++)
00201         {
00202           if (Nodes[iter].pre[iter2] == moved)
00203             Nodes[iter].pre[iter2] = p;
00204         }
00205         for (size_t iter2=0 ; iter2<Nodes[iter].post.Length() ; iter2++)
00206         {
00207           if (Nodes[iter].post[iter2] == moved)
00208             Nodes[iter].post[iter2] = p;
00209         }
00210       }
00211       NodeMap.Delete(Nodes[p].self, moved);
00212       NodeMap.PutUnique(Nodes[p].self, p);
00213     }
00214 
00215     SanityCheck();
00216   }
00217   
00224   bool AddOrder (const T& node1, const T& node2)
00225   {
00226     SanityCheck();
00227     size_t n1 = NodeMap.Get(node1, csArrayItemNotFound);
00228     size_t n2 = NodeMap.Get(node2, csArrayItemNotFound);
00229     CS_ASSERT(n1 != csArrayItemNotFound);
00230     CS_ASSERT(n2 != csArrayItemNotFound);
00231     
00232     /* make the forward link "n1->n2" */
00233     Nodes[n1].post.Push(n2);
00234     
00235     if (InternalCycleTest(n1)) 
00236     {
00237       /* undo our mischief and report failure */
00238       Nodes[n1].post.Pop();
00239       return false;
00240     } 
00241     else 
00242     {
00243       /* make the paired pre link "n2<-n1" */
00244       Nodes[n2].pre.Push(n1);
00245       return true;
00246     }
00247     SanityCheck();
00248   }
00249   
00251   void DeleteOrder (const T& node1, const T& node2)
00252   {
00253     SanityCheck();
00254     size_t n1 = NodeMap.Get(node1, csArrayItemNotFound);
00255     size_t n2 = NodeMap.Get(node2, csArrayItemNotFound);
00256     CS_ASSERT(n1 != csArrayItemNotFound);
00257     CS_ASSERT(n2 != csArrayItemNotFound);
00258     Nodes[n2].pre.DeleteFast(n1);
00259     Nodes[n1].post.DeleteFast(n2);
00260     SanityCheck();
00261   }
00262 
00264   size_t Size ()
00265   {
00266     return Nodes.Length();
00267   }
00268 
00270   const T GetByIndex(size_t i)
00271   {
00272     return Nodes[i].self;
00273   }
00274   
00279   void Solve (csList<const T> & result)
00280   {
00281     SanityCheck();
00282     for (size_t iter=0 ; iter<Nodes.Length() ; iter++) 
00283     {
00284       Nodes[iter].output = false;
00285     }
00286     result.DeleteAll();
00287     bool done;
00288     do 
00289     {
00290       done = true;
00291       for (size_t iter=0 ; iter<Nodes.Length() ; iter++) 
00292       {
00293         if (Nodes[iter].output == false) 
00294         {
00295           int canoutput = true;
00296           for (size_t i2=0 ; i2<Nodes[iter].pre.Length() ; i2++) 
00297           {
00298             if (!Nodes[Nodes[iter].pre[i2]].output) 
00299             {
00300               canoutput = false;
00301               break;
00302             }
00303           }
00304           if (canoutput) 
00305           {
00306             result.PushBack(Nodes[iter].self);
00307             Nodes[iter].output = true;
00308           } 
00309           else 
00310           {
00311             done = false;
00312           }
00313         }
00314       }
00315     } 
00316     while (!done);
00317     SanityCheck();
00318   }
00319   
00324   void Mark (const T& node)
00325   {
00326     size_t i = NodeMap.Get(node, csArrayItemNotFound);
00327     CS_ASSERT(i != csArrayItemNotFound);
00328     CS_ASSERT(i < Nodes.Length());
00329     Nodes[i].marked = true;
00330   }
00331   
00335   bool IsMarked (const T& node)
00336   {
00337     size_t i = NodeMap.Get(node, csArrayItemNotFound);
00338     CS_ASSERT(i != csArrayItemNotFound);
00339     CS_ASSERT(i < Nodes.Length());
00340     return Nodes[i].marked;
00341   }
00342   
00346   void ClearMark (const T& node)
00347   {
00348     size_t i = NodeMap.Get(node, csArrayItemNotFound);
00349     CS_ASSERT(i != csArrayItemNotFound);
00350     CS_ASSERT(i < Nodes.Length());
00351     Nodes[i].marked = false;
00352   }
00353   
00357   void ClearMark ()
00358   {
00359     for (size_t i=0 ; i<Nodes.Length() ; i++) 
00360     {
00361       Nodes[i].marked = false;
00362     }
00363   }
00364   
00369   bool IsEnabled(const T& node)
00370   {
00371     size_t i = NodeMap.Get(node, csArrayItemNotFound);
00372     CS_ASSERT(i != csArrayItemNotFound);
00373     return InternalIsEnabled(i);
00374   }
00375   
00379   bool HasEnabled()
00380   {
00381     for (size_t i=0 ; i<Nodes.Length() ; i++) 
00382     {
00383       if (InternalIsEnabled(i))
00384         return true;
00385     }
00386     return false;
00387   }
00388   
00392   const T GetEnabled(T fail)
00393   {
00394     for (size_t i=0 ; i<Nodes.Length() ; i++) 
00395     {
00396       if (InternalIsEnabled(i))
00397         return Nodes[i].self;
00398     }
00399     return fail;
00400   }
00401   
00402 protected:
00403   void SanityCheck ()
00404   {
00405 #ifdef CS_DEBUG
00406     CS_ASSERT_MSG ("NodeMap has different size from Node list", 
00407                    NodeMap.GetSize() == Nodes.Length());
00408     for (size_t i1=0; i1<Nodes.Length() ; i1++)
00409     {
00410       CS_ASSERT_MSG ("NodeMap names wrong location for node",
00411                      NodeMap.Get(Nodes[i1].self, csArrayItemNotFound) == i1);
00412       for (size_t i2=0 ; i2<Nodes[i1].pre.Length() ; i2++)
00413       {
00414         CS_ASSERT_MSG ("Node prefix index less than zero", 
00415                        Nodes[i1].pre[i2] >= 0);
00416         CS_ASSERT_MSG ("Node prefix index larger than Nodes list",
00417                        Nodes[i1].pre[i2] < Nodes.Length());
00418         bool reciprocal_post_exists = false;
00419         for (size_t i3=0 ; i3<Nodes[Nodes[i1].pre[i2]].post.Length() ; i3++)
00420         {
00421           if (Nodes[Nodes[i1].pre[i2]].post[i3] == i1)
00422           {
00423             reciprocal_post_exists = true;
00424             break;
00425           }
00426         }
00427         CS_ASSERT_MSG ("Node prefix does not have reciprocal postfix", 
00428                        reciprocal_post_exists);
00429       }
00430       for (size_t i2=0 ; i2<Nodes[i1].post.Length() ; i2++)
00431       {
00432         CS_ASSERT_MSG ("Node postfix index less than zero",
00433                        Nodes[i1].post[i2] >= 0);
00434         CS_ASSERT_MSG ("Node postfix index larger than Nodes list",
00435                        Nodes[i1].post[i2] < Nodes.Length());
00436         bool reciprocal_pre_exists = false;
00437         for (size_t i3=0 ; i3<Nodes[Nodes[i1].post[i2]].pre.Length() ; i3++)
00438         {
00439           if (Nodes[Nodes[i1].post[i2]].pre[i3] == i1)
00440           {
00441             reciprocal_pre_exists = true;
00442             break;
00443           }
00444         }
00445         CS_ASSERT_MSG ("Node postfix does not have reciprocal prefix",
00446                        reciprocal_pre_exists);
00447       }
00448     }
00449     typename csHash<size_t,const T>::GlobalIterator iter = 
00450       NodeMap.GetIterator ();
00451     while (iter.HasNext())
00452     {
00453       size_t idx = iter.Next();
00454       CS_ASSERT_MSG ("NodeMap contains an index larger than Nodes list",
00455                      idx < Nodes.Length());
00456     }
00457 #endif /* CS_DEBUG */
00458   }
00459 
00460   bool CycleTest(const T& node)
00461   {
00462     size_t n = NodeMap.Get(node, csArrayItemNotFound);
00463     CS_ASSERT(n != csArrayItemNotFound);
00464     return InternalCycleTest(n);
00465   }
00466   
00467   bool InternalIsEnabled(size_t i)
00468   {
00469     if (Nodes[i].marked)
00470       return false;
00471     for (size_t j=0 ; j<Nodes[i].pre.Length() ; j++) 
00472     {
00473       if (!Nodes[Nodes[i].pre[j]].marked)
00474         return false;
00475     }
00476     return true;
00477   }
00478   
00479   bool InternalCycleTest(size_t n1, size_t n2)
00480   {
00481     // n1 is the inserted node, see if n2 hits n1 again...
00482     if (n1==n2)
00483       return true;
00484     for (size_t i=0 ; i<Nodes[n2].post.Length() ; i++) 
00485     {
00486       if (InternalCycleTest(n1, Nodes[n2].post[i]))
00487         return true;
00488     }
00489     return false;
00490   }
00491   bool InternalCycleTest(size_t n)
00492   {
00493     for (size_t i=0 ; i<Nodes[n].post.Length() ; i++) 
00494     {
00495       if (InternalCycleTest(n, Nodes[n].post[i]))
00496         return true;
00497     }
00498     return false;
00499   }
00500 };
00501 
00502 #endif // __CS_UTIL_PO_H__

Generated for Crystal Space by doxygen 1.4.7