コード例 #1
0
    def test_sample_paths_wiener(self):
        """Tests paths properties for Wiener process (dX = dW)."""
        def drift_fn(_, x):
            return tf.zeros_like(x)

        def vol_fn(_, x):
            return tf.expand_dims(tf.ones_like(x), -1)

        times = np.array([0.1, 0.2, 0.3])
        num_samples = 10000

        paths = self.evaluate(
            euler_sampling.sample(dim=1,
                                  drift_fn=drift_fn,
                                  volatility_fn=vol_fn,
                                  times=times,
                                  num_samples=num_samples,
                                  seed=42,
                                  time_step=0.005))

        means = np.mean(paths, axis=0).reshape([-1])
        covars = np.cov(paths.reshape([num_samples, -1]), rowvar=False)
        expected_means = np.zeros((3, ))
        expected_covars = np.minimum(times.reshape([-1, 1]),
                                     times.reshape([1, -1]))
        self.assertAllClose(means, expected_means, rtol=1e-2, atol=1e-2)
        self.assertAllClose(covars, expected_covars, rtol=1e-2, atol=1e-2)
コード例 #2
0
    def sample_paths(self,
                     times,
                     num_samples=1,
                     initial_state=None,
                     random_type=None,
                     seed=None,
                     swap_memory=True,
                     name=None,
                     time_step=None):
        """Returns a sample of paths from the process using Euler sampling.

    The default implementation uses the Euler scheme. However, for particular
    types of Ito processes more efficient schemes can be used.

    Args:
      times: Rank 1 `Tensor` of increasing positive real values. The times at
        which the path points are to be evaluated.
      num_samples: Positive scalar `int`. The number of paths to draw.
        Default value: 1.
      initial_state: `Tensor` of shape `[dim]`. The initial state of the
        process.
        Default value: None which maps to a zero initial state.
      random_type: Enum value of `RandomType`. The type of (quasi)-random number
        generator to use to generate the paths.
        Default value: None which maps to the standard pseudo-random numbers.
      seed: Python `int`. The random seed to use. If not supplied, no seed is
        set.
      swap_memory: A Python bool. Whether GPU-CPU memory swap is enabled for
        this op. See an equivalent flag in `tf.while_loop` documentation for
        more details. Useful when computing a gradient of the op since
        `tf.while_loop` is used to propagate stochastic process in time.
        Default value: True.
      name: Python string. The name to give this op.
        Default value: `None` which maps to `sample_paths` is used.
      time_step: Real scalar `Tensor`. The maximal distance between time points
        in grid in Euler scheme.

    Returns:
     A real `Tensor` of shape `[num_samples, k, n]` where `k` is the size of the
     `times`, and `n` is the dimension of the process.
    """
        default_name = self._name + '_sample_path'
        with tf.compat.v1.name_scope(name,
                                     default_name=default_name,
                                     values=[times, initial_state]):
            return euler_sampling.sample(self._dim,
                                         self._drift_fn,
                                         self._volatility_fn,
                                         times,
                                         num_samples=num_samples,
                                         initial_state=initial_state,
                                         random_type=random_type,
                                         time_step=time_step,
                                         seed=seed,
                                         swap_memory=swap_memory,
                                         dtype=self._dtype,
                                         name=name)
コード例 #3
0
    def test_antithetic_sample_paths_mean_2d(self):
        """Tests path properties for 2-dimentional anthithetic variates method.

    The same test as above but with `PSEUDO_ANTITHETIC` random type.
    We construct the following Ito processes.

    dX_1 = mu_1 sqrt(t) dt + s11 dW_1 + s12 dW_2
    dX_2 = mu_2 sqrt(t) dt + s21 dW_1 + s22 dW_2

    mu_1, mu_2 are constants.
    s_ij = a_ij t + b_ij

    For this process expected value at time t is (x_0)_i + 2/3 * mu_i * t^1.5.
    """
        mu = np.array([0.2, 0.7])
        a = np.array([[0.4, 0.1], [0.3, 0.2]])
        b = np.array([[0.33, -0.03], [0.21, 0.5]])

        def drift_fn(t, x):
            del x
            return mu * tf.sqrt(t)

        def vol_fn(t, x):
            del x
            return (a * t + b) * tf.ones([2, 2], dtype=t.dtype)

        times = np.array([0.1, 0.21, 0.32, 0.43, 0.55])
        num_samples = 5000
        x0 = np.array([0.1, -1.1])
        paths = self.evaluate(
            euler_sampling.sample(
                dim=2,
                drift_fn=drift_fn,
                volatility_fn=vol_fn,
                times=times,
                num_samples=num_samples,
                initial_state=x0,
                random_type=random.RandomType.PSEUDO_ANTITHETIC,
                time_step=0.01,
                seed=12134))

        self.assertAllClose(paths.shape, (num_samples, 5, 2), atol=0)
        means = np.mean(paths, axis=0)
        times = np.reshape(times, [-1, 1])
        expected_means = x0 + (2.0 / 3.0) * mu * np.power(times, 1.5)
        # Antithetic variates method produces better estimate than the
        # estimate with the `PSEUDO` random type
        self.assertAllClose(means, expected_means, rtol=5e-3, atol=5e-3)
