Example #1
0
def solve(active: list, centers: list, sets: list, M: int) -> list:
    N, K = len(active), len(sets)
    ### model and variables
    m = Model(sense=MAXIMIZE, solver_name=CBC)
    # whether the ith set is picked
    x = [m.add_var(name=f"x{i}", var_type=BINARY) for i in range(K)]
    # whether the ith point is covered
    y = [m.add_var(name=f"y{i}", var_type=BINARY) for i in range(N)]

    ### constraints
    m += xsum(x) == M, "number_circles"
    for i in range(N):
        # if yi is covered, at least one set needs to have it
        included = [x[k] for k in range(K) if active[i] in sets[k]]
        m += xsum(included) >= y[i], f"inclusion{i}"

    ### objective: maximize number of circles covered
    m.objective = xsum(y[i] for i in range(N))

    m.emphasis = 2  # emphasize optimality
    m.verbose = 1
    status = m.optimize()
    circles = [centers[i] for i in range(K) if x[i].x >= 0.99]
    covered = {active[i] for i in range(N) if y[i].x >= 0.99}

    return circles, covered
Example #2
0
 def __init__(self, model: mip.Model):
     if model.status == mip.OptimizationStatus.LOADED:
         logger.debug("model not runned yet, checking if feasible or not")
         model.emphasis = 1  # feasibility
         model.preprocess = 1  # -1  automatic, 0  off, 1  on.
         model.optimize()
     assert (model.status == mip.OptimizationStatus.INFEASIBLE
             ), "model is not linear infeasible"
     self.model = model
Example #3
0
    def __init__(self, model: mip.Model):
        if model.status == mip.OptimizationStatus.LOADED:
            print("model not runned yet, checking if feasible or not")
            model.emphasis = 1  # feasibility
            model.preprocess = 1  # -1  automatic, 0  off, 1  on.
            model.optimize()
        assert (
            model.status == mip.OptimizationStatus.INFEASIBLE
        ), "model is not linear infeasible"

        self.model = model
        self.iis_num_iterations = 0
        self.iis_iterations = []
        self.relax_slack_iterations = []
Example #4
0
    def solve(self):
        """Try to solve the problem and identify possible matches."""
        self._check_linear_dependency()
        A_eq = self.A3D.reshape(-1, self.n_1 * self.n_2)
        n = self.n_1 * self.n_2

        # PYTHON MIP:
        model = Model()
        x = [model.add_var(var_type=BINARY) for i in range(n)]
        model.objective = minimize(xsum(x[i] for i in range(n)))
        for i, row in enumerate(A_eq):
            model += xsum(int(row[j]) * x[j]
                          for j in range(n)) == int(self.b[i])
        model.emphasis = 2
        model.verbose = 0
        model.optimize(max_seconds=2)
        self.X_binary = np.asarray([x[i].x for i in range(n)
                                    ]).reshape(self.n_1, self.n_2)
def model(antidisable: bool=True, disable_series: bool=True,
          force_disable: bool=True) -> tuple:
    """ Generates a model. """
    ### model and variables
    m = Model(sense=MAXIMIZE, solver_name=CBC)
    global x, y
    A = M if disable_series else 0
    # whether the ith bundle/series is disabled
    x = [m.add_var(name=f"x{i}", var_type=BINARY) for i in range(N + A)]
    # whether the ith series is included or not
    y = [m.add_var(name=f"y{i}", var_type=BINARY) for i in range(M)]
    if antidisable:
        global z
        # whether the ith series is antidisabled or not
        z = [m.add_var(name=f"z{i}", var_type=BINARY) for i in range(M)]

    ### constraints
    # can only disable up to K = 10 bundles, exactly K is faster but inaccurate
    # change to == K if it doesn't affect the solution and is faster
    m += xsum(x) <= NUM_DISABLE, "number_disable"
    # total sum of bundle sizes less than C = 20,000
    m += xsum(s[i]*x[i] for i in range(len(x))) <= OVERLAP, "capacity_limit"
    if antidisable:
        # can only antidisable up to A = 500 series
        m += xsum(z) <= NUM_ANTIDISABLE, "number_antidisable"
    for i in range(M):
        yi, name = y[i], series_list[i]
        bundles = [x[j] for j in range(N)
                   if name in bundle_dict[bundle_list[j]]]
        if disable_series:
            # the psuedo-bundle containing just the series
            bundles.append(x[i + N])
        # if yi is included, at least one bundle needs to have it
        m += xsum(bundles) >= yi, f"inclusion{i}"
        # forcing term, comment out if the objective incentivizes forcing
        if force_disable:
            m += xsum(bundles) <= len(bundles)*yi, f"forcing{i}"
        # shouldn't antidisable a series if it isn't disabled
        if antidisable:
            m += z[i] <= yi, f"antidisable{i}"

    m.emphasis = 2 # emphasize optimality

    return (m, x, y, z) if antidisable else (m, x, y)
