Julia: Menghentikan `yang`?

Dibuat pada 2 Nov 2017  ·  46Komentar  ·  Sumber: JuliaLang/julia

Sekarang kita membedakan one dan oneunit , ones(T, sz) sepertinya keliru. Menolak mendukung fill(oneunit(T), sz) ? Jika demikian, haruskah kita membuang zeros juga?

decision linear algebra stdlib

Komentar yang paling membantu

Bagi saya fill(oneunit(T), sz) terlihat seperti kerugian non-sepele dalam keterbacaan dibandingkan dengan ones(T, sz) .

Semua 46 komentar

xref https://github.com/JuliaLang/julia/issues/11557#issuecomment -339776065 dan di bawahnya, dan juga @Sacha0 's PR #24389

Saya memiliki pekerjaan yang sedang berjalan untuk efek ini yang saya harap akan saya posting dalam satu atau dua hari berikutnya :). Terbaik!

Bagi saya fill(oneunit(T), sz) terlihat seperti kerugian non-sepele dalam keterbacaan dibandingkan dengan ones(T, sz) .

Perhatikan bahwa Anda jarang perlu menulis sesuatu yang bertele-tele seperti fill(oneunit(T), sz) , karena biasanya literal atau sesuatu yang serupa sudah cukup sebagai pengganti oneunit(T) . Mantra yang lebih pendek juga dapat dimungkinkan dengan perubahan di masa mendatang pada konstruktor array. Selain itu, setelah Anda beralih ke fill , Anda akan menyukainya, saya jamin :). Terbaik!

Kita bisa memilih apakah ones menggunakan one atau oneunit . ones dan zeros harus dianggap sebagai fungsi kenyamanan, yang boleh saja asalkan memiliki arti yang jelas dalam hal fungsi yang lebih umum.

Rencana per triase: Kunjungi kembali minggu depan, khususnya mempertimbangkan untuk memindahkan ones dan zeros ke lapisan kompatibilitas MATLAB, demi fill di basis. Terbaik!

ones dan oneunits akan membedakan dua opsi.

Tidak yakin bagaimana perasaan saya tentang memindahkan ini dan zeros ke kompatibilitas MATLAB. Hanya karena Mathworks menemukan itu tidak berarti itu bukan API kenyamanan yang baik yang bisa kita banggakan . Secara singkat - apa alasan di balik pemikiran ini? (Maaf, saya harus mengatakan bahwa triase tampaknya jauh lebih efisien, tetapi secara signifikan kurang transparan ketika alasannya tidak diberikan).

Ini juga bukan perubahan yang membuat saya senang, tetapi saya mengangkatnya karena ini adalah inkonsistensi logis. Saya pikir adil untuk mengatakan bahwa ones(T, sz) menyiratkan fill(one(T), sz) tetapi sebenarnya apa yang dilakukannya di bawah tenda adalah fill(oneunit(T), sz) .

Salah satu opsi adalah mengganti namanya menjadi oneunits . Alternatifnya adalah melakukan swap yang mengerikan: one -> algebraic_one dan oneunit -> one . Ini melanggar dan tidak mungkin dilakukan melalui penghentian, itulah sebabnya saya mengatakan "mengerikan."

Ya, saya akan mengatakan menambahkan oneunits dan mengubah ones untuk memberikan fill(one(T), ...) akan menjadi perbaikan yang jelas untuk itu, bukan?

Aku akan baik-baik saja dengan itu. Karena penasaran, apa gunanya fill(one(T), sz) ? Apakah kita membutuhkan ones sama sekali?

Haha :) Saya akan bertanya - untuk apa Anda menggunakan fill(oneunits(T), sz) ? (Misalnya, untuk apa larik yang diisi dengan 1 meter, atau 1 kilogram, atau 1 detik?)

