예제 #1
0
 def test_ifft1_returns_type_of_original_input(self):
     d = 8
     input = torch.randn(6, d)
     res = fft.fft1(input).double()
     recon = fft.ifft1(res)
     self.assertEqual(input.size(), recon.size())
     self.assertLess(torch.norm(input.double() - recon), 1e-5)
     self.assertTrue(isinstance(res, torch.DoubleTensor))
예제 #2
0
    def test_ifft1_computes_ifft_of_1d_input_with_odd_size(self):
        d = 9
        input = torch.randn(d)

        res = fft.fft1(input)
        recon = fft.ifft1(res)
        self.assertEqual(input.size(), recon.size())
        self.assertLess(torch.norm(input - recon), 1e-5)
예제 #3
0
    def test_ifft1_computes_ifft_of_2d_input(self):
        d = 8
        input = torch.randn(6, d)

        res = fft.fft1(input)
        recon = fft.ifft1(res)
        self.assertEqual(input.size(), recon.size())
        self.assertLess(torch.norm(input - recon), 1e-5)
예제 #4
0
def test_ifft1_returns_type_of_original_input():
    d = 8
    input = torch.randn(6, d)
    res = fft.fft1(input).double()
    recon = fft.ifft1(res)
    assert input.size() == recon.size()
    assert torch.norm(input.double() - recon) < 1e-5
    assert isinstance(res, torch.DoubleTensor)
예제 #5
0
def test_ifft1_computes_ifft_of_2d_input():
    d = 8
    input = torch.randn(6, d)

    res = fft.fft1(input)
    recon = fft.ifft1(res)
    assert input.size() == recon.size()
    assert torch.norm(input - recon) < 1e-5
예제 #6
0
def test_ifft1_computes_ifft_of_1d_input_with_odd_size():
    d = 9
    input = torch.randn(d)

    res = fft.fft1(input)
    recon = fft.ifft1(res, input.size())
    assert input.size() == recon.size()
    assert torch.norm(input - recon) < 1e-5
예제 #7
0
def circulant_matmul(circulant_column, tensor):
    """
    Performs a matrix multiplication CM where the tensor C is circulant.
    Args:
        - circulant_column (vector n) - First column of the circulant tensor C.
        - tensor (tensor n x p) - Matrix or vector to multiply the Toeplitz tensor with.
    Returns:
        - tensor
    """
    if circulant_column.ndimension() != 1 or tensor.ndimension() != 2:
        raise RuntimeError(
            'All inputs to CirculantMV should be vectors (first column c and row r of the Toeplitz \
                            tensor plus the target vector vector).')

    if len(circulant_column) != len(tensor):
        raise RuntimeError(
            'c and r should have the same length (Toeplitz matrices are necessarily square).'
        )

    if type(circulant_column) != type(tensor):
        raise RuntimeError('The types of all inputs to ToeplitzMV must match.')

    output_dims = tensor.ndimension()
    if output_dims == 1:
        tensor = tensor.unsqueeze(1)

    if len(circulant_column) == 1:
        output = (circulant_column.view(1, 1).mv(tensor))

    else:
        fft_M = fft.fft1(tensor.t().contiguous())
        fft_c = fft.fft1(circulant_column).expand_as(fft_M)
        fft_product = fft_M.new(*fft_M.size()).zero_()

        fft_product[:, :, 0].addcmul_(fft_c[:, :, 0], fft_M[:, :, 0])
        fft_product[:, :, 0].addcmul_(-1, fft_c[:, :, 1], fft_M[:, :, 1])
        fft_product[:, :, 1].addcmul_(fft_c[:, :, 1], fft_M[:, :, 0])
        fft_product[:, :, 1].addcmul_(fft_c[:, :, 0], fft_M[:, :, 1])

        output = fft.ifft1(fft_product, tensor.size()).t()

    if output_dims == 1:
        output = output.squeeze(1)
    return output