def build_infeasible_cont_model(num_constraints: int = 10,
                                num_infeasible_sets: int = 20) -> Model:
    # build an infeasible model, based on many redundant constraints
    mdl = Model(name='infeasible_model_continuous')
    var = mdl.add_var(name='var', var_type=CONTINUOUS, lb=-1000, ub=1000)

    for idx, rand_constraint in enumerate(np.linspace(1, 1000,
                                                      num_constraints)):
        crt = mdl.add_constr(var >= rand_constraint,
                             name='lower_bound_{}'.format(idx))
        logger.debug('added {} to the model'.format(crt))

    num_constraint_inf = int(num_infeasible_sets / num_constraints)
    for idx, rand_constraint in enumerate(
            np.linspace(-1000, -1, num_constraint_inf)):
        crt = mdl.add_constr(var <= rand_constraint,
                             name='upper_bound_{}'.format(idx))
        logger.debug('added {} to the model'.format(crt))

    mdl.emphasis = 1  # feasibility
    mdl.preprocess = 1  # -1  automatic, 0  off, 1  on.
    # mdl.pump_passes TODO configure to feasibility emphasis
    return mdl
Example #7
0
    def top(self, v, mustvisits, weights, max_length, n_agents):
        """
        weights: [n,]
        """
        N = self.n
        M = n_agents
        L = max_length
        w = list(weights)
        MAX_VISIT = int(L / self.min_edge_length)
        l = list(np.array(self.edges).reshape(-1))

        MD = Model("plan")
        MD.verbose = 0
        x = [MD.add_var(var_type=BINARY) for i in range(N * N * M)]
        y = [MD.add_var(var_type=BINARY) for i in range(N * M)]
        u = [MD.add_var(var_type=INTEGER) for i in range(N * M)]
        z = [MD.add_var(var_type=BINARY) for i in range(N)]

        MD.objective = maximize(xsum(z[i] * w[i] for i in range(N)))
        MD.emphasis = 1

        for i in mustvisits:
            MD += (z[i] == 1)

        for m in range(M):
            MD += xsum(x[j * M + m] for j in range(1, N)) == 1

        for m in range(M):
            MD += xsum(x[i * M * N + m] for i in range(1, N)) == 1

        for i in range(1, N):
            MD += sum(y[i * M + m] for m in range(M)) >= z[i]
            MD += sum(y[i * M + m] for m in range(M)) <= z[i] * M

        for m in range(M):
            for k in range(N):
                MD += xsum(x[i * M * N + k * M + m]
                           for i in range(N)) == y[k * M + m]
                MD += xsum(x[k * M * N + i * M + m]
                           for i in range(N)) == y[k * M + m]

        for m in range(M):
            c5 = []
            for i in range(N):
                for j in range(N):
                    c5.append(l[i * N + j] * x[i * M * N + j * M + m])
            MD += xsum(iter(c5)) <= L

        for m in range(M):
            for i in range(1, N):
                for j in range(1, N):
                    MD += (u[i * M + m] - u[j * M + m] +
                           1) <= (N - 1) * (1 - x[i * M * N + j * M + m])
                    MD += 2 <= u[i * M + m]
                    MD += u[i * M + m] <= N
        MD.optimize(max_seconds=1000)

        X = np.zeros((N, N, M))
        for m in range(M):
            for i in range(N):
                for j in range(N):
                    X[i, j, m] = x[i * N * M + j * M + m].x
        return X
