ccforest.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /****************************************************************************
  2. *
  3. * MODULE: r.terraflow
  4. *
  5. * COPYRIGHT (C) 2007 Laura Toma
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. *****************************************************************************/
  18. #include "ccforest.h"
  19. #include "sortutils.h"
  20. #include "streamutils.h"
  21. #if(0)
  22. /* ---------------------------------------------------------------------- */
  23. static int valueCmp(const keyvalue<long> &a, const keyvalue<long> &b) {
  24. if(a.dst() < b.dst()) return -1;
  25. if(a.dst() > b.dst()) return 1;
  26. if(a.src() < b.src()) return -1;
  27. if(a.src() > b.src()) return 1;
  28. return 0;
  29. }
  30. /* ---------------------------------------------------------------------- */
  31. static int valueCmp(const keyvalue<int> &a, const keyvalue<int> &b) {
  32. if(a.dst() < b.dst()) return -1;
  33. if(a.dst() > b.dst()) return 1;
  34. if(a.src() < b.src()) return -1;
  35. if(a.src() > b.src()) return 1;
  36. return 0;
  37. }
  38. #endif
  39. /* ---------------------------------------------------------------------- */
  40. template<class T>
  41. ccforest<T>::ccforest() {
  42. edgeStream = new AMI_STREAM<ccedge>();
  43. rootStream = new AMI_STREAM<cckeyvalue>();
  44. superTree = NULL;
  45. rootCycles = 0;
  46. foundAllRoots = 0;
  47. savedRootValid = 0;
  48. }
  49. /* ---------------------------------------------------------------------- */
  50. template<class T>
  51. ccforest<T>::~ccforest() {
  52. delete edgeStream;
  53. delete rootStream;
  54. if(superTree) delete superTree;
  55. }
  56. /* ---------------------------------------------------------------------- */
  57. template<class T>
  58. int ccforest<T>::size() {
  59. size_t streamLength = edgeStream->stream_len();
  60. return streamLength;
  61. }
  62. /* ---------------------------------------------------------------------- */
  63. template<class T>
  64. void ccforest<T>::removeDuplicates(T src, T parent,
  65. EMPQueueAdaptive<cckeyvalue,T> &pq) {
  66. cckeyvalue kv;
  67. while(pq.min(kv) && (src == kv.getPriority())) {
  68. pq.extract_min(kv);
  69. if(kv.getValue() != parent) { /* cycles... */
  70. rootCycles++;
  71. if(parent < kv.getValue()) {
  72. superTree->insert(parent, kv.getValue());
  73. } else {
  74. superTree->insert(kv.getValue(), parent);
  75. }
  76. DEBUG_CCFOREST cerr << "ROOT CYCLE DETECTED! " << src << " (" <<
  77. parent << "," << kv.getValue() << ")" << endl;
  78. }
  79. }
  80. }
  81. /* ---------------------------------------------------------------------- */
  82. /* needs to be re-entrant */
  83. template<class T>
  84. void ccforest<T>::findAllRoots(int depth) {
  85. if(foundAllRoots) return;
  86. foundAllRoots = 1;
  87. Rtimer rt;
  88. rt_start(rt);
  89. if(depth > 5) {
  90. cerr << "WARNING: excessive recursion in ccforest (ignored)" << endl;
  91. }
  92. int explicitRootCount = 0;
  93. assert(!superTree);
  94. superTree = new ccforest<T>();
  95. DEBUG_CCFOREST *stats << "sort edgeStream (by cclabel)): ";
  96. keyCmpKeyvalueType<T> fo;
  97. sort(&edgeStream, fo); /* XXX -changed this to use a cmp obj */
  98. /* time forward processing */
  99. EMPQueueAdaptive<cckeyvalue,T> *pq =
  100. new EMPQueueAdaptive<cckeyvalue,T>(); /* parent queue */
  101. size_t streamLength = edgeStream->stream_len();
  102. T prevSrc = T(-1);
  103. T parent = T(-1);
  104. ccedge prevEdge;
  105. for(unsigned int i=0; i<streamLength; i++) {
  106. ccedge *e;
  107. AMI_err ae = edgeStream->read_item(&e);
  108. assert(ae == AMI_ERROR_NO_ERROR);
  109. #if(0)
  110. DEBUG_CCFOREST *stats << "------------------------------" << endl;
  111. DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
  112. DEBUG_CCFOREST pq->print();
  113. #endif
  114. if(*e == prevEdge) {
  115. DEBUG_CCFOREST *stats << "\tduplicate " << *e << " removed\n";
  116. continue; /* already have this done */
  117. }
  118. prevEdge = *e;
  119. DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
  120. /* find root (assign parent) */
  121. if(e->src() != prevSrc) {
  122. prevSrc = e->src();
  123. cckeyvalue kv;
  124. /* check if we have a key we don't use. */
  125. while(pq->min(kv) && (kv.getPriority() < e->src())) {
  126. pq->extract_min(kv);
  127. assert(kv.src() >= kv.dst());
  128. removeDuplicates(kv.src(), kv.dst(), *pq);
  129. ae = rootStream->write_item(kv); /* save root */
  130. assert(ae == AMI_ERROR_NO_ERROR);
  131. }
  132. /* try to find our root */
  133. if(pq->min(kv) && ((e->src() == kv.getPriority()))) {
  134. pq->extract_min(kv);
  135. parent = kv.getValue();
  136. removeDuplicates(e->src(), parent, *pq);
  137. } else {
  138. parent = e->src(); /* we are root */
  139. explicitRootCount++;
  140. /* technically, we could skip this part. the lookup function
  141. automatically assumes that values without parents are roots */
  142. }
  143. /* save result */
  144. cckeyvalue kroot(e->src(), parent);
  145. assert(kroot.src() >= kroot.dst());
  146. ae = rootStream->write_item(kroot);
  147. assert(ae == AMI_ERROR_NO_ERROR);
  148. }
  149. #ifndef NDEBUG
  150. cckeyvalue kv2;
  151. assert(pq->is_empty() || (pq->min(kv2) && kv2.getPriority() > e->src()));
  152. #endif
  153. /* insert */
  154. cckeyvalue kv(e->dst(), parent);
  155. assert(kv.src() >= kv.dst());
  156. pq->insert(kv);
  157. /* cout << "identified: " << kroot << endl; */
  158. }
  159. /* drain the priority queue */
  160. DEBUG_CCFOREST *stats << "draining priority queue" << endl;
  161. while (!pq->is_empty()) {
  162. cckeyvalue kv;
  163. pq->extract_min(kv);
  164. assert(kv.src() >= kv.dst());
  165. DEBUG_CCFOREST *stats << "processing edge " << kv << endl;
  166. removeDuplicates(kv.src(), kv.dst(), *pq);
  167. AMI_err ae = rootStream->write_item(kv);
  168. assert(ae == AMI_ERROR_NO_ERROR);
  169. }
  170. delete pq;
  171. /* note that rootStream is naturally ordered by src */
  172. if(superTree->size()) {
  173. DEBUG_CCFOREST *stats << "resolving cycles..." << endl;
  174. /* printStream(rootStream); */
  175. DEBUG_CCFOREST *stats << "sort rootStream: ";
  176. AMI_STREAM<cckeyvalue> *sortedRootStream;
  177. dstCmpKeyvalueType<T> dstfo;
  178. sortedRootStream = sort(rootStream, dstfo);
  179. /* XXX replaced this to use a cmp object -- laura
  180. AMI_STREAM<cckeyvalue>*sortedRootStream=new AMI_STREAM<cckeyvalue>();
  181. AMI_err ae = AMI_sort(rootStream, sortedRootStream, valueCmp);
  182. assert(ae == AMI_ERROR_NO_ERROR);
  183. */
  184. delete rootStream;
  185. cckeyvalue *kv;
  186. T parent;
  187. AMI_err ae;
  188. AMI_STREAM<cckeyvalue>* relabeledRootStream
  189. = new AMI_STREAM<cckeyvalue>();
  190. ae = sortedRootStream->seek(0);
  191. superTree->findAllRoots(depth+1);
  192. while((ae = sortedRootStream->read_item(&kv)) == AMI_ERROR_NO_ERROR) {
  193. parent = superTree->findNextRoot(kv->dst());
  194. ae = relabeledRootStream->write_item(cckeyvalue(kv->src(), parent));
  195. assert(ae == AMI_ERROR_NO_ERROR);
  196. }
  197. delete sortedRootStream;
  198. DEBUG_CCFOREST *stats << "sort relabeledRootStream: ";
  199. rootStream = sort(relabeledRootStream, fo);
  200. /* laura: changed this
  201. rootStream = new AMI_STREAM<cckeyvalue>();
  202. ae = AMI_sort(relabeledRootStream, rootStream);
  203. assert(ae == AMI_ERROR_NO_ERROR);
  204. */
  205. delete relabeledRootStream;
  206. DEBUG_CCFOREST *stats << "resolving cycles... done." << endl;
  207. }
  208. rootStream->seek(0);
  209. DEBUG_CCFOREST *stats << "Rootstream length="
  210. << rootStream->stream_len() << endl;
  211. DEBUG_CCFOREST printStream(*stats, rootStream);
  212. DEBUG_CCFOREST *stats << "Explicit root count=" << explicitRootCount << endl;
  213. rt_stop(rt);
  214. stats->recordTime("ccforest::findAllRoots", (long int)rt_seconds(rt));
  215. }
  216. /* ---------------------------------------------------------------------- */
  217. template<class T>
  218. void
  219. ccforest<T>::insert(const T& i, const T& j) {
  220. ccedge e(i,j);
  221. /* assert(i<j); not required, as long as it's consistent. */
  222. assert(i!=j); /* meaningless */
  223. AMI_err ae = edgeStream->write_item(e);
  224. assert(ae == AMI_ERROR_NO_ERROR);
  225. /* cout << "INST " << i << ", " << j << endl; */
  226. }
  227. /* ---------------------------------------------------------------------- */
  228. template<class T>
  229. T
  230. ccforest<T>::findNextRoot(const T& i) {
  231. AMI_err ae;
  232. cckeyvalue *kroot;
  233. T retRoot;
  234. findAllRoots(); /* find all the roots if not done */
  235. DEBUG_CCFOREST *stats << "looking for " << i << endl;
  236. if(!savedRootValid || savedRoot.src() < i) { /* need to read more */
  237. ae = rootStream->read_item(&kroot);
  238. while(ae == AMI_ERROR_NO_ERROR && kroot->src() < i) {
  239. ae = rootStream->read_item(&kroot);
  240. }
  241. if(ae == AMI_ERROR_NO_ERROR) {
  242. savedRoot = *kroot;
  243. savedRootValid = 1;
  244. } else {
  245. savedRootValid = -1; /* to avoid reading uselessly */
  246. }
  247. }
  248. if(savedRootValid==1 && savedRoot.src() == i) { /* check savedRoot */
  249. retRoot = savedRoot.dst();
  250. DEBUG_CCFOREST *stats << "using saved/found value" << endl;
  251. } else {
  252. DEBUG_CCFOREST *stats << "not found" << endl;
  253. retRoot = i;
  254. }
  255. DEBUG_CCFOREST *stats << "lookup for " << i << " gives " << retRoot
  256. << "; saved = " << savedRoot << endl;
  257. return retRoot;
  258. }
  259. /* ---------------------------------------------------------------------- */
  260. template<class T>
  261. void
  262. ccforest<T>::printRootStream() {
  263. findAllRoots(); /* find all the roots if not done */
  264. printStream(cout, rootStream);
  265. }
  266. template<class T> void
  267. ccforest<T>::printEdgeStream() {
  268. printStream(cout, edgeStream);
  269. }
  270. /* ---------------------------------------------------------------------- */
  271. template class keyvalue<cclabel_type>;
  272. template class keyCmpKeyvalueType<cclabel_type>;
  273. template class ccforest<cclabel_type>;