def test_conv1d_simplex_bounds_shape(self, dtype):
        num_vertices = 41
        batch_size = 11
        input_length = 13
        kernel_length = 5
        input_channels = 3
        output_channels = 2
        padding = 'VALID'
        strides = (2, )

        # Expected output dimensions, based on convolution settings.
        output_length = 5

        w = tf.placeholder(dtype=dtype,
                           shape=(kernel_length, input_channels,
                                  output_channels))
        b = tf.placeholder(dtype=dtype, shape=(output_channels, ))
        vertices = tf.placeholder(dtype=dtype,
                                  shape=(batch_size, num_vertices,
                                         input_length, input_channels))
        centres = tf.placeholder(dtype=dtype,
                                 shape=(batch_size, input_length,
                                        input_channels))
        r = .2

        bounds_in = ibp.SimplexBounds(vertices, centres, r)
        bounds_out = bounds_in.apply_conv1d(None, w, b, padding, strides)
        lb_out, ub_out = bounds_out.lower, bounds_out.upper

        self.assertEqual(dtype, lb_out.dtype)
        self.assertEqual(dtype, ub_out.dtype)
        self.assertEqual((batch_size, output_length, output_channels),
                         lb_out.shape)
        self.assertEqual((batch_size, output_length, output_channels),
                         ub_out.shape)
    def add_verifiable_objective(self,
                                 minibatch,
                                 vocab_table,
                                 perturbation,
                                 stop_gradient=False):
        # pylint: disable=g-missing-docstring
        data_batch = self.embed_dataset(minibatch, vocab_table)
        _, vertices = self.compute_mask_vertices(data_batch, perturbation)

        def classifier(embedded_inputs):
            representation = self.sentence_representer(embedded_inputs,
                                                       data_batch.length)
            return self.linear_classifier(representation)

        # Verification graph.
        network = ibp.VerifiableModelWrapper(classifier)
        network(data_batch.embedded_inputs)

        input_bounds = ibp.SimplexBounds(
            vertices=vertices,
            nominal=data_batch.embedded_inputs,
            r=(self.delta if not stop_gradient else self.config['delta']))
        network.propagate_bounds(input_bounds)

        # Calculate the verifiable objective.
        verifiable_obj = verifiable_objective(network,
                                              data_batch.sentiment,
                                              margin=1.)

        return verifiable_obj
    def test_linear_simplex_bounds_shape(self, dtype):
        vocab_size = 103
        batch_size = 11
        input_size = 7
        output_size = 5

        w = tf.placeholder(dtype=dtype, shape=(input_size, output_size))
        b = tf.placeholder(dtype=dtype, shape=(output_size, ))
        embedding = tf.placeholder(dtype=dtype, shape=(vocab_size, input_size))
        centres = tf.placeholder(dtype=dtype, shape=(batch_size, input_size))
        r = .2

        bounds_in = ibp.SimplexBounds(embedding, centres, r)
        bounds_out = bounds_in.apply_linear(None, w, b)
        lb_out, ub_out = bounds_out.lower, bounds_out.upper

        self.assertEqual(dtype, lb_out.dtype)
        self.assertEqual(dtype, ub_out.dtype)
        self.assertEqual((batch_size, output_size), lb_out.shape)
        self.assertEqual((batch_size, output_size), ub_out.shape)
    def test_linear_bounds_on_embedding_layer(self, dtype, tol):
        w = tf.constant([[1.0, 2.0, 3.0], [4.0, -5.0, 6.0]], dtype=dtype)
        b = tf.constant([0.01, -0.02, 0.03], dtype=dtype)
        embedding = tf.constant([[0.0, 0.0], [10.0, 10.0], [0.0, -20.0]],
                                dtype=dtype)
        centres = tf.constant([[7.0, 6.0]], dtype=dtype)
        r = .1
        # Simplex vertices: [6.3, 5.4], [7.3, 6.4], and [6.3, 3.4].
        # They map to: [27.91, -14.42, 51.33], [32.91, -17.42, 60.33],
        # and [19.91, -4.42, 39.33].

        bounds_in = ibp.SimplexBounds(embedding, centres, r)
        bounds_out = bounds_in.apply_linear(None, w, b)
        lb_out, ub_out = bounds_out.lower, bounds_out.upper

        lb_out_exp = np.array([[19.91, -17.42, 39.33]])
        ub_out_exp = np.array([[32.91, -4.42, 60.33]])

        with self.test_session() as session:
            lb_out_act, ub_out_act = session.run((lb_out, ub_out))
            self.assertAllClose(lb_out_exp, lb_out_act, atol=tol, rtol=tol)
            self.assertAllClose(ub_out_exp, ub_out_act, atol=tol, rtol=tol)
    def test_conv1d_simplex_bounds(self, dtype, tol):
        num_vertices = 37
        batch_size = 53
        input_length = 17
        kernel_length = 7
        input_channels = 3
        output_channels = 2
        padding = 'VALID'
        strides = (2, )

        w = tf.random_normal(dtype=dtype,
                             shape=(kernel_length, input_channels,
                                    output_channels))
        b = tf.random_normal(dtype=dtype, shape=(output_channels, ))
        vertices = tf.random_normal(dtype=dtype,
                                    shape=(batch_size, num_vertices,
                                           input_length, input_channels))
        centres = tf.random_normal(dtype=dtype,
                                   shape=(batch_size, input_length,
                                          input_channels))
        r = .2

        bounds_in = ibp.SimplexBounds(vertices, centres, r)
        bounds_out = bounds_in.apply_conv1d(None, w, b, padding, strides[0])
        lb_out, ub_out = bounds_out.lower, bounds_out.upper

        # Compare against equivalent linear layer.
        bounds_out_lin = _materialised_conv_simplex_bounds(
            w, b, padding, strides, bounds_in)
        lb_out_lin, ub_out_lin = bounds_out_lin.lower, bounds_out_lin.upper

        with self.test_session() as session:
            (lb_out_val, ub_out_val, lb_out_lin_val,
             ub_out_lin_val) = session.run(
                 (lb_out, ub_out, lb_out_lin, ub_out_lin))
            self.assertAllClose(lb_out_val, lb_out_lin_val, atol=tol, rtol=tol)
            self.assertAllClose(ub_out_val, ub_out_lin_val, atol=tol, rtol=tol)