예제 #1
0
    def add_model_soc_constr(
        self,
        model: ScipModel,
        variables: List,
        rows: Iterator,
        A: dok_matrix,
        b: ndarray,
    ) -> Tuple:
        """Adds SOC constraint to the model using the data from mat and vec.

        Return tuple contains (QConstr, list of Constr, and list of variables).
        """
        from pyscipopt.scip import quicksum

        # Assume first expression (i.e. t) is nonzero.
        expr_list = {i: [] for i in rows}
        for (i, j), c in A.items():
            v = variables[j]
            try:
                expr_list[i].append((c, v))
            except Exception:
                pass

        # Make a variable and equality constraint for each term.
        soc_vars = []
        for i in rows:
            lb = 0 if len(soc_vars) == 0 else None
            var = model.addVar(
                obj=0,
                name="soc_t_%d" % i,
                vtype=VariableTypes.CONTINUOUS,
                lb=lb,
                ub=None,
            )
            soc_vars.append(var)

        lin_expr_list = [
            b[i] - quicksum(coeff * var for coeff, var in expr_list[i])
            for i in rows
        ]

        new_lin_constrs = [
            model.addCons(soc_vars[i] == lin_expr_list[i])
            for i, _ in enumerate(lin_expr_list)
        ]

        # Interesting because only <=?
        t_term = soc_vars[0] * soc_vars[0]
        x_term = quicksum([var * var for var in soc_vars[1:]])
        constraint = model.addCons(x_term <= t_term)

        return (
            constraint,
            new_lin_constrs,
            soc_vars,
        )
예제 #2
0
def test_objective(model):
    m, x, y, z = model

    # setting linear objective
    m.setObjective(x + y)

    # using quicksum
    m.setObjective(quicksum(2 * v for v in [x, y, z]))

    # setting affine objective
    m.setObjective(x + y + 1)
    assert m.getObjoffset() == 1

    # setting nonlinear objective
    with pytest.raises(ValueError):
        m.setObjective(x**2 - y * z)
예제 #3
0
def test_objective(model):
    m, x, y, z = model

    # setting linear objective
    m.setObjective(x + y)

    # using quicksum
    m.setObjective(quicksum(2 * v for v in [x, y, z]))

    # setting affine objective
    m.setObjective(x + y + 1)
    assert m.getObjoffset() == 1

    # setting nonlinear objective
    with pytest.raises(ValueError):
        m.setObjective(x ** 2 - y * z)
예제 #4
0
    def add_model_lin_constr(
        self,
        model: ScipModel,
        variables: List,
        rows: Iterator,
        ctype: str,
        A: dok_matrix,
        b: ndarray,
    ) -> List:
        """Adds EQ/LEQ constraints to the model using the data from mat and vec.

        Return list contains constraints.
        """
        from pyscipopt.scip import quicksum

        constraints = []
        expr_list = {i: [] for i in rows}
        for (i, j), c in A.items():
            v = variables[j]
            try:
                expr_list[i].append((c, v))
            except Exception:
                pass

        for i in rows:
            # Ignore empty constraints.
            if expr_list[i]:
                expression = quicksum(coeff * var
                                      for coeff, var in expr_list[i])
                constraint = model.addCons((
                    expression == b[i]
                ) if ctype == ConstraintTypes.EQUAL else (expression <= b[i]))
                constraints.append(constraint)
            else:
                constraints.append(None)

        return constraints
