2

Hello I am working on a problem that seems to be out of my league so any tips, pointers to reading materials etc. are really appreciated. That being said here is the problem:

given 3 subsets of numbers a, b, c ⊆ {0, ..., n}. In nlog(n) check if there exists numbers n1, n2 in a, b and n3 in c where n1 + n2 = n3.

I am given the hint to convert a and b to polynomial coefficients and to use polynomial multiplication using ftt to multiply the coefficients of a and b.

Now where I am stuck is after getting the result of the polynomial multiplication, what do I do next?

Thank you in advanced.

from numpy.fft import fft, ifft
from numpy import real, imag

def polynomial_multiply(a_coeff_list, b_coeff_list):
    # Return the coefficient list of the multiplication 
    # of the two polynomials 
    # Returned list must be a list of floating point numbers.
    # list from complex to reals by using the 
    # real function in numpy
    len_a = len(a_coeff_list)
    len_b = len(b_coeff_list)
    for i in range(len_a-1):
        b_coeff_list.append(0)
    for i in range(len_b-1):
        a_coeff_list.append(0)
    a_fft = fft(a_coeff_list)
    b_fft = fft(b_coeff_list)
    c = []
    for i in range(len(a_fft)):
        c.append(a_fft[i] * b_fft[i])
    inverse_c = ifft(c)
    return real(inverse_c)

# inputs sets a, b, c
# return True if there exist n1 in a, n2 in B such that n1+n2 in C
# return False otherwise
# number n which signifies the maximum number in a, b, c
def check_sum_exists(a, b, c, n):
    a_coeffs = [0]*n
    b_coeffs = [0]*n 
    # convert sets a, b into polynomials as provided in the hint
    # a_coeffs and b_coeffs should contain the result
    i = 0
    for item in a:
        a_coeffs[i] = item
        i += 1
    i = 0
    for item in b:
        b_coeffs[i] = item
        i += 1
    # multiply them together
    c_coeffs = polynomial_multiply(a_coeffs, b_coeffs)
    # now this is where i am lost
    # how to determine with c_coeffs?
    return False
    # return True/False
blowtorch
  • 83
  • 7
  • @don'ttalkjustcode correct I just used the verbiage from the problem. I will edit to simplify. Thank you. – blowtorch Oct 16 '21 at 21:04
  • 1
    I think you must have misunderstood the problem and the hint you were given. As phrased in your question, this is exactly the [3SUM problem](https://en.wikipedia.org/wiki/3SUM), and there is no known algorithm which solves it in O(n log n) time. However, there is an algorithm which solves it in O(n + N log N) time where N is the maximum absolute value of any number in the three sets, and those numbers are all integers. I suspect you missed this detail about the problem and the hint. Wikipedia cites the famous *Introduction to Algorithms* (CLRS) textbook for this. – kaya3 Oct 16 '21 at 21:05
  • 1
    @kaya3 Ah... I guess that might be why they said "subset". With the superset being {0, 1, 2, ..., n}. – no comment Oct 16 '21 at 21:09
  • Are all the numbers positive integers or can they be negative and/or floating point ? are a,b,c in sorted order ? – Alain T. Oct 16 '21 at 21:17
  • @AlainT. all numbers are positive integers and 0. a,b,c are sorted. – blowtorch Oct 16 '21 at 21:27
  • 1
    Read off the powers of x in a(x) b(x) with a nonzero coefficient, test whether any belong to c. – David Eisenstat Oct 16 '21 at 22:31
  • 1
    `c = set(c); return any(j in c for (j, k) in enumerate(c_coeffs) if round(k))` or something like that. – David Eisenstat Oct 16 '21 at 23:11

1 Answers1

2

Thanks to all who helped. I figured it out and hopefully this can help anyone who runs into a similar problem. The issue I had was I incorrectly assigned the coefficients for a_coeffs and b_coeffs.

Here is the solution which passed the tests for those interested.

from numpy.fft import fft, ifft
from numpy import real, imag


def check_sum_exists(a, b, c, n):
    a_coeffs = [0] * n
    b_coeffs = [0] * n
    # convert sets a, b into polynomials as provided in the hint
    # a_coeffs and b_coeffs should contain the result
    for coeff in a:
        a_coeffs[coeff] = 1
    for coeff in b:
        b_coeffs[coeff] = 1
    # multiply them together
    c_coeffs = polynomial_multiply(a_coeffs, b_coeffs)
    # use the result to solve the problem at hand
    for coeff in c:
        if c_coeffs[coeff] >= .5:
            return True
    return False
    # return True/False


def polynomial_multiply(a_coeff_list, b_coeff_list):
    # Return the coefficient list of the multiplication
    # of the two polynomials
    # Returned list must be a list of floating point numbers.
    # Please convert list from complex to reals by using the
    # real function in numpy.
    for i in range(len(a_coeff_list) - 1):
        b_coeff_list.append(0)
    for i in range(len(b_coeff_list) - 1):
        a_coeff_list.append(0)
    a_fft = fft(a_coeff_list)
    b_fft = fft(b_coeff_list)
    c = []
    for i in range(len(a_fft)):
        c.append(a_fft[i] * b_fft[i])
    return real(ifft(c))

blowtorch
  • 83
  • 7
  • 1
    Thresholding at 1 is a little dangerous since you're using a floating-point FFT. I'd suggest 0.5 as an alternative threshold. (Another way to deal is to use a number-theoretic transform instead of a DFT.) – David Eisenstat Oct 17 '21 at 03:06
  • @DavidEisenstat I updated to 0.5 per your suggestion thank you! – blowtorch Oct 17 '21 at 03:09