nodes: 0, module; 1, function_definition; 2, function_name:get_closed_cycles; 3, parameters; 4, block; 5, identifier:self; 6, expression_statement; 7, comment:# A) construct all the cycles; 8, expression_statement; 9, expression_statement; 10, if_statement; 11, expression_statement; 12, while_statement; 13, comment:# B) normalize the cycle representation; 14, expression_statement; 15, comment:# a normal sort is sufficient because only the; 16, comment:# first item of each cycle is considered; 17, comment:# transform the structure into a tuple of tuples; 18, expression_statement; 19, return_statement; 20, comment:"""Return the closed cycles corresponding to this permutation
  
             The cycle will be normalized to facilitate the elimination of
             duplicates. The following is guaranteed:
  
             1) If this permutation is represented by disconnected cycles, the
                cycles will be sorted by the lowest index they contain.
             2) Each cycle starts with its lowest index. (unique starting point)
             3) Singletons are discarded. (because they are boring)
          """; 21, assignment; 22, assignment; 23, comparison_operator:todo != set(self.forward.values()); 24, block; 25, assignment; 26, comparison_operator:len(todo) > 0; 27, block; 28, call; 29, assignment; 30, identifier:closed_cycles; 31, identifier:closed_cycles; 32, list; 33, identifier:todo; 34, call; 35, identifier:todo; 36, call; 37, raise_statement; 38, identifier:current_vertex; 39, None; 40, call; 41, integer:0; 42, if_statement; 43, expression_statement; 44, expression_statement; 45, if_statement; 46, attribute; 47, argument_list; 48, identifier:closed_cycles; 49, call; 50, identifier:set; 51, argument_list; 52, identifier:set; 53, argument_list; 54, call; 55, identifier:len; 56, argument_list; 57, comparison_operator:current_vertex == None; 58, block; 59, else_clause; 60, call; 61, assignment; 62, comparison_operator:next_vertex == current_cycle[0]; 63, block; 64, else_clause; 65, identifier:closed_cycles; 66, identifier:sort; 67, identifier:tuple; 68, generator_expression; 69, call; 70, call; 71, identifier:GraphError; 72, argument_list; 73, identifier:todo; 74, identifier:current_vertex; 75, None; 76, expression_statement; 77, expression_statement; 78, block; 79, attribute; 80, argument_list; 81, identifier:next_vertex; 82, call; 83, identifier:next_vertex; 84, subscript; 85, if_statement; 86, expression_statement; 87, block; 88, call; 89, for_in_clause; 90, attribute; 91, argument_list; 92, attribute; 93, argument_list; 94, concatenated_string; 95, assignment; 96, assignment; 97, expression_statement; 98, identifier:current_cycle; 99, identifier:append; 100, identifier:current_vertex; 101, attribute; 102, argument_list; 103, identifier:current_cycle; 104, integer:0; 105, comparison_operator:len(current_cycle) > 1; 106, comment:# bring the lowest element in front; 107, block; 108, assignment; 109, expression_statement; 110, identifier:tuple; 111, argument_list; 112, identifier:cycle; 113, identifier:closed_cycles; 114, attribute; 115, identifier:keys; 116, attribute; 117, identifier:values; 118, string:"The subject and pattern graph must have the same "; 119, string:"numbering."; 120, identifier:current_vertex; 121, call; 122, identifier:current_cycle; 123, list; 124, call; 125, identifier:self; 126, identifier:get_destination; 127, identifier:current_vertex; 128, call; 129, integer:1; 130, expression_statement; 131, expression_statement; 132, expression_statement; 133, identifier:current_vertex; 134, None; 135, assignment; 136, identifier:cycle; 137, identifier:self; 138, identifier:forward; 139, identifier:self; 140, identifier:forward; 141, attribute; 142, argument_list; 143, attribute; 144, argument_list; 145, identifier:len; 146, argument_list; 147, assignment; 148, assignment; 149, call; 150, identifier:current_vertex; 151, identifier:next_vertex; 152, identifier:todo; 153, identifier:pop; 154, identifier:todo; 155, identifier:discard; 156, identifier:current_vertex; 157, identifier:current_cycle; 158, identifier:pivot; 159, call; 160, identifier:current_cycle; 161, binary_operator:current_cycle[pivot:] + \
                                      current_cycle[:pivot]; 162, attribute; 163, argument_list; 164, attribute; 165, argument_list; 166, subscript; 167, line_continuation:\; 168, subscript; 169, identifier:closed_cycles; 170, identifier:append; 171, identifier:current_cycle; 172, identifier:np; 173, identifier:argmin; 174, identifier:current_cycle; 175, identifier:current_cycle; 176, slice; 177, identifier:current_cycle; 178, slice; 179, identifier:pivot; 180, identifier:pivot
code: def get_closed_cycles(self):
          """Return the closed cycles corresponding to this permutation
  
             The cycle will be normalized to facilitate the elimination of
             duplicates. The following is guaranteed:
  
             1) If this permutation is represented by disconnected cycles, the
                cycles will be sorted by the lowest index they contain.
             2) Each cycle starts with its lowest index. (unique starting point)
             3) Singletons are discarded. (because they are boring)
          """
          # A) construct all the cycles
          closed_cycles = []
          todo = set(self.forward.keys())
          if todo != set(self.forward.values()):
              raise GraphError("The subject and pattern graph must have the same "
                               "numbering.")
          current_vertex = None
          while len(todo) > 0:
              if current_vertex == None:
                  current_vertex = todo.pop()
                  current_cycle = []
              else:
                  todo.discard(current_vertex)
              current_cycle.append(current_vertex)
              next_vertex = self.get_destination(current_vertex)
              if next_vertex == current_cycle[0]:
                  if len(current_cycle) > 1:
                      # bring the lowest element in front
                      pivot = np.argmin(current_cycle)
                      current_cycle = current_cycle[pivot:] + \
                                      current_cycle[:pivot]
                      closed_cycles.append(current_cycle)
                  current_vertex = None
              else:
                  current_vertex = next_vertex
          # B) normalize the cycle representation
          closed_cycles.sort() # a normal sort is sufficient because only the
                               # first item of each cycle is considered
  
          # transform the structure into a tuple of tuples
          closed_cycles = tuple(tuple(cycle) for cycle in closed_cycles)
          return closed_cycles