예제 #8
0
def circulant_inv_matmul(circulant_column, matrix):
    """
    Performs a batch of linear solves C^{-1}M where the matrix C is circulant.
    Args:
        - circulant_column (vector n) - First column of the circulant matrix C.
        - matrix (matrix n x p) - Matrix to multiply the Toeplitz matrix with.
    Returns:
        - Matrix (n x p) - The result of the linear solves C^{-1}M.
    """
    if circulant_column.ndimension() != 1:
        raise RuntimeError(
            'All inputs to CirculantMatmul should be vectors (first column c and row r of the Toeplitz \
                            matrix plus the target vector vector).')

    if len(circulant_column) != len(matrix):
        raise RuntimeError(
            'c and r should have the same length (Toeplitz matrices are necessarily square).'
        )

    if type(circulant_column) != type(matrix):
        raise RuntimeError('The types of all inputs to ToeplitzMV must match.')

    if len(circulant_column) == 1:
        return (circulant_column.view(1, 1).mv(matrix))

    fft_M = fft.fft1(matrix.t().contiguous())
    fft_c = fft.fft1(circulant_column)

    denominator = fft_c[:, 0].pow(2) + fft_c[:, 1].pow(2)
    fft_c[:, 0] = fft_c[:, 0] / denominator
    fft_c[:, 1] = -fft_c[:, 1] / denominator
    fft_c = fft_c.expand_as(fft_M)

    fft_product = fft_M.new(*fft_M.size()).zero_()

    fft_product[:, :, 0].addcmul_(fft_c[:, :, 0], fft_M[:, :, 0])
    fft_product[:, :, 0].addcmul_(-1, fft_c[:, :, 1], fft_M[:, :, 1])
    fft_product[:, :, 1].addcmul_(fft_c[:, :, 1], fft_M[:, :, 0])
    fft_product[:, :, 1].addcmul_(fft_c[:, :, 0], fft_M[:, :, 1])

    res = fft.ifft1(fft_product, matrix.size()).t()

    return res
예제 #9
0
    def test_fft1_computes_fft_of_nd_input(self):
        d = 8
        input = torch.randn(3, 6, d)

        res = fft.fft1(input)
        actual = np.fft.fft(input.numpy())
        self.assertEqual(tuple(res.size()), (3, 6, 8, 2))

        res_real = res[:, :, :, 0]
        res_imag = res[:, :, :, 1]
        actual_real = torch.from_numpy(actual.real[:, :, :]).float()
        actual_imag = torch.from_numpy(actual.imag[:, :, :]).float()

        self.assertLess(torch.norm(res_real - actual_real), 1e-5)
        self.assertLess(torch.norm(res_imag - actual_imag), 1e-5)
예제 #10
0
    def test_fft1_computes_fft_of_1d_input(self):
        d = 8
        input = torch.randn(d)

        res = fft.fft1(input)
        actual = np.fft.fft(input.numpy())
        self.assertEqual(tuple(res.size()), (8, 2))

        res_real = res[:, 0]
        res_imag = res[:, 1]
        actual_real = torch.from_numpy(actual.real).float()
        actual_imag = torch.from_numpy(actual.imag).float()

        assert torch.norm(res_real - actual_real) < 1e-5
        assert torch.norm(res_imag - actual_imag) < 1e-5
예제 #11
0
def test_fft1_computes_fft_of_nd_input():
    d = 8
    input = torch.randn(3, 6, d)

    res = fft.fft1(input)
    actual = np.fft.fft(input.numpy())
    assert (tuple(res.size()) == (3, 6, 5, 2))

    res_real = res[:, :, :, 0]
    res_imag = res[:, :, :, 1]
    actual_real = torch.from_numpy(actual.real[:, :, :5]).float()
    actual_imag = torch.from_numpy(actual.imag[:, :, :5]).float()

    assert torch.norm(res_real - actual_real) < 1e-5
    assert torch.norm(res_imag - actual_imag) < 1e-5