Example #8
0
def solve_integer_programing(
    reactant_species: List[str],
    product_species: List[str],
    reactant_bonds: List[Bond],
    product_bonds: List[Bond],
    msg: bool = True,
    threads: Optional[int] = None,
) -> Tuple[int, List[Union[int, None]], List[Union[int, None]]]:
    """
    Solve an integer programming problem to get atom mapping between reactants and
    products.

    This is a utility function for `get_reaction_atom_mapping()`.

    Args:
        reactant_species: species string of reactant atoms
        product_species: species string of product atoms
        reactant_bonds: bonds in reactant
        product_bonds: bonds in product
        msg: whether to show the solver running message to stdout.
        threads: number of threads for the solver. `None` to use default.

    Returns:
        objective: minimized objective value. This corresponds to the number of changed
            bonds (both broken and formed) in the reaction.
        r2p_mapping: mapping of reactant atom to product atom, e.g. r2p_mapping[0]
            giving 3 means that reactant atom 0 maps to product atom 3. A value of
            `None` means a mapping cannot be found for the reactant atom.
        p2r_mapping: mapping of product atom to reactant atom, e.g. p2r_mapping[3]
            giving 0 means that product atom 3 maps to reactant atom 0. A value of
            `None` means a mapping cannot be found for the product atom.

    Reference:
        `Stereochemically Consistent Reaction Mapping and Identification of Multiple
        Reaction Mechanisms through Integer Linear Optimization`,
        J. Chem. Inf. Model. 2012, 52, 84โ€“92, https://doi.org/10.1021/ci200351b
    """

    atoms = list(range(len(reactant_species)))

    # init model and variables
    model = Model(name="Reaction_Atom_Mapping",
                  sense=MINIMIZE,
                  solver_name=CBC)
    model.emphasis = 1

    if threads is not None:
        model.threads = threads

    if msg:
        model.verbose = 1
    else:
        model.verbose = 0

    y_vars = {(i, k): model.add_var(var_type=BINARY, name=f"y_{i}_{k}")
              for i in atoms for k in atoms}

    alpha_vars = {(i, j, k, l): model.add_var(var_type=BINARY,
                                              name=f"alpha_{i}_{j}_{k}_{l}")
                  for (i, j) in reactant_bonds for (k, l) in product_bonds}

    # add constraints

    # constraint 2: each atom in the reactants maps to exactly one atom in the products
    # constraint 3: each atom in the products maps to exactly one atom in the reactants
    for i in atoms:
        model += xsum([y_vars[(i, k)] for k in atoms]) == 1
    for k in atoms:
        model += xsum([y_vars[(i, k)] for i in atoms]) == 1

    # constraint 4: allows only atoms of the same type to map to one another
    for i in atoms:
        for k in atoms:
            if reactant_species[i] != product_species[k]:
                model += y_vars[(i, k)] == 0

    # constraints 5 and 6: define each alpha_ijkl variable, permitting it to take the
    # value of one only if the reactant bond (i,j) maps to the product bond (k,l)
    for (i, j) in reactant_bonds:
        for (k, l) in product_bonds:
            model += alpha_vars[(i, j, k,
                                 l)] <= y_vars[(i, k)] + y_vars[(i, l)]
            model += alpha_vars[(i, j, k,
                                 l)] <= y_vars[(j, k)] + y_vars[(j, l)]

    # create objective
    obj1 = xsum(1 - xsum(alpha_vars[(i, j, k, l)] for (k, l) in product_bonds)
                for (i, j) in reactant_bonds)
    obj2 = xsum(1 - xsum(alpha_vars[(i, j, k, l)] for (i, j) in reactant_bonds)
                for (k, l) in product_bonds)
    obj = obj1 + obj2

    # solve the problem
    try:
        model.objective = obj
        model.optimize()
    except Exception:
        raise ReactionMappingError("Failed solving integer programming.")

    if not model.num_solutions:
        raise ReactionMappingError("Failed solving integer programming.")

    # get atom mapping between reactant and product
    r2p_mapping = [None for _ in atoms]  # type: List[Union[int, None]]
    p2r_mapping = [None for _ in atoms]  # type: List[Union[int, None]]
    for (i, k), v in y_vars.items():
        if v.x == 1:
            r2p_mapping[i] = k
            p2r_mapping[k] = i

    objective = model.objective_value  # type: int

    return objective, r2p_mapping, p2r_mapping
