Making the PC to continue the search even if there is only one child. This
[dyninst.git] / paradyn / src / PCthread / PCshg.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /*
43  * PCshg.C
44  * 
45  * The searchHistoryNode and searchHistoryGraph class methods.
46  * 
47  * $Log: PCshg.C,v $
48  * Revision 1.55  1997/05/14 13:02:46  naim
49  * Making the PC to continue the search even if there is only one child. This
50  * is just a temporal fix - naim
51  *
52  * Revision 1.54  1996/12/08 17:36:21  karavan
53  * part 1 of 2 part commit to add new searching functionality
54  *
55  * Revision 1.53  1996/08/16 21:03:44  tamches
56  * updated copyright for release 1.1
57  *
58  * Revision 1.52  1996/08/16 07:07:51  karavan
59  * minor code cleanup
60  *
61  * Revision 1.51  1996/07/23 20:28:07  karavan
62  * second part of two-part commit.
63  *
64  * implements new search strategy which retests false nodes under certain
65  * circumstances.
66  *
67  * change in handling of high-cost nodes blocking the ready queue.
68  *
69  * code cleanup.
70  *
71  * Revision 1.50  1996/07/22 21:19:45  karavan
72  * added new suppress feature to hypothesis definition.
73  *
74  * Revision 1.29  1996/02/02 02:06:49  karavan
75  * A baby Performance Consultant is born!
76  *
77  */
78
79 #include "PCintern.h"
80 #include "PCshg.h"
81 #include "PCexperiment.h"
82 #include "PCsearch.h"
83
84 //
85 // ****** searchHistoryNode *******
86 //
87
88 // note: searchHistoryNodes never die.
89
90 searchHistoryNode::searchHistoryNode(searchHistoryNode *parent,
91                                      hypothesis *why, 
92                                      focus whereowhere, 
93                                      refineType axis,
94                                      bool persist,
95                                      searchHistoryGraph *mama,
96                                      const char *shortName,
97                                      unsigned newID,
98                                      bool amFlag):
99 why(why), where(whereowhere), 
100 persistent(persist), altMetricFlag(amFlag), 
101 exp(NULL), active(false), truthValue(tunknown), 
102 axis(axis), nodeID(newID), exStat(expandedNone),  
103 mamaGraph (mama), sname(shortName)
104 {
105   // full name of node (both why and where)
106   name = why->getName();
107   name += "::";
108   name += dataMgr->getFocusNameFromHandle(where);
109
110   // short label for node display
111   if (sname == NULL)
112     sname = why->getName();
113
114   if (parent != NULL)
115     parents += parent;
116   virtualNode = why->isVirtual();
117
118   // at this point, we know the parent is either the topLevelHypothesis or 
119   // it is some other true node
120   numTrueParents = 1;
121   numTrueChildren = 0;
122 }
123
124 searchHistoryNode*
125 searchHistoryNode::addChild (hypothesis *why, 
126                              focus whereowhere, 
127                              refineType axis,
128                              bool persist,
129                              const char *shortName,
130                              unsigned newID,
131                              bool amFlag)
132 {
133   searchHistoryNode *newkid = new searchHistoryNode (this, why, whereowhere, axis, 
134                                  persist, mamaGraph, shortName, newID, amFlag);
135   children += newkid;
136   return newkid;
137 }
138
139 bool 
140 searchHistoryNode::setupExperiment()
141 {
142   assert (exp == NULL);
143   bool errFlag;
144   if (virtualNode) {
145     // virtual nodes have no experiments
146     return false;
147   }
148   exp = new experiment (why, where, persistent, this, 
149                         mamaGraph->srch, altMetricFlag, &errFlag);
150   if (!exp || errFlag)
151     return false;
152   exp->findOutCost();
153   return true;
154 }
155
156 void
157 searchHistoryNode::startExperiment()
158 {
159   assert (exp);
160   if (!active && (numTrueParents >= 1)) 
161     // check here for true path to root; parent status may have changed
162     // while this node was waiting on the Ready Queue
163     exp->start();
164 }
165
166 void 
167 searchHistoryNode::enableReply (bool successful)
168 {
169   if (successful) {
170     changeActive(true);
171 #ifdef PCDEBUG
172     cout << "experiment started for node: " << nodeID << endl;
173 #endif
174   } else {
175 #ifdef PCDEBUG
176     cout << "unable to start experiment for node: " << nodeID << endl;
177 #endif
178   }
179   float mycost = getEstimatedCost();
180   mamaGraph->clearPendingSearch(mycost);
181 }
182
183 void 
184 searchHistoryNode::stopExperiment()
185 {
186   assert (exp);
187   exp->halt();
188   changeActive(false);
189 }
190
191 void 
192 searchHistoryNode::addNodeToDisplay() 
193 {
194   uiMgr->DAGaddNode (mamaGraph->guiToken, nodeID, 
195                      searchHistoryGraph::InactiveUnknownNodeStyle, 
196                      sname.string_of(), name.string_of(), 0);
197 }
198
199 void 
200 searchHistoryNode::addEdgeToDisplay(unsigned parentID, const char *label)
201 {
202     uiMgr->DAGaddEdge (mamaGraph->guiToken, parentID, nodeID, (unsigned)axis, label);
203 }
204
205 void 
206 searchHistoryNode::changeDisplay()
207 {
208   if (active) {
209     switch (truthValue) {
210     case ttrue:
211       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
212                             searchHistoryGraph::ActiveTrueNodeStyle);
213       break;
214     case tfalse:
215       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
216                             searchHistoryGraph::ActiveFalseNodeStyle);
217       break;
218     case tunknown:
219       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
220                             searchHistoryGraph::ActiveUnknownNodeStyle);
221       break;
222     };
223   } else {
224     switch (truthValue) {
225     case ttrue:
226       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
227                             searchHistoryGraph::InactiveTrueNodeStyle);
228       break;
229     case tfalse:
230       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
231                             searchHistoryGraph::InactiveFalseNodeStyle);
232       break;
233     case tunknown:
234       uiMgr->DAGconfigNode (mamaGraph->guiToken, nodeID, 
235                             searchHistoryGraph::InactiveUnknownNodeStyle);
236       break;
237     };
238   }
239 }
240
241 void 
242 searchHistoryGraph::addUIrequest(unsigned srcID, unsigned dstID, 
243                                  int styleID, const char *label)
244 {
245   if (uiRequestBuff == NULL)
246     uiRequestBuff = new vector<uiSHGrequest>;
247   uiSHGrequest newGuy;
248   newGuy.srcNodeID = srcID;
249   newGuy.dstNodeID = dstID;
250   newGuy.styleID = styleID;
251   newGuy.label = label;
252   (*uiRequestBuff) += newGuy;
253 }
254
255 void
256 searchHistoryGraph::flushUIbuffer()
257 {
258   if (uiRequestBuff) {
259     unsigned bufSize = uiRequestBuff->size();
260     if (!bufSize) return; // avoid sending empty buffer
261     uiMgr->DAGaddBatchOfEdges(guiToken, uiRequestBuff, bufSize);
262     uiRequestBuff = 0;
263   }
264 }
265
266 void 
267 searchHistoryGraph::clearPendingSearch(float pcost) {
268   if (guiToken == 0) {
269     PCsearch::decrNumPendingGlobalSearches();
270     PCsearch::clearPendingGlobalCost(pcost);
271   }
272   else {
273     PCsearch::decrNumPendingCurrentSearches();
274     PCsearch::clearPendingCurrentCost(pcost);
275   }
276 }
277
278 void 
279 searchHistoryNode::addActiveSearch() 
280 {
281   mamaGraph->addActiveSearch();
282 }
283
284 void 
285 searchHistoryGraph::addActiveSearch ()
286 {
287   if (guiToken == 0)
288     PCsearch::addGlobalActiveExperiment();
289   else
290     PCsearch::addCurrentActiveExperiment();
291 }
292
293 bool
294 searchHistoryNode::expandWhere()
295 {
296   searchHistoryNode *curr;
297   bool newNodeFlag;
298   bool altFlag;
299   bool expansionPossible = false;
300
301   // expand along where axis
302   vector<resourceHandle> *parentFocus = dataMgr->getResourceHandles(where);
303   vector<resourceHandle> *currFocus;
304   resourceHandle currHandle;
305   vector<rlNameId> *kids;
306   for (unsigned m = 0; m < parentFocus->size(); m++) {
307     currHandle = (*parentFocus)[m];
308     altFlag = (currHandle == Processes);
309     if (altFlag && (where == topLevelFocus))
310       // it is never useful to refine along process from the top level
311       continue;
312     if (!why->isPruned(currHandle)) {
313       // prunes limit the resource trees along which we will expand this node
314       kids = dataMgr->magnify(currHandle, where);
315       if ( (kids != NULL) && (kids->size() >= 1)) {
316         // note we don't bother refining if there's only a single child, 
317         // because the child would trivially test true.
318         for (unsigned j = 0; j < kids->size(); j++) {
319           // eliminate all resources explicitly pruned for this hypothesis
320           currFocus = dataMgr->getResourceHandles((*kids)[j].id);
321           bool suppressFound = false;;
322           for (unsigned n = 0; n < currFocus->size(); n++) {
323             if (why->isSuppressed((*currFocus)[n])) {
324               suppressFound = true;
325               break;
326             }
327           }
328           if (!suppressFound) {
329             expansionPossible = true;
330             curr = mamaGraph->addNode (this, why, (*kids)[j].id, 
331                                        refineWhereAxis,
332                                        false,  
333                                        (*kids)[j].res_name,
334                                        (altFlag || altMetricFlag),
335                                        &newNodeFlag);
336             if (newNodeFlag) {
337               // a new node was added
338               curr->addNodeToDisplay(); 
339               mamaGraph->addUIrequest(nodeID,   // parent ID
340                                       curr->getNodeId(),  // child ID
341                                       (unsigned)refineWhereAxis, // edge style
342                                       (char *)NULL);
343             } else {
344               // shadow node
345               mamaGraph->addUIrequest(nodeID,
346                                       curr->getNodeId(),
347                                       (unsigned)refineWhereAxis,
348                                       (*kids)[j].res_name);
349             }
350           }
351         }
352         delete kids;
353       }
354     }
355   }
356   delete parentFocus;
357   return expansionPossible;
358 }
359
360 bool
361 searchHistoryNode::expandWhy()
362 {
363   searchHistoryNode *curr;
364   bool newNodeFlag;
365   bool expansionPossible = false;
366
367   // expand along why axis
368   vector<hypothesis*> *hypokids = why->expand();
369   if (hypokids != NULL) { 
370     expansionPossible = true;
371     for (unsigned i = 0; i < hypokids->size(); i++) {
372       curr = mamaGraph->addNode (this, (*hypokids)[i], where,
373                                  refineWhyAxis, 
374                                  false,  
375                                  (*hypokids)[i]->getName(),
376                                  altMetricFlag,
377                                  &newNodeFlag);
378       if (newNodeFlag) {
379         // a new node was added
380         curr->addNodeToDisplay();
381         mamaGraph->addUIrequest(nodeID,   // parent ID
382                                 curr->getNodeId(),  // child ID
383                                 (unsigned)refineWhereAxis, // edge style
384                                 (char *)NULL);
385       } else {
386         // shadow node
387         mamaGraph->addUIrequest(nodeID,
388                                 curr->getNodeId(),
389                                 (unsigned)refineWhereAxis,
390                                 (*hypokids)[i]->getName());
391       }
392     }
393     delete hypokids;
394   }
395   return expansionPossible;
396 }
397
398 void
399 searchHistoryNode::expand ()
400 {
401   assert (children.size() == 0);
402   assert (exStat != expandedAll);
403
404 #ifdef PCDEBUG
405   // debug print
406   if (performanceConsultant::printSearchChanges) {
407     cout << "EXPAND: why=" << why->getName() << endl
408       << "        foc=<" << dataMgr->getFocusNameFromHandle(where) 
409         << ">" << endl
410           << "       time=" << exp->getEndTime() << endl;
411   }
412 #endif
413   exStat = expandedAll;
414   switch (getExpandPolicy()) {
415   case whyAndWhere:
416     expandWhy();
417     expandWhere();
418     break;
419   case whereAndWhy:
420     expandWhere();
421     expandWhy();
422     break;
423   case whyBeforeWhere:
424     if ( expandWhy() == false)
425       expandWhere();
426     break;
427   case whereBeforeWhy:
428     if (expandWhere() == false)
429       expandWhy();
430     break;
431   case whyOnly:
432     expandWhy();
433     break;
434   case whereOnly:
435     expandWhere();
436     break;
437   }  // end switch
438   
439   mamaGraph->flushUIbuffer();
440 }
441
442 void
443 searchHistoryNode::makeTrue()
444 {
445   truthValue = ttrue;
446   changeDisplay();
447   // update Search Display Status Area (eventually this will be printed 
448   // some better way, but this will have to do...)
449   string *status = new string (why->getName());
450   *status += string(" tested true for ");
451   *status += string(dataMgr->getFocusNameFromHandle(where));
452   *status += string("\n");
453   mamaGraph->updateDisplayedStatus (status);
454 }
455
456 void
457 searchHistoryNode::makeFalse()
458 {
459   truthValue = tfalse;
460   // if this node contains an experiment (ie, its non-virtual) then 
461   // we want to halt the experiment for now
462   if (!persistent) stopExperiment();
463   // change truth value and/or active status on the GUI
464   changeDisplay();
465 }
466
467 void
468 searchHistoryNode::makeUnknown()
469 {
470   truthValue = tunknown;
471   changeDisplay();
472 }
473
474 void
475 searchHistoryNode::changeActive (bool live)
476 {
477   active = live;
478   changeDisplay();
479 }
480
481
482 void 
483 searchHistoryNode::percolateDown(testResult newValue)
484 {
485   if (newValue == ttrue) {
486     // one of one or more parents just changed to true
487     numTrueParents++;
488     if (numTrueParents == 1) {
489       if ((exp) && (!active)) {
490         //** this will be replaced with more rational priority calculation
491         if (axis == refineWhyAxis)
492           PCsearch::addToQueue(5, this, getPhase());
493         else
494           PCsearch::addToQueue(10, this, getPhase());
495       }
496     }
497   } else {
498     // we're percolating a change to false; if no true parents are 
499     // left, this node is false by definition, we stop the experiment.
500     // Eventually the child node would become false on its own, this
501     // is just a shortcut.
502     numTrueParents--;
503     if (numTrueParents == 0)
504       changeTruth(tfalse); 
505   }
506 }
507       
508 void
509 searchHistoryNode::percolateUp(testResult newValue)
510 {
511   if (newValue == ttrue) {    
512     numTrueChildren++;
513     if ((virtualNode) && (numTrueChildren == 1)) {
514       // virtual Node represents or, one's enough
515       makeTrue();
516       for (unsigned i = 0; i < parents.size(); i++) {
517         parents[i] -> percolateUp(newValue);
518       }
519     }
520   } else {
521     numTrueChildren--;
522     if ((virtualNode) && (numTrueChildren == 0)) {
523       changeTruth(tfalse);
524     }
525   }
526 }
527
528 //
529 // experiment reports a change in truth value
530 //
531 void 
532 searchHistoryNode::changeTruth (testResult newTruth)
533 {
534   testResult oldValue = truthValue;
535   if (newTruth == tfalse)  {
536     // status change to false
537     this->makeFalse();
538     if (oldValue == ttrue) {
539       // change to false was from true
540       for (unsigned i = 0; i < parents.size(); i++) {
541         parents[i] -> percolateUp(tfalse);
542       }
543       for (unsigned k = 0; k < children.size(); k++) {
544         children[k]->percolateDown(tfalse);
545       }
546     }
547   } else {
548     if (oldValue == newTruth) {
549       // oops!  this isn't really a change!
550       return;
551     }
552     if (newTruth == ttrue) {
553       // status change to true
554       this->makeTrue();
555       for (unsigned i = 0; i < parents.size(); i++) {
556         parents[i] -> percolateUp(ttrue);
557       }
558       if (exStat != expandedNone) {
559         for (unsigned k = 0; k < children.size(); k++) {
560           children[k]->percolateDown(ttrue);
561         }
562       } else {
563         expand();
564       }
565     } else {
566       // change to unknown
567       makeUnknown();
568       changeDisplay ();
569     }
570   }
571 }
572
573 //
574 // move a node which has been tested back onto the ready q
575 //
576 void 
577 searchHistoryNode::retest()
578 {
579   if ((exp) && (!active)) {
580     //** this will be replaced with more rational priority calculation
581     if (axis == refineWhyAxis)
582       PCsearch::addToQueue(5, this, getPhase());
583     else
584       PCsearch::addToQueue(10, this, getPhase());
585   }
586 }
587
588 void
589 searchHistoryNode::retestAllChildren()
590 {
591   if (exStat != expandedNone) {
592     for (unsigned k = 0; k < children.size(); k++) {
593       children[k]->retest();
594     }
595   }
596 }
597   
598 float 
599 searchHistoryNode::getEstimatedCost()
600 {
601   return exp->getEstimatedCost();
602 }
603
604 unsigned 
605 searchHistoryNode::getPhase() {
606   return (mamaGraph->getPhase());
607 }
608
609 void 
610 searchHistoryNode::getInfo (shg_node_info *theInfo)
611 {
612   if (exp != NULL) {
613     theInfo->currentConclusion = exp->getCurrentConclusion();
614     theInfo->timeTrueFalse = exp->getTimeTrueFalse();
615     theInfo->currentValue = exp->getCurrentValue();
616     theInfo->startTime = exp->getStartTime();
617     theInfo->endTime = exp->getEndTime();
618     theInfo->estimatedCost = exp->getEstimatedCost();
619     theInfo->persistent = persistent;
620   } else {
621     //** this will change with split into virtual nodes
622     theInfo->currentConclusion = tunknown;
623     theInfo->timeTrueFalse = 0;
624     theInfo->currentValue = 0.0;
625     theInfo->startTime = 0;
626     theInfo->endTime = 0;
627     theInfo->estimatedCost = 0.0;
628     theInfo->persistent = true;
629   }
630 }
631
632 void 
633 searchHistoryNode::estimatedCostNotification() 
634 {
635 #ifdef PCDEBUG
636   cout << "Cost Received for Node " << name << endl;
637   cout << " in phase " << mamaGraph->guiToken << " is " << 
638     exp->getEstimatedCost() << endl;
639 #endif
640   if (!active && numTrueParents >= 1) {
641     // check numTrueParents here because parent may have become false
642     // while cost request was pending
643     //** this will be replaced with more rational priority calculation
644     if (axis == refineWhyAxis)
645       PCsearch::addToQueue(5, this, getPhase());
646     else
647       PCsearch::addToQueue(10, this, getPhase());
648   }
649 }
650
651 int 
652 searchHistoryNode::getGuiToken() 
653 {
654   return mamaGraph->guiToken;
655 }
656   
657 //
658 //  ******  searchHistoryGraph ********
659 //
660
661 // searchHistoryGraphs never die.
662
663 searchHistoryGraph::searchHistoryGraph(PCsearch *searchPhase, 
664                                        unsigned phaseToken)
665 :
666  NodeIndex(searchHistoryGraph::uhash),
667  NodesByFocus(searchHistoryGraph::uhash),
668  srch(searchPhase), 
669  guiToken(phaseToken),
670  nextID(0),
671  uiRequestBuff(NULL) 
672 {
673   vector<searchHistoryNode*> Nodes;
674   root = new searchHistoryNode ((searchHistoryNode *)NULL,
675                                 topLevelHypothesis,
676                                 topLevelFocus, refineWhyAxis,
677                                 true, this, "TopLevelHypothesis", nextID, 
678                                 false);
679   root->setExpanded();
680   Nodes += root;
681   NodeIndex[nextID] = root;
682   nextID++;
683 }
684
685 void 
686 searchHistoryGraph::updateDisplayedStatus (char *newmsg)
687 {
688   string *msgStr = new string (newmsg); // UI will call 'delete' on this
689   uiMgr->updateStatusDisplay(guiToken, msgStr);
690 }
691   
692 void 
693 searchHistoryGraph::updateDisplayedStatus (string *newmsg)
694 {
695   // note: UI will call 'delete' on newmsg
696   uiMgr->updateStatusDisplay(guiToken, newmsg);
697 }
698
699 //
700 // Any cleanup associated with search termination.
701 //
702 void 
703 searchHistoryGraph::finalizeSearch(timeStamp searchEndTime)
704 {
705   // right now search only terminates if phase ends, so just
706   // update Search Display Status Area (eventually this will be printed 
707   // some better way, but this will have to do...)
708   string *status = new string("\nSearch for Phase "); 
709   *status += string(performanceConsultant::DMcurrentPhaseToken);
710   *status += string (" ended due to end of phase at time ");
711   *status += string (searchEndTime);
712   *status += string(".\n");
713   updateDisplayedStatus(status);
714   // change display of all nodes to indicate "inactive"; no 
715   // change to truth value displayed
716   uiMgr->DAGinactivateEntireSearch(guiToken);
717 }
718
719 searchHistoryNode* 
720 searchHistoryGraph::addNode (searchHistoryNode *parent,
721                              hypothesis *why,
722                              focus whereowhere,
723                              refineType axis,
724                              bool persist,
725                              const char *shortName,
726                              bool amFlag,
727                              bool *newFlag)
728 {
729   // check if node already exists
730   searchHistoryNode *newkid = NULL;
731   vector<searchHistoryNode*> *foclist = NULL;
732   *newFlag = false;
733   if (NodesByFocus.defines(whereowhere)) {
734     foclist = NodesByFocus[whereowhere];
735     for (unsigned i = 0; i < foclist->size(); i++) {
736       if ((*foclist)[i]->hypoMatches(why)) {
737         newkid = (*foclist)[i];
738         return newkid;
739       }
740     }
741   }
742   *newFlag = true;
743   if (foclist == NULL) {
744     foclist = new vector<searchHistoryNode*>;
745     NodesByFocus[whereowhere] = foclist;
746   }
747   newkid = parent->addChild (why, whereowhere, axis, persist, 
748                              shortName, nextID++, amFlag);
749   *foclist += newkid;
750   newkid->setupExperiment();
751   Nodes += newkid;
752   NodeIndex [(newkid->getNodeId())] = newkid;
753   return newkid;
754 }
755   
756 searchHistoryNode *const
757 searchHistoryGraph::getNode (unsigned nodeId)
758 {
759   return NodeIndex [nodeId];
760 }
761
762 // for each hypothesis on the why axis, create a search node with 
763 // that hypothesis at the top level focus.
764 //
765 void 
766 searchHistoryGraph::initPersistentNodes()
767 {
768   searchHistoryNode *nodeptr;
769   hypothesis *currhypo;
770   vector<hypothesis*> *topmost = topLevelHypothesis->expand();
771   bool nodeAdded;
772   for (unsigned i = 0; i < topmost->size(); i++) {
773     currhypo = (*topmost)[i];
774     nodeptr = addNode (root, currhypo, topLevelFocus, 
775                        refineWhyAxis, true,  
776                        currhypo->getName(),
777                        false,
778                        &nodeAdded);
779     nodeptr->addNodeToDisplay();
780     nodeptr->addEdgeToDisplay(root->getNodeId(), (char *)NULL);
781   }
782   delete topmost;
783 }
784