Ejemplo n.º 1
0
def define_indicator_dv(s):
    variable = "ind_" + re.sub('[^A-Za-z0-9]+', '', s)
    variable = pulp.LpVariable(str(variable),
                               lowBound=0,
                               upBound=1,
                               cat='Integer')  # make variable binary
    return variable
Ejemplo n.º 2
0
def get_maintenance_scheme_pulp_optimization(de_capacity, dm_capacity,
                                             data_centers) -> tuple:
    """
    Uses PuLP library to find minimal values of equations
    """
    variables = list()

    for i in range(len(data_centers) * 2):
        variable = pulp.LpVariable('x{}'.format(i), lowBound=0, cat='Integer')
        variables.append(variable)

    managers = variables[::2]
    engineers = variables[1::2]
    problem = pulp.LpProblem("Minimize number of engineers", pulp.LpMinimize)
    problem += sum(engineers), 'Z'
    problem += sum(managers) == 1

    for i, data_center in enumerate(data_centers):
        problem += dm_capacity * managers[i] + de_capacity * engineers[
            i] >= data_center['servers']

    problem.solve()

    for variable in managers:
        if variable.value():
            data_center_id = int(
                int(re.search(r'\d+', str(variable)).group()) / 2)

    engineer_list = [x.value() for x in engineers]
    return int(sum(engineer_list)), data_centers[data_center_id]['name']
Ejemplo n.º 3
0
def define_dv(s):
    variable = "x_" + re.sub('[^A-Za-z0-9]+', '',
                             s["movie_name"]) + "_" + s["dates"].strftime(
                                 "%Y-%m-%d") + "_" + s["slots"]
    variable = pulp.LpVariable(str(variable),
                               lowBound=0,
                               upBound=1,
                               cat='Integer')  # make variable binary
    return variable
Ejemplo n.º 4
0
    def update_with_soft_affinity_constraints_and_objective(
            self, variables, prob, num_hosts, num_instances):
        #Adding column sum variables whose value is 1 if there is any instance on that host
        column_sum_var = []
        for i in range(num_hosts):
            column_sum_var.append(
                pulp.LpVariable("Normalised_Column_Sum_Host_" + str(i), 0, 1,
                                constants.LpInteger))

        #Adding normalisation constraint
        for i in range(num_hosts):
            prob += pulp.lpSum([variables[i][j]] for j in range(
                num_instances)) <= num_instances * column_sum_var[i]
            prob += column_sum_var[i] <= pulp.lpSum(
                [variables[i][j]] for j in range(num_instances))

        z_variables = []
        #Adding 'z' variables
        for i in range(num_hosts):
            for j in range(num_hosts):
                if i != j:
                    z_variables.append(
                        pulp.LpVariable(
                            "Z_variable_Col_" + str(i) + "Col_" + str(j), 0, 1,
                            constants.LpInteger))

        temp = 0
        for i in range(num_hosts):
            for j in range(num_hosts):
                if i != j:
                    prob += column_sum_var[i] + column_sum_var[
                        j] <= z_variables[temp] + 1
                    prob += 2 * z_variables[temp] <= column_sum_var[
                        i] + column_sum_var[j]
                    #print str(temp)  + " " + str(z_variables[temp])
                    temp = temp + 1

        #Adding the objective
        prob += z_variables[0] * 0 + z_variables[1] * 3 + z_variables[
            2] * 1 + z_variables[4] * 3 + z_variables[5] * 5 + z_variables[
                8] * 4
        return prob
Ejemplo n.º 5
0
    def update_with_strict_affinity_constraints_and_objective(
            self, variables, prob, num_hosts, num_instances):
        #Adding column sum variables whose value is 1 if there is any instance on that host
        column_sum_var = []
        for i in range(num_hosts):
            column_sum_var.append(
                pulp.LpVariable("Normalised_Column_Sum_Host_" + str(i), 0, 1,
                                constants.LpInteger))

        #Adding normalisation constraint
        for i in range(num_hosts):
            prob += pulp.lpSum([variables[i][j]] for j in range(
                num_instances)) <= num_instances * column_sum_var[i]
            prob += column_sum_var[i] <= pulp.lpSum(
                [variables[i][j]] for j in range(num_instances))

        prob += pulp.lpSum([column_sum_var[i]] for i in range(num_hosts)) == 1

        return prob
