Пример #1
0
def minimize(args):
  """Minimize the cost of a purchase"""
  ################# Loading ##################################
  # load in wanted parts lists
  if args.parts_list.endswith(".bsx"):
    wanted_parts = io.load_bsx(open(args.parts_list))
  else:
    wanted_parts = io.load_xml(open(args.parts_list))
  print 'Loaded %d different parts' % len(wanted_parts)

  # load in pricing data
  available_parts = io.load_price_guide(open(args.price_guide))
  n_available = len(available_parts)
  n_stores = len(set(e['store_id'] for e in available_parts))
  print 'Loaded %d available lots from %d stores' % (n_available, n_stores)

  # load in store metadata
  if args.store_list is not None:
    store_metadata = io.load_store_metadata(open(args.store_list))
    print 'Loaded metadata for %d stores' % len(store_metadata)

    ################# Filtering Stores #########################
    # select which stores to get parts from
    allowed_stores = list(store_metadata)
    if args.source_country is not None:
      print 'Only allowing stores from %s' % (args.source_country,)
      allowed_stores = filter(lambda x: x['country_name'] == args.source_country, allowed_stores)

    if args.target_country is not None:
      print 'Only allowing stores that ship to %s' % (args.target_country,)
      allowed_stores = [s for s in allowed_stores
                        if args.target_country in s['ships']
                        or (len(s['ships']) == 1 and s['ships'][0] == 'All Countries WorldWide')]

    if args.feedback is not None and args.feedback > 0:
      print 'Only allowing stores with feedback >= %d' % (args.feedback,)
      allowed_stores = filter(lambda x: x['feedback'] >= args.feedback, allowed_stores)

    if args.exclude is not None:
      excludes = set(args.exclude.strip().split(","))
      excludes = map(lambda x: int(x), excludes)
      print 'Forcing exclusion of: %s' % (excludes,)
      allowed_stores = filter(lambda x: not (x['store_id'] in excludes), allowed_stores)

    store_ids = map(lambda x: x['store_id'], allowed_stores)
    store_ids = list(set(store_ids))
    print 'Using %d stores' % len(store_ids)

    available_parts = filter(lambda x: x['store_id'] in store_ids, available_parts)

    solution = minimizer.greedy(wanted_parts, available_parts)[0]
    if not minimizer.is_valid_solution(wanted_parts, solution['allocation']):
      print ("You're too restrictive. There's no way to buy what " +
             "you want with these stores")
      sys.exit(1)

  ################# Minimization #############################
  if args.algorithm in ['ilp', 'greedy']:
    if args.algorithm == 'ilp':
      ### Integer Linear Programming ###
      solution = minimizer.gurobi(
          wanted_parts,
          available_parts,
          allowed_stores,
          shipping_cost=args.shipping_cost
      )[0]
      assert minimizer.is_valid_solution(wanted_parts, solution['allocation'], allowed_stores)
    elif args.algorithm == 'greedy':
      ### Greedy Set Cover ###
      solution = minimizer.greedy(wanted_parts, available_parts)[0]

    # check and save
    io.save_solution(open(args.output + ".json", 'w'), solution)

    # print outs
    stores = set(e['store_id'] for e in solution['allocation'])
    cost = solution['cost']
    unsatisified =  minimizer.unsatisified(wanted_parts, solution['allocation'])
    print 'Total cost: $%.2f | n_stores: %d | remaining lots: %d' % (cost, len(stores), len(unsatisified))


  elif args.algorithm == 'brute-force':
    # for each possible number of stores
    for k in range(1, args.max_n_stores):
      # find all possible solutions using k stores
      solutions = minimizer.brute_force(wanted_parts, available_parts, k)
      solutions = list(sorted(solutions, key=lambda x: x['cost']))
      solutions = solutions[0:10]

      # save output
      output_folder = os.path.join(args.output, str(k))
      try:
        os.makedirs(output_folder)
      except OSError:
        pass

      for (i, solution) in enumerate(solutions):
        output_path = os.path.join(output_folder, "%02d.json" % i)
        with open(output_path, 'w') as f:
          io.save_solution(f, solution)

      # print outs
      if len(solutions) > 0:
        print '%8s %40s' % ('Cost', 'Store IDs')
        for sol in solutions:
          print '$%7.2f %40s' % (sol['cost'], ",".join(str(s) for s in sol['store_ids']))
      else:
        print "No solutions using %d stores" % k
Пример #2
0
def wanted_list(args):
  """Create BrickLink Wanted Lists for each store"""
  # load recommendation
  recommendation = io.load_solution(open(args.recommendation))
  store_metadata = io.load_store_metadata(open(args.store_list))
  io.save_xml_per_vendor(args.output, recommendation, store_metadata)