Example #9
0
    def solve(self,
              list_of_locations,
              list_of_homes,
              starting_car_location,
              adjacency_matrix,
              input_file,
              params=[]):
        """
		Solve the problem using an MST/DFS approach.
		Input:
			list_of_locations: A list of locations such that node i of the graph corresponds to name at index i of the list
			list_of_homes: A list of homes
			starting_car_location: The name of the starting location for the car
			adjacency_matrix: The adjacency matrix from the input file
		Output:
			A cost of how expensive the current solution is
			A list of locations representing the car path
			A dictionary mapping drop-off location to a list of homes of TAs that got off at that particular location
			NOTE: all outputs should be in terms of indices not the names of the locations themselves
		"""
        conn = sqlite3.connect('models.sqlite')
        c = conn.cursor()
        seen = c.execute(
            'SELECT best_objective_bound FROM models WHERE input_file = (?)',
            (input_file, )).fetchone()

        self.log_new_entry(input_file)

        home_indices = convert_locations_to_indices(list_of_homes,
                                                    list_of_locations)
        location_indices = convert_locations_to_indices(
            list_of_locations, list_of_locations)

        edge_scale = 1.0
        if "--approx" in params:
            edge_scale = 1 / 10000

        G, message = adjacency_matrix_to_graph(adjacency_matrix, edge_scale)
        E = list(G.to_directed().edges(data='weight'))

        starting_car_index = list_of_locations.index(starting_car_location)

        start_paths = [
            convert_locations_to_indices([starting_car_location],
                                         list_of_locations)
        ]
        num_random_paths = 5
        if "-r" in params:
            num_random_paths = int(params[params.index("-r") + 1])

        for i in range(num_random_paths):
            start_paths.append(self.generate_random(G, starting_car_index))

        if seen:
            output_file = 'submissions/submission_final/{}.out'.format(
                input_file.split('.')[0])
            print(output_file)
            if not "--no-prev" in params and os.path.isfile(output_file):
                start_paths.append(
                    convert_locations_to_indices(
                        utils.read_file(output_file)[0], list_of_locations))

        best_start_path_cost = float('inf')
        best_start_path_index = -1
        for i, path in enumerate(start_paths):
            walk_cost, dropoffs = self.find_best_dropoffs(
                G, home_indices, path)
            cost, msg = cost_of_solution(G, path, dropoffs)

            if cost < best_start_path_cost:
                best_start_path_cost = cost
                best_start_path_index = i

        start_path = start_paths[best_start_path_index]
        print("Starting path:")
        if best_start_path_index == num_random_paths:
            print("SAVED PATH:", start_path)
        elif best_start_path_index >= 0:
            print("RANDOM PATH:", start_path)
        else:
            print("No start path found")
        print("Starting cost:", best_start_path_cost)

        # number of nodes and list of vertices, not including source or sink
        n, V, H = len(list_of_locations), location_indices, home_indices
        bigNum = (2 * n)

        model = Model()

        # does the car drive from i to j?
        x = [model.add_var(var_type=BINARY) for e in E]

        # does the kth TA walk from i to j? over all num_homes TAs
        t = [[model.add_var(var_type=BINARY) for e in E] for k in H]

        # car flow from vertex u to vertex v
        f = [model.add_var(var_type=INTEGER) for e in E] \
        + [model.add_var(var_type=INTEGER) for v in V] \
        + [model.add_var(var_type=INTEGER)]

        # kth TA flow from vertex u to vertex v
        f_t = [[model.add_var(var_type=BINARY)
                for e in E] + [model.add_var(var_type=BINARY) for v in V]
               for k in H]

        for i in range(len(f)):
            model += f[i] >= 0

        # For each vertex v where v != source and v != sink, Sum{x_(u, v)} = Sum{x_(v, w)}
        for v in V:
            model += xsum([x[i] for i in range(len(E))
                           if E[i][1] == v]) == xsum(
                               [x[i] for i in range(len(E)) if E[i][0] == v])

        # For each vertex v where v != sink, Sum{f_(u, v)} = Sum{f_(v, w)}
        for j in range(len(V)):
            model += xsum([f[i] for i in range(len(E)) if E[i][1] == V[j]]) + (f[-1] if V[j] == starting_car_index else 0) \
              == xsum([f[i] for i in range(len(E)) if E[i][0] == V[j]]) + f[len(E) + j]

        # For each edge (u, v) where u != source and v != sink, f_(u, v) <= (big number) * x_(u, v)
        for i in range(len(E)):
            model += f[i] <= bigNum * x[i]

        # For edge (source, start vertex), f_(source, start vertex) <= (big number)
        model += f[-1] <= bigNum

        # For each edge (u, sink), f_(u, sink) <= Sum{x_(w, u)}
        for j in range(len(V)):
            model += f[j + len(E)] \
              <= xsum([x[i] for i in range(len(E)) if E[i][1] == V[j]])

        # For just the source vertex, f_(source,start vertex)} = Sum{x_(a, b)}
        model += f[-1] == xsum(x)

        # For every TA for every edge, can't flow unless edge is walked along
        for i in range(len(t)):
            for j in range(len(E)):
                model += f_t[i][j] <= t[i][j]

        # For every TA for every non-home vertex, flow in equals flow out
        for i in range(len(H)):
            for j in range(len(V)):
                if V[j] != H[i]:
                    model += xsum(f_t[i][k] for k in range(len(E)) if E[k][1] == V[j]) + f_t[i][len(E) + j] \
                     == xsum(f_t[i][k] for k in range(len(E)) if E[k][0] == V[j])

        # For every TA, flow out of the source vertex is exactly 1
        for k in f_t:
            model += xsum(k[len(E) + i] for i in range(len(V))) == 1

        # For every TA for every edge out of source, can't flow unless car visits vertex
        for k in f_t:
            for i in range(len(V)):
                model += k[len(E) + i] <= xsum(
                    x[j] for j in range(len(E)) if E[j][1] == V[i])

        # For every TA, flow into the home vertex is exactly 1
        for i in range(len(H)):
            model += xsum(f_t[i][j] for j in range(len(E))
                          if E[j][1] == H[i]) + f_t[i][len(E) + H[i]] == 1

        # objective function: minimize the distance
        model.objective = minimize(2.0/3.0 * xsum([x[i] * E[i][2] for i in range(len(E))]) \
         + xsum([xsum([t[i][j] * E[j][2] for j in range(len(E))]) for i in range(len(t))]))

        # WINNING ONLINE
        model.max_gap = 0.00001
        model.emphasis = 2
        model.symmetry = 2

        if "--no-model-start" not in params:
            model.start = self.construct_starter(x, t, G, home_indices,
                                                 start_path)

        timeout = 300
        if "-t" in params:
            timeout = int(params[params.index("-t") + 1])

        if timeout != -1:
            status = model.optimize(max_seconds=timeout)
        else:
            status = model.optimize()

        objective_value = model.objective_value / edge_scale
        objective_bound = model.objective_bound / edge_scale

        if status == OptimizationStatus.OPTIMAL:
            print('optimal solution cost {} found'.format(objective_value))
            self.log_update_entry(Fore.GREEN +
                                  "Optimal cost={}.".format(objective_value) +
                                  Style.RESET_ALL)
        else:
            print("!!!! TIMEOUT !!!!")
            self.log_update_entry(Fore.RED + "Timeout!" + Style.RESET_ALL)

            if status == OptimizationStatus.FEASIBLE:
                print('sol.cost {} found, best possible: {}'.format(
                    objective_value, objective_bound))
                self.log_update_entry("Feasible cost={}, bound={}.".format(
                    objective_value, objective_bound))
            elif status == OptimizationStatus.NO_SOLUTION_FOUND:
                print('no feasible solution found, lower bound is: {}'.format(
                    objective_bound))
                self.log_update_entry(
                    "Failed, bound={}.".format(objective_bound))

        # if no solution found, return inf cost
        if model.num_solutions == 0:
            conn.close()
            return float('inf'), [], {}

        # printing the solution if found
        out.write('Route with total cost %g found. \n' % (objective_value))

        if "-v" in params:
            out.write('\nEdges (In, Out, Weight):\n')
            for i in E:
                out.write(str(i) + '\t')

            out.write('\n\nCar - Chosen Edges:\n')
            for i in x:
                out.write(str(i.x) + '\t')

            out.write('\n\nCar - Flow Capacities:\n')
            for i in f:
                out.write(str(i.x) + '\t')

            out.write('\n\nTAs - Home Indices:\n')
            for i in H:
                out.write(str(i) + '\n')

            out.write('\nTAs - Chosen Edges:\n')
            for i in t:
                for j in range(len(i)):
                    out.write(str(i[j].x) + '\t')
                out.write('\n')

            out.write('\nTAs - Flow Capacities:\n')
            for i in f_t:
                for j in range(len(i)):
                    out.write(str(i[j].x) + '\t')
                out.write('\n')

            out.write('\nActive Edges:\n')

            for i in range(len(x)):
                if (x[i].x >= 1.0):
                    out.write('Edge from %i to %i with weight %f \n' %
                              (E[i][0], E[i][1], E[i][2]))
            out.write('\n')

        list_of_edges = [E[i] for i in range(len(x)) if x[i].x >= 1.0]
        car_path_indices = self.construct_path(starting_car_index,
                                               list_of_edges, input_file)

        walk_cost, dropoffs_dict = self.find_best_dropoffs(
            G, home_indices, car_path_indices)
        updated = False
        if not seen:
            print("SAVING", input_file)
            c.execute('INSERT INTO models (input_file, best_objective_bound, optimal) VALUES (?, ?, ?)', \
             (input_file, objective_value, status == OptimizationStatus.OPTIMAL))
            conn.commit()
        elif objective_value <= seen[0]:
            updated = True
            print("UPDATING", input_file)
            c.execute('UPDATE models SET best_objective_bound = ?, optimal = ? WHERE input_file = ?', \
             (objective_value, status == OptimizationStatus.OPTIMAL, input_file))
            conn.commit()
        if not "-s" in params:
            print("Walk cost =", walk_cost, "\n")

        if updated:
            self.log_update_entry(Fore.GREEN + "Updated" + Style.RESET_ALL)
        else:
            self.log_update_entry(Fore.RED + "Not Updated" + Style.RESET_ALL)

        conn.close()
        return objective_value, car_path_indices, dropoffs_dict