Saya pikir fill(one(T), sz) digunakan untuk alasan yang hampir sama dengan zeros(T, sz) , yaitu menginisialisasi array untuk operasi tipe pengurangan kustom. Array z = zeros(T, sz) siap untuk menambahkan elemennya dengan z[i] += x sedangkan o = fill(one(T), sz) siap untuk elemennya dikalikan o[i] *= x . Misalnya, saya sedang memikirkan situasi di mana elemen array mungkin mewakili probabilitas (relatif). Dalam dua kasus ini, saya mencari identitas untuk masing-masing operator + atau * (dan bukan generator tambahan).

Lihat juga #23544

Haha :) Saya akan bertanya - untuk apa Anda menggunakan fill(oneunits(T), sz)? (Misalnya, untuk apa larik yang diisi dengan 1 meter, atau 1 kilogram, atau 1 detik?)

Variabel dependen untuk ODE. Akan aneh jika hanya memotong unit secara acak ketika Anda meminta array tipe T ?

Alasan mendasar untuk memilih fill adalah bahwa seperangkat alat yang kuat, ortogonal, dan dapat dikomposisi berfungsi lebih baik daripada kumpulan alat ad hoc, terbatas, dan tumpang tindih yang lebih besar seperti ones / zeros / trues / falses . Diskusi di atas menyoroti poin ini: Sementara fill mengakomodasi semua kasus penggunaan di atas dengan jelas dan (dalam sebagian besar penggunaan nyata) secara ringkas, ones / zeros / trues / Pendekatan falses membutuhkan fungsi baru untuk setiap kasus penggunaan.

Beberapa contoh yang relevan dari penulisan ulang di pangkalan:

complex.(ones(size(Ac, 1)), ones(size(Ac, 1)))

menjadi

fill(1.0 + 1.0im, size(Ac, 1))

dan

2ones(Int, 2, 2, 2)

menjadi

fill(2, (2, 2, 2)) # or fill(2, 2, 2, 2) if you prefer

Harap dicatat bahwa mantra fill ini lebih sederhana, lebih mudah dibaca, lebih ringkas, dan lebih efisien daripada mantra non- fill , dan base/ dan test/ adalah penuh dengan contoh seperti ini. Seperti semua perubahan, transisi ke fill memerlukan beberapa penyesuaian mental awal. Tapi pasca-penyesuaian Anda menemukan Anda memiliki lebih banyak kekuatan dan keanggunan di ujung jari Anda :). Terbaik!

@Sacha0 : trues / falses tidak langsung dapat diganti oleh fill , tetapi perlu menggunakan fill! dengan BitArray initializer. Mereka juga tidak termasuk dalam ambiguitas antara one dan oneunit . Oleh karena itu saya tidak berpikir bahwa mereka cocok dalam diskusi ini sama sekali.

Adapun ones , saya biasanya menentang untuk mencelanya, saya tidak melihat manfaatnya. Argumen bahwa beberapa ekspresi dapat ditulis lebih efektif dengan fill tidak terlalu meyakinkan, karena semua contoh ini menggunakan ones sebagai langkah perantara untuk melakukan sesuatu yang lain; tetapi bagaimana ketika Anda benar-benar menginginkan array? Kemudian harus menggunakan fill lebih lama, kurang jelas dan hanya lebih mengganggu. Saya paling suka proposal @JeffBezanson . Jika bagian dari base atau test dapat ditulis ulang dengan lebih efektif menggunakan fill daripada ones tidak ada yang mencegahnya sekarang.

@carlobaldassi Sementara itu benar, pencarian cepat di GitHub mengungkapkan bahwa hampir semua penggunaan ones seharusnya benar-benar menggunakan fill untuk menghindari alokasi perantara...

Menggunakan fill untuk kasus ini masuk akal bagi saya. Perhatikan bahwa kita akan menginginkan metode fill(x, A) = fill!(x, copymutable(A)) untuk menggantikan metode yang sesuai dari ones dll.

@TotalVerb Dari skim cepat di 10 halaman pertama pencarian itu, saya tidak akan mengatakan bahwa "hampir semua" adalah penilaian yang adil. Sebuah "fraksi yang signifikan", di terbaik. Ada banyak sekali kasus penggunaan yang sah untuk ones sana, bahkan mungkin sebagian besar (dan bahkan jika mereka hanya mengatakan 20%, saya pikir argumen saya masih berlaku).

