docs: def knapsack_ilp(items, maxweight, verbose=False):
      """
      solves knapsack using an integer linear program
  
      CommandLine:
          python -m utool.util_alg knapsack_ilp
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> from utool.util_alg import *  # NOQA
          >>> import utool as ut
          >>> # Solve https://xkcd.com/287/
          >>> weights = [2.15, 2.75, 3.35, 3.55, 4.2, 5.8, 6.55]
          >>> values  = [2.15, 2.75, 3.35, 3.55, 4.2, 5.8, 6.55]
          >>> indices = ['mixed fruit', 'french fries', 'side salad',
          >>>            'hot wings', 'mozzarella sticks', 'sampler plate',
          >>>            'barbecue']
          >>> items = [(v, w, i) for v, w, i in zip(values, weights, indices)]
          >>> #items += [(3.95, 3.95, 'mystery plate')]
          >>> maxweight = 15.05
          >>> verbose = True
          >>> total_value, items_subset = knapsack_ilp(items, maxweight, verbose)
          >>> print('items_subset = %s' % (ut.repr3(items_subset, nl=1),))
      """
      import pulp
      # Given Input
      values  = [t[0] for t in items]
      weights = [t[1] for t in items]
      indices = [t[2] for t in items]
      # Formulate integer program
      prob = pulp.LpProblem("Knapsack", pulp.LpMaximize)
      # Solution variables
      x = pulp.LpVariable.dicts(name='x', indexs=indices,
                                lowBound=0, upBound=1, cat=pulp.LpInteger)
      # maximize objective function
      prob.objective = sum(v * x[i] for v, i in zip(values, indices))
      # subject to
      prob.add(sum(w * x[i] for w, i in zip(weights, indices)) <= maxweight)
      # Solve using with solver like CPLEX, GLPK, or SCIP.
      #pulp.CPLEX().solve(prob)
      pulp.PULP_CBC_CMD().solve(prob)
      # Read solution
      flags = [x[i].varValue for i in indices]
      total_value = sum([val for val, flag in zip(values, flags) if flag])
      items_subset = [item for item, flag in zip(items, flags) if flag]
      # Print summary
      if verbose:
          print(prob)
          print('OPT:')
          print('\n'.join(['    %s = %s' % (x[i].name, x[i].varValue) for i in indices]))
          print('total_value = %r' % (total_value,))
      return total_value, items_subset