Quali sono i metodi semplici per campionare in modo adattivo una funzione 2D?


22

Ho una funzione bidimensionale cui vorrei campionare i valori. La funzione è molto costosa da calcolare e ha una forma complessa, quindi ho bisogno di trovare un modo per ottenere il maggior numero di informazioni sulla sua forma usando il minor numero di punti campione.f(x,y)

Quali buoni metodi ci sono per farlo?

Quello che ho finora

  • Comincio da un insieme esistente di punti in cui ho già calcolato il valore della funzione (questo potrebbe essere un reticolo quadrato di punti o qualcos'altro).

  • Quindi computo una triangolazione Delaunay di questi punti.

  • Se due punti vicini nella triangolazione di Delaunay sono abbastanza lontani ( ) e il valore della funzione differisce sufficientemente in essi ( ), inserisco un nuovo punto a metà tra di loro. Lo faccio per ogni coppia di punti adiacente.> Δ f>ΔX>Δf

Cosa c'è di sbagliato in questo metodo?

Bene, funziona relativamente bene, ma su funzioni simili a questa non è l'ideale perché i punti campione tendono a "saltare" sulla cresta e non si accorgono nemmeno che è lì.

Grafica Mathematica

Produce risultati come questo (se la risoluzione della griglia del punto iniziale è sufficientemente approssimativa):

Grafica Mathematica

Questo diagramma sopra mostra i punti in cui viene calcolato il valore della funzione (in realtà celle Voronoi attorno a loro).

Grafica Mathematica

Questo diagramma sopra mostra l'interpolazione lineare generata dagli stessi punti e la confronta con il metodo di campionamento incorporato di Mathematica (per circa la stessa risoluzione iniziale).

Come migliorarlo?

Penso che il problema principale qui sia che il mio metodo decida se aggiungere un punto di raffinamento o meno in base al gradiente.

Sarebbe meglio tenere conto della curvatura o almeno della seconda derivata quando si aggiungono punti di raffinamento.

Domanda

Qual è un modo molto semplice da implementare per tenere conto della seconda derivata o curvatura quando le posizioni dei miei punti non sono affatto vincolate? (Non ho necessariamente un reticolo quadrato di punti di partenza, questo dovrebbe idealmente essere generale.)

O quali altri modi semplici ci sono per calcolare la posizione dei punti di raffinamento in modo ottimale?

Lo implementerò in Mathematica, ma questa domanda riguarda principalmente il metodo. Per il bit "facile da implementare", conta comunque che sto usando Mathematica (ad esempio, è stato facile farlo finora perché ha un pacchetto per fare triangolazione Delaunay)

A quale problema pratico sto applicando questo

Sto calcolando un diagramma di fase. Ha una forma complessa. In una regione il suo valore è 0, in un'altra regione è tra 0 e 1. C'è un forte salto tra le due regioni (è discontinuo). Nella regione in cui la funzione è maggiore di zero ci sono sia alcune variazioni regolari che un paio di discontinuità.

Il valore della funzione viene calcolato sulla base di una simulazione Monte Carlo, quindi occasionalmente è prevedibile un valore di funzione errato o rumore (questo è molto raro, ma accade per un gran numero di punti, ad esempio quando lo stato stazionario non viene raggiunto a causa qualche fattore casuale)

L'ho già chiesto su Mathematica.SE ma non riesco a collegarlo perché è ancora in beta privata. Questa domanda qui riguarda il metodo, non l'implementazione.


Rispondi a @suki

È questo il tipo di divisione che suggerisci, ovvero mettere un nuovo punto nel mezzo dei triangoli?

Grafica Mathematica Grafica Mathematica Grafica Mathematica Grafica Mathematica

La mia preoccupazione qui è che sembra richiedere una gestione speciale ai bordi della regione, altrimenti darà triangoli molto lunghi e molto sottili, come mostrato sopra. Hai corretto per questo?

AGGIORNARE

Un problema che appare sia con il metodo che descrivo sia con il suggerimento di @ suki di mettere la suddivisione in base ai triangoli e di inserire i punti di suddivisione all'interno del triangolo è che quando ci sono discontinuità (come nel mio problema), ricalcolare la triangolazione di Delaunay dopo un passaggio può fa sì che i triangoli cambino e forse compaiano alcuni triangoli grandi che hanno valori di funzione diversi nei tre vertici.

Ecco due esempi:

EX1 EX2

Il primo mostra il risultato finale quando si campiona intorno a una discontinuità lineare. Il secondo mostra la distribuzione del punto di campionamento per un caso simile.

Quali modi semplici ci sono per evitarlo? Attualmente sto semplicemente suddividendo quegli egdes che scompaiono dopo una retriangolazione, ma questo sembra un hack e deve essere fatto con cura come nel caso di maglie simmetriche (come una griglia quadrata) ci sono diverse triangolazioni Delaunay valide, quindi i bordi potrebbero cambiare casualmente dopo la retriangolazione.


ci sono nuovi sviluppi su questo tema?
Andrei,

Risposte:


10

Ho lavorato su un problema simile a questo qualche tempo fa.

Penso che la differenza principale tra le nostre implementazioni sia che stavo scegliendo dove aggiungere punti in base ai triangoli, non ai bordi. Scelgo anche nuovi punti all'interno dei triangoli anziché sui bordi.

Ho la sensazione che l'aggiunta di punti all'interno dei triangoli lo renderebbe più efficiente dando un piccolo aumento della distanza media dai punti vecchi a quelli nuovi.

Ad ogni modo, un altro aspetto positivo dell'uso dei triangoli anziché dei bordi è che fornisce una stima del vettore gradiente, anziché della pendenza lungo questo particolare bordo.

Nel mio codice matlab ho usato una classe base per occuparmi della maggior parte dei macchinari, con alcuni metodi astratti:

  • weight(self) per decidere la priorità per i quali triangoli suddividere successivamente.
  • choosePoints(self,npoints = "auto") per decidere nuovi punti da valutare in base al peso di ciascun triangolo.

Ho trovato questa configurazione molto flessibile:

  • l'impostazione della weight()funzione di una sottoclasse sull'area del triangolo produce una densità di mesh costante.
  • L'impostazione weight()per calcolare il valore medio della funzione moltiplicata per l'area del triangolo fornisce una sorta di campionamento di probabilità quasi casuale.
  • usare var(triangle.zs)potrebbe fare, per le funzioni che hanno un output binario, ciò che ritengo sia una generalizzazione di una ricerca bisection in più di 1 dimensione.
  • l'utilizzo è area + var(triangle.zs)stato piuttosto efficace nel mettere una densità costante ovunque e una maggiore densità lungo qualsiasi pendenza (quasi quello che hai ora).

Ho usato la varianza dei valori z per approssimare l'importanza degli effetti del primo ordine (pendenza) perché la varianza non andrà mai all'infinito come la pendenza.

Per l'ultimo esempio la densità di sfondo era buona perché stavo cercando BLOB discontinui di alto valore in uno spazio di basso valore. Quindi si riempirebbe lentamente nell'intera mesh e quando troverebbe una chiazza si concentrerebbe seguendo il bordo della macchia tutto intorno a causa dell'elevato peso che ho messo sul gradiente (e che ha riempito solo i ntriangoli superiori su ogni iterazione). Alla fine potevo sapere che non c'erano blob (o buchi nei miei blob) (di forma ragionevole) di dimensioni maggiori della densità di mesh di sfondo risultante.

Come te ho ottenuto alcuni punti negativi nei miei risultati, non sono stati un problema per me perché l'errore era tale che se avessi eseguito nuovamente i punti vicini avrebbero probabilmente dato la risposta corretta. Vorrei solo finire con blip di maggiore densità di maglia attorno ai miei punti negativi.

Qualunque cosa tu faccia, consiglio sempre di fare i pesi relativi alla dimensione del triangolo in modo tale che, a parità di condizioni, i triangoli di grandi dimensioni vengano scomposti per primi.

Forse una soluzione per te è quella di portare il mio approccio un passo avanti e invece di valutare i triangoli in base al contenuto di quella cella triangolare, valutare in base a quello e a tutti e tre i triangoli adiacenti.

Ciò conterrà abbastanza informazioni per ottenere una stima della matrice completa dell'Assia. puoi ottenerlo facendo un minimo di adattamento di z = c1*x + C2*y c11*x^2+c12*x*y+c22*y^2tutti i vertici nei triangoli di interesse (centrare prima il sistema di coordinate sul triangolo).

Non userei direttamente il gradiente o l'Assia (quelle costanti) perché andranno all'infinito a discontinuità.

Forse l'errore di somma quadrata dei valori z relativi a un'approssimazione planare di quei punti sarebbe una misura utile di quanto siano interessanti gli effetti del secondo ordine.


aggiornato:

Mi sembra ragionevole.

In realtà non sono mai andato in giro per il rivestimento speciale dei bordi. Mi ha infastidito un po ', ma per quello che stavo facendo, è stato sufficiente iniziare con molti punti attorno ai bordi.

più elegante sarebbe quello di combinare i nostri due approcci, bordi di ponderazione e triangoli. Quindi se un bordo è troppo lungo, taglialo a metà ... Mi piace il modo in cui il concetto si generalizza a dimensioni più alte (ma i numeri diventano grandi velocemente) ...

Ma poiché non ti aspetti che il corpo principale della mesh abbia triangoli con proporzioni elevate, puoi usare una funzione come la funzione di confine libero di Matlab per trovare il confine, quindi eseguire lo stesso algoritmo in una dimensione in meno sul confine. Se fatto bene, ad esempio su un cubo, potresti ottenere la stessa densità di mesh sui bordi, sulle facce e all'interno del cubo. Interessante.

Una cosa per cui non ho mai trovato una buona soluzione era il fatto che la mia versione non avrebbe mai esplorato al di fuori dello scafo convesso del set di punti iniziale.


Ho anche pensato di usare prima i triangoli, ma prima ho avuto qualche problema tecnico (che ho risolto da allora), e poi ho pensato che non sarebbe stato molto meglio usare i triangoli comunque. Domanda: dove metti i nuovi punti? Nel mezzo dei triangoli? Non l'ho fatto perché mi aspettavo che avrebbe creato dei triangoli molto lunghi e sottili. A breve aggiornerò il mio post con quello che ho capito che hai fatto in modo da poter verificare se ho capito bene :-) grazie!
Szabolcs,

Potete per favore vedere la mia modifica e chiarire?
Szabolcs,

Si scopre che un involucro speciale i bordi è inevitabile, indipendentemente dal tipo di schema di suddivisione che uso. Nel mio caso ho un gradiente elevato perpendicolare al bordo, ma non parallelo ad esso, il che rendeva le cose inefficienti se non avessi caso speciale i bordi.
Szabolcs,

Un altro problema che ho riscontrato è che la ri-triangolazione faceva apparire occasionalmente grandi triangoli in cui i vertici avevano valori di funzione diversi. Ho finito con cose come questa: i.stack.imgur.com/nRPwi.png è il diagramma di densità interpolato linearmente e i.stack.imgur.com/208bP.png sono i punti di campionamento (non esattamente gli stessi). Questa è solo una discontinuità lungo un rettilineo. Hai riscontrato questo problema? Se sì, come l'hai risolto? Hai ritocculato completamente dopo ogni passaggio di suddivisione?
Szabolcs,

Non sono sicuro che la triangolazione significhi davvero qualcosa qui. Ogni punto che hai valutato è il valore della funzione in un punto, quindi perché non fare qualcosa di simile che usano in metodi senza mesh? it.wikipedia.org/wiki/Smoothed-particle_hydrodynamics Puoi anche stimare i derivati ​​in questo modo ...
meawoppl

0

Penso che il problema principale nella tua euristica sia che stai considerando il gradiente in una sola dimensione e quindi, nelle regioni in cui dfdx è piccolo ma dfdy è grande (come accade nel mezzo del tuo esempio), ti mancheranno i punti quando guardi nella dimensione "sbagliata".

Una soluzione rapida sarebbe quella di considerare gruppi di quattro punti, prendendo il loro centro di gravità e approssimando | dfdx | + | dfdy | usando quei quattro punti. Un'altra alternativa è quella di prendere tre punti (cioè un triangolo) e prendere il massimo gradiente della superficie su di essi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.