예제 #12
0
def toeplitz_matmul(toeplitz_column, toeplitz_row, tensor):
    """
    Performs multiplication T * M where the matrix T is Toeplitz.
    Args:
        - toeplitz_column (vector n or b x n) - First column of the Toeplitz matrix T.
        - toeplitz_row (vector n or b x n) - First row of the Toeplitz matrix T.
        - tensor (matrix n x p or b x n x p) - Matrix or vector to multiply the Toeplitz matrix with.
    Returns:
        - tensor (n x p or b x n x p) - The result of the matrix multiply T * M.
    """
    if toeplitz_column.size() != toeplitz_row.size():
        raise RuntimeError(
            'c and r should have the same length (Toeplitz matrices are necessarily square).'
        )

    is_batch = True
    if toeplitz_column.ndimension() == 1:
        toeplitz_column = toeplitz_column.unsqueeze(0)
        toeplitz_row = toeplitz_row.unsqueeze(0)
        if tensor.ndimension() < 3:
            tensor = tensor.unsqueeze(0)
        is_batch = False

    if toeplitz_column.ndimension() != 2:
        raise RuntimeError(
            'The first two inputs to ToeplitzMV should be vectors \
                            (or matrices, representing batch) \
                            (first column c and row r of the Toeplitz matrix)')

    if toeplitz_column.size(0) == 1:
        toeplitz_column = toeplitz_column.expand(tensor.size(0),
                                                 toeplitz_column.size(1))
        toeplitz_row = toeplitz_row.expand(tensor.size(0),
                                           toeplitz_row.size(1))

    if toeplitz_column.size()[:2] != tensor.size()[:2]:
        raise RuntimeError(
            'Dimension mismatch: attempting to multiply a {}x{} Toeplitz matrix against a matrix with \
                            leading dimension {}.'.format(
                len(toeplitz_column), len(toeplitz_column), len(tensor)))

    if not torch.equal(toeplitz_column[:, 0], toeplitz_row[:, 0]):
        raise RuntimeError(
            'The first column and first row of the Toeplitz matrix should have the same first element, \
                            otherwise the value of T[0,0] is ambiguous. \
                            Got: c[0]={} and r[0]={}'.format(
                toeplitz_column[0], toeplitz_row[0]))

    if type(toeplitz_column) != type(toeplitz_row) or type(
            toeplitz_column) != type(tensor):
        raise RuntimeError('The types of all inputs to ToeplitzMV must match.')

    output_dims = tensor.ndimension()
    if output_dims == 2:
        tensor = tensor.unsqueeze(2)

    if toeplitz_column.size(1) == 1:
        output = toeplitz_column.view(-1, 1, 1).matmul(tensor)

    else:
        batch_size, orig_size, num_rhs = tensor.size()
        r_reverse = utils.reverse(toeplitz_row[:, 1:], dim=1)

        c_r_rev = toeplitz_column.new(batch_size,
                                      orig_size + r_reverse.size(1)).zero_()
        c_r_rev[:, :orig_size] = toeplitz_column
        c_r_rev[:, orig_size:] = r_reverse

        temp_tensor = toeplitz_column.new(batch_size, 2 * orig_size - 1,
                                          num_rhs).zero_()
        temp_tensor[:, :orig_size, :] = tensor

        fft_M = fft.fft1(temp_tensor.transpose(1, 2).contiguous())
        fft_c = fft.fft1(c_r_rev).unsqueeze(1).expand_as(fft_M)
        fft_product = toeplitz_column.new(fft_M.size()).zero_()

        fft_product[:, :, :, 0].addcmul_(fft_c[:, :, :, 0], fft_M[:, :, :, 0])
        fft_product[:, :, :, 0].addcmul_(-1, fft_c[:, :, :, 1], fft_M[:, :, :,
                                                                      1])
        fft_product[:, :, :, 1].addcmul_(fft_c[:, :, :, 1], fft_M[:, :, :, 0])
        fft_product[:, :, :, 1].addcmul_(fft_c[:, :, :, 0], fft_M[:, :, :, 1])

        output = fft.ifft1(fft_product,
                           (batch_size, num_rhs, 2 * orig_size - 1)).transpose(
                               1, 2)
        output = output[:, :orig_size, :]

    if output_dims == 2:
        output = output.squeeze(2)

    if not is_batch:
        output = output.squeeze(0)

    return output
예제 #13
0
    def test_fft1_returns_type_of_original_input(self):
        d = 8
        input = torch.randn(3, 6, d).double()

        res = fft.fft1(input)
        self.assertTrue(isinstance(res, torch.DoubleTensor))
예제 #14
0
def toeplitz_mv(toeplitz_column, toeplitz_row, vector):
    """
    Performs a matrix-vector multiplication Tv where the matrix T is Toeplitz.
    Args:
        - toeplitz_column (vector n) - First column of the Toeplitz matrix T.
        - toeplitz_row (vector n) - First row of the Toeplitz matrix T.
        - vector (vector n) - Vector to multiply the Toeplitz matrix with.
    Returns:
        - vector n - The result of the matrix-vector multiply Tv.
    """
    if toeplitz_column.ndimension() != 1 or toeplitz_row.ndimension(
    ) != 1 or vector.ndimension() != 1:
        raise RuntimeError(
            'All inputs to ToeplitzMV should be vectors (first column c and row r of the Toeplitz \
                            matrix plus the target vector vector).')

    if len(toeplitz_column) != len(toeplitz_row):
        raise RuntimeError(
            'c and r should have the same length (Toeplitz matrices are necessarily square).'
        )

    if len(toeplitz_column) != len(vector):
        raise RuntimeError(
            'Dimension mismatch: attempting to multiply a {}x{} Toeplitz matrix against a length \
                            {} vector.'.format(len(toeplitz_column),
                                               len(toeplitz_column),
                                               len(vector)))

    if toeplitz_column[0] != toeplitz_row[0]:
        raise RuntimeError(
            'The first column and first row of the Toeplitz matrix should have the same first \
                            otherwise the value of T[0,0] is ambiguous. \
                            Got: c[0]={} and r[0]={}'.format(
                toeplitz_column[0], toeplitz_row[0]))

    if type(toeplitz_column) != type(toeplitz_row) or type(
            toeplitz_column) != type(vector):
        raise RuntimeError('The types of all inputs to ToeplitzMV must match.')

    if len(toeplitz_column) == 1:
        return (toeplitz_column.view(1, 1).mv(vector))

    orig_size = len(toeplitz_column)
    r_reverse = utils.reverse(toeplitz_row[1:])

    c_r_rev = torch.zeros(orig_size + len(r_reverse))
    c_r_rev[:orig_size] = toeplitz_column
    c_r_rev[orig_size:] = r_reverse

    temp_vector = torch.zeros(2 * orig_size - 1)
    temp_vector[:orig_size] = vector

    fft_c = fft.fft1(c_r_rev)
    fft_v = fft.fft1(temp_vector)
    fft_product = torch.zeros(fft_c.size())

    fft_product[:, 0].addcmul_(fft_c[:, 0], fft_v[:, 0])
    fft_product[:, 0].addcmul_(-1, fft_c[:, 1], fft_v[:, 1])
    fft_product[:, 1].addcmul_(fft_c[:, 1], fft_v[:, 0])
    fft_product[:, 1].addcmul_(fft_c[:, 0], fft_v[:, 1])

    res = fft.ifft1(fft_product, temp_vector.size())
    res.resize_(orig_size)
    return res
