示例#1
0
    def test_convex(self):
        mb_0 = Metaball(1.0, 2.0, 0.0)
        mb_1 = Metaball(1.0, 2.0, 2.8)

        interval = mb_1.lower, mb_0.upper
        coeffs = mb_0.get_coeffs(False) + mb_1.get_coeffs(True)
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))
        a, b = np_roots(coeffs, interval)[:2]
        mid = (a + b) / 2

        # Only left root.
        interval = mb_1.lower, mid
        self._test_result(coeffs, interval, a, np.nan)

        # Only right root.
        interval = mid, mb_0.upper
        self._test_result(coeffs, interval, b, np.nan)

        # Roots are interval ends.
        # The root must be picked up either in interval i or i + 1
        interval = a, b
        result = self.get_roots(coeffs, interval)
        np_result = np_roots(coeffs, interval)
        interval = b, mb_0.upper
        result = np.sort(np.concatenate((result,
                                         self.get_roots(coeffs, interval))))
        np_result = np.sort(np.concatenate((np_result,
                                            np_roots(coeffs, interval))))
        result = filter_close(result)
        np_result = filter_close(np_result)
        np.testing.assert_almost_equal(result, np_result,
                                       decimal=self.precision_places)
示例#2
0
    def test_derivative_stationary(self):
        """Test the case when there are two roots and f' has stationary
        points in the interval end points.
        """
        mb = Metaball(1.0, 2.0, 0.0)
        coeffs = mb.get_coeffs(True)

        stat_left = self.get_stationary(coeffs, (mb.lower, 0))
        stat_right = self.get_stationary(coeffs, (0, mb.upper))
        self._test_result(coeffs, (mb.lower, stat_right), -1, 1)
        self._test_result(coeffs, (stat_left, mb.upper), -1, 1)
        self._test_result(coeffs, (stat_left, stat_right), -1, 1)
示例#3
0
    def test_derivative_stationary(self):
        """Test the case when there are two roots and f' has stationary
        points in the interval end points.
        """
        mb = Metaball(1.0, 2.0, 0.0)
        coeffs = mb.get_coeffs(True)

        stat_left = self.get_stationary(coeffs, (mb.lower, 0))
        stat_right = self.get_stationary(coeffs, (0, mb.upper))
        self._test_result(coeffs, (mb.lower, stat_right), -1, 1)
        self._test_result(coeffs, (stat_left, mb.upper), -1, 1)
        self._test_result(coeffs, (stat_left, stat_right), -1, 1)
示例#4
0
    def test_small_on_big_metaball(self):
        mb_0 = Metaball(0.0, 0.5, 0.51)
        mb_1 = Metaball(1.5, 100.0, -1.5)

        # First interval, only big metaball, two roots.
        coeffs = mb_1.get_coeffs(True)
        interval = mb_1.lower, mb_0.lower
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))

        # Last interval, nothing in it.
        interval = mb_0.upper, mb_1.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # Small and big metaballs, two roots.
        coeffs = mb_0.get_coeffs(False) + mb_1.get_coeffs(True)
        interval = mb_0.lower, mb_0.upper
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))
示例#5
0
    def test_stationary_far_from_center(self):
        mb = Metaball(0.1, 2.0, 0.0)

        # Far left and right beyond the object.
        # Both roots.
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, 1.5 * mb.r
        self._test_result(coeffs, interval, -mb.r, mb.r)

        # One root.
        interval = mb.lower, 0
        self._test_result(coeffs, interval, -mb.r, np.nan)

        # Far right
        interval = -1.5 * mb.r, mb.upper
        self._test_result(coeffs, interval, -mb.r, mb.r)

        # One root.
        interval = 0, mb.upper
        self._test_result(coeffs, interval, mb.r, np.nan)
示例#6
0
    def test_stationary_far_from_center(self):
        mb = Metaball(0.1, 2.0, 0.0)

        # Far left and right beyond the object.
        # Both roots.
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, 1.5 * mb.r
        self._test_result(coeffs, interval, -mb.r, mb.r)

        # One root.
        interval = mb.lower, 0
        self._test_result(coeffs, interval, -mb.r, np.nan)

        # Far right
        interval = -1.5 * mb.r, mb.upper
        self._test_result(coeffs, interval, -mb.r, mb.r)

        # One root.
        interval = 0, mb.upper
        self._test_result(coeffs, interval, mb.r, np.nan)
