コード例 #1
0
    def cut_at(self, dimension, value):
        """Cuts the given core into two parts (at the given value on the given dimension).
        
        Returns the lower part and the upper part as a tuple (lower, upper)."""

        lower_cuboids = []
        upper_cuboids = []

        for cuboid in self._cuboids:
            if value >= cuboid._p_max[dimension]:
                lower_cuboids.append(cuboid)
            elif value <= cuboid._p_min[dimension]:
                upper_cuboids.append(cuboid)
            else:
                p_min = list(cuboid._p_min)
                p_min[dimension] = value
                p_max = list(cuboid._p_max)
                p_max[dimension] = value
                lower_cuboids.append(
                    cub.Cuboid(list(cuboid._p_min), p_max, cuboid._domains))
                upper_cuboids.append(
                    cub.Cuboid(p_min, list(cuboid._p_max), cuboid._domains))

        lower_core = None if len(lower_cuboids) == 0 else Core(
            lower_cuboids, self._domains)
        upper_core = None if len(upper_cuboids) == 0 else Core(
            upper_cuboids, self._domains)

        return lower_core, upper_core
コード例 #2
0
def from_cuboids(cuboids, domains):
    """Create a core from possibly non-intersecting cuboids by applying the repair mechanism."""

    # first: simplify the cuboids to make life easier (and avoid weird results down the road)
    cubs = simplify(cuboids)

    if check(cubs, domains):
        return Core(cubs,
                    domains)  # all cuboids already intersect --> nothing to do

    # need to perform repair mechanism
    midpoints = []
    for cuboid in cubs:  # midpoint of each cuboid
        midpoints.append(
            map(lambda x, y: 0.5 * (x + y), cuboid._p_min, cuboid._p_max))
    # sum up all midpoints & divide by number of cuboids
    midpoint = reduce(lambda x, y: map(lambda a, b: a + b, x, y), midpoints)
    midpoint = map(lambda x: x / len(cubs), midpoint)

    # extend cuboids
    modified_cuboids = []
    for cuboid in cubs:
        p_min = map(min, cuboid._p_min, midpoint)
        p_max = map(max, cuboid._p_max, midpoint)
        modified_cuboids.append(cub.Cuboid(p_min, p_max, cuboid._domains))

    return Core(modified_cuboids, domains)
コード例 #3
0
def _check_crisp_betweenness(points, first, second):
    """Returns a list of boolean flags indicating which of the given points are strictly between the first and the second concept."""

    # store whether the ith point has already be shown to be between the two other cores
    betweenness = [False] * len(points)

    for c1 in first._core._cuboids:
        for c2 in second._core._cuboids:

            if not c1._compatible(c2):
                raise Exception("Incompatible cuboids")
            p_min = map(min, c1._p_min, c2._p_min)
            p_max = map(max, c1._p_max, c2._p_max)
            dom_union = dict(c1._domains)
            dom_union.update(c2._domains)
            bounding_box = cub.Cuboid(p_min, p_max, dom_union)

            local_betweenness = [True] * len(points)
            # check if each point is contained in the bounding box
            for i in range(len(points)):
                local_betweenness[i] = bounding_box.contains(points[i])

            if reduce(lambda x, y: x or y, local_betweenness
                      ) == False:  # no need to check inequalities
                continue

            # check additional contraints for each domain
            for domain in dom_union.values():
                if len(domain
                       ) < 2:  # we can safely ignore one-dimensional domains
                    continue

                for i in range(len(domain)):
                    for j in range(i + 1, len(domain)):
                        # look at all pairs of dimensions within this domain
                        d1 = domain[i]
                        d2 = domain[j]

                        # create list of inequalities
                        inequalities = []

                        def makeInequality(p1, p2, below):
                            sign = -1 if below else 1
                            a = (p2[1] - p1[1]) if p2[0] > p1[0] else (p1[1] -
                                                                       p2[1])
                            b = -abs(p1[0] - p2[0])
                            c = -1 * (a * p1[0] + b * p1[1])
                            return (lambda x: (sign *
                                               (a * x[0] + b * x[1] + c) <= 0))

                        # different cases
                        if c2._p_max[d1] > c1._p_max[d1] and c2._p_min[
                                d2] > c1._p_min[d2]:
                            inequalities.append(
                                makeInequality([c1._p_max[d1], c1._p_min[d2]],
                                               [c2._p_max[d1], c2._p_min[d2]],
                                               False))
                        if c2._p_max[d1] > c1._p_max[d1] and c1._p_max[
                                d2] > c2._p_max[d2]:
                            inequalities.append(
                                makeInequality(c1._p_max, c2._p_max, True))
                        if c2._p_min[d1] > c1._p_min[d1] and c2._p_max[
                                d2] > c1._p_max[d2]:
                            inequalities.append(
                                makeInequality([c1._p_min[d1], c1._p_max[d2]],
                                               [c2._p_min[d1], c2._p_max[d2]],
                                               True))
                        if c2._p_min[d1] > c1._p_min[d1] and c2._p_min[
                                d2] < c1._p_min[d2]:
                            inequalities.append(
                                makeInequality(c1._p_min, c2._p_min, False))

                        if c1._p_max[d1] > c2._p_max[d1] and c1._p_min[
                                d2] > c2._p_min[d2]:
                            inequalities.append(
                                makeInequality([c1._p_max[d1], c1._p_min[d2]],
                                               [c2._p_max[d1], c2._p_min[d2]],
                                               False))
                        if c1._p_max[d1] > c2._p_max[d1] and c2._p_max[
                                d2] > c1._p_max[d2]:
                            inequalities.append(
                                makeInequality(c1._p_max, c2._p_max, True))
                        if c1._p_min[d1] > c2._p_min[d1] and c1._p_max[
                                d2] > c2._p_max[d2]:
                            inequalities.append(
                                makeInequality([c1._p_min[d1], c1._p_max[d2]],
                                               [c2._p_min[d1], c2._p_max[d2]],
                                               True))
                        if c1._p_min[d1] > c2._p_min[d1] and c1._p_min[
                                d2] < c2._p_min[d2]:
                            inequalities.append(
                                makeInequality(c1._p_min, c2._p_min, False))

                        for k in range(len(points)):
                            for ineq in inequalities:
                                local_betweenness[k] = local_betweenness[
                                    k] and ineq([points[k][d1], points[k][d2]])

                        if not reduce(lambda x, y: x or y, local_betweenness):
                            break
                    if not reduce(lambda x, y: x or y, local_betweenness):
                        break
                if not reduce(lambda x, y: x or y, local_betweenness):
                    break

            betweenness = map(lambda x, y: x or y, betweenness,
                              local_betweenness)
            if reduce(lambda x, y: x and y, betweenness):
                return betweenness

    return betweenness