예제 #5
0
파일: generic.py 프로젝트: CharJon/GeCO
def late_tasks_formulation(
    number_of_facilities,
    number_of_tasks,
    time_steps,
    processing_times,
    capacities,
    assignment_costs,
    release_dates,
    deadlines,
    name="Hooker Scheduling Late Tasks Formulation",
):
    """Generates late tasks mip formulation described in section 4 in [1].

    Parameters
    ----------
    number_of_facilities: int
        the number of facilities to schedule on
    number_of_tasks: int
        the number of tasks to assign to facilities
    time_steps:
        the number of time steps starting from 0 (corresponds to "N" in the paper)
    processing_times: dict[int,int]
        time steps to process each task
    capacities: list[int]
        capacity of each facility
    assignment_costs: dict[int,int]
        cost of assigning a task to a facility
    release_dates: list[int]
        time step at which a job is released
    deadlines: dict[int, float]
        deadline (time step) to finish a job
    name: str
        assigned name to generated instance

    Returns
    -------
        model: SCIP model of the late tasks instance

    References
    ----------
    .. [1] Hooker, John. (2005). Planning and Scheduling to Minimize
     Tardiness. 314-327. 10.1007/11564751_25.
    """
    model = scip.Model(name)

    start_time = min(release_dates)
    time_steps = range(start_time, start_time + time_steps)

    # add variables and their cost
    L = []
    for i in range(number_of_tasks):
        var = model.addVar(lb=0, ub=1, obj=1, name=f"L_{i}", vtype="B")
        L.append(var)

    # assignment vars
    x = {}
    for j, i, t in itertools.product(range(number_of_tasks),
                                     range(number_of_facilities), time_steps):
        var = model.addVar(lb=0, ub=1, obj=0, name=f"x_{j}_{i}_{t}", vtype="B")
        x[j, i, t] = var

    # add constraints
    # constraint (a)
    for j, t in itertools.product(range(number_of_tasks), time_steps):
        model.addCons(
            len(time_steps) * L[j] >= scip.quicksum((
                (t + processing_times[j, i]) * x[j, i, t] - deadlines[j]
                for i in range(number_of_facilities))))

    # constraint (b)
    for j in range(number_of_tasks):
        vars = (x[j, i, t] for i, t in itertools.product(
            range(number_of_facilities), time_steps))
        model.addCons(scip.quicksum(vars) == 1)

    # constraint (c)
    for i, t in itertools.product(range(number_of_facilities), time_steps):
        vars = []
        for j in range(number_of_tasks):
            vars += [
                assignment_costs[j, i] * x[j, i, t_prime]
                for t_prime in range(t - processing_times[j, i] + 1, t + 1)
                if (j, i, t_prime) in x
            ]
        model.addCons(scip.quicksum(vars) <= capacities[i])

    # constraint (d)
    for i, j, t in itertools.product(range(number_of_facilities),
                                     range(number_of_tasks), time_steps):
        if t < release_dates[j] or t > len(time_steps) - processing_times[j,
                                                                          i]:
            model.addCons(x[j, i, t] == 0)

    model.setMinimize()

    return model
예제 #6
0
파일: generic.py 프로젝트: CharJon/GeCO
def hooker_cost_formulation(
    number_of_facilities,
    number_of_tasks,
    processing_times,
    capacities,
    assignment_costs,
    release_dates,
    deadlines,
    resource_requirements,
    name="Hooker Cost Scheduling Formulation",
):
    """Generates scheduling MIP formulation according to [1].

    Parameters
    ----------
    number_of_facilities: int
        the number of facilities to schedule on
    number_of_tasks: int
        the number of tasks to assign to facilities
    processing_times: dict[(int,int),int]
        time steps to process each task
    capacities: list[int]
        capacity of each facility
    assignment_costs: dict[(int,int),int]
        cost of assigning a task to a facility
    release_dates: list[int]
        time step at which a job is released
    deadlines: dict[int, float]
        deadline (time step) to finish a job
    resource_requirements: dict[(int,int),int]
        resources required for each task assigned to a facility
    name: str
        assigned name to generated instance

    Returns
    -------
        model: SCIP model of generated instance

    References
    ----------
    .. [1] J. N. Hooker, A hybrid method for planning and scheduling, CP 2004.
    """
    model = scip.Model(name)

    time_steps = range(min(release_dates), int(max(deadlines)))

    # objective function
    x = {}
    for j, i, t in itertools.product(range(number_of_tasks),
                                     range(number_of_facilities), time_steps):
        var = model.addVar(lb=0,
                           ub=1,
                           obj=assignment_costs[j, i],
                           name=f"x_{j}_{i}_{t}",
                           vtype="B")
        x[j, i, t] = var

    # add constraints
    # constraints (a)
    for j in range(number_of_tasks):
        model.addCons(
            scip.quicksum(x[j, i, t] for i, t in itertools.product(
                range(number_of_facilities), time_steps)) == 1)

    # constraints (b)
    for i, t in itertools.product(range(number_of_facilities), time_steps):
        model.addCons(
            scip.quicksum(resource_requirements[j, i] * x[j, i, t]
                          for j in range(number_of_tasks)) <= capacities[i])

    # constraints (c)
    for j, i, t in itertools.product(range(number_of_tasks),
                                     range(number_of_facilities), time_steps):
        if (deadlines[j] - processing_times[j, i] < t < release_dates[j]
                or t > number_of_tasks - processing_times[j, i]):
            model.addCons(x[j, i, t] == 0)

    return model
