Confronto di oggetti con tolleranza

1

Il seguente codice dice che c1 == c2 e c2 == c3 , ma c1 != c3 .

TOL = 0.11

class C:
    def __init__(self, x):
        self.x = x

    def __eq__(self, other):
        return abs(self.x - other.x) <= TOL

c1 = C(1.1)
c2 = C(1.2)
c3 = C(1.3)

print(c1 == c2)  # True
print(c2 == c3)  # True
print(c1 == c3)  # False

Per lo stesso motivo la forma al centro dell'immagine qui sotto potrebbe essere uguale a tutte le altre forme, mentre nessuna altra forma sarebbe uguale a tutte le altre.

Leggermentediversi"rettangoli"

Non importa quanto piccola o grande sia la tolleranza, ci sarà sempre un angolo per la linea superiore delle forme in cui si presenta il problema.

Ho bisogno di trovare un modo affidabile per abbinare le forme in modo che quando c1 == c1 una volta, c1 == c1 sempre. Nell'esempio sopra posso accettare che sia c2 == c3 o c2 != c3 , ma qualunque sia il caso, deve essere (1) coerente durante l'esecuzione e (2) coerente con altri confronti.

Se stringo la tolleranza, nessuna forma sarà mai uguale ad altre forme, a causa dei piccoli errori introdotti dalle trasformazioni.

Se allento la tolleranza, tutte le forme saranno identiche, il che non va bene.

Forse c'è un algoritmo di confronto che ricorda la prima istanza di ogni valore mai confrontato e crea un secchio per questo? Quindi, nel mio primo esempio, se confronti prima c1 in c2, allora il valore di riferimento sarà 1.1 e c2 sarà diverso da c3, ma se confronti c2 in c1 prima il valore di riferimento sarà 1.2 e saranno tutti uguali .

C'è un modo per evitare questo problema?

    
posta stenci 04.11.2016 - 15:50
fonte

4 risposte

1

Penso che tu voglia qualcosa come un istogramma ma dove le categorie si basano sui dati che trovi e sull'ordine in cui li trovi. È fondamentale capire che le categorie non saranno garantite per essere distribuite uniformemente nel dominio come avviene normalmente in un istogramma.

categories = []

def categorize(shape):
  index=0

  for c in categories:
    if c.withinTolerance(shape):
      return c
    elif c.largerThan(shape):
      categories.insert(i, shape)
      return shape

    index += 1        

  categories.append(shape)
  return shape

def equalish(a, b):
  return categorize(a) == categorize(b)

Quindi, in base all'ancora della tua categoria basata su quanto sopra, puoi creare un uguale (anche se sono d'accordo con @Servy che dovrebbe essere usato un nome diverso).

Modifica

Questo è un esempio funzionante che mostra come è coerente (all'interno di una sessione).

TOL = 0.11

class C:
    categories = []

    def __init__(self, x):
        self.x = x

def _compare(self, other):
    return abs(self.x - other.x) < TOL

def __eq__(self, other):
    for c in self.categories:
        self_equal_c = c._compare(self)
        other_equal_c = c._compare(other)
        if self_equal_c or other_equal_c:
            return self_equal_c and other_equal_c
    self.categories.append(self)
    return self._compare(other)

a = C(1.1)
b = C(1.2)
c = C(1.3)

print('a == c', a == c)
print('a == b', a == b)
print('a == c', a == c)
print('b == c', b == c)

Questa soluzione è leggermente migliore di un istogramma quando vengono confrontati solo due elementi perché un istogramma renderebbe due elementi diversi quando si trovano in due diversi secchi anche se la loro distanza è inferiore alla tolleranza.

Questa soluzione è molto meglio di un istogramma quando vengono confrontate più di una proprietà. Se la classe C aveva più di un campo (come nell'esempio precedente), l'uso dell'istogramma causerebbe la quasi totalità degli elementi.

    
risposta data 04.11.2016 - 16:43
fonte
4

Evitare l'annullamento di un'uguaglianza implicita di oggetti quando si utilizza una tolleranza. Esporre un metodo specifico o un oggetto di confronto che confronta gli oggetti usando una tolleranza (ed è molto chiaro a riguardo nel suo nome / documentazione). L'eguaglianza implicita dell'oggetto dovrebbe rimanere transitiva, che questa implementazione non soddisfa.

In questo modo si garantisce che chiunque utilizzi questo metodo di confronto sia consapevole del fatto che non mantiene tutte le proprietà di un confronto di uguaglianza tradizionale e che dovrebbero utilizzarlo solo in un contesto in cui ciò è corretto e assicurati che le persone che usano l'uguaglianza implicita non abbiano le loro aspettative violate su come si comporta.

    
risposta data 04.11.2016 - 16:09
fonte
0

Stai chiedendo l'impossibile. O abbini esattamente o abbini con una tolleranza. Non puoi fare entrambe le cose contemporaneamente.

    
risposta data 04.11.2016 - 16:08
fonte
0

Dopo aver letto il tuo caso d'uso, posso pensare a un modo per affrontarlo. Capisco che inizi sempre con una forma che può essere tradotta e / o copiata un paio di volte. Perché non mantenere una proprietà di origine attaccata alla forma e confrontarla invece della forma stessa? Se due forme hanno la stessa origine, devono essere uguali indipendentemente dal numero di volte in cui sono state ridimensionate o ruotate. Quando una forma viene copiata, ottiene l'id origine del suo modello. Le nuove forme ottengono nuovi ID di origine.

    
risposta data 05.11.2016 - 08:32
fonte

Leggi altre domande sui tag