(Saya juga sebenarnya memiliki keraguan tentang argumen keterbacaan, saya pikir patut dipertanyakan untuk mengklaim bahwa misalnya fill(2, 2, 2, 2) lebih mudah dibaca daripada 2 * ones(Int, 2, 2, 2) , atau itu, katakanlah, fill(k * 1.0, 3) akan lebih dapat dibaca dari k * ones(3) ; Saya sama sekali tidak yakin bahwa ini hanya masalah kebiasaan. Ini adalah poin kecil sekalipun.)

trues/falses tidak langsung diganti dengan fill, tetapi perlu menggunakan fill! dengan penginisialisasi BitArray. Mereka juga tidak termasuk dalam ambiguitas antara satu dan satu kesatuan. Oleh karena itu saya tidak berpikir bahwa mereka cocok dalam diskusi ini sama sekali.

Memang, trues dan falses tidak dapat langsung diganti dengan fill :). Sebaliknya, trues dan falses adalah contoh tambahan dari masalah umum yang dijelaskan di atas / terkait dengan #11557 (dan yang diharapkan akan ditangani oleh konstruktor array baru-baru ini). Contoh lain termasuk keberadaan misalnya bones , bzeros , brand , brandn , dan beye di BandedMatrices.jl dan yang setara dengan d awalan di DistributedArrays.jl.

Adapun yang, saya biasanya menentang mencela itu, saya tidak melihat manfaatnya. Argumen bahwa beberapa ekspresi dapat ditulis lebih efektif dengan isian tidak terlalu meyakinkan menurut saya, karena semua contoh ini menggunakan yang sebagai langkah perantara untuk melakukan sesuatu yang lain

Baru saja menulis ulang beberapa ratus penggunaan ones di basis, saya dapat menegaskan pernyataan @TotalVerb

pencarian GitHub cepat mengungkapkan bahwa hampir semua penggunaan yang benar-benar harus menggunakan isian untuk menghindari alokasi perantara...

(Sunting: Meskipun saya akan mengatakan kira-kira setengah daripada hampir semua, dan penulisan ulang yang tepat mungkin sesuatu selain fill .) Selain itu, pengalaman menulis ulang itu telah mengajari saya ...

tetapi bagaimana ketika Anda benar-benar menginginkan array? Kemudian harus menggunakan fill lebih lama, kurang jelas dan hanya lebih mengganggu.

... bahwa di sisi lain, fill seringkali lebih pendek dan sederhana dalam hal ini: Yang diminta seringkali bukan Float64 (sebagai gantinya, misalnya ones(Int, n...) dan ones(Complex{Float64}, n...) ), dalam hal ini fill lebih pendek dan sederhana dengan mengakui literal (misalnya fill(1, n...) dan fill(1.0 + 0im, n...) ). Secara terukur, cabang di mana saya telah menulis ulang panggilan ones di basis ~5% lebih pendek menurut jumlah karakter dari ones -> fill menulis ulang. Terbaik!

Untuk mendapatkan pemahaman objektif tentang bagaimana ones muncul di alam liar, saya mengumpulkan semua panggilan ones muncul di sepuluh halaman pertama pencarian GitHub untuk ones dalam kode Julia, menulis ulang setiap panggilan tersebut sesuai dan mengklasifikasikan perubahan yang sesuai (lihat Intisari ini ), dan kemudian mengurangi data klasifikasi menjadi ringkasan berikut:

