Example #1
0
    def test_bracket_batching(self):
        """Tests that bracketing works in batching mode."""
        wolfe_threshold = 1e-6
        # We build an example function with 4 batches, each for one of the
        # following cases:
        # - a) Minimum bracketed from the beginning.
        # - b) Minimum bracketed after one expansion.
        # - c) Needs bisect from the beginning.
        # - d) Needs one round of expansion and then bisect.
        x = tf.constant([0.0, 1.0, 5.0])
        y = tf.constant([[1.0, 1.2, 1.1], [1.0, 0.9, 1.2], [1.0, 1.1, 1.2],
                         [1.0, 0.9, 1.1]])
        dy = tf.constant([[-0.8, 0.6, -0.8], [-0.8, -0.7, 0.6],
                          [-0.8, -0.7, -0.8], [-0.8, -0.7, -0.8]])
        fun = test_function_x_y_dy(x, y, dy, eps=0.1)

        val_a = hzl._apply(fun, tf.zeros(4))  # Values at zero.
        val_b = hzl._apply(fun, tf.ones(4))  # Values at initial step.
        f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

        expected_left = np.array([0.0, 1.0, 0.0, 0.0])
        expected_right = np.array([1.0, 5.0, 0.5, 2.5])

        result = self.evaluate(
            hzl.bracket(fun, val_a, val_b, f_lim, max_iterations=5))
        self.assertEqual(result.num_evals,
                         2)  # Once bracketing, once bisecting.
        self.assertTrue(np.all(result.stopped))
        self.assertTrue(np.all(~result.failed))
        self.assertTrue(np.all(result.left.df < 0))  # Opposite slopes.
        self.assertTrue(np.all(result.right.df >= 0))
        self.assertArrayNear(result.left.x, expected_left, 1e-5)
        self.assertArrayNear(result.right.x, expected_right, 1e-5)
Example #2
0
  def test_bisect_batching(self):
    """Tests that bisect works in batching mode."""
    wolfe_threshold = 1e-6
    # Let's build our example function with 4 batches, each evaluating a
    # different poly. They all have negative slopes both on 0.0 and 1.0,
    # but different slopes (positive, negative) and values (low enough, too
    # high) on their midpoint.
    x = np.array([0.0, 0.5, 1.0])
    y = np.array([[1.0, 0.6, 1.2],
                  [1.0, 0.6, 1.2],
                  [1.0, 1.6, 1.2],
                  [1.0, 1.6, 1.2]])
    dy = np.array([[-0.8, 0.6, -0.7],
                   [-0.8, -0.4, -0.7],
                   [-0.8, 0.8, -0.7],
                   [-0.8, -0.4, -0.7]])
    fun = test_function_x_y_dy(x, y, dy)

    val_a = hzl._apply(fun, tf.zeros(4))  # Values at zero.
    val_b = hzl._apply(fun, tf.ones(4))  # Values at initial step.
    f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

    expected_left = np.array([0.0, 0.5, 0.0, 0.0])
    expected_right = np.array([0.5, 0.75, 0.5, 0.25])

    result = self.evaluate(hzl.bisect(fun, val_a, val_b, f_lim))
    self.assertTrue(np.all(result.stopped))
    self.assertTrue(np.all(~result.failed))
    self.assertTrue(np.all(result.left.df < 0))
    self.assertTrue(np.all(result.right.df >= 0))
    self.assertArrayNear(result.left.x, expected_left, 1e-5)
    self.assertArrayNear(result.right.x, expected_right, 1e-5)
Example #3
0
 def eval_update(fun, p=lambda x: x):
     val_a = hzl._apply(fun, p(0.0))
     val_b = hzl._apply(fun, p(1.0))
     val_trial = hzl._apply(fun, p(0.6))
     f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))
     return self.evaluate(
         hzl.update(fun, val_a, val_b, val_trial, f_lim))
