def step(self, data):
        """
        Run convolution over a single position. The data must be exactly as wide as the convolution filters.

        :param data: Shape: (batch_size, kernel_width, num_hidden).
        :return: Single result of a convolution. Shape: (batch_size, 1, num_hidden).
        """

        # As we only run convolution over a single window that is exactly the size of the convolutional filter
        # we can use FullyConnected instead of Convolution for efficiency reasons. Additionally we do not need to
        # perform any masking.

        num_hidden = self._pre_activation_num_hidden()

        # (batch_size, num_hidden, kernel_width)
        data = mx.sym.swapaxes(data, dim1=1, dim2=2)
        # (batch_size, num_hidden * kernel_width)
        data = mx.sym.reshape(data, shape=(0, -3))
        # (preact_num_hidden, num_hidden * kernel_width)
        weight = mx.sym.reshape(self.conv_weight, shape=(0, -3))
        data_conv = mx.sym.FullyConnected(data=data,
                                          weight=weight,
                                          bias=self.conv_bias,
                                          num_hidden=num_hidden)
        # (batch_size, num_hidden, 1)
        data_conv = mx.sym.expand_dims(data_conv, axis=2)
        return self._post_convolution(data_conv)
Run convolution over a single position. The data must be exactly as wide as the convolution filters.

        :param data: Shape: (batch_size, kernel_width, num_hidden).
        :return: Single result of a convolution. Shape: (batch_size, 1, num_hidden).