Analisis ini mencakup 156 panggilan ones . Dari panggilan-panggilan itu,

  • 84 panggilan (~54%) adalah ad hoc fill s. (Misalnya, ones(100)/sqrt(100)*7 disederhanakan menjadi fill(7/sqrt(100), 100) atau, lebih baik lagi, fill(.7, 100) . Favorit saya adalah kron(0.997, ones(1, J*J*s) -> fill(0.997, 1, J*J*s) .)

  • 3 panggilan (~2%) adalah siaran ad hoc. (Misalnya, A - ones(n,n) disederhanakan menjadi A .- 1. .)

  • 5 panggilan (~3%) adalah literal vektor ad hoc. (Misalnya, ones(1) disederhanakan menjadi [1.] .)

  • 1 panggilan (~ 0,5%) secara semantik adalah konstruksi matriks sampah. (Meskipun relatif jarang di alam liar, pola ini cukup umum di test/ karena kami tidak memiliki konstruktor praktis yang ringkas untuk Array s yang tidak diinisialisasi, seperti misalnya <strong i="32">@test_throws</strong> DimensionMismatch BLAS.trsv(...,Vector{elty}(n+1)) versus <strong i="34">@test_throws</strong> DimensionMismatch BLAS.trsv(...,ones(elty,n+1)) .)

Panggilan yang tersisa secara semantik masuk akal sebagai ones , meskipun seringkali ones melihat penggunaan hanya karena pendek, bukan karena one secara khusus diperlukan. Dari panggilan yang tersisa,

  • 13 panggilan (~8%) sedikit lebih pendek karena fill . (Misalnya, ones(Int, n, n) -> fill(1, n, n) atau ones(Float64, n) -> fill(1., n) .)

  • 50 panggilan (~32%) sedikit lebih lama karena fill . (Misalnya, ones(n, n) -> fill(1., n, n) .)

Secara keseluruhan, di alam liar ~60% dari ones lebih baik ditulis dengan cara lain, ~8% secara semantik ones dan sedikit lebih pendek sebagai fill , dan ~32% adalah cukup semantik ones dan sedikit lebih lama sebagai fill .

Pengamatan tambahan:

Saya hanya menemukan satu contoh panggilan ones menerima argumen array, dan tidak jelas apakah cuplikan terlampir adalah kode asli. Jadi metode ones menerima argumen array tidak banyak berguna jika digunakan di alam liar.

Diskusi yang benar-benar menarik ... beralih dari pihak yang menentang ke pihak yang mendukung ... Juga sebagai preseden bahasa lain, R menggunakan rep dan matrix dengan cara yang setara dengan fill (sesuai dengan kasus 1d dan 2d) dan Anda akan terbiasa dengan sangat cepat -- meskipun saya berasal dari dunia nol/satuan.

Wow, terima kasih @Sacha0 telah melakukan upaya itu!

Pertanyaan secara alami muncul sebagai "bagaimana dengan zeros "? Saya menduga akan ada lebih banyak penggunaan secara signifikan, dan beberapa kategori penggunaan lagi (termasuk hal-hal seperti "Saya tidak mempercayai array yang tidak diinisialisasi" atau "Saya tidak tahu cara menggunakan Array konstruktor ").

Untuk alasan apa pun (saya kira itu adalah simetri one dan zero ), saya agak tertarik untuk mengganti ones dan zeros dengan fill , atau tidak keduanya.

Masalahnya dengan nol adalah Anda tampaknya berada dalam salah satu situasi ini:

  1. Anda perlu menimpa sebagian besar angka nol – dalam hal ini Anda lebih baik menggunakan pemahaman;
  2. Anda tidak perlu mengganti sebagian besar angka nol – dalam hal ini Anda lebih baik menggunakan matriks sparse;
  3. Anda sebenarnya membutuhkan matriks nol – dalam hal ini Anda lebih baik menggunakan 0I .

Benar-benar tidak ada kasus penggunaan di mana sebenarnya mengalokasikan matriks nol padat sebenarnya adalah ide yang bagus.

Itu mungkin benar untuk aljabar linier. Tidak jarang membutuhkan koleksi yang diinisialisasi nol dalam pekerjaan saya tentang kompiler dan struktur data lainnya. Mungkin mereka sering jarang, tetapi tidak sebanding dengan dampak kinerja untuk mewakilinya secara kompak.

Cukup adil – terkadang Anda tidak peduli dengan kepadatan dan kesederhanaannya sepadan.

Triage: memutuskan bahwa kami hanya menyimpan metode yang sepenuhnya non-generik yaitu zeros(dims...) dan ones(dims...) dan mungkin juga zeros(dims) dan ones(dims) .

@StefanKarpinski untuk rekomendasi penggunaan apakah itu berarti kami akan merekomendasikan zeros(3, 3) lebih dari fill(0.0, 3, 3) untuk kode normal (ketika array padat diinginkan, dll, dll)? Beberapa detail efisiensi dll berada di luar jangkauan saya, saya hanya memikirkan bagaimana saya akan mengajarkan praktik terbaik/idiomatik di julia bergerak maju.

Keputusan ini tampaknya sangat mengejutkan bagi saya, tidak begitu umum di pangkalan untuk secara khusus mencegah kedermawanan. Apa alasan di baliknya? apakah fungsi ini berasal dari matlab yang tidak umum (dan hanya berfungsi dengan pelampung)?

Triage: memutuskan bahwa kami hanya menyimpan metode yang sepenuhnya non-generik

Apa alasan di baliknya?

Lebih jauh dari ini, apakah masalah ini entah bagaimana terkait dengan masalah umum dalam membangun array yang tampaknya sedang dipertimbangkan saat ini, dan jika demikian, bagaimana ini membantu? Atau, apakah kita mencoba mengurangi jumlah metode yang diekspor dari Base ? (Atau sesuatu yang lain sama sekali?)

Penulisan akan datang di https://github.com/JuliaLang/julia/issues/24595 :). Terbaik!

OP 24595 merinci konteks masalah ini yang lebih luas, dan sekarang tindak lanjut di #24595 secara khusus membahas konstruktor kenyamanan ones , zeros , dan fill secara mendalam. Membaca yang pertama berharga dalam menghargai yang terakhir. Terbaik!

Yah, menyimpan setidaknya kasing Float64 lebih baik daripada tidak sama sekali.
Saya percaya bahwa kasus bilangan bulat nol juga cukup relevan, yang -- saya asumsikan -- pada dasarnya adalah poin yang dibuat oleh sini .

Perlu juga dicatat bahwa zeros tidak memiliki "masalah" untuk mengizinkan 3 * ones(n) anti-pola. Sebenarnya, saya tidak begitu mengerti mengapa ones dan zeros harus berjalan bersama, kecuali dalam arti luas sebagai konstruktor kenyamanan. Tidak ada 'simetri' nyata di antara keduanya.

Beberapa komentar tambahan pada analisis statistik , karena tampaknya menjadi dasar dari diskusi berikut dan penulisan #24595. Pertama, sepuluh halaman tidak benar-benar cukup untuk kesimpulan halus tentang apa yang terjadi di alam liar, mereka dapat memberikan gambaran kasar yang terbaik. Beberapa file datang langsung dari matlab, misalnya, karena jelas dari nama/gayanya. Kedua, seperti yang saya duga, bahkan analisis itu menunjukkan bahwa kira-kira setengah dari penggunaan ones di sana adalah "sah". Ketiga, melihat kode seperti ini tidak memberi tahu apa pun tentang saat menulis 3 * ones(...) benar-benar anti-pola yang menciptakan masalah kinerja, atau itu adalah bagian dari kode yang tidak memiliki implikasi kinerja sama sekali (dan penulis mungkin telah memutuskan bahwa itu hanya lebih mudah dibaca ditulis seperti itu - yang menurut saya bukan urusan orang lain untuk memutuskan sebaliknya, dalam kasus itu).

Terkait dengan poin terakhir, dan saya pikir yang lebih penting, apa yang Anda lihat dari pencarian github tidak akan pernah memperhitungkan apa yang terjadi di REPL orang yang melakukan pekerjaan eksplorasi/pendahuluan di Julia. Di situlah fungsi kenyamanan paling berguna, dan mengambilnya tanpa alasan yang jelas adalah hal yang paling menjengkelkan. Maksud saya adalah, memiliki seperangkat primitif ortogonal yang konsisten yang memungkinkan untuk menulis kode generik dan efisien adalah tujuan yang bagus, dan upaya untuk sampai ke sana benar-benar terpuji; hanya saja tidak semua kode seharusnya indah, generik, kode perpustakaan yang dapat dikomposisi. Hanya dua sen saya.

Tentang

Saya percaya bahwa kasus bilangan bulat nol juga cukup relevan, yang -- saya asumsikan -- pada dasarnya adalah poin yang dibuat @vtjnash sini.

yang mengacu pada

Tidak jarang membutuhkan koleksi yang diinisialisasi nol dalam pekerjaan saya tentang kompiler dan struktur data lainnya. Mungkin mereka sering jarang, tetapi tidak sebanding dengan dampak kinerja untuk mewakilinya secara kompak.

Perhatikan bahwa fill berfungsi dengan baik atau lebih baik dalam hal ini: fill(0, shape...) versus zeros(Int, shape...) .

Mengenai poin Anda yang lain, #24595 mungkin layak dibaca :). Terbaik!

Saya hanya menemukan bahwa zeros(Int, 10, 10) lebih mudah dibaca/eksplisit daripada fill(0, 10, 10) , dan zeros(T, k) lebih baik daripada fill(zero(T), k) . Mengapa kita tidak memiliki keduanya saja? Saya tidak menerima argumen bahwa zeros mengalami masalah ambiguitas yang sama dengan ones .

Mengenai poin Anda yang lain, #24595 mungkin layak dibaca

Saya telah membacanya. (Saya bahkan menghubungkannya.)

Saya telah membacanya. (Saya bahkan menghubungkannya.)

Setelah membaca #24595 secara penuh dan mempertimbangkannya, Anda kemudian menyadari bahwa #24595: (1) menyangkut masalah yang jauh lebih luas di mana konstruktor kenyamanan hanya merupakan bagian; dan (2) mempertimbangkan lebih dari sekadar analisis statistik yang diposting di atas dan poin-poin yang Anda fokuskan di sini.

Saya menghargai bahwa Anda merasa sangat yakin tentang ones dan zeros ; sentimen Anda telah datang dengan keras dan jelas :). Dengan demikian, kemungkinan bandwidth kita akan lebih baik dihabiskan untuk mendorong bidang lain ke depan daripada melanjutkan percakapan ini dalam bentuknya yang sekarang. Terbaik!

