def create_aggretriever(aggregation_info):
    """This function works to aggregate a retriever following the instructions
    input in the aggregation_info variable. It returns an instance of a
    retriever object to be appended in the collection manager list of
    retrievers.

    Parameters
    ----------
    aggregation_info: tuple
        the information to create a retriever aggregation.

    Returns
    -------
    ret_out: pst.BaseRetriever
        the retriever instance.

    """
    ## 0. Preparing inputs
    assert type(aggregation_info) == tuple
    disc_info, _, retriever_out, agg_info = aggregation_info
    assert type(agg_info) == tuple
    assert len(agg_info) == 2
    aggregating_ret, _ = agg_info
    ## 1. Computing retriever_out
    locs, regs, disc = _discretization_parsing_creation(disc_info)
    ret_out = aggregating_ret(retriever_out, locs, regs, disc)
    assert isinstance(ret_out, BaseRetriever)
    return ret_out
def create_m_in_direct_discretization(discretization_info):
    """Create in_map for direct discretization.

    Parameters
    ----------
    discretization_info: tuple or pst.BaseSpatialDiscretizor
        It is defined by a discretization object or a tuple of locations,
        regions and discretization object. The standard inputs of that
        function parameter are:
            * (discretizator, locs)
            * (locs, regions)
            * disc
            * locs, regs, disc

    Returns
    -------
    m_in_direct_discretazation: function
        the function which formats the input of the retriever.

    """
    ## 0. Parsing discretization information input
    locs, regions, disc = _discretization_parsing_creation(discretization_info)
    ## 1. Building map
    if disc is not None:
        def m_in_direct_discretazation(self, idxs):
            """Direct application of the discretization information."""
            return [disc.discretize(locs[i]) for i in idxs]
    else:
        def m_in_direct_discretazation(self, idxs):
            """Direct application of the discretization information."""
            return [np.array(regions[e]) for e in idxs]

    return m_in_direct_discretazation
def create_m_in_inverse_discretization(discretization_info):
    """Create in_map for inverse discretization.

    Parameters
    ----------
    discretization_info: tuple or pst.BaseSpatialDiscretizor
        It is defined by a discretization object or a tuple of locations,
        regions and discretization object. The standard inputs of that
        function parameter are:
            * (discretizator, locs)
            * (locs, regions)
            * disc
            * locs, regs, disc

    Returns
    -------
    m_in_inverse_discretazation: function
        the function which formats the input of the retriever.

    """
    ## 0. Parsing discretization information input
    locs, regions, disc = _discretization_parsing_creation(discretization_info)

    ## 1. Building map
    def m_in_inverse_discretazation(self, idxs):
        """Inverse application of the discretization information."""
        new_idxs = []
        for i in idxs:
            new_idxs.append(np.where(regions == i)[0])
        return new_idxs

    return m_in_inverse_discretazation
def create_m_out_inverse_discretization(discretization_info):
    """Create out_map for inverse discretization.

    Parameters
    ----------
    discretization_info: tuple or pst.BaseSpatialDiscretizor
        It is defined by a discretization object or a tuple of locations,
        regions and discretization object. The standard inputs of that
        function parameter are:
            * (discretizator, locs)
            * (locs, regions)
            * disc
            * locs, regs, disc

    Returns
    -------
    m_out_inverse_discretization: function
        the function which formats the output of the retriever.

    """
    ## 0. Parsing discretization information input
    locs, regions, disc = _discretization_parsing_creation(discretization_info)

    ## 1. Building map
    if type(regions) == np.ndarray:
        def m_out_inverse_discretization(self, idxs, neighs_info):
            """This out_map for retrievers change the size of neighbourhood by
            substituting the regions_id or groups_id in the neighs_info for the
            elements which belong to this groups.
            """
            neighs, dists = neighs_info
            neighs_o, dists_o = [], []
            for iss_i in range(len(neighs)):
                neighs_p, dists_p = [], []
                for i in range(len(neighs[iss_i])):
                    neighs_ip = np.where(regions == neighs[iss_i][i])[0]
                    neighs_p.append(neighs_ip)
                    if dists[iss_i] is not None:
                        sh = len(neighs_ip), 1
                        dists_p.append(np.ones(sh) * dists[iss_i][i])
                if neighs_p:
                    neighs_p = np.concatenate(neighs_p)
                if dists_p:
                    dists_p = np.concatenate(dists_p)
                else:
                    dists_p = np.ones((0, 1))
                neighs_o.append(neighs_p)
                dists_o.append(dists_p)
            return neighs_o, dists_o

    return m_out_inverse_discretization
