def test_invalid_interpolate_parameter_value(self): """Test where a value to interpolate lies outside the spline points.""" x_data1 = np.linspace(-5.0, 5.0, num=11) x_data2 = np.linspace(0.0, 10.0, num=11) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2]) x_data_series = tf.stack(x_series, axis=0) y_data_series = tf.stack(y_series, axis=0) # num_test_values = 3 search_args = tf.constant([[-5.2, 0.0, 5.3], [2.2, 1.8, 5.0]], dtype=tf.float64) x_test = tf.stack(search_args, axis=0) spline = cubic.build_spline(x_data_series, y_data_series) msg = ("Failed to catch that the test vector data lies outside of " "spline range") with self.assertRaises(tf.errors.InvalidArgumentError, msg=msg) as cm: self.evaluate(cubic.interpolate(x_test, spline, validate_args=True)) print(cm.exception)
def test_error_calc(self): """Test that the deviation between the interpolated values and the actual values. This should be less than 0.02. This value was derived by running the same test with scipy cubic interpolation """ sampling_points = 1000 spline_x = np.linspace(0.0, 10.0, num=11, dtype=np.float64) spline_y = [1.0 / (1.0 + x * x) for x in spline_x] x_series = np.array([spline_x]) y_series = np.array([spline_y]) spline = cubic.build_spline(x_series, y_series) # There is an error if we go to 10.0 test_range_x = np.linspace(0.0, 9.99, num=sampling_points, dtype=np.float64) search_args = tf.constant(np.array([test_range_x]), dtype=tf.float64) projected_y = cubic.interpolate(search_args, spline) expected_y = tf.constant([[1.0 / (1.0 + x * x) for x in test_range_x]], dtype=tf.float64) errors = expected_y - projected_y deviation = self.evaluate(tfp.stats.stddev(errors[0], sample_axis=0)) limit = 0.02 self.assertLess(deviation, limit)
def test_compare_shape_conformance_of_interpolate(self): """Test that the shape of the result of the interpolate method is correct. i.e. given x_points.shape (num_splines, spline_length) y_points.shape (num_splines, spline_length) x_test.shape (num_splines, num_test_values) then interpolate(x_test, spline ) -> shape(num_splines, num_test_values) """ # num splines = 2 # spline_length = 11 x_data1 = np.linspace(-5.0, 5.0, num=11) x_data2 = np.linspace(0.0, 10.0, num=11) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2]) # num_test_values = 3 search_args = tf.constant([[-1.2, 0.0, 0.3], [2.2, 1.8, 5.0]], dtype=tf.float64) x_data_series = tf.stack(x_series, axis=0) y_data_series = tf.stack(y_series, axis=0) x_test = tf.stack(search_args, axis=0) spline = cubic.build_spline(x_data_series, y_data_series) predicted = cubic.interpolate(x_test, spline) self.assertAllEqual(tf.shape(x_test), tf.shape(predicted)) # num_test_values = 13 search_args11 = tf.constant( [[-1.2, 0.0, 0.3, 1.2, 2.1, 0.8, 0.0, 0.3, 1.2, 2.1, 0.8], [2.2, 1.8, 5.0, 2.2, 1.8, 5.0, 5.0, 2.2, 1.8, 5.0, 2.2]], dtype=tf.float64) x_test11 = tf.stack(search_args11, axis=0) predicted11 = cubic.interpolate(x_test11, spline) self.assertAllEqual(tf.shape(x_test11), tf.shape(predicted11))
def test_invalid_interpolate_parameter_shape(self): """Test shape(x_points)[0] != shape(test_x)[0].""" x_data1 = np.linspace(-5.0, 5.0, num=11) x_data2 = np.linspace(0.0, 10.0, num=11) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2]) x_data_series = tf.stack(x_series, axis=0) y_data_series = tf.stack(y_series, axis=0) search_args = tf.constant([[-1.2, 0.0, 0.3]], dtype=tf.float64) x_test = tf.stack(search_args, axis=0) spline = cubic.build_spline(x_data_series, y_data_series) msg = "Failed to catch that the test vector has less rows than x_points" with self.assertRaises(ValueError, msg=msg): cubic.interpolate(x_test, spline)
def interpolate(self, x_values, y_values, name=None): """Performs 2-D interpolation on a specified set of points. Args: x_values: Real-valued `Tensor` of shape `batch_shape + [num_points]`. Defines the x-coordinates at which the interpolation should be performed. Note that `batch_shape` should be the same as in the underlying data. y_values: A `Tensor` of the same shape and `dtype` as `x_values`. Defines the y-coordinates at which the interpolation should be performed. name: Python `str` name prefixed to ops created by this function. Default value: `None` which is mapped to the default name `interpolate`. Returns: A `Tensor` of the same shape and `dtype` as `x_values`. Represents the interpolated values of the function on for the coordinates `(x_values, y_values)`. """ name = name or self._name + "_interpolate" with tf.name_scope(name): x_values = tf.convert_to_tensor(x_values, dtype=self._dtype, name="x_values") y_values = tf.convert_to_tensor(y_values, dtype=self._dtype, name="y_values") # Broadcast `y_values` to the number of `x_data` points y_values = tf.expand_dims(y_values, axis=-2) # For each `x_data` point interpolate values of the function at the # y_values. Shape of `xy_values` is # batch_shape + `[num_x_data_points, num_points]`. xy_values = cubic.interpolate(y_values, self._spline_yz, name="interpolation_in_y_direction") # Interpolate the value of the function along x-direction # Prepare xy_values for linear interpolation. Put the batch dims in front xy_rank = xy_values.shape.rank perm = [xy_rank - 1] + list(range(xy_rank - 1)) # Shape [num_points] + batch_shape + [num_x_data_points] yx_values = tf.transpose(xy_values, perm=perm) # Get the permutation to the original shape perm_original = list(range(1, xy_rank)) + [0] # Reshape to [num_points] + batch_shape + [1] x_values = tf.expand_dims(tf.transpose(x_values, [xy_rank - 2] + list(range(xy_rank - 2))), axis=-1) # Interpolation takes care of braodcasting z_values = linear.interpolate(x_values, self._xdata, yx_values) return tf.squeeze(tf.transpose(z_values, perm=perm_original), axis=-2)
def interpolate(self, x_values, y_values, name=None): """Performs 2-D interpolation on a specified set of points. Args: x_values: Real-valued `Tensor` of rank 1. Defines the x-coordinates at which the interpolation should be performed. y_values: Rank 1 `Tensor` of the same `dtype` as `x_values`. Defines the y-coordinates at which the interpolation should be performed. name: Python `str` name prefixed to ops created by this function. Default value: `None` which is mapped to the default name `interpolate`. Returns: A `Tensor` of the same `dtype` as `x_values` and of shape `x_values.shape + y_values.shape`. Represents the interpolated values of the function on the grid `[x_values, y_values]` """ name = name or self._name + "_interpolate" with tf.name_scope(name): x_values = tf.convert_to_tensor(x_values, dtype=self._dtype, name="x_values") y_values = tf.convert_to_tensor(y_values, dtype=self._dtype, name="y_values") num_x_data = self._xdata.shape.as_list()[-1] num_y_values = y_values.shape.as_list()[-1] # Broadcast `y_values` to the number of `x_data` points y_values = ( tf.expand_dims(y_values, 0) + tf.zeros([num_x_data, num_y_values], dtype=y_values.dtype)) # For each `x_data` point interpolate values of the function at the # y_values. Shape of `xy_values` is `[num_x_data, num_y_values]`. xy_values = cubic.interpolate(y_values, self._spline_yz, name="interpolation_in_y_direction") # Interpolate the value of the function along x-direction # Prepare xy_values for linear interpolation. Put the batch dims in front xy_rank = xy_values.shape.rank perm = [xy_rank - 1] + list(range(xy_rank - 1)) yx_values = tf.transpose(xy_values, perm=perm) # Get the permutation to the original shape perm_original = list(range(1, xy_rank)) + [0] # Interpolation takes care of braodcasting z_values = linear.interpolate(x_values, self._xdata, yx_values) return tf.transpose(z_values, perm=perm_original)
def test_dtype_conversion_float64_32(self): """Test specifying float64 data but requiring conversion to float32.""" x_data1 = np.linspace(-5.0, 5.0, num=11, dtype=np.float64) x_data2 = np.linspace(0.0, 10.0, num=11, dtype=np.float64) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2], dtype=np.float64) search_args = tf.constant([[-1.2, 0.0, 0.3], [2.2, 1.8, 5.0]], dtype=tf.float64) spline2 = cubic.build_spline(x_series, y_series, dtype=tf.float32) msg = "Tensor conversion from float64 to float32 should fail here" with self.assertRaises(ValueError, msg=msg) as cm: self.evaluate( cubic.interpolate(search_args, spline2, dtype=tf.float32)) print(cm)
def test_compare_spline_32(self): x_data1 = np.linspace(-5.0, 5.0, num=11, dtype=np.float32) x_data2 = np.linspace(0.0, 10.0, num=11, dtype=np.float32) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2], dtype=np.float32) search_args = tf.constant([[-1.2, 0.0, 0.3], [2.2, 1.8, 5.0]], dtype=tf.float32) spline2 = cubic.build_spline(x_series, y_series) result = tf.reshape(cubic.interpolate(search_args, spline2), [6]) expected = tf.constant([ 0.401153371166, 1.0, 0.927547412565, 0.144129651521, 0.194406085855, 0.037037037037 ], dtype=tf.float32) self.assertAllClose(expected, result)
def test_build_and_interpolate(self): """Test a combined call by just calling interpolate.""" # num splines = 2 # spline_length = 11 x_data1 = np.linspace(-5.0, 5.0, num=11) x_data2 = np.linspace(0.0, 10.0, num=11) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2]) # num_test_values = 3 search_args = tf.constant([[-1.2, 0.0, 0.3], [2.2, 1.8, 5.0]], dtype=tf.float64) x_data_series = tf.stack(x_series, axis=0) y_data_series = tf.stack(y_series, axis=0) x_test = tf.stack(search_args, axis=0) spline = cubic.SplineParameters(x_data_series, y_data_series, None) predicted = cubic.interpolate(x_test, spline) self.assertAllEqual(tf.shape(x_test), tf.shape(predicted))
def test_validate_args_interpolate(self): """Test that validation can be turned off in the interpolate call.""" x_data1 = np.linspace(-5.0, 5.0, num=11) x_data2 = np.linspace(0.0, 10.0, num=11) x_series = np.array([x_data1, x_data2]) y_data1 = [1.0 / (1.0 + x * x) for x in x_data1] y_data2 = [1.0 / (2.0 + x * x) for x in x_data2] y_series = np.array([y_data1, y_data2]) x_data_series = tf.stack(x_series, axis=0) y_data_series = tf.stack(y_series, axis=0) # num_test_values = 3 search_args = tf.constant([[-5.2, 0.0, 5.3], [2.2, 1.8, 5.0]], dtype=tf.float64) x_test = tf.stack(search_args, axis=0) spline = cubic.build_spline(x_data_series, y_data_series) # this should not fail with a validation error but a separate error # thrown by gather_nd msg = "The error should be an invalid argument" with self.assertRaises(tf.errors.InvalidArgumentError, msg=msg) as cm: self.evaluate( cubic.interpolate(x_test, spline, validate_args=False)) print(cm.exception)