Apakah ada fill generik yang masuk bersama dengan perubahan zeros ? zeros memiliki penggunaan yang sangat sah untuk pemrograman generik karena jauh lebih aman daripada similar , jadi semua DiffEq, dan kemudian saya tahu baru-baru ini Optim dan NLsolve pindah dari mengalokasikan dengan similar ke zeros karena mengetahui semuanya dialokasikan untuk memiliki nol di dalamnya menghentikan banyak bug. Namun, sekarang tampaknya tidak akan ada metode untuk:

zeros(X)

lagi, selain:

similar(X); fill!(X,0)

karena fill hanya membangun Array s dan karenanya tidak cocok dengan tipe seperti similar atau zeros . Saya tahu bahwa beberapa orang menyalahgunakan zeros untuk mengalokasikan ketika mereka tidak seharusnya, tetapi mengalokasikan dengan zeros adalah hal yang sangat wajar untuk dilakukan dalam banyak kasus. Saya berharap steno fill(0,X) ditambahkan untuk mengisi kekosongan ini.

Banyak terima kasih untuk posting bijaksana Chris! :) Sebagai pengganti singkatan sementara, apakah zero(X) berhasil?

Perhatikan bahwa kasus penggunaan seperti itu tepat di mana ambiguitas dalam zeros dan ones dapat menjadi masalah: Apakah zeros(X) menghasilkan objek dengan eltype(X) dan diisi dengan eltype(X) identitas aditif fill!(similar(X), 0) ), atau sebagai gantinya sebuah objek yang diisi dengan nol perkalian untuk eltype(X) (mungkin bukan eltype(X) )? (Untuk perluasan, lihat #24595.)

Konsep fill(0, X) melihat sedikit diskusi di #11557, dan saya setuju itu mungkin merupakan generalisasi yang berguna dari fill . Terima kasih dan terbaik!

Masalah lainnya adalah bahwa array dengan indeks yang tidak konvensional mungkin ingin dibuat dengan sesuatu seperti zeros(inds...) (karena tipe indeks menentukan tipe array ). Tetapi untuk kasus 1-d, apakah X "array yang Anda inginkan mirip dengan" atau "indeks untuk larik yang diinginkan"? (Lagi pula, AbstractUnitRange <: AbstractArray .) Secara konkret, apakah zeros(3:5) berarti fill!(similar(3:5), 0) atau fill!(OffsetArray(Vector{Float64}(3), 3:5), 0) ?

Menautkan https://github.com/JuliaLang/julia/pull/24656 , yang berisi diskusi tambahan tentang konstruktor kenyamanan {ones|zeros }(A::AbstractArray, ...) . Terbaik!

Saya terkejut itu dianggap aneh untuk menggunakan zeros untuk membuat variabel cache menurut #24656. Saya akan berpikir bahwa, jika zeros dikurangi mendekati nol overhead, hampir semua kasus di mana orang menggunakan similar seharusnya menjadi zeros karena itu cenderung memperbaiki beberapa bug. Saya pikir kita harus mendorong lebih banyak orang untuk melakukan ini karena similar bisa sangat tidak aman, dan tidak memiliki fungsi dan malah menyatukan fill! + similar membuatnya kurang jelas bahwa apa yang seharusnya dilakukan orang. Berikut komentar tentang ini yang muncul di Optim.jl:

https://github.com/JuliaNLSolvers/NLsolve.jl/issues/89#issuecomment -294585960

Namun, saya setuju dengan @timholy bahwa tidak jelas bagaimana seharusnya ditafsirkan. Biarkan saya mengarahkan Anda ke contoh yang sangat tidak sederhana di DiffEq.

https://github.com/JuliaDiffEq/MultiScaleArrays.jl

MultiScaleArrays.jl membuat array abstrak yang merupakan struktur seperti grafik rekursif yang dapat digunakan dalam pemecah diffeq (dan saya pikir itu mungkin kompatibel dengan Optim.jl dan NLsolve.jl sekarang?). Ini adalah kenyamanan yang bagus untuk model biologis antara lain. Ketika kita melemparkannya ke dalam ODE solver ada pertanyaan: apa yang harus kita buat array cache? Dalam beberapa kasus penting bahwa pengguna mendapatkan kembali array yang mereka inginkan karena akan muncul dalam fungsi ODE mereka f(t,u,du) dan mereka akan ingin memperlakukannya sesuai. Namun, dalam kasus lain itu hanya muncul sebagai sesuatu yang disiarkan secara internal. Jadi ada dua jenis variabel cache yang berbeda.

Untuk menangani ini, lihat cache untuk salah satu algoritme:

https://github.com/JuliaDiffEq/OrdinaryDiffEq.jl/blob/master/src/caches/low_order_rk_caches.jl#L224 -L234

Di sini, rate_prototype = similar(u,first(u)/t,indices(u) serupa tetapi dengan eltype yang berpotensi berbeda untuk unit. Tetapi perhatikan bahwa ada dua jenis terpisah di sini: similar(u) vs similar(u,indices(u)) . Saya telah menafsirkan itu berarti "cocok dengan tipe dan bentuknya" vs "cocok dengan bentuk dan eltype, tetapi tidak harus tipe yang sama". Jadi untuk AbstractMultiScaleArray , yang pertama akan membuat AbstractMultiScaleArray sementara yang lain, untuk kecepatan karena tidak terlihat oleh pengguna, hanya akan membuat Array yang sesuai ukuran. Ini kemudian diperluas ke similar(u,T) dan similar(u,T,indices(u)) .

Mungkin itu hanya mengolok-olok apa yang sudah ada, tapi saya pikir ini adalah perbedaan penting. Saat melakukan pemrograman generik, Anda memiliki dua cache terpisah: cache yang menghadap pengguna yang ingin Anda cocokkan jenisnya agar sesuai dengan harapan mereka, dan cache internal yang hanya digunakan oleh algoritme dan Anda menginginkan kecepatan sebanyak mungkin.

Perhatikan bahwa ini menggunakan similar karena saya terlalu malas untuk membuat versi zeros . Saya sebenarnya memiliki tempat terpisah yang dapat menghilangkan beberapa array ini karena jika pengguna hanya menetapkan du dalam perhitungan turunan f(t,u,du) mereka, mereka cenderung secara implisit mengatakan "apa yang tidak saya tetapkan berarti nol", yang hanya benar ketika dialokasikan dengan zeros , jadi saya mencoba mengalokasikan sebelumnya menggunakan zeros sebanyak mungkin (masalah yang sama muncul di NLsolve.jl untuk ini) .

Semoga penjelasan itu tidak terlalu membingungkan untuk diikuti. Dalam semua kasus saya, saya hanya dapat beralih ke similar diikuti oleh fill! , tetapi saya tahu beberapa paket tidak dan itu akan menjadi sumber bug.

Menarik. Anda benar bahwa similar(A, inds) mungkin membuat tipe yang berbeda dari similar(A) , tetapi secara umum saya selalu menganggapnya sebagai kemungkinan membuat tipe yang sama tetapi dengan indeks yang berbeda. Misalnya, jika Anda memerlukan cache 1 dimensi untuk operasi kolom pada objek 2-d, saya akan menggunakan similar(A, first(inds)) . (Tentu saja ini adalah tipe yang berbeda karena dimensi adalah parameter tipe, tetapi mungkin tipe kontainer abstrak yang sama.) Anda juga dapat menggunakannya untuk membuat cache 5x5 dari petak kecil, dll.

Secara keseluruhan ini tampaknya menjadi masalah yang menantang. Ini sedikit terlambat dalam permainan, tetapi haruskah kita memperkenalkan same ? Itu bisa memiliki argumen yang sama dengan similar , tetapi kontraknya adalah bahwa itu akan diminta untuk mengembalikan wadah abstrak yang sama.

Saya dapat mendukung bentuk satu argumen same , tetapi bahkan ini rumit - perhatikan bahwa same(a) tidak dapat mengembalikan tipe array yang sama jika a tidak mendukung setindex! karena same dan similar hanya berguna jika Anda akan menulis ke array setelahnya. Kita dapat membuat kesalahan ini untuk a tidak dapat diubah, tetapi sebagai antarmuka untuk AbstractArray ini tampaknya tidak perlu (dan mungkin tidak membantu) untuk membuat kode generik yang benar.

Demikian pula, kami tidak dapat mengasumsikan setiap AbstractArray dapat mendukung eltypes atau indeks yang berbeda. Bagi saya, memiliki bentuk dua atau tiga argumen same hanya akan menimbulkan kesalahan run-time di banyak tempat sambil memberi orang rasa aman yang salah bahwa kode generik mereka akan berfungsi dengan baik untuk AbstractArray apa pun

Tetapi untuk kasus 1-d, apakah X "array yang Anda inginkan serupa" atau "indeks untuk larik yang diinginkan"?

Ini adalah alasan lain saya mendukung keys mengembalikan wadah dengan indeks dan nilai yang identik, dan kemudian menjadikannya persyaratan similar (kecuali jika Anda memberikan satu (beberapa) bilangan bulat di dalam hal ini Base.OneTo (CartesianRange) diasumsikan).

Diskusi ini mengarah ke #18161, dan mungkin harus dilanjutkan di sana :).

Triase terbaru condong ke arah hanya mempertahankan ones .

Apakah sakit untuk menjaga mereka? Saya pikir itu membantu orang-orang yang datang dari numpy merasa di rumah di Julia.

Penutupan karena kami mempertahankan ones dan zeros .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

tkoolen picture tkoolen  ·  3Komentar

dpsanders picture dpsanders  ·  3Komentar

Keno picture Keno  ·  3Komentar

felixrehren picture felixrehren  ·  3Komentar

omus picture omus  ·  3Komentar