예제 #15
0
def toeplitz_mm(toeplitz_column, toeplitz_row, matrix):
    """
    Performs a matrix-matrix multiplication TM where the matrix T is Toeplitz.
    Args:
        - toeplitz_column (vector n) - First column of the Toeplitz matrix T.
        - toeplitz_row (vector n) - First row of the Toeplitz matrix T.
        - matrix (matrix n x p) - Matrix to multiply the Toeplitz matrix with.
    Returns:
        - Matrix (n x p) - The result of the matrix-vector multiply TM.
    """
    if toeplitz_column.ndimension() != 1 or toeplitz_row.ndimension(
    ) != 1 or matrix.ndimension() != 2:
        raise RuntimeError(
            'The first two inputs to ToeplitzMV should be vectors \
                            (first column c and row r of the Toeplitz matrix), and the last input should be a matrix.'
        )

    if len(toeplitz_column) != len(toeplitz_row):
        raise RuntimeError(
            'c and r should have the same length (Toeplitz matrices are necessarily square).'
        )

    if len(toeplitz_column) != len(matrix):
        raise RuntimeError(
            'Dimension mismatch: attempting to multiply a {}x{} Toeplitz matrix against a matrix with \
                            leading dimension {}.'.format(
                len(toeplitz_column), len(toeplitz_column), len(matrix)))

    if toeplitz_column[0] != toeplitz_row[0]:
        raise RuntimeError(
            'The first column and first row of the Toeplitz matrix should have the same first element, \
                            otherwise the value of T[0,0] is ambiguous. \
                            Got: c[0]={} and r[0]={}'.format(
                toeplitz_column[0], toeplitz_row[0]))

    if type(toeplitz_column) != type(toeplitz_row) or type(
            toeplitz_column) != type(matrix):
        raise RuntimeError('The types of all inputs to ToeplitzMV must match.')

    if len(toeplitz_column) == 1:
        return (toeplitz_column.view(1, 1).mm(matrix))

    _, num_rhs = matrix.size()
    orig_size = len(toeplitz_column)
    r_reverse = utils.reverse(toeplitz_row[1:])

    c_r_rev = torch.zeros(orig_size + len(r_reverse))
    c_r_rev[:orig_size] = toeplitz_column
    c_r_rev[orig_size:] = r_reverse

    temp_matrix = torch.zeros(2 * orig_size - 1, num_rhs)
    temp_matrix[:orig_size, :] = matrix

    fft_M = fft.fft1(temp_matrix.t().contiguous())
    fft_c = fft.fft1(c_r_rev).expand_as(fft_M)
    fft_product = torch.zeros(fft_M.size())

    fft_product[:, :, 0].addcmul_(fft_c[:, :, 0], fft_M[:, :, 0])
    fft_product[:, :, 0].addcmul_(-1, fft_c[:, :, 1], fft_M[:, :, 1])
    fft_product[:, :, 1].addcmul_(fft_c[:, :, 1], fft_M[:, :, 0])
    fft_product[:, :, 1].addcmul_(fft_c[:, :, 0], fft_M[:, :, 1])

    res = fft.ifft1(fft_product, (num_rhs, 2 * orig_size - 1)).t()
    res = res[:orig_size, :]
    return res