コード例 #4
0
  def test_sample_paths_2d(self, random_type):
    """Tests path properties for 2-dimentional Ito process.

    We construct the following Ito processes.

    dX_1 = mu_1 sqrt(t) dt + s11 dW_1 + s12 dW_2
    dX_2 = mu_2 sqrt(t) dt + s21 dW_1 + s22 dW_2

    mu_1, mu_2 are constants.
    s_ij = a_ij t + b_ij

    For this process expected value at time t is (x_0)_i + 2/3 * mu_i * t^1.5.

    Args:
      random_type: Random number type defined by tff.math.random.RandomType
        enum.
    """
    mu = np.array([0.2, 0.7])
    a = np.array([[0.4, 0.1], [0.3, 0.2]])
    b = np.array([[0.33, -0.03], [0.21, 0.5]])

    def drift_fn(t, x):
      return mu * tf.sqrt(t) * tf.ones_like(x, dtype=t.dtype)

    def vol_fn(t, x):
      del x
      return (a * t + b) * tf.ones([2, 2], dtype=t.dtype)

    num_samples = 10000
    times = np.array([0.1, 0.21, 0.32, 0.43, 0.55])
    x0 = np.array([0.1, -1.1])
    paths = self.evaluate(
        euler_sampling.sample(
            dim=2,
            drift_fn=drift_fn, volatility_fn=vol_fn,
            times=times,
            num_samples=num_samples,
            initial_state=x0,
            time_step=0.01,
            seed=12134))

    self.assertAllClose(paths.shape, (num_samples, 5, 2), atol=0)
    means = np.mean(paths, axis=0)
    times = np.reshape(times, [-1, 1])
    expected_means = x0 + (2.0 / 3.0) * mu * np.power(times, 1.5)
    self.assertAllClose(means, expected_means, rtol=1e-2, atol=1e-2)
コード例 #5
0
  def test_sample_paths_dtypes(self):
    """Sampled paths have the expected dtypes."""
    for dtype in [np.float32, np.float64]:
      drift_fn = lambda t, x: tf.sqrt(t) * tf.ones_like(x, dtype=t.dtype)
      vol_fn = lambda t, x: t * tf.ones([1, 1], dtype=t.dtype)

      paths = self.evaluate(
          euler_sampling.sample(
              dim=1,
              drift_fn=drift_fn, volatility_fn=vol_fn,
              times=[0.1, 0.2],
              num_samples=10,
              initial_state=[0.1],
              time_step=0.01,
              seed=123,
              dtype=dtype))

      self.assertEqual(paths.dtype, dtype)
コード例 #6
0
    def test_sample_paths_1d(self):
        """Tests path properties for 1-dimentional Ito process.

    We construct the following Ito process.

    ````
    dX = mu * sqrt(t) * dt + (a * t + b) dW
    ````

    For this process expected value at time t is x_0 + 2/3 * mu * t^1.5 .
    """
        mu = 0.2
        a = 0.4
        b = 0.33

        def drift_fn(t, x):
            return mu * tf.sqrt(t) * tf.ones_like(x, dtype=t.dtype)

        def vol_fn(t, x):
            del x
            return (a * t + b) * tf.ones([1, 1], dtype=t.dtype)

        times = np.array([0.1, 0.21, 0.32, 0.43, 0.55])
        num_samples = 10000
        x0 = np.array([0.1])
        paths = self.evaluate(
            euler_sampling.sample(dim=1,
                                  drift_fn=drift_fn,
                                  volatility_fn=vol_fn,
                                  times=times,
                                  num_samples=num_samples,
                                  initial_state=x0,
                                  time_step=0.01,
                                  seed=12134))

        self.assertAllClose(paths.shape, (num_samples, 5, 1), atol=0)
        means = np.mean(paths, axis=0).reshape(-1)
        expected_means = x0 + (2.0 / 3.0) * mu * np.power(times, 1.5)
        self.assertAllClose(means, expected_means, rtol=1e-2, atol=1e-2)