Como interromper o python depois que o produto de destino é encontrado no subconjunto?

8

Eu tenho aprendido python para meu hobby e pesquisas empíricas sobre problemas completos de NP, como Subset Product. O algoritmo que tenho funciona, mas não está do jeito que pretendo fazer.

O que estou tentando fazer é interromper as ferramentas de controle combinationsassim que chegarem a um produto de subconjunto da variável de entrada target. Isso tornará o código um pouco mais rápido. O código está no estágio de polimento, portanto há uma lista desnecessáriares_2

Aqui está o loop.

res_2 = [];
for i in range(1, len(s)+1):

   var = (findsubsets(s, i))   
   kk = list(map(numpy.prod, var))
   res_2.append(kk)
   if target in kk:
     print('yes')
     print(var)
     break

Esta é a saída que eu não quero. Observe que o script não irá parar no (4, 4). É um desperdício de recursos continuar verificando todas as combinações quando um alvo é "atingido".

Enter numbers WITH SPACES: 4 4 3 12
enter target integer:
16
yes
[(4, 4), (4, 3), (4, 12), (4, 3), (4, 12), (3, 12)]
 kk
[16, 12, 48, 12, 48, 36]

Minha saída pretendida é parar em (4, 4) se for o primeiro "acerto". O mesmo para qualquer outro subconjunto como (1,2,3) ou (1,2,3 --- qualquer comprimento). Eu preferiria que o script continuasse até encontrar um hit. Depois de encontrar o acerto, ele para, porque isso melhoraria a velocidade do algoritmo.

Script completo abaixo

# Naive Subset-Product solver
# with python's itertools

import itertools 
import numpy

s = list(map(int, input('Enter numbers WITH SPACES: ').split(' ')))
print('enter target integer: ')
target = int(input())


if s.count(target) > 0:
   print('yes')
   quit()

if target > numpy.prod(s):
  print('sorry cant be bigger than total product of s')
  quit()


def findsubsets(s, n): 
    return list(itertools.combinations(s, n)) 

# Driver Code 
n = len(s)

# This code snippet is a for loop. It also is intended to cut down execution
# time once it finds the target integer. (instead of creating all combinations)

res_2 = [];
for i in range(1, len(s)+1):

   var = (findsubsets(s, i))   
   kk = list(map(numpy.prod, var))
   res_2.append(kk)
   if target in kk:
     print('yes')
     print(var)
     break

Questão

Como faço para que isso funcione para aumentar a velocidade do algoritmo? Que truques pitônicos resolveriam meu problema? Existe uma maneira mais curta de fazer isso?

Travis Wells
fonte

Respostas:

3

É prematuro converter o combinationsvalor de retorno das ferramentas em um list, especialmente quando você está tentando sair mais cedo e evitar muita sobrecarga. Geralmente, há um bom motivo para que as funções da biblioteca retornem iteradores em vez de listas totalmente realizadas.

Aqui está uma sugestão:

def findsubsets(s, n): 
    return itertools.combinations(s, n)

def find_subset(target,nums):
    for i in range(1,len(nums)+1):
        for ss in findsubsets(nums, i):
            if np.prod(ss) == target:
                prodstr = '*'.join(str(num) for num in ss)
                print(f"{target} = {prodstr}")
                return ss
    return None

find_subset(96,[1,6,2,8])

Dado que essa findsubsetsé uma linha única, é questionável tê-la como uma função autônoma (estamos basicamente aliasing, o combinationsque poderia ter sido feito com uma import X as Ydeclaração). De qualquer forma, isso deve parar mais cedo sem consumir muita RAM com entradas maiores.

smarchese
fonte