2017-01-25 2 views
0

Ich generiere alle vectors respecting some symmetry groups mit Iertools in Python.itertools entfernen äquivalente Elemente

Grundsätzlich ist alles nur Permutation von x, y, z-Achse und Zeichen. Ich bin nur nicht sicher, was der beste Weg ist sicherzustellen, dass äquivalente Vektoren nicht dupliziert werden.

  1. 0 = -0 daher unterzeichnen permuations von [1, 2, 0] sollte nur [[1, 2, 0], [1, -2, 0], [-1, 2, 0], [-1, -2, 0]]
  2. itertools.permutations('AAB' ) sein sollte produzieren [('A', 'B', 'A'), ('B', 'A', 'A'), ('A', 'A', 'B')] dh nicht jedes Element, die durch den Austausch von Vorbehalten, Duplizieren A

Meine aktuelle Lösung:

zum Entfernen von dumplicate überlasse ich es durch eine set wie lst = list(set(lst)). Aber ich mag es nicht, viel Müll zu erzeugen, der später herausgefiltert wird. Auch es ändert willkürlich die Reihenfolge von Elementen. Es kann auch nur in Form von hashbaren Elementen (z. B. Tupeln, aber nicht Listen oder Nummernfeldern) erstellt werden, die konvertiert werden müssen.

# using itertools.product and set filer 
def signPermut(t): 
    lst = [] 
    n = len(t) 
    for signs in itertools.product([-1,1], repeat=n): 
     p = [ ti*si for ti,si in zip(t,signs) ] 
     lst.append(tuple(p)) 
    #return lst 
    return list(set(lst)) 

Diese Funktion führt das Zeichen Permutation für Nullen mit der Überprüfung, aber es ist wahrscheinlich sehr ineffizient:

def permutSign(t): 
    lst = [ [] ] 
    for c in t: 
     lst_ = [] 
     if c != 0: 
      for p in lst: 
       lst_.append(p+[ c]) 
       lst_.append(p+[-c]) 
     else: 
      for p in lst: 
       lst_.append(p+[c]) 
     lst = lst_ 
    return lst 

Es funktioniert, aber ich dachte, vielleicht gibt es etwas vorfabriziert ... effizienter , einfach und pythonic

Antwort

1

wie etwa eine Liste mit den Zeichen Erstellen und verwenden von itertools.product über die:

from itertools import product 

lst = [1, 2, 0] 

signs = [(1, -1) if item != 0 else (1,) for item in lst] 
print(signs) # [(1, -1), (1, -1), (1,)] 

res = [] 
for sign in product(*signs): 
    res.append([s*n for s, n in zip(sign, lst)]) 

print(res) # [[1, 2, 0], [1, -2, 0], [-1, 2, 0], [-1, -2, 0]] 

oder in einem Rutsch:

from itertools import product 

sgn_lst = [(n, -n) if n != 0 else (0,) for n in lst] 
print(sgn_lst) # [(1, -1), (2, -2), (0,)] 

res = [] 
for item in product(*sgn_lst): 
    res.append(item) 

print(res) # [(1, 2, 0), (1, -2, 0), (-1, 2, 0), (-1, -2, 0)] 

diese Art und Weise gibt es viel weniger Arbeit in der Schleife zu tun ist.

2

Vielleicht ist das ein bisschen mehr Pythonic:

import itertools 

def signProducts(vector): 
    svector = [[x,-x] if x != 0 else [x] for x in vector] 
    return itertools.product(*svector) 

#test: 
v = [1,2,0] 
for w in signProducts(v): print(w) 

Ausgang:

(1, 2, 0) 
(1, -2, 0) 
(-1, 2, 0) 
(-1, -2, 0) 
0

Ich denke, egal, wie intelligent Sie sind über itertools, Sätze oder Iteratoren verwenden - das Wichtigste ist, schreibe Code, der leicht zu verstehen ist, z es wird nicht weh zu Namen besser VARs und deutlich machen, dass Sie Vektoren multiplizieren:

import itertools 
import operator 

def genAxes(n): 
    return itertools.product((-1, 1), repeat=n) 

def multiplyVectors(x, y): 
    return itertools.imap(operator.mul, x, y) 

def signPermutation(v): 
    n = len(v) 
    axes = genAxes(n) 
    permut = map(lambda a: tuple(multiplyVectors(v, a)), axes) 
    return list(set(permut)) 

v = [0, 1, 2] 
print signPermutation(v) 

Dies ist nur ein Beispiel, wie es einfacher zu machen IMHO zu folgen.