コード例 #4
0
    def _intersect_fuzzy_cuboids(self, c1, c2, other):
        """Find the highest intersection of the two cuboids (c1 from this, c2 from the other concept)."""

        crisp_intersection = c1.intersect_with(c2)
        if (crisp_intersection != None):  # crisp cuboids already intersect
            return min(self._mu, other._mu), crisp_intersection

        # already compute new set of domains
        new_domains = dict(c1._domains)
        new_domains.update(c2._domains)

        # get ranges of closest points, store which dimensions need to be extruded, pick example points
        a_range, b_range = c1.get_closest_points(c2)
        a = map(lambda x: x[0], a_range)
        b = map(lambda x: x[0], b_range)
        extrude = map(lambda x: x[0] != x[1], a_range)

        mu = None
        p_min = None
        p_max = None
        if self._mu * exp(
                -self._c * cs.distance(a, b, self._weights)) >= other._mu:
            # intersection is part of other cuboid
            mu = other._mu
            p_min, p_max = self._intersection_mu_special_case(a, c2, b, mu)
        elif other._mu * exp(
                -other._c * cs.distance(a, b, other._weights)) >= self._mu:
            # intersection is part of this cuboid
            mu = self._mu
            p_min, p_max = other._intersection_mu_special_case(b, c1, a, mu)
        else:
            # intersection is in the cuboid between a and b
            # --> find point with highest identical membership to both cuboids

            # only use the relevant dimensions in order to make optimization easier
            def membership(x, point, mu, c, weights):
                x_new = []
                j = 0
                for dim in range(cs._n_dim):
                    if extrude[dim]:
                        x_new.append(point[dim])
                    else:
                        x_new.append(x[j])
                        j += 1
                return mu * exp(-c * cs.distance(point, x_new, weights))

            bounds = []
            for dim in range(cs._n_dim):
                if not extrude[dim]:
                    bounds.append((min(a[dim], b[dim]), max(a[dim], b[dim])))
            first_guess = map(lambda (x, y): (x + y) / 2.0, bounds)
            to_minimize = lambda x: -membership(x, a, self._mu, self._c, self.
                                                _weights)
            constr = [{
                "type":
                "eq",
                "fun": (lambda x: abs(
                    membership(x, a, self._mu, self._c, self._weights) -
                    membership(x, b, other._mu, other._c, other._weights)))
            }]
            opt = scipy.optimize.minimize(to_minimize,
                                          first_guess,
                                          constraints=constr,
                                          bounds=bounds,
                                          options={"eps": cs._epsilon
                                                   })  #, "maxiter":500
            if not opt.success and abs(opt.fun - membership(
                    opt.x, b, other._mu, other._c, other._weights)) < 1e-06:
                # if optimizer failed to find exact solution, but managed to find approximate solution: take it
                raise Exception("Optimizer failed!")
            # reconstruct full x by inserting fixed coordinates that will be extruded later
            x_star = []
            j = 0
            for dim in range(cs._n_dim):
                if extrude[dim]:
                    x_star.append(a[dim])
                else:
                    x_star.append(opt.x[j])
                    j += 1
            mu = membership(opt.x, a, self._mu, self._c, self._weights)

            # check if the weights are linearly dependent w.r.t. all relevant dimensions
            relevant_dimensions = []
            for i in range(cs._n_dim):
                if not extrude[i]:
                    relevant_dimensions.append(i)
            relevant_domains = self._reduce_domains(cs._domains,
                                                    relevant_dimensions)

            t = None
            weights_dependent = True
            for (dom, dims) in relevant_domains.items():
                for dim in dims:
                    if t is None:
                        # initialize
                        t = (self._weights._domain_weights[dom] *
                             sqrt(self._weights._dimension_weights[dom][dim])
                             ) / (other._weights._domain_weights[dom] * sqrt(
                                 other._weights._dimension_weights[dom][dim]))
                    else:
                        # compare
                        t_prime = (
                            self._weights._domain_weights[dom] *
                            sqrt(self._weights._dimension_weights[dom][dim])
                        ) / (other._weights._domain_weights[dom] *
                             sqrt(other._weights._dimension_weights[dom][dim]))
                        if round(t, 10) != round(t_prime, 10):
                            weights_dependent = False
                            break
                if not weights_dependent:
                    break

            if weights_dependent and len(relevant_domains.keys()) > 1:
                # weights are linearly dependent and at least two domains are involved
                # --> need to find all possible corner points of resulting cuboid
                epsilon_1 = -log(mu / self._mu) / self._c
                epsilon_2 = -log(mu / other._mu) / other._c
                points = []

                for num_free_dims in range(1, len(relevant_dimensions)):
                    # start with a single free dimensions (i.e., edges of the bounding box) and increase until we find a solution
                    for free_dims in itertools.combinations(
                            relevant_dimensions, num_free_dims):
                        # free_dims is the set of dimensions that are allowed to vary, all other ones are fixed

                        binary_vecs = list(
                            itertools.product([False, True],
                                              repeat=len(relevant_dimensions) -
                                              num_free_dims))

                        for vec in binary_vecs:

                            # compute the difference between the actual distance and the desired epsilon-distance
                            def epsilon_difference(x, point, weights, epsilon):
                                i = 0
                                j = 0
                                x_new = []
                                # puzzle together our large x vector based on the fixed and the free dimensions
                                for dim in range(cs._n_dim):
                                    if dim in free_dims:
                                        x_new.append(x[i])
                                        i += 1
                                    elif extrude[dim]:
                                        x_new.append(a[dim])
                                    else:
                                        x_new.append(
                                            a[dim] if vec[j] else b[dim])
                                        j += 1
                                return abs(
                                    cs.distance(point, x_new, weights) -
                                    epsilon)

                            bounds = []
                            for dim in free_dims:
                                bounds.append(
                                    (min(a[dim], b[dim]), max(a[dim], b[dim])))
                            first_guess = map(lambda (x, y): (x + y) / 2.0,
                                              bounds)
                            to_minimize = lambda x: max(
                                epsilon_difference(x, a, self._weights,
                                                   epsilon_1)**2,
                                epsilon_difference(x, b, other._weights,
                                                   epsilon_2)**2)

                            opt = scipy.optimize.minimize(
                                to_minimize, first_guess)  #tol = 0.000001
                            if opt.success:
                                dist1 = epsilon_difference(
                                    opt.x, a, self._weights, epsilon_1)
                                dist2 = epsilon_difference(
                                    opt.x, b, other._weights, epsilon_2)
                                between = True
                                k = 0
                                for dim in free_dims:
                                    if not (min(a[dim], b[dim]) <= opt.x[k] <=
                                            max(a[dim], b[dim])):
                                        between = False
                                        break
                                    k += 1
                                # must be between a and b on all free dimensions AND must be a sufficiently good solution
                                if dist1 < 0.00001 and dist2 < 0.00001 and between:
                                    point = []
                                    i = 0
                                    j = 0
                                    # puzzle together our large x vector based on the fixed and the free dimensions
                                    for dim in range(cs._n_dim):
                                        if dim in free_dims:
                                            point.append(opt.x[i])
                                            i += 1
                                        elif extrude[dim]:
                                            point.append(a[dim])
                                        else:
                                            point.append(
                                                a[dim] if vec[j] else b[dim])
                                            j += 1

                                    points.append(point)

                    if len(points) > 0:
                        # if we found a solution for num_free_dims: stop looking at higher values for num_free_dims
                        p_min = []
                        p_max = []
                        for i in range(cs._n_dim):
                            p_min.append(
                                max(min(a[i], b[i]),
                                    reduce(min, map(lambda x: x[i], points))))
                            p_max.append(
                                min(max(a[i], b[i]),
                                    reduce(max, map(lambda x: x[i], points))))
                        break

                if p_min == None or p_max == None:
                    # this should never happen - if the weights are dependent, there MUST be a solution
                    raise Exception(
                        "Could not find solution for dependent weights")

            else:
                # weights are not linearly dependent: use single-point cuboid
                p_min = list(x_star)
                p_max = list(x_star)
                pass

        # round everything, because we only found approximate solutions anyways
        mu = cs.round(mu)
        p_min = map(cs.round, p_min)
        p_max = map(cs.round, p_max)

        # extrude in remaining dimensions
        for i in range(len(extrude)):
            if extrude[i]:
                p_max[i] = a_range[i][1]

        # finally, construct a cuboid and return it along with mu
        cuboid = cub.Cuboid(p_min, p_max, new_domains)

        return mu, cuboid