nodes: 0, module; 1, function_definition; 2, function_name:merge; 3, parameters; 4, block; 5, identifier:a_intervals; 6, identifier:b_intervals; 7, identifier:op; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, expression_statement; 13, expression_statement; 14, expression_statement; 15, expression_statement; 16, expression_statement; 17, expression_statement; 18, while_statement; 19, return_statement; 20, comment:"""
          Merge two lists of intervals according to the boolean function op
  
          ``a_intervals`` and ``b_intervals`` need to be sorted and consistent (no overlapping intervals).
          This operation keeps the resulting interval set consistent.
  
          Parameters
          ----------
          a_intervals : `~numpy.ndarray`
              A sorted merged list of intervals represented as a N x 2 numpy array
          b_intervals : `~numpy.ndarray`
              A sorted merged list of intervals represented as a N x 2 numpy array
          op : `function`
              Lambda function taking two params and returning the result of the operation between
              these two params.
              Exemple : lambda in_a, in_b: in_a and in_b describes the intersection of ``a_intervals`` and
              ``b_intervals`` whereas lambda in_a, in_b: in_a or in_b describes the union of ``a_intervals`` and
              ``b_intervals``.
  
          Returns
          -------
          array : `numpy.ndarray`
              a N x 2 numpy containing intervals resulting from the op between ``a_intervals`` and ``b_intervals``.
          """; 21, assignment; 22, assignment; 23, assignment; 24, augmented_assignment; 25, augmented_assignment; 26, assignment; 27, assignment; 28, assignment; 29, assignment; 30, comparison_operator:scan < sentinel; 31, block; 32, call; 33, identifier:a_endpoints; 34, call; 35, identifier:b_endpoints; 36, call; 37, identifier:sentinel; 38, binary_operator:max(a_endpoints[-1], b_endpoints[-1]) + 1; 39, identifier:a_endpoints; 40, list; 41, identifier:b_endpoints; 42, list; 43, identifier:a_index; 44, integer:0; 45, identifier:b_index; 46, integer:0; 47, identifier:res; 48, list; 49, identifier:scan; 50, call; 51, identifier:scan; 52, identifier:sentinel; 53, expression_statement; 54, expression_statement; 55, expression_statement; 56, if_statement; 57, if_statement; 58, if_statement; 59, expression_statement; 60, attribute; 61, argument_list; 62, attribute; 63, argument_list; 64, attribute; 65, argument_list; 66, call; 67, integer:1; 68, identifier:sentinel; 69, identifier:sentinel; 70, identifier:min; 71, argument_list; 72, assignment; 73, assignment; 74, assignment; 75, binary_operator:in_res ^ (len(res) % 2); 76, block; 77, comparison_operator:scan == a_endpoints[a_index]; 78, block; 79, comparison_operator:scan == b_endpoints[b_index]; 80, block; 81, assignment; 82, call; 83, identifier:reshape; 84, tuple; 85, call; 86, identifier:tolist; 87, call; 88, identifier:tolist; 89, identifier:max; 90, argument_list; 91, subscript; 92, subscript; 93, identifier:in_a; 94, not_operator; 95, identifier:in_b; 96, not_operator; 97, identifier:in_res; 98, call; 99, identifier:in_res; 100, parenthesized_expression; 101, expression_statement; 102, identifier:scan; 103, subscript; 104, expression_statement; 105, identifier:scan; 106, subscript; 107, expression_statement; 108, identifier:scan; 109, call; 110, attribute; 111, argument_list; 112, unary_operator; 113, integer:2; 114, attribute; 115, argument_list; 116, attribute; 117, argument_list; 118, subscript; 119, subscript; 120, identifier:a_endpoints; 121, integer:0; 122, identifier:b_endpoints; 123, integer:0; 124, parenthesized_expression; 125, parenthesized_expression; 126, identifier:op; 127, argument_list; 128, binary_operator:len(res) % 2; 129, augmented_assignment; 130, identifier:a_endpoints; 131, identifier:a_index; 132, augmented_assignment; 133, identifier:b_endpoints; 134, identifier:b_index; 135, augmented_assignment; 136, identifier:min; 137, argument_list; 138, identifier:np; 139, identifier:asarray; 140, identifier:res; 141, integer:1; 142, identifier:a_intervals; 143, identifier:flatten; 144, identifier:b_intervals; 145, identifier:flatten; 146, identifier:a_endpoints; 147, unary_operator; 148, identifier:b_endpoints; 149, unary_operator; 150, binary_operator:(scan < a_endpoints[a_index]) ^ (a_index % 2); 151, binary_operator:(scan < b_endpoints[b_index]) ^ (b_index % 2); 152, identifier:in_a; 153, identifier:in_b; 154, call; 155, integer:2; 156, identifier:res; 157, list; 158, identifier:a_index; 159, integer:1; 160, identifier:b_index; 161, integer:1; 162, subscript; 163, subscript; 164, integer:1; 165, integer:1; 166, parenthesized_expression; 167, parenthesized_expression; 168, parenthesized_expression; 169, parenthesized_expression; 170, identifier:len; 171, argument_list; 172, identifier:scan; 173, identifier:a_endpoints; 174, identifier:a_index; 175, identifier:b_endpoints; 176, identifier:b_index; 177, comparison_operator:scan < a_endpoints[a_index]; 178, binary_operator:a_index % 2; 179, comparison_operator:scan < b_endpoints[b_index]; 180, binary_operator:b_index % 2; 181, identifier:res; 182, identifier:scan; 183, subscript; 184, identifier:a_index; 185, integer:2; 186, identifier:scan; 187, subscript; 188, identifier:b_index; 189, integer:2; 190, identifier:a_endpoints; 191, identifier:a_index; 192, identifier:b_endpoints; 193, identifier:b_index