def create_aggfeatures(sp_descriptor, features):
    """Average distance of points of the different regions.
    Function to compute the spatial distances between regions.

    Parameters
    ----------
    sp_descriptor: tuple (aggregation_info format) or SpatialDescriptorModel
        the information to compute aggregation.
    features: pst.BaseFeatures
        the features we want to aggregate.

    Returns
    -------
    new_exlicit_features: pst.Features object
        the features object obtained by aggregating the features.

    """
    ## 1. Computing
    if type(sp_descriptor) == tuple:
        ## 0. Parsing inputs
        disc_info, retriever_in, _, agg_info = sp_descriptor
        assert type(agg_info) == tuple
        assert len(agg_info) == 2
        _, aggregating_feat = agg_info
        agg_f_ret, desc_in, pars_feat_in, pars_feats, desc_out = _parse_aggregation_feat(aggregating_feat, features)
        ## Retrievers
        locs, regs, disc = _discretization_parsing_creation(disc_info)
        retrievers = agg_f_ret(retriever_in, locs, regs, disc)
        ## Featurers
        # Feature creation
        object_feats, core_features, pars_fea_o_in = features.export_features()
        pars_fea_o_in["descriptormodel"] = desc_in
        new_features = object_feats(core_features, **pars_fea_o_in)
        # Feature manager creation
        pars_feat_in["maps_vals_i"] = regs
        pars_feat_in["selectors"] = (0, 0), (0, 0), (0, 0)
        featurers = FeaturesManager(new_features, **pars_feat_in)
        ## 1. Preparing spdesc object
        spdesc = SpatialDescriptorModel(retrievers, featurers)
        ## 2. Compute
        aggfeatures = spdesc.compute()
    else:
        aggfeatures = sp_descriptor.compute()
        pars_feats = {}
        desc_out = sp_descriptor.featurers.features[0].descriptormodel

    ## 3. Creation of the object features aggregations
    new_exlicit_features = _featuresobject_parsing_creation((aggfeatures, pars_feats, desc_out))
    return new_exlicit_features
def test():
    ## 0. Artificial data
    # Parameters
    n = 1000
    ngx, ngy = 100, 100
    # Artificial distribution in space
    fucnts = [lambda locs: locs[:, 0]*np.cos(locs[:, 1]*2*np.pi),
              lambda locs: locs[:, 0]*np.sin(locs[:, 1]*np.pi*2)]
    locs1 = random_transformed_space_points(n, 2, None)
    locs2 = random_transformed_space_points(n, 2, fucnts)
    locs3 = random_transformed_space_points(n/100, 2, None)
    Locs = [locs1, locs2, locs3]
    # Set discretization
    elements1 = np.random.randint(0, 50, 200)
    elements2 = np.random.randint(0, 2000, 200)
