0

I am trying to write a script that determines whether it is possible to factorize an integer value in a list of integers. The way I have done it is to search recursivley for a valid factorization, effectiveley doing a DFS in a tree of possible factors (in the code below). Is it possible to make a greedy algorithm that finds this fast? My idea was to keep searching the list for the largest factor in the remainder until a valid factorization is found. Will that be a correct algorith in this case? If not, is this problem in NP?

Code to solve the problem written in Python:

def can_factorize_in_list(n, list):
    # Determines whether it is possible to factorize 'n' in 'list'
    # Filter the list to only include the values which are factors
    fac_list = [p for p in list if (n % p is 0)]
    for x in fac_list:
        if n % x is 0:
            if n/x is 1:
                # If we end up at 1, we have a valid factorization
                return 1 # End state
            else:
                # If we do not end at 1, keep trying
                if can_factorize_in_list(n/x, fac_list):
                    return 1
                else:
                    continue
    return 0

EDIT: For instance, given integer 30 and list [2,3,5,8], the algorithm should return True because 30 = 2*3*5. It is not required to use all the elements in the list as factors and factors can be used more than once.

Meldrin
  • 1
  • 2
  • What do you mean by factorizing an integer "in" a list of integers? The usual interpretation would be that the integer is an element of the list, and you just want to factorize the integer (so the list doesn't even matter), but that doesn't seem to be what you're trying to say. Are the factors required to come from the list? If so, can factors be reused? – user2357112 Apr 19 '16 at 16:37
  • You don't need to recheck `n%x is 0`. Your `fac_list` already filtered those values. Also the `else: continue` is unnecessary. And you could rewrite it as `if n/x is 1 or can_factorize_in_list(n/x, fac_list): return True`. And please, return boolean values not `0`/`1`, it will make your code cleaner and less hacky – Mr. E Apr 19 '16 at 16:37
  • Factors are required to come from the list, yes. Factors can also be used more than once. – Meldrin Apr 19 '16 at 16:40
  • Are you asking, for example, whether the list of factors [2, 3, 5] factorises the number 30 and return True, while for 31 it'd return False? – Reti43 Apr 19 '16 at 16:41
  • This is a variation of the multidimensional knapsack problem. I would expect it to be difficult, probably NP-complete, although I haven't entirely worked out if the input encoding changes things. `(100, 200, 300)` is more compact than `2**100 * 3**200 * 5*300`. – user2357112 Apr 19 '16 at 16:42
  • 2
    Don't use `list` as a variable name, your shadowing the builtin `list`. – Jason Apr 19 '16 at 16:43
  • 1
    The problem is quite definitely in NP; if the output is "yes", a valid factorization serves as a polynomial-time-checkable certificate that the answer is "yes". – user2357112 Apr 19 '16 at 16:48
  • And it isn't necessary for all the factors to be used, right? For example, [2, 3, 5] factorise 6, even though 5 isn't needed because it can be expressed as 2\*\*1 * 3\*\*1 * 5\*\*0, right? – Reti43 Apr 19 '16 at 16:48
  • @Reti43 Yes, I do not need to use all the elements in the list as factors. – Meldrin Apr 19 '16 at 16:50
  • @user2357112 Apologies, what I tried to ask is if the best possible solution has exponential run-time. Does that mean that it is in NPC? – Meldrin Apr 19 '16 at 16:54
  • It's not clear what it is exactly you're asking. Are you asking for the complexity of factorising an integer given a list of integers or are you asking if your code can be optimised? For one thing, you can turn it to an iterative approach which will cut down on time. Is this a theoretical question or do you intend using it for some big numbers (and how big)? – Reti43 Apr 19 '16 at 17:05
  • @Reti43 What I am asking is if the greedy approach I described is correct. I am not asking for the complexity of the problem, it is of little importance for me right now. – Meldrin Apr 19 '16 at 17:09

1 Answers1

0

There is no need for depth-first search, and the problem is linear in the size of the list of potential factors. Here's a function that either returns the factorization of the target number, or False if it cannot be factored over the list of factors:

def smooth(n, fs):
    xs = []
    for f in fs:
        if n == 1: return xs
        while n % f == 0:
            n = n / f
            xs.append(f)
    if n == 1: return xs
    return False

I called the function smooth because that is the concept in number theory that you are trying to calculate: a number that factors over a given list is said to be smooth over that list of factors. For most applications you probably want all the potential factors to be prime.

user448810
  • 17,381
  • 4
  • 34
  • 59
  • This greedy algorithm does not solve the problem I'm trying to solve. It would work if the elements in the list `fs` are all prime, but this is not necessarily the case. A trivial counter-example: `n = 46` and `fs = [2,46]`. The algorithm you described would first divide by two, and then terminate there as `23`has no factors in `xs`. – Meldrin May 15 '16 at 22:21
  • Calling the function as `smooth(46, [46,2])` seems to work. Failing that, you could factorize both the target and each member of the list and compare factors. What is the actual problem you are trying to solve? – user448810 May 16 '16 at 00:44