def tsp_mip_solver(input_data):
    # parse the input
    lines = input_data.split('\n')

    nodeCount = int(lines[0])

    points = []
    for i in range(1, nodeCount + 1):
        line = lines[i]
        parts = line.split()
        points.append(Point(float(parts[0]), float(parts[1])))
    print('Points parsed!')

    # calculate distance matrix
    d_m = [[length(q, p) for q in points] for p in points]
    print('Distance matrix ready!')

    # declare MIP model
    m = Model(solver_name='GRB')
    print('-Model instatiated!', datetime.datetime.now())

    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 0

    # whenever the distance of the lower and upper bounds is less or
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05

    # specifies number of used threads
    # 0 uses solver default configuration,
    # -1 uses the number of available processing cores
    # โ‰ฅ1 uses the specified number of threads.
    # An increased number of threads may improve the solution time but also increases
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = 0

    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts = -1

    m.preprocess = 1
    m.pump_passes = 20
    m.sol_pool_size = 1

    nodes = set(range(nodeCount))

    # instantiate "entering and leaving" variables
    x = [[m.add_var(name="x{}_{}".format(p, q), var_type='B') for q in nodes]
         for p in nodes]
    # instantiate subtour elimination variables
    y = [m.add_var(name="y{}".format(i)) for i in nodes]
    print('-Variables instantiated', datetime.datetime.now())

    # declare objective function
    m.objective = minimize(
        xsum(d_m[i][j] * x[i][j] for i in nodes for j in nodes))

    print('-Objective declared!', datetime.datetime.now())

    # declare constraints
    # leave each city only once
    for i in tqdm(nodes):
        m.add_constr(xsum(x[i][j] for j in nodes - {i}) == 1)

    # enter each city only once
    for i in tqdm(nodes):
        m.add_constr(xsum(x[j][i] for j in nodes - {i}) == 1)

    # subtour elimination constraints
    for (i, j) in tqdm(product(nodes - {0}, nodes - {0})):
        if i != j:
            m.add_constr(y[i] - (nodeCount + 1) * x[i][j] >= y[j] - nodeCount)

    print('-Constraints declared!', datetime.datetime.now())

    #Maximum time in seconds that the search can go on if a feasible solution
    #is available and it is not being improved
    mssi = 1000  #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 1000000  #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000  #default = inf

    # executes the optimization
    print('-Optimizer start.', datetime.datetime.now())
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds=ms, max_seconds_same_incumbent=mssi)

    print('Opt. Status:', status)
    print('MIP Sol. Obj.:', m.objective_value)
    print('Dual Bound:', m.objective_bound)
    print('Dual gap:', m.gap)

    sol = [0]
    c_node = 0
    for j in range(nodeCount - 1):
        for i in range(nodeCount):
            if round(m.var_by_name("x{}_{}".format(c_node, i)).x) != 0:
                sol.append(i)
                c_node = i
                break

    obj = m.objective_value

    # prepare the solution in the specified output format
    if status == OptimizationStatus.OPTIMAL:
        output_data = '%.2f' % obj + ' ' + str(1) + '\n'
        output_data += ' '.join(map(str, sol))
    elif status == OptimizationStatus.FEASIBLE:
        output_data = '%.2f' % obj + ' ' + str(0) + '\n'
        output_data += ' '.join(map(str, sol))

    return output_data