示例#7
0
    def test_convex(self):
        mb_0 = Metaball(1.0, 2.0, 0.0)
        mb_1 = Metaball(1.0, 2.0, 2.8)

        interval = mb_1.lower, mb_0.upper
        coeffs = mb_0.get_coeffs(False) + mb_1.get_coeffs(True)
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))
        a, b = np_roots(coeffs, interval)[:2]
        mid = (a + b) / 2

        # Only left root.
        interval = mb_1.lower, mid
        self._test_result(coeffs, interval, a, np.nan)

        # Only right root.
        interval = mid, mb_0.upper
        self._test_result(coeffs, interval, b, np.nan)

        # Roots are interval ends.
        # The root must be picked up either in interval i or i + 1
        interval = a, b
        result = self.get_roots(coeffs, interval)
        np_result = np_roots(coeffs, interval)
        interval = b, mb_0.upper
        result = np.sort(
            np.concatenate((result, self.get_roots(coeffs, interval))))
        np_result = np.sort(
            np.concatenate((np_result, np_roots(coeffs, interval))))
        result = filter_close(result)
        np_result = filter_close(np_result)
        np.testing.assert_almost_equal(result,
                                       np_result,
                                       decimal=self.precision_places)
示例#8
0
        def test(offset):
            mb = Metaball(1.0, 2.0, 0.0)
            # Root into the stationary point.
            coeffs = mb.get_coeffs(True)
            coeffs = coeffs - \
                np.array([0, 0, 0, 0, f(coeffs, mb.center) + offset])
            # Tip of the quartic is the stationary point.
            interval = mb.lower, mb.upper
            self._test_result(coeffs, interval, *np_roots(coeffs, interval))

            # Moreover, split the interval in the root
            interval = mb.lower, 0.0
            result = self.get_roots(coeffs, interval)
            ground_truth = np_roots(coeffs, interval)

            interval = 0.0, mb.upper
            result = np.sort(
                np.concatenate((result, self.get_roots(coeffs, interval))))
            ground_truth = np.sort(
                np.concatenate((ground_truth, np_roots(coeffs, interval))))
            np.testing.assert_almost_equal(result,
                                           ground_truth,
                                           decimal=self.precision_places)
示例#9
0
        def test(offset):
            mb = Metaball(1.0, 2.0, 0.0)
            # Root into the stationary point.
            coeffs = mb.get_coeffs(True)
            coeffs = coeffs - \
                np.array([0, 0, 0, 0, f(coeffs, mb.center) + offset])
            # Tip of the quartic is the stationary point.
            interval = mb.lower, mb.upper
            self._test_result(coeffs, interval, *np_roots(coeffs, interval))

            # Moreover, split the interval in the root
            interval = mb.lower, 0.0
            result = self.get_roots(coeffs, interval)
            ground_truth = np_roots(coeffs, interval)

            interval = 0.0, mb.upper
            result = np.sort(np.concatenate((result,
                                             self.get_roots(coeffs,
                                                            interval))))
            ground_truth = np.sort(np.concatenate((ground_truth,
                                                   np_roots(coeffs,
                                                            interval))))
            np.testing.assert_almost_equal(result, ground_truth,
                                           decimal=self.precision_places)
示例#10
0
    def test_small_on_big_metaball(self):
        mb_0 = Metaball(0.0, 0.5, 0.51)
        mb_1 = Metaball(1.5, 100.0, -1.5)

        # First interval, only big metaball, two roots.
        coeffs = mb_1.get_coeffs(True)
        interval = mb_1.lower, mb_0.lower
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))

        # Last interval, nothing in it.
        interval = mb_0.upper, mb_1.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # Small and big metaballs, two roots.
        coeffs = mb_0.get_coeffs(False) + mb_1.get_coeffs(True)
        interval = mb_0.lower, mb_0.upper
        self._test_result(coeffs, interval, *np_roots(coeffs, interval))