#
#    ## Test distributions
#    #fig1 = plt.plot(locs[:,0], locs[:, 1], '.')
#    #fig2 = plt.plot(locs2[:,0], locs2[:, 1], '.')
#
    ### Testing utils
    # Discretization 2d utils
    regions_id = np.arange(10)
    indices = np.unique(np.random.randint(0, 10, 5))
    indices_assignation(indices, regions_id)
    mask_application_grid(np.random.random(), np.random.random(10))
    #compute_limital_polygon(limits)
    #match_regions(polygons, regionlocs, n_dim=2)
    # testing voronoi tesselation
    tesselation(np.random.random((10, 2)))

    # Checker
    try:
        boolean = False
        check_discretizors(5)
        boolean = True
        raise Exception("It has to halt here.")
    except:
        if boolean:
            raise Exception("It has to halt here.")

    class Prueba:
        def __init__(self):
            self.n_dim = 9
            self.metric = None
            self.format_ = None
    try:
        boolean = False
        check_discretizors(Prueba)
        boolean = True
        raise Exception("It has to halt here.")
    except:
        if boolean:
            raise Exception("It has to halt here.")

    class Prueba:
        def __init__(self):
            self._compute_limits = 9
            self._compute_contiguity_geom = None
            self._map_loc2regionid = None
            self._map_regionid2regionlocs = None
    try:
        boolean = False
        check_discretizors(Prueba)
        boolean = True
        raise Exception("It has to halt here.")
    except:
        if boolean:
            raise Exception("It has to halt here.")

    ### Discretization
    ############################# Grid discretizer ############################
    disc1 = GridSpatialDisc((ngx, ngy), xlim=(0, 1), ylim=(0, 1))
    disc2 = GridSpatialDisc((ngx, ngy), xlim=(-1, 1), ylim=(-1, 1))

    mapping2grid(Locs[0], (ngx, ngy), xlim=(0, 1), ylim=(0, 1))
    compute_contiguity_grid(-10, (ngx, ngy))

    # Test functions
    disc1[0]
    disc1[locs1[0]]
    len(disc1)
    for i in range(len(Locs)):
        disc1.discretize(Locs[i])
        disc1.map_locs2regionlocs(Locs[i])
        disc1.map2agglocs(Locs[i])
        disc1._map_regionid2regionlocs(0)
        disc1._map_locs2regionlocs(Locs[i])
        disc1.retrieve_region(Locs[i][0], {})
        disc1.retrieve_neigh(Locs[i][0], Locs[i])
        disc1.get_activated_regions(Locs[i])
        disc1.belong_region(Locs[i])
        disc1.belong_region(Locs[i], disc1[0])
        disc1.check_neighbors([disc1[0], disc1[1]], disc1[2])
        disc1.get_limits()
        disc1.get_limits(disc1[0])
        # General functions applyable to this class
        disc1.map_locs2regionlocs(Locs[i])
        disc1.map2agglocs(Locs[i])
        disc1.get_contiguity()

        ## Special functions (recomendable to elevate in the hierharchy)
        disc1.get_nregs()
        disc1.get_regions_id()
        disc1.get_regionslocs()
        ## Class functions
        disc1._compute_contiguity_geom()
        disc1._compute_contiguity_geom(disc1[0])

    ########################### Bisector discretizer ##########################
    try:
        boolean = False
        disc6 = BisectorSpatialDisc(locs3, np.arange(len(locs3)+1))
        boolean = True
        raise Exception("It has to halt here.")
    except:
        if boolean:
            raise Exception("It has to halt here.")
    disc6 = BisectorSpatialDisc(locs3, np.arange(len(locs3)))
    # Test functions
    disc6[0]
    disc6[locs1[0]]
    len(disc6)
    for i in range(len(Locs)):
        disc6.discretize(Locs[i])
        disc6.map_locs2regionlocs(Locs[i])
        disc6.map2agglocs(Locs[i])
        disc6._map_regionid2regionlocs(0)
        disc6._map_locs2regionlocs(Locs[i])
        disc6.retrieve_region(Locs[i][0], {})
        disc6.retrieve_neigh(Locs[i][0], Locs[i])
        disc6.get_activated_regions(Locs[i])
        disc6.belong_region(Locs[i])
        disc6.belong_region(Locs[i], disc6[0])
        disc6.check_neighbors([disc6[0], disc6[1]], disc6[2])
        ## Not implemented yet
        #disc6.get_contiguity()
        #disc6.get_contiguity(disc6[0])
        #disc6.get_limits()
        #disc6.get_limits(disc6[0])

    ########################### Circular discretizer ##########################
    # Parameters
    centers = np.random.random((20, 2))
    radios = np.random.random(20)/5
    jit = np.random.random((100, 2))
    locs_r = centers[np.random.randint(0, 20, 100)] + jit/100000.
    regions_ids = [np.arange(20), np.arange(10, 30)]

    # General tests
    disc4 = CircularSpatialDisc(centers, 0.5)
    disc4._compute_limits(disc4.regions_id[0])
    disc4._map_regionid2regionlocs(0)
    try:
        boolean = False
        disc4._map_regionid2regionlocs(-1)
        boolean = True
        raise Exception("It has to halt here.")
    except:
        if boolean:
            raise Exception("It has to halt here.")

    # Exhaustive tests
    for j in range(len(regions_ids)):
        disc4 = CircularInclusiveSpatialDisc(centers, radios, regions_ids[j])
        disc5 = CircularExcludingSpatialDisc(centers, radios, regions_ids[j])

        # Testing functions
        for i in range(len(Locs)):
            disc4.discretize(Locs[i])
