コード例 #1
0
 def __init__(self):
     self.prob = LpProblem('pydfs_lineup_optimizer', LpMaximize)
コード例 #2
0
def optimise_selection(
    schedule_input: pd.DataFrame,
    selection_limit: int,
    black_points_limit: int,
    rounds: List[str],
    loser: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Optimise player selection.
    :param schedule_input: Players and their schedule.
    :param selection_limit: Number of players to choose.
    :param black_points_limit: Maximum number of black points.
    :param rounds: Rounds to play
    :param loser: Selected loser
    :return: Optimal selection
    """
    LOGGER.info("Optimising selection")

    schedule = schedule_input.copy()
    black_extra = 0
    selection_limit_extra = 0
    extra_loss = 0

    if loser:
        loser_record = schedule[schedule["player"].str.lower() ==
                                loser.lower()].iloc[0]

        if loser_record.empty:
            LOGGER.warning("Unable to find player %s in draw", loser)
            loser = None
        else:
            loser = loser_record.player

            # extra_loss = TennisPoolEmulator.rounds_to_score(
            #     rounds=loser_record.rounds,
            #     black=loser_record.black,
            #     loser=True
            # )

            extra_loss = TennisPoolEmulator.probabilities_to_score(
                round_probs=loser_record[rounds],
                black=loser_record.black,
                loser=True)

            schedule.loc[schedule.player == loser, "potency"] = extra_loss

            black_extra = loser_record.black
            selection_limit_extra = 1
            LOGGER.info(
                "Allowing %d extra black points, because of your selected loser",
                black_extra,
            )
            LOGGER.info(
                "Adding the loser to your selection, and simultaneously increasing the limit of your"
                "selection, such that your loser is taken into account.")

    black_points_limit += black_extra

    players = schedule["player"].tolist()
    potency = schedule["potency"].tolist()
    black_points = schedule["black"].tolist()

    param_player = range(len(schedule))

    # Declare problem instance, maximization problem
    probability = LpProblem("PlayerSelection", LpMaximize)

    # Declare decision variable x, which is 1 if a
    # player is part of the selection and 0 else
    param_x = LpVariable.matrix("x", list(param_player), 0, 1, LpInteger)

    # Objective function -> Maximise potency
    probability += sum(potency[p] * param_x[p] for p in param_player)

    # Constraint definition
    probability += sum(param_x[p]
                       for p in param_player) == (selection_limit +
                                                  selection_limit_extra)
    probability += (sum(black_points[p] * param_x[p]
                        for p in param_player) <= black_points_limit)

    if loser:
        probability += param_x[players.index(loser)] == 1

    # Start solving the problem instance
    probability.solve()

    # Extract solution
    player_selection = [
        players[p] for p in param_player if param_x[p].varValue
    ]

    LOGGER.info("Optimiser finished")

    if loser:
        LOGGER.warning(
            "Do note you're going to lose %d points because of your loser.",
            -extra_loss)

    return {
        "schedule":
        schedule[schedule["player"].isin(
            player_selection)].copy().reset_index(),
        "loser":
        extra_loss,
    }
コード例 #3
0
 def __init__(self, **kwargs):
     self.name = kwargs.get('name', 'DFSModel')
     self.salary_cap = kwargs.get('salary_cap', 50000)
     self.model = LpProblem(self.name, LpMaximize)
コード例 #4
0
 def test_result_size(self):
     function_result = solve_linear_problem(LpProblem())
     self.assertEqual(len(function_result), 3)
コード例 #5
0
# This collection of models is licensed under The Creative Commons    #
# CC BY-SA 3.0 License, a copy of which is available here:            #
#                                                                     #
# http://creativecommons.org/licenses/by-sa/3.0/                      #
#                                                                     #
# Copyright 2014, Ted Ralphs                                          #
# All Rights Reserved                                                 #
# [email protected]                                                      #
#                                                                     #
#######################################################################

from pulp import LpProblem, LpVariable, lpSum, LpMaximize, value, LpStatus

from bonds_data import bonds, max_rating, max_maturity, max_cash

prob = LpProblem("Bond Selection Model", LpMaximize)

buy = LpVariable.dicts('bonds', bonds.keys(), 0, None)

prob += lpSum(bonds[b]['yield'] * buy[b] for b in bonds)

prob += lpSum(buy[b] for b in bonds) <= max_cash, "cash"

prob += lpSum(bonds[b]['rating'] * buy[b]
              for b in bonds) <= max_cash * max_rating, "ratings"

prob += lpSum(bonds[b]['maturity'] * buy[b]
              for b in bonds) <= max_cash * max_maturity, "maturities"

status = prob.solve()
コード例 #6
0
# Problem Data
feed: List = [0, 1, 2, 3, 4, 5]

costs: Dict = {0: 0.74, 1: 0.70, 2: 0.83, 3: 0.81, 4: 0.73, 5: 0.75}

minimum: Dict = {0: 200, 1: 180, 2: 150}  # Carbohydrate  # Protein  # Vitamin

inf_nutri: List = [
    [50, 60, 30, 0, 20, 45],
    [27, 0, 40.5, 20, 30, 50],
    [50, 80, 60, 30, 20, 40],
]

# Model and Decision Variables
model = LpProblem("Diet_problem", LpMinimize)
var = LpVariable.dict("R", feed, lowBound=0, cat="Integer")

# Goal function
model += lpSum(var[x] * costs[x] for x in var.keys())

# Constrains
list_rest: List = []
for i in minimum.keys():
    for j in feed:
        list_rest.append(var[j] * inf_nutri[i][j])
    model += lpSum(list_rest) >= minimum[i]
    list_rest = []

print(model)
コード例 #7
0
    def generate_mincost_relaxations(candidate, negative_cycle,
                                     feasibility_type):

        all_cycles = candidate.continuously_resolved_cycles.copy()
        all_cycles.add(negative_cycle)

        # print("Solving against " + str(len(all_cycles)) + " cycles")

        # Solve using PuLP, TODO, incorporate interface to other solvers,
        # especially for nonlinear objective functions
        prob = LpProblem("MinCostConflictResolution", LpMinimize)

        # Solve using PyOpt/Snopt,
        # especially for nonlinear constraints/objective functions

        # construct variables and constraints
        lp_variables = {}
        lp_objective = []

        # status indicating the feasibility of the relaxation problem
        # 1 is feasible
        # 0 is infeasible
        # Note that this variable is shared by PuLP for its result
        status = 1
        # print("Cycles: " + str(len(all_cycles)))
        for cycle in all_cycles:
            # cycle.pretty_print()

            lp_ncycle_constraint = []

            for constraint, bound in cycle.constraints.keys():
                # The constraint is a pair (temporal_constraint,0/1)
                # where 0 or 1 represent if it is the lower or upper bound

                # first we define the variables
                # which only come from relaxable bounds of constraints
                # in other words, if no constraint in a negative cycle is
                # relaxable, the LP is infeasible
                # and we can stop here

                # TODO: add handler for uncontrollable duration
                variable = None
                if (constraint, bound) in lp_variables:
                    variable = lp_variables[(constraint, bound)]

                coefficient = cycle.constraints[(constraint, bound)]

                if variable is None:
                    if bound == 0:
                        # lower bound, the domain is less than the original LB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_lb:
                            # print("LB cost " + str(constraint.relax_cost_lb) + "/" + constraint.name)

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                variable = LpVariable(constraint.id + "-LB",
                                                      None,
                                                      constraint.lower_bound)
                                # print("New LB VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (constraint.lower_bound - variable) *
                                    constraint.relax_cost_lb)
                            else:
                                variable = LpVariable(
                                    constraint.id + "-LB",
                                    constraint.lower_bound,
                                    constraint.upper_bound - 0.001)
                                # print("New LB-UC VAR: " + str(variable) + " [" + str(None) + "," + str(constraint.lower_bound) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (variable - constraint.lower_bound) *
                                    constraint.relax_cost_lb)

                                # Add an additional constraint to make sure that
                                # the lower bound is smaller than the upper bound
                                if (constraint, 1) in lp_variables:
                                    ub_variable = lp_variables[(constraint, 1)]
                                    uncertain_duration_constraint = []
                                    uncertain_duration_constraint.append(
                                        (ub_variable - variable))
                                    prob += sum(
                                        uncertain_duration_constraint) >= 0.001
                                    # print("Adding domain constraint for " + constraint.name)

                        else:
                            variable = constraint.lower_bound

                    elif bound == 1:
                        # upper bound, the domain is larger than the original UB
                        # if the constraint is not relaxable, fix its domain
                        if constraint.relaxable_ub:
                            # print("UB cost " + str(constraint.relax_cost_ub) + "/" + constraint.name)

                            if constraint.controllable or feasibility_type == FeasibilityType.CONSISTENCY:
                                variable = LpVariable(constraint.id + "-UB",
                                                      constraint.upper_bound,
                                                      None)
                                # print("New UB VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                # add the variable to the objective function
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (variable - constraint.upper_bound) *
                                    constraint.relax_cost_ub)
                            else:
                                variable = LpVariable(
                                    constraint.id + "-UB",
                                    constraint.lower_bound + 0.001,
                                    constraint.upper_bound)
                                # print("New UB-UC VAR: " + str(variable) + " [" + str(constraint.upper_bound) + "," + str(None) + "]")
                                lp_variables[(constraint, bound)] = variable
                                lp_objective.append(
                                    (constraint.upper_bound - variable) *
                                    constraint.relax_cost_ub)

                                # Add an additional constraint to make sure that
                                # the lower bound is smaller than the upper bound
                                if (constraint, 0) in lp_variables:
                                    lb_variable = lp_variables[(constraint, 0)]
                                    uncertain_duration_constraint = []
                                    uncertain_duration_constraint.append(
                                        (variable - lb_variable))
                                    prob += sum(
                                        uncertain_duration_constraint) >= 0.001
                                    # print("Adding domain constraint for " + constraint.name)
                        else:
                            variable = constraint.upper_bound

                    assert variable is not None
                # print("Adding variable " + str(coefficient) + "*"+str(variable))
                lp_ncycle_constraint.append(variable * coefficient)

            # add the constraint to the problem
            # print(str(lp_ncycle_constraint))
            if sum(lp_ncycle_constraint) >= 0:
                # print(str(sum(lp_ncycle_constraint)) + " >= 0")
                # Over relax a bit to account for precision issues
                prob += sum(lp_ncycle_constraint) >= 0.0
            else:
                status = 0
                # this is not resolvable
                # no need to proceed

        if status > 0:
            # Set the objective function
            prob += sum(lp_objective)
            # for c in prob.constraints:
            #     print("CON: ", prob.constraints[c])
            # print("OBJ: ", prob.objective)

            # Solve the problem
            try:
                import gurobipy
                status = prob.solve(pulp.GUROBI(mip=False, msg=False))
            except ImportError:
                # pass # Gurobi doesn't exist, use default Pulp solver.
                status = prob.solve()

            # exit(0);

        # print("Computing relaxation")
        # if no solution was found, do nothing

        if status > 0:

            # A solution has been found
            # extract the result and store them into a set of relaxation
            # the outcome is a set of relaxations
            relaxations = []

            # print("Found relaxation")
            for constraint, bound in lp_variables.keys():
                variable = lp_variables[(constraint, bound)]
                relaxed_bound = value(variable)

                if bound == 0:
                    # check if this constraint bound is relaxed
                    if relaxed_bound != constraint.lower_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_lb = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_lb <= constraint.upper_bound

                elif bound == 1:
                    # same for upper bound
                    if relaxed_bound != constraint.upper_bound:
                        # yes! create a new relaxation for it
                        relaxation = TemporalRelaxation(constraint)
                        relaxation.relaxed_ub = relaxed_bound
                        # relaxation.pretty_print()
                        relaxations.append(relaxation)
                        assert relaxation.relaxed_ub >= constraint.lower_bound

            # print("")

            if len(relaxations) > 0:
                return relaxations, 0

        return None, 0
コード例 #8
0
def ilp_cgdp(
        cg: ComputationGraph,
        agentsdef: Iterable[AgentDef],
        footprint: Callable[[str], float],
        capacity: Callable[[str], float],
        route: Callable[[str, str], float],
        msg_load: Callable[[str, str], float],
        hosting_cost: Callable[[str, str], float],
        timeout=600,  # Max 10 min
):
    start_t = time.time()

    agt_names = [a.name for a in agentsdef]
    pb = LpProblem("oilp_cgdp", LpMinimize)

    # One binary variable xij for each (variable, agent) couple
    xs = LpVariable.dict("x", (cg.node_names(), agt_names), cat=LpBinary)

    # TODO: Do not create var for computation that are already assigned to an agent with hosting = 0 ?
    # Force computation with hosting cost of 0 to be hosted on that agent.
    # This makes the work much easier for glpk !
    x_fixed_to_0 = []
    x_fixed_to_1 = []
    for agent in agentsdef:
        for comp in cg.node_names():
            assigned_agent = None
            if agent.hosting_cost(comp) == 0:
                pb += xs[(comp, agent.name)] == 1
                x_fixed_to_1.append((comp, agent.name))
                assigned_agent = agent.name
                for other_agent in agentsdef:
                    if other_agent.name == assigned_agent:
                        continue
                    pb += xs[(comp, other_agent.name)] == 0
                    x_fixed_to_0.append((comp, other_agent.name))
                logger.debug(
                    f"Setting binary varaibles to fixed computation {comp}")

    # One binary variable for computations c1 and c2, and agent a1 and a2
    betas = {}
    count = 0
    for a1, a2 in combinations(agt_names, 2):
        # Only create variables for couple c1, c2 if there is an edge in the
        # graph between these two computations.
        for l in cg.links:
            # As we support hypergraph, we may have more than 2 ends to a link
            for c1, c2 in combinations(l.nodes, 2):
                if (c1, a1, c2, a2) in betas:
                    continue
                count += 2
                b = LpVariable("b_{}_{}_{}_{}".format(c1, a1, c2, a2),
                               cat=LpBinary)
                betas[(c1, a1, c2, a2)] = b
                # Linearization constraints :
                # a_ijmn <= x_im
                # a_ijmn <= x_jn
                if (c1, a1) in x_fixed_to_0 or (c2, a2) in x_fixed_to_0:
                    pb += b == 0
                elif (c1, a1) in x_fixed_to_1:
                    pb += b == xs[(c2, a2)]
                elif (c2, a2) in x_fixed_to_1:
                    pb += b == xs[(c1, a1)]
                else:
                    pb += b <= xs[(c1, a1)]
                    pb += b <= xs[(c2, a2)]
                    pb += b >= xs[(c2, a2)] + xs[(c1, a1)] - 1

                b = LpVariable("b_{}_{}_{}_{}".format(c1, a2, c2, a1),
                               cat=LpBinary)
                if (c1, a2) in x_fixed_to_0 or (c2, a1) in x_fixed_to_0:
                    pb += b == 0
                elif (c1, a2) in x_fixed_to_1:
                    pb += b == xs[(c2, a1)]
                elif (c2, a1) in x_fixed_to_1:
                    pb += b == xs[(c1, a2)]
                else:
                    betas[(c1, a2, c2, a1)] = b
                    pb += b <= xs[(c2, a1)]
                    pb += b <= xs[(c1, a2)]
                    pb += b >= xs[(c1, a2)] + xs[(c2, a1)] - 1

    # Set objective: communication + hosting_cost
    pb += (
        _objective(xs, betas, route, msg_load, hosting_cost),
        "Communication costs and prefs",
    )

    # Adding constraints:
    # Constraints: Memory capacity for all agents.
    for a in agt_names:
        pb += (
            lpSum([footprint(i) * xs[i, a]
                   for i in cg.node_names()]) <= capacity(a),
            "Agent {} capacity".format(a),
        )

    # Constraints: all computations must be hosted.
    for c in cg.node_names():
        pb += (
            lpSum([xs[c, a] for a in agt_names]) == 1,
            "Computation {} hosted".format(c),
        )

    # the timeout for the solver must be minored by the time spent to build the pb:
    remaining_time = round(timeout - (time.time() - start_t)) - 2
    # solve using GLPK
    try:
        status = pb.solve(solver=GLPK_CMD(
            keepFiles=0,
            msg=False,
            options=["--pcost", "--tmlim",
                     str(remaining_time)]))
    except PulpSolverError as pse:
        raise ImpossibleDistributionException(f"Pulp error {pse}", pse)
    if status == LpStatusUndefined:
        # Generally means we have reach the timeout.
        raise TimeoutError(f"Could not find solution in {timeout}")

    if status != LpStatusOptimal:
        raise ImpossibleDistributionException(
            f"No possible optimal distribution {status}")
    logger.debug("GLPK cost : %s", pulp.value(pb.objective))

    mapping = {}
    for k in agt_names:
        agt_computations = [
            i for i, ka in xs if ka == k and pulp.value(xs[(i, ka)]) == 1
        ]
        # print(k, ' -> ', agt_computations)
        mapping[k] = agt_computations
    return mapping
コード例 #9
0
# constraints_matrix = np.transpose([sov_mv, sov_mv_l, corp_mv, illiquid_mv, illiquid_mv_l,  bbb_mv, below_bbb_mv])  # sov_mv, sov_mv_l, corp_mv, illiquid_mv, illiquid_mv_l,  bbb_mv, below_bbb_mv
# #print(constraints_matrix)

# # define the A_ub matrix
# #    rows:  47                  20              20                7
# opt_matrix = np.concatenate((main_matrix, funding_gap_matrix, constraints_matrix), axis=1)    # 200 x 47
# #opt_matrix = np.concatenate((main_matrix, funding_gap_matrix), axis=1)

# # prepare arguments
# bonds_mv_T = np.transpose(bonds_mv)               # 200 x 1
# opt_matrix_T = np.transpose(opt_matrix)           # 47 x 200
# bounds_vector_T = np.transpose(bounds_vector)     # 47 x 1
# #bounds_vector_T = np.transpose(funding_gap_bounds)

#Model solver:
model = LpProblem(name="BondPortfolio", sense=LpMaximize)
x = {i: LpVariable(name=f"x{i}", lowBound=0) for i in range(200)}

# objective:
model += liabilities_NPV - lpSum(cost_vector[i] * x[i] for i in range(200))

# funding gap constraints
for i in range(20):
    model += lpSum(x[j] * main_matrix[j, i]
                   for j in range(200)) <= funding_gap_upper[i]
    model += lpSum(x[j] * main_matrix[j, i]
                   for j in range(200)) >= funding_gap_lower[i]

status = model.solve()
print(f"status: {model.status}, {LpStatus[model.status]}")
print(f"objective: {model.objective.value()}")
コード例 #10
0
 def __init__(self):
     self.prob = LpProblem('Daily Fantasy Sports', LpMaximize)
コード例 #11
0
LOAN2 = 80 * 1000
MONTHLY_INTEREST2 = 0.08 / 12.0

ANNUAL_SALARY = 109 * 1000
TAX_RATE = 0.30
SAVINGS_RATE = 0.50

MONTHLY_CONTRIBUTIONS = (SAVINGS_RATE * ANNUAL_SALARY * (1 - TAX_RATE)) / 12.0
MONTHLY_COMPOUNDING = 0.07 / 12.0

print(MONTHLY_CONTRIBUTIONS)

NUM_MONTHS = 10 * 12

# Define the model
model = LpProblem(name="loan_optimization", sense=LpMaximize)

# Define the decision variables
loan1 = \
  {i: LpVariable(name=f"l1_{i}", lowBound=0) for i in range(NUM_MONTHS)}
loan_contribution1 = \
  {i: LpVariable(name=f"lc1_{i}", lowBound=0) for i in range(NUM_MONTHS)}
interest1 = \
  {i: LpVariable(name=f"interest1_{i}", lowBound=0) for i in range(NUM_MONTHS)}

loan2 = \
  {i: LpVariable(name=f"l2_{i}", lowBound=0) for i in range(NUM_MONTHS)}
loan_contribution2 = \
  {i: LpVariable(name=f"lc2_{i}", lowBound=0) for i in range(NUM_MONTHS)}
interest2 = \
  {i: LpVariable(name=f"interest2_{i}", lowBound=0) for i in range(NUM_MONTHS)}
コード例 #12
0
def main():
    logger.info("start")
    n_family = 5000
    n_days = 100
    n_choice = 10

    days = list(range(n_days, 0, -1))

    df_family = pd.read_csv("../input/family_data.csv", index_col="family_id")

    map_family_size = df_family["n_people"].to_dict()

    with open("mat_cost.pkl", "rb") as f:
        mat_cost = pickle.load(f)
    map_var_x_cost = {(f, d): mat_cost[f, d - 1] for f in range(n_family) for d in days}

    # map_var_x_cost[f, d] family i, day d

    map_cost_ac = {}
    for i in tqdm(range(125, 301)):
        for j in range(125, 301):
            diff = abs(i - j)
            map_cost_ac[i, j] = min(
                max(0, (i - 125.0) / 400.0 * i ** (0.5 + diff / 50.0)), 100000
            )
    map_var_x_name = {(i, j): f"x_{i}_{j}" for i in range(n_family) for j in days}

    map_var_z_cost = {
        (p, q, d): map_cost_ac[p, q]
        for p in range(125, 301)
        for q in range(125, 301)
        for d in days
    }
    map_var_z_name = {
        (p, q, d): f"z_{p}_{q}_{d}"
        for p in range(125, 301)
        for q in range(125, 301)
        for d in days
    }

    model = LpProblem("santa2019", LpMinimize)

    logger.info("Define vars")
    var_x = {k: LpVariable(f"x_{k}", cat=LpBinary) for k in map_var_x_cost}
    var_z = {k: LpVariable(f"z_{k}", cat=LpBinary) for k in map_var_z_cost}

    logger.info("Each familiy must attend 1 session")
    for f in range(n_family):
        model += lpSum([var_x[f, d] for d in days]) == 1

    logger.info("Each day has 125-300 people")
    for d in tqdm(days):
        model += (
            lpSum(var_z[p, q, d] for p in range(125, 301) for q in range(125, 301)) == 1
        )

    logger.info("Knapsack constraints")
    for d in tqdm(days):
        model += lpSum(
            map_family_size[f] * var_x[f, d] for f in range(n_family)
        ) == lpSum(p * var_z[p, q, d] for p in range(125, 301) for q in range(125, 301))

    logger.info("Day-by-day constraints")
    for d in tqdm(days):
        for q in range(125, 301):
            model += lpSum(var_z[p, q, d] for p in range(125, 301)) == lpSum(
                var_z[q, p, min(d + 1, 100)] for p in range(125, 301)
            )

    logger.info("Objective function")
    model += lpSum(v * var_x[k] for k, v in map_var_x_cost.items()) + lpSum(
        v * var_z[k] for k, v in map_var_z_cost.items()
    )

    logger.info("Output LP file")
    model.writeLP("santa2019_pulp.lp")

    logger.info("optimization starts")

    solver = COIN_CMD(presolve=1, threads=8, maxSeconds=3600, msg=1)

    model.solve(solver)
コード例 #13
0
from pulp import LpMaximize, LpProblem, LpStatus, lpSum, LpVariable, PULP_CBC_CMD
import numpy as np

# Store the key figures
hardware = [
    "Notebook Büro 13\"", "Notebook Büro 14\"", "Notebook outdoor",
    "Mobiltelefon Büro", "Mobiltelefon Outdoor", "Mobiltelefon Heavy Duty",
    "Tablet Büro klein", "Tablet Büro groß", "Tablet outdoor klein",
    "Tablet outdoor groß"
]
max_amount = [205, 420, 450, 60, 157, 220, 620, 250, 540, 370]
weights = [2451, 2978, 3625, 717, 988, 1220, 1405, 1455, 1690, 1980]
benefits = [40, 35, 80, 30, 60, 65, 40, 40, 45, 68]

# Create the model
model = LpProblem(name="opt-transport", sense=LpMaximize)

# Initialize the decision variables
x = list({
    i: LpVariable(name=f"x{i}", lowBound=0, cat="Integer")
    for i in range(1, 21)
}.values())

# Add the constraints to the model
total_weight1 = np.dot(weights, x[:10])
total_weight2 = np.dot(weights, x[10:])
model += (total_weight1 <= 1100000 - 72400, "transporter1"
          )  # Upper limit for the loading weight of the first transporter
model += (total_weight2 <= 1100000 - 85700, "transporter2"
          )  # Upper limit for the loading weight of the second transporter
for i in range(10):
コード例 #14
0
 def _initialize_model(self):
     self.mdl = LpProblem("MultiTerminalCuts", LpMinimize)
コード例 #15
0
from pulp import LpMaximize, LpProblem, LpStatus, lpSum, LpVariable


# Problem #1

# minimize z = x + 2y
# st        2x + y <= 20 (red)
#          -4x + 5y <= 10 (blue)
#           -x + 2y >= -2 (yellow)
#          -x + 5y = 15 (green)
#           x >= 0
#           y >= 0

# create the model
model = LpProblem(name='small-problem', sense=LpMaximize)

# initialize decision variables
# default is negative infinity to positive infinity
# can set upper bound with upBound
# can specify category with cat='Continuous', 'Integer', 'Binary'
x = LpVariable(name='x', lowBound=0)
y = LpVariable(name='y', lowBound=0)

# now that we have create the decision variables x and y, we can use them 
# to create other PuLP objects
expression = 2*x + 4*y
type(expression)

constraint = 2*x + 4*y >= 8
type(constraint)
コード例 #16
0
bb = []
for i in range(15):
    bb.append(1)

c = np.array(aa)
A_ub = np.array(judge)  # 不等式约束
b_ub = np.array(bb)
# A_eq = np.array(select)                # 等式约束
# b_eq = np.array(aa)
r = linprog(c, A_ub=-A_ub, b_ub=-b_ub, bounds=(
    (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1)))
print(r)
'''

# Create a new model
m = LpProblem(name="MIP Model", sense=LpMinimize)

# Create variables
name_list = [
    'x1',
    'x2',
    'x3',
    'x4',
    'x5',
    'x6',
    'x7',
    'x8',
    'x9',
    'x10',
    'x11',
    'x12',
コード例 #17
0
ファイル: tnep.py プロジェクト: jbarberia/TNEP.py
    def solve(self, nets, parameters):
        """
        Resuelve el TNEP, devuelve un listado de PFNET Networks
        con la solucion

        parameters es un objeto del tipo Parameters
        """
        options = self.options

        # Create useful data structure
        ds = self._create_data_structure(nets, parameters)

        # Instanciate problem
        prob = LpProblem("TLEP", LpMinimize)

        # Variables
        w = {(i, bus_i): LpVariable(f'w_{i}_{bus_i}') for (i, bus_i) in ds["ref"]["bus"]}
        r = {(i, bus_i): LpVariable(f'r_{i}_{bus_i}', lowBound=0) for (i, bus_i) in ds["ref"]["bus"]}
        pg = {(i, bus_i, name): LpVariable(f'ps_{i}_{bus_i}_{name}') for (i, bus_i, name) in ds["ref"]["gen"]}
        f = {(i, k, m, ckt): LpVariable(f'f_{i, k, m, ckt}') for (i, k, m, ckt) in ds["ref"]["arcs"]}
        f_ = {(i, k, m, ckt): LpVariable(f'f_vio_{i, k, m, ckt}') for (i, k, m, ckt) in list(set(ds["ref"]["ne_arcs"] + ds["ref"]["mo_arcs"]))}
        phi_ = {(i, k, m, ckt): LpVariable(f'phi_{i, k, m, ckt}') for (i, k, m, ckt) in ds["ref"]["ne_arcs"]}
        x = {(k, m, ckt): LpVariable(f'x{k, m, ckt}', cat='Integer', lowBound=0, upBound=1) for (k, m, ckt) in ds["ref"]["ne_arc"]}

        # Objective
        prob += (sum(arc['cost'] * x[index] for (index, arc) in ds["ne_br"].items()) 
                 + options['penalty'] * sum(vio for vio in f_.values())
                 + options['ens'] * sum(ds['c_k'][i[0]] * ds['crf'] * l_shed for i, l_shed in r.items()))

        # Constraints
        for i, net in ds["nets"].items():
            for bus in net.buses: # Power Balance
                if not bus.is_in_service():
                    continue
                dp = 0.0

                for gen in bus.generators:
                    dp += pg[i, bus.number, gen.name] if bus.is_slack() else gen.P

                # Recorte de carga  
                dp += r[i, bus.number]

                for load in bus.loads:
                    dp -= load.P

                # Se podria optimizar esta parte
                for (j, k, m, ckt) in ds["ref"]["arcs"]: # Arcs es la union de lineas + lineas candidatos
                    if j == i:
                        if k == bus.number:
                            dp -= f[i, k, m, ckt]
                        if m == bus.number:
                            dp += f[i, k, m, ckt]

                prob += dp == 0

            for br in net.branches: # Lineas comunes y a monitorear
                if not br.is_in_service():
                    continue
                k, m, ckt = br.bus_k.number, br.bus_m.number, br.name
                prob += f[i, k, m, ckt] == -br.b*(w[i, k]-w[i, m])
            
            for bus in net.buses:
                if not bus.is_in_service():
                    continue

                if bus.is_slack():
                    prob += w[i, bus.number] == 0.
                prob += r[i, bus.number] <= sum(load.P for load in bus.loads if load.is_in_service()) * ds['load bus'].get(bus.number, 0.)

        for (i, k, m, ckt) in ds["ref"]["mo_arcs"]:
            rate = ds["mo_br"][(k, m, ckt)]['rate'] * options['rate factor']
            prob += f[i, k, m, ckt] <= rate + f_[i, k, m, ckt]
            prob += f[i, k, m, ckt] >= -rate - f_[i, k, m, ckt]
            prob += f_[i, k, m, ckt] >= 0
            prob += f_[i, k, m, ckt] <= 1.5
                
        for (i, k, m, ckt) in ds["ref"]["ne_arcs"]:
            br = ds["ne_br"][(k, m, ckt)]['br']
            rate = ds["ne_br"][(k, m, ckt)]['rate'] * options['rate factor']

            M = 1e3
            prob += f[i, k, m, ckt]+br.b*(w[i, k]-w[i, m]) <= (1-x[k, m, ckt])*M
            prob += f[i, k, m, ckt]+br.b*(w[i, k]-w[i, m]) >= -(1-x[k, m, ckt])*M

            prob += f[i, k, m, ckt] <= rate + f_[i, k, m, ckt]
            prob += f[i, k, m, ckt] >= -rate - f_[i, k, m, ckt]

            prob += f[i, k, m, ckt] <= x[k, m, ckt]*rate + phi_[i, k, m, ckt]
            prob += f[i, k, m, ckt] >= -x[k, m, ckt]*rate - phi_[i, k, m, ckt]

            prob += phi_[i, k, m, ckt] - f_[i, k, m, ckt] <= (1-x[k, m, ckt])*M
            prob += phi_[i, k, m, ckt] - f_[i, k, m, ckt] >= -(1-x[k, m, ckt])*M

            prob += phi_[i, k, m, ckt] <= x[k, m, ckt]*M
            prob += phi_[i, k, m, ckt] >= -x[k, m, ckt]*M
            prob += f_[i, k, m, ckt] >= 0

        prob.solve(
            PULP_CBC_CMD(
                mip=True,
                cuts=False,
                msg=1,
                options=['preprocess off presolve on gomoryCuts on'],
                )
            )
        
        # Get solution details
        ds["solution"] = {
            'objective': prob.objective.value(),
            'br_builded': sum(var.value() for var in x.values()),
            'br_cost': sum(x[index].value() * br['cost'] for (index, br) in ds["ne_br"].items()),
            'overload': options['penalty'] * sum(vio.value() for vio in f_.values()),
            'r_dem': sum(var.value() for var in r.values()),
            'ens': options['ens'] * sum(ds['c_k'][i[0]] * ds['crf'] * l_shed.value() for i, l_shed in r.items()),
            'status': prob.status
        }

        # Update Branches in Network
        for net in ds["nets"].values():
            build_branches = []
            for (k, m, ckt), build in x.items():
                if round(build.value()) > 0:
                    ref_br = (ds["ne_br"][(k, m, ckt)]['br'])
                    br = pfnet.Branch()
                    br.bus_k = net.get_bus_from_number(k)
                    br.bus_m = net.get_bus_from_number(m)
                    br.name = ref_br.name
                    br.g = ref_br.g
                    br.b = ref_br.b
                    br.ratingA = ref_br.ratingA
                    br.in_service = br.in_service
                    build_branches.append(br)

            net.add_branches(build_branches)
            net.update_properties()

        # Update load shed
        for i, i_bus in r.keys():
            net = ds["nets"][i]
            bus = net.get_bus_from_number(i_bus)
            if sum(l.P for l in bus.loads) > 0:
                load = bus.loads[0]
                load.P = load.P - r[i, i_bus].value()
                load.update_P_components(1, 0, 0)
            net.update_properties()        
        
        return list(ds["nets"].values()), ds["solution"]
コード例 #18
0
ファイル: diet.py プロジェクト: danielggu/pulp-examples
        'calcium': 2,
        'vitamin': 10
    },
    'b': {
        'protein': 45,
        'calcium': 1,
        'vitamin': 5
    }
}
q = {'protein': 700, 'calcium': 28, 'vitamin': 150}
c = {'a': 0.3, 'b': 0.35}

#### Problem statement

# Create a variable to store problem information
myProblem = LpProblem('Diet Problem', LpMinimize)
# Create a variable to store decision variables;
# they will be named as <name>_<index> by PuLP modeler
x = LpVariable.dicts(
    'food',  # name
    foods,  # array of indexes
    0  # lower bound
)
# Add objective function (must be added first)
myProblem += lpSum([c[i] * x[i] for i in foods])
# Add problem constraints
for j in nutrients:
    myProblem += lpSum([p[i][j] * x[i] for i in foods]) >= q[j]
# Note there is no need to include x[i] >= 0 constraint since x has been
# created with lower bound equals to zero
コード例 #19
0
    [0, 45, 0, 0, 150],
    [0, 0, 0, 0, 0],
]

# Decision variables
var: Dict = {}
for i in nodes:
    for j in nodes:
        if fork[i][j] == 1:
            var[(i, j)] = LpVariable(name=f"x{i}{j}", cat="Binary")
        else:
            continue
    var.update(var)

# Model
model = LpProblem("Shortest_path_problem", LpMinimize)

# Goal function
model += lpSum(var[x] * costs[x[0]][x[1]] for x in var.keys())

# Constrains
constrains_o: List = []
constrains_f: List = []

for node in nodes:
    for edge in var.keys():

        if edge[0] == node:
            constrains_o.append(var[edge])

        if edge[1] == node:
コード例 #20
0
random.seed(1)

#顧客の集合(顧客は主にjで表す)
D_SIZE = 30

#施設候補場所(施設は主にiで表す)
F_SIZE = 5

###問題設定
#施設建設にかかるコスト
f = np.random.randint(low=100, high=200, size=F_SIZE)
#各施設から顧客への輸送コスト
c = np.random.randint(low=10, high=100, size=(F_SIZE, D_SIZE))

p = LpProblem(name="FLP", sense=LpMinimize)

#施設iから顧客jに運ぶ製品の割合(どれだけ需要を満たすかの割合)
x = LpVariable.dict('x',
                    indexs=(range(F_SIZE), range(D_SIZE)),
                    lowBound=0,
                    upBound=1,
                    cat=LpContinuous)

#施設iを開設するか(1)しないか(0)を表す変数y
y = LpVariable.dict('y',
                    indexs=(range(F_SIZE)),
                    lowBound=0,
                    upBound=1,
                    cat=LpBinary)
コード例 #21
0
 def test_result_type(self):
     function_result = solve_linear_problem(LpProblem())
     self.assertTrue(isinstance(function_result, tuple))
コード例 #22
0
ファイル: exact.py プロジェクト: rwei5/region
    def fit_from_scipy_sparse_matrix(self, adj, attr, spatially_extensive_attr,
                                     threshold, solver="cbc",
                                     metric="euclidean"):
        """
        Solve the max-p-regions problem as MIP as described in [DAR2012]_.

        The resulting region labels are assigned to the instance's
        :attr:`labels_` attribute.

        Parameters
        ----------
        adj : class:`scipy.sparse.csr_matrix`
            Adjacency matrix representing the areas' contiguity relation.
        attr : :class:`numpy.ndarray`
            Array (number of areas x number of attributes) of areas' attributes
            relevant to clustering.
        spatially_extensive_attr : :class:`numpy.ndarray`
            Array (number of areas x number of attributes) of areas' attributes
            relevant to ensuring the threshold condition.
        threshold : numbers.Real or :class:`numpy.ndarray`
            The lower bound for a region's sum of spatially extensive
            attributes. The argument's type is numbers.Real if there is only
            one spatially extensive attribute per area, otherwise it is a
            one-dimensional array with as many entries as there are spatially
            extensive attributes per area.
        solver : {"cbc", "cplex", "glpk", "gurobi"}, default: "cbc"
            The solver to use. Unless the default solver is used, the user has
            to make sure that the specified solver is installed.

            * "cbc" - the Cbc (Coin-or branch and cut) solver
            * "cplex" - the CPLEX solver
            * "glpk" - the GLPK (GNU Linear Programming Kit) solver
            * "gurobi" - the Gurobi Optimizer

        metric : str or function, default: "euclidean"
            See the `metric` argument in
            :func:`region.util.get_metric_function`.
        """
        self.metric = get_metric_function(metric)
        check_solver(solver)

        prob = LpProblem("Max-p-Regions", LpMinimize)

        # Parameters of the optimization problem
        n_areas = adj.shape[0]
        I = list(range(n_areas))  # index for areas
        II = [(i, j)
              for i in I
              for j in I]
        II_upper_triangle = [(i, j) for i, j in II if i < j]
        # index of potential regions, called k in [DAR2012]_:
        K = range(n_areas)
        # index of contiguity order, called c in [DAR2012]_:
        O = range(n_areas)
        d = {(i, j): self.metric(attr[i].reshape(1, -1),
                                 attr[j].reshape(1, -1))
             for i, j in II_upper_triangle}
        h = 1 + floor(log10(sum(d[(i, j)] for i, j in II_upper_triangle)))

        # Decision variables
        t = LpVariable.dicts(
            "t",
            ((i, j) for i, j in II_upper_triangle),
            lowBound=0, upBound=1, cat=LpInteger)
        x = LpVariable.dicts(
            "x",
            ((i, k, o) for i in I for k in K for o in O),
            lowBound=0, upBound=1, cat=LpInteger)

        # Objective function
        # (1) in Duque et al. (2012): "The Max-p-Regions Problem"
        prob += -10**h * lpSum(x[i, k, 0] for k in K for i in I) \
            + lpSum(d[i, j] * t[i, j] for i, j in II_upper_triangle)

        # Constraints
        # (2) in Duque et al. (2012): "The Max-p-Regions Problem"
        for k in K:
            prob += lpSum(x[i, k, 0] for i in I) <= 1
        # (3) in Duque et al. (2012): "The Max-p-Regions Problem"
        for i in I:
            prob += lpSum(x[i, k, o] for k in K for o in O) == 1
        # (4) in Duque et al. (2012): "The Max-p-Regions Problem"
        for i in I:
            for k in K:
                for o in range(1, len(O)):
                    prob += x[i, k, o] <= lpSum(x[j, k, o-1]
                                                for j in neighbors(adj, i))
        # (5) in Duque et al. (2012): "The Max-p-Regions Problem"
        if isinstance(spatially_extensive_attr[I[0]], numbers.Real):
            for k in K:
                lhs = lpSum(x[i, k, o] * spatially_extensive_attr[i]
                            for i in I for o in O)
                prob += lhs >= threshold * lpSum(x[i, k, 0] for i in I)
        elif isinstance(spatially_extensive_attr[I[0]], collections.Iterable):
            for el in range(len(spatially_extensive_attr[I[0]])):
                for k in K:
                    lhs = lpSum(x[i, k, o] * spatially_extensive_attr[i][el]
                                for i in I for o in O)
                    if isinstance(threshold, numbers.Real):
                        rhs = threshold * lpSum(x[i, k, 0] for i in I)
                        prob += lhs >= rhs
                    elif isinstance(threshold, np.ndarray):
                        rhs = threshold[el] * lpSum(x[i, k, 0] for i in I)
                        prob += lhs >= rhs
        # (6) in Duque et al. (2012): "The Max-p-Regions Problem"
        for i, j in II_upper_triangle:
            for k in K:
                prob += t[i, j] >= \
                        lpSum(x[i, k, o] + x[j, k, o] for o in O) - 1
        # (7) in Duque et al. (2012): "The Max-p-Regions Problem"
        # already in LpVariable-definition
        # (8) in Duque et al. (2012): "The Max-p-Regions Problem"
        # already in LpVariable-definition

        # additional constraint for speedup (p. 405 in [DAR2012]_)
        for o in O:
            prob += x[I[0], K[0], o] == (1 if o == 0 else 0)

        # Solve the optimization problem
        solver = get_solver_instance(solver)
        print("start solving with", solver)
        prob.solve(solver=solver)
        print("solved")
        result = np.zeros(n_areas)
        for i in I:
            for k in K:
                for o in O:
                    if x[i, k, o].varValue == 1:
                        result[i] = k
        self.labels_ = result
        self.solver = solver
コード例 #23
0
 def test_result_subtypes_1(self):
     function_result = solve_linear_problem(LpProblem())
     self.assertTrue(isinstance(function_result[0], LpProblem))
     self.assertTrue(function_result[1] is None)
     self.assertTrue(isinstance(function_result[2], int))
コード例 #24
0
ファイル: reaction.py プロジェクト: samblau/mrnet
def solve_integer_programing(
    reactant_species: List[str],
    product_species: List[str],
    reactant_bonds: List[Bond],
    product_bonds: List[Bond],
    solver: str = "COIN_CMD",
    **kwargs,
) -> 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
        solver: pulp solver to solve the integer linear programming problem. Different
            solver may give different result if there is degeneracy in the problem,
            e.g. symmetry in molecules. So, to give deterministic result, the default
            solver is set to `COIN_CMD`. If this solver is unavailable on your machine,
            try a different one (e.g. PULP_CBC_CMD). For a full list of solvers, see
            https://coin-or.github.io/pulp/guides/how_to_configure_solvers.html
        kwargs: additional keyword arguments passed to the pulp solver.

    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
    """
    solver = _check_pulp_solver(solver)

    # default msg to False to avoid printing solver info
    msg = kwargs.pop("msg", False)
    solver = pulp.getSolver(solver, msg=msg, **kwargs)

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

    # init model and variables
    model = LpProblem(name="Reaction_Atom_Mapping", sense=LpMinimize)

    y_vars = {(i, k): LpVariable(cat=LpBinary, name=f"y_{i}_{k}")
              for i in atoms for k in atoms}

    alpha_vars = {(i, j, k, l): LpVariable(cat=LpBinary,
                                           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 += lpSum([y_vars[(i, k)] for k in atoms]) == 1
    for k in atoms:
        model += lpSum([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 = lpSum(1 - lpSum(alpha_vars[(i, j, k, l)]
                           for (k, l) in product_bonds)
                 for (i, j) in reactant_bonds)
    obj2 = lpSum(1 - lpSum(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.setObjective(obj)
        model.solve(solver)
    except Exception:
        raise ReactionMappingError("Failed solving integer programming.")

    objective = pulp.value(model.objective)  # type: int
    if objective is None:
        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 pulp.value(v) == 1:
            r2p_mapping[i] = k
            p2r_mapping[k] = i

    return objective, r2p_mapping, p2r_mapping
コード例 #25
0
def BranchAndBound(T,
                   CONSTRAINTS,
                   VARIABLES,
                   OBJ,
                   MAT,
                   RHS,
                   branch_strategy=MOST_FRACTIONAL,
                   search_strategy=DEPTH_FIRST,
                   complete_enumeration=False,
                   display_interval=None,
                   binary_vars=True):

    if T.get_layout() == 'dot2tex':
        cluster_attrs = {
            'name': 'Key',
            'label': r'\text{Key}',
            'fontsize': '12'
        }
        T.add_node('C',
                   label=r'\text{Candidate}',
                   style='filled',
                   color='yellow',
                   fillcolor='yellow')
        T.add_node('I',
                   label=r'\text{Infeasible}',
                   style='filled',
                   color='orange',
                   fillcolor='orange')
        T.add_node('S',
                   label=r'\text{Solution}',
                   style='filled',
                   color='lightblue',
                   fillcolor='lightblue')
        T.add_node('P',
                   label=r'\text{Pruned}',
                   style='filled',
                   color='red',
                   fillcolor='red')
        T.add_node('PC',
                   label=r'\text{Pruned}$\\ $\text{Candidate}',
                   style='filled',
                   color='red',
                   fillcolor='yellow')
    else:
        cluster_attrs = {'name': 'Key', 'label': 'Key', 'fontsize': '12'}
        T.add_node('C',
                   label='Candidate',
                   style='filled',
                   color='yellow',
                   fillcolor='yellow')
        T.add_node('I',
                   label='Infeasible',
                   style='filled',
                   color='orange',
                   fillcolor='orange')
        T.add_node('S',
                   label='Solution',
                   style='filled',
                   color='lightblue',
                   fillcolor='lightblue')
        T.add_node('P',
                   label='Pruned',
                   style='filled',
                   color='red',
                   fillcolor='red')
        T.add_node('PC',
                   label='Pruned \n Candidate',
                   style='filled',
                   color='red',
                   fillcolor='yellow')
    T.add_edge('C', 'I', style='invisible', arrowhead='none')
    T.add_edge('I', 'S', style='invisible', arrowhead='none')
    T.add_edge('S', 'P', style='invisible', arrowhead='none')
    T.add_edge('P', 'PC', style='invisible', arrowhead='none')
    T.create_cluster(['C', 'I', 'S', 'P', 'PC'], cluster_attrs)
    # The initial lower bound
    LB = -INFINITY
    # The number of LP's solved, and the number of nodes solved
    node_count = 1
    iter_count = 0
    lp_count = 0

    if binary_vars:
        var = LpVariable.dicts("", VARIABLES, 0, 1)
    else:
        var = LpVariable.dicts("", VARIABLES)

    numCons = len(CONSTRAINTS)
    numVars = len(VARIABLES)
    # List of incumbent solution variable values
    opt = dict([(i, 0) for i in VARIABLES])
    pseudo_u = dict((i, (OBJ[i], 0)) for i in VARIABLES)
    pseudo_d = dict((i, (OBJ[i], 0)) for i in VARIABLES)
    print("===========================================")
    print("Starting Branch and Bound")
    if branch_strategy == MOST_FRACTIONAL:
        print("Most fractional variable")
    elif branch_strategy == FIXED_BRANCHING:
        print("Fixed order")
    elif branch_strategy == PSEUDOCOST_BRANCHING:
        print("Pseudocost brancing")
    else:
        print("Unknown branching strategy %s" % branch_strategy)
    if search_strategy == DEPTH_FIRST:
        print("Depth first search strategy")
    elif search_strategy == BEST_FIRST:
        print("Best first search strategy")
    else:
        print("Unknown search strategy %s" % search_strategy)
    print("===========================================")
    # List of candidate nodes
    Q = PriorityQueue()
    # The current tree depth
    cur_depth = 0
    cur_index = 0
    # Timer
    timer = time.time()
    Q.push(0, -INFINITY, (0, None, None, None, None, None, None))
    # Branch and Bound Loop
    while not Q.isEmpty():
        infeasible = False
        integer_solution = False
        (cur_index, parent, relax, branch_var, branch_var_value, sense,
         rhs) = Q.pop()
        if cur_index is not 0:
            cur_depth = T.get_node_attr(parent, 'level') + 1
        else:
            cur_depth = 0
        print("")
        print("----------------------------------------------------")
        print("")
        if LB > -INFINITY:
            print("Node: %s, Depth: %s, LB: %s" % (cur_index, cur_depth, LB))
        else:
            print("Node: %s, Depth: %s, LB: %s" %
                  (cur_index, cur_depth, "None"))
        if relax is not None and relax <= LB:
            print("Node pruned immediately by bound")
            T.set_node_attr(parent, 'color', 'red')
            continue
        # ====================================
        #    LP Relaxation
        # ====================================
        # Compute lower bound by LP relaxation
        prob = LpProblem("relax", LpMaximize)
        prob += lpSum([OBJ[i] * var[i] for i in VARIABLES]), "Objective"
        for j in range(numCons):
            prob += (lpSum([MAT[i][j] * var[i]
                            for i in VARIABLES]) <= RHS[j], CONSTRAINTS[j])
        # Fix all prescribed variables
        branch_vars = []
        if cur_index is not 0:
            sys.stdout.write("Branching variables: ")
            branch_vars.append(branch_var)
            if sense == '>=':
                prob += LpConstraint(lpSum(var[branch_var]) >= rhs)
            else:
                prob += LpConstraint(lpSum(var[branch_var]) <= rhs)
            print(branch_var, end=' ')
            pred = parent
            while not str(pred) == '0':
                pred_branch_var = T.get_node_attr(pred, 'branch_var')
                pred_rhs = T.get_node_attr(pred, 'rhs')
                pred_sense = T.get_node_attr(pred, 'sense')
                if pred_sense == '<=':
                    prob += LpConstraint(
                        lpSum(var[pred_branch_var]) <= pred_rhs)
                else:
                    prob += LpConstraint(
                        lpSum(var[pred_branch_var]) >= pred_rhs)
                print(pred_branch_var, end=' ')
                branch_vars.append(pred_branch_var)
                pred = T.get_node_attr(pred, 'parent')
            print()
        # Solve the LP relaxation
        prob.solve()
        lp_count = lp_count + 1
        # Check infeasibility
        infeasible = LpStatus[prob.status] == "Infeasible" or \
            LpStatus[prob.status] == "Undefined"
        # Print status
        if infeasible:
            print("LP Solved, status: Infeasible")
        else:
            print("LP Solved, status: %s, obj: %s" %
                  (LpStatus[prob.status], value(prob.objective)))
        if (LpStatus[prob.status] == "Optimal"):
            relax = value(prob.objective)
            # Update pseudocost
            if branch_var != None:
                if sense == '<=':
                    pseudo_d[branch_var] = (old_div(
                        (pseudo_d[branch_var][0] * pseudo_d[branch_var][1] +
                         old_div((T.get_node_attr(parent, 'obj') - relax),
                                 (branch_var_value - rhs))),
                        (pseudo_d[branch_var][1] + 1)),
                                            pseudo_d[branch_var][1] + 1)
                else:
                    pseudo_u[branch_var] = (old_div(
                        (pseudo_u[branch_var][0] * pseudo_d[branch_var][1] +
                         old_div((T.get_node_attr(parent, 'obj') - relax),
                                 (rhs - branch_var_value))),
                        (pseudo_u[branch_var][1] + 1)),
                                            pseudo_u[branch_var][1] + 1)
            var_values = dict([(i, var[i].varValue) for i in VARIABLES])
            integer_solution = 1
            for i in VARIABLES:
                if (abs(round(var_values[i]) - var_values[i]) > .001):
                    integer_solution = 0
                    break
            # Determine integer_infeasibility_count and
            # Integer_infeasibility_sum for scatterplot and such
            integer_infeasibility_count = 0
            integer_infeasibility_sum = 0.0
            for i in VARIABLES:
                if (var_values[i] not in set([0, 1])):
                    integer_infeasibility_count += 1
                    integer_infeasibility_sum += min(
                        [var_values[i], 1.0 - var_values[i]])
            if (integer_solution and relax > LB):
                LB = relax
                for i in VARIABLES:
                    # These two have different data structures first one
                    # list, second one dictionary
                    opt[i] = var_values[i]
                print("New best solution found, objective: %s" % relax)
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" % (i, var_values[i]))
            elif (integer_solution and relax <= LB):
                print("New integer solution found, objective: %s" % relax)
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" % (i, var_values[i]))
            else:
                print("Fractional solution:")
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" % (i, var_values[i]))
            # For complete enumeration
            if complete_enumeration:
                relax = LB - 1
        else:
            relax = INFINITY
        if integer_solution:
            print("Integer solution")
            BBstatus = 'S'
            status = 'integer'
            color = 'lightblue'
        elif infeasible:
            print("Infeasible node")
            BBstatus = 'I'
            status = 'infeasible'
            color = 'orange'
        elif not complete_enumeration and relax <= LB:
            print("Node pruned by bound (obj: %s, UB: %s)" % (relax, LB))
            BBstatus = 'P'
            status = 'fathomed'
            color = 'red'
        elif cur_depth >= numVars:
            print("Reached a leaf")
            BBstatus = 'fathomed'
            status = 'L'
        else:
            BBstatus = 'C'
            status = 'candidate'
            color = 'yellow'
        if BBstatus is 'I':
            if T.get_layout() == 'dot2tex':
                label = '\text{I}'
            else:
                label = 'I'
        else:
            label = "%.1f" % relax
        if iter_count == 0:
            if status is not 'candidate':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            if status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before ' +
                          'first incumbent.')
            T.AddOrUpdateNode(0,
                              None,
                              None,
                              'candidate',
                              relax,
                              integer_infeasibility_count,
                              integer_infeasibility_sum,
                              label=label,
                              obj=relax,
                              color=color,
                              style='filled',
                              fillcolor=color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = -1
                T._new_integer_solution = True
#           #Currently broken
#           if ETREE_INSTALLED and T.attr['display'] == 'svg':
#               T.write_as_svg(filename = "node%d" % iter_count,
#                                 nextfile = "node%d" % (iter_count + 1),
#                                 highlight = cur_index)
        else:
            _direction = {'<=': 'L', '>=': 'R'}
            if status is 'infeasible':
                integer_infeasibility_count = T.get_node_attr(
                    parent, 'integer_infeasibility_count')
                integer_infeasibility_sum = T.get_node_attr(
                    parent, 'integer_infeasibility_sum')
                relax = T.get_node_attr(parent, 'lp_bound')
            elif status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before' +
                          ' first incumbent.')
                    print('  This may indicate an error in the input file.')
            elif status is 'integer':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            T.AddOrUpdateNode(cur_index,
                              parent,
                              _direction[sense],
                              status,
                              relax,
                              integer_infeasibility_count,
                              integer_infeasibility_sum,
                              branch_var=branch_var,
                              branch_var_value=var_values[branch_var],
                              sense=sense,
                              rhs=rhs,
                              obj=relax,
                              color=color,
                              style='filled',
                              label=label,
                              fillcolor=color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = parent
                T._new_integer_solution = True
            # Currently Broken


#           if ETREE_INSTALLED and T.attr['display'] == 'svg':
#               T.write_as_svg(filename = "node%d" % iter_count,
#                                 prevfile = "node%d" % (iter_count - 1),
#                                 nextfile = "node%d" % (iter_count + 1),
#                                 highlight = cur_index)
            if T.get_layout() == 'dot2tex':
                _dot2tex_label = {'>=': ' \geq ', '<=': ' \leq '}
                T.set_edge_attr(
                    parent, cur_index, 'label',
                    str(branch_var) + _dot2tex_label[sense] + str(rhs))
            else:
                T.set_edge_attr(parent, cur_index, 'label',
                                str(branch_var) + sense + str(rhs))
        iter_count += 1
        if BBstatus == 'C':
            # Branching:
            # Choose a variable for branching
            branching_var = None
            if branch_strategy == FIXED_BRANCHING:
                # fixed order
                for i in VARIABLES:
                    frac = min(var[i].varValue - math.floor(var[i].varValue),
                               math.ceil(var[i].varValue) - var[i].varValue)
                    if (frac > 0):
                        min_frac = frac
                        branching_var = i
                        # TODO(aykut): understand this break
                        break
            elif branch_strategy == MOST_FRACTIONAL:
                # most fractional variable
                min_frac = -1
                for i in VARIABLES:
                    frac = min(var[i].varValue - math.floor(var[i].varValue),
                               math.ceil(var[i].varValue) - var[i].varValue)
                    if (frac > min_frac):
                        min_frac = frac
                        branching_var = i
            elif branch_strategy == PSEUDOCOST_BRANCHING:
                scores = {}
                for i in VARIABLES:
                    # find the fractional solutions
                    if (var[i].varValue - math.floor(var[i].varValue)) != 0:
                        scores[i] = min(pseudo_u[i][0] * (1 - var[i].varValue),
                                        pseudo_d[i][0] * var[i].varValue)
                    # sort the dictionary by value
                branching_var = sorted(list(scores.items()),
                                       key=lambda x: x[1])[-1][0]
            else:
                print("Unknown branching strategy %s" % branch_strategy)
                exit()
            if branching_var is not None:
                print("Branching on variable %s" % branching_var)
            # Create new nodes
            if search_strategy == DEPTH_FIRST:
                priority = (-cur_depth - 1, -cur_depth - 1)
            elif search_strategy == BEST_FIRST:
                priority = (-relax, -relax)
            elif search_strategy == BEST_ESTIMATE:
                priority = (-relax - pseudo_d[branching_var][0] *
                            (math.floor(var[branching_var].varValue) -
                             var[branching_var].varValue),
                            -relax + pseudo_u[branching_var][0] *
                            (math.ceil(var[branching_var].varValue) -
                             var[branching_var].varValue))
            node_count += 1
            Q.push(node_count, priority[0],
                   (node_count, cur_index, relax, branching_var,
                    var_values[branching_var], '<=',
                    math.floor(var[branching_var].varValue)))
            node_count += 1
            Q.push(node_count, priority[1],
                   (node_count, cur_index, relax, branching_var,
                    var_values[branching_var], '>=',
                    math.ceil(var[branching_var].varValue)))
            T.set_node_attr(cur_index, color, 'green')
        if T.root is not None and display_interval is not None and\
                iter_count % display_interval == 0:
            T.display(count=iter_count)

    timer = int(math.ceil((time.time() - timer) * 1000))
    print("")
    print("===========================================")
    print("Branch and bound completed in %sms" % timer)
    print("Strategy: %s" % branch_strategy)
    if complete_enumeration:
        print("Complete enumeration")
    print("%s nodes visited " % node_count)
    print("%s LP's solved" % lp_count)
    print("===========================================")
    print("Optimal solution")
    # print optimal solution
    for i in sorted(VARIABLES):
        if opt[i] > 0:
            print("%s = %s" % (i, opt[i]))
    print("Objective function value")
    print(LB)
    print("===========================================")
    if T.attr['display'] is not 'off':
        T.display(count=iter_count)
    T._lp_count = lp_count
    return opt, LB
コード例 #26
0
def solve_sudoku(initial_value_constraints: InitialValueConstraints):
    
    # --- set up Sudoku problem
    # The Vals, Rows and Cols sequences all follow this form
    Vals = [1,2,3,4,5,6,7,8,9]
    Rows = [0,1,2,3,4,5,6,7,8]
    Cols = [0,1,2,3,4,5,6,7,8]
    
    # The boxes list is created, with the row and column index of each square in each box
    Boxes =[]
    for i in range(3):
        for j in range(3):
            Boxes += [[(Rows[3*i+k],Cols[3*j+l]) for k in range(3) for l in range(3)]]
    
    # The prob variable is created to contain the problem data        
    prob = LpProblem("Sudoku Problem",LpMinimize)
    
    # The problem variables are created
    choices = LpVariable.dicts("Choice",(Vals,Rows,Cols),0,1,LpInteger)
    
    # The arbitrary objective function is added
    prob += 0, "Arbitrary Objective Function"
    
    # A constraint ensuring that only one value can be in each square is created
    for r in Rows:
        for c in Cols:
            prob += lpSum([choices[v][r][c] for v in Vals]) == 1, ""
    
    # The row, column and box constraints are added for each value
    for v in Vals:
        for r in Rows:
            prob += lpSum([choices[v][r][c] for c in Cols]) == 1,""
            
        for c in Cols:
            prob += lpSum([choices[v][r][c] for r in Rows]) == 1,""
    
        for b in Boxes:
            prob += lpSum([choices[v][r][c] for (r,c) in b]) == 1,""

    # add initial values if needed
    if initial_value_constraints != None and len(initial_value_constraints.initial_values) != 0:
        for initial_value_constraint in initial_value_constraints.initial_values:
            prob += choices[initial_value_constraint.value][initial_value_constraint.row_index][initial_value_constraint.column_index] == 1,""
            
    # --- solve sudoku with linear programing
    solution_status = prob.solve()

    if solution_status == -1:

        return SudokuSolution(solved = solution_status)
    elif solution_status == 1:

        solved_grid = [[None]*9 for i in range(9)]
        
        for row in Rows:
            for column in Cols:
                for val in Vals:
                    if value(choices[val][row][column]) == 1:
                        solved_grid[row][column] = val

        return SudokuSolution(solved = solution_status,
                              solution = solved_grid)
res1 = p.dot(a).dot(Q.transpose())
print(res1)
res2 = p.dot(a).dot(Q1.transpose())
print(res2)

data3 = pd.DataFrame([[-4, -5, -1, 6], [-1, 0, -3, 5], [-3, 1, -5, 5], [-8, -7, -6, 0]],
                     columns=['B1', 'B2', 'B3', 'B4'], index=['A1', 'A2', 'A3', 'A4'])
k = 1000
for i in range(4):
    g = data3['B' + str(i + 1)].sum()
    if k > g:
        k = g
        f = i + 1
data3.drop(columns='B3')

model = LpProblem(name="small-problem", sense=LpMinimize)
x = {i: LpVariable(name=f"x{i}", lowBound=0) for i in range(1, 5)}
model += (
    data3.loc['A1'][0] * x[1] + data3.loc['A2'][0] * x[2] + data3.loc['A3'][0] * x[3] +
    data3.loc['A4'][0] * x[4] >= -1,
    "A1")
model += (
    data3.loc['A1'][1] * x[1] + data3.loc['A2'][1] * x[2] + data3.loc['A3'][1] * x[3] +
    data3.loc['A4'][1] * x[4] >= -1,
    "A2")
model += (
    data3.loc['A1'][2] * x[1] + data3.loc['A2'][2] * x[2] + data3.loc['A3'][2] * x[3] +
    data3.loc['A4'][2] * x[4] >= -1,
    "A3")
model += -x[1] - x[2] - x[3] - x[4]
status = model.solve()
# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
from pulp import LpProblem, LpMaximize, LpVariable

# Initialize Class
model = LpProblem("Maximize Bakery Profits", LpMaximize)

# Define Decision Variables
A = LpVariable('A', lowBound=0, cat='Integer')
B = LpVariable('B', lowBound=0, cat='Integer')


# Define Objective Function
model += 20 * A + 40 * B

# Define Constraints
model += 0.5 * A + 1 * B <= 30
model += 1 * A + 2.5 * B <= 60
model += 1 * A + 2 * B <= 22


# Solve Model
model.solve()
print("Produce {} Cake A".format(A.varValue))
print("Produce {} Cake B".format(B.varValue))
コード例 #29
0
from pulp import LpProblem, LpVariable, LpMaximize, LpStatus, LpInteger, LpAffineExpression

if __name__ == "__main__":
    #LpMaximize means maximize the objective
    problem = LpProblem("counting to seven", LpMaximize)
    objects = {"stele" : (20, 400),"codex" : (10, 3000),"manuscript" : (5, 2900),"tablet" : (3, 50),"slab" : (2, 10),"plaque" : (8, 150) }

    exc1 = False
    exc2 = True
    
    #we declare a new variable named "counter" with a lower limit of 0,
    #upper limit of 10, and type Integer
    varTab = {}
    for obj in objects:
        varTab[obj] = LpVariable(obj, 0, 1, LpInteger)
    #var1 = LpVariable("counter", 0, 10, LpInteger)

    #the first line added to the problem is the objective
    objective = []
    for obj, (wt, chs) in objects.items():
        print varTab[obj], chs
        objective.append( (varTab[obj], chs) )
    problem += LpAffineExpression(objective)
    
    constraint = []
    for obj, (wt, chs) in objects.items():
        constraint.append( (varTab[obj], wt) )
    problem += ( LpAffineExpression(constraint) <= 25)
    
    if exc1:
        problem += varTab["manuscript"] + varTab["codex"] <= 1
コード例 #30
0
def runtimetable_with_rooms_two_step(
        STUDENTS, SUBJECTS, TIMES, day, DAYS, TEACHERS, SUBJECTMAPPING,
        REPEATS, TEACHERMAPPING, TUTORAVAILABILITY, maxclasssize, minclasssize,
        ROOMS, PROJECTORS, PROJECTORROOMS, numroomsprojector,
        NONPREFERREDTIMES, CAPACITIES):
    '''
    Run the timetabling process and input into the database.

    This process calls the CBCSolver using the PuLP package and then adds the classes to the database.


    :param STUDENTS: should be an array of student names
    :param SUBJECTS: should be an array of subject codes
    :param TIMES: an array of strings representing possible timeslots
    :param day:
    :param DAYS: the days corresponding to the timeslots above
    :param TEACHERS: an array of the names of the tutors
    :param SUBJECTMAPPING: This is a dictionary representing the subjects
                            each tutor is taking
    :param REPEATS: A dictionary of how many repeats each subject has
    :param TEACHERMAPPING: A dictionary of what subject each tutor teachers
    :param TUTORAVAILABILITY:
    :param maxclasssize: An integer representing the maximum class size
    :param minclasssize: An integer representing the minimum class size
    :param nrooms: An integer representing the max allowable concurrent classes
    :param CAPACITIES: A dictionary indexed by room name with the amount of people that each room can contain
    :return: A string representing model status.
    '''
    print("Running solver")
    model = LpProblem('Timetabling', LpMinimize)
    # Create Variables
    print("Creating Variables")
    app.logger.info('Assignment Variables')
    assign_vars = LpVariable.dicts("StudentVariables",
                                   [(i, j, k, m) for m in TEACHERS
                                    for j in TEACHERMAPPING[m]
                                    for i in SUBJECTMAPPING[j]
                                    for k in TIMES], 0, 1, LpBinary)
    app.logger.info('Subject Variables')
    subject_vars = LpVariable.dicts("SubjectVariables",
                                    [(j, k, m) for m in TEACHERS
                                     for j in TEACHERMAPPING[m]
                                     for k in TIMES], 0, 1, LpBinary)

    # c
    app.logger.info('9:30 classes')
    num930classes = LpVariable.dicts("930Classes", [(i) for i in TIMES],
                                     lowBound=0,
                                     cat=LpInteger)
    # w
    app.logger.info('Days for teachers')
    daysforteachers = LpVariable.dicts("numdaysforteachers",
                                       [(i, j) for i in TEACHERS
                                        for j in range(len(DAYS))], 0, 1,
                                       LpBinary)
    # p
    daysforteacherssum = LpVariable.dicts("numdaysforteacherssum",
                                          [(i) for i in TEACHERS],
                                          0,
                                          cat=LpInteger)
    # variables for student clashes
    studenttime = LpVariable.dicts("StudentTime",
                                   [(i, j) for i in STUDENTS for j in TIMES],
                                   lowBound=0,
                                   upBound=1,
                                   cat=LpBinary)
    studentsum = LpVariable.dicts("StudentSum", [(i) for i in STUDENTS],
                                  0,
                                  cat=LpInteger)

    projectortime = LpVariable.dicts("ProjectorSum", [(k) for k in TIMES],
                                     cat=LpInteger)
    projectorpositive = LpVariable.dicts("ProjectorPositivePart",
                                         [(k) for k in TIMES],
                                         0,
                                         cat=LpInteger)
    # Count the days that a teacher is rostered on. Make it bigger than a small number times the sum
    # for that particular day.
    for m in TEACHERS:
        app.logger.info('Counting Teachers for ' + m)
        for d in range(len(day)):
            model += daysforteachers[(
                m, d)] >= 0.1 * lpSum(subject_vars[(j, k, m)]
                                      for j in TEACHERMAPPING[m]
                                      for k in DAYS[day[d]])
            model += daysforteachers[(m, d)] <= lpSum(
                subject_vars[(j, k, m)] for j in TEACHERMAPPING[m]
                for k in DAYS[day[d]])
    for m in TEACHERS:
        model += daysforteacherssum[(m)] == lpSum(daysforteachers[(m, d)]
                                                  for d in range(len(day)))

    print("Constraining tutor availability")
    # This bit of code puts in the constraints for the tutor availability.
    # It reads in the 0-1 matrix of tutor availability and constrains that no classes
    # can be scheduled when a tutor is not available.
    # The last column of the availabilities is the tutor identifying number, hence why we have
    # used a somewhat convoluted idea down here.
    for m in TEACHERS:
        for k in TIMES:
            if k not in TUTORAVAILABILITY[m]:
                model += lpSum(subject_vars[(j, k, m)]
                               for j in TEACHERMAPPING[m]) == 0

    # Constraints on subjects for each students
    print("Constraining student subjects")
    for m in TEACHERS:
        for j in TEACHERMAPPING[m]:
            for i in SUBJECTMAPPING[j]:
                model += lpSum(assign_vars[(i, j, k, m)] for k in TIMES) == 1

    # This code means that students cannot attend a tute when a tute is not running
    # But can not attend a tute if they attend a repeat.
    for m in TEACHERS:
        for j in TEACHERMAPPING[m]:
            for i in SUBJECTMAPPING[j]:
                for k in TIMES:
                    model += assign_vars[(i, j, k, m)] <= subject_vars[(j, k,
                                                                        m)]

    # Constraints on which tutor can take each class
    # This goes through each list and either constrains it to 1 or 0 depending if
    # the teacher needs to teach that particular class.
    print("Constraining tutor classes")
    for m in TEACHERS:
        for j in TEACHERMAPPING[m]:
            model += lpSum(subject_vars[(j, k, m)]
                           for k in TIMES) == REPEATS[j]

    # General Constraints on Rooms etc.
    print("Constraining times")
    # For each time cannot exceed number of rooms
    for k in TIMES:
        model += lpSum(subject_vars[(j, k, m)] for m in TEACHERS
                       for j in TEACHERMAPPING[m]) <= len(ROOMS)

    #Number of rooms that need projectors less than the number that have projectors. Want to make this a soft constraint so
    #that it will not affect the feasibility of the model. We'll have a large penalty for exceeding the number of rooms with
    #projectors.
    for k in TIMES:
        model += projectortime[(
            k)] == (lpSum(subject_vars[(j, k, m)] for m in TEACHERS
                          for j in TEACHERMAPPING[m] if j in PROJECTORS) -
                    numroomsprojector)
        model += projectorpositive[(k)] >= projectortime[(k)]
        model += projectorpositive[(k)] >= 0

    # Teachers can only teach one class at a time
    for k in TIMES:
        for m in TEACHERS:
            model += lpSum(subject_vars[(j, k, m)]
                           for j in TEACHERMAPPING[m]) <= 1
    print("Constraint: Minimize student clashes")
    # STUDENT CLASHES
    for i in STUDENTS:
        for k in TIMES:
            model += studenttime[(i, k)] <= lpSum(
                assign_vars[(i, j, k, m)] for m in TEACHERS
                for j in TEACHERMAPPING[m] if i in SUBJECTMAPPING[j]) / 2
            model += studenttime[(i, k)] >= 0.3 * (0.5 * lpSum(
                assign_vars[(i, j, k, m)] for m in TEACHERS
                for j in TEACHERMAPPING[m] if i in SUBJECTMAPPING[j]) - 0.5)
    for i in STUDENTS:
        model += studentsum[(i)] == lpSum(studenttime[(i, k)] for k in TIMES)

    # This minimizes the number of 9:30 classes.
    for i in TIMES:
        if i in NONPREFERREDTIMES:
            model += num930classes[(i)] == lpSum(subject_vars[(j, i, m)]
                                                 for m in TEACHERS
                                                 for j in TEACHERMAPPING[m])

        else:
            model += num930classes[(i)] == 0

    print("Setting objective function")

    # Class size constraint
    for m in TEACHERS:
        for j in TEACHERMAPPING[m]:
            for k in TIMES:
                model += lpSum(
                    assign_vars[(i, j, k, m)]
                    for i in SUBJECTMAPPING[j]) >= minclasssize * subject_vars[
                        (j, k, m)]
                model += lpSum(assign_vars[(i, j, k, m)]
                               for i in SUBJECTMAPPING[j]) <= maxclasssize

    # Solving the model
    model += (100 * lpSum(studentsum[(i)] for i in STUDENTS) +
              lpSum(num930classes[(i)]
                    for i in TIMES) + 500 * lpSum(daysforteacherssum[(m)]
                                                  for m in TEACHERS) +
              5000 * lpSum(projectorpositive[(k)] for k in TIMES))
    print("Solving Model")
    model.solve()
    print("Status:", LpStatus[model.status])
    print("Completed Timetable")

    classpop = {}
    for m in TEACHERS:
        for j in TEACHERMAPPING[m]:
            for k in TIMES:
                if subject_vars[(j, k, m)].varValue == 1:
                    classpop[(j, k, m)] = sum(assign_vars[(i, j, k,
                                                           m)].varValue
                                              for i in SUBJECTMAPPING[j])

    if LpStatus[model.status] == "Optimal":
        print("Allocating Rooms")
        model2 = LpProblem('RoomAllocation', LpMinimize)
        print("Defining Variables")
        subject_vars_rooms = LpVariable.dicts(
            "SubjectVariablesRooms",
            [(j, k, m, n) for m in TEACHERS for j in TEACHERMAPPING[m]
             for k in TIMES
             for n in ROOMS if (j, k, m) in classpop.keys()], 0, 1, LpBinary)

        teacher_number_rooms = LpVariable.dicts("NumberRoomsTeacher",
                                                [(m, n) for m in TEACHERS
                                                 for n in ROOMS], 0, 1,
                                                LpBinary)
        teacher_number_rooms_sum = LpVariable.dicts("NumberRoomsTeacherSum",
                                                    [(m) for m in TEACHERS], 0)

        projector_rooms_sum = LpVariable.dicts("ProjectorRooms",
                                               [(j) for j in PROJECTORS])

        populationovershoot = LpVariable.dicts("PopulationOvershoot",
                                               [(k, n) for k in TIMES
                                                for n in ROOMS])

        poppositive = LpVariable.dicts("PopulationPositivePart",
                                       [(k, n) for k in TIMES for n in ROOMS])

        print("Minimizing number of rooms for each tutor")
        for m in TEACHERS:
            for n in ROOMS:
                model2 += teacher_number_rooms[(m, n)] >= 0.01 * lpSum(
                    subject_vars_rooms[(j, k, m, n)] for j in TEACHERMAPPING[m]
                    for k in TIMES if (j, k, m) in classpop.keys())
                model2 += teacher_number_rooms[(m, n)] <= lpSum(
                    subject_vars_rooms[(j, k, m, n)] for j in TEACHERMAPPING[m]
                    for k in TIMES if (j, k, m) in classpop.keys())
        for m in TEACHERS:
            model2 += teacher_number_rooms_sum[(m)] == lpSum(
                teacher_number_rooms[(m, n)] for n in ROOMS)

        # Rooms must be allocated at times when the classes are running
        print("Constraining Times")
        for m in TEACHERS:
            for j in TEACHERMAPPING[m]:
                for k in TIMES:
                    if (j, k, m) in classpop.keys():
                        model2 += lpSum(
                            subject_vars_rooms[(j, k, m, n)]
                            for n in ROOMS) == subject_vars[(j, k, m)].varValue

        for m in TEACHERS:
            for j in TEACHERMAPPING[m]:
                if j in PROJECTORS:
                    model2 += projector_rooms_sum[(j)] == lpSum(
                        subject_vars_rooms[(j, k, m, n)]
                        for n in PROJECTORROOMS for k in TIMES
                        if (j, k, m) in classpop.keys())

        print("Ensuring Uniqueness")
        # Can only have one class in each room at a time.
        for k in TIMES:
            for n in ROOMS:
                model2 += lpSum(subject_vars_rooms[(j, k, m, n)]
                                for m in TEACHERS for j in TEACHERMAPPING[m]
                                if (j, k, m) in classpop.keys()) <= 1

        print("Accomodating Capacities")

        for k in TIMES:

            for n in ROOMS:

                model2 += populationovershoot[(k, n)] == (lpSum(
                    classpop[(j, k, m)] * subject_vars_rooms[(j, k, m, n)]
                    for m in TEACHERS for j in TEACHERMAPPING[m]
                    if (j, k, m) in classpop.keys()) - CAPACITIES[n])
                #print("Second")
                model2 += poppositive[(k, n)] >= populationovershoot[(k, n)]
                model2 += poppositive[(k, n)] >= 0

        print("Setting Objective Function")
        model2 += lpSum(
            teacher_number_rooms_sum[(m)]
            for m in TEACHERS) - 50 * lpSum(projector_rooms_sum[
                (j)] for j in PROJECTORS) + 10 * lpSum(poppositive[(k, n)]
                                                       for k in TIMES
                                                       for n in ROOMS)
        print("Solve Room Allocation")
        model2.solve()
        print(LpStatus[model2.status])
        if LpStatus[model2.status] == 'Optimal':
            print("Complete")
            print("Adding to Database")
            timetabler.models.add_classes_to_timetable_twostep(
                TEACHERS, TEACHERMAPPING, SUBJECTMAPPING, TIMES,
                subject_vars_rooms, assign_vars, ROOMS, classpop)
            print("Status:", LpStatus[model2.status])
    return LpStatus[model.status]