示例#11
0
    def test_one_metaball(self):
        # Regular two roots.
        for r in np.linspace(self.pixel_size / 4, 1.0 - self.pixel_size, 10):
            mb = Metaball(r, 1.0, 0.0)
            coeffs = mb.get_coeffs(True)
            interval = (mb.lower, mb.upper)
            self._test_result(coeffs, interval, -r, r)

        # One root left
        mb = Metaball(1.0, 2.0, 0.0)
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, mb.center - mb.r / 2
        self._test_result(coeffs, interval, -1.0, np.nan)

        # One root right
        interval = mb.center + mb.r / 2, mb.upper
        self._test_result(coeffs, interval, 1, np.nan)

        # Make interval end points stationary.
        coeffs = mb.get_coeffs(True)
        interval = (mb.lower, 0)
        self._test_result(coeffs, interval, -1, np.nan)
        interval = (0, mb.upper)
        self._test_result(coeffs, interval, 1, np.nan)

        # Put interval end points to roots.
        # In right endpoint.
        interval = mb.lower, -1.0
        self._test_result(coeffs, interval, -1.0)
        # In left endpoint.
        interval = -1.0, 0.0
        self._test_result(coeffs, interval)
        # By epsilon too far -> no root expected
        interval = mb.lower, -1 - self.pixel_size
        self._test_result(coeffs, interval)

        interval = 1.0, mb.upper
        # By epsilon too far -> no root expected
        interval = 1.0 + self.pixel_size, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # Left end point is a root.
        coeffs = coeffs - np.array([0, 0, 0, 0, f(coeffs, mb.center)])
        interval = 0.0, mb.upper
        self._test_result(coeffs, interval, 0.0)

        # Right end point is a root.
        interval = mb.lower, 0.0
        self._test_result(coeffs, interval, 0.0)

        # No roots
        coeffs = mb.get_coeffs(True)
        coeffs = coeffs - np.array([0, 0, 0, 0, f(coeffs, mb.center) + 1])
        interval = mb.lower, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots on the left from the stationary point
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, (mb.lower - mb.r) / 2
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots on the right from the stationary point
        coeffs = mb.get_coeffs(True)
        interval = mb.upper - (mb.upper - mb.r) / 2, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots because the metaball does not reach y = 1.
        mb = Metaball(0.0, 0.5, 0.0)
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)
示例#12
0
    def test_thickness(self):
        def test(coeffs,
                 roots,
                 expected_thickness,
                 expected_previous,
                 previous=np.nan,
                 last_derivative_sgn=-2,
                 expected_last_derivative_sgn=None):
            thickness_res, previous_res, last_derivative_sgn_res = \
                self.get_thickness_addition(coeffs,
                                            roots, previous,
                                            last_derivative_sgn)
            np.testing.assert_almost_equal(expected_thickness,
                                           thickness_res,
                                           decimal=self.precision_places)
            np.testing.assert_almost_equal(expected_previous,
                                           previous_res,
                                           decimal=self.precision_places)
            if expected_last_derivative_sgn is not None:
                np.testing.assert_almost_equal(expected_last_derivative_sgn,
                                               last_derivative_sgn_res)

        mb_0 = Metaball(1.0, 2.0, 0.0)
        coeffs = mb_0.get_coeffs(True)

        # Simple cases, no previous, no last accounted value.
        roots = 4 * [np.nan]
        test(coeffs, roots, 0.0, np.nan, np.nan)

        roots_base = [-2.5, -1, 1, 2.5, np.nan]

        for i in range(1, 5):
            roots[:i] = roots_base[:i]
            if i % 2 == 0:
                # Roots are coupled.
                test(coeffs, roots + [np.nan], i / 2 * 1.5, np.nan)
            else:
                # Previous is created.
                test(coeffs,
                     roots + [np.nan], (i - 1) / 2 * 1.5,
                     roots[i - 1],
                     expected_last_derivative_sgn=sgn(
                         f(derivative(coeffs), roots[i])))

        # Previous is not nan.
        roots = [-1, 1, 1.5, np.nan, np.nan]
        previous = -3
        test(coeffs,
             roots,
             2,
             roots[1],
             previous=previous,
             last_derivative_sgn=f(derivative(coeffs), previous))

        roots = [-1, 1, 2.5, 4, np.nan]
        previous = -3
        test(coeffs, roots, 3.5, np.nan, previous=previous)

        # The leftmost root was coupled before, just skip the current
        # first root.
        roots = [1, 2, np.nan, np.nan, np.nan]
        previous = np.nan
        last_accounted = 1 - self.pixel_size / 2
        last_derivative_sgn = sgn(f(derivative(coeffs), last_accounted))
        test(coeffs, roots, 0, roots[1], previous, last_derivative_sgn)

        # The leftmost root existed before, but was not coupled.
        # Take the root into account.
        roots = [1, 2, np.nan, np.nan, np.nan]
        previous = 1 - self.pixel_size / 2
        last_derivative_sgn = sgn(f(derivative(coeffs), previous))
        test(coeffs, roots, 1, np.nan, previous, last_derivative_sgn)

        # Extremum in the middle of the new roots, but the surrounding
        # roots lie on the opposite sides, thus take them into account.
        roots = [-2.1, -self.pixel_size / 4, self.pixel_size / 4, 2.1, np.nan]
        test(coeffs, roots, roots[1] - roots[0] + roots[3] - roots[2], np.nan)

        # Make the middle roots to be on the same slope of the extremum,
        # thus do not take them both into account.
        # First root is not coupled with anything, thus must be coupled
        # with one of them.
        roots = [-1, self.pixel_size / 4, self.pixel_size / 2, 2.5, np.nan]
        test(coeffs, roots, roots[1] - roots[0], roots[-2])

        # Create some previous value in order for the first root to be
        # coupled with some previous, then one of the two roots is saved
        # as previous.
        roots = [-1, self.pixel_size / 4, self.pixel_size / 2, np.nan, np.nan]
        previous = -2.5
        test(coeffs, roots, roots[0] - previous, roots[1], previous=previous)

        # Multiple roots.
        roots = [1, 1, 1, 1, np.nan]
        test(coeffs,
             roots,
             0,
             1,
             expected_last_derivative_sgn=sgn(f(derivative(coeffs), 1)))

        # Multiple roots with previous.
        previous = 1
        last_derivative_sgn = sgn(f(derivative(coeffs), previous))
        test(coeffs,
             roots,
             0,
             previous,
             expected_last_derivative_sgn=last_derivative_sgn)

        # Left multiple roots.
        roots = [-1, -1, 1.5, 1.7, np.nan]
        test(coeffs, roots, roots[2] - roots[0], np.nan)

        # Right multiple roots.
        roots = [-1, 1, 2.5, 2.5, np.nan]
        test(coeffs, roots, roots[1] - roots[0], roots[-2])

        # Stationary points as roots which are not extrema.
        roots = [-2, 2, np.nan, np.nan, np.nan]
        test(coeffs, roots, 4, np.nan, np.nan)

        # More than polynomial degree roots.
        roots = [-2.5, -1, 1, 2.5, 2.5]
        test(coeffs, roots, 3, np.nan)
