Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
automorphism.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/chemical/automorphism.cc
11 ///
12 /// @brief
13 /// @author Ian W. Davis
14 
15 
17 #include <core/chemical/Atom.hh>
18 
19 #include <utility/vector1.hh>
20 
21 
22 namespace core {
23 namespace chemical {
24 
25 /// @details First automorphism is the identity, [1 2 3 4 ... N]
26 /// The algorithm works its way through the list of atoms one at a time,
27 /// for each one trying to pair it with every other possible atom
28 /// (including itself) that isn't already paired with some earlier atom.
29 /// To be paired, the atoms need only be of the same chemical type;
30 /// for efficiency though, we also check that they have the same number of neighbors.
31 /// We also check that all the edges between the current atom and previously paired atoms
32 /// also exist between their paired counterparts (a condition for true automorphisms).
33 /// If we get to a point where we can't find a partner for some atom,
34 /// we know some earlier pairing is wrong, so we backtrack and try something else.
35 /// This algorithm would be more natural to represent recursively,
36 /// keeping state on the stack, but by "flattening" it like this we can use
37 /// the backtracking machinery to "resume" our search on the next call to next(),
38 /// thereby iterating over all the possible automorphisms.
39 /// The vector curr_[] thus takes the place of the stack, and used[] serves
40 /// to prevent two different atoms from being paired with the same partner simultaneously.
43 {
44  Size i = 1; // one of the atoms
45  // used[i] = has atom i already been partnered with someone?
46  utility::vector1<bool> used(natoms_, false);
47  while(true) {
48  Size const j = curr_[i]; // i's partner atom (at the moment)
49  // We can (and do) get j > natoms_ on subsequent calls to next();
50  // this should skip down to the "backtracking" code in the else block.
51  if( j <= natoms_ && !used[j] && can_pair(i, j) && edges_match(i) ) {
52  used[j] = true;
53  ++i; // look for a partner for the next i
54  if( i > natoms_ ) {
55  // They've all been partnered successfully! Yay!
56  utility::vector1<Size> retval = curr_; // make a copy
57  ++curr_[natoms_]; // try the next atom when we come back
58  return retval;
59  }
60  } else {
61  while(true) {
62  ++curr_[i]; // try the next atom
63  if( curr_[i] > natoms_ ) {
64  // Oops, there is no next atom!
65  // Reset curr_[] for this atom and subsequent ones;
66  // pop up to previous i and increment it instead.
67  for(Size k = i; k <= natoms_; ++k) curr_[k] = 1;
68  --i;
69  // I think we'd only get i < 0 if someone calls next() again
70  // after it returns the empty list; i == 0 is the proper end condition.
71  if( i <= 0 ) {
72  // We've reached the end; return an empty list as a signal
73  return empty_list_;
74  }
75  used[ curr_[i] ] = false;
76  } else {
77  break; // there's a next atom to try, so we're done
78  }
79  }// end while loop for finding next permutation to try
80  }// end if/else for trying to pair i and j
81  }// end infinite while()
82  return empty_list_; // to make compiler happy -- never get here
83 }
84 
85 inline
86 bool
88  return restype_->atom(i).atom_type_index() == restype_->atom(j).atom_type_index()
89  && restype_->nbrs(i).size() == restype_->nbrs(j).size();
90 }
91 
92 } // namespace chemical
93 } // namespace core