예제 #7
0
파일: generic.py 프로젝트: CharJon/GeCO
def heinz_formulation(
    number_of_facilities,
    number_of_tasks,
    processing_times,
    capacities,
    assignment_costs,
    release_dates,
    deadlines,
    resource_requirements,
    name="Heinz Scheduling Formulation",
):
    """Generates scheduling MIP formulation according to Model 4 in [1].

    Parameters
    ----------
    number_of_facilities: int
        the number of facilities to schedule on
    number_of_tasks: int
        the number of tasks to assign to facilities
    processing_times: dict[(int,int),int]
        time steps to process each task
    capacities: list[int]
        capacity of each facility
    assignment_costs: dict[(int,int),int]
        cost of assigning a task to a facility
    release_dates: list[int]
        time step at which a job is released
    deadlines: dict[int, float]
        deadline (time step) to finish a job
    resource_requirements: dict[(int,int),int]
        resources required for each task assigned to a facility
    name: str
        assigned name to generated instance

    Returns
    -------
        model: SCIP model of generated instance

    References
    ----------
    .. [1] Heinz, J. (2013). Recent Improvements Using Constraint Integer Programming for Resource Allocation and Scheduling.
    In Integration of AI and OR Techniques in Constraint Programming for Combinatorial Optimization Problems
    (pp. 12–27). Springer Berlin Heidelberg.
    """
    model = scip.Model(name)

    time_steps = range(min(release_dates), int(max(deadlines)))

    # objective function
    x = {}
    for j, k in itertools.product(range(number_of_tasks),
                                  range(number_of_facilities)):
        var = model.addVar(lb=0,
                           ub=1,
                           obj=assignment_costs[j, k],
                           name=f"x_{j}_{k}",
                           vtype="B")
        x[j, k] = var

    # y vars
    y = {}
    for j, k, t in itertools.product(range(number_of_tasks),
                                     range(number_of_facilities), time_steps):
        if release_dates[j] <= t <= deadlines[j] - processing_times[j, k]:
            var = model.addVar(lb=0,
                               ub=1,
                               obj=0,
                               name=f"y_{j}_{k}_{t}",
                               vtype="B")
            y[j, k, t] = var

    # add constraints
    # constraint (12)
    for j in range(number_of_tasks):
        model.addCons(
            scip.quicksum(x[j, k] for k in range(number_of_facilities)) == 1)

    # constraint (13)
    for j, k in itertools.product(range(number_of_tasks),
                                  range(number_of_facilities)):
        model.addCons(
            scip.quicksum(
                y[j, k, t]
                for t in range(release_dates[j],
                               int(deadlines[j]) - processing_times[j, k])
                if t < len(time_steps)) == x[j, k])

    # constraint (14)
    for k, t in itertools.product(range(number_of_facilities), time_steps):
        model.addCons(
            scip.quicksum(
                resource_requirements[j, k] * y[j, k, t_prime]
                for j in range(number_of_tasks)
                for t_prime in range(t - processing_times[j, k], t + 1)
                if (j, k, t_prime) in y) <= capacities[k])

    # constraint (15)
    epsilon = filter(lambda ts: ts[0] < ts[1],
                     itertools.product(release_dates, deadlines))
    for k, (t1, t2) in itertools.product(range(number_of_facilities), epsilon):
        model.addCons(
            scip.quicksum(
                processing_times[j, k] * resource_requirements[j, k] * x[j, k]
                for j in range(number_of_tasks) if t1 <= release_dates[j]
                and t2 >= deadlines[j]) <= capacities[k] * (t2 - t1))

    return model