Example #11
0
def fl_mip_solver(input_data):
    # Modify this code to run your optimization algorithm

    # parse the input
    lines = input_data.split('\n')

    parts = lines[0].split()
    facility_count = int(parts[0])
    customer_count = int(parts[1])
    
    facilities = []
    for i in range(1, facility_count+1):
        parts = lines[i].split()
        facilities.append(Facility(i-1, float(parts[0]), int(parts[1]), Point(float(parts[2]), float(parts[3])) ))

    customers = []
    for i in range(facility_count+1, facility_count+1+customer_count):
        parts = lines[i].split()
        customers.append(Customer(i-1-facility_count, int(parts[0]), Point(float(parts[1]), float(parts[2]))))
    
    print('F count:',facility_count)
    print('C count:',customer_count)
    
    # instantiates setup cost vector
    set_cost = [f.setup_cost for f in facilities]
    
    # instantiates proportional capacity matrix such that Cap[i,j] represents the demand of 
    # customer 'j' as a fraction of the total capacity of facility 'i'
    Cap = [[c.demand/f.capacity  for c in customers] for f in facilities]
    
    # instantiates distance matrix in such a way that "sum_{j \in M} D[i,j]*at[i,j]" is the total
    # distance cost for facility 'i'
    D = [[length(c.location, f.location)  for c in customers] for f in facilities]
    
    # declares MIP model
    #m = Model(solver_name=CBC)
    m = Model(solver_name='GRB')
    print('-Model instatiated!',datetime.datetime.now())
    
    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 2
    
    # whenever the distance of the lower and upper bounds is less or 
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05
    
    # specifies number of used threads
    # 0 uses solver default configuration, 
    # -1 uses the number of available processing cores 
    # โ‰ฅ1 uses the specified number of threads. 
    # An increased number of threads may improve the solution time but also increases 
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = -1
    
    
    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts=-1

    m.preprocess=1
    m.pump_passes=10
    m.sol_pool_size=1

    # instantiates open facilities variables
    op = [m.add_var(name="op{}".format(i),var_type='B') for i in range(facility_count)]
    
    # instantiates matrix of atribution variables 
    # (line 'i' is an atribution vector for facility 'i')
    # e.g.: At[3][4] returns whether customer 4 is assigned to facility 3
    At = [[m.add_var(name="At{},{}".format(i,j) ,var_type='B') for j in range(customer_count)] 
          for i in range(facility_count)]
    
    print('-Variables declared!',datetime.datetime.now())
    
    # instantiates objective function
    # m.objective = minimize("setup costs" + "distance costs")
    # Form example:
    # m.objective = minimize(
    # xsum(dist[i, j] * x[i, j] for (i, j) in product(F, C)) + xsum(y[i] for i in F) )
    
    m.objective = minimize(
        xsum(set_cost[i]*op[i] for i in range(facility_count)) +
        xsum(sum(D[i][j]*At[i][j] for j in range(customer_count)) for i in range(facility_count)) 
            )
    
    print('-Objective declared!',datetime.datetime.now())
    
    # instatiates capacity constraints
    #     -can be expressed as "sum_{j \in M} Cap[i,j]*At[i,j] <= op[i]" for all facilities 'i'
    #     -if a facility is closed (op[i]=0), its effective capacity is 0
    for i in range(facility_count):
        m.add_lazy_constr( xsum(Cap[i][j]*At[i][j] for j in range(customer_count)) <= op[i] )
    
    # instantiates assignment constraints (maximum of 1 facility per customer)
    #     -can be expressed as: "sum of elements over of each column of 'At' == 1"     
    for i in range(customer_count):
        m += xsum(At[j][i] for j in range(facility_count)) == 1 
    
    print('-Contraints processed!',datetime.datetime.now())
    
    #Maximum time in seconds that the search can go on if a feasible solution 
    #is available and it is not being improved
    mssi = 1000 #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 40000 #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000 #default = inf
    
    print('-Optimizer start.',datetime.datetime.now())
    # executes the optimization
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi)
    final_obj = m.objective_value

    print('Opt. Status:',status)
    print('MIP Sol. Obj.:',final_obj)
    print('Dual Bound:',m.objective_bound)
    print('Dual gap:',m.gap)
    
    
    used=[i for i in range(facility_count) if m.vars[i].x==1]

    solution=[None] * customer_count
    for i in range(facility_count):
        for j in range(customer_count):
            if round(m.vars[i*customer_count + j + facility_count].x) == 1:
                solution[j]=i
    # parse output varibles and convert to conventional solution output format
    
    # calculate the cost of the solution
    obj = sum([facilities[f].setup_cost for f in used])
    
    for customer in customers:
        obj += length(customer.location, facilities[solution[customer.index]].location)

    if status == OptimizationStatus.OPTIMAL:
    	# prepare the solution in the specified output format
    	output_data = '%.2f' % obj + ' ' + str(1) + '\n'
    	output_data += ' '.join(map(str, solution))
    elif status == OptimizationStatus.FEASIBLE:
    	output_data = '%.2f' % obj + ' ' + str(0) + '\n'
    	output_data += ' '.join(map(str, solution))
    
    return output_data
