nodes: 0, module; 1, function_definition; 2, function_name:estimate; 3, parameters; 4, block; 5, identifier:self; 6, default_parameter; 7, default_parameter; 8, default_parameter; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, if_statement; 13, expression_statement; 14, expression_statement; 15, while_statement; 16, return_statement; 17, identifier:start; 18, None; 19, identifier:tabu_length; 20, integer:0; 21, identifier:max_indegree; 22, None; 23, comment:"""
          Performs local hill climb search to estimates the `DAG` structure
          that has optimal score, according to the scoring method supplied in the constructor.
          Starts at model `start` and proceeds by step-by-step network modifications
          until a local maximum is reached. Only estimates network structure, no parametrization.
  
          Parameters
          ----------
          start: DAG instance
              The starting point for the local search. By default a completely disconnected network is used.
          tabu_length: int
              If provided, the last `tabu_length` graph modifications cannot be reversed
              during the search procedure. This serves to enforce a wider exploration
              of the search space. Default value: 100.
          max_indegree: int or None
              If provided and unequal None, the procedure only searches among models
              where all nodes have at most `max_indegree` parents. Defaults to None.
  
          Returns
          -------
          model: `DAG` instance
              A `DAG` at a (local) score maximum.
  
          Examples
          --------
          >>> import pandas as pd
          >>> import numpy as np
          >>> from pgmpy.estimators import HillClimbSearch, BicScore
          >>> # create data sample with 9 random variables:
          ... data = pd.DataFrame(np.random.randint(0, 5, size=(5000, 9)), columns=list('ABCDEFGHI'))
          >>> # add 10th dependent variable
          ... data['J'] = data['A'] * data['B']
          >>> est = HillClimbSearch(data, scoring_method=BicScore(data))
          >>> best_model = est.estimate()
          >>> sorted(best_model.nodes())
          ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
          >>> best_model.edges()
          [('B', 'J'), ('A', 'J')]
          >>> # search a model with restriction on the number of parents:
          >>> est.estimate(max_indegree=1).edges()
          [('J', 'A'), ('B', 'J')]
          """; 24, assignment; 25, assignment; 26, comparison_operator:start is None; 27, block; 28, elif_clause; 29, assignment; 30, assignment; 31, True; 32, block; 33, identifier:current_model; 34, identifier:epsilon; 35, float:1e-8; 36, identifier:nodes; 37, call; 38, identifier:start; 39, None; 40, expression_statement; 41, expression_statement; 42, boolean_operator; 43, block; 44, identifier:tabu_list; 45, list; 46, identifier:current_model; 47, identifier:start; 48, expression_statement; 49, expression_statement; 50, for_statement; 51, if_statement; 52, attribute; 53, argument_list; 54, assignment; 55, call; 56, not_operator; 57, not_operator; 58, raise_statement; 59, assignment; 60, assignment; 61, pattern_list; 62, call; 63, block; 64, boolean_operator; 65, block; 66, elif_clause; 67, elif_clause; 68, elif_clause; 69, attribute; 70, identifier:keys; 71, identifier:start; 72, call; 73, attribute; 74, argument_list; 75, call; 76, comparison_operator:set(start.nodes()) == set(nodes); 77, call; 78, identifier:best_score_delta; 79, integer:0; 80, identifier:best_operation; 81, None; 82, identifier:operation; 83, identifier:score_delta; 84, attribute; 85, argument_list; 86, if_statement; 87, comparison_operator:best_operation is None; 88, comparison_operator:best_score_delta < epsilon; 89, break_statement; 90, comparison_operator:best_operation[0] == '+'; 91, block; 92, comparison_operator:best_operation[0] == '-'; 93, block; 94, comparison_operator:best_operation[0] == 'flip'; 95, block; 96, identifier:self; 97, identifier:state_names; 98, identifier:DAG; 99, argument_list; 100, identifier:start; 101, identifier:add_nodes_from; 102, identifier:nodes; 103, identifier:isinstance; 104, argument_list; 105, call; 106, call; 107, identifier:ValueError; 108, argument_list; 109, identifier:self; 110, identifier:_legal_operations; 111, identifier:current_model; 112, identifier:tabu_list; 113, identifier:max_indegree; 114, comparison_operator:score_delta > best_score_delta; 115, block; 116, identifier:best_operation; 117, None; 118, identifier:best_score_delta; 119, identifier:epsilon; 120, subscript; 121, string; 122, expression_statement; 123, expression_statement; 124, subscript; 125, string; 126, expression_statement; 127, expression_statement; 128, subscript; 129, string; 130, expression_statement; 131, expression_statement; 132, expression_statement; 133, expression_statement; 134, identifier:start; 135, identifier:DAG; 136, identifier:set; 137, argument_list; 138, identifier:set; 139, argument_list; 140, string:"'start' should be a DAG with the same variables as the data set, or 'None'."; 141, identifier:score_delta; 142, identifier:best_score_delta; 143, expression_statement; 144, expression_statement; 145, identifier:best_operation; 146, integer:0; 147, string_content:+; 148, call; 149, assignment; 150, identifier:best_operation; 151, integer:0; 152, string_content:-; 153, call; 154, assignment; 155, identifier:best_operation; 156, integer:0; 157, string_content:flip; 158, assignment; 159, call; 160, call; 161, assignment; 162, call; 163, identifier:nodes; 164, assignment; 165, assignment; 166, attribute; 167, argument_list; 168, identifier:tabu_list; 169, subscript; 170, attribute; 171, argument_list; 172, identifier:tabu_list; 173, subscript; 174, pattern_list; 175, subscript; 176, attribute; 177, argument_list; 178, attribute; 179, argument_list; 180, identifier:tabu_list; 181, subscript; 182, attribute; 183, argument_list; 184, identifier:best_operation; 185, identifier:operation; 186, identifier:best_score_delta; 187, identifier:score_delta; 188, identifier:current_model; 189, identifier:add_edge; 190, list_splat; 191, parenthesized_expression; 192, slice; 193, identifier:current_model; 194, identifier:remove_edge; 195, list_splat; 196, parenthesized_expression; 197, slice; 198, identifier:X; 199, identifier:Y; 200, identifier:best_operation; 201, integer:1; 202, identifier:current_model; 203, identifier:remove_edge; 204, identifier:X; 205, identifier:Y; 206, identifier:current_model; 207, identifier:add_edge; 208, identifier:Y; 209, identifier:X; 210, parenthesized_expression; 211, slice; 212, identifier:start; 213, identifier:nodes; 214, subscript; 215, binary_operator:[('-', best_operation[1])] + tabu_list; 216, identifier:tabu_length; 217, subscript; 218, binary_operator:[('+', best_operation[1])] + tabu_list; 219, identifier:tabu_length; 220, binary_operator:[best_operation] + tabu_list; 221, identifier:tabu_length; 222, identifier:best_operation; 223, integer:1; 224, list; 225, identifier:tabu_list; 226, identifier:best_operation; 227, integer:1; 228, list; 229, identifier:tabu_list; 230, list; 231, identifier:tabu_list; 232, tuple; 233, tuple; 234, identifier:best_operation; 235, string; 236, subscript; 237, string; 238, subscript; 239, string_content:-; 240, identifier:best_operation; 241, integer:1; 242, string_content:+; 243, identifier:best_operation; 244, integer:1