#            disc4.map_locs2regionlocs(Locs[i])
#            disc4.map2agglocs(Locs[i])
#            disc4._map_regionid2regionlocs(0)
#            disc4._map_locs2regionlocs(Locs[i])
#            disc4.retrieve_region(Locs[i][0], {})
#            disc4.retrieve_neigh(Locs[i][0], Locs[i])
#            disc4.get_activated_regions(Locs[i])
#            disc4.belong_region(Locs[i])
#            disc4.belong_region(Locs[i], disc4[0])
#            disc4.check_neighbors([disc4[0], disc4[1]], disc4[2])
#            ## Not implemented yet
#            #disc4.get_contiguity()
#            #disc4.get_contiguity(disc6[0])
#            #disc4.get_limits(Locs[i])
#            #disc4.get_limits(Locs[i], disc6[0])
            disc5.discretize(Locs[i])
#            #disc5.map_locs2regionlocs(Locs[i])
#            disc5.map2agglocs(Locs[i])
#            disc5.retrieve_region(Locs[i][0], {})
#            disc5.retrieve_neigh(Locs[i][0], Locs[i])
#            disc5.get_activated_regions(Locs[i])
#            disc5.belong_region(Locs[i])
#            disc5.belong_region(Locs[i], disc5[0])
#            disc5.check_neighbors([disc5[0], disc5[1]], disc5[2])
#            ## Not implemented yet
#            #disc5.get_contiguity()
#            #disc5.get_contiguity(disc5[0])
#            #disc5.get_limits(Locs[i])
#            #disc5.get_limits(Locs[i], disc5[0])
        disc4.discretize(locs_r)
        #disc4.map_locs2regionlocs(locs_r)
        disc4.map2agglocs(locs_r)
        disc4.get_activated_regions(locs_r)
        disc4.belong_region(locs_r)
        disc4.belong_region(locs_r, disc4[0])

        disc5.discretize(locs_r)
        #disc5.map_locs2regionlocs(locs_r)
        disc5.map2agglocs(locs_r)
        disc5.get_activated_regions(locs_r)
        disc5.belong_region(locs_r)
        disc5.belong_region(locs_r, disc5[0])

    ############################## Set discretizer ############################
    ## Format auxiliar functions
    random_membership(10, 20, True)
    random_membership(10, 20, False)
    memb, out = format_membership(randint_sparse_matrix(0.2, (2000, 100), 1))
#    to_sparse(memb, out)
#    memb, out = format_membership(np.random.random((20, 10)))
    to_sparse(memb, out)
    memb, out = format_membership(list_membership(20, 10))
    to_sparse(memb, out)
    memb0 = list_membership(10, 20)
    memb0 = [list(e) for e in memb0]
    memb, out = format_membership(memb0)
    to_sparse(memb, out)
    memb0 = list_membership(10, 20)
    memb0[0] = 0
    memb, out = format_membership(memb0)
    to_sparse(memb, out)
    memb0 = [[np.random.randint(0, 20)] for e in range(10)]
    memb, out = format_membership(memb0)
    to_sparse(memb, out)
    memb0 = list_membership(10, 20)
    memb0 = [dict(zip(m, len(m)*[{}])) for m in memb0]
    memb, out = format_membership(memb0)
    to_sparse(memb, out)
    find_idx_in_array(10, np.arange(40))

    ## Format discretizer
    disc6 = SetDiscretization(np.random.randint(0, 2000, 50))
    # Test functions
    disc6[0]
    disc6[disc6.regionlocs[0]]
    len(disc6)
    disc6.borders
    disc6.discretize(disc6.regionlocs)
    disc6._map_regionid2regionlocs(0)
    disc6.retrieve_region(disc6.regionlocs[0], {})
    disc6.retrieve_neigh(disc6.regionlocs[0], disc6.regionlocs)
    disc6.get_activated_regions(disc6.regionlocs)
    disc6.belong_region(disc6.regionlocs)
    disc6.belong_region(disc6.regionlocs, disc6[0])
    disc6.check_neighbors([disc6[0], disc6[1]], disc6[2])