Example #12
0
def mip_solver(input_data):
    # Modify this code to run your optimization algorithm

    # parse the input
    lines = input_data.split('\n')

    firstLine = lines[0].split()
    item_count = int(firstLine[0])
    capacity = int(firstLine[1])

    items = []

    for i in range(1, item_count+1):
        line = lines[i]
        parts = line.split()
        items.append(Item(i-1, int(parts[0]), int(parts[1])))

    # a trivial algorithm for filling the knapsack
    # it takes items in-order until the knapsack is full
    value = 0
    weight = 0
    taken = [0]*len(items)
    
    # declare value vector
    val_vec = [item.value for item in items]
    
    # declare weight vector scaled by capacity
    wgt_vec = [item.weight/capacity for item in items]
    
    # start MIP solver
    m = Model(solver_name='GRB')
    print('-Model instatiated!',datetime.datetime.now())
    
    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 2
    
    # whenever the distance of the lower and upper bounds is less or 
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05
    
    # specifies number of used threads
    # 0 uses solver default configuration, 
    # -1 uses the number of available processing cores 
    # โ‰ฅ1 uses the specified number of threads. 
    # An increased number of threads may improve the solution time but also increases 
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = -1
    
    
    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts=-1

    m.preprocess=1
    m.pump_passes=10
    m.sol_pool_size=1
    
    # instantiates taken items variable vector
    taken = [m.add_var(name="it{}".format(i),var_type='B') for i in range(item_count)]
    print('-Variables declared!',datetime.datetime.now())
    
    # instantiates objective function
    m.objective = maximize( xsum( val_vec[i]*taken[i] for i in range(item_count) ) )
    print('-Objective declared!',datetime.datetime.now())
    
    m.add_constr( xsum( wgt_vec[i]*taken[i] for i in range(item_count)) <=1 )
    print('-Contraints processed!',datetime.datetime.now())
    
    #Maximum time in seconds that the search can go on if a feasible solution 
    #is available and it is not being improved
    mssi = 1000 #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 40000 #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000 #default = inf
    
    print('-Optimizer start.',datetime.datetime.now())
    # executes the optimization
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi)
    final_obj = m.objective_value
    
    print('Opt. Status:',status)
    print('MIP Sol. Obj.:',final_obj)
    print('Dual Bound:',m.objective_bound)
    print('Dual gap:',m.gap)
    
    sol = [round(it.x) for it in taken]
    value = int(final_obj)
    
    taken = sol
    # prepare the solution in the specified output format
    if status == OptimizationStatus.OPTIMAL:
        output_data = str(value) + ' ' + str(1) + '\n'
        output_data += ' '.join(map(str, taken))
    elif status == OptimizationStatus.FEASIBLE:
        output_data = str(value) + ' ' + str(0) + '\n'
        output_data += ' '.join(map(str, taken))


    if item_count == 10000:
        output_data=greedy(input_data)

    return output_data
