Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Graph.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/graph/Graph.cc
11 /// @brief graph base classes
12 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com)
13 
14 //Unit Headers
15 #include <core/graph/Graph.hh>
16 
17 //STL Headers
18 // AUTO-REMOVED #include <list>
19 // AUTO-REMOVED #include <vector>
20 #include <algorithm>
21 #include <iostream>
22 #include <cassert>
23 
24 // Boost Headers
26 
27 //ObjexxFCL Headers
28 // AUTO-REMOVED #include <ObjexxFCL/FArray1A.hh>
29 
30 #include <platform/types.hh>
31 #include <core/graph/Graph.fwd.hh>
33 #include <utility/down_cast.hh>
34 #include <utility/vector1_bool.hh>
35 #include <utility/pointer/ReferenceCount.fwd.hh>
36 #include <utility/pointer/ReferenceCount.hh>
37 #include <utility/pointer/owning_ptr.functions.hh>
38 #include <utility/pointer/owning_ptr.fwd.hh>
39 #include <utility/pointer/owning_ptr.hh>
40 #include <ObjexxFCL/Dimension.fwd.hh>
41 #include <ObjexxFCL/Dimension.hh>
42 #include <ObjexxFCL/DimensionExpression.hh>
43 #include <ObjexxFCL/DynamicIndexRange.fwd.hh>
44 #include <ObjexxFCL/DynamicIndexRange.hh>
45 #include <ObjexxFCL/FArray.fwd.hh>
46 #include <ObjexxFCL/FArray.hh>
47 #include <ObjexxFCL/FArray2.fwd.hh>
48 #include <ObjexxFCL/FArray2.hh>
49 #include <ObjexxFCL/FArray2D.fwd.hh>
50 #include <ObjexxFCL/FArray2D.hh>
51 #include <ObjexxFCL/FArrayInitializer.fwd.hh>
52 #include <ObjexxFCL/FArrayInitializer.hh>
53 #include <ObjexxFCL/FArraySection.fwd.hh>
54 #include <ObjexxFCL/FArraySection.hh>
55 #include <ObjexxFCL/FArrayTraits.fwd.hh>
56 #include <ObjexxFCL/FArrayTraits.hh>
57 #include <ObjexxFCL/IndexRange.fwd.hh>
58 #include <ObjexxFCL/IndexRange.hh>
59 #include <ObjexxFCL/InitializerSentinel.hh>
60 #include <ObjexxFCL/Observer.fwd.hh>
61 #include <ObjexxFCL/Observer.hh>
62 #include <ObjexxFCL/ObserverMulti.hh>
63 #include <ObjexxFCL/ObserverSingle.hh>
64 #include <ObjexxFCL/ProxySentinel.hh>
65 #include <ObjexxFCL/SetWrapper.fwd.hh>
66 #include <ObjexxFCL/Star.fwd.hh>
67 #include <ObjexxFCL/Star.hh>
68 #include <ObjexxFCL/proxy_const_assert.hh>
69 #include <cstddef>
70 #include <cstdio>
71 #include <iosfwd>
72 #include <string>
73 #include <boost/pool/pool.hpp>
74 #include <boost/pool/poolfwd.hpp>
75 
76 
77 using namespace ObjexxFCL;
78 
79 namespace core {
80 namespace graph {
81 
82 EdgeList::EdgeList(
84 )
85 :
86  edge_list_element_pool_( edge_list_element_pool ),
87  end_( new EdgeListElement )
88 {
89  end_->next_ = end_;
90  end_->previous_ = end_;
91 }
92 
94 {
95  for ( EdgeListIterator
96  eiter = begin(), eiter_end = end();
97  eiter != eiter_end; /* no increment */ ) {
98  EdgeListIterator eiter_next( eiter );
99  ++eiter_next;
100 
101  // remove the list element
102  //delete eiter.element_;
103  edge_list_element_pool_.destroy( eiter.element_ );
104  eiter = eiter_next;
105  }
106  delete end_;
107 }
108 
109 void
111 {
112  assert( edgeptr ); // Do not accept null-pointing edges
113 
114  //EdgeListElement * new_node = new EdgeListElement( edgeptr, end_->previous_, end_ );
115  EdgeListElement * new_node = edge_list_element_pool_.construct( edgeptr, end_->previous_, end_ );
116 
117  end_->previous_->next_ = new_node; // may be end_->next_ if 0-element list
118  end_->previous_ = new_node;
119 }
120 
121 void
123 {
124  assert( edgeptr ); // Do not accept null-pointing edges
125 
126  //EdgeListElement * new_node = new EdgeListElement( edgeptr, end_, end_->next_ );
127  EdgeListElement * new_node = edge_list_element_pool_.construct( edgeptr, end_, end_->next_ );
128 
129  end_->next_->previous_ = new_node; // may be end_->next_ if 0-element list
130  end_->next_ = new_node;
131 
132 }
133 
134 
137  EdgeListIterator const & element_to_insert_before,
138  Edge * edgeptr
139 )
140 {
141  assert( edgeptr );
142  assert( element_to_insert_before.owner_ == this );
143 
144  EdgeListElement * next_node = element_to_insert_before.element_;
145  EdgeListElement * prev_node = element_to_insert_before.element_->previous_;
146 
147  //EdgeListElement * new_node = new EdgeListElement( edgeptr, prev_node, next_node );
148  EdgeListElement * new_node = edge_list_element_pool_.construct( edgeptr, prev_node, next_node );
149 
150  next_node->previous_ = new_node;
151  prev_node->next_ = new_node;
152  return EdgeListIterator( this, new_node );
153 }
154 
156 {
157  assert( to_erase.owner_ == this );
158  EdgeListElement * next_node = to_erase.element_->next_;
159  EdgeListElement * prev_node = to_erase.element_->previous_;
160 
161  assert( next_node->previous_ == to_erase.element_ );
162  assert( prev_node->next_ == to_erase.element_ );
163 
164  // deallocate the list element
165  //delete to_erase.element_;
166  edge_list_element_pool_.destroy( to_erase.element_ );
167 
168 
169  next_node->previous_ = prev_node;
170  prev_node->next_ = next_node;
171 
172 }
173 
174 /// O(N)
177 {
178  platform::Size nelements( 0 );
180  eiter = begin(), eiter_end = end();
181  eiter != eiter_end; ++eiter ) {
182  ++nelements;
183  }
184  return nelements;
185 }
186 
187 
188 //----------------------------------------------------------------------------//
189 //------------------------------ Graph Node Class ---------------------------//
190 //----------------------------------------------------------------------------//
191 
192 
194 
195 
196 /// @brief
197 /// virtual destructor
199 {}
200 
201 /// @brief
202 /// Main constructor, no default constructor nor copy constructor
203 Node::Node(Graph * owner, platform::Size node_id ) :
204  node_index_(node_id), num_incident_edges_(0),
205  num_neighbors_counting_self_static_(1),
206  loop_incident_( false ),
207  num_edges_to_smaller_indexed_nodes_(0),
208  num_edges_to_larger_indexed_nodes_(0),
209  incident_edge_list_( owner->edge_list_element_pool() ),
210  first_upper_edge_( incident_edge_list_.end() ),
211  owner_(owner)
212 {}
213 
214 /// @brief copy-from for use in Graph::operator= and copy ctors;
215 /// derived classes must define their own version of this function
216 // to copy any data stored on nodes
217 void Node::copy_from( Node const * ) {}
218 
219 
220 
221 /// @details If the other node this node is attached to by edge_ptr has a higher index
222 /// then the edge is added to the end of its edge list; if the node has a
223 /// smaller index, the edge pointer is added to the front of the edge list.
224 /// The presence of a new edge means the edge vector is not up to date.
225 ///
226 /// @param edge_ptr - [in] - the new edge
227 ///
228 void
229 Node::add_edge( Edge* edge_ptr, EdgeListIter & eiter )
230 {
232  platform::Size other_node_index = edge_ptr->get_other_ind( node_index_);
233  if (other_node_index < node_index_) {
235  eiter = incident_edge_list_.insert( incident_edge_list_.begin(), edge_ptr);
236  } else {
237  if ( !( edge_ptr->is_loop() && loop_incident_) ) {
238  eiter = incident_edge_list_.insert(incident_edge_list_.end(), edge_ptr);
239  if ( edge_ptr->is_loop() ) loop_incident_ = true;
240  } else {
241  //loop already attached; return 0 eiter/ceiter as a dummy
242  // fixing odd iterator behavior with g++ -v 4.1.1
243  assert( num_edges_to_larger_indexed_nodes_ != 0 );
244  eiter = incident_edge_list_.end(); //eiter = 0;
245  }
246 
249  first_upper_edge_ = eiter;
250  }
251  }
253 }
254 
255 
256 /// @details edges efficiently delete themselves from the edge lists of the nodes they
257 /// are incident upon by keeping a pair of iterators. Edges request nodes
258 /// delete them by handing the iterator back to the node.
259 ///
260 /// @param
261 /// edge - [in] - the iterator for this node's edge list that points at the
262 /// edge which is trying to delete itself
263 ///
265 {
266  if ( first_upper_edge_ == eiter ) { ++first_upper_edge_; }
267 
268  if ( ! (*eiter)->is_loop() )
269  {
270 
271  platform::Size other_node_index = (*eiter)->get_other_ind( node_index_ );
272  if (node_index_ < other_node_index) {
274  } else {
276  }
277  incident_edge_list_.erase( eiter );
279  } else {
280  if ( loop_incident_ ) {
281  loop_incident_ = false;
282 
283  incident_edge_list_.erase(eiter);
284 
287  }
288  }
290 }
291 
292 
293 /// @details As edges delete themselves, they invalidate any iterators
294 /// that point to their (former) positions in the node and graph edge lists.
295 /// Therefore, before calling delete on an edge object, one must grab the next
296 /// iterator in a list. Below, nextiter copies iter and is incremented before
297 /// iter's edge is deleted. Note also that "++iter" does not appear in the
298 /// for loop.
300 {
301  for (EdgeListIter iter = incident_edge_list_.begin();
302  iter != incident_edge_list_.end(); /*no increment statement*/ ) {
303 
304  EdgeListIter nextiter = iter;
305  ++nextiter;
306  owner_->delete_edge( *iter ); iter = nextiter;
307  }
308 }
309 
310 /// @details manually change the number of neighbors for a Node. Used
311 /// for symmetry scoring
313 {
315 }
316 
317 /// @details Constant time if each vertex has a constant number of edges. Edges are
318 /// identified by the index of the node to which the edge connects this node.
319 /// Returns NULL when there is no such connecting edge.
320 ///
321 /// @param
322 /// other_node - [in] - the index of the node that the desired
323 /// edge connects this node to
324 ///
325 Edge const * Node::find_edge(platform::Size other_node) const
326 {
327  //call non-const version of this function, which in fact does
328  //not change any data, but simply returns a Edge * instead of
329  //the desired Edge const *
330  return const_cast< Node * > (this)->find_edge( other_node );
331 }
332 
333 /// @brief non-const edge finding method; changes no data, but returns a non-const pointer
335 {
337  if ( other_node > get_node_index() )
338  {
339  start = first_upper_edge_;
340  end = incident_edge_list_.end();
341  } else {
342  start = incident_edge_list_.begin();
343  end = first_upper_edge_;
344  }
345 
346  //iterate over range of edges
347  for ( EdgeListIter iter = start; iter != end; ++iter) {
348  if ( (*iter)->same_edge( node_index_, other_node) )
349  return (*iter);
350  }
351  return 0;
352 }
353 
354 
355 /// @brief virtual function to print node to standard out
356 void Node::print() const
357 {
358  std::cout << "Node " << get_node_index() << " attached to edges: " << std::endl;
359  for ( EdgeListConstIter
361  iter_end = incident_edge_list_.const_end();
362  iter != iter_end; ++iter ) {
363  std::cout << " Edge( " << (*iter)->get_first_node_ind() << ", ";
364  std::cout << (*iter)->get_second_node_ind() << ")" << std::endl;
365  }
366 }
367 
368 
369 /// @details called on most-derived class. The most-derived class should NOT recursively call this method
370 /// on its parent class. The sizeof function will handle the whole Node (or DerivedNode).
372 {
373  return sizeof( Node );
374 }
375 
376 
377 /// @details recursively descend through heirarchy accounting for heap memory usage. Each derived
378 /// class in the heirarchy should recursively add the amount of dynamic memory its parent
379 /// allocates by calling parent::count_dynamic_memory
381 {
382  platform::Size tot = 0;
383  tot += sizeof( EdgeListElement ) * ( num_incident_edges_ + 1 ); // edge list
384  return tot;
385 }
386 
387 //----------------------------------------------------------------------------//
388 //------------------------------ Graph Edge Class ----------------------------//
389 //----------------------------------------------------------------------------//
390 
391 /// @brief destructor
392 ///
393 /// @details removes all record of this edge from edge-lists of
394 /// the 1) nodes this edge is incident upon and 2) the owning
395 /// interaction graph
397 {
399  if ( !is_loop() ) {
401  }
403 }
404 
405 /// @brief main constructor for edge, no default nor copy constructors
406 ///
407 /// @details edge adds itself to the edge list of the two nodes its set to be
408 /// incident upon, and stores the list-iterators that the nodes return.
409 ///
410 /// @param owner - [in] - owning InteractionGraph
411 /// @param first_node_ind - [in] - the index of the first node
412 /// @param second_node_ind - [in] - the index of the second node
413 ///
415 (
416  Graph* owner,
417  platform::Size first_node_ind,
418  platform::Size second_node_ind
419 )
420  : owner_(owner)
421 {
422  assert( first_node_ind <= second_node_ind );
423  node_indices_[0] = first_node_ind;
424  node_indices_[1] = second_node_ind;
425  nodes_[0] = owner->nodes_[ node_indices_[0] ];
426  nodes_[1] = owner->nodes_[ node_indices_[1] ];
427 
428  nodes_[0]->add_edge( this, pos_in_nodes_edge_list_[0] );
429  nodes_[1]->add_edge( this, pos_in_nodes_edge_list_[1] );
430 
431  return;
432 }
433 
434 
435 /// @details derived classes should recursively call the copy_from method to ensure all parent class
436 /// data is copied. It just so happens that this method does nothing, but that could change
437 /// and the derived class should include a call to this function for that reason.
438 void Edge::copy_from( Edge const * ) {}
439 
440 /// @brief returns the index of the other node that the edge is incident upon
442 {
443  assert( node_ind == node_indices_[0] || node_ind == node_indices_[1]);
444  return node_indices_[0] == node_ind ? node_indices_[1] : node_indices_[0];
445 }
446 
447 /// @brief returns a pointer to the other node that the edge is incident upon
449 {
450  assert( node_ind == node_indices_[0] || node_ind == node_indices_[1]);
451  return node_indices_[0] == node_ind ? nodes_[1] : nodes_[0];
452 }
453 
454 /// @brief return a const pointer to the other node that the edge is incident upon
455 Node const * Edge::get_other_node(platform::Size node_ind) const
456 {
457  return const_cast< Edge * >(this)->get_other_node( node_ind );
458 }
459 
460 /// @brief sets the iterator for this edge's position in its owner's edge list
462 {
463  assert( this == *iter );
465  return;
466 }
467 
468 
469 /// @brief returns true if this edge connects nodes of index node1 and node2
470 /// the order of node1 and node2 is not important
471 ///
472 /// @param node1 - [in] - index of one of the two nodes
473 /// @param node2 - [in] - index of the other of the two nodes
475 {
476  if (node1 > node2) {
477  platform::Size temp = node2;
478  node2 = node1;
479  node1 = temp;
480  }
481  return (node1 == node_indices_[0] && node2 == node_indices_[1]);
482 }
483 
484 /// @brief memory accouting scheme
485 ///
486 /// @details This is called non-recursively on the most-derived class
488 {
489  return sizeof( Edge );
490 }
491 
492 /// @brief memory accounting scheme
493 ///
494 /// @details This method should be called recursively by derived classes -- that is, each class should
495 /// recurse to its parent.
497 {
498  platform::Size tot = 0;
499  //no dynamic memory
500  return tot;
501 }
502 
503 //----------------------------------------------------------------------------//
504 //--------------------------------- Graph Class -----------------------------//
505 //----------------------------------------------------------------------------//
506 
507 /// @brief destructor
509 {
512  delete edge_pool_; edge_pool_ = 0;
513 }
514 
515 /// @brief default constructor; creates an empty graph (no nodes, no edges)
517  parent(),
518  num_nodes_( 0 ),
519  nodes_(),
520  num_edges_( 0 ),
521  edge_list_element_pool_( new boost::unordered_object_pool< EdgeListElement > ( 256 ) ),
522  edge_list_( *edge_list_element_pool_ ),
523  edge_pool_( new boost::unordered_object_pool< Edge > ( 256 ) ),
524  focused_edge_( 0 )
525 {}
526 
527 /// @details Do not call this constructor from a derived class in the initialization list,
528 /// since this constructor calls the polymorphic function create_new_node, and polymorphism
529 /// does not work during constructors or destructors.
530 ///
531 /// @param num_ig_nodes - [in] - number of nodes that this graph will contain
533  parent(),
534  num_nodes_(num_nodes),
535  nodes_(num_nodes, (Node*) 0),
536  num_edges_( 0 ),
537  edge_list_element_pool_( new boost::unordered_object_pool< EdgeListElement > ( 256 ) ),
538  edge_list_( *edge_list_element_pool_ ),
539  edge_pool_( new boost::unordered_object_pool< Edge > ( 256 ) ),
540  focused_edge_( 0 )
541 {
542  for ( platform::Size ii = 1; ii <= num_nodes; ++ii ) {
543  nodes_[ ii ] = create_new_node( ii );
544  }
545 }
546 
547 
548 /// @brief copy constructor relies on factory methods and virtual "copy_from" methods
549 ///
550 /// @details This copy constructor should NOT be used by derived classes. At the time
551 /// this is called, the identity of this has not yet been resolved -- this constructor will
552 /// produce Node and Edge objects when it calls "create_new_node" and not
553 /// DerivedNode or DerivedEdge objects. Derived class copy constructors should call
554 /// the base class assignment operator once the initial construction has been completed.
555 Graph::Graph( Graph const & source ) :
556  parent(),
557  num_nodes_( source.num_nodes_ ),
558  nodes_( num_nodes_, (Node *) 0 ),
559  num_edges_( 0 ),
560  edge_list_element_pool_( new boost::unordered_object_pool< EdgeListElement > ( 256 ) ),
561  edge_list_( *edge_list_element_pool_ ),
562  edge_pool_( new boost::unordered_object_pool< Edge > ( 256 ) ),
563  focused_edge_( 0 )
564 {
565  for (platform::Size ii = 1; ii <= num_nodes_; ++ii) {
566  nodes_[ ii ] = create_new_node( ii );
567  nodes_[ ii ]->copy_from( source.nodes_[ii] );
568  }
569 
570  for ( EdgeListConstIter
571  iter = source.const_edge_list_begin(),
572  iter_end = source.const_edge_list_end();
573  iter != iter_end; ++iter ) {
574  platform::Size const n1((*iter)->get_first_node_ind()), n2((*iter)->get_second_node_ind());
575  add_edge( n1, n2 );
576  Edge * the_edge = find_edge( n1, n2 ); // O(1) op since focused_edge_ points to it already.
577  the_edge->copy_from( *iter );
578  }
579 
580 }
581 
582 /// @brief operator = (). Relies on factory methods and virtual "copy_from" methods
583 ///
584 /// @details operator= must only be performed on graphs of the same type e.g.
585 /// an EnergyGraph may be copied from another EnergyGraph, but should
586 /// not be copied from a Graph.
587 Graph &
588 Graph::operator = ( Graph const & source )
589 {
590  if ( this == &source ) return *this;
591 
592  if( num_nodes_ != source.num_nodes_ ) { set_num_nodes( source.num_nodes_ );}
593  drop_all_edges();
594 
595  for (platform::Size ii = 1; ii <= num_nodes_; ++ii) {
596  nodes_[ ii ]->copy_from( source.nodes_[ii] );
597  }
598 
599  for ( EdgeListConstIter
600  iter = source.const_edge_list_begin(),
601  iter_end = source.const_edge_list_end();
602  iter != iter_end; ++iter ) {
603  add_edge( *iter ); // no longer calling copy_from method!
604  }
605  return *this;
606 }
607 
608 /// @brief copy the connectivity of the source graph, but do not copy the data stored in the
609 /// nodes and edges of the source graph. Useful for when copying a graph of a different type
610 /// (e.g. from an EnergyGraph into a Graph)
611 void Graph::copy_connectivity( Graph const & source )
612 {
613  if( num_nodes_ != source.num_nodes_ ) { set_num_nodes( source.num_nodes_ );}
614  drop_all_edges();
615 
616  for ( EdgeListConstIter
617  iter = source.const_edge_list_begin(),
618  iter_end = source.const_edge_list_end();
619  iter != iter_end; ++iter ) {
620  platform::Size const n1((*iter)->get_first_node_ind()), n2((*iter)->get_second_node_ind());
621  add_edge( n1, n2 );
622  }
623 }
624 
625 /// @brief creates a new edge between nodes index1 and index2. Nodes do
626 /// not have to be listed in order. For speed, does NOT check to see if
627 /// edge already exists -- except in debug mode.
628 ///
629 /// @details uses factory method create_new_edge and adds the created edge to the graph's edge list.
630 /// Not threadsafe. Only a single thread should add edges to the graph at a time.
631 ///
632 /// @param index1 - [in] - index of one of the two nodes the edge is to connect
633 /// @param index2 - [in] - index of the second of the two nodes the edge is to connect
634 Edge *
636 {
637  assert( ! get_edge_exists( index1, index2 ) );
638 
639  //swap so that index1 < index2
640  platform::Size temp = index1 < index2 ? index1 : index2;
641  index2 = index1 < index2 ? index2 : index1;
642  index1 = temp;
643 
644  Edge* new_edge = create_new_edge(index1, index2);
645  edge_list_.push_back( new_edge );
646  ++num_edges_;
647  new_edge->set_pos_in_owners_list( edge_list_.last() );
648  focused_edge_ = new_edge;
649  return new_edge;
650 }
651 
652 /// @brief for use in Graph operator=
653 ///
654 /// @details Uses the edge copy constructor so that data stored
655 /// on edges of one graph may be placed rapidly into the new edge
656 /// of this graph.
657 Edge *
658 Graph::add_edge( Edge const * example_edge )
659 {
660  assert( ! get_edge_exists(
661  example_edge->get_first_node_ind(),
662  example_edge->get_second_node_ind() ) );
663 
664  Edge* new_edge = create_new_edge( example_edge );
665  edge_list_.push_front( new_edge );
666  ++num_edges_;
667  new_edge->set_pos_in_owners_list( edge_list_.begin() );
668  focused_edge_ = new_edge;
669  return new_edge;
670 }
671 
672 
673 /// @brief alternative to integer constructor; first create an empty graph and
674 /// later tell the graph how many nodes it has. If the graph is not already
675 /// empty, it will delete everything its holding.
677 {
680  nodes_.resize( num_nodes_ );
681  for ( platform::Size ii = 1; ii <= num_nodes_; ++ii) nodes_[ ii ] = create_new_node( ii );
682 }
683 
684 /// @brief returns true if an edge between node1 and node2 exists
685 ///
686 /// @param node1 - [in] - index of the one of the nodes
687 /// @param node2 - [in] - index of the other node
689 {
690  Edge const * edge = find_edge( node1, node2 );
691  return (edge != NULL);
692 }
693 
694 /// @brief deletes all edges adjacent to the node specified
695 ///
696 /// @param node - [in] - index of the node
698 {
699  Node* nodeptr = get_node( node );
700  nodeptr->drop_all_edges();
701 }
702 
703 /// @brief deletes all edges in the graph
705 {
706  for ( EdgeListIter iter = edge_list_.begin(), iter_end = edge_list_.end();
707  iter != iter_end; /*no increment*/ ) {
708 
709  EdgeListIter iter_next = iter;
710  ++iter_next;
711  delete_edge(*iter);
712  iter = iter_next;
713  }
714 }
715 
716 
717 
718 /// @brief calls print() on each of the nodes in the graph
720 {
721  for (platform::Size ii = 1; ii <= num_nodes_; ii++)
722  nodes_[ii]->print();
723  return;
724 }
725 
726 /// @brief writes out a list of all the edges in the graph
727 ///
728 /// @param os - [in] - the output stream to write to
729 void Graph::output_connectivity(std::ostream & os) const
730 {
731  platform::Size counter = 1;
732  for (EdgeListConstIter iter = edge_list_.begin(); iter != edge_list_.end(); ++iter) {
733  os << "edge " << counter << " between " << (*iter)->get_first_node_ind()
734  << " " << (*iter)->get_second_node_ind() << std::endl;
735  counter++;
736  }
737  return;
738 }
739 
740 /// @brief writes out a connectivity description of the graph in the famous
741 /// dimacs format. (where the first column "DIMACS:" should be sed'ed out)
742 ///
743 /// @param os - [in] - the output stream to write to
744 void Graph::output_dimacs(std::ostream & os) const
745 {
747  os << "DIMACS: " << "p edges " << num_nodes_ << " " ;
748  os << num_edges << std::endl;
749  for (EdgeListConstIter iter = edge_list_.begin(); iter != edge_list_.end(); ++iter) {
750  os << "DIMACS: " << "e " << (*iter)->get_first_node_ind();
751  os << " " << (*iter)->get_second_node_ind() << std::endl;
752  }
753 
754  return;
755 }
756 
757 
758 /// @brief compute all node distances and return FArray2D with that information
759 ///
760 /// O(n^3)
761 FArray2D_int
763 {
764  platform::Size const inf( 12345678 ); //assumption: fewer than 12 million nodes in the graph.
765  assert( num_nodes_ < inf );
766 
767  FArray2D_int distance_table( num_nodes_, num_nodes_, inf);
768  for ( platform::Size ii = 1; ii <= num_nodes_; ++ii ) distance_table( ii, ii ) = 0; //nodes are 0 distance from themselves.
769 
770  for ( EdgeListConstIter iter = edge_list_.begin();
771  iter != edge_list_.end(); ++iter ) {
772  platform::Size n1 = (*iter)->get_first_node_ind();
773  platform::Size n2 = (*iter)->get_second_node_ind();
774 
775  if (! (*iter)->is_loop() ) {
776  distance_table( n2, n1 ) = 1;
777  distance_table( n1, n2 ) = 1;
778  }
779 
780  }
781 
782  // Warshall algorithm
783  // symmetry makes this marginally inefficient, but easy to read
784  // if this shows up in a hotspot, it can be made more efficient
785  for ( platform::Size ii = 1; ii <= num_nodes_; ++ii ) {
786  for ( platform::Size jj = 1; jj <= num_nodes_; ++jj ) {
787  for ( platform::Size kk = 1; kk <= num_nodes_; ++kk ) {
788  int const jj_2_kk = distance_table( jj, kk );
789  int const jj_2_ii = distance_table( jj, ii );
790  int const ii_2_kk = distance_table( ii, kk );
791 
792  int const jj_2_ii_2_kk = jj_2_ii + ii_2_kk;
793 
794  if ( jj_2_kk > jj_2_ii_2_kk ) {
795  distance_table( jj, kk ) = jj_2_ii_2_kk;
796  distance_table( kk, jj ) = jj_2_ii_2_kk;
797  }
798  }
799  }
800  }
801 
802  return distance_table;
803 }
804 
805 
806 /// @brief removes edge from edge list at iterator iter
807 ///
808 /// @details each edge keeps track of its position in its owner's graph's edge list
809 /// so it can efficiently delete itself should it need to.
810 ///
811 /// @param iter - [in] - the iterator in the non-const edge list pointing at the edge that's deleting itself
812 /// @param citer - [in] - the iterator in the const edge list pointing at the edge that's deleting itself
814 {
815  if (*iter == focused_edge_ ) focused_edge_ = NULL; //invalidate focused_edge_
816 
817  --num_edges_;
818  edge_list_.erase(iter);
819 
820  return;
821 }
822 
823 /// @brief deletes each edge in the graph and then deletes each node
824 ///
825 /// @details its important to note that nodes must outlive their incident edges
827 {
828  for (EdgeListIter iter = edge_list_.begin();
829  iter != edge_list_.end(); /*no increment*/ ) {
830  EdgeListIter next_iter = iter;
831  ++next_iter;
832  delete_edge( *iter );
833  iter = next_iter;
834  }
835  for (platform::Size ii = 1; ii <= num_nodes_; ii++) { delete nodes_[ii]; nodes_[ii] = 0; }
836  num_nodes_ = 0;
837  nodes_.resize( 0 );
838  focused_edge_ = 0;
839 }
840 
841 /// @brief
842 /// returns the edge connecting node1 and node2 (const version)
843 ///
844 /// @details
845 /// graph keeps a pointer to the last edge that was accessed to that search is
846 /// fairly efficient.
847 ///
848 /// @param
849 /// node1 - [in] - index of the first node
850 /// @param
851 /// node2 - [in] - index of the second node
853 {
854  if (focused_edge_ == NULL || !( focused_edge_->same_edge(node1, node2)) ) {
855  focused_edge_ = nodes_[node1]->find_edge(node2);
856  }
857  return focused_edge_;
858 }
859 
860 /// @brief
861 /// returns the edge connecting node1 and node2
862 ///
863 /// @details graph keeps a pointer to the last edge that was accessed to that search is
864 /// fairly efficient.
865 ///
866 /// @param
867 /// node1 - [in] - index of the first node
868 /// @param
869 /// node2 - [in] - index of the second node
871 {
872  if (focused_edge_ == NULL || !( focused_edge_->same_edge(node1, node2)) ) {
873  focused_edge_ = nodes_[node1]->find_edge(node2);
874  }
875  return focused_edge_;
876 }
877 
878 
879 void Graph::delete_edge( Edge * edge )
880 {
881  edge_pool_->destroy( edge );
882 }
883 
886 {
887  platform::Size total_memory = 0;
888  for (platform::Size ii = 1; ii <= num_nodes(); ++ii) {
889  total_memory += nodes_[ ii ]->count_dynamic_memory();
890  total_memory += nodes_[ ii ]->count_static_memory();
891  }
893  iter != edge_list_.const_end(); ++iter ) {
894  total_memory += (*iter)->count_dynamic_memory();
895  total_memory += (*iter)->count_static_memory();
896  }
897 
898  total_memory += count_dynamic_memory();
899  total_memory += count_static_memory();
900 
901  return total_memory;
902 }
903 
905 {
906  return sizeof( Graph );
907 }
908 
910 {
911  platform::Size tot = 0;
912  tot += sizeof( Node* ) * num_nodes_;
913  tot += sizeof( EdgeListElement ) * ( num_edges_ + 1 ); // edge list
914  return tot;
915 
916  return tot;
917 }
918 
919 
920 /// @brief factory method for node creation
921 /// Should be overriden in derived classes
923 {
924  return new Node( this, index );
925 }
926 
927 /// @brief factory method for edge creation
928 /// Should be overriden in derived classes
930 {
931  return edge_pool_->construct( this, index1, index2 );
932 }
933 
934 Edge* Graph::create_new_edge( Edge const * example_edge )
935 {
936  return edge_pool_->construct(
937  this,
938  example_edge->get_first_node_ind(),
939  example_edge->get_second_node_ind()
940  );
941 }
942 
943 
944 } //end namespace graph
945 } //end namespace core
946