ccforest.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. if (stats)
  96. DEBUG_CCFOREST *stats << "sort edgeStream (by cclabel)): ";
  97. keyCmpKeyvalueType<T> fo;
  98. sort(&edgeStream, fo); /* XXX -changed this to use a cmp obj */
  99. /* time forward processing */
  100. EMPQueueAdaptive<cckeyvalue,T> *pq =
  101. new EMPQueueAdaptive<cckeyvalue,T>(); /* parent queue */
  102. size_t streamLength = edgeStream->stream_len();
  103. T prevSrc = T(-1);
  104. T parent = T(-1);
  105. ccedge prevEdge;
  106. for(unsigned int i=0; i<streamLength; i++) {
  107. ccedge *e;
  108. AMI_err ae = edgeStream->read_item(&e);
  109. assert(ae == AMI_ERROR_NO_ERROR);
  110. #if(0)
  111. if (stats) {
  112. DEBUG_CCFOREST *stats << "------------------------------" << endl;
  113. DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
  114. }
  115. DEBUG_CCFOREST pq->print();
  116. #endif
  117. if(*e == prevEdge) {
  118. if (stats)
  119. DEBUG_CCFOREST *stats << "\tduplicate " << *e << " removed\n";
  120. continue; /* already have this done */
  121. }
  122. prevEdge = *e;
  123. if (stats)
  124. DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
  125. /* find root (assign parent) */
  126. if(e->src() != prevSrc) {
  127. prevSrc = e->src();
  128. cckeyvalue kv;
  129. /* check if we have a key we don't use. */
  130. while(pq->min(kv) && (kv.getPriority() < e->src())) {
  131. pq->extract_min(kv);
  132. assert(kv.src() >= kv.dst());
  133. removeDuplicates(kv.src(), kv.dst(), *pq);
  134. ae = rootStream->write_item(kv); /* save root */
  135. assert(ae == AMI_ERROR_NO_ERROR);
  136. }
  137. /* try to find our root */
  138. if(pq->min(kv) && ((e->src() == kv.getPriority()))) {
  139. pq->extract_min(kv);
  140. parent = kv.getValue();
  141. removeDuplicates(e->src(), parent, *pq);
  142. } else {
  143. parent = e->src(); /* we are root */
  144. explicitRootCount++;
  145. /* technically, we could skip this part. the lookup function
  146. automatically assumes that values without parents are roots */
  147. }
  148. /* save result */
  149. cckeyvalue kroot(e->src(), parent);
  150. assert(kroot.src() >= kroot.dst());
  151. ae = rootStream->write_item(kroot);
  152. assert(ae == AMI_ERROR_NO_ERROR);
  153. }
  154. #ifndef NDEBUG
  155. cckeyvalue kv2;
  156. assert(pq->is_empty() || (pq->min(kv2) && kv2.getPriority() > e->src()));
  157. #endif
  158. /* insert */
  159. cckeyvalue kv(e->dst(), parent);
  160. assert(kv.src() >= kv.dst());
  161. pq->insert(kv);
  162. /* cout << "identified: " << kroot << endl; */
  163. }
  164. /* drain the priority queue */
  165. if (stats)
  166. DEBUG_CCFOREST *stats << "draining priority queue" << endl;
  167. while (!pq->is_empty()) {
  168. cckeyvalue kv;
  169. pq->extract_min(kv);
  170. assert(kv.src() >= kv.dst());
  171. if (stats)
  172. DEBUG_CCFOREST *stats << "processing edge " << kv << endl;
  173. removeDuplicates(kv.src(), kv.dst(), *pq);
  174. AMI_err ae = rootStream->write_item(kv);
  175. assert(ae == AMI_ERROR_NO_ERROR);
  176. }
  177. delete pq;
  178. /* note that rootStream is naturally ordered by src */
  179. if(superTree->size()) {
  180. if (stats) {
  181. DEBUG_CCFOREST *stats << "resolving cycles..." << endl;
  182. /* printStream(rootStream); */
  183. DEBUG_CCFOREST *stats << "sort rootStream: ";
  184. }
  185. AMI_STREAM<cckeyvalue> *sortedRootStream;
  186. dstCmpKeyvalueType<T> dstfo;
  187. sortedRootStream = sort(rootStream, dstfo);
  188. /* XXX replaced this to use a cmp object -- laura
  189. AMI_STREAM<cckeyvalue>*sortedRootStream=new AMI_STREAM<cckeyvalue>();
  190. AMI_err ae = AMI_sort(rootStream, sortedRootStream, valueCmp);
  191. assert(ae == AMI_ERROR_NO_ERROR);
  192. */
  193. delete rootStream;
  194. cckeyvalue *kv;
  195. T parent;
  196. AMI_err ae;
  197. AMI_STREAM<cckeyvalue>* relabeledRootStream
  198. = new AMI_STREAM<cckeyvalue>();
  199. ae = sortedRootStream->seek(0);
  200. superTree->findAllRoots(depth+1);
  201. while((ae = sortedRootStream->read_item(&kv)) == AMI_ERROR_NO_ERROR) {
  202. parent = superTree->findNextRoot(kv->dst());
  203. ae = relabeledRootStream->write_item(cckeyvalue(kv->src(), parent));
  204. assert(ae == AMI_ERROR_NO_ERROR);
  205. }
  206. delete sortedRootStream;
  207. if (stats)
  208. DEBUG_CCFOREST *stats << "sort relabeledRootStream: ";
  209. rootStream = sort(relabeledRootStream, fo);
  210. /* laura: changed this
  211. rootStream = new AMI_STREAM<cckeyvalue>();
  212. ae = AMI_sort(relabeledRootStream, rootStream);
  213. assert(ae == AMI_ERROR_NO_ERROR);
  214. */
  215. delete relabeledRootStream;
  216. if (stats)
  217. DEBUG_CCFOREST *stats << "resolving cycles... done." << endl;
  218. }
  219. rootStream->seek(0);
  220. if (stats){
  221. DEBUG_CCFOREST *stats << "Rootstream length="
  222. << rootStream->stream_len() << endl;
  223. DEBUG_CCFOREST printStream(*stats, rootStream);
  224. DEBUG_CCFOREST *stats << "Explicit root count=" << explicitRootCount << endl;
  225. }
  226. rt_stop(rt);
  227. if (stats)
  228. stats->recordTime("ccforest::findAllRoots", (long int)rt_seconds(rt));
  229. }
  230. /* ---------------------------------------------------------------------- */
  231. template<class T>
  232. void
  233. ccforest<T>::insert(const T& i, const T& j) {
  234. ccedge e(i,j);
  235. /* assert(i<j); not required, as long as it's consistent. */
  236. assert(i!=j); /* meaningless */
  237. AMI_err ae = edgeStream->write_item(e);
  238. assert(ae == AMI_ERROR_NO_ERROR);
  239. /* cout << "INST " << i << ", " << j << endl; */
  240. }
  241. /* ---------------------------------------------------------------------- */
  242. template<class T>
  243. T
  244. ccforest<T>::findNextRoot(const T& i) {
  245. AMI_err ae;
  246. cckeyvalue *kroot;
  247. T retRoot;
  248. findAllRoots(); /* find all the roots if not done */
  249. if (stats)
  250. DEBUG_CCFOREST *stats << "looking for " << i << endl;
  251. if(!savedRootValid || savedRoot.src() < i) { /* need to read more */
  252. ae = rootStream->read_item(&kroot);
  253. while(ae == AMI_ERROR_NO_ERROR && kroot->src() < i) {
  254. ae = rootStream->read_item(&kroot);
  255. }
  256. if(ae == AMI_ERROR_NO_ERROR) {
  257. savedRoot = *kroot;
  258. savedRootValid = 1;
  259. } else {
  260. savedRootValid = -1; /* to avoid reading uselessly */
  261. }
  262. }
  263. if(savedRootValid==1 && savedRoot.src() == i) { /* check savedRoot */
  264. retRoot = savedRoot.dst();
  265. if (stats)
  266. DEBUG_CCFOREST *stats << "using saved/found value" << endl;
  267. } else {
  268. if (stats)
  269. DEBUG_CCFOREST *stats << "not found" << endl;
  270. retRoot = i;
  271. }
  272. if (stats)
  273. DEBUG_CCFOREST *stats << "lookup for " << i << " gives " << retRoot
  274. << "; saved = " << savedRoot << endl;
  275. return retRoot;
  276. }
  277. /* ---------------------------------------------------------------------- */
  278. template<class T>
  279. void
  280. ccforest<T>::printRootStream() {
  281. findAllRoots(); /* find all the roots if not done */
  282. printStream(cout, rootStream);
  283. }
  284. template<class T> void
  285. ccforest<T>::printEdgeStream() {
  286. printStream(cout, edgeStream);
  287. }
  288. /* ---------------------------------------------------------------------- */
  289. template class keyvalue<cclabel_type>;
  290. template class keyCmpKeyvalueType<cclabel_type>;
  291. template class ccforest<cclabel_type>;