示例#13
0
    def test_thickness(self):
        def test(coeffs, roots, expected_thickness, expected_previous,
                 previous=np.nan, last_derivative_sgn=-2,
                 expected_last_derivative_sgn=None):
            thickness_res, previous_res, last_derivative_sgn_res = \
                self.get_thickness_addition(coeffs,
                                            roots, previous,
                                            last_derivative_sgn)
            np.testing.assert_almost_equal(expected_thickness, thickness_res,
                                           decimal=self.precision_places)
            np.testing.assert_almost_equal(expected_previous, previous_res,
                                           decimal=self.precision_places)
            if expected_last_derivative_sgn is not None:
                np.testing.assert_almost_equal(expected_last_derivative_sgn,
                                               last_derivative_sgn_res)

        mb_0 = Metaball(1.0, 2.0, 0.0)
        coeffs = mb_0.get_coeffs(True)

        # Simple cases, no previous, no last accounted value.
        roots = 4 * [np.nan]
        test(coeffs, roots, 0.0, np.nan, np.nan)

        roots_base = [-2.5, -1, 1, 2.5, np.nan]

        for i in range(1, 5):
            roots[:i] = roots_base[:i]
            if i % 2 == 0:
                # Roots are coupled.
                test(coeffs, roots + [np.nan], i / 2 * 1.5, np.nan)
            else:
                # Previous is created.
                test(coeffs, roots + [np.nan], (i - 1) / 2 * 1.5, roots[i - 1],
                     expected_last_derivative_sgn=sgn(f(derivative(coeffs),
                                                        roots[i])))

        # Previous is not nan.
        roots = [-1, 1, 1.5, np.nan, np.nan]
        previous = -3
        test(coeffs, roots, 2, roots[1], previous=previous,
             last_derivative_sgn=f(derivative(coeffs), previous))

        roots = [-1, 1, 2.5, 4, np.nan]
        previous = -3
        test(coeffs, roots, 3.5, np.nan, previous=previous)

        # The leftmost root was coupled before, just skip the current
        # first root.
        roots = [1, 2, np.nan, np.nan, np.nan]
        previous = np.nan
        last_accounted = 1 - self.pixel_size / 2
        last_derivative_sgn = sgn(f(derivative(coeffs), last_accounted))
        test(coeffs, roots, 0, roots[1], previous, last_derivative_sgn)

        # The leftmost root existed before, but was not coupled.
        # Take the root into account.
        roots = [1, 2, np.nan, np.nan, np.nan]
        previous = 1 - self.pixel_size / 2
        last_derivative_sgn = sgn(f(derivative(coeffs), previous))
        test(coeffs, roots, 1, np.nan, previous, last_derivative_sgn)

        # Extremum in the middle of the new roots, but the surrounding
        # roots lie on the opposite sides, thus take them into account.
        roots = [-2.1, -self.pixel_size / 4, self.pixel_size / 4, 2.1, np.nan]
        test(coeffs, roots, roots[1] - roots[0] + roots[3] - roots[2], np.nan)

        # Make the middle roots to be on the same slope of the extremum,
        # thus do not take them both into account.
        # First root is not coupled with anything, thus must be coupled
        # with one of them.
        roots = [-1, self.pixel_size / 4, self.pixel_size / 2, 2.5, np.nan]
        test(coeffs, roots, roots[1] - roots[0], roots[-2])

        # Create some previous value in order for the first root to be
        # coupled with some previous, then one of the two roots is saved
        # as previous.
        roots = [-1, self.pixel_size / 4, self.pixel_size / 2, np.nan, np.nan]
        previous = -2.5
        test(coeffs, roots, roots[0] - previous, roots[1], previous=previous)

        # Multiple roots.
        roots = [1, 1, 1, 1, np.nan]
        test(coeffs, roots, 0, 1,
             expected_last_derivative_sgn=sgn(f(derivative(coeffs), 1)))

        # Multiple roots with previous.
        previous = 1
        last_derivative_sgn = sgn(f(derivative(coeffs), previous))
        test(coeffs, roots, 0, previous,
             expected_last_derivative_sgn=last_derivative_sgn)

        # Left multiple roots.
        roots = [-1, -1, 1.5, 1.7, np.nan]
        test(coeffs, roots, roots[2] - roots[0], np.nan)

        # Right multiple roots.
        roots = [-1, 1, 2.5, 2.5, np.nan]
        test(coeffs, roots, roots[1] - roots[0], roots[-2])

        # Stationary points as roots which are not extrema.
        roots = [-2, 2, np.nan, np.nan, np.nan]
        test(coeffs, roots, 4, np.nan, np.nan)

        # More than polynomial degree roots.
        roots = [-2.5, -1, 1, 2.5, 2.5]
        test(coeffs, roots, 3, np.nan)