Ejemplo n.º 6
0
    def objective(self, tab):
        """Define and create the objective function from the data set and assign this function
                   to a linear problem (prob).

                   Keyword arguments:
                   tab -- (3D list) the data set
                   prob -- (LinearProblem) the linear problem
                """
        dictionary = {}
        for i in range(len(tab)):
            for j in range(len(tab[i])):
                for k in range(len(tab[i][j])):
                    varNameX = 'X' + str(i) + "_" + str(j) + "_" + str(k)
                    varNameD = 'D' + str(i) + "_" + str(j) + "_" + str(k)
                    varNameC = 'C' + str(i) + "_" + str(j) + "_" + str(k)
                    varNameR = 'R' + str(i) + "_" + str(j) + "_" + str(k)

                    self.macroDynamic(
                        varNameX,
                        pulp.LpVariable(varNameX,
                                        upBound=1,
                                        lowBound=0,
                                        cat='LpInteger'))

                    R = tab[i][j][k][0]
                    C = tab[i][j][k][1]

                    # print R,C,R-C
                    globals()[varNameR] = R
                    globals()[varNameC] = C
                    self.macroDynamic(varNameD, R - C)
                    dictionary.update(
                        {globals()[varNameX]: globals()[varNameD]})
                    # print globals()[varNameD], globals()[varNameX]

        self.prob += pulp.LpAffineExpression(dictionary)
    def host_solve(self, hosts, instance_uuids, request_spec,
                   filter_properties):
        """This method returns a list of tuples - (host, instance_uuid)
        that are returned by the solver. Here the assumption is that
        all instance_uuids have the same requirement as specified in
        filter_properties.
        """
        host_instance_tuples_list = []

        if instance_uuids:
            num_instances = len(instance_uuids)
        else:
            num_instances = request_spec.get('num_instances', 1)
            #Setting a unset uuid string for each instance.
            instance_uuids = [
                'unset_uuid' + str(i) for i in xrange(num_instances)
            ]

        num_hosts = len(hosts)

        LOG.debug(_("All Hosts: %s") % [h.host for h in hosts])
        for host in hosts:
            LOG.debug(_("Host state: %s") % host)

        # Create dictionaries mapping host/instance IDs to hosts/instances.
        host_ids = ['Host' + str(i) for i in range(num_hosts)]
        host_id_dict = dict(zip(host_ids, hosts))
        instance_ids = ['Instance' + str(i) for i in range(num_instances)]
        instance_id_dict = dict(zip(instance_ids, instance_uuids))

        # Create the 'prob' variable to contain the problem data.
        prob = pulp.LpProblem("Host Instance Scheduler Problem",
                              constants.LpMinimize)

        # Create the 'variables' matrix to contain the referenced variables.
        variables = [[
            pulp.LpVariable("IA" + "_Host" + str(i) + "_Instance" + str(j), 0,
                            1, constants.LpInteger)
            for j in range(num_instances)
        ] for i in range(num_hosts)]

        # Get costs and constraints and formulate the linear problem.
        self.cost_objects = [cost() for cost in self.cost_classes]
        self.constraint_objects = [
            constraint(variables, hosts, instance_uuids, request_spec,
                       filter_properties)
            for constraint in self.constraint_classes
        ]

        costs = [[0 for j in range(num_instances)] for i in range(num_hosts)]
        for cost_object in self.cost_objects:
            cost = cost_object.get_cost_matrix(hosts, instance_uuids,
                                               request_spec, filter_properties)
            cost = cost_object.normalize_cost_matrix(cost, 0.0, 1.0)
            weight = float(self.cost_weights[cost_object.__class__.__name__])
            costs = [[
                costs[i][j] + weight * cost[i][j] for j in range(num_instances)
            ] for i in range(num_hosts)]
        prob += (pulp.lpSum([
            costs[i][j] * variables[i][j] for i in range(num_hosts)
            for j in range(num_instances)
        ]), "Sum_of_Host_Instance_Scheduling_Costs")

        for constraint_object in self.constraint_objects:
            coefficient_vectors = constraint_object.get_coefficient_vectors(
                variables, hosts, instance_uuids, request_spec,
                filter_properties)
            variable_vectors = constraint_object.get_variable_vectors(
                variables, hosts, instance_uuids, request_spec,
                filter_properties)
            operations = constraint_object.get_operations(
                variables, hosts, instance_uuids, request_spec,
                filter_properties)
            for i in range(len(operations)):
                operation = operations[i]
                len_vector = len(variable_vectors[i])
                prob += (operation(
                    pulp.lpSum([
                        coefficient_vectors[i][j] * variable_vectors[i][j]
                        for j in range(len_vector)
                    ])), "Costraint_Name_%s" %
                         constraint_object.__class__.__name__ + "_No._%s" % i)

        # The problem is solved using PULP's choice of Solver.
        prob.solve()

        # Create host-instance tuples from the solutions.
        if pulp.LpStatus[prob.status] == 'Optimal':
            for v in prob.variables():
                if v.name.startswith('IA'):
                    (host_id,
                     instance_id) = v.name.lstrip('IA').lstrip('_').split('_')
                    if v.varValue == 1.0:
                        host_instance_tuples_list.append(
                            (host_id_dict[host_id],
                             instance_id_dict[instance_id]))

        return host_instance_tuples_list
