Saya memiliki fungsi dua dimensi yang nilainya ingin saya sampel. Fungsi ini sangat mahal untuk dikomputasi dan memiliki bentuk yang kompleks, jadi saya perlu mencari cara untuk mendapatkan informasi paling banyak tentang bentuknya menggunakan jumlah titik sampel yang paling sedikit.
Metode apa yang bagus untuk melakukan ini?
Apa yang saya miliki sejauh ini
Saya mulai dari set poin yang ada di mana saya sudah menghitung nilai fungsi (ini bisa berupa kisi persegi poin atau yang lainnya).
Lalu saya menghitung triangulasi Delaunay dari poin-poin ini.
Jika dua titik tetangga dalam triangulasi Delaunay cukup jauh ( ) dan nilai fungsi cukup berbeda di dalamnya ( > Δ f ), maka saya memasukkan titik baru di tengah-tengah di antara mereka. Saya melakukan ini untuk setiap pasangan titik tetangga.
Apa yang salah dengan metode ini?
Yah, itu bekerja relatif baik, tetapi pada fungsi yang mirip dengan ini tidak ideal karena titik sampel cenderung "melompati" punggungan dan bahkan tidak menyadari itu ada di sana.
Ini menghasilkan hasil seperti ini (jika resolusi grid titik awal cukup kasar):
Plot di atas menunjukkan titik di mana nilai fungsi dihitung (sebenarnya sel Voronoi di sekitarnya).
Plot di atas menunjukkan interpolasi linier yang dihasilkan dari titik yang sama, dan membandingkannya dengan metode pengambilan sampel bawaan Mathematica (untuk resolusi awal yang hampir sama).
Bagaimana cara memperbaikinya?
Saya pikir masalah utama di sini adalah bahwa metode saya memutuskan apakah akan menambahkan titik perbaikan atau tidak berdasarkan gradien.
Akan lebih baik untuk memperhitungkan kelengkungan atau setidaknya turunan kedua saat menambahkan poin perbaikan.
Pertanyaan
Apa cara yang sangat sederhana untuk menerapkan cara memperhitungkan turunan atau kelengkungan kedua ketika lokasi poin saya tidak dibatasi sama sekali? (Saya tidak harus memiliki kisi kuadrat dari titik awal, ini idealnya bersifat umum.)
Atau cara sederhana apa yang ada untuk menghitung posisi titik perbaikan secara optimal?
Saya akan menerapkan ini dalam Mathematica, tetapi pertanyaan ini terutama tentang metode ini. Untuk bit "mudah diimplementasikan" tidak dihitung bahwa saya menggunakan Mathematica (yaitu ini mudah dilakukan sejauh ini karena memiliki paket untuk melakukan triangulasi Delaunay)
Masalah praktis apa yang saya terapkan ini
Saya menghitung diagram fase. Ini memiliki bentuk yang rumit. Di satu wilayah nilainya 0, di wilayah lain itu antara 0 dan 1. Ada lompatan tajam antara kedua wilayah (itu terputus-putus). Di wilayah di mana fungsi lebih besar dari nol ada beberapa variasi halus dan beberapa diskontinuitas.
Nilai fungsi dihitung berdasarkan simulasi Monte Carlo, sehingga kadang-kadang nilai fungsi atau noise yang salah diharapkan (ini sangat jarang terjadi, tetapi untuk sejumlah besar titik itu terjadi, misalnya ketika kondisi mapan tidak tercapai karena beberapa faktor acak)
Saya sudah menanyakan ini di Mathematica.SE tetapi saya tidak dapat menautkannya karena masih dalam versi beta pribadi. Pertanyaan ini di sini adalah tentang metode, bukan implementasinya.
Balas ke @suki
Apakah ini jenis pembagian yang Anda sarankan, yaitu menempatkan titik baru di tengah segitiga?
Perhatian saya di sini adalah bahwa tampaknya memerlukan penanganan khusus di tepi wilayah, jika tidak akan memberikan segitiga yang sangat panjang dan sangat tipis, seperti yang ditunjukkan di atas. Apakah Anda benar untuk ini?
MEMPERBARUI
Masalah yang muncul baik dengan metode yang saya jelaskan dan dengan saran @ suki untuk menempatkan pembagian berdasarkan segitiga dan menempatkan titik pembagian di dalam segitiga adalah bahwa ketika ada diskontinuitas (seperti dalam masalah saya), mengkompilasi ulang triangulasi Delaunay setelah langkah mungkin menyebabkan segitiga berubah dan mungkin beberapa segitiga besar muncul yang memiliki nilai fungsi yang berbeda dalam tiga simpul.
Berikut ini dua contoh:
Yang pertama menunjukkan hasil akhir saat pengambilan sampel di sekitar diskontinuitas lurus. Yang kedua menunjukkan distribusi titik sampling untuk kasus serupa.
Apa cara sederhana yang ada untuk menghindari ini? Saat ini saya hanya membagi lagi egdes yang hilang setelah retriangulation, tapi ini terasa seperti retasan dan perlu dilakukan dengan hati-hati seperti dalam kasus jerat simetris (seperti kotak persegi) ada beberapa triangulasi Delaunay yang valid, maka ujung-ujungnya mungkin berubah secara acak setelah retriangulasi.
sumber
Jawaban:
Saya bekerja pada masalah yang mirip dengan ini beberapa waktu lalu.
Saya pikir perbedaan utama antara implementasi kami adalah bahwa saya memilih tempat untuk menambahkan poin berdasarkan segitiga, bukan tepi. Saya juga memilih titik-titik baru di dalam segitiga daripada di tepi.
Saya merasa bahwa menambahkan titik di dalam segitiga akan membuatnya lebih efisien dengan memberikan sedikit peningkatan jarak rata-rata dari titik lama ke yang baru.
Pokoknya hal baik lainnya tentang menggunakan segitiga bukan tepi adalah memberikan perkiraan vektor gradien, bukan kemiringan di sepanjang tepi khusus ini.
Dalam kode matlab saya, saya menggunakan kelas dasar untuk mengurus sebagian besar mesin, dengan beberapa metode abstrak:
weight(self)
untuk memutuskan prioritas segitiga mana yang akan dibagi berikutnya.choosePoints(self,npoints = "auto")
untuk memutuskan poin-poin baru untuk dievaluasi berdasarkan bobot masing-masing segitiga.Saya menemukan pengaturan ini sangat fleksibel:
weight()
ke area segitiga menghasilkan kepadatan jala yang konstan.weight()
untuk menghitung nilai fungsi rata-rata kali luas segitiga memberikan semacam sampling probabilitas kuasi-acak.var(triangle.zs)
bisa lakukan, untuk fungsi yang memiliki keluaran biner, apa yang saya rasakan adalah generalisasi dari pencarian pembelahan ke lebih dari 1 dimensi.area + var(triangle.zs)
cukup efektif untuk menempatkan kepadatan konstan di mana-mana, dan peningkatan kepadatan di sepanjang lereng apa pun (hampir seperti yang Anda miliki sekarang).Saya menggunakan varians dari nilai z, untuk memperkirakan pentingnya efek urutan pertama (kemiringan) karena varians tidak akan pernah pergi hingga tak terbatas seperti kemiringan yang bisa.
Sebagai contoh terakhir, kepadatan latar belakangnya bagus karena saya sedang mencari gumpalan diskontinyu bernilai tinggi di ruang bernilai rendah. Jadi perlahan-lahan akan mengisi seluruh jala dan ketika akan menemukan gumpalan itu akan berkonsentrasi mengikuti tepi gumpalan sepanjang jalan di sekitar karena berat tinggi saya memakai gradien (dan itu hanya mengisi
n
segitiga atas) pada setiap iterasi). Pada akhirnya saya bisa tahu bahwa tidak ada gumpalan (berbentuk cukup) (atau lubang di gumpalan saya) dengan ukuran lebih besar dari kepadatan latar belakang mesh yang dihasilkan.Seperti Anda, saya memang mendapatkan beberapa poin buruk dalam hasil saya, mereka tidak masalah bagi saya karena kesalahannya adalah bahwa jika Anda menjalankan kembali poin terdekat, mereka mungkin akan memberikan jawaban yang benar. Saya baru saja berakhir dengan blip peningkatan kepadatan mesh di sekitar poin buruk saya.
Apa pun yang Anda lakukan, saya selalu menyarankan untuk membuat bobot yang terkait dengan ukuran segitiga sehingga, semua yang sama, segitiga besar dipecah terlebih dahulu.
Mungkin solusi bagi Anda adalah mengambil pendekatan saya satu langkah lebih jauh dan alih-alih mengevaluasi segitiga berdasarkan isi sel segitiga itu, evaluasi berdasarkan pada satu dan ketiga segitiga yang berdekatan.
Itu akan berisi informasi yang cukup untuk mendapatkan perkiraan matriks Goni lengkap. Anda bisa mendapatkannya dengan melakukan paling tidak kuadrat dari
z = c1*x + C2*y c11*x^2+c12*x*y+c22*y^2
semua verteks dalam segitiga bunga (pusatkan sistem koordinat pada segitiga terlebih dahulu).Saya tidak akan menggunakan gradien atau Hessian (konstanta-konstanta itu) secara langsung karena mereka akan menjadi tak terhingga pada diskontinuitas.
Mungkin kesalahan sum-kuadrat dari nilai z relatif terhadap perkiraan planar dari titik-titik tersebut akan menjadi ukuran yang berguna tentang seberapa menarik efek urutan kedua.
Diperbarui:
Itu terlihat masuk akal bagi saya.
Saya tidak pernah benar-benar sempat ke casing khusus tepi. Itu sedikit mengganggu saya, tetapi untuk apa yang saya lakukan, itu sudah cukup untuk memulai dengan banyak poin di tepinya.
lebih elegan akan menggabungkan dua pendekatan kami, tepi bobot dan segitiga. Kemudian jika suatu tepi terlalu panjang, potong menjadi dua ... Saya suka cara konsep itu digeneralisasi ke dimensi yang lebih tinggi (tetapi jumlahnya menjadi sangat cepat) ...
Tetapi karena Anda tidak mengharapkan tubuh utama mesh memiliki segitiga aspek rasio tinggi, sehingga Anda bisa menggunakan fungsi seperti fungsi freeboundary Matlab untuk menemukan batas, kemudian jalankan algoritma yang sama dalam satu dimensi kurang pada batas. Jika dilakukan dengan benar, pada kubus misalnya, Anda bisa mendapatkan kepadatan jala yang sama di tepi, di wajah, dan di dalam kubus. Menarik.
Satu hal yang saya tidak pernah menemukan solusi yang baik adalah kenyataan bahwa versi saya tidak akan pernah mengeksplorasi di luar cembung cangkang dari set poin awal.
sumber
Saya pikir masalah utama dalam heuristik Anda adalah bahwa Anda mempertimbangkan gradien hanya dalam satu dimensi dan dengan demikian, di daerah di mana dfdx kecil tetapi dfdy besar (seperti yang terjadi di tengah-tengah contoh Anda), Anda akan kehilangan poin ketika melihat dalam dimensi "salah".
Salah satu perbaikan cepat adalah dengan mempertimbangkan set empat titik, mengambil pusat gravitasi mereka, dan mendekati | dfdx | + | dfdy | menggunakan empat poin itu. Alternatif lain adalah mengambil tiga titik (yaitu segitiga) dan mengambil gradien maksimum permukaan di atasnya.
sumber