def conv1d_md(input, filters, image_shape, filter_shape, border_mode='valid',
              subsample=(1,), filter_flip=True):
    """
    using multiple dot products
    """
    if border_mode not in ('valid', 0, (0,)):
        raise RuntimeError("Unsupported border_mode for conv1d_md: "
                           "%s" % border_mode)

    batch_size, num_input_channels, input_length = image_shape
    num_filters, num_input_channels_, filter_length = filter_shape
    stride = subsample[0]

    if filter_length % stride > 0:
        raise RuntimeError("Filter length (%d) is not a multiple of the "
                           "stride (%d)" % (filter_length, stride))

    num_steps = filter_length // stride
    output_length = (input_length - filter_length + stride) // stride
    output_shape = (batch_size, num_filters, output_length)

    filters_flipped = filters[:, :, ::-1] if filter_flip else filters

    conved = T.zeros(output_shape)

    for num in range(num_steps):
        shift = num * stride
        length = (input_length - shift) // filter_length

        if length == 0:
            # we can safely skip this product, it doesn't contribute to the
            # final convolution.
            continue

        r_input_shape = (batch_size, num_input_channels, length, filter_length)
        r_input = input[
            :, :, shift:length * filter_length + shift].reshape(r_input_shape)

        # shape (b, l, n_filters)
        r_conved = T.tensordot(r_input, filters_flipped,
                               np.asarray([[1, 3], [1, 2]]))
        r_conved = r_conved.dimshuffle(0, 2, 1)  # shape is (b, n_filters, l)
        conved = T.set_subtensor(conved[:, :, num::num_steps], r_conved)

    return conved


# TODO: conv1d_md_channelslast?

# 2D convolutions

# TODO
dataset/ETHPy150Open Lasagne/Lasagne/lasagne/theano_extensions/conv.py/conv1d_md/original