class_docstr: Jointly trains 2 surrogate decision trees.
  Refines diff (or sim) regions by sample generation.
code: def fit1(self, x, y, path=None, depth=0):
      if path is None:
          path = []
      if len(y) == 0:
          return None
      elif self.all_same(y):
          return {
              "val": y[0],
              "depth": depth,
              "ispure": self.all_same(y),
              "dist": np.bincount(y),
              "path": path,
          }
      elif depth >= self.max_depth:
          # compute majority class in y
          label = np.argmax(np.bincount(y))
          return {
              "val": label,
              "depth": depth,
              "ispure": self.all_same(y),
              "dist": np.bincount(y),
              "path": path,
          }
      else:
          col, cutoff, entropy = self.find_best_split_of_all(x, y)
          y_left = y[x[:, col] < cutoff]
          y_right = y[x[:, col] >= cutoff]
  
          left_path = path + [
              (self.feature_names[col], "<", np.around(cutoff, 4))
          ]
          right_path = path + [
              (self.feature_names[col], ">=", np.around(cutoff, 4))
          ]
  
          par_node = {
              "col": self.feature_names[col],
              "index_col": col,
              "cutoff": cutoff,
              "val": np.argmax(np.bincount(y)),
              "depth": depth,
              "dist": np.bincount(y),
              # recursive calls
              "left": self.fit1(
                  x[x[:, col] < cutoff], y_left, left_path, depth + 1
              ),
              "right": self.fit1(
                  x[x[:, col] >= cutoff], y_right, right_path, depth + 1
              ),
          }
  
          return par_node
  
imports: import numpy
  import pandas
  from aix360.algorithms.imd.rule import Rule
label_desc: Use image node_id 4 for calling the JointSurrogateTree obj's underlying member method code with example usage: obj.fit1(x, y, path, depth) and returns: None, dict, dict, par_node