#    disc6.get_limits()
#    disc6.get_limits(disc6.regions_id[0])

    disc7 = SetDiscretization(randint_sparse_matrix(0.2, (2000, 100), 1))
    # Test functions
    disc7[0]
    disc7.borders
    disc7[disc7.regionlocs[0]]
    len(disc7)
    disc7.discretize(disc7.regionlocs)
    disc7._map_regionid2regionlocs(0)
    disc7.retrieve_region(disc7.regionlocs[0], {})
    disc7.retrieve_neigh(disc7.regionlocs[0], disc7.regionlocs)
    disc7.get_activated_regions(disc7.regionlocs)
#    disc7.belong_region(disc6.regionlocs)
#    disc7.belong_region(disc6.regionlocs, disc7[0])
#    disc7.check_neighbors([disc7[0], disc7[1]], disc7[2])
#    disc7.get_limits()
#    disc7.get_limits(disc6.regions_id[0])

    ###########################################################################
    #### Testing auxiliar parsing
    locs = np.random.random((100, 2))
    discretization_info = disc1, locs
    _discretization_parsing_creation(discretization_info)
    discretization_info = locs, np.random.randint(0, 10, 100)
    locs, regs, discs = _discretization_parsing_creation(discretization_info)
    disc1.discretize(locs)
    locs, regs, discs = _discretization_parsing_creation((locs, regs, discs))

    regs, locs = _discretization_regionlocs_parsing_creation(disc1)
#    assert(len(regs) == len(locs))
    regs, locs = _discretization_regionlocs_parsing_creation((disc1, locs))
#    assert(len(regs) == len(locs))
    regs, locs = _discretization_regionlocs_parsing_creation((disc1, locs),
                                                             None, True)
#    assert(len(regs) == len(locs))
    locs = np.random.random((100, 2))
    disc1 = GridSpatialDisc((ngx, ngy), xlim=(0, 1), ylim=(0, 1))
    regs, locs = _discretization_regionlocs_parsing_creation((disc1, locs),
                                                             np.arange(100),
                                                             True)
#    assert(len(regs) == len(locs))
    regs, locs = _discretization_regionlocs_parsing_creation((disc1, locs),
                                                             np.arange(100),
                                                             False)
