docs: def clean_dependencies(self):
          """
          Cleans the dependency graph.
  
          This is achieved by performing a transitive reduction on the dependency
          graph and removing unused dependency ids from the graph (in that
          order).
          """
          def remove_tag(p_todo, p_tag, p_value):
              """
              Removes a tag from a todo item.
              """
              p_todo.remove_tag(p_tag, p_value)
              self.dirty = True
  
          def clean_parent_relations():
              """
              Remove id: tags for todos without child todo items.
              """
  
              for todo in [todo for todo in self._todos if todo.has_tag('id')]:
                  value = todo.tag_value('id')
                  if not self._depgraph.has_edge_id(value):
                      remove_tag(todo, 'id', value)
                      del self._parentdict[value]
  
          def clean_orphan_relations():
              """
              Remove p: tags for todos referring to a parent that is not in the
              dependency graph anymore.
              """
  
              for todo in [todo for todo in self._todos if todo.has_tag('p')]:
                  for value in todo.tag_values('p'):
                      parent = self.todo_by_dep_id(value)
  
                      if not self._depgraph.has_edge(hash(parent), hash(todo)):
                          remove_tag(todo, 'p', value)
  
          self._depgraph.transitively_reduce()
          clean_parent_relations()
          clean_orphan_relations()