code: def merge(a_intervals, b_intervals, op):
          """
          Merge two lists of intervals according to the boolean function op
  
          ``a_intervals`` and ``b_intervals`` need to be sorted and consistent (no overlapping intervals).
          This operation keeps the resulting interval set consistent.
  
          Parameters
          ----------
          a_intervals : `~numpy.ndarray`
              A sorted merged list of intervals represented as a N x 2 numpy array
          b_intervals : `~numpy.ndarray`
              A sorted merged list of intervals represented as a N x 2 numpy array
          op : `function`
              Lambda function taking two params and returning the result of the operation between
              these two params.
              Exemple : lambda in_a, in_b: in_a and in_b describes the intersection of ``a_intervals`` and
              ``b_intervals`` whereas lambda in_a, in_b: in_a or in_b describes the union of ``a_intervals`` and
              ``b_intervals``.
  
          Returns
          -------
          array : `numpy.ndarray`
              a N x 2 numpy containing intervals resulting from the op between ``a_intervals`` and ``b_intervals``.
          """
          a_endpoints = a_intervals.flatten().tolist()
          b_endpoints = b_intervals.flatten().tolist()
  
          sentinel = max(a_endpoints[-1], b_endpoints[-1]) + 1
  
          a_endpoints += [sentinel]
          b_endpoints += [sentinel]
  
          a_index = 0
          b_index = 0
  
          res = []
  
          scan = min(a_endpoints[0], b_endpoints[0])
          while scan < sentinel:
              in_a = not ((scan < a_endpoints[a_index]) ^ (a_index % 2))
              in_b = not ((scan < b_endpoints[b_index]) ^ (b_index % 2))
              in_res = op(in_a, in_b)
  
              if in_res ^ (len(res) % 2):
                  res += [scan]
              if scan == a_endpoints[a_index]:
                  a_index += 1
              if scan == b_endpoints[b_index]:
                  b_index += 1
  
              scan = min(a_endpoints[a_index], b_endpoints[b_index])
  
          return np.asarray(res).reshape((-1, 2))