class_docstr: Forest structure, i.e. a set of trees
  
  The nodes can be segmented into trees.
  
  Within each tree a node has one parent and children
  that describe the associated hierarchical structure.
  Some of the nodes can be viewed as leaves, other as roots
  The edges within a tree are associated with a weight:
  
  * +1 from child to parent
  * -1 from parent to child
  
  Attributes
  ----------
  V : int
      int > 0, the number of vertices
  E : int
      the number of edges
  parents : (self.V,) array
      the parent array
  edges : (self.E, 2) array
      representing pairwise neighbors
  weights : (self.E,) array
      +1/-1 for ascending/descending links
  children: list
      list of arrays that represents the children any node
class_docstr_tok: ["Forest","structure",",","i.e",".","a","set","of","trees","The","nodes","can","be","segmented","into","trees",".","Within","each","tree","a","node","has","one","parent","and","children","that","describe","the","associated","hierarchical","structure",".","Some","of","the","nodes","can","be","viewed","as","leaves",",","other","as","roots","The","edges","within","a","tree","are","associated","with","a","weight",":","*","+1","from","child","to","parent","*","-1","from","parent","to","child","Attributes","--","--","--","--","--","V",":","int","int",">","0",",","the","number","of","vertices","E",":","int","the","number","of","edges","parents",":","(","self.V",",",")","array","the","parent","array","edges",":","(","self.E",",","2",")","array","representing","pairwise","neighbors","weights",":","(","self.E",",",")","array","+1\/-1","for","ascending\/descending","links","children",":","list","list","of","arrays","that","represents","the","children","any","node"]
docstr: tests whether the given nodes are the leaves of a certain subtree
  
  Parameters
  ----------
  ids: array of shape (n) that takes values in [0..self.V-1]
  custom == False, boolean
         if custom==true the behavior of the function is more specific
         - the different connected components are considered
         as being in a same greater tree
         - when a node has more than two subbranches,
         any subset of these children is considered as a subtree
docstr_tok: ["tests","whether","the","given","nodes","are","the","leaves","of","a","certain","subtree","Parameters","--","--","--","--","--","ids",":","array","of","shape","(","n",")","that","takes","values","in","[","0","..","self.V-1","]","custom","==","False",",","boolean","if","custom==true","the","behavior","of","the","function","is","more","specific","-","the","different","connected","components","are","considered","as","being","in","a","same","greater","tree","-","when","a","node","has","more","than","two","subbranches",",","any","subset","of","these","children","is","considered","as","a","subtree"]
code: def leaves_of_a_subtree(self, ids, custom=False):
      """tests whether the given nodes are the leaves of a certain subtree
  
      Parameters
      ----------
      ids: array of shape (n) that takes values in [0..self.V-1]
      custom == False, boolean
             if custom==true the behavior of the function is more specific
             - the different connected components are considered
             as being in a same greater tree
             - when a node has more than two subbranches,
             any subset of these children is considered as a subtree
      """
      leaves = self.isleaf().astype("bool")
      for i in ids:
          if leaves[i] == 0:
              raise ValueError("some of the ids are not leaves")
  
      # 1. find the highest node that is a common ancestor to all leaves
      # if there is none, common ancestor is -1
      com_ancestor = ids[0]
      for i in ids:
          ca = i
          dca = self.get_descendants(ca)
          while com_ancestor not in dca:
              ca = self.parents[ca]
              dca = self.get_descendants(ca)
              if (ca == self.parents[ca]) & (com_ancestor not in dca):
                  ca = -1
                  break
          com_ancestor = ca
  
      # 2. check whether all the children of this ancestor are within ids
      if com_ancestor > -1:
          st = self.get_descendants(com_ancestor)
          valid = [i in ids for i in st if leaves[i]]
          bresult = np.sum(valid) == np.size(valid)
          if custom == False:
              return bresult
  
          # now, custom =True
          # check that subtrees of ancestor are consistently labelled
          kids = self.get_children(com_ancestor)
          if np.size(kids) > 2:
              bresult = True
              for v in kids:
                  st = np.array(self.get_descendants(v))
                  st = st[leaves[st]]
                  if np.size(st) > 1:
                      valid = [i in ids for i in st]
                      bresult *= (
                          np.sum(valid) == np.size(valid)
                      ) + np.sum(valid == 0)
          return bresult
  
      # now, common ancestor is -1
      if custom == False:
          st = np.squeeze(np.nonzero(leaves))
          valid = [i in ids for i in st]
          bresult = np.sum(valid) == np.size(valid)
      else:
          cc = self.cc()
          bresult = True
          for i in ids:
              st = np.squeeze(np.nonzero((cc == cc[i]) * leaves))
              if np.size(st) > 1:
                  valid = [i in ids for i in st]
                  bresult *= np.sum(valid) == np.size(valid)
              else:
                  bresult *= st in ids
      return bresult
  
imports: import numpy
  from .graph import WeightedGraph
label_desc: Use image node_id 14 for calling the Forest obj's underlying member method code with example usage: obj.leaves_of_a_subtree(ids, custom) and returns: bresult, bresult, bresult