class_docstr: An approximation method to deal with intractably
  large size of graph tuning problem.
  
  This graph coloring algorithm mainly comes from:
  
  Lang Hames and Bernhard Scholz.
  Nearly optimal register allocation with pbqp.JMLC 2006.
  LNCS, vol.4228,pp. 346-361, 2016
class_docstr_tok: ["An","approximation","method","to","deal","with","intractably","large","size","of","graph","tuning","problem",".","This","graph","coloring","algorithm","mainly","comes","from",":","Lang","Hames","and","Bernhard","Scholz",".","Nearly","optimal","register","allocation","with","pbqp.JMLC","2006",".","LNCS",",","vol.4228",",","pp",".","346-361",",","2016"]
docstr: Run partitioned boolean quadratic programming tuner.
docstr_tok: ["Run","partitioned","boolean","quadratic","programming","tuner","."]
code: def run(self, **kwargs):
      """Run partitioned boolean quadratic programming tuner."""
      self._logger.info("Start to run PBQP algorithm...")
      # Define virtual record lists and layout transformaton matrices
      # for multi-input nodes.
      input_names = self._input_shapes.keys()
      temp = {}
      for key, val in self._in_nodes_dict.items():
          target_input_idx = -1
          target_input_pos = -1
          if has_multiple_inputs(
              self._node_list, key, input_names, self._opt_out_op
          ):
              for i, item in enumerate(val):
                  node = self._node_list[item]
                  if not is_boundary_node(node, input_names):
                      target_input_idx = item
                      target_input_pos = i
                      break
  
              # Skip boundary operator
              if target_input_idx < 0:
                  continue
  
              temp[(target_input_idx, key)] = []
              record_candidates = self._node_list[target_input_idx][
                  "record_candidates"
              ]
              for j in range(len(record_candidates)):
                  temp[(target_input_idx, key)].append([])
                  for k in range(len(record_candidates)):
                      temp[(target_input_idx, key)][j].append(
                          0 if j == k else INVALID_LAYOUT_TIME
                      )
  
              for j in range(target_input_pos + 1, len(val)):
                  input_idx = val[j]
                  input_node = self._node_list[input_idx]
                  if is_boundary_node(input_node, input_names):
                      continue
                  temp[
                      (input_idx, key)
                  ] = self._layout_transform_interlayer_cost[
                      (input_idx, target_input_idx)
                  ]
      self._layout_transform_interlayer_cost.update(temp)
  
      # Create reverse layout transformation matrices
      temp = {}
      for (
          idx_pair,
          ltf_matrix,
      ) in self._layout_transform_interlayer_cost.items():
          reverse_key = (idx_pair[1], idx_pair[0])
          reverse_matrix = [[] for _ in range(len(ltf_matrix[0]))]
          for i, _ in enumerate(ltf_matrix):
              for j, ltf in enumerate(ltf_matrix[i]):
                  reverse_matrix[j].append(ltf)
          temp[reverse_key] = reverse_matrix
      self._layout_transform_interlayer_cost.update(temp)
  
      self._forward()
      self._backward()
      is_optimal = "optimal" if self._is_optimal else "sub-optimal"
      msg = f"Finished PBQPExecutor run. Got {is_optimal} solution."
      self._logger.info(msg)
  
file_path: tvm/python/tvm/autotvm/graph_tuner/pbqp_tuner.py
imports: from ._base import INVALID_LAYOUT_TIME
  from .base_graph_tuner import BaseGraphTuner
  from .utils import is_boundary_node, has_multiple_inputs
label_desc: Use image node_id 12 for calling the PBQPTuner obj's underlying member method code with example usage: obj.run() without return types