Пример #1
0
    def fit_from_scipy_sparse_matrix(
        self,
        adj,
        attr,
        spatially_extensive_attr,
        threshold,
        max_it=10,
        objective_func=ObjectiveFunctionPairwise()):
        """
        Solve the max-p-regions problem in a heuristic way (see [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.
        max_it : int, default: 10
            The maximum number of partitions produced in the algorithm's
            construction phase.
        objective_func : :class:`region.objective_function.ObjectiveFunction`, default: ObjectiveFunctionPairwise()
            The objective function to use.
        """
        print("f_f_SCIPY got:\n",
              attr,
              "\n",
              spatially_extensive_attr,
              "\n",
              threshold,
              sep="")
        weights = ps_api.WSP(adj).to_W()
        areas_dict = weights.neighbors
        self.metric = objective_func.metric

        best_partition = None
        best_obj_value = float("inf")
        feasible_partitions = []
        partitions_before_enclaves_assignment = []
        max_p = 0  # maximum number of regions

        # construction phase
        # print("constructing")
        for _ in range(max_it):
            # print(" ", _)
            partition, enclaves = self.grow_regions(adj, attr,
                                                    spatially_extensive_attr,
                                                    threshold)
            n_regions = len(partition)
            if n_regions > max_p:
                partitions_before_enclaves_assignment = [(partition, enclaves)]
                max_p = n_regions
            elif n_regions == max_p:
                partitions_before_enclaves_assignment.append(
                    (partition, enclaves))

        # print("\n" + "assigning enclaves")
        for partition, enclaves in partitions_before_enclaves_assignment:
            # print("  cleaning up in partition", partition)
            feasible_partitions.append(
                self.assign_enclaves(partition, enclaves, areas_dict, attr))

        for partition in feasible_partitions:
            print(partition, "\n")

        # local search phase
        if self.local_search is None:
            self.local_search = AZP()
        self.local_search.allow_move_strategy = AllowMoveAZPMaxPRegions(
            spatially_extensive_attr, threshold,
            self.local_search.allow_move_strategy)
        for partition in feasible_partitions:
            self.local_search.fit_from_scipy_sparse_matrix(
                adj,
                attr,
                max_p,
                initial_labels=array_from_region_list(partition),
                objective_func=objective_func)
            partition = self.local_search.labels_
            # print("optimized partition", partition)
            obj_value = objective_func(partition, attr)
            if obj_value < best_obj_value:
                best_obj_value = obj_value
                best_partition = partition
        self.labels_ = best_partition
Пример #2
0
def _tree(adj, attr, n_regions, solver, metric):
    """
    Parameters
    ----------
    adj : class:`scipy.sparse.csr_matrix`
        Refer to the corresponding argument in :func:`_flow`.
    attr : :class:`numpy.ndarray`
        Refer to the corresponding argument in :func:`_flow`.
    n_regions : int
        Refer to the corresponding argument in :func:`_flow`.
    solver : str
        Refer to the corresponding argument in :func:`_flow`.
    metric : function
        Refer to the corresponding argument in :func:`_flow`.

    Returns
    -------
    result : :class:`numpy.ndarray`
        Refer to the return value in :func:`_flow`.
    """
    print("running TREE algorithm")  # TODO: rm
    prob = LpProblem("Tree", LpMinimize)

    # Parameters of the optimization problem
    n_areas = attr.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]
    d = {
        (i, j): metric(
            attr[i].reshape(attr.shape[1], 1),  # reshaping to...
            attr[j].reshape(attr.shape[1], 1))  # ...avoid warnings
        for i, j in II
    }
    # Decision variables
    t = LpVariable.dicts("t", ((i, j) for i, j in II),
                         lowBound=0,
                         upBound=1,
                         cat=LpInteger)
    x = LpVariable.dicts("x", ((i, j) for i, j in II),
                         lowBound=0,
                         upBound=1,
                         cat=LpInteger)
    u = LpVariable.dicts("u", (i for i in I), lowBound=0, cat=LpInteger)

    # Objective function
    # (3) in Duque et al. (2011): "The p-Regions Problem"
    prob += lpSum(d[i, j] * t[i, j] for i, j in II_upper_triangle)

    # Constraints
    # (4) in Duque et al. (2011): "The p-Regions Problem"
    lhs = lpSum(x[i, j] for i in I for j in neighbors(adj, i))
    prob += lhs == n_areas - n_regions
    # (5) in Duque et al. (2011): "The p-Regions Problem"
    for i in I:
        prob += lpSum(x[i, j] for j in neighbors(adj, i)) <= 1
    # (6) in Duque et al. (2011): "The p-Regions Problem"
    for i in I:
        for j in I:
            for m in I:
                if i != j and i != m and j != m:
                    prob += t[i, j] + t[i, m] - t[j, m] <= 1
    # (7) in Duque et al. (2011): "The p-Regions Problem"
    for i, j in II:
        prob += t[i, j] - t[j, i] == 0
    # (8) in Duque et al. (2011): "The p-Regions Problem"
    for i in I:
        for j in neighbors(adj, i):
            prob += x[i, j] <= t[i, j]
    # (9) in Duque et al. (2011): "The p-Regions Problem"
    for i in I:
        for j in neighbors(adj, i):
            prob += u[i] - u[j] + (n_areas - n_regions) * x[i, j] \
                    + (n_areas - n_regions - 2) * x[j, i] \
                    <= n_areas - n_regions - 1
    # (10) in Duque et al. (2011): "The p-Regions Problem"
    for i in I:
        prob += u[i] <= n_areas - n_regions
        prob += u[i] >= 1
    # (11) in Duque et al. (2011): "The p-Regions Problem"
    # already in LpVariable-definition
    # (12) in Duque et al. (2011): "The p-Regions Problem"
    # already in LpVariable-definition

    # Solve the optimization problem
    solver = get_solver_instance(solver)
    prob.solve(solver)

    # build a list of regions like [[0, 1, 2, 5], [3, 4, 6, 7, 8]]
    idx_copy = set(I)
    regions = [[] for _ in range(n_regions)]
    for i in range(n_regions):
        area = idx_copy.pop()
        regions[i].append(area)

        for other_area in idx_copy:
            if t[area, other_area].varValue == 1:
                regions[i].append(other_area)

        idx_copy.difference_update(regions[i])

    result = array_from_region_list(regions)
    return result