示例#14
0
    def test_one_metaball(self):
        # Regular two roots.
        for r in np.linspace(self.pixel_size / 4, 1.0 - self.pixel_size, 10):
            mb = Metaball(r, 1.0, 0.0)
            coeffs = mb.get_coeffs(True)
            interval = (mb.lower, mb.upper)
            self._test_result(coeffs, interval, -r, r)

        # One root left
        mb = Metaball(1.0, 2.0, 0.0)
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, mb.center - mb.r / 2
        self._test_result(coeffs, interval, -1.0, np.nan)

        # One root right
        interval = mb.center + mb.r / 2, mb.upper
        self._test_result(coeffs, interval, 1, np.nan)

        # Make interval end points stationary.
        coeffs = mb.get_coeffs(True)
        interval = (mb.lower, 0)
        self._test_result(coeffs, interval, -1, np.nan)
        interval = (0, mb.upper)
        self._test_result(coeffs, interval, 1, np.nan)

        # Put interval end points to roots.
        # In right endpoint.
        interval = mb.lower, -1.0
        self._test_result(coeffs, interval, -1.0)
        # In left endpoint.
        interval = -1.0, 0.0
        self._test_result(coeffs, interval)
        # By epsilon too far -> no root expected
        interval = mb.lower, - 1 - self.pixel_size
        self._test_result(coeffs, interval)

        interval = 1.0, mb.upper
        # By epsilon too far -> no root expected
        interval = 1.0 + self.pixel_size, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # Left end point is a root.
        coeffs = coeffs - np.array([0, 0, 0, 0, f(coeffs, mb.center)])
        interval = 0.0, mb.upper
        self._test_result(coeffs, interval, 0.0)

        # Right end point is a root.
        interval = mb.lower, 0.0
        self._test_result(coeffs, interval, 0.0)

        # No roots
        coeffs = mb.get_coeffs(True)
        coeffs = coeffs - np.array([0, 0, 0, 0, f(coeffs, mb.center) + 1])
        interval = mb.lower, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots on the left from the stationary point
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, (mb.lower - mb.r) / 2
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots on the right from the stationary point
        coeffs = mb.get_coeffs(True)
        interval = mb.upper - (mb.upper - mb.r) / 2, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)

        # No roots because the metaball does not reach y = 1.
        mb = Metaball(0.0, 0.5, 0.0)
        coeffs = mb.get_coeffs(True)
        interval = mb.lower, mb.upper
        self._test_result(coeffs, interval, np.nan, np.nan)