Ejemplo n.º 8
0
    def solve(self, hosts, filter_properties):
        """This method returns a list of tuples - (host, instance_uuid)
        that are returned by the solver. Here the assumption is that
        all instance_uuids have the same requirement as specified in
        filter_properties.
        """
        host_instance_combinations = []

        num_instances = filter_properties['num_instances']
        num_hosts = len(hosts)

        instance_uuids = filter_properties.get('instance_uuids') or [
            '(unknown_uuid)' + str(i) for i in xrange(num_instances)
        ]

        filter_properties.setdefault('solver_cache', {})
        filter_properties['solver_cache'].update({
            'cost_matrix': [],
            'constraint_matrix': []
        })

        cost_matrix = self._get_cost_matrix(hosts, filter_properties)
        cost_matrix = self._adjust_cost_matrix(cost_matrix)
        constraint_matrix = self._get_constraint_matrix(
            hosts, filter_properties)

        # Create dictionaries mapping temporary host/instance keys to
        # hosts/instance_uuids. These temorary keys are to be used in the
        # solving process since we need a convention of lp variable names.
        host_keys = ['Host' + str(i) for i in xrange(num_hosts)]
        host_key_map = dict(zip(host_keys, hosts))
        instance_num_keys = [
            'InstanceNum' + str(i) for i in xrange(num_instances + 1)
        ]
        instance_num_key_map = dict(
            zip(instance_num_keys, xrange(num_instances + 1)))

        # create the pulp variables
        variable_matrix = [[
            pulp.LpVariable('HI_' + host_key + '_' + instance_num_key, 0, 1,
                            constants.LpInteger)
            for instance_num_key in instance_num_keys
        ] for host_key in host_keys]

        # create the 'prob' variable to contain the problem data.
        prob = pulp.LpProblem("Host Instance Scheduler Problem",
                              constants.LpMinimize)

        # add cost function to pulp solver
        cost_variables = [
            variable_matrix[i][j] for i in xrange(num_hosts)
            for j in xrange(num_instances + 1)
        ]
        cost_coefficients = [
            cost_matrix[i][j] for i in xrange(num_hosts)
            for j in xrange(num_instances + 1)
        ]
        prob += (pulp.lpSum([
            cost_coefficients[i] * cost_variables[i]
            for i in xrange(len(cost_variables))
        ]), "Sum_Costs")

        # add constraints to pulp solver
        for i in xrange(num_hosts):
            for j in xrange(num_instances + 1):
                if constraint_matrix[i][j] is False:
                    prob += (variable_matrix[i][j] == 0,
                             "Cons_Host_%s" % i + "_NumInst_%s" % j)

        # add additional constraints to ensure the problem is valid
        # (1) non-trivial solution: number of all instances == that requested
        prob += (pulp.lpSum([
            variable_matrix[i][j] * j for i in xrange(num_hosts)
            for j in xrange(num_instances + 1)
        ]) == num_instances, "NonTrivialCons")
        # (2) valid solution: each host is assigned 1 num-instances value
        for i in xrange(num_hosts):
            prob += (pulp.lpSum([
                variable_matrix[i][j] for j in xrange(num_instances + 1)
            ]) == 1, "ValidCons_Host_%s" % i)

        # The problem is solved using PULP's choice of Solver.
        prob.solve(
            pulp_solver_classes.PULP_CBC_CMD(
                maxSeconds=CONF.solver_scheduler.pulp_solver_timeout_seconds))

        # Create host-instance tuples from the solutions.
        if pulp.LpStatus[prob.status] == 'Optimal':
            num_insts_on_host = {}
            for v in prob.variables():
                if v.name.startswith('HI'):
                    (host_key, instance_num_key
                     ) = v.name.lstrip('HI').lstrip('_').split('_')
                    if v.varValue == 1:
                        num_insts_on_host[host_key] = (
                            instance_num_key_map[instance_num_key])
            instances_iter = iter(instance_uuids)
            for host_key in host_keys:
                num_insts_on_this_host = num_insts_on_host.get(host_key, 0)
                for i in xrange(num_insts_on_this_host):
                    host_instance_combinations.append(
                        (host_key_map[host_key], instances_iter.next()))
        else:
            LOG.warn(
                _LW("Pulp solver didnot find optimal solution! "
                    "reason: %s"), pulp.LpStatus[prob.status])
            host_instance_combinations = []

        return host_instance_combinations