def compute_AvgDistanceRegions(sp_descriptor, store='network', elements=None,
                               symmetric=False, activated=None):
    """Average distance of points of the different regions.
    Function to compute the spatial distances between regions.

    Parameters
    ----------
    locs: np.ndarray
        the locations of the elements.
    discretizor: pst.Discretization object
        the discretization information to transform locations into regions.

    store: optional, ['network', 'sparse', 'matrix']
        the type of object we want to store the relation metric.
    elements: array_like, list or None
        the regions we want to use for measure the metric distance between
        them.
    activated: numpy.ndarray or None
        the location points we want to know if we use the regions non-empty
        or None if we want to use all of them.

    Returns
    -------
    relations: networkx, scipy.sparse, np.ndarray
        the relationship information between regions.
    _data: np.ndarray
        the regions_id.
    symmetric: boolean
        if the relations are symmetric or not (in order to save memory space).
    store: str
        how we want to store the relations.

    """
    pars_rel = {'distanceorweighs': False, 'symmetric': symmetric}
    ## 1. Computing
    if type(sp_descriptor) == tuple:
        disc_info, retriever_info, _ = sp_descriptor
        locs, regs, _ = _discretization_parsing_creation(disc_info)
        assert(retriever_info is not None)
        retriever_info = tuple([retriever_info[0]] + [locs] +
                               list(retriever_info[1:]))
        # Preparing descriptormodel
        _data = np.unique(regs)
        ## WARNING:
        #map_idx = lambda reg: reg
        map_idx = lambda reg: np.where(_data == reg)[0][0]
        descriptormodel =\
            NormalizedDistanceDescriptor(regs, len(_data), map_idx=map_idx)
        # Preparing spdesc
        feats_info = PhantomFeatures((None, len(_data)),
                                     descriptormodel=descriptormodel)
        # Map_vals_i setting
        pars_feats = {'maps_vals_i': regs}
        feats_info = feats_info, pars_feats
        sp_descriptor = _spdesc_parsing_creation(retriever_info, feats_info)
        # Compute
        relations = sp_descriptor.compute()[:, :, 0]
    else:
        relations = sp_descriptor.compute()[:, :, 0]
        _data = np.arange(len(relations))
    ## 2. Formatting output
    if store == 'matrix':
        pass
    elif store == 'sparse':
        relations = coo_matrix(relations)
    elif store == 'network':
        relations = coo_matrix(relations)
        relations = nx.from_scipy_sparse_matrix(relations)
        mapping = dict(zip(relations.nodes(), _data.ravel()))
        relations = nx.relabel_nodes(relations, mapping)
    pars_rel = {'symmetric': symmetric, 'store': store}

    return relations, pars_rel, _data
def create_m_out_direct_discretization(discretization_info):
    """Create out_map for inverse discretization.

    Parameters
    ----------
    discretization_info: tuple or pst.BaseSpatialDiscretizor
        It is defined by a discretization object or a tuple of locations,
        regions and discretization object. The standard inputs of that
        function parameter are:
            * (discretizator, locs)
            * (locs, regions)
            * disc
            * locs, regs, disc

    Returns
    -------
    m_out_direct_discretization: function
        the function which formats the output of the retriever.

    """
    ## 0. Parsing discretization information input
    locs, regions, disc = _discretization_parsing_creation(discretization_info)

    ## 1. Building map
    if disc is None:
        def m_out_direct_discretization(self, idxs, neighs_info):
            """This out_map for retrievers don't change the size of
            neighbourhood, only substitutes the element id for the group or
            regions id. It is useful for PhantomFeatures and direct distance
            features. Distance don't change.

            Parameters
            ----------
            neighs_info: tuple (neighs, dists)
                the neighbourhood information.

            Returns
            -------
            neighs_info: tuple (neighs, dists)
                the neighbourhood information.

            """
            neighs, dists = neighs_info
            neighs_o = []
            for iss_i in range(len(neighs)):
                neighs_p = []
                for i in range(len(neighs[iss_i])):
                    neighs_ip = np.array([regions[neighs[iss_i][i]]]).ravel()
                    neighs_p.append(neighs_ip)
                if neighs_p:
                    neighs_p = np.concatenate(neighs_p)
                neighs_o.append(neighs_p)
            return neighs_o, dists
    else:
        def m_out_direct_discretization(self, idxs, neighs_info):
            """This out_map for retrievers don't change the size of
            neighbourhood, only substitutes the element id for the group or
            regions id. It is useful for PhantomFeatures and direct distance
            features. Distance don't change.

            Parameters
            ----------
            neighs_info: tuple (neighs, dists)
                the neighbourhood information.

            Returns
            -------
            neighs_info: tuple (neighs, dists)
                the neighbourhood information.

            """
            neighs, dists = neighs_info
            neighs_o = []
            for iss_i in range(len(neighs)):
                neighs_p = []
                for i in range(len(neighs[iss_i])):
                    neighs_ip = disc.discretize(locs[neighs[iss_i][i]])
                    neighs_p.append(np.array([neighs_ip]).ravel())
                if neighs_p:
                    neighs_p = np.concatenate(neighs_p)
                neighs_o.append(neighs_p)
            return neighs_o, dists

    return m_out_direct_discretization