code: def estimate(self, start=None, tabu_length=0, max_indegree=None):
          """
          Performs local hill climb search to estimates the `DAG` structure
          that has optimal score, according to the scoring method supplied in the constructor.
          Starts at model `start` and proceeds by step-by-step network modifications
          until a local maximum is reached. Only estimates network structure, no parametrization.
  
          Parameters
          ----------
          start: DAG instance
              The starting point for the local search. By default a completely disconnected network is used.
          tabu_length: int
              If provided, the last `tabu_length` graph modifications cannot be reversed
              during the search procedure. This serves to enforce a wider exploration
              of the search space. Default value: 100.
          max_indegree: int or None
              If provided and unequal None, the procedure only searches among models
              where all nodes have at most `max_indegree` parents. Defaults to None.
  
          Returns
          -------
          model: `DAG` instance
              A `DAG` at a (local) score maximum.
  
          Examples
          --------
          >>> import pandas as pd
          >>> import numpy as np
          >>> from pgmpy.estimators import HillClimbSearch, BicScore
          >>> # create data sample with 9 random variables:
          ... data = pd.DataFrame(np.random.randint(0, 5, size=(5000, 9)), columns=list('ABCDEFGHI'))
          >>> # add 10th dependent variable
          ... data['J'] = data['A'] * data['B']
          >>> est = HillClimbSearch(data, scoring_method=BicScore(data))
          >>> best_model = est.estimate()
          >>> sorted(best_model.nodes())
          ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
          >>> best_model.edges()
          [('B', 'J'), ('A', 'J')]
          >>> # search a model with restriction on the number of parents:
          >>> est.estimate(max_indegree=1).edges()
          [('J', 'A'), ('B', 'J')]
          """
          epsilon = 1e-8
          nodes = self.state_names.keys()
          if start is None:
              start = DAG()
              start.add_nodes_from(nodes)
          elif not isinstance(start, DAG) or not set(start.nodes()) == set(nodes):
              raise ValueError("'start' should be a DAG with the same variables as the data set, or 'None'.")
  
          tabu_list = []
          current_model = start
  
          while True:
              best_score_delta = 0
              best_operation = None
  
              for operation, score_delta in self._legal_operations(current_model, tabu_list, max_indegree):
                  if score_delta > best_score_delta:
                      best_operation = operation
                      best_score_delta = score_delta
  
              if best_operation is None or best_score_delta < epsilon:
                  break
              elif best_operation[0] == '+':
                  current_model.add_edge(*best_operation[1])
                  tabu_list = ([('-', best_operation[1])] + tabu_list)[:tabu_length]
              elif best_operation[0] == '-':
                  current_model.remove_edge(*best_operation[1])
                  tabu_list = ([('+', best_operation[1])] + tabu_list)[:tabu_length]
              elif best_operation[0] == 'flip':
                  X, Y = best_operation[1]
                  current_model.remove_edge(X, Y)
                  current_model.add_edge(Y, X)
                  tabu_list = ([best_operation] + tabu_list)[:tabu_length]
  
          return current_model