Example #4
0
    def test_update_batching(self):
        """Tests that update function works in batching mode."""
        wolfe_threshold = 1e-6
        # We build an example function with 4 batches, each for one of the
        # following cases:
        # - a) Trial point has positive slope, so works as right end point.
        # - b) Trial point has negative slope and value is not too large,
        #      so works as left end point.
        # - c) Trial point has negative slope but the value is too high,
        #      bisect is used to squeeze the interval.
        # - d) Trial point is outside of the (a, b) interval.
        x = np.array([0.0, 0.6, 1.0])
        y = np.array([[1.0, 1.2, 1.1], [1.0, 0.9, 1.2], [1.0, 1.1, 1.2],
                      [1.0, 1.1, 1.2]])
        dy = np.array([[-0.8, 0.6, 0.6], [-0.8, -0.7, 0.6], [-0.8, -0.7, 0.6],
                       [-0.8, -0.7, 0.6]])
        fun = test_function_x_y_dy(x, y, dy)

        val_a = hzl._apply(fun, tf.zeros(4))  # Values at zero.
        val_b = hzl._apply(fun, tf.ones(4))  # Values at initial step.
        val_trial = hzl._apply(fun, [0.6, 0.6, 0.6, 1.5])
        f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

        expected_left = np.array([0.0, 0.6, 0.0, 0.0])
        expected_right = np.array([0.6, 1.0, 0.3, 1.0])

        result = self.evaluate(hzl.update(fun, val_a, val_b, val_trial, f_lim))
        self.assertEqual(result.num_evals, 1)  # Had to do bisect once.
        self.assertTrue(np.all(result.stopped))
        self.assertTrue(np.all(~result.failed))
        self.assertTrue(np.all(result.left.df < 0))  # Opposite slopes.
        self.assertTrue(np.all(result.right.df >= 0))
        self.assertArrayNear(result.left.x, expected_left, 1e-5)
        self.assertArrayNear(result.right.x, expected_right, 1e-5)
Example #5
0
  def test_bisect_simple(self):
    """Tests that bisect works on a 1 variable scalar valued function."""
    wolfe_threshold = 1e-6
    x = np.array([0.0, 0.5, 1.0])
    y = np.array([1.0, 0.6, 1.2])
    dy = np.array([-0.8, 0.6, -0.7])
    fun = test_function_x_y_dy(x, y, dy)

    val_a = hzl._apply(fun, 0.0)  # Value at zero.
    val_b = hzl._apply(fun, 1.0)  # Value at initial step.
    f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

    result = self.evaluate(hzl.bisect(fun, val_a, val_b, f_lim))
    self.assertEqual(result.right.x, 0.5)
Example #6
0
  def test_update_simple(self):
    """Tests that update works on a single line function."""
    # Example where trial point works as new left end point.
    wolfe_threshold = 1e-6
    x = np.array([0.0, 0.6, 1.0])
    y = np.array([1.0, 0.9, 1.2])
    dy = np.array([-0.8, -0.7, 0.6])
    fun = test_function_x_y_dy(x, y, dy)

    val_a = hzl._apply(fun, 0.0)
    val_b = hzl._apply(fun, 1.0)
    val_trial = hzl._apply(fun, 0.6)
    f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

    result = self.evaluate(hzl.update(fun, val_a, val_b, val_trial, f_lim))
    self.assertEqual(result.num_evals, 0)  # No extra evaluations needed.
    self.assertTrue(result.stopped)
    self.assertTrue(~result.failed)
    self.assertAlmostEqual(result.left.x, 0.6)
    self.assertAlmostEqual(result.right.x, 1.0)
    self.assertLess(result.left.df, 0)  # Opposite slopes.
    self.assertGreaterEqual(result.right.df, 0)
Example #7
0
  def test_bracket_simple(self):
    """Tests that bracketing works on a 1 variable scalar valued function."""
    # Example crafted to require one expansion during bracketing, and then
    # some bisection; same as case (d) in test_bracket_batching below.
    wolfe_threshold = 1e-6
    x = np.array([0.0, 1.0, 2.5, 5.0])
    y = np.array([1.0, 0.9, -2.0, 1.1])
    dy = np.array([-0.8, -0.7, 1.6, -0.8])
    fun = test_function_x_y_dy(x, y, dy)

    val_a = hzl._apply(fun, 0.0)  # Value at zero.
    val_b = hzl._apply(fun, 1.0)  # Value at initial step.
    f_lim = val_a.f + (wolfe_threshold * tf.abs(val_a.f))

    result = self.evaluate(
        hzl.bracket(fun, val_a, val_b, f_lim, max_iterations=5))

    self.assertEqual(result.iteration, 1)  # One expansion.
    self.assertEqual(result.num_evals, 2)  # Once bracketing, once bisecting.
    self.assertEqual(result.left.x, 0.0)
    self.assertEqual(result.right.x, 2.5)
    self.assertLess(result.left.df, 0)  # Opposite slopes.
    self.assertGreaterEqual(result.right.df, 0)
Example #8
0
 def eval_secant2(fun, p=lambda x: x):
     val_0 = hzl._apply(fun, p(0.0))
     val_a = hzl._apply(fun, p(1.0))
     val_b = hzl._apply(fun, p(2.0))
     f_lim = val_0.f + (wolfe_threshold * tf.abs(val_0.f))
     return self.evaluate(hzl.secant2(fun, val_0, val_a, val_b, f_lim))