Ejemplo n.º 9
0
def define_tvr_slacks(start, end):
    var1 = "slack_{}_{}_period".format(start, end)
    var2 = "slack_{}_{}_avg".format(start, end)
    var1 = pulp.LpVariable(str(var1), lowBound=0)
    var2 = pulp.LpVariable(str(var2), lowBound=0)
    return var1, var2
Ejemplo n.º 10
0
    def distribute(self, fairness=True, output=None):
        """
        This method is responsible for actually solving the linear programming problem.
        It uses the data in the instance variables.
        The optional parameter **fairness** indicates if the solution should minimize individual effort. By default the solution will enforce this condition.
        An error will be raised in case the data has inconsistencies.
        """
        # Validate the problem variables
        self._validate()

        # State problem
        problem = pulp.LpProblem("Fair Distribution Problem", pulp.LpMinimize)

        # Prepare variables
        targets_objects = {}
        for (t, target) in enumerate(self._targets):
            for (o, object) in enumerate(self._objects):
                variable = pulp.LpVariable(
                    'x' + str(t) + str(o), lowBound=0, cat='Binary')
                position = {'target': t, 'object': o}
                targets_objects['x' + str(t) + str(o)] = (variable, position)

        # Generate linear expression for self._weights (Summation #1)
        weights = [(variable, self._weights[weight_position['target']][weight_position['object']])
                   for (variable, weight_position) in targets_objects.values()]
        weight_expression = pulp.LpAffineExpression(weights)

        # Generate linear expression for effort distribution (Summation #2)
        weight_diff_vars = []
        if fairness:
            total_targets = len(self._targets)
            for (t, target) in enumerate(self._targets):
                weight_diff_aux_variable = pulp.LpVariable(
                    'weight_diff_'+str(t), lowBound=0)
                weight_diff_vars.append(weight_diff_aux_variable)

                negative_effort_diff_weights = []
                positive_effort_diff_weights = []
                negative_factor = -1 * total_targets
                positive_factor = 1 * total_targets
                for (o, object) in enumerate(self._objects):
                    id = 'x' + str(t) + str(o)
                    negative_effort_diff_weights.append(
                        (targets_objects[id][0], negative_factor * self._weights[t][o]))
                    positive_effort_diff_weights.append(
                        (targets_objects[id][0], positive_factor * self._weights[t][o]))

                negative_effort_diff = pulp.LpAffineExpression(
                    negative_effort_diff_weights) + weight_expression
                positive_effort_diff = pulp.LpAffineExpression(
                    positive_effort_diff_weights) - weight_expression

                problem += negative_effort_diff <= weight_diff_aux_variable, 'abs negative effort diff ' + \
                    str(t)
                problem += positive_effort_diff <= weight_diff_aux_variable, 'abs positive effort diff ' + \
                    str(t)

        # Constraints - Each task must be done
        for (o, object) in enumerate(self._objects):
            constraints = []
            for (t, target) in enumerate(self._targets):
                constraints.append(targets_objects['x' + str(t) + str(o)][0])
            problem += pulp.lpSum(constraints) == 1, 'Task ' + \
                str(o) + ' must be done'

        # Set objective function
        problem += weight_expression + \
            pulp.lpSum(weight_diff_vars), "obj"

        if output:
            problem.writeLP(output)

        problem.solve()

        # Build output
        data = {}
        for v in filter(lambda x: x.varValue > 0, problem.variables()):
            if v.name not in targets_objects:
                continue
            position = targets_objects[v.name][1]
            target = self._targets[position['target']]
            object = self._objects[position['object']]

            if target not in data:
                data[target] = []

            data[target].append(object)

        return data