# denominator of the expected value
m += xsum(w[i]*(d - (y[1][i] - z[1][i])) for i in range(M)) == 1, "denominator"

# if not antidisabling, turn each antidisable off 
if not ANTIDISABLE:
    for i in range(len(z[0])):
        m += z[0][i] == 0, f"{zi.name}0"
        m += z[1][i] == 0, f"{zi.name}1"

### objective: maximize expected value of the remaining characters
# numerator of the expected value, denominator has been accounted for
m.objective = xsum(t[i]*(d - (y[1][i] - z[1][i])) for i in range(M))

if __name__ == "__main__":
    m.emphasis = 2   # emphasize optimality
    m.preprocess = 1 # don't preprocess if it introduces error
    status = m.optimize()

    disable_list = [bundle_list[i] for i in range(N) if x[i].x >= 0.99] + \
        [series_list[i - N] for i in range(N, N + A) if x[i].x >= 0.99]
    antidisable_list = [series_list[i] for i in range(M) if z[0][i].x >= 0.99]
    total = get_size(disable_list)
    count, count_anti = get_wa(disable_list), get_wa(antidisable_list)

    X, p = random_variable(character_values(disable_list, antidisable_list))
    print(f"expected value: {E(p, X):.3f}")

    print(f"disablelist ({len(disable_list)}/{NUM_DISABLE})")
    print(f"{server_disabled + total} disabled ({server_wa + count} $wa)")
    print(f"Overlap limit: {total} / {OVERLAP} characters")