Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Energies.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/scoring/Energies.cc
11 /// @brief Energies class to store cached energies and track the residue
12 /// neighbor relationships
13 /// @author Phil Bradley
14 /// @author Andrew Leaver-Fay
15 
16 // Unit Headers
17 #include <core/scoring/Energies.hh>
18 
19 #include <basic/Tracer.hh>
20 
21 // Package Headers
32 
34 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
35 
36 
37 // Project Headers
40 
41 #include <core/pose/Pose.hh>
42 #include <core/pose/util.hh>
43 
44 #include <core/id/AtomID.hh>
45 
46 // ObjexxFCL headers
47 #include <ObjexxFCL/format.hh>
48 
49 // Numeric headers
50 #include <numeric/numeric.functions.hh>
51 
52 // Utility headers
53 #include <utility/exit.hh>
54 #include <utility/string_util.hh>
55 
56 //Auto Headers
57 #include <utility/vector1.hh>
58 //Auto Headers
60 #include <core/graph/ArrayPool.hh>
63 
64 
65 
66 static basic::Tracer tr("core.scoring.Energies");
67 
68 using namespace ObjexxFCL::fmt;
69 
70 namespace core {
71 namespace scoring {
72 
73 Energies::Energies()
74 : utility::pointer::ReferenceCount(),
75  size_(0),
76  owner_( 0 ),
77  energy_graph_( new EnergyGraph ),
78  context_graphs_( scoring::num_context_graph_types, 0 ),
79  externally_required_context_graphs_( scoring::num_context_graph_types, false ),
80  required_context_graphs_( scoring::num_context_graph_types, false ),
81  max_context_neighbor_cutoff_( 0.0 ),
82  long_range_energy_containers_( scoring::methods::n_long_range_types, 0 ),
83  use_nblist_(false),
84  use_nblist_auto_update_(false),
85  minimization_graph_( 0 ),
86  residue_total_energies_uptodate_( false ),
87  residue_total_energy_uptodate_( false ),
88  total_energy_( 0.0 ),
89  scorefxn_info_( new ScoreFunctionInfo ),
90  scorefxn_weights_(),
91  scoring_(false),
92  energy_state_( BAD ),
93  graph_state_( BAD ),
94  data_cache_( EnergiesCacheableDataType::num_cacheable_data_types ),
95  point_graph_( 0 )
96 {}
97 
98 
99 /// copy ctor -- deep copy
100 Energies::Energies( Energies const & other )
101 : utility::pointer::ReferenceCount(),
102  size_( other.size_ ),
103  owner_( 0 ),
104  energy_graph_( new EnergyGraph( *other.energy_graph_ ) ),
105  context_graphs_( scoring::num_context_graph_types, 0 ),
106  externally_required_context_graphs_( other.externally_required_context_graphs_ ),
107  required_context_graphs_( other.required_context_graphs_ ),
108  max_context_neighbor_cutoff_( other.max_context_neighbor_cutoff_ ),
109  long_range_energy_containers_( scoring::methods::n_long_range_types, 0 ),
110  use_nblist_( other.use_nblist_ ),
111  use_nblist_auto_update_( other.use_nblist_auto_update_ ),
112  minimization_graph_( other.minimization_graph_ ? new MinimizationGraph( * other.minimization_graph_ ) : 0 ),
113  onebody_energies_( other.onebody_energies_ ),
114  residue_total_energies_uptodate_( false ),
115  residue_total_energies_( size_ ),
116  residue_total_energy_uptodate_( false ),
117  residue_total_energy_( size_, 0.0 ),
118  total_energies_( other.total_energies_ ),
119  total_energy_( other.total_energy_ ),
120  finalized_energies_( other.finalized_energies_ ),
121  scorefxn_info_( new ScoreFunctionInfo( *(other.scorefxn_info_) )),
122  scorefxn_weights_( other.scorefxn_weights_ ),
123  domain_map_( other.domain_map_ ),
124  scoring_( other.scoring_ ),
125  energy_state_( other.energy_state_ ),
126  graph_state_( other.graph_state_ ),
127  data_cache_( other.data_cache_ ),
128  point_graph_( 0 )
129 {
130  copy_nblists( other );
131  copy_context_graphs( other );
132  copy_lr_energy_containers( other );
133 }
134 
135 /// assignment operator -- deep copy
136 Energies const &
138 {
139  if ( this == &rhs ) return *this;
140 
141  size_ = rhs.size_;
142  (*energy_graph_) = (*rhs.energy_graph_);
144  use_nblist_ = rhs.use_nblist_;
149  //std::fill( residue_total_energies_.begin(), residue_total_energies_.end(), EnergyMap() ); // unncessary
155  if ( *scorefxn_info_ == *rhs.scorefxn_info_ ) {
156  // noop; sfxn info matches, so no need to duplicate the score function.
157  } else {
159  }
161  domain_map_ = rhs.domain_map_;
162  scoring_ = rhs.scoring_;
165  data_cache_ = rhs.data_cache_;
166 
167  copy_nblists( rhs );
168  copy_context_graphs( rhs );
170 
171  /// NOTE: point_graph_ is intentionally not copied here ////
172 
173  return *this;
174 }
175 
176 ///@details If recurse is true, then this is the first call to same_type_as_me;
177 // determine if the other object is also an Energies object. If recurse is false
178 // then the other object is also of type Energies, so return true.
179 bool
180 Energies::same_type_as_me( Energies const & other, bool recurse /* = true */ ) const
181 {
182  if ( recurse ) {
183  return other.same_type_as_me( *this, false );
184  } else {
185  return true;
186  }
187 }
188 
189 
190 
192 {
193  //std::cout << "energies dstor" << std::endl;
194 }
195 
196 ///@details make a copy of this Energies( allocate actual memory for it )
199 {
200  return new Energies( *this );
201 }
202 
203 
204 void
206  if ( owner == 0 ) {
207  owner_ = 0;
208  } else if ( owner_ != 0 ) {
209  utility_exit_with_message( "Attempted to set the owner twice, once with " + utility::to_string( owner_ ) + " and now with " + utility::to_string( owner ) );
210  } else {
211  owner_ = owner;
212  }
213 }
214 
215 
216 ///////////////////////////////////////////////////////////////////////////////
217 ///////////////////////////////////////////////////////////////////////////////
218 // accessors
219 ///////////////////////////////////////////////////////////////////////////////
220 ///////////////////////////////////////////////////////////////////////////////
221 
222 ///
223 EnergyMap const &
225 {
226  return total_energies_;
227 }
228 
229 EnergyMap &
231 {
232  return total_energies_;
233 }
234 
235 ///////////////////////////////////////////////////////////////////////////////
236 /// @brief get the energy graph (const)
237 ///
238 /// @details assert that the graph state reflects the current set of neighbors; if the
239 /// structure has moved, the neighbors may have changed.
240 /// update_residue_neighbors should have been called first. If nb_list_ is true
241 /// then update_residue_neighbors will set the graph state to GOOD without
242 /// updating the neighbors.
243 Energies::EnergyGraph const &
245 {
246  assert( graph_state_ == GOOD );
247  return *energy_graph_;
248 }
249 
250 /// @brief get the energy graph - see comments for const version of this method
253 {
254  assert( graph_state_ == GOOD );
255  return *energy_graph_;
256 }
257 
258 /// @details IA: Note derived classes may need access to graph before it has been initalized!
259 /// In particular a derived class might overload update_residue_neighbors.
262 {
263  return *energy_graph_;
264 }
265 
266 /// @details convenience function -- this function violates the idea that the
267 /// energies object doesn't know the kind of context information its
268 /// maintaining. There is no reason to add a method like this for future
269 /// context graphs.
272 {
273  using namespace scoring;
274 
275  assert( graph_state_ == GOOD );
276 
278  require_context_graph_( ten_A_neighbor_graph, true );
279  }
280 
281  assert( dynamic_cast< TenANeighborGraph const * > (context_graphs_[ ten_A_neighbor_graph ].get()) );
282 
283  return static_cast< TenANeighborGraph const & > ( *context_graphs_[ ten_A_neighbor_graph ] );
284 }
285 
286 /// @brief get the graph encoding # neighbors within 10 Angstroms -- see comments for const version of this method
289 {
290  using namespace scoring;
291 
292  assert( graph_state_ == GOOD );
293 
295  require_context_graph_( ten_A_neighbor_graph, true );
296  }
297 
298  assert( dynamic_cast< TenANeighborGraph const * > (context_graphs_[ ten_A_neighbor_graph ].get()) );
299 
300  return static_cast< TenANeighborGraph & > ( *context_graphs_[ ten_A_neighbor_graph ] );
301 }
302 
303 /// @details convenience function -- this function violates the idea that the
304 /// energies object doesn't know the kind of context information its
305 /// maintaining. There is no reason to add a method like this for future
306 /// context graphs.
309 {
310  using namespace scoring;
311  assert( graph_state_ == GOOD );
312 
314  require_context_graph_( twelve_A_neighbor_graph, true );
315  }
316 
317  assert( dynamic_cast< TwelveANeighborGraph const * > (context_graphs_[ twelve_A_neighbor_graph ].get()) );
318 
319  return static_cast< TwelveANeighborGraph const & > ( *context_graphs_[ twelve_A_neighbor_graph ] );
320 }
321 
322 /// @brief get the graph encoding # CB (or Gly CA) neighbors within 12 Angstroms
323 /// of the side-chain "centroid" atom for each residue.
326 {
327  using namespace scoring;
328 
329  assert( graph_state_ == GOOD );
330 
332  require_context_graph_( twelve_A_neighbor_graph, true );
333  }
334 
335  assert( dynamic_cast< TwelveANeighborGraph const * > (context_graphs_[ twelve_A_neighbor_graph ].get()) );
336 
337  return static_cast< TwelveANeighborGraph & > ( *context_graphs_[ twelve_A_neighbor_graph ] );
338 }
339 
340 
341 /// @brief non-const access to a particular context graph
344 {
345  assert( graph_state_ == GOOD );
346  if ( context_graphs_[ type ] == 0 ) require_context_graph_( type, true );
347  return context_graphs_[ type ];
348 }
349 
350 /// @brief const access to a particular context graph
353 {
354  assert( graph_state_ == GOOD );
355  if ( context_graphs_[ type ] == 0 ) require_context_graph_( type, true );
356  return context_graphs_[ type ];
357 }
358 
359 void
361 {
362  require_context_graph_( type, true );
363 }
364 
365 
366 /// @details May not be called during scoring, to discourage access by energy methods.
367 EnergyMap
369 {
370  if ( scoring_ ) {
371  utility_exit_with_message(
372  "Energies:: operation NOT permitted during scoring." );
373  }
374 
375  return scorefxn_weights_;
376 }
377 
378 
379 void
380 Energies::weights( EnergyMap new_weights ) {
381  scorefxn_weights_ = new_weights;
382 }
383 
384 /// @brief get access to the point graph. For derived classes
387 {
388  return point_graph_;
389 }
390 
393 {
394  return context_graphs_;
395 }
396 
399 {
401 }
402 
403 Real
405 {
407 }
408 
409 void
411 {
413 }
414 
417 {
418  return owner_;
419 }
420 
421 ///////////////////////////////////////////////////////////////////////////////
422 ///////////////////////////////////////////////////////////////////////////////
423 // private
424 ///////////////////////////////////////////////////////////////////////////////
425 ///////////////////////////////////////////////////////////////////////////////
426 
427 
428 
429 ///////////////////////////////////////////////////////////////////////////////
430 ///////////////////////////////////////////////////////////////////////////////
431 
432 ///////////////////////////////////////////////////////////////////////////////
433 void
435 {
436  domain_map_ = 0;
438  onebody_energies_.clear();
439  residue_total_energies_.clear();
441  residue_total_energy_.clear();
443  if ( size_ ) {
444  onebody_energies_.resize( size_ );
445  residue_total_energies_.resize( size_ );
446  residue_total_energy_.resize( size_ );
447  std::fill( residue_total_energy_.begin(), residue_total_energy_.end(), (Real) 0.0 );
448  }
449  energy_graph_->drop_all_edges();
450  for ( uint ii = 1; ii <= context_graphs_.size(); ++ii ) {
451  if ( context_graphs_[ ii ] ) context_graphs_[ ii ]->drop_all_edges();
452  }
453  // is this really what we want to do here?
454  for ( Size ii = 1; ii <= long_range_energy_containers_.size(); ++ii ) {
456  }
457  graph_state_ = BAD;
458  energy_state_ = BAD;
459 }
460 
461 
462 ///////////////////////////////////////////////////////////////////////////////
463 void
465 {
466  // The graph state should either be GOOD (no work requried) or MOD (correct, mod the domain map)
467  assert( graph_state_ != BAD );
469 
470  // Later, the absence of edges from the energy_graph_ is taken as a signal
471  // that all residues have moved with respect to each other, and therefore
472  // all found neighbor pairs will have edges added in the context graphs.
473  // The context graphs must be empty to avoid an edge duplication event.
474  if ( energy_graph_->num_edges() != 0 ) {
475  for ( uint ii = 1; ii <= context_graphs_.size(); ++ii ) {
477  }
478  } else {
479  for ( uint ii = 1; ii <= context_graphs_.size(); ++ii ) {
480  if ( context_graphs_[ ii ] ) context_graphs_[ ii ]->drop_all_edges();
481  }
482  }
483 
484  // Tell LR graphs about the new domain-map
485  for ( Size ii = 1; ii <= long_range_energy_containers_.size(); ++ii ) {
486  if ( long_range_energy_containers_[ ii ] && ! long_range_energy_containers_[ ii ]->empty() ) {
488  }
489  }
490 }
491 
492 
493 ///////////////////////////////////////////////////////////////////////////////
494 /// @brief removes all edges in the graph that represent connections that have changed;
495 ///
496 /// @details O(N) as it iterates across the edges that already exist, instead over over all pairs
497 /// that moved with respect to each other (which would be O(N^2)) and deleting any
498 /// obsolete edges
500 {
501  using namespace graph;
502  for ( Graph::EdgeListIter iter = g.edge_list_begin(),
503  iter_end = g.edge_list_end(); iter != iter_end; /* no increment statement*/ )
504  {
505  Graph::EdgeListIter iter_next = iter;
506  ++iter_next;
507 
508  int const n1( (*iter)->get_first_node_ind() ), n2( (*iter)->get_second_node_ind() );
509  if ( domain_map_( n1 ) == 0 || domain_map_( n2 ) == 0 || domain_map_( n1 ) != domain_map_( n2 ) )
510  {
511  g.delete_edge(*iter); //drop the edge from the graph.
512  }
513  iter = iter_next;
514  }
515 }
516 
519 )
520 {
521  // Potentially O(N^2) operation...
522  for ( Size ii = 1; ii <= size_; ++ii ) {
523  int iimap = domain_map_( ii );
525  rni = lrec->upper_neighbor_iterator_begin( ii ),
526  rniend = lrec->upper_neighbor_iterator_end( ii );
527  (*rni) != (*rniend); ++(*rni) ) {
528  if ( iimap == 0 || iimap != domain_map_( rni->upper_neighbor_id() ) ) {
529  rni->mark_energy_uncomputed();
530  }
531  }
532  }
533 }
534 
537 {
538  return minimization_graph_;
539 }
540 
543 {
544  return minimization_graph_;
545 }
546 
547 void
549 {
550  minimization_graph_ = mingraph;
551 }
552 
553 ///
554 scoring::NeighborList const &
556 {
557  assert( use_nblist_ && nblist_.find( type ) != nblist_.end() );
558  return *( nblist_.find( type )->second );
559 }
560 
561 ///
562 
563 void
565  EnergiesCacheableDataType::Enum const & type,
566  scoring::NeighborListOP nblist_in
567 )
568 {
569  assert( use_nblist_ && nblist_.find( type ) == nblist_.end() );
570  nblist_[ type ] = nblist_in;
571 }
572 
573 ///////////////////////////////////////////////////////////////////////////////
574 void
576  pose::Pose const & ,
577  DomainMap const & domain_map_in,
578  bool const use_nblist_auto_update
579 )
580 {
581  assert( !use_nblist_ && !scoring_ );
582  assert( energy_state_ == GOOD ); // we should have just scored
583 
584  use_nblist_ = true;
586 
587  domain_map_ = domain_map_in;
589 
590  // setup the energy graph and context graphs
591  // this deletes pair-moved edges
592  // APL MOD 6.29.2010 -- no longer delete edges holding CD scores -- prepare_neighbor_graphs();
593 
594  // this adds appropriate pair-moved edges
595  /// APL MOD 6.29.2010 -- do not try to add new edges either -- update_neighbor_links( pose );
596 
597  // so at this point, the neighbor links are correct and complete
598  // but the neighbor-links for moving pairs are empty (no cached energies)
599  // (here moving pairs are defined wrt the passed-in set of moving
600  // dofs)
601  //
602  // this is what we want, since inside atom_pair_energy we want to
603  // recover cached energies for non-moving rsd pairs while
604  // calculating interactions for moving rsd pairs using the atom-atom nblist
605  //
606 }
607 
608 
609 
610 /// @details Show the per-residue and total energies, only for scores with a non-zero weight in the last
611 /// energy evaluation
612 
613 void
614 Energies::show( std::ostream & out ) const
615 {
616  assert( energy_state_ == GOOD );
617 
619 
620  // show the header (names of scoretypes)
621  out << "E "; // "E" plus spaces to account for "(i)" plus the four character alignment of the residue number
623  it_end = total_energies_.end(); it != it_end; ++it ) {
624  ScoreType const scoretype = ScoreType( it - total_energies_.begin() + 1 ); // hacky
625  if ( scorefxn_weights_[ scoretype ] != 0 ) {
626  out << A(14, name_from_score_type(scoretype));
627  }
628  }
629  out << std::endl;
630 
631  // show the onebody energies
632  for ( Size i=1; i<= size(); ++i ) {
633  out << "E(i)" << I(4,i);
634  EnergyMap const & emap( residue_total_energies_[i] );
635  for ( EnergyMap::const_iterator it = emap.begin(), it_end = emap.end(); it != it_end; ++it ) {
636  ScoreType const scoretype = ScoreType( it - emap.begin() + 1 ); // hacky
637  if ( scorefxn_weights_[ scoretype ] != 0 ) {
638  out << F(14,2,*it);
639  }
640  }
641  out << std::endl;
642  }
643 
644  // show the total energies
646  it_end = total_energies_.end(); it != it_end; ++it ) {
647  ScoreType const scoretype = ScoreType( it - total_energies_.begin() + 1 ); // hacky
648  if ( scorefxn_weights_[ scoretype ] != 0 ) {
649  //out << "total_energy " << scoretype << ' ' << F(12,3,*it) << std::endl;
650  out << "total_energy" << A(14, name_from_score_type(scoretype)) << F(12,3,*it) << std::endl;
651  }
652  }
653 }
654 
655 /// @details Show the residue energies, only for scores with a non-zero weight in the last
656 /// energy evaluation
657 void
658 Energies::show( std::ostream & out, Size res ) const
659 {
660  assert( energy_state_ == GOOD );
661 
663  // show the header (names of scoretypes)
664  out << "E "; // "E" plus spaces to account for "(i)" plus the four character alignment of the residue number
666  it_end = total_energies_.end(); it != it_end; ++it ) {
667  ScoreType const scoretype = ScoreType( it - total_energies_.begin() + 1 ); // hacky
668  if ( scorefxn_weights_[ scoretype ] != 0 ) {
669  out << A(14, name_from_score_type(scoretype));
670  }
671  }
672  out << std::endl;
673 
674  out << "E(i)" << I(4,res);
675  EnergyMap const & emap( residue_total_energies_[res] );
676  for ( EnergyMap::const_iterator it = emap.begin(), it_end = emap.end(); it != it_end; ++it ) {
677  ScoreType const scoretype = ScoreType( it - emap.begin() + 1 ); // hacky
678  if ( scorefxn_weights_[ scoretype ] != 0 ) {
679  out << F(14,2,*it);
680  }
681  }
682  out << std::endl;
683 }
684 
685 std::ostream & operator<<(std::ostream & out, const Energies& e )
686 {
687  if (e.size() == 0) {
688  out << "The pose must be scored first to generate an energy table." << std::endl;
689  }
690  else {
691  // per-residue energies
692  out << A( 4, "res" );
693  //EnergyMap const & temp_emap( e.residue_total_energies( 1 ) );
694  EnergyMap const & temp_emap( e.get_scorefxn_info().scores_present() );
695  for ( EnergyMap::const_iterator it = temp_emap.begin(),
696  it_end = temp_emap.end(); it != it_end; ++it ) {
697  if ( *it ) {
698  out << A( 15, name_from_score_type( ScoreType( it - temp_emap.begin() + 1 ) ) );
699  }
700  }
701  out << std::endl;
702 
703  for ( Size i=1; i <= e.size(); ++i ) {
704  out << I( 4, i );
705  EnergyMap const & emap( e.residue_total_energies( i ) );
706  for ( EnergyMap::const_iterator it = emap.begin(),
707  it_end = emap.end(); it != it_end; ++it ) {
708  if (temp_emap[ ScoreType( it - emap.begin() + 1) ]) out << F( 15, 3, *it );
709  }
710  out << std::endl;
711  }
712 
713  // total energies
714  out << A( 4, "tot" );
716  it_end = e.total_energies().end(); it != it_end; ++it ) {
717  if ( temp_emap[ ScoreType( it - e.total_energies().begin() + 1 ) ] )
718  out << F(15,3,*it);
719  //out << "total_energy ";
720  // << ScoreType( it - e.total_energies().begin() + 1 ) << ' '
721  }
722  out << std::endl;
723  }
724 
725  return out;
726 }
727 
728 
729 void
731 const {
732  if ( scoring_ ) {
733  utility_exit_with_message("No structure mods allowed during scoring!");
734  }
735 
738 
739  if ( energy_state_ == GOOD ) energy_state_ = MOD;
740  if ( graph_state_ == GOOD ) graph_state_ = MOD;
741 
742  total_energy_ = 0.0;
743 
744  if ( nres != size_ ) {
745  energy_state_ = BAD;
746  graph_state_ = BAD;
747  }
748 }
749 
750 void
751 Energies::show_total_headers( std::ostream & out ) const
752 {
753  // total energies
754  EnergyMap const & temp_emap( get_scorefxn_info().scores_present() );
755  for ( EnergyMap::const_iterator it = total_energies().begin(),
756  it_end = total_energies().end(); it != it_end; ++it ) {
757  if ( temp_emap[ ScoreType( it - total_energies().begin() + 1 ) ] )
758  // out << A( 15, ScoreType( it - total_energies().begin() + 1 ) );
759  out << ScoreType( it - total_energies().begin() + 1 ) << ' ';
760  }
761 }
762 
763 void
764 Energies::show_totals( std::ostream & out ) const
765 {
766  // total energies
767 
768  EnergyMap const & temp_emap( get_scorefxn_info().scores_present() );
769  for ( EnergyMap::const_iterator it = total_energies().begin(),
770  it_end = total_energies().end(); it != it_end; ++it ) {
771  if ( temp_emap[ ScoreType( it - total_energies().begin() + 1 ) ] )
772  // out << ScoreType( it - total_energies().begin() + 1 ) << ' '
773  // << F(15,3,*it);
774  out << F( 15,3, *it );
775 
776  }
777 }
778 
779 void
781 {
782  clear_energies();
783  domain_map_.clear();
784  size_ = 0;
785 
788  return;
789 }
790 
791 ///////////////////////////////////////////////////////////////////////////////
792 void
794 {
795  assert( use_nblist_ && !scoring_ );
796  use_nblist_ = false;
797  nblist_.clear();
798 
799  // trigger complete recalculation of nbr links
800  // since we have not been updating these during minimization
801  //
802  //fpd Is setting graphstate to BAD necessary? It seems to cause recalculation
803  //fpd of every energy term, even when a very small portion of the graph moved during
804  //fpd minimization. Changing this to MOD
805  graph_state_ = MOD;
806 
807  /// APL destroy the minimization graph
809 
811 }
812 
813 void
814 Energies::reset_res_moved( int const seqpos )
815 {
816  energy_graph_->get_energy_node( seqpos )->moved( false );
817 }
818 
819 ///////////////////////////////////////////////////////////////////////////////
820 void
821 Energies::set_size( Size const new_size )
822 {
823  if ( size_ == new_size ) {
824  assert( domain_map_.size() == size_ &&
825  Size(energy_graph_->num_nodes()) == size_ );
826  return;
827  }
828  size_ = new_size;
829  energy_graph_->set_num_nodes( size_ );
830  for ( uint ii = 1; ii <= context_graphs_.size(); ++ii ) {
831  if ( context_graphs_[ ii ] ) context_graphs_[ ii ]->set_num_nodes( size_ );
832  }
833  for ( uint ii = 1; ii <= long_range_energy_containers_.size(); ++ii ) {
834  if ( long_range_energy_containers_[ ii ] ) long_range_energy_containers_[ ii ]->set_num_nodes( size_ );
835  }
836  domain_map_.dimension( size_ );
837  onebody_energies_.clear();
838  onebody_energies_.resize( size_ );
841  residue_total_energies_.clear();
842  residue_total_energies_.resize( size_ );
844  residue_total_energy_.clear();
845  residue_total_energy_.resize( size_ );
846  std::fill( residue_total_energy_.begin(), residue_total_energy_.end(), (Real) 0.0 );
847 }
848 
849 ///////////////////////////////////////////////////////////////////////////////
850 void
852  DomainMap const & domain_map_in,
853  pose::Pose const & pose
854 )
855 {
856 
857  if ( graph_state_ == GOOD ) return;
858 
859  if ( size_ != pose.total_residue() ) {
860  set_size( pose.total_residue() );
861  graph_state_ = BAD;
862  }
863 
864  if ( graph_state_ == BAD ) {
865  graph_state_ = MOD;
866  domain_map_ = 0;
867  } else {
868  domain_map_ = domain_map_in;
869  }
870 
872 
873  // no updates to the neighbors during minimization
874  // the neighbors should have been calculated inside set_use_nblist
875  if ( use_nblist_ ) {
876  assert( size_ == pose.total_residue() && graph_state_ != BAD );
877  graph_state_ = GOOD; // pretend
878  return;
879  }
880 
882  update_neighbor_links( pose );
883  graph_state_ = GOOD;
884 
885 }
886 
887 
888 /// @details because the Energies object does not update the EnergyGraph during minimization, the Pose should
889 /// not direct the conformation object to discard its movement data. Movement data should be discarded
890 /// immediately after a call to update_neighbors where use_nblist_ has been false.
891 bool
893 {
894  return ! use_nblist_;
895 }
896 
897 void
899 {
900  long_range_energy_containers_[ lrtype ] = lrec;
901 }
902 
905 {
906  return long_range_energy_containers_[ lrtype ];
907 }
908 
911 {
912  return long_range_energy_containers_[ lrtype ];
913 }
914 
915 
916 
917 void
919 {
920 
921  for ( uint ii = 1, ii_end = size_; ii <= ii_end; ++ii ) {
922 
923  if ( domain_map_(ii) == 0) {
924  //energy_graph_->get_energy_node( ii )->moved( true );
925  energy_graph_->get_energy_node( ii )->moved( true );
926 
927  /// moved from scoring_begin()
928  // onebody residue energies are still valid unless bb/chi changed
929  // for that sequence position
930  //std::cout << "Energies::scoring_begin() res_moved: " << i << std::endl;
931  onebody_energies_[ii].clear();
932  }
933  }
934 }
935 
936 void
938 {
939  if ( residue_total_energies_uptodate_ ) return;
940 
941  if ( residue_total_energies_.size() != size_ ) {
942  residue_total_energies_.resize( size_ );
943  }
944 
945  if ( energy_state_ != GOOD ) {
946  for ( Size ii = 1; ii <= residue_total_energies_.size(); ++ii ) {
947  residue_total_energies_[ ii ].zero();
948  }
949  /// Consider the residue_total_energies up to date in the sense
950  /// that they reflect the current total_energies emap; not in the
951  /// sense that they reflect the preserved energies held in the
952  /// energy graph.
954 
955  return;
956  }
957 
958  ScoreTypes twobody_score_types;
959  ScoreTypes all_score_types;
960  for ( Size ii = 1; ii <= n_score_types; ++ii ) {
961  /// ODDITY: The former code accumulated all energies, even those with weights of 0;
962  /// I'll duplicate that behavior here, though it does not seem to be the correct meaning
963  /// of residue total energies.
964  /// uncomment the if block to instead accumulate only those residue energies with a non-zero weight.
965  //if ( scorefxn_weights_[ (ScoreType) ii ] != 0.0 ) {
966  if ( ii <= n_shortranged_2b_score_types ) twobody_score_types.push_back( (ScoreType) ii );
967  all_score_types.push_back( (ScoreType) ii );
968  //}
969  }
970 
971  // debug
972  assert( !use_nblist() && energies_updated() );
973 
974  // start with the one-body energies
975  for ( Size i=1, i_end = residue_total_energies_.size(); i<= i_end; ++i ) {
977  }
978 
979  for ( Size i=1, i_end = residue_total_energies_.size(); i<= i_end; ++i ) {
981  iru = energy_graph_->get_node(i)->const_upper_edge_list_begin(),
982  irue = energy_graph_->get_node(i)->const_upper_edge_list_end();
983  iru != irue; ++iru ) {
984 
985  EnergyEdge const & edge( static_cast< EnergyEdge const & > (**iru) );
986 
987  Size const j( edge.get_second_node_ind() );
988 
989  // accumulate energies
990  for ( Size ii = 1; ii <= twobody_score_types.size(); ++ii ) {
991  residue_total_energies_[ i ][ twobody_score_types[ ii ]] += 0.5 * edge[ twobody_score_types[ ii ]];
992  residue_total_energies_[ j ][ twobody_score_types[ ii ]] += 0.5 * edge[ twobody_score_types[ ii ]];
993  }
994 
995  } // nbrs of i
996  } // i=1,nres
997 
998  for ( Size ii = 1; ii <= long_range_energy_containers_.size(); ++ii ) {
1000  if ( lrec == 0 ) continue;
1001  if ( lrec->empty() ) continue;
1002 
1003  // Potentially O(N^2) operation...
1004  for ( Size i = 1; i <= residue_total_energies_.size(); ++i ) {
1006  rni = lrec->const_upper_neighbor_iterator_begin( i ),
1007  rniend = lrec->const_upper_neighbor_iterator_end( i );
1008  (*rni) != (*rniend); ++(*rni) ) {
1009  Size j = rni->upper_neighbor_id();
1010  EnergyMap emap;
1011  rni->retrieve_energy( emap );
1012 
1013  residue_total_energies_[ i ].accumulate( emap, all_score_types, 0.5 );
1014  residue_total_energies_[ j ].accumulate( emap, all_score_types, 0.5 );
1015  }
1016  }
1017  }
1018 
1019  for ( Size i=1, i_end = residue_total_energies_.size(); i<= i_end; ++i ) {
1021  }
1022 
1024 }
1025 
1026 void
1028 {
1029  if ( residue_total_energy_uptodate_ ) return;
1030 
1031  ScoreTypes twobody_score_types;
1032  for ( Size ii = 1; ii <= n_shortranged_2b_score_types; ++ii ) {
1033  if ( scorefxn_weights_[ (ScoreType) ii ] != 0.0 ) {
1034  twobody_score_types.push_back( (ScoreType) ii );
1035  }
1036  }
1037 
1038  for ( Size ii = 1; ii <= size_; ++ii ) {
1040  }
1041 
1042  for ( Size ii = 1; ii <= size_; ++ii ) {
1043  //conformation::Residue const & resl( pose.residue( i ) );
1044 
1046  iru = energy_graph_->get_node(ii)->const_upper_edge_list_begin(),
1047  irue = energy_graph_->get_node(ii)->const_upper_edge_list_end();
1048  iru != irue; ++iru ) {
1049  EnergyEdge const & edge( static_cast< EnergyEdge const & > (**iru) );
1050  Size const jj( edge.get_second_node_ind() );
1051 
1052  Real half = 0.5 * edge.dot( scorefxn_weights_ );
1053 
1054  residue_total_energy_[ ii ] += half;
1055  residue_total_energy_[ jj ] += half;
1056  } // nbr jj of ii
1057  } // ii=1,nres
1058 
1059  for ( Size ii = 1; ii <= long_range_energy_containers_.size(); ++ii ) {
1061  if ( lrec == 0 ) continue;
1062  if ( lrec->empty() ) continue;
1063 
1064  // Potentially O(N^2) operation...
1065  for ( Size ii = 1; ii <= size_; ++ii ) {
1067  rni = lrec->const_upper_neighbor_iterator_begin( ii ),
1068  rniend = lrec->const_upper_neighbor_iterator_end( ii );
1069  (*rni) != (*rniend); ++(*rni) ) {
1070  Size jj = rni->upper_neighbor_id();
1071  EnergyMap emap;
1072  rni->retrieve_energy( emap );
1073  Real half = 0.5 * scorefxn_weights_.dot( emap );
1074  residue_total_energy_[ ii ] += half;
1075  residue_total_energy_[ jj ] += half;
1076  }
1077  }
1078  }
1079 
1080 
1082 }
1083 
1084 
1085 /// @brief update the context graphs and the energy graph according to a new
1086 /// score function type
1087 ///
1088 void
1090 {
1091  using namespace scoring;
1092  bool deleted_a_graph( false ); // update the max_context_neighbor_cutoff_ if deleting a graph
1093  for ( int ii = 1; ii <= num_context_graph_types; ++ii ) {
1094 
1095  if ( scorefxn_info_->requires_context_graph( ContextGraphType( ii )) != required_context_graphs_[ ii ] ) {
1096  if ( required_context_graphs_[ ii ] ) {
1097  if ( ! externally_required_context_graphs_[ ii ] ) {
1098  assert( context_graphs_[ ii ] );
1099  /// The new score function does not require that the context graph be maintained, nor
1100  /// did any external (non-energy-method ) peice of code. It is safe to delete this
1101  /// graph and to stop maintaining it during score evaluations.
1102  required_context_graphs_[ ii ] = false;
1103  context_graphs_[ ii ] = 0;
1104  deleted_a_graph = true;
1105  }
1106  } else {
1107  /// Required by the score function, but not externally required, nor required by the previous
1108  /// score function.
1109  assert( context_graphs_[ ii ] == 0 );
1110  assert( externally_required_context_graphs_[ ii ] );
1112  }
1113  }
1114  // else -- noop, score function and I already agree on context graph ii
1115  }
1116 
1117  if ( deleted_a_graph ) {
1119  for ( Size ii = 1; ii <= num_context_graph_types; ++ii ) {
1120  if ( context_graphs_[ ii ] ) {
1121  if ( max_context_neighbor_cutoff_ < context_graphs_[ ii ]->neighbor_cutoff() ) {
1122  max_context_neighbor_cutoff_ = context_graphs_[ ii ]->neighbor_cutoff() ;
1123  }
1124  }
1125  }
1126  }
1127 
1128  /// Inform the EnergyGraph of the currently-active terms. Active means that the term has a
1129  /// non-zero weight.
1130  ScoreTypes active;
1131  active.reserve( n_shortranged_2b_score_types );
1132  for ( Size ii = 1; ii <= n_shortranged_2b_score_types; ++ii ) {
1133  if ( info->scores_present()[ (ScoreType) ii ] != 0.0 ) {
1134  active.push_back( (ScoreType) ii );
1135  }
1136  }
1137  energy_graph_->active_score_types( active );
1138  scorefxn_info_ = info;
1139 }
1140 
1141 
1142 
1143 /// @brief Add edges to the energy_graph and the context graphs according to domain map
1144 ///
1145 /// @details Precondition: if the graph contains any edges, then all neighbor relationships between
1146 /// pairs of residues that have not moved relative to each other are represented by the
1147 /// presence or absence of edges in the energy graph. If there are no edges in the
1148 /// energy graph, then all pair inforamtion must be calculated
1149 /// Precondition: if two residues have changed relative to one another according to
1150 /// the domain map, then there are no edges between them.
1151 void
1153  pose::Pose const & pose
1154 )
1155 {
1156  using namespace graph;
1157  using namespace scoring;
1158 
1159  runtime_assert( !core::pose::symmetry::is_symmetric( pose ) );
1160 
1161  //std::cout << "update_neighbor_links: interaction dist: " << scorefxn_info_->max_atomic_interaction_distance() <<
1162  // std::endl;
1163 
1164  if ( point_graph_ == 0 ) {
1166  }
1167  fill_point_graph( pose, point_graph_ );
1168 
1169  // According to the domain map, add some of the edges detected by the octree to
1170  // the energy graph and to the context graphs
1171 
1172  bool all_moved( energy_graph_->num_edges() == 0 );
1173 
1174  utility::vector1< ContextGraphOP > context_graphs_present;
1175  for ( uint ii = 1, ii_end = context_graphs_.size(); ii <= ii_end; ++ii ) {
1176  if ( context_graphs_[ ii ] ) context_graphs_present.push_back( context_graphs_[ ii ] );
1177  }
1178 
1179  for ( uint ii = 1, ii_end = pose.total_residue(); ii <= ii_end; ++ii ) {
1180 
1181  int const ii_map( domain_map_(ii) );
1182  bool const ii_moved( ii_map == 0 || all_moved );
1183 
1184  Distance const iiradius( pose.residue_type( ii ).nbr_radius() );
1185  Distance const ii_intxn_radius( iiradius +
1186  scorefxn_info_->max_atomic_interaction_distance() );
1187 
1189  ii_iter = point_graph_->get_vertex( ii ).upper_edge_list_begin(),
1190  ii_end_iter = point_graph_->get_vertex( ii ).upper_edge_list_end();
1191  ii_iter != ii_end_iter; ++ii_iter ) {
1192  uint const jj = ii_iter->upper_vertex();
1193  if ( ( domain_map_(jj) != ii_map ) || ii_moved ) {
1194 
1195  Distance const jjradius( pose.residue_type( jj ).nbr_radius() );
1196  DistanceSquared const square_distance( ii_iter->data().dsq() );
1197 
1198  // How about we simply make sure the radii sum is positive instead of paying for a sqrt
1199  // if ( std::sqrt( square_distance ) < ( ii_intxn_radius + jj_res.nbr_radius() ) ) {
1200  if ( ii_intxn_radius + jjradius > 0 ) {
1201  if ( square_distance < (ii_intxn_radius + jjradius )*(ii_intxn_radius + jjradius )) {
1202  energy_graph_->add_energy_edge( ii, jj, square_distance );
1203  }
1204  for ( uint kk = 1; kk <= context_graphs_present.size(); ++kk ) {
1205  context_graphs_present[ kk ]->conditionally_add_edge( ii, jj, square_distance );
1206  }
1207  }
1208  }
1209  }
1210  }
1211 }
1212 
1213 /// @brief determine distance cutoff threshold based on scorefxn_info_ and
1214 /// then add edges to the PointGraph class
1215 void
1217 
1219 
1220  Distance const max_pair_radius = pose::pose_max_nbr_radius( pose );
1221  Distance const energy_neighbor_cutoff = 2 * max_pair_radius + scorefxn_info_->max_atomic_interaction_distance();
1222 
1223  Distance const context_cutoff = max_context_neighbor_cutoff_;
1224 
1225  Distance const neighbor_cutoff = numeric::max( energy_neighbor_cutoff, context_cutoff );
1226 
1227  // Stuarts O( n log n ) octree algorithm
1228  core::conformation::find_neighbors<core::conformation::PointGraphVertexData,core::conformation::PointGraphEdgeData>( pg, neighbor_cutoff );
1229 }
1230 
1231 void Energies::copy_nblists( Energies const & other )
1232 {
1233  for ( std::map< EnergiesCacheableDataType::Enum, scoring::NeighborListOP >::const_iterator
1234  other_nblist_iter = other.nblist_.begin(),
1235  other_nblist_end = other.nblist_.end();
1236  other_nblist_iter != other_nblist_end; ++other_nblist_iter ) {
1237  nblist_[ other_nblist_iter->first ] = other_nblist_iter->second->clone();
1238  }
1239 }
1240 
1242 {
1243  assert( other.context_graphs_.size() == context_graphs_.size() );
1247  for ( Size ii = 1; ii <= other.context_graphs_.size(); ++ii ) {
1248  if ( other.context_graphs_[ ii ] ) {
1249  context_graphs_[ ii ] = other.context_graphs_[ ii ]->clone();
1250  } else {
1251  context_graphs_[ ii ] = 0;
1252  }
1253  }
1254 }
1255 
1257 {
1258  for ( Size ii = 1; ii <= other.long_range_energy_containers_.size(); ++ii ) {
1259  if ( other.long_range_energy_containers_[ ii ] ) {
1260  long_range_energy_containers_[ ii ] = other.long_range_energy_containers_[ ii ]->clone();
1261  } else {
1263  }
1264  }
1265 }
1266 
1267 /// @brief Create a context graph. If the requirement is external, someone other than a ScoreFunction
1268 /// has declared that the context graph is needed (possibly by asking for it right now) so the graph
1269 /// must also be made up-to-date.
1270 void
1272 {
1273  assert( context_graphs_[ type ] == 0 );
1274  required_context_graphs_[ type ] = true;
1276  if ( context_graphs_[ type ] == 0 ) {
1277  utility_exit_with_message( "Error: Null returned from ContextGraphFactory::create_context_graph( " + utility::to_string( type ) + ")" );
1278  }
1279  context_graphs_[ type ]->set_num_nodes( size_ );
1280 
1281  if ( max_context_neighbor_cutoff_ < context_graphs_[ type ]->neighbor_cutoff() ) {
1282  max_context_neighbor_cutoff_ = context_graphs_[ type ]->neighbor_cutoff() ;
1283  }
1284 
1285  if ( external ) {
1286  externally_required_context_graphs_[ type ] = true;
1287 
1288  using namespace graph;
1289 
1292  for ( uint ii = 1, ii_end = size_; ii <= ii_end; ++ii ) {
1293  Distance const iiradius( owner_->residue_type( ii ).nbr_radius() );
1294  Distance const ii_intxn_radius( iiradius +
1295  scorefxn_info_->max_atomic_interaction_distance() );
1297  ii_iter = point_graph->get_vertex( ii ).upper_edge_list_begin(),
1298  ii_end_iter = point_graph->get_vertex( ii ).upper_edge_list_end();
1299  ii_iter != ii_end_iter; ++ii_iter ) {
1300  uint const jj = ii_iter->upper_vertex();
1301  Distance const jjradius( owner_->residue_type( jj ).nbr_radius() );
1302 
1303  // Make sure to add edges only if the intereaction radius
1304  if ( ii_intxn_radius + jjradius > 0 ) {
1305  DistanceSquared const square_distance( ii_iter->data().dsq() );
1306  context_graphs_[ type ]->conditionally_add_edge( ii, jj, square_distance );
1307  }
1308  }
1309  }
1310  }
1311 
1312 
1313 }
1314 
1315 
1316 ///////////////////////////////////////////////////////////////////////////////
1317 /// @brief This is called by ScoreFunction at the start of an energy calculation
1318 ///
1319 /// @details
1320 /// the responsibilities are:
1321 /// 1. to check for size/scorefxn mismatches,
1322 /// 2. reset some of the cached energies
1323 /// Expect that Energies::structure_has_moved( ... ) has been called
1324 /// already if the stucture has changed, ie if domain_map != 1
1325 ///
1326 
1327 void
1329  scoring::ScoreFunction const & sfxn,
1330  pose::Pose const & pose // for the neighbor calculation
1331 )
1332 {
1333  // set our scoring flag to true
1334  scoring_ = true;
1335 
1336  total_energy_ = 0.0;
1338 
1339  // check for info mismatch and save scorefxn_info_ before (possibly) calling set_size()
1340  // context graphs and energy graph invalidated with change of scoring function
1341  bool scorefunction_changed( false );
1342  if ( *(sfxn.info()) != (*scorefxn_info_) ) {
1343  //std::cout << "ScoreFunction changed!" << std::endl;
1344  energy_state_ = BAD;
1345  graph_state_ = BAD;
1346  set_scorefxn_info( sfxn.info() );
1347  scorefunction_changed = true;
1348  }
1349 
1350  /*if ( ! scorefunction_changed ) {
1351  /// Force a rescore if weights have changed.
1352  for ( Size ii = 1; ii <= n_shortranged_2b_score_types; ++ii ) {
1353  if ( scorefxn_weights_[ (ScoreType) ii ] != sfxn.weights()[ (ScoreType) ii ] ) {
1354  energy_state_ = BAD;
1355  graph_state_ = BAD;
1356  scorefunction_changed = true;
1357  break;
1358  }
1359  }
1360  }*/
1361 
1362  // check size
1363  if ( size_ != pose.total_residue() ) {
1364  energy_state_ = BAD;
1365  graph_state_ = BAD;
1366  set_size( pose.total_residue() );
1367  }
1368 
1369  // set our internal domain_map if the size has changed
1370  if ( energy_state_ == BAD ) {
1371  domain_map_ = 0;
1372  energy_state_ = MOD; // since everything in domain_map has moved, we're
1373  graph_state_ = MOD; // completely correct modulo the domain_map
1375  if ( scorefunction_changed ) {
1377  update_neighbor_links( pose );
1378  // update connectivity in EnergyGraph, but do not mark the graph state as good.
1379  }
1380  }
1381 
1382  // reset total_energies_ -- should probably have been done
1384 
1387 
1388  scorefxn_weights_ = sfxn.weights();
1389 
1390 }
1391 
1392 
1393 
1394 ///////////////////////////////////////////////////////////////////////////////
1395 void
1397 {
1398  scoring_ = false;
1399  energy_state_ = GOOD;
1400 }
1401 
1402 bool
1403 Energies::res_moved( int const seqpos ) const
1404 {
1405  require_scoring();
1406  return energy_graph_->get_energy_node( seqpos )->moved();
1407 }
1408 
1409 
1410 } // scoring
1411 } // core
1412 
1413 // ///////////////////////////////////////////////////////////////////////////////
1414 // // this is called by ScoreFunction at the start of an energy calculation
1415 // //
1416 // //
1417 // void
1418 // Energies::scoring_begin(
1419 // DomainMap const & domain_map_in,
1420 // ScoreFunctionInfo const & info,
1421 // bool update_neighbors,
1422 // pose::Pose const & pose // for the neighbor calculation
1423 // )
1424 // {
1425 
1426 // // check size
1427 // if ( size_ != pose.total_residue() ) {
1428 // energy_state_ = BAD;
1429 // graph_state_ = BAD;
1430 // set_size( pose.total_residue() );
1431 // }
1432 
1433 // // check for info mismatch
1434 // if ( info != scorefxn_info_ ) {
1435 // energy_state_ = BAD;
1436 // scorefxn_info_ = info;
1437 // }
1438 
1439 // // set our scoring flag to true
1440 // scoring_ = true;
1441 
1442 // // update the domain_map
1443 // if ( ( update_neighbors && graph_state_ == BAD ) ||
1444 // ( energy_state_ == BAD ) ) {
1445 // domain_map_ = 0;
1446 // energy_state_ = MOD;
1447 // graph_state_ = MOD;
1448 // } else {
1449 // domain_map_ = domain_map_in;
1450 // }
1451 
1452 
1453 // // reset energy/neighbor links
1454 // if ( !use_nblist_ ) {
1455 // // deletes the moving links
1456 // prepare_neighbor_graphs();
1457 // } else {
1458 // // pass -- preserve the nbr graphs during minimization
1459 // }
1460 
1461 
1462 // // total and twobody energies have to be reset if anything has changed
1463 // for ( Size i=1; i<= size_; ++i ) {
1464 // if ( domain_map_(i) == 0 || domain_map_(i) != domain_map_(1) ) {
1465 // total_energies_.clear();
1466 // break;
1467 // }
1468 // }
1469 
1470 // // onebody residue energies are still valid unless bb/chi changed
1471 // // for that sequence position
1472 // for ( Size i=1; i<= size_; ++i ) {
1473 // if ( res_moved(i) ) {
1474 // onebody_energies_[i].clear();
1475 // }
1476 // }
1477 
1478 
1479 // ////////////////////////////////////////////
1480 // // update the neighbor links if desired
1481 // if ( use_nblist_ ) {
1482 // // don't modify the graphs at all
1483 // // we pretend that the graph_state is good
1484 // if ( update_neighbors ) graph_state_ = GOOD;
1485 // } else if ( update_neighbors ) {
1486 // scoring::update_neighbor_energy_links
1487 // ( pose, energy_graph_, tenA_neighbor_graph_, domain_map_ );
1488 // graph_state_ = GOOD;
1489 // } else {
1490 // //apl do we really want to do this?
1491 // //if graph state was good going into this, why would it no longer be good?
1492 // // rotamer trials wants to use the neighbor graph that already exists
1493 // // (and it has to call this function once for each residue it modifies)
1494 // //
1495 // //graph_state_ = BAD;
1496 // }
1497 
1498 
1499 
1500 // }