code: def get_exchangeable_nodes(self, n):
          
          parent = n.parent_node
          a, b = random.sample(n.child_nodes(), 2)
          if parent.parent_node is None:
              if self.tree.rooted:
                  c, d = random.sample(n.sister_nodes()[0].child_nodes(), 2)
              else:
                  c, d = random.sample(n.sister_nodes(), 2)
          else:
              c = random.choice(n.sister_nodes())
              d = random.choice(parent.sister_nodes())
  
          return a, b, c, d
docs: A      C    | Subtrees A, B, C and D are the exchangeable nodes
               \    /     | around the edge headed by n
                -->n      | The NNI exchanges either A or B with either C or D
               /    \
              B      D
  
              A      C                        C      A    | Subtree A is exchanged
               \    /        +NNI(A,C)         \    /     | with subtree C.
                -->n        ==========>         -->n
               /    \                          /    \
              B      D                        B      D