Julia: Menangani transposisi vektor dengan serius

Dibuat pada 10 Nov 2013  ·  417Komentar  ·  Sumber: JuliaLang/julia

dari @alanedelman :

Kita benar-benar harus memikirkan dengan hati-hati tentang bagaimana transpose vektor harus mengirimkan berbagai metode A_*op*_B* . Itu harus mungkin untuk menghindari jenis baru dan matematika jelek. Misalnya, vektor 'vektor yang menghasilkan vektor (# 2472, # 2936), vektor' menghasilkan matriks, dan vektor '' menghasilkan matriks (# 2686) semuanya adalah matematika yang buruk.

Apa yang berhasil bagi saya secara matematis (yang menghindari memperkenalkan tipe baru) adalah untuk 1 dimensi Vector v :

  • v' adalah no-op (yaitu hanya mengembalikan v ),
  • v'v atau v'*v adalah skalar,
  • v*v' adalah matriks, dan
  • v'A atau v'*A (di mana A adalah AbstractMatrix ) adalah vektor

Transpose umum _N_-dimensional membalik urutan indeks. Sebuah vektor, yang memiliki satu indeks, harus tidak berubah di bawah transposisi.

Dalam praktiknya v' jarang digunakan dalam isolasi, dan biasanya ditemukan dalam produk vektor-matriks dan produk matriks-matriks. Contoh umum adalah membangun bentuk bilinear v'A*w dan bentuk kuadrat v'A*v yang digunakan dalam gradien konjugasi, quotients Rayleigh, dll.

Satu-satunya alasan untuk memperkenalkan tipe Transpose{Vector} adalah untuk mewakili perbedaan antara vektor kontravarian dan kovarian, dan menurut saya ini tidak cukup menarik.

arrays breaking design linear algebra

Komentar yang paling membantu

BAM

Semua 417 komentar

Misalnya, vektor 'vektor yang menghasilkan vektor (# 2472, # 2936), vektor' menghasilkan matriks, dan vektor '' menghasilkan matriks (# 2686) semuanya adalah matematika yang buruk.

Rangkap ganda ruang vektor berdimensi hingga adalah isomorfik, tidak identik. Jadi saya tidak jelas bagaimana ini adalah matematika yang buruk. Lebih dari itu kita cenderung mengabaikan perbedaan antara hal-hal yang isomorfik dalam matematika, karena otak manusia pandai menangani ambiguitas licin semacam itu dan hanya melakukan hal yang benar. Meskipun demikian, saya setuju bahwa ini harus diperbaiki, tetapi bukan karena secara matematis salah, melainkan karena mengganggu.

Bagaimana bisa v' == v , tapi v'*v != v*v ? Apakah lebih masuk akal daripada yang kita pikirkan untuk x' * y menjadi operatornya sendiri?

Rangkap ganda ruang vektor berdimensi hingga adalah isomorfik, tidak identik.

(Berbicara sebagai diriku sekarang) Ini bukan hanya isomorfik, itu juga secara alami isomorfik, yaitu isomorfisme tidak tergantung pada pilihan basis. Saya tidak dapat memikirkan aplikasi praktis yang akan berguna untuk membedakan antara isomorfisme jenis ini dan identitas. IMO faktor gangguan berasal dari membuat perbedaan semacam ini.

Apakah lebih masuk akal daripada yang kita pikirkan untuk x' * y menjadi operatornya sendiri?

Itulah kesan yang saya dapatkan dari diskusi sore ini dengan @alanedelman.

Saya pikir apa yang Jeff tanyakan benar tentang uangnya ... itu mulai terlihat seperti x'_y dan x_y 'menghasilkan lebih banyak
rasa dari sebelumnya.

Saya dalam perjanjian kekerasan dengan @stefan. Matematika yang buruk tidak dimaksudkan untuk berarti, matematika yang salah, melainkan
berarti matematika yang menjengkelkan. Ada banyak hal yang secara teknis benar, tetapi tidak terlalu bagus ....

Jika kita mengikuti logika ini, berikut adalah dua pilihan yang kita miliki

x_x tetap error ..... mungkin dengan saran "mungkin Anda ingin menggunakan titik"
atau x_x adalah produk titik (saya tidak suka pilihan itu)

Jika x dan x' adalah hal yang sama, maka jika Anda ingin (x')*y berarti dot(x,y) yang berarti x*y juga dot(x,y) . Tidak ada jalan keluarnya. Kita bisa membuat x'y dan x'*y operasi yang berbeda, tapi saya tidak yakin itu ide yang bagus. Orang ingin dapat memberi tanda kurung ini dengan cara yang jelas dan masih berfungsi.

Saya akan menunjukkan bahwa jika kita mengizinkan x*x berarti produk titik, pada dasarnya tidak ada kata mundur. Itu akan dimasukkan ke dalam kode orang di mana-mana dan memberantasnya akan menjadi mimpi buruk. Jadi, isomorfisme alami atau tidak, ini bukan matematika murni dan kita harus berurusan dengan fakta bahwa hal yang berbeda di komputer itu berbeda.

Berikut pembahasan praktis tentang membedakan "up tuple" dan "down tuple" yang saya suka:

http://mitpress.mit.edu/sites/default/files/titles/content/sicm/book-ZH-79.html#% _idx_3310

Ini dengan hati-hati menghindari kata-kata seperti "vektor" dan "ganda", mungkin untuk menghindari orang yang mengganggu. Saya menemukan aplikasi untuk turunan parsial menarik:

http://mitpress.mit.edu/sites/default/files/titles/content/sicm/book-ZH-79.html#% _sec_Temp_453

Alasan lain untuk membedakan M[1,:] dan M[:,1] adalah bahwa saat ini perilaku penyiaran kami memungkinkan perilaku yang sangat nyaman ini: M./sum(M,1) adalah kolom-stokastik dan M./sum(M,2) adalah baris-stokastik . Hal yang sama dapat dilakukan untuk normalisasi jika kita "memperbaiki" fungsi norm untuk memungkinkan aplikasi melewati baris dan kolom dengan mudah. Tentu saja, kita masih dapat memiliki matriks pengembalian sum(M,1) dan sum(M,2) alih-alih vektor naik dan turun, tetapi tampaknya agak salah.

Saya suka ide vektor naik dan turun. Masalahnya adalah menggeneralisasikannya ke dimensi yang lebih tinggi dengan cara yang tidak sepenuhnya gila. Atau Anda bisa menjadikan vektor sebagai kasus khusus. Tapi itu juga terasa salah.

Benar bahwa naik / turun bisa jadi teori tersendiri. Pendekatan untuk menggeneralisasi mereka tampaknya merupakan struktur bersarang, yang membawa segala sesuatunya ke arah yang berbeda. Sangat mungkin ada alasan mengapa mereka tidak menyebutnya vektor.

Juga, x*y = dot(x,y) akan membuat * non-asosiatif, seperti dalam x*(y*z) vs. (x*y)*z . Saya sangat berharap kita bisa menghindari itu.

Iya. Bagi saya, itu sama sekali tidak bisa diterima. Maksud saya secara teknis, floating-point * adalah non-asosiatif, tetapi hampir asosiatif, sedangkan ini hanya akan sangat non-asosiatif.

Kita semua setuju bahwa x*x seharusnya bukan produk titik.

Pertanyaannya tetap apakah kita dapat menganggap v'w dan v'*w sebagai produk titik -
Saya sangat suka ini bekerja seperti itu.

@JeffBezanson dan saya sedang mengobrol

Sebuah proposal adalah sebagai berikut:

v' adalah kesalahan untuk vektor (Inilah yang dilakukan mathematica)
v'w dan v'*w adalah produk titik (result = scalar)
v*w adalah matriks hasil kali luar (result = matrix)

Tidak ada perbedaan antara vektor baris dan kolom. Aku tetap suka ini
dan senang melihat preseden mathematica
Dari mathematica: http://reference.wolfram.com/mathematica/tutorial/VectorsAndMatrices.html
Karena cara Mathematica menggunakan daftar untuk mewakili vektor dan matriks, Anda tidak perlu membedakan antara vektor "baris" dan "kolom"

Pengguna harus menyadari bahwa tidak ada vektor baris .... titik.

Jadi jika M adalah sebuah matriks

M[1,:]*v adalah kesalahan ..... (dengan asumsi kita menggunakan M[1,:] adalah skalar
Peringatan dapat menyarankan untuk mencoba dot atau '* atau M[i:i,:]

M[[1],:]*v or M[1:1,:]*v adalah vektor dengan panjang 1 (Ini adalah perilaku julia saat ini)

Mengenai masalah yang terkait erat di https://groups.google.com/forum/#!topic/julia -users / L3vPeZ7kews

Mathematica memampatkan bagian array seperti skalar:

m = Array[a, {2, 2, 2}] 


Out[49]= {{{a[1, 1, 1], a[1, 1, 2]}, {a[1, 2, 1], 
   a[1, 2, 2]}}, {{a[2, 1, 1], a[2, 1, 2]}, {a[2, 2, 1], a[2, 2, 2]}}}

In[123]:= Dimensions[m]
Dimensions[m[[All, 1, All]]]
Dimensions[m[[2, 1, All]]]
Dimensions[m[[2, 1 ;; 1, All]]]

Out[123]= {2, 2, 2}

Out[124]= {2, 2}

Out[125]= {2}

Out[126]= {1, 2}

[Edit: pemformatan kode - @StefanKarpinski]

@ alanedel

dengan asumsi kita pergi dengan M [1 ,:] adalah skalar

maksud Anda M [1 ,:] hanyalah sebuah vektor?

Ya maaf. Maksud saya, M [1 ,:] sedang memproses skalar 1 :-)

Mathematica menggunakan periode . daripada tanda bintang *
dan kemudian pergi ke seluruh 9 yard dan membuat (vektor. vektor) menjadi skalar, persis apa yang kita hindari
dengan tanda bintang.

Tidak diragukan lagi ada banyak masalah dengan periode tersebut, salah satunya adalah tidak
terlihat seperti "titik" dalam produk titik, dan yang lainnya berbenturan dengan
pembacaan "pointwise op" dari titik,

Unicode menyediakan karakter yang sangat baik bernama "the dot operator"
(char(8901)) yang bisa kita bayangkan menawarkan

jadi kita bisa membuat (v ⋅ w) menjadi sama dengan (v'*w)

Singkatnya, subjek proposal saat ini untuk diperdebatkan adalah

  1. Dengan demikian, pengindeksan skalar membunuh dimensi
    A[i,:] adalah vektor seperti A[:,i,j]
  2. Pengindeksan vektor tebal
    A[ i:i , : ] atau A[ [i], : ] mengembalikan matriks dengan satu baris
  3. v'w atau v'*w adalah perkalian titik untuk vektor (sama halnya dengan v*w' untuk perkalian luar)
  4. v' tidak ditentukan untuk vektor (arahkan pengguna ke permutedims(v,1) ????)
  5. v*A mengembalikan vektor jika A adalah matriks
  6. v⋅w juga mengembalikan produk titik (tetapi tidak sejauh . mathematica dengan mengerjakan matriks
  7. v*w tidak ditentukan untuk vektor tetapi peringatan mungkin memberi petunjuk kepada pengguna dengan saran yang bagus termasuk

Konsekuensinya adalah itu

Sebuah. jika Anda tetap berpegang pada semua vektor sebagai vektor kolom, semuanya bekerja
b. jika Anda membuat semuanya menjadi matriks, semuanya pasti berfungsi, dan mudah untuk membuat semuanya menjadi matriks
c. jika pikiran Anda tidak dapat membedakan vektor baris dari matriks satu baris, kemungkinan besar Anda akan berpendidikan
sopan dan anggun
d. Notasi titik ini cukup enak dipandang

Saran 5) terlihat sangat aneh bagi saya. Saya lebih suka v'*A sehingga secara eksplisit Anda menggunakan vektor ganda. Ini sangat penting dalam ruang vektor kompleks di mana rangkapnya bukan hanya transformasi "bentuk".

Saya ingin menggemakan @StefanKarpinski bahwa sangat disayangkan kehilangan perilaku penyiaran singkat kami dalam semua ini. Setelah perubahan ini, apa sintaks ringkas untuk mengambil vektor v dan menormalkan kolom matriks A dengan nilai tersebut? Saat ini, seseorang dapat menggunakan A ./ v' . Ini sangat bagus untuk manipulasi data.

Pertanyaan bagus

Skema saya tidak menghalangi v'*A mengambil konjugasi kompleks v dan mulitiplying oleh A
dan semua kasus lain yang belum saya sebutkan secara eksplisit, tetapi sudah bisa

kita bisa menghilangkan 5
mungkin itu diinginkan
itu tidak sesuai dengan aturan vektor kolom saya

Pendekatan penyiaran ini lucu dan kludgy
Satu solusi sekarang adalah A ./ v[:,[1]]

Ini memiliki keuntungan mendokumentasikan dimensi mana yang sedang disiarkan
dan menggeneralisasi ke array dimensi yang lebih tinggi

Oh dan solusi v[:,[1]] memiliki kebajikan TIDAK mengambil konjugasi kompleks
yang mungkin merupakan keinginan pengguna .....

SAYA SUKA DUA CONTOH INI karena yang pertama adalah contoh ALJABRA LINEAR
di mana konjugasi kompleks sangat sering diinginkan, tetapi contoh kedua adalah
CONTOH DATA MULTIDIMENSI di mana kami ingin segala sesuatunya berfungsi di semua dimensi
tidak hanya untuk matriks, dan kami sangat mungkin tidak ingin conjuugate yang rumit

membutuhkan # 552. Ini adalah ketiga kalinya muncul dalam dua minggu terakhir.

Alasan lain untuk membedakan M [1 ,:] dan M [:, 1] adalah bahwa saat ini perilaku penyiaran kami memungkinkan perilaku yang sangat sesuai ini: M./sum(M,1) adalah kolom-stokastik dan M./sum(M, 2) adalah baris-stokastik. Hal yang sama dapat dilakukan untuk normalisasi jika kita "memperbaiki" fungsi norma untuk memungkinkan penerapan baris dan kolom dengan mudah. Tentu saja, kita masih dapat memiliki matriks hasil penjumlahan (M, 1) dan sum (M, 2), bukan vektor naik dan turun, tetapi tampaknya agak salah.

Bagi saya, meskipun memiliki perilaku penyiaran yang baik di beberapa waktu, Anda akhirnya harus memeras unit ekstra itu sesering mungkin. Jadi, harus melakukan yang sebaliknya pada beberapa waktu tidak masalah jika sistem lainnya lebih bagus (dan menurut saya dimensi skalar yang turun akan membuat sistem lebih bagus). Jadi Anda akan membutuhkan fungsi seperti

julia> widen(A::AbstractArray,dim::Int) = reshape(A,insert!([size(A)...],dim,1)...)
# methods for generic function widen
widen(A::AbstractArray{T,N},dim::Int64) at none:1

yang akan memungkinkan kode seperti M ./ widen(sum(M,2),2) atau A ./ widen(v,1) (lihat contoh @blakejohnson di atas)

M [:, 0 ,:] dan v [:, 0] ?????

Saya lebih banyak dengan @blakejohnson tentang masalah pengurangan; Saya pribadi berpikir itu lebih jelas untuk squeeze dimensi daripada widen mereka. Saya menduga saya akan terus-menerus melihat dokumen untuk mencari tahu apakah widen menyisipkan dimensi pada atau setelah indeks yang ditunjukkan, dan penomoran menjadi sedikit lebih kompleks jika Anda ingin memperluas beberapa dimensi sekaligus. (Apa yang dilakukan widen(v, (1, 2)) untuk vektor v ?) Tak satu pun dari ini adalah masalah untuk squeeze .

Terlepas dari apakah kami akan memperlebar atau memeras secara default, saya pikir Julia harus mengikuti jejak dari numpy dalam hal pelebaran dan mengizinkan sesuatu seperti v[:, newaxis] . Tapi saya percaya bahwa saya lebih suka menyimpan dimensi daripada membuangnya, lebih sulit untuk menangkap bug di mana Anda secara tidak sengaja melebar ke arah yang salah daripada ketika Anda menekan dengan cara yang salah (yang biasanya akan memberikan kesalahan).

Dalam daftar @alanedelman
aku merasakannya

v * A mengembalikan vektor jika A adalah matriks

tidak baik.

v_A seharusnya error jika A tidak 1x1 (ketidakcocokan rentang indeks)
v'_A harus menjadi cara yang tepat untuk melakukannya.

Salah satu cara untuk menangani masalah ini adalah dengan mengonversi vektor v ke matriks nx1 secara otomatis (bila diperlukan)
dan selalu perlakukan v 'sebagai matriks 1xn (jangan pernah mengubahnya menjadi vektor atau matriks nx1)
Juga kami mengizinkan untuk secara otomatis mengubah matriks 1x1 menjadi nomor scaler (bila diperlukan).

Saya merasa ini mewakili cara berpikir yang konsisten dan seragam tentang aljabar linier. (matematika yang bagus)

Cara seragam untuk menangani semua masalah tersebut adalah dengan mengizinkan konversi otomatis (tipe?) (Bila diperlukan)
antara larik ukuran (n), (n, 1), (n, 1,1), (n, 1,1,1) dll (tetapi tidak antara larik ukuran (n, 1) dan (1, n) )
(Sama seperti kita secara otomatis mengubah bilangan real menjadi bilangan kompleks bila diperlukan)

Dalam hal ini larik ukuran (1,1) dapat diubah menjadi angka (bila diperlukan) (Lihat # 4797)

Xiao-Gang (fisikawan)

Ini meninggalkan v'_A bagaimanapun .... Saya benar-benar ingin v'_A * w bekerja

Kesan saya tentang aljabar linier di Julia adalah ia sangat terorganisir seperti aljabar matriks, meskipun ada skalar dan vektor asli (yang menurut saya bagus!)

Mari kita pertimbangkan bagaimana menangani produk seperti x*y*z*w , di mana setiap faktor dapat berupa skalar, vektor, atau matriks, mungkin dengan transpos di atasnya. Aljabar matriks mendefinisikan produk dari matriks, di mana matriks memiliki ukuran n x m . Salah satu pendekatannya adalah memperluas definisi ini sehingga n atau m dapat diganti dengan absent , yang akan bertindak seperti nilai satu sejauh menghitung produk yang bersangkutan , tetapi digunakan untuk membedakan skalar dan vektor dari matriks:

  • skalar akan menjadi absent x absent
  • vektor (kolom) akan menjadi n x absent
  • vektor baris akan menjadi absent x n

Idealnya, kami ingin mengatur hal-hal sehingga kami tidak perlu merepresentasikan vektor baris, tetapi itu akan cukup untuk mengimplementasikan operasi seperti x'*y dan x*y' . Saya merasa ini adalah skema yang dicari banyak dari kita.

Tapi saya mulai curiga bahwa pelarangan vektor baris dalam skema semacam ini akan menimbulkan biaya tinggi. Contoh: Pertimbangkan bagaimana kita perlu mengurung produk untuk menghindari pembentukan vektor baris pada langkah perantara: ( a adalah skalar, u dan v adalah vektor)

a*u'*v = a*(u'*v) // a*u' is forbidden
v*u'*a = (v*u')*a // u'*a is forbidden

Untuk mengevaluasi produk x*y'*z sambil menghindari menghasilkan vektor baris, kita perlu mengetahui jenis faktor sebelum memilih urutan perkalian! Jika pengguna harus melakukannya sendiri, ini sepertinya merupakan hambatan bagi pemrograman umum. Dan saya tidak yakin bagaimana Julia bisa melakukannya secara otomatis dengan cara yang waras.

Alasan lain untuk tidak memperbaiki urutan perkalian sebelumnya: Saya ingat bahwa ada ide untuk menggunakan pemrograman dinamis untuk memilih urutan evaluasi yang optimal dari *(x,y,z,w) untuk meminimalkan jumlah operasi yang diperlukan. Apa pun yang kita lakukan untuk menghindari pembentukan vektor baris kemungkinan akan mengganggu ini.

Jadi saat ini, memperkenalkan jenis vektor yang dialihkan sepertinya merupakan alternatif yang paling masuk akal bagi saya. Itu, atau melakukan semuanya seperti sekarang, tetapi menghapus dimensi tunggal yang tertinggal saat menyimpannya akan mengakibatkan kesalahan.

Transposisi hanyalah cara tertentu untuk mengubah mode. Jika Anda mengizinkan v.' mana v adalah vektor, maka permutedims(v,[2 1]) harus mengembalikan hal yang sama persis. Baik keduanya mengembalikan jenis vektor baris khusus, atau mereka memperkenalkan dimensi baru.

Memiliki tipe khusus untuk vektor baris tidak terlihat seperti solusi yang baik bagi saya, karena apa yang akan Anda lakukan tentang jenis vektor mode-n lainnya, misalnya, permutedims([1:4],[3 2 1]) ? Saya mendorong Anda untuk juga mempertimbangkan aljabar multilinear sebelum mengambil keputusan.

@toivoh menyebutkan itu

"Salah satu pendekatan adalah memperluas definisi ini sehingga n atau m dapat diganti dengan absen, yang akan bertindak seperti nilai satu sejauh menyangkut penghitungan produk, tetapi digunakan untuk membedakan skalar dan vektor dari matriks:

  1. skalar tidak akan ada x tidak ada
  2. vektor (kolom) akan nx tidak ada
  3. vektor baris tidak akan ada xn "

Dalam aljabar multi linier (atau untuk tensor rand tinggi), proposal di atas sesuai dengan use absent untuk merepresentasikan
banyak indeks rentang 1, yaitu ukuran (m, n, tidak ada) mungkin sesuai dengan (m, n), (m, n, 1), (m, n, 1,1), dll.

Jika kita menggunakan interpretasi absen ini, maka 1. dan 2. OK dan bagus untuk dimiliki, tapi 3. mungkin tidak OK.
Kami tidak ingin mencampur array dengan ukuran (1, n) dan (1,1, n).

Saya bukan spesialis dalam teori tensor, tetapi saya telah menggunakan semua sistem yang disebutkan di atas (_tanpa_ paket tambahan apa pun) untuk proyek besar yang melibatkan aljabar linier.

[TL; DR: lompat ke SUMMARY]

Berikut adalah skenario paling umum di mana saya telah menemukan kebutuhan untuk generalitas yang lebih besar dalam penanganan array daripada operasi matriks-vektor biasa:

(1) Analisis fungsional: Misalnya, segera setelah Anda menggunakan Hessian dari fungsi bernilai vektor, Anda memerlukan tensor tingkat tinggi untuk bekerja. Jika Anda menulis banyak matematika, akan sangat merepotkan jika harus menggunakan sintaks khusus untuk kasus ini.

(2) Pengendalian evaluasi: Misalnya, mengingat produk apa pun yang dapat dihitung, seseorang harus dapat menghitung setiap sub-entitas dari produk itu secara terpisah, karena seseorang mungkin ingin menggabungkannya dengan beberapa sub-entitas yang berbeda untuk membentuk produk yang berbeda. Jadi perhatian Toivo tentang, misalnya, a*u' dilarang bukan hanya masalah kompilasi, tetapi masalah pemrograman; varian yang lebih umum adalah pra-komputasi x'Q untuk menghitung bentuk kuadrat x'Q*y1 , x'Q*y2 , ... (di mana ini harus dilakukan secara berurutan).

(3) Menyederhanakan kode: Beberapa kali ketika berhadapan dengan operasi aritmatika yang dipetakan melalui kumpulan data multi-dimensi, saya telah menemukan bahwa 6-7 baris kode perulangan atau pemetaan fungsi yang tidak dapat dipahami dapat diganti dengan satu atau dua operasi array singkat, dalam sistem yang memberikan keumuman yang sesuai. Jauh lebih mudah dibaca, dan lebih cepat.

Berikut adalah pengalaman umum saya dengan sistem di atas:

MATLAB: Bahasa inti terbatas di luar operasi vektor-matriks biasa, jadi biasanya berakhir dengan menulis loop dengan pengindeksan.

NumPy: Kemampuan yang lebih umum daripada MATLAB, tetapi berantakan dan rumit. Untuk hampir setiap contoh masalah nontrivial, saya harus merujuk ke dokumentasi, dan bahkan kadang-kadang menemukan bahwa saya harus mengimplementasikan sendiri beberapa operasi array yang saya rasa secara intuitif harus didefinisikan. Sepertinya ada begitu banyak ide terpisah dalam sistem sehingga setiap pengguna dan pengembang tertentu akan kesulitan menebak secara otomatis bagaimana pihak lain akan memikirkan sesuatu. Biasanya mungkin untuk menemukan cara yang singkat dan efisien untuk melakukannya, tetapi cara itu tidak selalu jelas bagi penulis atau pembaca. Secara khusus, saya merasa bahwa kebutuhan untuk pelebaran dan dimensi tunggal hanya mencerminkan kurangnya keumuman dalam penerapan untuk menerapkan operator (meskipun mungkin beberapa menganggapnya lebih intuitif).

Mathematica: Bersih dan sangat umum --- khususnya, semua operator yang relevan dirancang dengan mempertimbangkan perilaku tensor tingkat tinggi. Selain Dot, lihat misalnya dokumen tentang Transpose, Flatten / Partition, dan Inner / Outer. Dengan hanya menggabungkan operasi ini, Anda sudah dapat mencakup sebagian besar kasus penggunaan juggling array, dan di versi 9 mereka bahkan memiliki operasi aljabar tensor tambahan yang ditambahkan ke bahasa inti. Sisi negatifnya adalah bahwa meskipun cara Mathematica melakukan sesuatu bersih dan masuk akal (jika Anda tahu bahasanya), itu mungkin tidak jelas sesuai dengan notasi matematika biasa untuk melakukannya. Dan tentu saja, sifat umum membuatnya sulit untuk mengetahui bagaimana kode akan bekerja.

scmutils: Untuk analisis fungsional, ini bersih, umum, dan menyediakan operasi yang paling intuitif secara matematis (baik menulis maupun membaca) dari semua hal di atas. Ide tupel atas / bawah sebenarnya hanyalah perluasan yang lebih konsisten dan lebih umum dari apa yang sering dilakukan orang dalam matematika tertulis menggunakan tanda transpos, konvensi diferensiasi, dan gagasan semi-standar lainnya; tapi semuanya berjalan lancar. (Untuk menulis tesis Ph.D. saya, saya akhirnya mengembangkan notasi yang konsisten dan tidak ambigu menyerupai notasi matematika tradisional tetapi isomorfik dengan sintaks SICM Sussman & Wisdom.) Mereka juga telah menggunakannya untuk implementasi geometri diferensial [1], yang memiliki menginspirasi port ke SymPy [2]. Saya belum menggunakannya untuk analisis data, tetapi saya berharap bahwa dalam konteks array umum di mana Anda hanya menginginkan satu jenis tupel (seperti Daftar Mathematica), Anda hanya dapat memilih satu ("naik") dengan konvensi. Sekali lagi, keumuman mengaburkan pertimbangan kinerja untuk pemrogram, tapi saya berharap ini adalah area di mana Julia bisa unggul.

RINGKASAN

Saya pikir jenis vektor yang ditransposisikan harus dicirikan sebagai tupel "bawah" yang lebih umum di scmutils, sedangkan vektor biasa akan menjadi tupel "atas". Menyebutnya sesuatu seperti "vektor" dan "vektor yang dialihkan" mungkin akan lebih masuk akal bagi orang-orang daripada menyebut mereka "atas" dan "ke bawah" (dengan mengorbankan keringkasan). Ini akan mendukung tiga kategori penggunaan:

(1) untuk analisis data, jika orang hanya ingin array bersarang, mereka hanya perlu "vektor";
(2) untuk aljabar linier matriks-vektor dasar, orang dapat menggunakan "vektor" dan "vektor yang dialihkan" dalam korespondensi langsung dengan konvensi matematika ("matriks" akan setara dengan "vektor yang dialihkan" dari "vektor");
(3) untuk operasi tensor tingkat tinggi (di mana ada lebih sedikit standarisasi dan orang biasanya harus berpikir pula), implementasi harus mendukung keumuman penuh dari sistem aritmatika tupel dua jenis.

Saya percaya pendekatan ini mencerminkan konsensus yang muncul di atas untuk hasil berbagai operasi, dengan pengecualian bahwa kasus-kasus yang posting sebelumnya dianggap kesalahan ( v' dan v*A ) akan benar-benar memberi makna (dan seringkali berguna ) hasil.

[1] http://dspace.mit.edu/handle/1721.1/30520
[2] http://krastanov.wordpress.com/diff-geometry-in-python/

@thomasmcoffee terdengar seperti Anda menganjurkan perbedaan eksplisit antara vektor co- dan contravariant.

Saya akan menganggapnya sebagai aplikasi umum, tetapi terlalu spesifik untuk apa yang saya anjurkan: bagi saya, itu memiliki makna geometris yang menyiratkan batasan pada tensor bilangan persegi panjang (untuk representasi koordinat). Karena saya membayangkan (tanpa keahlian di bidang ini) bahwa pustaka fungsi aljabar tensor yang sesuai dengan larik standar biasanya cukup untuk tujuan ini, saya bersimpati pada poin Alan bahwa ini saja tidak cukup menarik untuk memperkenalkan sistem dua jenis di bahasa inti.

Saya terutama memikirkan aplikasi lain yang bergantung pada struktur bersarang yang lebih umum, misalnya, kalkulus pada fungsi beberapa argumen dimensi campuran, yang akan lebih sulit untuk dikembangkan sebagai "tambahan" nanti jika bahasa inti tidak mendukung perbedaan ini. Mungkin maksud kami sama.

Masalah dengan vektor naik dan turun adalah Anda perlu memperluas ide ke array umum. Jika tidak, vektor menjadi sesuatu yang istimewa dan terpisah dari array, bukan hanya kasus 1 dimensi dari sebuah array, yang akan menyebabkan kekacauan besar pada masalah yang mengerikan. Saya telah banyak berpikir tentang bagaimana melakukan itu, tetapi belum menemukan yang dapat diterima. Jika Anda memiliki ide bagus tentang bagaimana menggeneralisasi vektor naik dan turun menjadi array, saya akan senang mendengarnya.

Hanya mencoba mengekstrapolasi ide ini. Seperti yang saya pahami, untuk menggunakan array untuk menghitung dengan vektor naik dan turun, Anda perlu menunjukkan untuk setiap dimensi apakah naik atau turun. Secara umum, ini dapat dicapai dengan membungkus array dalam sesuatu seperti

immutable UpDownTensor{T, N, UPMASK} <: AbstractArray{T, N}
    A::AbstractArray{T, N}
end

di mana UPMASK akan menjadi topeng bit untuk menunjukkan dimensi mana yang naik. Kemudian operasi pada array yang tidak dibungkus dapat diimplementasikan dengan menyediakan default UPMASK sebagai fungsi dari N : vektor akan default ke atas tunggal, matriks ke atas pertama dan ke bawah kedua; maka saya tidak yakin bagaimana itu akan dilanjutkan.

Beberapa pemikiran acak:

  • Apakah bentuk kuadrat / bilinear lebih baik diwakili oleh dua dimensi bawah?
  • Jika tranpose akan sesuai dengan hanya membalik atas / bawah setiap dimensi, saya rasa kita juga akan mendapatkan jenis matriks transposisi dengan dimensi pertama turun dan dimensi kedua naik.
  • Pola-atas yang terkait dengan default dapat direpresentasikan secara langsung oleh larik yang mendasari alih-alih membungkusnya.

Nah, ini tentunya merupakan salah satu generalisasi dari tipe Transposed , dan tentu saja ada manfaatnya. Tidak yakin apakah itu layak.

Menurut saya saran Toivo adalah realisasi yang masuk akal dari apa yang saya anjurkan di atas. Bagi saya, default yang paling masuk akal adalah melanjutkan bolak-balik arah pada pesanan yang lebih tinggi: misalnya, jika seseorang menyediakan komponen rangkaian daya sebagai larik yang tidak terbungkus, ini akan melakukan hal yang benar.

Tetapi pada refleksi lebih lanjut, saya pikir akan sangat bermanfaat untuk menggabungkan kedua ide: (1) perbedaan antara vektor atas dan bawah dan (2) perbedaan antara array dan vektor. Kemudian Anda dapat memiliki objek dengan beberapa dimensi di atas, beberapa di bawah, dan beberapa "netral". Alasan untuk membedakan larik dan vektor adalah bahwa, secara semantik, larik adalah untuk organisasi (mengumpulkan banyak hal dari jenis yang sama), sedangkan vektor untuk koordinasi (mewakili ruang multidimensi). Kekuatan dari menggabungkan kedua perbedaan dalam satu objek adalah bahwa hal itu kemudian dapat melayani kedua tujuan ini secara bersamaan. Dimensi netral akan diperlakukan sesuai dengan aturan penyiaran, sedangkan dimensi atas / bawah akan diperlakukan sesuai dengan aturan aritmatika tensor.

Kembali ke contoh saya sebelumnya, misalkan Anda menghitung sejumlah bentuk kuadrat x'Q*y1, x'Q*y2, ... untuk vektor berbeda y1, y2, ... . Mengikuti SICM, tupel naik (vektor kolom) dengan (...) dan tupel bawah (vektor baris) dengan [...] . Jika Anda ingin melakukan semua ini sekaligus, dan Anda terjebak dengan naik / turun saja, cara konvensional adalah menggabungkan yi ke dalam matriks Y = [y1, y2, ...] menggunakan tupel bawah (dari up tuple), dan hitung r = x'Q*Y , yang memberikan hasil pada tuple bawah r . Tetapi bagaimana jika Anda ingin mengalikan setiap hasil ini dengan vektor (kolom) v ? Anda tidak bisa hanya melakukan r*v , karena Anda akan mendapatkan kontraksi (perkalian titik). Anda dapat mengonversi r menjadi tupel naik, dan kemudian mengalikannya, yang memberi Anda hasil dalam tupel naik (tupel naik). Tetapi misalkan untuk langkah selanjutnya Anda membutuhkan tupel bawah? Secara semantik, Anda memiliki dimensi yang melalui kalkulasi Anda yang hanya mewakili sekumpulan hal, yang selalu ingin Anda siarkan; tetapi untuk mencapai ini di dunia yang benar-benar naik / turun, Anda harus terus melakukan konversi bergantung konteks yang sewenang-wenang untuk mendapatkan perilaku yang benar.

Sebaliknya, misalkan Anda juga memiliki tupel netral (array), dinotasikan {...} . Kemudian Anda secara alami menulis ys = {y1, y2, ...} sebagai array (up tuple), sehingga r = x'Q*ys adalah array, dan r*v juga merupakan array (up tupel). Semuanya masuk akal, dan tidak diperlukan konversi sewenang-wenang.

Stefan menyarankan bahwa membedakan array 1-D dari vektor atas / bawah adalah bencana, tetapi saya pikir masalah ini diselesaikan oleh fakta bahwa sebagian besar fungsi masuk akal beroperasi pada vektor _atau_ pada array, tetapi TIDAK _either_. (Atau, pada matriks _atau_ pada array vektor _atau_ pada vektor array _atau_ pada array array, tetapi TIDAK _either_. Dan seterusnya.) Jadi dengan aturan konversi yang sesuai, saya belum memikirkan kasus umum yang tidak akan berhasil. hal yang benar secara otomatis. Mungkin seseorang bisa?

Setelah melihat lebih dalam [1], saya menemukan bahwa scmutils sebenarnya membedakan apa yang mereka sebut "vektor" dari tupel atas dan bawah di bawah kap; tetapi saat ini aturan konversi ditetapkan sehingga "vektor" ini dipetakan ke atas tupel (seperti yang saya usulkan sebelumnya) setiap kali mereka memasuki dunia atas / bawah, dengan peringatan bahwa "Kami berhak mengubah penerapan ini untuk membedakan Vektor skema dari tupel atas. " (Mungkin seseorang di kampus dapat bertanya kepada GJS apakah dia memiliki ide spesifik dalam pikirannya.) Sistem Sage [2] sebagian besar memisahkan penanganan array dari vektor dan matriks (saat ini tidak ada dukungan inti untuk tensor), dan satu-satunya masalah yang saya alami dengan ini harus dilakukan dengan kurangnya built-in konversi di antara mereka dalam kasus-kasus yang jelas masuk akal.

[1] http://groups.csail.mit.edu/mac/users/gjs/6946/refman.txt --- dimulai dari "Objek Terstruktur"
[2] http://www.sagemath.org/

Saya sedang berbicara dengan @jiahao di meja makan siang dan dia menyebutkan bahwa tim Julia mencoba mencari cara untuk menggeneralisasi operasi aljabar linier ke array dimensi yang lebih tinggi. Dua tahun lalu saya menghabiskan beberapa bulan memikirkan hal ini karena saya membutuhkannya untuk KroneckerBio. Saya ingin berbagi pendekatan saya.

Mari kita pertimbangkan produk antara dua larik untuk saat ini. Operasi lain memiliki generalisasi serupa. Tiga jenis produk yang paling umum saat menangani array adalah produk luar, produk dalam, dan produk elemen. Kami biasanya berpikir untuk melakukan operasi seperti ini antara dua objek, seperti inner(A,B) atau A*B . Ketika melakukan operasi ini pada array berdimensi lebih tinggi, bagaimanapun, mereka tidak dilakukan antara array secara keseluruhan, tetapi antara dimensi array tertentu. Beberapa suboperasi luar / dalam / berelemen terjadi dalam satu operasi antara dua larik dan setiap dimensi dari setiap larik harus ditetapkan ke tepat satu suboperasi (baik secara eksplisit atau default). Untuk produk inner dan elementwise, satu dimensi di sebelah kiri harus dipasangkan dengan dimensi yang berukuran sama di sebelah kanan. Dimensi produk luar tidak harus dipasangkan. Sebagian besar waktu pengguna melakukan produk dalam atau produk elemen antara sepasang dimensi dan produk luar untuk yang lainnya. Produk luar menjadi default yang baik karena merupakan yang paling umum dan tidak harus dipasangkan.

Saya biasanya berpikir tentang dimensi sebagai dinamai daripada diurutkan, seperti sumbu x, y, dan z dari sebuah plot. Tetapi jika Anda ingin pengguna benar-benar dapat mengakses array dengan pengindeksan yang dipesan (seperti A[1,2,5] daripada A[a1=1, a3=5, a2=2] ) maka Anda harus memiliki prosedur yang konsisten untuk memesan hasil operasi. Saya mengusulkan memesan hasil dengan mendaftar semua dimensi dari array pertama diikuti dengan mendaftar semua dimensi dari array kedua. Setiap dimensi yang berpartisipasi dalam produk dalam diperas, dan untuk dimensi yang berpartisipasi dalam produk berelemen, hanya dimensi dari larik kedua yang diperas.

Saya akan membuat beberapa notasi untuk ini. Jangan ragu untuk Juliafy itu. Misalkan A menjadi array yang a1 oleh a2 oleh a3 dan biarkan B menjadi array yang b1 oleh b2 . Misalkan array_product(A, B, inner=[2, 1], elementwise=[3, 2]) akan mengambil produk dalam antara dimensi a2 dan b1 , produk elementwise antara a3 dan b2 , dan produk luar a1 . Hasilnya akan menjadi array yang a1 oleh a3 .

Harus jelas bahwa tidak ada operator biner atau unary yang akan memiliki banyak arti dalam konteks array berdimensi lebih tinggi. Anda memerlukan lebih dari dua argumen untuk menentukan apa yang harus dilakukan dengan setiap dimensi. Namun, Anda dapat memperoleh kembali kemudahan aljabar linier dengan menjadikan operator Matlab singkatan untuk operasi larik hanya pada dua dimensi pertama:

A*B Matlab adalah array_product(A, B, inner=[2,1]) .

Matlab's A.' adalah permute(A, B, [2,1]) dimana permute tetap tidak berubah semua dimensi lebih tinggi dari hitungan argumen ketiga.

Anda dapat memilih apakah akan menampilkan kesalahan atau tidak jika dimensi array lebih besar dari 2 atau bahkan tidak sama dengan 2, seperti yang dilakukan Mathematica dengan transposisi vektor. Jika Anda hanya menggunakan kalkulasi array umum, Anda tidak perlu memutuskan apakah akan mengambil saran @wenxgwen atau tidak untuk menafsirkan semua array (n, m) sebagai (n, m, 1) dan (n, m, 1 , 1). Hanya ketika menggunakan operator aljabar linier atau operator lain yang mengharapkan larik atau dimensi tertentu Anda harus membuat keputusan ini. Saya suka saran @wenxgwen , karena ada sedikit kerugian dalam bahasa yang diketik secara dinamis.

Saya menulis deskripsi yang lebih

Terima kasih untuk perspektifnya! Saya menemukan ini cukup mencerahkan untuk memahami jenis binatang apa itu produk array * array umum sebenarnya.

Mungkin menarik untuk mereferensikan proposal perkalian array multidimensi dengan semantik yang diusulkan untuk operator perkalian matriks dalam PEP 0465 . Khususnya:

Input vektor 1d dipromosikan menjadi 2d dengan menambahkan atau menambahkan '1' ke bentuk, operasi dilakukan, dan kemudian dimensi yang ditambahkan dihapus dari output. Angka 1 selalu ditambahkan di "luar" bentuk: diawali untuk argumen kiri, dan ditambahkan untuk argumen kanan. Hasilnya adalah matriks @ vektor dan vektor @ matriks keduanya legal (dengan asumsi bentuk yang kompatibel), dan keduanya mengembalikan vektor 1d; vektor @ vektor mengembalikan skalar ... Kekurangan definisi ini untuk vektor 1d adalah bahwa ia membuat @ non-asosiatif dalam beberapa kasus ((Mat1 @ vec) @ Mat2! = Mat1 @ (vec @ Mat2)). Tapi ini tampaknya menjadi kasus di mana kepraktisan mengalahkan kemurnian

Mengetik dengan Python menyebabkan masalah khusus. Biasanya, array dan matriks harus dapat dipertukarkan (data dasar yang sama). Tetapi karena Python melarang pengecekan suatu tipe, matriks tidak dilemparkan ke antarmuka yang benar di awal fungsi yang mengharapkan sebuah array dan sebaliknya. Inilah mengapa mereka harus memiliki karakter operator yang berbeda. Julia dengan pemeriksaan tipe runtime dan metode convert tidak mengalami ambiguitas ini.

Dari PEP 0465:

Kekurangan definisi ini untuk vektor 1d adalah bahwa ia membuat @ non-asosiatif dalam beberapa kasus ((Mat1 @ vec) @ Mat2! = Mat1 @ (vec @ Mat2))

Khususnya, definisi semacam ini dapat menghasilkan hasil yang salah di Mathematica, karena Dot ( . ) dianggap asosiatif ( Flat ) ketika dievaluasi secara simbolis (seperti dengan f bawah, tetapi tidak dengan g ):

In[1]:= f=X.(y.Z);
g:=X.(y.Z)

In[3]:= Block[{
X=Array[a,{2,2}],
y=Array[b,2],
Z=Array[c,{2,2}]
},{f,g}]

Out[3]= {{(a[1,1] b[1]+a[1,2] b[2]) c[1,1]+(a[2,1] b[1]+a[2,2] b[2]) c[2,1],(a[1,1] b[1]+a[1,2] b[2]) c[1,2]+(a[2,1] b[1]+a[2,2] b[2]) c[2,2]},{a[1,1] (b[1] c[1,1]+b[2] c[2,1])+a[1,2] (b[1] c[1,2]+b[2] c[2,2]),a[2,1] (b[1] c[1,1]+b[2] c[2,1])+a[2,2] (b[1] c[1,2]+b[2] c[2,2])}}

In[4]:= SameQ@@Expand[%]
Out[4]= False

Dari @drhagen :

Julia dengan pemeriksaan tipe runtime dan metode convert tidak mengalami ambiguitas ini.

Inilah sebabnya mengapa saya merasakan solusi yang tepat untuk Julia _should_ membiarkan datanya sendiri membedakan antara semantik seperti array (untuk penyiaran universal) dan semantik seperti tensor (untuk kemungkinan kontraksi).

Saya sama sekali bukan otoritas di sini, tetapi saya tidak berpikir bahwa jenis koleksi dimensi sewenang-wenang umum ( Array ) harus mendukung operator yang melakukan produk titik. Operator ini tidak dapat didefinisikan secara bijaksana untuk jenis ini karena perkalian titik dapat berada di antara dua dimensi, memerlukan argumen tambahan yang tidak dapat diberikan ke operator biner. Hal yang sama berlaku untuk semua operasi aljabar linier, inv , transpose , dll.

Untuk beroperasi dalam bidang matematika aljabar linier, harus ada tiga jenis lagi, Matrix , ColumnVector , dan RowVector , di mana semua operator dan fungsi aljabar linier normal bekerja seperti biasa.

Sekarang setelah struktur tipe didefinisikan dengan baik, Anda dapat mempermudah pengguna dengan menambahkan konversi implisit untuk Matrix menjadi Array{2} , ColumnVector hingga Array{1} , dan RowVector menjadi Array{2} (tidak yakin tentang yang satu ini), Array{2} menjadi Matrix , dan Array{1} menjadi ColumnVector .

Proposal saya di atas (https://github.com/JuliaLang/julia/issues/4774#issuecomment-32705055) memungkinkan setiap dimensi struktur multidimensi untuk membedakan apakah ia memiliki netral ("collection" / "array"), up (" kolom "), atau semantik bawah (" baris "). Saya pikir apa yang Anda gambarkan adalah kasus khusus.

Keuntungan dari pendekatan umum ini adalah bahwa bahkan dalam komputasi dengan banyak dimensi data atau ruang, Anda dapat membuat operator melakukan hal yang benar tanpa secara eksplisit menentukan dimensi mana yang harus dioperasikan. Saya pikir kami setuju bahwa, setidaknya di Julia, jauh lebih intuitif dan mudah dibaca bagi pengguna untuk menentukan sekali arti dari data input dengan memilih parameter tipe, daripada harus menentukan arti setiap operasi dengan memanggil setiap contoh dengan argumen tambahan yang memberikan indeks dimensi. Konversi implisit atau eksplisit masih dapat digunakan, dengan dimensi umum penuh, dalam kasus di mana artinya harus diubah di tengah jalan dengan cara yang tidak biasa.

@thomasmcoffee Saya sangat menyukai proposal Anda. Saya menerapkan sesuatu yang agak mirip di DSL (lama sekali, jauh sekali) dengan beberapa prinsip panduan (alias pendapat pribadi):

  1. Gagasan tentang dualitas sebagai yang berbeda sangat penting untuk semantik yang konsisten dengan diri sendiri.
  2. Penerapan ad hoc aljabar tensor dengan operator berparameter (atau apa pun di luar data dalam hal ini) secara estetika sangat tidak menyenangkan.

Keluhan terbesar yang saya dapatkan saat itu (dan sangat keras) adalah tentang jenis ketidaknyamanan yang dipecahkan oleh semantik trivalen Anda (menambahkan gagasan pengumpulan netral). Bagus! Ide itu tidak pernah terpikir oleh saya, tetapi sangat masuk akal sekarang karena Anda meletakkannya di sana. Saya sangat ingin menggunakan sistem seperti itu, dan maksud saya untuk pekerjaan nyata. Alangkah baiknya jika Julia bisa menampung ini!

Apa yang kalian gambarkan adalah tensor biasa. Saya ragu itu adalah kasus penggunaan yang cukup umum saja untuk membenarkan berada di perpustakaan standar, karena dua kasus penggunaan lainnya (koleksi dan aljabar linier) jauh lebih umum. Namun, jika bisa diintegrasikan dengan mulus, saya akan mendukungnya. Bisakah Anda memberikan beberapa contoh tentang beberapa operasi umum yang akan terlihat di bawah sistem ini, seperti perkalian vektor-matriks, perkalian array-skalar, mendistribusikan penambahan satu array ke dalam array array, dll.?

Saya pikir Anda benar David. Kami benar-benar berbicara tentang dua kasus penggunaan.

Himpunan bagian dari Aljabar Linear paling sering dibutuhkan oleh kebanyakan orang seperti Anda
mengatakan. Bahkan di sana saya menganjurkan untuk mempertahankan perbedaan antara v dan v '.

Yang saya benar-benar ingin (masukkan pengungkapan keserakahan di sini) adalah dengan Tensor
status kelas satu (atau dekat) ... mendekati kecepatan asli (dalam kasus pembatas,
Dibandingkan dengan kinerja Aljabar Linear) dengan sintaks yang mudah, tidak berlebihan
masalah pengetikan, dengan co / kontravarian yang dikodekan dalam data, tidak disisipkan ke
operator. Setelah saya mendefinisikan semantik data, operasi seharusnya
bekerja saja. Pengetikan Tensoral Duck.

Mungkin tensor dan TDT termasuk dalam satu paket dan bukan dalam inti, hanya pada
alasan popularitas relatif. Tapi seperti pernyataan Julia
kemerdekaan mengatakan, Julia lahir dari keserakahan. Dan seperti yang dikatakan Gordon Gecko,
keserakahan itu baik. :)
Pada 21 Mar 2014 3:14 AM, "David Hagen" [email protected] menulis:

Apa yang kalian gambarkan adalah tensor biasa. Saya ragu itu adalah
kasus penggunaan yang cukup umum saja untuk membenarkan berada di pustaka standar, sebagai
dua kasus penggunaan lainnya (koleksi dan aljabar linier) jauh lebih banyak
umum. Namun, jika bisa diintegrasikan dengan mulus, saya akan mendukungnya.
Bisakah Anda memberikan beberapa contoh tentang beberapa operasi umum akan terlihat
di bawah sistem ini, seperti perkalian vektor-matriks, skalar-larik
perkalian, mendistribusikan penambahan satu larik di atas larik
array, dll.?

Balas email ini secara langsung atau lihat di Gi tHubhttps: //github.com/JuliaLang/julia/issues/4774#issuecomment -38262998
.

Saya pikir integrasi yang mulus pasti dapat dicapai mengingat jenis keluarga yang cukup kaya. Memperluas https://github.com/JuliaLang/julia/issues/4774#issuecomment -32693110 Toivo di atas, mungkin secara sengaja dimulai seperti ini:

immutable AbstractTensorArray{T, N, UPMASK, DOWNMASK} <: AbstractArray{T, N}
    A::AbstractArray{T, N}
end
# where !any(UPMASK & DOWNMASK)

typealias AbstractColumnVector{T} AbstractTensorArray{T, 1, [true], [false]}
typealias AbstractRowVector{T} AbstractTensorArray{T, 1, [false], [true]}
typealias AbstractMatrix{T} AbstractTensorArray{T, 2, [false, true], [true, false]}

(saat ini AbstractMatrix{T} hanya alias AbstractArray{T, 2} ; kemungkinan besar, nama lain dapat digunakan di sini)

Dari sini, implementasi berikut tampak logis:

  1. Metode transpose digeneralisasi, setelah mengatur ulang dimensi dan indeks UPMASK dan DOWNMASK yang sesuai, kemudian menukar UPMASK dan DOWNMASK. Dimensi netral tidak akan terpengaruh.
  2. Setiap subtipe AbstractArray{T, N} biasanya diubah secara default menjadi subtipe AbstractTensorArray{T, N, [..., false, true, false, true], [..., true, false, true, false]} alternatif yang sesuai dalam operasi tensor. Ini mempertahankan semantik yang ada dari sintaks array khusus Julia untuk vektor dan matriks.
  3. Metode konstruktor (katakanlah, array ) untuk AbstractTensorArray digunakan untuk menghasilkan dimensi netral, dan dapat menggabungkan AbstractTensorArray s lainnya (atau tipe yang dapat dikonversi padanya) untuk membuat gabungan AbstractTensorArray dengan dimensi tingkat atas netral.

Mempertimbangkan contoh @drhagen :

perkalian vektor-matriks, perkalian larik skalar

c = 1               # Int
v = [1, 2]          # Array{Int, 1}
M = [[1, 2] [3, 4]] # Array{Int, 2}

# scalar-array
c * M               # UNCHANGED: *(Int, Array{Int, 2}) => Array{Int, 2}

# matrix-vector
M * v               # *(Array{Int, 2}, Array{Int, 1}) => *(Matrix{Int}, ColumnVector{Int}) => ColumnVector{Int}

# vector-matrix
v' * M              # transpose(Array{Int, 1}) => transpose(ColumnVector{Int}) => RowVector{Int}
                    # *(RowVector{Int}, Array{Int, 2}) => *(RowVector{Int}, Matrix{Int}) => RowVector{Int}

# (1-array)-(2-array)
v .* M              # UNCHANGED: .*(Array{Int, 1}, Array{Int, 2}) => Array{Int, 2}

(menggunakan Matrix dengan definisi yang sesuai dengan definisi AbstractMatrix atas)

mendistribusikan penambahan satu larik di atas larik larik

Saya mengartikan hal ini, secara semantik, penambahan satu vektor pada array vektor, penambahan satu matriks pada array matriks, dan seterusnya:

# vector-(vector-array)
ws = array([1, 2], [3, 4])
                    # TensorArray{Int, 2, [false, true], [false, false]}
v + ws              # +(Array{Int, 1}, TensorArray{Int, 2, [false, true], [false, false]}) => +(ColumnVector{Int}, TensorArray{Int, 2, [false, true], [false, false]}) => TensorArray{Int, 2, [false, true], [false, false]}
# => array([2, 4], [4, 6])

# array-(vector-array)
u = array(1, 2)     # TensorArray{Int, 1, [false], [false]}
u + ws              # +(TensorArray{Int, 1, [false], [false]}, TensorArray{Int, 2, [false, true], [false, false]}) => TensorArray{Int, 2, [false, true], [false, false]}
# => array([2, 3], [5, 6])
# alternatively:
v .+ ws             # .+(Array{Int, 1}, TensorArray{Int, 2, [false, true], [false, false]}) => TensorArray{Int, 2, [false, true], [false, false]}
# => array([2, 3], [5, 6])
# same effect, but meaning less clear:
v .+ M              # UNCHANGED: .+(Array{Int, 1}, Array{Int, 2}) => Array{Int, 2}
# => [[2, 4] [4, 6]]

# matrix-(matrix-array)
Ns = array([[1, 2] [3, 4]], [[5, 6] [7, 8]])
                    # TensorArray{Int, 2, [false, false, true], [false, true, false]}
M + Ns              # +(Array{Int, 2}, TensorArray{Int, 2, [false, false, true], [false, true, false]}) => +(Matrix{Int}, TensorArray{Int, 2, [false, false, true], [false, true, false]}) => TensorArray{Int, 2, [false, false, true], [false, true, false]}
# => array([[2, 4] [6, 8]], [[6, 8] [10, 12]])

Mempertimbangkan contoh saya sebelumnya tentang penskalaan vektor v dengan beberapa bentuk kuadrat berbeda x'M*w1, x'M*w2, ... , untuk hasil akhir x'M*w1*v, x'M*w2*v, ... :

x = v
x' * M * ws * v     # *(RowVector{Int}, Array{Int, 2}) => *(RowVector{Int}, Matrix{Int}) => RowVector{Int}
                    # *(RowVector{Int}, TensorArray{Int, 2, [false, true], [false, false]}) => TensorArray{Int, 1, [false], [false]}
                    # *(TensorArray{Int, 1, [false], [false]}, Array{Int, 1}) => *(TensorArray{Int, 1, [false], [false]}, ColumnVector{Int}) => TensorArray{Int, 1, [false, true], [false, false]}
# => array([27, 54], [59, 118])

Dalam implementasi nosional ini, saya berasumsi bahwa AbstractArray dibiarkan sendiri, dan dengan demikian AbstractTensorArray membentuk "spasi" -nya sendiri dalam hierarki tipe. Hal-hal mungkin disederhanakan jika seluruh keluarga AbstractArray hanya diganti dengan AbstractTensorArray , tapi itu diskusi lain.

Dalam konteks paket untuk sesuatu dalam fisika kuantum, saya telah bermain-main dengan mendefinisikan jenis tensor saya sendiri (sebenarnya lebih dari satu). Awalnya, saya juga memiliki beberapa gagasan tentang indeks yang datang dalam dua bentuk (atas dan bawah, masuk dan keluar, kovarian dan kontravarian, bagaimanapun Anda ingin menyebutnya), dengan informasi ini disimpan baik dalam bidang dalam jenis atau bahkan dalam jenis parameter. Setelah beberapa saat saya memutuskan ini hanya terlalu merepotkan. Jauh lebih mudah untuk hanya mengaitkan indeks tensor ke ruang vektor (yang sudah saya lakukan) dan memungkinkan ruang vektor ini memiliki rangkap yang berbeda. Dalam praktiknya, ruang vektor yang saya maksud hanyalah tipe Julia sederhana yang membungkus dimensi ruang dan apakah itu ganda atau bukan. Jika indeks tensor dikaitkan ke ruang vektor normal, itu adalah indeks naik, jika dikaitkan dengan indeks ganda, itu adalah indeks turun. Apakah Anda ingin bekerja dengan tensor / array yang tidak ada perbedaannya, Anda tinggal menentukan jenis ruang vektor yang berbeda yang tidak membedakan antara ruang vektor normal dan rangkapnya.

Dalam proposal ini, Anda hanya dapat mengontrak indeks tensor yang terkait dengan ruang vektor yang saling ganda. ctranspose (= Hermitian conjugation) memetakan ruang vektor dari setiap indeks ke rangkapnya (bersama dengan permutasi indeks dalam kasus matriks, dan definisi yang disukai untuk tensor orde tinggi) dll.

Tentu saja, transposisi normal dan konjugasi kompleks tidak didefinisikan dengan baik dalam pengaturan ini (yaitu, ini bukan konsep independen basis)

Secara minimalis, tampilannya seperti ini:

immutable Space
    dim::Int
    dual::Bool
end
Space(dim::Int)=Space(dim,false) # assume normal vector space by default
dual(s::Space)=Space(s.dim,!s.dual)

matrix=Tensor((Space(3),dual(Space(5))))
# size is no longer sufficient to characterise the tensor and needs to be replaced by space
space(matrix) # returns (Space(3),dual(Space(5))) 
space(matrix') # returns (Space(5),dual(Space(3)))

Tentu saja, Anda dapat menemukan sintaks agar tidak perlu terus-menerus menulis Spasi. Anda dapat membuat tipe spasi yang berbeda dengan dual (s) == s untuk memiliki tensor yang tidak membedakan indeks atas dan bawah, dan seterusnya. Tapi tentu saja tidak mungkin ini masih bisa dibangun ke dalam tipe Array standar Julia tanpa merusak segalanya ...

Saya selalu bertanya-tanya mengapa tidak ada hubungan yang lebih dekat antara bagaimana tensor digunakan dalam teknik / fisika dan bagaimana mereka ditangani dalam program perangkat lunak matematika. Saya menemukan percakapan pertukaran tumpukan yang menarik tentang topik ... http://math.stackexchange.com/questions/412423/differences-between-a-matrix-and-a-tensor. Di sini, juga, ada pos referensi yang bagus.
http://www.mat.univie.ac.at/~neum/physfaq/topics/tensors

Saya sering menggunakan Matlab untuk komputasi ilmiah harian saya, tetapi masih pemula di Julia. Di sini, saya melihat bahwa ada banyak diskusi tentang perkalian dan transposisi Array dimensi tinggi atau operasi array serupa lainnya. Saya sarankan untuk melihat di http://www.mathworks.com/matlabcentral/fileexchange/8773-multiple-matrix-multiplications--with-array-expansion-enabled

Ini pada dasarnya mengikuti sintaks yang mirip dengan apa yang telah disebutkan @drhagen di posting sebelumnya, seperti array_product (A, B, inner_A_dim = [1, 2], inner_B_dim = [3, 4]) untuk produk antara array A dan B di dimensi dalam yang diberikan.

Ini adalah salah satu paket Matlab yang dapat menerapkan operasi perkalian atau transposisi pada beberapa dimensi yang dipilih. Ada manual dalam paket tentang bagaimana mengimplementasikan operasi ini di Matlab, tapi menurut saya teori matematika harus diterapkan untuk bahasa lain juga. Ide mereka adalah untuk mengimplementasikan operasi array dengan menghindari penggunaan For-loops, dan sebagian besar mengandalkan pembentukan ulang array dan sebagainya. Jadi, sangat cepat di Matlab. Saya tidak tahu apakah Julia lebih menyukai operasi vektor atau operasi devektorisasi (tampaknya yang lebih baru). Saya merasa bahwa operasi vektorisasi adalah keuntungan untuk operasi array berdimensi tinggi, jika inti mendukungnya. Mungkin kita harus dengan tulus mempertimbangkan operasi array semacam ini pada tahap ini.

Untuk referensi Anda: Penerapan serupa lainnya di Matlab untuk operasi INV ada di sini: http://www.mathworks.com/matlabcentral/fileexchange/31222-inversion-every-2d-slice-for-arbitrary-multi-dimension-array

Juga perhatikan bahwa, setelah rilis paket dukungan operasi larik Matlab pada tahun 2005, catatan unduhan dipertahankan pada tingkat yang tinggi hingga hari ini. Seperti dalam pengalaman praktis saya, operasi array sangat sering digunakan dalam fisika dan bidang lainnya. Saya akan mengatakan, jika Julia memiliki fungsi serupa untuk array operasi dengan ukuran yang berubah-ubah, permainan akan menjadi sangat menarik!

pilih lagi di sini untuk solusi yang diusulkan @alanedelman menuju puncak. inilah contoh yang memotivasi.

sekarang, baris-slice adalah array 2d, sedangkan slice kolom adalah array 1d; yang anehnya asimetris dan jelek:

julia> A = randn(4,4)
4x4 Array{Float64,2}:
  2.12422    0.317163   1.32883    0.967186
 -1.0433     1.44236   -0.822905  -0.130768
 -0.382788  -1.16978   -0.19184   -1.15773
 -1.2865     1.21368   -0.747717  -0.66303

julia> x = A[:,1]
4-element Array{Float64,1}:
  2.12422
 -1.0433
 -0.382788
 -1.2865

julia> y = A[1,:]
1x4 Array{Float64,2}:
 2.12422  0.317163  1.32883  0.967186

khususnya, itu berarti saya tidak dapat mengalikan baris dengan kolom dan mengekstrak angka tanpa melakukan manipulasi yang sangat jelek seperti

julia> dot(y[:],x)
2.4284575954571106
julia> (y*x)[1]
2.42845759545711

Ini bukan proposal yang koheren kecuali Anda membuat '* sebagai operator khusus, yang cukup meragukan, sejak saat itu x'*y dan (x')*y tidak berarti hal yang sama. Selain itu, perkalian akan menjadi non-asosiatif.

saya memahami kesulitan dengan x_y 'dan y'_x. Mungkin lebih baik untuk diobati
produk dalam dan luar sebagai operasi terpisah, menggunakan misalnya titik (). (Mungkin
juga menggunakan cdot?)

Tapi apa argumen yang mendukung memiliki potongan di sepanjang yang pertama
dimensi mengembalikan objek yang dimensinya berbeda dari potongan bersama
dimensi kedua? Untuk konsistensi, tampaknya setiap kali Anda mengiris,
dimensi objek yang dihasilkan harus dikurangi satu.

Pada Rabu, 16 Juli 2014 pukul 20:17, Stefan Karpinski [email protected]
menulis:

Ini bukan proposal yang koheren kecuali Anda membuat '* sebagai operator khusus, yang mana
cukup meragukan, sejak itu x'_y dan (x ') _ y tidak berarti hal yang sama.
Selain itu, perkalian akan menjadi non-asosiatif.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -49254346.

Madeleine Udell
Kandidat PhD di Teknik Komputasi dan Matematika
Universitas Stanford
www.stanford.edu/~udell

@madeleineudell , saya setuju dengan Anda, tetapi itu masalah yang berbeda, lihat # 5949. Meski masalah itu sepertinya sudah ditutup, saya tidak ingat ada kesepakatan atau kesimpulan yang jelas.

Setelah kita beralih ke tampilan array, akan lebih mudah untuk menjelajahi arah tersebut. Khususnya, mengatakan slice(A, i, :) memberi Anda perilaku yang Anda inginkan. (Itu melakukannya sekarang, tetapi dengan biaya memperkenalkan tipe yang lebih lambat, SubArray.)

Dari sudut pandang matematis murni, semua masalah yang disajikan di sini berasal dari gabungan (dan kebingungan antara) apa yang kami maksud dengan array dan apa yang kami maksud dengan vektor / tensor / matriks. Array, secara konseptual, hanyalah daftar (atau, dalam kasus larik n-dim, daftar daftar). Dengan demikian, tidak ada spesifikasi alami untuk operasi seperti perkalian larik, transposisi, dll. Sementara fungsi seperti permutedim, operasi berdasarkan elemen, dan operasi spesifik sumbu (mean, median, dll.) Masuk akal dan dapat didefinisikan secara unik dalam cara alami, operasi seperti produk titik tidak dapat dilakukan.

Seperti disebutkan di atas, vektor dan tensor adalah objek geometris, dan meskipun dimungkinkan untuk merepresentasikannya menggunakan array, representasi ini tidak mengandung kekayaan struktur yang sama seperti objek matematika yang mereka wakili. Transposisi larik 1-dim adalah tanpa operasi; transpos dari vektor adalah gandanya. Transpose array 2-dim dapat didefinisikan secara unik dan alami sebagai permutasi dimensinya, tetapi ini umumnya tidak berlaku untuk tensor: sementara kasus alami berlaku untuk tensor peringkat (1,1) (alias, matriks), a rank (2,0) tensor diubah menjadi tensor rank (0,2). Sekali lagi, dengan memperlakukan tensor sebagai larik, informasi geometrik yang membuat tensor tensor hilang.

Ini penting saat mendefinisikan operasi seperti produk titik. Perkalian titik memiliki makna geometris tertentu (proyeksi satu vektor ke ruang ganda yang ditentukan oleh vektor kedua), dan dengan demikian definisi produk titik yang konsisten memerlukan pelestarian informasi geometris yang terkandung dalam vektor. Menggunakan asumsi tertentu mungkin memungkinkan untuk menggunakan array dan masih mencakup sebagian besar kasus penggunaan, tetapi asumsi ini berantakan (seperti yang terlihat oleh berbagai proposal di utas ini) dan sebenarnya mempersulit siapa pun yang membutuhkan struktur tensor yang lebih kaya .

Jadi, anggap ini sebagai suara yang kuat untuk mendukung saran thomasmcoffee untuk menyertakan jenis Sensor Abstrak yang lebih kaya. Preferensi pribadi saya adalah bahwa operasi seperti transposisi dan produk titik bahkan tidak ditentukan untuk array, tetapi karena saya curiga kebanyakan orang tidak akan berbagi pandangan itu, saya setidaknya menginginkan kemampuan untuk membuat tensor sejati jika diperlukan.

Implikasi praktis dari perspektif ini tampaknya bahwa array harus diidentifikasi dengan subset tensor, dan transposisi array 1-hari akan menghasilkan DualVector atau mungkin kesalahan. Pandangan saya adalah bahwa ini analog dengan operasi pada bilangan real yang memberikan bilangan kompleks.

Perspektif saya adalah bahwa keluarga AbstractArray umum, wadah data (multidimensi), adalah cukup umum untuk menjadi bagian yang tidak dapat diterima dari bahasa pemrograman teknis apa pun. Tensor yang mengikuti aturan matematika yang ketat, meskipun saya sangat memedulikannya, adalah objek yang bagus untuk paket khusus. Sebenarnya, saya sedang mengerjakan sesuatu di sepanjang baris yang ditentukan oleh @jdbates di https://github.com/Jutho/TensorToolbox.jl . Sejauh ini belum terdokumentasi dan sebagian besar belum teruji. Saya menulisnya untuk hal-hal yang saya butuhkan secara pribadi dalam fisika tubuh banyak kuantum, tetapi saya berharap ini dibangun dengan cara yang cukup umum dan dapat diperluas agar berguna bagi komunitas ahli matematika dan fisikawan yang lebih besar yang peduli tentang bekerja dengan tensor.

Untuk memberikan beberapa detail (disalin dari forum JuliaQuantum): Saya memutuskan untuk menentukan hierarki tipe baru untuk tensor, yang tidak bergantung pada jenis AbstrakArray Julia (meskipun Tensor dasar hanyalah pembungkus untuk Array). Hierarki tipe ini seharusnya bekerja dengan cara yang sedikit lebih formal. Indeks tensor dikaitkan dengan ruang vektor (selanjutnya disebut ruang indeks), dan jika jenis ruang vektor yang dikaitkan dengan indeks tensor berbeda dari rangkapnya, hal ini sesuai dengan tensor yang membedakan antara indeks kovarian dan kontravarian.

Jadi bagian pertama dari paket ini adalah bagian abstrak untuk menentukan ruang vektor, di mana saya mencocokkan tipe hierarki objek Julia dengan hierarki matematika ruang vektor. Ruang vektor umum V datang dalam empat varietas, sesuai dengan teori representasi dari kelompok linier umum pada V, yaitu V itu sendiri (representasi fundamental), konj (V), rangkap (V) dan rangkap (konj (V)). Untuk ruang vektor nyata, konj (V) = V dan hanya ada V dan rangkap (V), sesuai dengan vektor kontravarian dan kovarian. Lalu ada ruang hasil kali dalam, dan di tingkat teratas dari hierarki adalah ruang Euclidean, yang merupakan ruang hasil kali dalam dengan hasil kali dalam standar Euclidean (yaitu basis ortogonal). Dalam fisika, juga berguna untuk memikirkan ruang vektor yang didekomposisi menjadi sektor-sektor yang berbeda, yaitu mereka dinilai oleh, misalnya, representasi aksi simetri yang tidak dapat direduksi.

Tensor adalah objek yang hidup dalam (subruang dari) hasil kali tensor dari beberapa ruang vektor elementer. Namun, selain Tensor standar, yang merupakan objek yang hidup dalam ruang hasil kali tensor dari ruang indeksnya, kita dapat membangun tensor yang hidup di misalnya sektor invarian dari produk tensor ruang yang dinilai oleh irrep, subruang simetris atau antisimetris dari produk tensor ruang identik, ... Seseorang dapat memiliki ruang vektor fermionik sebagai ruang indeks, yang menyiratkan bahwa permutasi indeks tensor akan menyebabkan perubahan tanda tertentu tergantung pada sektor paritas, dll ...

Kemudian seharusnya ada operasi tertentu yang didefinisikan pada tensor, yang paling penting adalah mengontrak tensor, tetapi juga, misalnya faktorisasi ortogonal (dekomposisi nilai tunggal), dll. Akhirnya harus ada peta linier yang memetakan satu tensor ke tensor lainnya. Mereka berhak mendapatkan tipe khusus yang biasanya tidak ingin sepenuhnya menyandikannya sebagai matriks, melainkan dengan cara agar produk vektor matriks dapat dihitung secara efisien, untuk digunakan dalam metode iteratif (Lanczos dll). Dua paket saya yang ada sejauh ini (TensorOperations.jl dan LinearMaps.jl) menerapkan fungsi ini untuk Array standar, kotak alat tensor yang sedang dibangun akan membebani / mendefinisikan ulang mereka untuk hierarki AbstractTensor baru.

Semoga paket ini cukup umum sehingga bermanfaat juga bagi masyarakat fisika / matematika yang lebih luas. Misalnya, jika seseorang datang yang membuat paket untuk bekerja dengan manifold, dia kemudian dapat mendefinisikan ruang vektor TangentSpace sebagai subruang dari InnerProductSpace abstrak, dan dia kemudian dapat segera membuat tensor yang hidup dalam produk tensor dari beberapa ruang tangen dan kotangen. Sebenarnya, saya sedang berpikir untuk memisahkan bagian untuk mendefinisikan ruang vektor menjadi paket terpisah, yang dapat tumbuh menjadi paket untuk mendefinisikan struktur / objek matematika.

Akhirnya, interop dengan julia standar berasal dari memanggil tensor pada standar Array , yang membungkusnya menjadi objek tipe Tensor dengan indeks yang terkait dengan spasi tipe CartesianSpace . Ini adalah ruang vektor nyata standar R ^ n dengan hasil perkalian Euclidean, di mana tidak ada perbedaan antara indeks kovarian dan kontravarian. Saya pikir ini memerlukan apa yang terbaik dari Julia Array standar.

@JeffBezanson , saya ambivalen dalam memperlakukan array sebagai subset tensor. Tidak ada informasi yang hilang dengan cara itu, tetapi pada saat yang sama ada beberapa kemungkinan interpretasi untuk array, dan interpretasi tensor tidak selalu (atau bahkan biasanya) masuk akal. Pertimbangkan gambar: gambar dapat dianggap sebagai bidang bernilai vektor pada manifold (biasanya 2d). Membatasi bidang itu menjadi kisi persegi panjang memberi Anda struktur yang, tentu saja, ingin Anda wakili menggunakan larik 3d. Namun, sebenarnya, ini hanyalah pemetaan dari ruang titik kisi ke dalam ruang vektor {R, G, B}, sehingga makna geometris dari dua dimensi pertama (label x dan y dari kisi) berbeda dari makna geometris dari dimensi ketiga (yang sebenarnya adalah vektor).

Saya tidak menentang saran @Jutho untuk memisahkan mekanisme tensor menjadi paket terpisah. Dia mungkin benar bahwa jumlah pengguna yang membutuhkan mekanik tensor penuh jauh lebih kecil daripada jumlah orang yang hanya ingin operasi larik langsung. Pertanyaan yang sebenarnya ingin kita tanyakan di sini adalah "dalam domain apa aljabar linier seharusnya jatuh?"

Mesin aljabar linier adalah subset yang cukup substantif dari mesin aljabar tensor yang, menurut saya setidaknya, tidak masuk akal untuk menerapkan yang pertama tanpa menerapkan yang terakhir. Operasi seperti v'M lebih ringkas dan konsisten direpresentasikan jika kita memiliki pengertian vektor co- dan contravariant, tetapi itu sudah menempatkan kita sebagian besar jalan menuju operasi tensor umum.

Saya setuju dengan Anda bahwa ini secara konseptual mirip dengan operasi pada bilangan real yang mengembalikan bilangan kompleks.

Pertimbangkan gambar: gambar dapat dianggap sebagai bidang bernilai vektor pada manifold (biasanya 2d). Membatasi bidang itu menjadi kisi persegi panjang memberi Anda struktur yang, tentu saja, ingin Anda wakili menggunakan larik 3d. Namun, sebenarnya, ini hanyalah pemetaan dari ruang titik kisi ke dalam ruang vektor {R, G, B}, sehingga makna geometris dari dua dimensi pertama (label x dan y dari kisi) berbeda dari makna geometris dari dimensi ketiga (yang sebenarnya adalah vektor).

Meskipun ini tidak mengatasi atau menghilangkan pesan Anda secara keseluruhan, https://github.com/timholy/Images.jl/pull/135 sedang bekerja untuk mengimplementasikan ide ini untuk gambar. Saya berharap ini juga memudahkan menangani tensor struktur warna , yang ingin saya gunakan untuk proyek.

Pada 23 Agustus 2014, pukul 20:36, jdbates [email protected] menulis:

@JeffBezanson , saya ambivalen dalam memperlakukan array sebagai subset tensor. Tidak ada informasi yang hilang dengan cara itu, tetapi pada saat yang sama ada beberapa kemungkinan interpretasi untuk gambar, dan interpretasi tensor tidak selalu (atau bahkan biasanya) masuk akal. Pertimbangkan gambar: gambar dapat dianggap sebagai bidang bernilai vektor pada manifold (biasanya 2d). Membatasi bidang itu menjadi kisi persegi panjang memberi Anda struktur yang, tentu saja, ingin Anda wakili menggunakan larik 3d. Namun, sebenarnya, ini hanyalah pemetaan dari ruang titik kisi ke dalam ruang vektor {R, G, B}, sehingga makna geometris dari dua dimensi pertama (label x dan y dari kisi) berbeda dari makna geometris dari dimensi ketiga (yang sebenarnya adalah vektor).

Saya setuju bahwa tensor tidak menggantikan array. Contoh di atas memang merupakan struktur matematika yang berbeda (yaitu berkas vektor atau lebih umum lagi berkas tensor) yang representasi juga dapat diberikan sebagai larik multidimensi dengan memilih kisi untuk koordinat manifol dan basis untuk bagian ruang vektor. Jadi memang, Anda dapat memiliki objek / struktur matematika berbeda yang didefinisikan dengan baik dalam cara koordinat-independen / basis-independen tetapi dapat direpresentasikan (setelah memilih sistem koordinat atau basis) sebagai array multidimensi. Jadi array multidimensi tentu tidak terbatas mewakili tensor. Kebalikannya juga gagal, karena tidak semua tensor memiliki representasi yang nyaman menggunakan array multidimensi. Ini hanya terjadi jika Anda menggunakan basis tertentu yang dikenal sebagai basis produk, yang diperoleh dengan mengambil produk langsung dari semua kemungkinan kombinasi vektor basis individual dari ruang vektor yang terlibat dalam ruang hasil kali tensor. Dalam beberapa kasus, misalnya saat menggunakan tensor dalam subruang invarian-simetri dari ruang hasil perkalian tensor, representasi seperti itu tidak lagi mungkin dan Anda perlu menentukan basis yang berbeda untuk ruang lengkap, sehubungan dengan yang tensornya hanya direpresentasikan sebagai daftar angka satu dimensi yang panjang.

Saya tidak menentang saran @Jutho untuk memisahkan mekanisme tensor menjadi paket terpisah. Dia mungkin benar bahwa jumlah pengguna yang membutuhkan mekanik tensor penuh jauh lebih kecil daripada jumlah orang yang hanya ingin operasi larik langsung. Pertanyaan yang sebenarnya ingin kita tanyakan di sini adalah "dalam domain apa aljabar linier seharusnya jatuh?"

Mesin aljabar linier adalah subset yang cukup substantif dari mesin aljabar tensor yang, menurut saya setidaknya, tidak masuk akal untuk menerapkan yang pertama tanpa menerapkan yang terakhir. Operasi seperti v'M lebih ringkas dan konsisten direpresentasikan jika kita memiliki pengertian vektor co- dan contravariant, tetapi itu sudah menempatkan kita sebagian besar jalan menuju operasi tensor umum.

Saya setuju dengan Anda bahwa ini secara konseptual mirip dengan operasi pada bilangan real yang mengembalikan bilangan kompleks.

-
Balas email ini secara langsung atau lihat di GitHub.

ada beberapa kemungkinan interpretasi untuk array, dan interpretasi tensor tidak selalu (atau bahkan biasanya) masuk akal. Pertimbangkan gambar: gambar dapat dianggap sebagai bidang bernilai vektor pada manifold (biasanya 2d). Membatasi bidang itu menjadi kisi persegi panjang memberi Anda struktur yang, tentu saja, ingin Anda wakili menggunakan larik 3d. Namun, sebenarnya, ini hanyalah pemetaan dari ruang titik kisi ke dalam ruang vektor {R, G, B}, sehingga makna geometris dari dua dimensi pertama (label x dan y dari kisi) berbeda dari makna geometris dari dimensi ketiga (yang sebenarnya adalah vektor).

Perbedaan semacam inilah yang saya coba tangkap dalam proposal AbstractTensorArray nosional dari https://github.com/JuliaLang/julia/issues/4774#issuecomment -38333295 dengan mengizinkan bentuk array dan tensor dimensi seperti. Di bawah skema ini, saya berharap untuk mewakili contoh Anda sebagai

AbstractTensorArray{Uint8, 3, [false, true, false], [true, false, false]}

sehingga dimensi x, y, dan RGB masing-masing adalah "bawah", "atas", dan "netral". Operasi geometris (misalnya, transformasi affine) kemudian dapat menangani dimensi koordinat grid dengan cara seperti tensor saat memetakan nilai RGB dalam gaya seperti array. (Jika nanti Anda ingin memperlakukan nilai RGB secara geometris, Anda harus mengubah mask secara eksplisit untuk tujuan itu, tetapi saya kira (a) kurang umum bahwa dua jenis operasi geometris yang berbeda akan diterapkan ke subruang yang berbeda dari tabel data yang sama, dan (b) dalam situasi ini, konversi eksplisit mungkin akan _meningkatkan_ kejelasan kode.)

Saya belum mempertimbangkan representasi konjugasi yang disebutkan @Jutho , tetapi menurut saya generalisasi ini dapat ditangani dengan lebih memperluas pendekatan masking yang sama, untuk ruang kompleks.

Pertanyaan yang sebenarnya ingin kita tanyakan di sini adalah "dalam domain apa aljabar linier seharusnya jatuh?"

Setelah desain diselesaikan untuk bagaimana operasi mirip-array dan seperti tensor bermain bersama, entitas untuk aljabar linier hanya dapat ditentukan oleh kasus-kasus khusus (seperti alias yang saya gunakan di atas), sehingga pengguna aljabar linier murni dapat terlupa seluruh hierarki tensor umum hingga diperlukan (tetapi tidak perlu menulis ulang jika diperlukan). Jadi saya tidak akan melihat masalah (kecuali mungkin mengasapi) meletakkan semuanya di Base.

sehingga dimensi x, y, dan RGB masing-masing adalah "bawah", "atas", dan "netral". Operasi geometris (misalnya, transformasi affine) kemudian dapat menangani dimensi koordinat grid dengan cara seperti tensor saat memetakan nilai RGB dalam gaya seperti array. (Jika nanti Anda ingin memperlakukan nilai RGB secara geometris, Anda harus mengubah mask secara eksplisit untuk tujuan itu, tetapi saya kira (a) kurang umum bahwa dua jenis operasi geometris yang berbeda akan diterapkan ke subruang yang berbeda dari tabel data yang sama, dan (b) dalam situasi ini, konversi eksplisit mungkin akan meningkatkan kejelasan kode.)

Saya pikir Anda sedang mencampur sesuatu di sini. Dalam pembahasan di atas, sebenarnya dijelaskan bahwa koordinat x dan y tidak membawa interpretasi ruang vektor, karena dapat bersesuaian dengan koordinat pada lipatan lengkung sembarang, tidak harus pada ruang datar. Dimensi RGB-lah yang diberi interpretasi vektor, meskipun ini sebenarnya juga bukan pilihan terbaik, seperti yang saya ingat (saya tidak memiliki latar belakang yang layak dalam pemrosesan gambar) bahwa ruang warna juga agak melengkung. Juga, bahkan untuk kasus di mana domain (x dan y) membentuk ruang vektor, mengapa x dan y naik dan turun, atau ini hanya sebagai contoh notasi Anda?

Bagaimanapun, saya juga mulai dengan TensorToolbox.jl dengan menunjukkan indeks kovarian dan kontravarian sebagai semacam parameter atau topeng, tetapi ini segera menjadi mimpi buruk yang lengkap, itulah mengapa saya beralih ke representasi di mana setiap tensor adalah elemen dari beberapa ruang vektor , dan untuk melakukan operasi, kita harus memeriksa apakah spasi cocok, sama seperti Anda perlu memeriksa kecocokan ukuran saat melakukan operasi dengan array.

Koordinat x dan y tidak membawa interpretasi ruang vektor

Maaf, saya membaca lebih dari "kotak persegi panjang" --- Saya kira @jdbates berarti persis seperti yang dia katakan. Tapi bukankah kita hanya berbicara tentang mengganti produk titik dengan produk dalam yang digeneralisasi? (Maafkan saya jika saya salah paham, saya menghabiskan hampir seluruh waktu saya di ruang Euclidean :-)

setiap tensor adalah elemen dari beberapa ruang vektor

Sepertinya ide yang bagus --- Saya tertarik untuk melihat beberapa contoh cara kerjanya untuk pengguna (saya tidak terlalu jauh membaca kode).

Saya punya proposal baru untuk masalah ini.


(1) Pengirisan gaya APL.

size(A[i_1, ..., i_n]) == tuple(size(i_1)..., ..., size(i_n)...)

Secara khusus, ini berarti bahwa "irisan tunggal" - yaitu irisan di mana indeksnya skalar atau berdimensi nol - selalu dibuang dan M[1,:] dan M[:,1] keduanya vektor, bukan salah satunya adalah vektor sedangkan yang lainnya adalah matriks baris, atau perbedaan serupa lainnya.


(2) Perkenalkan tipe pembungkus Transpose dan ConjTranspose untuk vektor dan matriks. Dengan kata lain, sesuatu seperti ini:

immutable Transpose{T,n,A<:AbstractArray} <: AbstractArray{T,n}
    array::A
end
Transpose{T,n}(a::AbstractArray{T,n}) = Transpose{T,n,typeof(a)}(a)

dan semua metode yang sesuai untuk membuat ini berfungsi sebagaimana mestinya untuk vektor dan matriks. Kami mungkin ingin membatasinya hanya untuk bekerja untuk vektor dan matriks, karena tidak jelas apa arti transpos umum untuk dimensi arbitrer (meskipun hanya membalikkan dimensi saja sudah cukup). Ketika Anda menulis a' Anda mendapatkan ConjTranspose(a) dan juga v.' menghasilkan Transpose(a) .


(3) Tentukan berbagai metode khusus untuk (konjugasi) vektor dan matriks yang dialihkan, seperti:

*(v::Transpose{T,1}, w::AbstractVector) = dot(v.array,w)
*(v::AbstractVector, w::Transpose{T,1}) = [ v[i]*w[j] for i=1:length(v), j=1:length(w) ]

dll., termasuk mengganti semua fungsi At_mul_B mengerikan dan penguraian khusus dengan konstruksi transpose malas (konjugasi) diikuti dengan pengiriman pada tipe Transpose dan ConjTranspose .


(4) Batasi operasi penyiaran untuk kasus-kasus di mana argumennya adalah skalar atau array dengan jumlah dimensi yang sama. Jadi, berikut ini, yang saat ini berfungsi seperti yang ditunjukkan akan gagal:

julia> M = rand(3,4);

julia> M./M[1,:]
3x4 Array{Float64,2}:
 1.0       1.0       1.0      1.0
 0.516884  0.675712  2.11216  9.0797
 1.00641   0.726229  2.48336  4.38751

julia> M./M[:,1]
3x4 Array{Float64,2}:
 1.0  0.891557  0.561464  0.103968
 1.0  1.16552   2.29433   1.82633
 1.0  0.643353  1.38544   0.453257

Sebaliknya, Anda harus melakukan sesuatu seperti ini:

julia> M./M[[1],:]
3x4 Array{Float64,2}:
 1.0       1.0       1.0      1.0
 0.516884  0.675712  2.11216  9.0797
 1.00641   0.726229  2.48336  4.38751

julia> M./M[:,[1]]
3x4 Array{Float64,2}:
 1.0  0.891557  0.561464  0.103968
 1.0  1.16552   2.29433   1.82633
 1.0  0.643353  1.38544   0.453257

Saya yakin proposal ini menyelesaikan semua masalah utama yang kami miliki saat ini:

  1. perilaku pemotongan simetris - dimensi trailing tidak lagi istimewa.
  2. v'' === v .
  3. v' == v .
  4. v'w adalah produk titik dari v dan w - khususnya, ini adalah skalar, bukan vektor satu elemen.
  5. v*w' adalah hasil luar v dan w .
  6. M*v adalah vektor.
  7. M*v' adalah kesalahan.
  8. v'*M adalah vektor yang dialihkan.
  9. v*M adalah kesalahan.
  10. At_mul_B dan penguraian khusus dihentikan.

: +1: untuk semuanya. Saya melakukan beberapa pekerjaan pada 2 dan 3 di # 6837, tetapi tidak pernah menyelesaikannya. @simonbyrne juga

+1 juga. Kedengarannya seperti itu akan menawarkan perilaku yang cukup konsisten di semua tempat.

Satu-satunya bagian yang benar-benar mengganggu dari proposal ini sebenarnya adalah bahwa M[1,:] adalah vektor vertikal implisit dan bukan matriks baris horizontal eksplisit. Jika tidak, ini sebenarnya adalah serangkaian perubahan yang cukup mulus dan tidak mengganggu (satu harapan). Pencerahan utama (bagi saya) adalah bahwa perilaku pemotongan APL dapat dikombinasikan dengan transposes malas. Jika kita mendapat dukungan, kita dapat membuat rencana dan membagi pekerjaan. Saya sangat berharap bahwa fungsi pemindahan posisi dan bertahap yang malas memungkinkan pengurangan dan penyederhanaan kode.

Ya silahkan! Tensor transpose mungkin harus mengizinkan permutasi yang ditentukan pengguna, dengan membalikkan redup sebagai default.

Tensor transpose mungkin harus mengizinkan permutasi yang ditentukan pengguna, dengan membalikkan redup sebagai default.

Sepertinya itu akan memperumit jenisnya sedikit, mungkin kita dapat memiliki jenis PermuteDims yang memungkinkan permutasi dimensi malas sewenang-wenang.

@ Stefan : Sepertinya ide yang cukup bagus untuk menyelesaikan vektor dan 2-dim
aljabar. Hanya beberapa tantangan:

  1. Mengenai kasus larik beberapa dimensi: Untuk larik A dengan dimensi
    (i_1, i_2, ..., i_n), jika seseorang ingin transpos diterapkan ke [i_2, i_3]
    dimensi - atau, bahkan hash, pada dimensi [i_2, i_4]. Bisakah Anda melakukannya di
    definisi baru transpos?
  2. Mengenai dimensi tunggal: ada kemungkinan potongan tunggal adalah
    pergi dengan sengaja. Haruskah Julia mempertahankan dimensi tunggal ini setelah
    perhitungan? Misalnya, jika seseorang mendefinisikan vektor sebagai larik V di
    dimensi (2,1), dan ingin mengalikan transpos dengan matriks A in
    dimensi (2,3,4). Bisakah Anda menghasilkan hasil v '* A dalam dimensi
    (1,3,4)?

Pada hari Kamis, 16 Oktober 2014 pukul 14.31, Stefan Karpinski [email protected]
menulis:

Satu-satunya gangguan sebenarnya adalah bahwa M [1 ,:] adalah vektor (vertikal)
bukan matriks baris. Jika tidak, ini sebenarnya cukup mulus,
serangkaian perubahan yang tidak mengganggu (satu harapan). Pencerahan utama (bagi saya) adalah
bahwa perilaku pemotongan APL dapat dikombinasikan dengan transposes malas. Jika kita mendapatkan
buy-in, kita bisa membuat rencana dan membagi pekerjaan. aku sangat berharap
bahwa lazy transposes dan fungsi bertahap memungkinkan beberapa pengurangan kode dan
penyederhanaan.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -59425385.

Re 2 & 3: setelah mendapat tikaman kasar, saya sampai pada kesimpulan bahwa transpos vektor TIDAK boleh menjadi subtipe AbstractVector , jika tidak semuanya akan berantakan (lihat diskusi di # 6837). Saya pikir cara maju yang paling waras adalah dengan Transpose{T,A} <: AbstractMatrix{T} , dan tipe Covector (+ Conjugate varian).

Masalah penting lainnya yang saya temui adalah sering kali Anda ingin mengirimkan jenis matriks tertentu, transposenya, atau transpos konjugatnya. Sayangnya, saya tidak dapat menemukan cara untuk mengekspresikan ini melalui mesin tipe yang ada (lihat diskusi milis ini ). Tanpa ini, saya khawatir kita akan mendapatkan banyak @eval -ing lebih dari 3x3 kemungkinan kombinasi argumen.

@simonbyrne , saya tunduk pada pengalaman Anda dengan penerapannya. Apakah sisanya tampak masuk akal?

Saya telah menunjukkan (di forum yang tidak terlalu umum, jadi mungkin perlu disebutkan secara singkat di sini) bahwa alternatif potensial adalah menangani semua pembentukan _internally_, dengan memperluas jenis indeks yang dapat digunakan SubArray. Secara khusus, seseorang dapat memiliki tipe "transposed range" yang akan memberikan bentuk yang dialihkan ke SubArray, bahkan ketika array induk adalah Vector . (Lihat https://github.com/JuliaLang/julia/blob/d4cab1dd127a6e13deae5652872365653a5f4010/base/subarray.jl#L5-L9 jika Anda tidak terbiasa dengan cara SubArray / dapat diimplementasikan.)

Saya tidak yakin apakah strategi alternatif ini membuat hidup lebih mudah atau lebih sulit. Ini mengurangi jumlah tipe yang menghadap ke luar, yang mungkin berarti bahwa seseorang membutuhkan lebih sedikit metode. (Sebagai seseorang yang _still_ mengisi metode yang hilang karena transisi Color dalam Images , ini tampak seperti Hal yang Baik.) Di sisi lain, dengan tidak adanya pengiriman segitiga yang nyaman, ini bisa membuatnya agak canggung untuk menulis metode selektif, yang mungkin memperburuk masalah yang diangkat oleh @simonbyrne.

Wawasan apa pun akan sangat diterima.

Selain detail seperti itu, saya suka bentuk proposal @StefanKarpinski . Saya tidak terikat dengan pengindeksan gaya APL, tetapi saya yakin ini adalah pilihan yang lebih baik daripada aturan turunan Matlab yang kita miliki sekarang.

Dua pemikiran:

  • Jika pengindeksan seperti A[[2], :] menjadi idiomatik, tampaknya sedikit boros harus membuat vektor hanya untuk membungkus indeks tunggal 2 . Haruskah kita mempertimbangkan untuk mengizinkan A[(2,), :] untuk hal yang sama, atau yang serupa? Saya kira satu rentang elemen tidak apa-apa, tetapi alangkah baiknya memiliki sintaks yang hampir senyaman [2] .
  • Jika kita membutuhkan jumlah dimensi yang cocok untuk melakukan penyiaran, seharusnya ada cara sederhana untuk menambahkan dimensi tunggal ke sebuah array, mungkin sesuatu seperti numpy newaxis indexing.

Saya berpikir untuk mengusulkan bahwa pengindeksan dengan titik koma, a la A[2;:] , bisa menjadi mode pengindeksan yang berbeda di mana hasilnya selalu memiliki jumlah dimensi yang sama dengan A - yaitu tidak ada lajang dan pengindeksan dengan apa pun yang memiliki peringkat lebih dari satu adalah kesalahan. Memutuskan untuk tidak memasukkan hal itu dari proposal inti demi kesederhanaan, tetapi hal seperti itu tampaknya merupakan hal yang baik untuk dimiliki.

Saya dapat melihat kekhawatiran yang diungkapkan oleh @simonbyrne . Namun pada prinsipnya, sebuah covector juga hanyalah sebuah vektor yang hidup dalam ruang vektor yang berbeda, yaitu ruang ganda. Jadi membuat tipe Transpose atau Covector bukan subtipe AbstractArray juga terasa agak tidak menyenangkan. Resolusi yang mungkin, yang akan menjadi perubahan besar dan mungkin tidak akan dipertimbangkan (tapi saya tetap ingin menyebutkannya) adalah dengan memberikan seluruh AbstractArray keluarga parameter tipe tambahan trans , yang bisa memiliki nilai :N , :T atau :C . Untuk semua metode yang hanya mengasumsikan vektor sebagai daftar angka satu dimensi, metode tersebut tidak perlu membedakan antara nilai yang berbeda dari parameter akhir ini, sehingga definisi metode yang sesuai dapat tetap seperti sekarang.

Untuk array berdimensi-N dengan N> 2, ada berbagai opsi. Entah transpose memberikan kesalahan dan tidak mungkin untuk benar-benar membuat objek tipe AbstractArray{3,Float64,trans} mana trans!=:N , atau, alternatifnya, :T hanya berarti baris-mayor dan transpose dari array umum memiliki efek membalikkan semua dimensi. Saya pikir yang terakhir juga merupakan konvensi yang diterima oleh orang-orang yang menggunakan notasi grafis Penrose (lihat http://en.wikipedia.org/wiki/Penrose_graphical_notation meskipun transpos tidak dijelaskan di sana, tetapi juga melihat buku yang dikutip oleh Cvitanović).

Saya tidak benar-benar melihat peran permutasi indeks arbitrer yang didukung oleh transpose , ada permutedims untuk itu, dan mungkin beberapa pendekatan malas menggunakan SubArrays yang dirubah. Selain itu, motivasi utama untuk masalah ini adalah untuk menyederhanakan kebun binatang A_mul_B, dan kontraksi tensor tingkat tinggi tidak (dan seharusnya tidak) didukung melalui perkalian normal.

Saya yakin ada beberapa masalah baru terkait dengan pendekatan ini yang belum saya pikirkan.

Saya rasa saya menemukan solusi yang masuk akal untuk masalah pengiriman di sini .

Proposal @Jutho sepertinya menarik, dan menurut saya perlu ditelusuri. Sayangnya, satu-satunya cara nyata untuk mengevaluasi hal-hal ini adalah dengan mencoba menerapkannya.

@tokopedia ,

  • A[2:2,:] juga akan mempertahankan dimensi, dan itu tidak memerlukan alokasi atau sintaks baru.
  • Sesuatu seperti newaxis tampaknya sangat mungkin. Memang, dengan arsitektur # 8501 tampaknya mungkin untuk membuat penyiaran secara langsung dengan mengindeks: memiliki tipe indeks yang selalu menghasilkan 1 tidak peduli berapa nilai yang diisi pengguna ke dalam slot itu.

Masalah dengan 2:2 adalah pengulangan jika ada ekspresi panjang untuk indeks, bukan hanya 2 . Tetapi tentu saja Anda selalu dapat menentukan fungsi Anda sendiri untuk membuat rentang dari indeks.

Proposal yang sangat bagus: +1 :.

Ingatkan saya mengapa kita menginginkan v' == v ?

Kita tidak benar-benar membutuhkannya, tetapi ini cukup bagus karena rangkap ruang vektor (berdimensi hingga) bersifat isomorfik.

Atau lebih kuat lagi, karena larik Julia tidak membedakan antara indeks kovarian dan kontravarian, masuk akal untuk menganggap ini sebagai vektor dalam ruang Cartesian (metrik Euclidean = matriks Identitas = delta kronecker), di mana memang ruang ganda secara alami isomorfis.

Saya tidak begitu yakin kita menginginkan v '== v, tapi menurut saya itu cukup ortogonal
sisanya. Apakah kita ingin matriks kolom dan vektor membandingkan sama jika mereka
memiliki elemen yang sama?

Itu sebenarnya masalah yang berbeda karena mereka memiliki jumlah dimensi yang berbeda.

Secara khusus, proposal ini secara efektif menghapus identifikasi antara vektor dan matriks kolom - karena jika Anda mengiris matriks secara horizontal atau vertikal, Anda akan mendapatkan vektor. Sebelumnya Anda dapat mengabaikan dimensi singleton yang tertinggal - atau berpura-pura bahwa ada lebih dari yang sebenarnya. Ini tidak akan menjadi ide yang baik untuk melakukan itu karena vektor bisa berasal dari potongan array mana pun.

Apakah masuk akal untuk convert sesuatu dari 1-d hingga 2-d dengan menambahkan dimensi singleton trailing?

Dengan proposal ini, saya pikir itu mungkin bukan lagi ide yang bagus. Tapi mungkin karena vektor masih berperilaku seperti kolom sementara covectors berperilaku seperti baris.

Satu hal yang saya catat di # 8416 adalah bahwa sparsevec secara acak dipalsukan sebagai matriks CSC kolom tunggal sekarang. Sparse harus dapat menyesuaikan dengan ini dengan cukup baik setelah tipe vektor sparse 1-d yang tepat diterapkan (yang akan menjadi kasus paling sederhana yang berguna dari tipe Nd COO generik, hanya perlu ditulis).

Hanya menerima semua ini. Jadi berikut ini tidak akan berhasil?

A [1 ,:] * A * A [:, 1] # baris dari kolom Matriks * Matriks * dari matriks ???

Kau menulis

v'w adalah produk titik dari v dan w - khususnya, ini adalah skalar, bukan vektor satu elemen.

Juga v '* w adalah skalar?

Saya suka gagasan titik (x, y) mengambil dua item yang bentuknya adalah (1, ..., 1, m, 1, ..., 1) dan
mengembalikan produk titik apa pun yang terjadi. Tapi saya tidak ingin x * y memberi titik (x, y) dalam pengertian ini
kecuali x adalah covector dan y adalah vektor.

Tidak yakin apakah ini ide yang bagus tapi mungkin tidak apa-apa jika
A [:, 1,1] adalah vektor dan A [1,:, 1] atau A [:, 1,:] adalah covectors.
Terasa lebih baik untuk mengikuti dimensi vektor - slot, di mana Anda
diperbolehkan mengontraksi tensor, dengan aljabar linear standar
1 (vektor baris) dan 2 vektor kolom.

Dalam pandangan saya, dua tantangan utama yang telah kami tangani sebelumnya dalam masalah ini adalah:

(A) bagaimana membedakan semantik tensor (untuk kontraksi) dan semantik larik (untuk penyiaran) saat beroperasi pada data multidimensi;
(B) bagaimana menanamkan aljabar linier yang jelas dan nyaman dalam kerangka yang konsisten yang menggeneralisasi ke dimensi yang lebih tinggi.

Tidak jelas bagi saya bagaimana proposal ini menangani salah satu dari masalah ini. Sejauh yang saya tahu, untuk mencapai (A) masih membutuhkan manipulasi pengguna ad-hoc (seperti dengan fungsionalitas saat ini); dan untuk mengatasi (B) menggunakan lazy wrappers akan membutuhkan sesuatu seperti ekstensi SubArray yang disarankan oleh @timholy , yang mana hal itu menjadi versi lazy dari pendekatan masking yang dibahas beberapa waktu lalu. Saya dapat membayangkan memberikan dukungan tambahan untuk (A) menggunakan beberapa mekanisme malas serupa (seperti tipe List pembungkus), tetapi dalam semua kasus ini menurut saya kemalasan harus menjadi strategi opsional.

Saya tidak tahu berapa banyak yang berbagi pandangan @Jutho bahwa "kontraksi tensor tingkat tinggi tidak (dan seharusnya tidak) didukung melalui perkalian normal", tetapi saya sangat setuju: Saya hanya melakukan apa yang saya anggap sebagai teknik biasa matematika, dan saya membutuhkannya setiap saat. Meskipun bahasa saat ini seperti Mathematica dan NumPy memiliki batasan desain dalam hal ini (seperti yang telah saya bahas di atas), setidaknya mereka didukung! Misalnya, segera setelah Anda ingin menggunakan gradien bidang vektor dalam metode numerik sederhana, Anda memerlukan kontraksi tensor tingkat tinggi.

Saat Anda berkata, "... memiliki batasan desain dalam hal ini (seperti yang telah saya diskusikan di atas), setidaknya mereka didukung", apakah Anda berbicara tentang fungsionalitas yang hilang, atau sesuatu yang mendasar tentang vektor dan transposes yang tidak dapat ditangani di tingkat yang lebih tinggi, atau dengan menambahkan fungsi?

Apakah ada sesuatu tentang proposal ini _konflik_ dengan peningkatan poin Anda (A) dan (B)?

Saya benar-benar tidak melihat bagaimana kontraksi tensor didukung oleh operator perkalian standar matlabs *, atau melalui fungsi matlab bawaan lainnya dalam hal ini. Numpy memiliki fungsi bawaan (saya lupa namanya) tetapi juga agak terbatas sejauh yang saya ingat.

Saya juga membutuhkan kontraksi tensor dalam bentuk paling umum sepanjang waktu, itulah mengapa saya tahu bahwa menentukan kontraksi tensor paling umum, apalagi menerapkannya secara efisien, tidak sepenuhnya langsung. Itulah mengapa saya berpendapat bahwa perlu ada fungsi khusus untuk ini, daripada mencoba menjejalkan beberapa fungsi yang setengah berfungsi atau agak spesifik ke dalam operator standar di basis Julia, yang tidak mencakup setengah kasus penggunaan. Tapi saya senang mengubah pendapat saya, misalnya jika ada satu kontraksi 'standar' yang jauh lebih penting / berguna daripada yang lain? Tetapi ini mungkin sangat bergantung pada domain dan karenanya tidak cocok sebagai aturan umum untuk adopsi di Julia Base.

Op 19-okt.-2014 om 22:52 heeft thomasmcoffee [email protected] het volgende geschreven:

Dalam pandangan saya, dua tantangan utama yang telah kami tangani sebelumnya dalam masalah ini adalah:

(A) bagaimana membedakan semantik tensor (untuk kontraksi) dan semantik larik (untuk penyiaran) saat beroperasi pada data multidimensi;
(B) bagaimana menanamkan aljabar linier yang jelas dan nyaman dalam kerangka yang konsisten yang menggeneralisasi ke dimensi yang lebih tinggi.

Tidak jelas bagi saya bagaimana proposal ini menangani salah satu dari masalah ini. Sejauh yang saya tahu, untuk mencapai (A) masih membutuhkan manipulasi pengguna ad-hoc (seperti dengan fungsionalitas saat ini); dan untuk mengatasi (B) menggunakan lazy wrappers akan membutuhkan sesuatu seperti ekstensi SubArray yang disarankan oleh @timholy , yang mana hal itu menjadi versi lazy dari pendekatan masking yang dibahas beberapa waktu lalu. Saya dapat membayangkan memberikan dukungan tambahan untuk (A) menggunakan beberapa mekanisme malas yang serupa (seperti jenis pembungkus Daftar), tetapi dalam semua kasus ini menurut saya kemalasan harus menjadi strategi opsional.

Saya tidak tahu berapa banyak yang berbagi pandangan @Jutho bahwa "kontraksi tensor tingkat tinggi tidak (dan seharusnya tidak) didukung melalui perkalian normal", tetapi saya sangat setuju: Saya hanya melakukan apa yang saya anggap sebagai teknik biasa matematika, dan saya membutuhkannya setiap saat. Meskipun bahasa saat ini seperti Mathematica dan NumPy memiliki batasan desain dalam hal ini (seperti yang telah saya bahas di atas), setidaknya mereka didukung! Misalnya, segera setelah Anda ingin menggunakan gradien bidang vektor dalam metode numerik sederhana, Anda memerlukan kontraksi tensor tingkat tinggi.

-
Balas email ini secara langsung atau lihat di GitHub.

inilah kontraksi selama indeks terakhir A dan indeks pertama B
semacam titik matematika

function contract(A,B)
   s=size(A)
   t=size(B)
   reshape(reshape(A, prod(s[1:end-1]), s[end]) *  reshape(B,t[1],prod(t[2:end])) , [s[1:end-1]... t[2:end]...]...)
end

Saya selalu bisa melakukan kontraksi umum dengan bentuk ulang, permutes, dan mungkin kompleks
konjugasi bila dibutuhkan kurang lebih seperti di atas

tidak yakin apa masalah besar sebenarnya dengan tensor, mengapa kita tidak bisa menerapkan beberapa saja
fungsi?

Ya persis. Dalam masalah ini, yang ingin kami selesaikan untuk maju adalah

  1. Dimensi apa yang harus diturunkan dalam pengindeksan? "Gaya APL" tampaknya tidak kontroversial.
  2. Apa yang diberikan vector' ?

Untuk kontraksi tensor, dengan jenis dan fungsi bertahap yang sesuai, saya pikir kita sebenarnya bisa mendapatkan implementasi berkinerja cukup tinggi.

Perasaan saya adalah bahwa tensor akan mengurus dirinya sendiri dan kita harus yakin
agar pengguna aljabar linier tidak merasa frustrasi.

Kekhawatiran terbesar saya adalah itu

(mengambil baris dari array 2d) * (array 2d) * (mengambil kolom dari array 2d)

yang merupakan operasi umum tetap tidak akan berhasil kecuali kita ambil
(mengambil pertengkaran) dengan covector atau mungkin lebih baik lagi
beri tag dengan indeks slot umum.

@JeffBezanson , ketika saya mengatakan bahwa operasi ini didukung, yang saya maksud adalah tipe dan fungsi data Dot dari Mathematica. Jadi, bagi pengguna, ada cara bawaan, terdokumentasi, dan / atau jelas untuk melakukan hal-hal tertentu. Untuk desain apa pun, dukungan untuk apa pun dapat diperoleh dengan menambahkan fungsi, seperti halnya dengan implementasi saat ini; jadi ini bukan masalah konflik teknis, ini masalah desain.

@ Jutho , saya jarang menggunakan MATLAB, jadi saya tidak bisa berkomentar. Saya setuju desain NumPy kurang koheren daripada Mathematica (seperti yang saya diskusikan di atas), tetapi juga mendukung berbagai perilaku yang lebih kaya. Saya setuju bahwa aljabar linier dasar harus membiarkan mesin tensor umum tidak terlihat oleh pengguna yang tidak membutuhkannya, tetapi karena fitur bahasa Julia yang hebat, tampaknya tidak perlu memperkenalkan implementasi yang berbeda untuk mereka, seperti yang dimiliki NumPy dan Mathematica terpaksa melakukannya sampai batas tertentu. Bagi saya masalah ini, setidaknya sebagian, tentang menemukan sistem terpadu yang tepat untuk keduanya, untuk mengungkapkan spesialisasi apa yang harus digunakan untuk kasus aljabar linier umum: misalnya, apa yang harus dilakukan tentang vector' .

A [1 ,:] * A * A [:, 1] # baris dari kolom Matriks * Matriks * dari matriks ???

Benar - Anda harus menulis A[1,:]' * A * A[:,1] .

Juga v '* w adalah skalar?

Ya, v'w adalah hal yang sama. Salah satu hal baik dari proposal ini adalah ia sepenuhnya menghilangkan peretasan sintaksis yang murah.

Tidak yakin apakah ini ide yang bagus ...

Saya tidak berpikir demikian. Salah satu tujuan dari proposal ini adalah untuk membuat aturan pemotongan dan pengindeksan menjadi simetris dan ini akan membuat salah satu indeks menjadi spesial, yang menurut saya mengalahkan keseluruhan tujuan. Jika mengiris akan menjadi asimetris, sebaiknya kita mempertahankan perilaku saat ini.

@thomasmcoffee Anda harus lebih spesifik. Tentu saja semua orang ingin segala sesuatunya koheren, didokumentasikan, jelas, dll. Pertanyaannya adalah, apakah proposal di atas meja memenuhi tujuan tersebut? Mungkin proposal saat ini tidak memengaruhi tujuan tersebut sama sekali, tidak apa-apa --- selama itu mengarah pada peningkatan di tempat lain, kami masih memiliki peningkatan bersih.

Jadi biarkan saya menjelaskan ini

Jika A tidak persegi

| | Saat ini | Diusulkan | MATLAB |
| --- | --- | --- | --- |
| A * A [1 ,:] | Tidak | Ya | Tidak |
| A * A [1 ,:] '| Ya | Tidak | Ya |
| A [:, 1] A | Tidak |
A [:, 1] ' A | Ya | Ya | Ya |

dan jika A persegi

| | Saat ini | Diusulkan | MATLAB |
| --- | --- | --- | --- |
| A * A [:, 1] | Ya | Ya | Ya |
| A * A [:, 1] '| Tidak | Tidak | Tidak |
| A [1 ,:] A | Tidak |
A [1 ,:] ' A | Tidak | Ya | Tidak |

Saya bersumpah saya baru saja memposting jawaban untuk ini tetapi entah bagaimana itu menghilang ke eter. Ini semua benar. Dalam pengaturan saat ini, Anda perlu mempertimbangkan apakah Anda akan mengambil irisan baris atau irisan kolom serta apakah Anda mengalikan di kiri atau kanan saat memutuskan apakah akan mengubah urutan atau tidak (kolom ditransposisikan di sebelah kiri, baris dialihkan di sebelah kanan). Dalam proposal, Anda hanya mempertimbangkan di sisi mana Anda mengalikan - Anda selalu mengubah urutan di kiri, tidak pernah di kanan.

Apakah tidak apa-apa jika

dot(x,y) dan dot(x.',y) dan dot(x,y.') dan dot(x.',y.') semuanya memberikan skalar yang sama?

yaitu Σᵢ konj (xᵢ) * yᵢ

dengan cara ini seseorang dapat mengerjakan titik (x, A * y) tanpa berpikir terlalu banyak

Contoh oleh @alanedelman tersebut terasa agak mundur di tempat yang tidak seharusnya, karena pengindeksan APL. Mungkin itu motivasi yang cukup untuk memiliki dimensi yang melestarikan varian pengindeksan, seperti yang saya pikir telah dibahas (mis. A[i; :] ?)

Tapi kemudian Anda ingin memberikan covector dalam kasus di atas.

@ alanedelman , saya tidak melihat alasan mengapa metode dot tidak boleh ada dan memberikan hasil yang sama.

Saya selalu bisa melakukan kontraksi umum dengan bentuk ulang, permutes, dan mungkin kompleks
konjugasi bila dibutuhkan kurang lebih seperti di atas

Persis seperti itulah penerapannya dalam fungsi tensorcontract di TensorOperations.jl, jika Anda memilih metode: BLAS, yang tentunya merupakan yang tercepat untuk tensor besar. Saya juga menulis implementasi julia asli, menggunakan fungsionalitas Cartesian.jl (dan semoga suatu hari menggunakan fungsi bertahap) yang menghilangkan kebutuhan permutedims (alokasi memori tambahan) dan lebih cepat untuk tensor yang lebih kecil.

Saya baru saja menanggapi klaim palsu bahwa matlab menyediakan fungsionalitas bawaan untuk ini yang tidak dimiliki Julia. Baik bentuk ulang dan permutasi tersedia di Julia. Numpy memang memiliki fungsi tensordot yang melakukan hal ini, tetapi tidak memungkinkan Anda menentukan urutan indeks tensor keluaran, jadi Anda masih memerlukan permutedims setelahnya jika Anda memiliki urutan keluaran tertentu.

Tapi ini terlalu jauh dari topik saat ini, yang memang mendapatkan perilaku yang konsisten untuk aljabar vektor dan matriks.

1 untuk proposal Stefan. Tampaknya memberikan semantik yang sangat jelas tetapi cukup fleksibel. Sebagai pengguna aljabar linier, bahkan yang terbiasa dengan sintaks gaya MATLAB, saya akan menemukan aturannya cukup sederhana untuk digunakan.

Saya agak bingung tentang apa yang dimaksud dengan ' secara umum. Jika v adalah vektor, v' adalah transpose . Jika a adalah array 2d, a' sekarang akan menjadi transpose juga. Keduanya tampaknya didefinisikan untuk kepentingan dapat dengan mudah membentuk b' * a dengan mengontrak dimensi pertama b dengan dimensi pertama a .

Tampaknya tidak ada konsensus tentang definisi a' ketika dimensi a adalah> 2. Saya belum pernah mendengar ada yang mengusulkan apa pun selain membalikkan dimensi, dan ini bertepatan dengan b' * a mengontrak dimensi pertama b dengan dimensi pertama a .

Saya pikir alangkah baiknya jika kita dapat menyatakan apa yang dilakukan ' secara ringkas tanpa mengacu pada ukuran dari hal yang sedang dioperasikan.

Tampaknya masuk akal untuk memiliki fungsi penyusutan lain yang tersedia di Base untuk situasi yang lebih umum, misalnya contract(a, b, 2, 3) untuk mengkontrak dimensi ke-2 dari a dengan dimensi ketiga b .

Omong-omong, dot(a,b) == a'*b ketika a dan b adalah vektor, tetapi dot(a,b) saat ini tidak ditentukan untuk matriks. Bisakah kita memiliki dot(a,b) = trace(a'*b) ?

@ madeleineudell : Saya agak bingung tentang apa yang dimaksud 'secara umum.

Saya berbagi keprihatinan ini. Pada dasarnya Anda dapat mengambil properti 2-5, 7, 8 & 10 dalam proposal saya sebagai karakteristik yang menentukan. Yaitu Anda ingin memegang ini:

  • v' adalah satu dimensi tetapi bukan vektor
  • v'' === v
  • v' == v
  • v'w adalah skalar
  • v*w' adalah matriks
  • v'*M adalah hal yang sama seperti v'
  • M' adalah dua dimensi tapi bukan matriks, mungkin tampilan matriks

Secara khusus, tidak ada batasan tentang apa artinya atau fungsinya untuk array dimensi yang lebih tinggi. Sebuah teori umum tentang apa itu covectors yang mencakup dimensi yang lebih tinggi akan bagus, tetapi saya tidak yakin itu benar-benar dapat dilakukan tanpa terlalu memperumit banyak hal, misalnya dengan memiliki dimensi naik / turun atau setiap dimensi diberi label dengan indeks.

Jelas setidaknya bahwa aturan umum untuk ' bukanlah bahwa itu akan membalikkan dimensi, karena itu bukan yang akan dilakukannya untuk vektor dan covectors.

Satu-satunya aturan sederhana yang dapat saya pikirkan yang menangkap perilaku di atas untuk kedua vektor, covectors, dan matriks adalah dengan mengubah dua dimensi pertama (vektor memiliki dimensi kedua yang tidak ada dan covector memiliki detik pertama dan sekarang tidak ada).

Pada 20 Okt 2014, pukul 09:05, toivoh [email protected] menulis:

Jelas setidaknya bahwa aturan umum untuk 'bukanlah membalikkan dimensi, karena bukan itu yang akan dilakukannya untuk vektor dan covectors.

Satu-satunya aturan sederhana yang dapat saya pikirkan yang menangkap perilaku di atas untuk kedua vektor, covectors, dan matriks adalah dengan mengubah dua dimensi pertama (vektor memiliki dimensi kedua yang tidak ada dan covector memiliki detik pertama dan sekarang tidak ada).

Saya berpendapat bahwa ini tidak benar jika Anda ingin memikirkan tensor umum. Mungkin benar jika Anda hanya berpikir tentang matriks dan vektor sebagai beberapa blok dengan angka di dalamnya, dan Anda menganggap v sebagai kolom dan v 'sebagai baris.

Akan tetapi, jika Anda menganggap v sebagai elemen ruang vektor, dan w = v 'sebagai cara untuk memetakan v ke elemen w ruang ganda V_, maka w masih merupakan vektor, yaitu objek satu dimensi. Secara umum, seseorang membutuhkan metrik untuk mendefinisikan pemetaan ini dari V ke V_, yaitu w_i = g_ {i, j} v ^ j. Sekarang jika V adalah ruang Cartesian, yaitu R ^ n dengan standar metrik Euclidean, maka V * secara alami isomorfik ke V. Ini berarti bahwa tidak ada pengertian indeks atas atau bawah (kovarian atau kontravarian) dan karenanya w_i = v_i = v ^ i = w ^ i. Saya berpendapat bahwa ini adalah kasus yang digunakan di sebagian besar pemrograman, yaitu kasus yang perlu didukung oleh Julia Base. (Untuk ruang vektor kompleks, V * secara alami isomorfik terhadap Vbar, ruang vektor konjugasi, dan karenanya pemetaan alaminya adalah w_i = conj (v ^ i).)

Konvensi untuk menunjukkan vektor sebagai kolom dengan angka, vektor ganda sebagai baris dengan angka, dan karenanya matriks (yang merupakan elemen dari V \ otimes V_) sebagai blok dengan angka sangatlah mudah, tetapi berhenti segera setelah Anda juga ingin mempertimbangkan dimensi yang lebih tinggi. array, yaitu elemen ruang hasilkali tensor orde tinggi. Dalam hal ini, 'vektor baris', yaitu objek dua dimensi di mana dimensi pertamanya berukuran 1, dalam terminologi matlab / julia, adalah beberapa elemen dari ruang perkalian tensor V1 \ otimes V2, di mana V1 kebetulan terjadi pada menjadi R (atau ruang satu dimensi lainnya). Saya setuju bahwa ini mungkin bukan yang Anda inginkan sebagai perilaku default, tetapi saya lebih suka seseorang tidak mencoba mendefinisikan transpos untuk array umum dan merujuk ke permutedims, seperti yang dilakukan matlab. Membalik dua dimensi pertama untuk tensor umum sebagai konvensi default tidak masuk akal. Mentransposisi elemen dari beberapa ruang produk tensor tingkat tinggi V1 \ otimes V2 \ otimes… \ otimes Vn tidak memiliki definisi yang unik. Konvensi untuk membalikkan semua dimensi hanya berasal dari representasi grafis yang nyaman oleh Penrose, seperti yang disebutkan di atas. Selain itu, ini adalah salah satu yang memetakan ruang matriks (V \ otimes V_) ke dirinya sendiri (V * \ otimes V * = V \ otimes V ).

Saya dapat melihat dua cara ke depan:
1) Membuat operator kenyamanan '(dan mungkin bahkan *) bekerja dengan array tingkat tinggi sewenang-wenang menggunakan beberapa konvensi yang dipilih, dalam pengaturan tensor Cartesian (yaitu tidak ada perbedaan antara indeks atas atau bawah). Ini mungkin membawa hasil yang mengejutkan untuk kasus penggunaan biasa.

2) Batasi 'dan * untuk vektor dan matriks. Kesalahan pada array order yang lebih tinggi. Saya rasa ini adalah pendekatan yang paling populer (misalnya Matlab dll).

Posting ini sedikit mengambil sisi lain dari posisi yang saya ambil tahun lalu, jadi

jelajahi ambivalensi dari kedua sisi.

Semoga tidak apa-apa.
Akhirnya saya tersadar bahwa ada logika untuk pendekatan saat ini, tetapi tidak pernah diartikulasikan.
Itu terlihat sangat mirip retasan sehingga itu hanya mengganggu saya. Entah bagaimana sekarang aku mengerti
itu, saya lebih menyukainya.

Dalam pendekatan saat ini, semua array berdimensi tak hingga dengan penurunan 1 yang tersirat.
Operator apostrof dapat berarti menukar dua dimensi pertama,
tetapi dalam kenyataannya seperti yang ada saat ini, itu berarti

ndim (A) <= 2? interchange_first_two_dims: no_op

maaf jika semua orang melihat itu dan saya melewatkannya. Pikiranku macet
dengan gagasan bahwa vektor adalah satu dimensi, bukan berdimensi tak hingga, dan
Oleh karena itu transpose harus membalikkan dimensi, maka menjadi no_op.

Saya baik-baik saja dengan apostrof melakukan ini, atau apostrof selalu bertukar
dua dimensi pertama - Saya rasa saya tidak peduli. Saya pikir apostrof itu ada
untuk aljabar linier dan bukan aljabar multilinear.

Saya bermain-main dengan apakah apostrof-star ("'*") (jika memungkinkan! Atau sesuatu yang lain jika tidak mungkin)
berarti mengkontraksikan dimensi terakhir ke dimensi pertama (seperti titik Mathematica)
dan memiliki pengindeksan apl dan tidak ada covectors. Sebagian otakku masih berpikir yang perlu ditelusuri,
tetapi saat saya bangun, inilah pendekatan saat ini yang tampak lebih baik dan lebih baik.
(Mari kita lihat bagaimana perasaan saya nanti hari ini)

Saya tidak menyesal memulai utas ini tahun lalu, tetapi saya bertanya-tanya lagi kasus apa
benar-benar mengganggu orang hari ini ... bisakah kita mendapatkan daftar contohnya? ... dan apakah
menjelaskan kasus-kasus ini lebih baik daripada mengubah apa yang kita lakukan.

Saya telah membaca seluruh utas ini dan melihat banyak prinsip - yang bagus,
tapi tidak cukup kasus penggunaan untuk memusatkan perhatian pada berbagai hal.

Saya dapat mengatakan bahwa saya sering merasa terganggu

[1 2 3] # tujuan == 2
[1,2,3] # tujuan == 1
[1; 2; 3] # target == 1

terutama karena saya tidak bisa mengingatnya.

Hanya eksperimen pikiran. Fungsionalitas apa yang akan hilang jika kita mendefinisikan kembali * untuk melayani sebagai operator kontraksi yang serupa dengan apa yang dipikirkan @alanedelman untuk '* ? Bukankah itu menghilangkan kebutuhan untuk ' dalam operasi aljabar linier sama sekali (selain berfungsi sebagai transpos untuk matriks)? Saya hanya dapat melihat bahwa itu akan menghilangkan produk luar w*v' , yang dapat dengan mudah diganti dengan outer(w,v) .

EDIT: Dengan asumsi mengiris APL. Misalnya A[1,:]*A*A[:,1] akan memiliki hasil yang diharapkan tanpa perlu mengubah posisi operan pertama dengan ' .

Saya memikirkan ini juga. Saya pikir v * w menjadi produk titik sepertinya terlalu membebani steroid
yang mungkin rawan kesalahan.
Ini adalah satu tempat di mana titik mathematica tampak tidak terlalu buruk.

Jadi untuk meringkas, kontrak terakhir untuk pertama tampaknya masuk akal, tetapi
apakah itu bisa berupa bintang apostrof atau bisa juga * atau harus titik
memiliki masalah.

Agak tidak terkait tetapi tidak sepenuhnya tidak terkait ....
Saya ingin menunjukkan bahwa dot-star yang dibaca semua orang sebagai dot-star awalnya (saya diberitahu) adalah
dimaksudkan untuk menjadi point-star karena operator POINTWISE adalah apa
dimaksudkan

Saya dapat mengatakan bahwa saya sering merasa terganggu

[1 2 3] # tujuan == 2
[1,2,3] # tujuan == 1
[1; 2; 3] # target == 1

terutama karena saya tidak bisa mengingatnya.

Saya selalu berpikir "mengapa kita tidak menggunakan hanya , ?"

Fungsionalitas apa yang akan hilang jika kita mendefinisikan ulang * untuk melayani sebagai operator kontraksi yang mirip dengan apa yang @alanedelman pikirkan untuk '*?

Kita akan kehilangan keterkaitan: misalnya (M*v)*v akan memberikan dot(v,M*v) (skalar) saat ini, sedangkan M*(v*v) akan menghasilkan M.*dot(v,v) (matriks).

Mengapa kita tidak menjadikan dot sebagai operator kontraksi (yang toh tidak asosiatif)? Kami juga dapat menentukan kontraksi pesanan yang lebih tinggi, misalnya ddot(A::Matrix,B::Matrix) == A⋅⋅B == trace(A'*B) .

Jadi, apakah saya memahami dengan benar bahwa satu-satunya tujuan memperkenalkan transposisi vektor adalah untuk menyelamatkan kita dari non-asosiativitas * ? Kerancuan dari contoh @alanedelman dapat diperbaiki dengan mengubah salah satu vektor ( M*v*v' vs M*v'*v ) tetapi hal yang sama dapat dilakukan dengan tanda kurung ( M*(v*v) vs (M*v)*v ) tanpa repot mengimplementasikan transpose untuk vektor (seperti yang telah ditunjukkan @Jutho, penerapan transpose untuk tensor orde tinggi tidak masuk akal secara matematis). Bagi saya pertanyaannya adalah notasi mana yang lebih mudah dibaca / ringkas / elegan / murni.

Sebenarnya M*(v*v) dan (M*v)*v saat ini keduanya diurai sebagai

*(M, v, v)

untuk memungkinkan produk matriks yang mengoptimalkan urutan perkalian berdasarkan ukuran argumen, sehingga parser juga harus diubah.

Tapi setidaknya secara pribadi saya berpikir bahwa asosiatif adalah masalah yang cukup besar. Anda harus menerjemahkan antara matematika dan sebagian besar bahasa pemrograman; untuk Julia Saya masih berharap Anda tidak perlu banyak menerjemahkan.

(seperti yang telah ditunjukkan @Jutho, menerapkan transpos untuk tensor tingkat tinggi tidak masuk akal secara matematis).

Saya tidak berpikir itulah yang saya katakan.

Fungsionalitas apa yang akan hilang jika kita mendefinisikan ulang * untuk melayani sebagai operator kontraksi yang mirip dengan apa yang @alanedelman pikirkan untuk '*?

Kita akan kehilangan asosiativitas: misalnya (M_v) _v akan memberikan titik saat ini (v, M_v) (skalar), sedangkan M_ (v_v) akan memberikan M._dot (v, v) (matriks).

Mengapa kita tidak menjadikan titik sebagai operator kontraksi (yang toh tidak asosiatif)? Kita juga bisa mendefinisikan kontraksi orde tinggi, misalnya ddot (A :: Matrix, B :: Matrix) == A⋅⋅B == trace (A '* B).

Dengan garis penalaran tersebut, kita tidak perlu lagi operator perkalian untuk vektor dan matriks, kita tinggal menulis semuanya dalam bentuk titik:
A ∙ B
A ∙ v
v ∙ A ∙ w
v ∙ w

Jadi itu hanya proposal @pwl tetapi dengan * diganti dengan titik.

Tapi setidaknya secara pribadi saya berpikir bahwa asosiatif adalah masalah yang cukup besar. Anda harus menerjemahkan antara matematika dan sebagian besar bahasa pemrograman; untuk Julia Saya masih berharap Anda tidak perlu banyak menerjemahkan.

Saya kira sebagian dari masalahnya adalah bahwa bahkan dalam matematika ada konvensi yang berbeda. Apakah berpikir dalam kerangka vektor baris dan kolom matematika, atau apakah kita ingin perilaku yang lebih abstrak dalam hal operator linier dan spasi ganda (di mana saya kira operator tidak dikalikan dengan vektor, tetapi diterapkan pada vektor, jadi mengapa tidak menulis A (v) bukannya A * v atau A ∙ v)?

Saya tidak terlalu membutuhkan sintaks kenyamanan, saya pribadi lebih suka menulis titik (v, w) di atas v '* w setiap saat, karena yang pertama lebih jelas mengungkapkan dasar operasi matematika independen (Sebenarnya, yang pertama perlu mendefinisikan a produk skalar sebelum pemetaan alami dari vektor ke vektor ganda bahkan dapat ditentukan). =

Maaf karena terlalu bodoh, tapi mengapa sebenarnya M[1, :] bisa menjadi transpos, berperilaku seperti v' ?

Saya akan menambahkan ke daftar hal-hal yang mengganggu saya

1.

[1 2 3] # ndims == 2
[1,2,3] # ndims == 1
[1;2;3] # ndims == 1

2.
v=rand(3)
v' * v memiliki ndims == 1 (proposal @StefanKarpinski memperbaiki ini)
(v' * v)/( v' * v ) memiliki ndims ==2 (ini benar-benar mengganggu saya dan juga akan diperbaiki)

Masih saya tidak benar-benar ingin covectors
dan pengindeksan apl adalah sesuatu yang terus saya lakukan
--- masih berpikir, tapi saya ingin melihat daftar hal-hal itu
mengganggu orang lain di julia saat ini

Saya sangat menyukai ide cdotmengontrak indeks terakhir ke indeks pertama selain operator *
dan membiarkan titik (a, b, ..) memungkinkan penyempitan yang sangat umum.

Terlepas dari konvensi penamaan Numpy (dan mungkin penampilan posting saya sebelumnya), saya memiliki perasaan agak campur aduk tentang penggunaan titik untuk kontraksi tensor umum. Ini adalah kalimat pertama Wikipedia:

Dalam matematika, perkalian titik, atau perkalian skalar (atau terkadang hasil kali dalam dalam konteks ruang Euclidean), adalah operasi aljabar yang mengambil dua urutan angka yang sama panjangnya (biasanya vektor koordinat) dan mengembalikan satu angka.

Dalam pikiran saya juga, titik harus mengembalikan skalar.

@ brk00 , masalah dengan pertanyaan Anda adalah tidak jelas bagaimana memperluas ini ke irisan array berdimensi lebih tinggi / peringkat lebih tinggi (saya benar-benar tidak suka dimensi dunia untuk ini).

Maaf karena terlalu cuek, tapi kenapa tepatnya M [1,:] tidak bisa menjadi transpose, berperilaku seperti v '?

Itu bisa, tapi bagaimana Anda menggeneralisasi ini?

@ Jutho , saya minta maaf, saya harus mengucapkannya secara berbeda. Maksud saya baris Anda "Mentransposisi elemen dari beberapa ruang produk tensor tingkat tinggi [...] tidak memiliki definisi unik", jadi tidak ada motivasi matematis untuk memperkenalkan satu definisi tertentu, atau untuk mendefinisikannya sama sekali.

@ alanedel :

Saya akan menambahkan ke daftar hal-hal yang mengganggu saya

[1 2 3] # tujuan == 2
[1,2,3] # tujuan == 1
[1; 2; 3] # target == 1

Perilaku penggabungan tidak terkait dengan masalah ini. Jangan sampai membuat air semakin keruh.

Saya pasti menyukai gagasan`cdot mengontrak indeks terakhir ke indeks pertama selain operator *
dan membiarkan titik (a, b, ..) memungkinkan penyempitan yang sangat umum.

Ini juga tangensial. Mari tetap fokus pada array dan slicing.


Dalam pendekatan saat ini, semua array berdimensi tak hingga dengan penurunan 1 yang tersirat.

Ini tidak benar. Jika ini benar, tidak akan ada perbedaan antara ones(n) , ones(n,1) , ones(n,1,1) , dll. Tapi itu semua adalah objek berbeda dengan tipe berbeda yang bahkan tidak sama satu sama lain. lain. Kami melakukan beberapa upaya untuk mengimplementasikan sesuatu sehingga mereka berperilaku _similarly_ tetapi itu jauh dari array yang sebenarnya berdimensi tak hingga.


Daftar hal-hal yang saat ini mengganggu sebagian besar mencerminkan (bagian dari) properti bagus dari proposal saya di atas. Yaitu:

  1. perilaku pemotongan asimetris - dimensi trailing adalah spesial.
  2. v'' !== v - sebenarnya v'' != v ; ini karena mereka tidak memiliki peringkat yang sama.
  3. v' != v - kesepakatan yang sama.
  4. v'w adalah vektor satu elemen, bukan skalar.
  5. kita membutuhkan parsing khusus untuk A*_mul_B* , yang merupakan hal yang paling mengerikan.

Saya setuju dengan sebagian besar poin @StefanKarpinski , kecuali untuk v' == v bit: Saya tidak berpikir ini harus sama. Ya, mereka mungkin isomorfik tetapi mereka masih merupakan objek yang berbeda, karena mereka berperilaku sangat berbeda: matriks M dan M' juga isomorfik namun saya rasa kita tidak ingin keduanya sama (kecuali mereka adalah Hermitian tentunya).

Pandangan umum saya dengan tipe Covector adalah bahwa mereka harus relatif ringan: selain operasi dasar (perkalian, penjumlahan, dll.), Kami akan menghindari menentukan terlalu banyak operasi (saya bahkan ragu-ragu untuk mendefinisikan pengindeksan ). Jika Anda ingin melakukan sesuatu dengannya, Anda harus mengubahnya kembali menjadi vektor dan mengerjakan tugas Anda di sana.

Memberi +1 untuk pendapat @simonbyrne , termasuk persetujuan umum atas pandangan @StefanKarpinski .

Juga setuju dengan @simonbyrne.

Ya, v dan v' memiliki tipe yang berbeda, tetapi kita telah mempertimbangkan tipe array yang berbeda dengan bentuk dan data yang sama agar sama - misalnya speye(5) == eye(5) . Mengapa covector berbeda dengan sparse?

Saya berharap bahwa covectors akan disiarkan seperti matriks baris. Untuk array A dan B yang dianggap sama, sejauh ini berlaku bahwa

all(A .== B)

yang tidak akan menjadi masalah jika satu adalah vektor dan satu adalah covector.

Bagi saya, covector lebih seperti matriks baris daripada vektor atau matriks kolom.

Saya kira pertanyaan kuncinya adalah apa itu size(v' )? Jika jawabannya adalah (length(v),) maka menurut saya v == v' seharusnya benar. Jika size(v') == (1,length(v)) maka itu mungkin salah, tapi bisa dibilang v' == reshape(v,1,length(v)) seharusnya benar. Jadi pertanyaannya adalah haruskah v' menjadi jenis vektor khusus atau jenis matriks khusus?

Saya semakin yakin bahwa masalah ini benar-benar tentang arti transpose yang sebenarnya.

Cover sebenarnya bukan array, jadi saya rasa kita tidak bisa mengatakan "bentuk" apa yang mereka miliki. Covector benar-benar ditentukan oleh apa yang dilakukannya, yaitu *(::Covector, ::Vector) memberikan skalar: karena AbstractVector tidak melakukan itu, itu sebenarnya bukan hal yang sama.

Masalah lain akan berada di bidang kompleks: akankah kita memiliki v' == v atau v.' == v ?

@simonbyrne :

Covector benar-benar ditentukan oleh apa yang dilakukannya, yaitu *(::Covector, ::Vector) memberikan skalar: karena AbstractVector tidak melakukan itu, itu sebenarnya bukan hal yang sama.

Ini adalah poin yang sangat bagus. Namun, mungkin agak menjengkelkan jika v' tidak dapat digunakan sebagai objek. Mungkin pendekatan yang tepat adalah memperlakukan v' sebagai matriks baris lucu alih-alih vektor lucu.

Mungkin pendekatan yang tepat adalah memperlakukan v 'sebagai matriks baris lucu daripada vektor lucu.

Baik, tapi menurut saya itu juga bukan subtipe dari AbstractMatrix : Menurut saya AbstractCovector harus menjadi tipe tingkat atas. Saya akan dengan senang hati mendefinisikan length(::Covector) , tapi menurut saya kita tidak perlu mendefinisikan metode size .

Saya tidak yakin tentang menangani penyiaran: kecuali kita dapat menemukan kriteria yang masuk akal, saya akan keliru dengan tidak menentukan metode penyiaran.

Diskusi ini tampaknya menyatu ke arah penggunaan transposes dan vektor seperti yang digunakan dalam teknik, yaitu menganggap segala sesuatu sebagai matriks. Pikirkan vektor sebagai kolom dan konvektor sebagai baris. Ini bagus untuk vektor dan peta linier dalam ruang Cartesian (kasus penggunaan tipikal), tetapi mulai gagal jika seseorang mencoba untuk menggeneralisasi ke aljabar multilinear atau ke ruang vektor yang lebih umum dll. Tampaknya ada banyak kebingungan yang berasal dari fakta bahwa untuk ruang kartesius banyak hal yang ekivalen yang tidak setara untuk ruang umum. Saya tidak selalu menentang ini sebagai perilaku default Julia, tetapi saya benar-benar tidak setuju dengan beberapa pernyataan di atas seolah-olah mereka akan "benar secara matematis". Jadi izinkan saya membantah yang di bawah ini.

Pada 20 Okt 2014, pukul 17:39, Simon Byrne [email protected] menulis:

Saya setuju dengan sebagian besar poin @StefanKarpinski , kecuali untuk v '== v bit: Saya tidak berpikir ini harus sama. Ya, mereka mungkin isomorfik tetapi mereka masih merupakan objek yang berbeda, karena mereka berperilaku sangat berbeda: matriks M dan M 'juga isomorfik namun saya tidak berpikir kita akan pernah menginginkan keduanya sama (kecuali mereka Hermitian tentu saja).

Pernyataan ini tidak masuk akal di tingkat mana pun.

1), saya pikir Anda menyalahgunakan arti isomorfik di sini. Isomorfik adalah hubungan antara dua ruang (dalam pengaturan ini). Secara umum, untuk setiap ruang vektor (nyata) V terdapat ruang ganda V * dari fungsi linier (untuk ruang kompleks, ada juga ruang konjugasi dan rangkap ruang konjugasi). Ini biasanya adalah ruang yang berbeda, dan bahkan tidak ada pemetaan unik atau alami dari satu ke yang lain, yaitu secara umum tidak ada arti untuk menghubungkan elemen v dari V ke elemen phi dari V *. Satu-satunya operasi umum adalah menerapkan fungsi linier, yaitu phi (v) adalah skalar.

Pemetaan alami dari V ke V * dapat ditentukan setelah Anda memiliki bentuk bilinear V x V -> skalar, biasanya produk dalam / metrik. Seseorang kemudian dapat mendefinisikan phi_i = g_ {i, j} v ^ j.

2), pada kenyataannya tidak ada operasi alami yang terkait dengan "mentransposisi vektor" (lihat poin 3). Kebingungan ini berasal dari identifikasi vektor dengan matriks kolom.
Menempatkannya mungkin terlalu kuat, saya sebenarnya ingin melihat kasus penggunaan transpos dari vektor yang tidak dapat Anda peroleh menggunakan titik dan mungkin beberapa operasi produk luar / produk tensor?

Namun, jika Anda ingin menggunakan transpos sebagai cara untuk memetakan vektor ke vektor ganda, yaitu untuk memetakan v dalam V ke beberapa phi = v 'di V_, maka Anda mengasumsikan bahwa Anda bekerja dengan hasil kali dalam Euclidean standar (g_ { i, j} = delta_ {i, j}). Pada titik itu, Anda menghapus perbedaan antara indeks kovarian dan kontravarian, Anda pada dasarnya bekerja dengan tensor Cartesian, dan V dan V_ menjadi isomorfik alami. Seperti yang dinyatakan di atas, w_i = v ^ i = v_i = w ^ i, jadi ya, v == w dan saya bahkan akan mengatakan bahwa tidak ada yang membedakan keduanya.

3) Operasi "transpose" awalnya hanya didefinisikan untuk peta linier dari V -> W (http://en.wikipedia.org/wiki/Dual_space#Transpose_of_a_linear_map), dan bahkan di sana itu mungkin tidak berarti apa yang Anda pikirkan. Transpos dari peta linier A: V-> W adalah peta A ^ T dari W _-> V_, yaitu bekerja pada vektor di W_, pada vektor ganda, dan menghasilkan elemen V_, yaitu covectors dari V. Ini berarti, jika Anda memikirkannya dalam istilah transpos yang biasa A ^ T dari matriks A, bahwa matriks A ^ T ini akan dikalikan dengan kolom yang mewakili vektor dalam W * dan bahwa kolom yang keluar dari ini mewakili sebuah covector V Jadi pada titik ini identifikasi vektor ganda dengan vektor baris sudah gagal.

Namun, dalam kasus penggunaan tipikal ruang vektor nyata di mana V * dan W * diidentifikasi dengan V dan W melalui perkalian dalam Euclidean standar, transposisi peta linier dapat diidentifikasi dengan adjoint dari peta linier itu, yang memang peta dari V-> W seperti yang dipikirkan kebanyakan orang juga merupakan kasus untuk transpos peta. Dalam kasus yang kompleks, ini gagal karena transposisi matriks biasa (tanpa konjugasi kompleks) hanya masuk akal sebagai peta W _-> V_, sebagai peta W-> V ini bukan definisi independen dasar dan dengan demikian tidak bermakna secara operasional.

Seperti apa arti transpos untuk larik berdimensi lebih tinggi, dalam pendekatan matlab / teknik yang kita konvergen: seharusnya ada kesalahan, itu tidak digeneralisasikan. Ini tidak berarti bahwa tidak ada cara untuk mendefinisikannya. Masalahnya adalah, apa yang direpresentasikan oleh array orde tinggi. Apakah itu elemen dari ruang perkalian tensor V1 \ otimes V2 \ otimes… \ otimes VN, apakah itu peta multilinear yang bekerja pada V1 x V2 x… x VN, apakah itu peta linier dari beberapa ruang perkalian tensor V1 \ otimes V2 \ otimes … \ Kadang VN ke ruang produk tensor lain W1 \ kadang W2 \ otimes… \ otimes WM? Untuk kasus dua dimensi, ada resolusi. Mengidentifikasi peta linier A: V-> W dengan vektor di W \ otimes V_, transposisi dalam pengertian peta linier sesuai dengan membalikkan ruang dalam ruang hasil kali tensor ini, A ^ i_j -> A_j ^ i dengan A ^ T di V_ \ otimes W = V * \ kadang W _, yang memang merupakan peta dari W_ -> V. Hal yang menyenangkan tentang membalikkan dimensi untuk objek orde tinggi adalah ia memiliki representasi grafis yang nyaman.

Sebagai kesimpulan, saya pikir masalahnya adalah apakah Julia's Vector perlu menangkap properti vektor umum sembarang dalam pengertian matematika, atau apakah itu hanya mewakili kolom angka, daftar, ... Kata vektor, tensor, ... sudah baik -definisi operasional dan makna independen dasar dalam matematika, yang mungkin bertentangan dengan jenis operasi yang ingin Anda definisikan pada Julia Vector. Sebaliknya, beberapa objek sebenarnya adalah vektor dari sudut pandang matematika (vektor ganda, dll.) Yang mungkin tidak dapat diidentifikasi dengan Vektor Julia, karena jenis Vektor Julia (Abstrak) standar tidak memiliki cara untuk membedakan antara ruang vektor yang berbeda.

Dalam hal ini, ada beberapa asimetri, karena istilah Matriks jauh lebih sedikit kelebihan beban, bahkan dari sudut pandang matematis, matriks hanyalah representasi yang mudah dari peta linier dalam basis tertentu. Perhatikan bahwa ada juga banyak kasus di mana Anda tidak ingin merepresentasikan peta linier sebagai Matriks, melainkan sebagai fungsi (masalah ini telah muncul sebelumnya misalnya argumen dari eig dll). Dalam hal ini, saya dapat melihat mengapa matlab bahkan tidak repot-repot memiliki vektor, struktur satu dimensi yang sesungguhnya. Dalam pendekatan ini, semuanya hanya diartikan sebagai 'matriks', yaitu blok dengan angka.

Pertanyaan? Misalkan c menjadi covector. Apa itu fft (c)?

Jawaban: fft (c ')' yang mengambil konjugasi kompleks dengan cara yang tidak terduga
jika dibandingkan dengan fft (c)

pengguna mungkin mendapat manfaat dari itu yang tidak ditentukan
(atau mungkin ini akan baik untuk pengguna, jika didokumentasikan dengan baik ??)

Saya yakin ada lebih banyak hal seperti ini

Saya menduga hal yang benar untuk dilakukan di Base untuk saat ini adalah hanya mendefinisikan:

  • covector kali vektor lain
  • covector kali matriks
  • covector 'untuk mendapatkan vektor

1 untuk dukungan minimal untuk covectors untuk saat ini.

Ya, +1.

Jadi jika saya sebutkan itu, saya cukup yakin
norma (covector, q) harus berupa norma (vektor, p) dimana 1 / p + 1 / q = 1
dari ketidaksetaraan Pemegang, yang tidak akan diterapkan untuk waktu yang lama. :-)

Syukurlah untuk p = q = 2

Itu tidak akan terlalu sulit untuk diterapkan:

norm(c::Covector, q::Integer) = norm(c.vector, q/(1-q))

Anda mungkin ingin beberapa pemeriksaan tambahan untuk menghindari q == 0 dan q == 1 .

Saya pikir q == 1 akan baik-baik saja

Med venlig hilsen

Andreas Noack

22-10-2014 15:19 GMT-04.00 Stefan Karpinski [email protected] :

Itu tidak akan terlalu sulit untuk diterapkan:

norma (c :: Covector, q :: Integer) = norma (c.vector, q / (1-q))

Anda mungkin ingin beberapa pemeriksaan tambahan untuk menghindari q == 0 dan q == 1.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -60139762.

Saya sedang mengerjakan penulisan proposal covector (yang sebagian besar saya dukung), tetapi mungkin berguna untuk memposting sekarang satu hal yang membuat gagasan @StefanKarpinski tepat tentang "matriks baris lucu".

Penutup bukanlah vektor, tetapi penjelasan mengapa tidak selalu jelas. Sebuah covector (atau vektor-bra, sebagaimana fisikawan menyebutnya) adalah fungsi linier yang memakan vektor dan mengeluarkan angka yang merupakan perkalian titik.

Lebih tepatnya:

  • Misalkan V = V(F) dan W = W(F) menjadi vektor di atas beberapa bidang elemen F ,
  • v dan w adalah vektor yang masing-masing merupakan elemen V dan W ,
  • <.,.> menjadi produk dalam seperti <.,.> : V × W → F dan v, w ↦ <v, w>

Covector yang sesuai dengan v adalah fungsional linier v' : W → F yang melakukan pemetaan w ↦ <v, w> .

Deskripsi biasa diakhiri dengan mengatakan bahwa v' adalah elemen ruang ganda V* dengan tidak banyak lagi yang mengatakan tentang apa _is_ spasi ganda.

Untuk ilmu komputer-y orang, ada deskripsi sederhana dari v' sebagai kari produk dalam sehubungan dengan parameter pertama, dan V* sebagai kumpulan fungsi yang merupakan satu parameter kari dengan vektor pertama yang berbeda.

Artikel Wikipedia ini mungkin berguna untuk mendamaikan berbagai notasi yang terkait dengan kedua deskripsi tersebut, tetapi keduanya mengungkapkan konsep yang persis sama.

Juga, awalnya saya berpikir bahwa pengindeksan menjadi covector harus dilarang. Namun, mengindeks v'[1] sama dengan menerapkan v' ke vektor dasar kanonik e₁ = (1, 0, ...) , sehingga v'[1] dapat didefinisikan sebagai <v, e₁> . Semantik pengindeksan yang lebih umum seperti 1:n mengikuti secara alami dari penerapan v' ke matriks proyeksi yang sesuai dengan setiap kolom menjadi vektor basis kanonis.

Mempertimbangkan semantik pengindeksan covectors dalam konteks # 987 memberikan alasan lain mengapa covectors bukan AbstractVector s: tidak mungkin secara umum mengindeks v' murah karena semuanya tergantung pada seberapa mahal kuantitas seperti <v, e₁> adalah untuk menghitung. Secara umum Anda dapat memiliki produk dalam yang ditentukan sehubungan dengan matriks <v, w> = v'*A*w dan biaya pengindeksan didominasi oleh produk matvec A*w (atau A'*v ), yang tentunya terlalu mahal untuk memenuhi syarat sebagai AbstractVector .

Karena kita berbicara tentang DFT dan norma ... ini terlintas dalam pikiran saya hari ini

jika f adalah fungsi dari vektor dan menghasilkan skalar, maka saya ingin diff(f) menjadi fungsi yang menerima Vector dan menghasilkan Covector jadi f(x) ~= f(x0) + diff(f)(x0) * (x-x0) . Penggunaan gradien yang sangat umum adalah untuk mendapatkan perkiraan linier dari perubahan inkremental dalam keluaran fungsi dengan adanya perubahan tambahan pada masukan. Jika input adalah vektor, maka wajar jika gradien menjadi sesuatu yang berkontraksi di sepanjang semua dimensi input.

Tetapi jika saya akan menerapkan penurunan gradien, saya perlu menambahkan (versi skala dari) gradien pada x ke dirinya sendiri. Dalam pengertian ini, gradien adalah vektor yang menunjuk ke arah paling curam, yang normanya sebanding dengan laju perubahan di sepanjang arah paling curam itu.

Naluri saya mengatakan "gradien fungsi input vektor pada suatu titik adalah covector" lebih penting.

Saya menduga hal yang benar untuk dilakukan di Base untuk saat ini adalah hanya menentukan:

covector kali vektor lain
covector kali matriks
covector 'untuk mendapatkan vektor

Terlepas dari kesan yang mungkin Anda dapatkan dari pos mengerikan saya sebelumnya, beri +1 untuk ini.

Namun demikian, beberapa komentar tentang ini:

Saya sedang mengerjakan penulisan proposal covector (yang sebagian besar saya dukung), tetapi mungkin berguna untuk memposting sekarang satu hal yang membuat gagasan @StefanKarpinski tepat tentang "matriks baris lucu".

Penutup bukanlah vektor, tetapi penjelasan mengapa tidak selalu jelas. Sebuah covector (atau vektor-bra, sebagaimana fisikawan menyebutnya) adalah fungsi linier yang memakan vektor dan mengeluarkan angka yang merupakan perkalian titik.

Saya pikir vektor ganda / covectors (saya juga lebih suka istilah fungsional linier) dapat didefinisikan tanpa produk bagian dalam. Hanya saja Anda membutuhkan produk dalam jika Anda ingin mendefinisikan pemetaan dari V ke V *

Lebih tepatnya:

Misalkan V = V (F) dan W = W (F) menjadi vektor pada beberapa bidang elemen F,
v dan w adalah vektor yang masing-masing merupakan elemen V dan W,
<.,.> menjadi produk dalam sehingga <.,.>: V × W → F dan v, w ↦
Cukup aneh, dan saya pikir tidak mungkin, untuk memiliki hasil kali dalam yang ditentukan antara dua ruang vektor yang berbeda V dan W. Bagaimana Anda mendefinisikan sifat kepastian positif?
Kovektor yang sesuai dengan v adalah fungsi linier v ': W → F yang melakukan pemetaan w ↦.

Deskripsi biasa diakhiri dengan mengatakan bahwa v 'adalah elemen dari ruang ganda V * dengan tidak banyak lagi yang dikatakan tentang apa itu ruang ganda.

Saya rasa cukup jelas, tentunya untuk kasus berdimensi-hingga, bahwa ruang ganda, sesuai namanya, adalah ruang vektor. Namun, ringkasan dari kata-kata kasar saya sebelumnya adalah bahwa, jenis Vektor Julia (Abstrak) lebih seperti Daftar. Dapat digunakan untuk merepresentasikan vektor tertentu, dan struktur data satu dimensi lainnya yang tidak memiliki struktur matematis sebuah vektor, tetapi tidak cukup umum untuk menangkap semua objek yang merupakan vektor matematika (karena tidak dapat membedakan antara vektor yang berbeda. spasi).

Mempertimbangkan semantik pengindeksan covectors dalam konteks # 987 memberikan alasan lain mengapa covectors bukanlah Abstrak Vektor: secara umum tidak mungkin untuk mengindeks v 'dengan murah karena semuanya tergantung pada seberapa mahal kuantitas seperti= v'_A_w dan biaya pengindeksan didominasi oleh produk matvec A_w (atau A'_v), yang tentunya terlalu mahal untuk memenuhi syarat sebagai AbstractVector.

Ini semacam argumen pengulangan. Seperti disebutkan di atas, fungsional linier (covector) lebih umum dan ada bahkan untuk ruang vektor tanpa hasil kali bagian dalam. Kedua, jika metrik adalah matriks pasti positif A, pemetaan natural dari vektor v ke covector memang v'_A. Namun, apa ini v 'di sini? Apakah sudah ada pemetaan dari v ke covector yang berbeda yang didefinisikan sehubungan dengan norma Euclidean standar (dengan identitas sebagai metrik)? Tidak, bukan. Jika vektor memiliki indeks kontravarian (atas), dan covectors memiliki indeks kovarian (lebih rendah), maka metrik A memiliki dua indeks lebih rendah dan hasil kali dalam adalah= v ^ i A_ {i, j} v ^ j. Sehingga pemetaan ini dapat ditulis sebagai (dengan phi covector yang terkait dengan vektor v) sebagai phi_j = v ^ i A_ {i, j}. (Catatan, ini berbeda dari operator linier biasa, yang berbentuk w ^ i = O ^ i_j v ^ j). Oleh karena itu, v dalam ekspresi ini v'_A tetaplah satu dengan indeks atas, masih vektor yang sama.

Jadi sebenarnya, salah satu poin yang saya coba buat di atas, adalah bahwa orang sering menulis v 'ketika mereka tidak benar-benar mencoba bekerja dengan seorang covector. Mereka hanya mencoba menulis ekspresi yang ditentukan pada vektor, seperti hasil kali dalamatau sesuatu seperti v ^ i A_ {i, j} w ^ j dalam representasi matriks familiar sebagai v'_A_w. Bahkan produk dalam Euclidean standar v'w harus dibaca sebagai v ^ i delta_ {i, j} w ^ j dan tidak perlu memasukkan konvektor. Seperti disebutkan di atas, menurut saya penggunaan covectors yang tepat sebenarnya yang bukan merupakan bentuk tersembunyi dari produk skalar agak terbatas di sebagian besar aplikasi. Orang hanya menulis v 'agar dapat menggunakan sintaks matriks yang mudah digunakan, tetapi yang sebenarnya mereka lakukan adalah menghitung hasilkali dalam, dll. Yang didefinisikan sehubungan dengan vektor, bukan covectors.

Di samping itu, ada beberapa komentar sebelumnya tentang asosiativitas perkalian jika kita ingin v '== v seperti dalam proposal asli Stefan. Namun, bahkan tanpa ini, saya tidak akan mengatakan bahwa * adalah asosiatif, bahkan jika v 'adalah covector yang tidak teridentifikasi dengan vektor biasa:
A_ (v'_w) adalah matriks
(A_v '] _ w menghasilkan kesalahan

Gradien dari fungsi bernilai skalar memang merupakan salah satu aplikasi covectors yang tepat, yaitu tanpa argumen gradien adalah covector. Apa yang secara implisit diasumsikan dalam aplikasi seperti gradien konjugasi adalah bahwa ada metrik (dan sebenarnya metrik terbalik) untuk memetakan covektor ini kembali menjadi vektor. Jika tidak, tidak ada gunanya melakukan sesuatu seperti x ^ i (vektor posisi) + alpha g_i (gradien). Cara yang tepat untuk menulis ini adalah x ^ i + alpha delta ^ {i, j} g_j di mana delta ^ {i, j} adalah metrik invers. Jika seseorang mencoba untuk menentukan teknik pengoptimalan pada manifold dengan metrik non-trivial, maka seseorang perlu mempertimbangkan metrik (terbalik) ini. Ada buku bagus tentang ini:
http://sites.uclouvain.be/absil/amsbook/
dan paket matlab yang sesuai:
http://www.manopt.org

Pada 22 Okt 2014, pukul 22:52, goretkin [email protected] menulis:

Karena kita berbicara tentang DFT dan norma ... ini terlintas dalam pikiran saya hari ini

jika fis adalah fungsi dari vektor dan menghasilkan skalar, maka saya ingin diff (f) menjadi fungsi yang menerima Vektor dan menghasilkan Covector sehingga f (x) ~ = f (x0) + diff (f) ( x0) * (x-x0). Penggunaan gradien yang sangat umum adalah untuk mendapatkan perkiraan linier dari perubahan inkremental dalam keluaran fungsi dengan adanya perubahan tambahan pada masukan. Jika input berupa vektor, maka wajar jika gradien menjadi covector.

Tetapi jika saya akan menerapkan penurunan gradien, saya perlu menambahkan (versi berskala dari) gradien pada x ke dirinya sendiri. Dalam pengertian ini, gradien adalah vektor yang menunjuk ke arah paling curam, yang normanya sebanding dengan laju perubahan di sepanjang arah paling curam itu.

Perasaan saya mengatakan gradien adalah penyambung lebih penting.

-
Balas email ini secara langsung atau lihat di GitHub.

A_ (v'_w) adalah matriks
(A_v '] _ w menghasilkan kesalahan

Oh sial.

b2e4d59001f67400bbcc46e15be2bbc001f07bfe05c7c60a2f473b8dae6dd78a

Utas ini sudah lewat waktu untuk postingan dengan gambar lucu di dalamnya.

@ Jutho Saya akui bahwa saya tidak menggunakan bentuk ruang ganda yang paling umum, tetapi saya tidak melihat bagaimana deskripsi saya melingkar sama sekali mengingat pilihan saya untuk menentukan ruang ganda menggunakan kerangka ruang Banach. Formalisme ruang Banach sudah berlebihan untuk ruang vektor berdimensi-hingga.

Edaran memang bukan istilah yang tepat. Apa yang saya coba katakan dengan paragraf itu adalah bahwa saya dapat membalik garis penalaran ini mengenai evaluasi entri yang efisien, karena misalnya dalam kasus gradien (konjugasi) pada lipatan melengkung, saya kira gradien (covector) g_i dapat dihitung secara efisien, tetapi vektor terkait A ^ {i, j} g_ {j} yang akan ditambahkan ke x ^ i (dengan A ^ {i, j} metrik terbalik) mungkin tidak efisien. Saya baru saja menyadari betapa buruknya garis besar pesan saya sebelumnya muncul di Github; tidak apa-apa saat saya menulis email. Saya mencoba memperbaikinya sekarang. Saya tidak ingin terus mengulang, saya juga tidak ingin memberikan kesan (salah) seolah-olah saya tidak setuju dengan proposal saat ini. Satu-satunya poin yang saya coba buat.

  1. Ruang ganda tentunya merupakan ruang vektor, oleh karena itu elemen-elemennya adalah vektor. Namun, tujuannya tidak boleh agar semua objek yang memiliki makna matematis dari sebuah vektor menjadi subtipe dari Julia AbstractVector , dan tidak semua objek yang merupakan subtipe AbstractVector memiliki karakteristik matematika yang tepat. dari sebuah vektor. Dalam hal ini, saya lebih menyukai nama Matrix daripada nama Vector , karena memiliki konotasi yang jauh lebih sedikit. Oleh karena itu, saya kira saya setuju dengan fakta bahwa, apapun tipe Covector yang diperkenalkan sebagai bagian dari proposal ini, itu tidak boleh menjadi subtipe dari AbstractVector atau bahkan AbstractArray , bahkan dalam kasus di mana V * secara alami isomorfik ke V (ruang Cartesian, yang mungkin merupakan setengah dari aplikasi).
  2. Produk dalam memungkinkan Anda membuat pemetaan dari V ke V_, tetapi ini bukan prasyarat untuk keberadaan V_. Tentu saja, ini terdengar seperti masalah yang tidak relevan karena dalam pemrograman Anda selalu memiliki ruang vektor berdimensi terbatas dan selalu ada produk dalam (meskipun mungkin bukan yang relevan untuk aplikasi), tetapi poin praktis yang saya coba buat ini. Ada aplikasi covectors yang tepat dalam pemrograman, seperti contoh gradien yang bagus oleh @goretkin , tetapi di sebagian besar aplikasi di mana orang menulis v' , mereka tidak benar-benar mencoba membuat covector, mereka hanya mencoba menulis bilinear pemetaan antara dua vektor (yaitu V x V ke skalar), seperti dalam v'_A_w = v ^ i A_ {i, j} w ^ j atau bahkan v'w = v ^ i delta_ {i, j} w ^ j menggunakan representasi matriks yang nyaman. Saya lebih suka menulis dot(v,A*w) secara eksplisit, tapi itu pilihan pribadi. Karena kita tidak memiliki informasi tentang indeks atas atau bawah pada matriks, kita dapat membuat kasus penggunaan di mana dalam ekspresi skalar seperti v'*A*w baik v' dan w dapat berupa vektor atau covectors dalam arti matematis. Satu-satunya konsekuensi dari ini adalah bahwa saya tidak yakin apakah saya benar-benar senang dengan menyebut tipe v' Covector , seperti halnya nama Vector itu terlalu banyak matematika konotasi yang mungkin tidak dapat dibenarkan di sebagian besar aplikasi, yang kemudian mengarah ke lebih banyak diskusi (kebanyakan tidak relevan) seperti ini.

@jutho +1 untuk gradien menjadi covectors
Saya pertama kali belajar ini dari tesis phd Steve Smith dan telah menggunakan ide ini
untuk menjelaskan dengan jelas gagasan samar-samar tentang gradien konjugasi ini untuk perhitungan nilai eigen
yang biasa dibicarakan orang dalam kimia dan fisika.

Saya semakin terpesona tentang betapa konsistennya secara internal
dan mandiri adalah dunia tensor peringkat 2 dengan satu indeks atas dan satu indeks lebih rendah.
Inilah yang secara konvensional kita sebut sebagai komputasi matriks atau aljabar linier biasa.
Heck, sementara saya bisa menemukan banyak contoh seperti norma (v, p) atau fft (v) di mana fungsi
berbeda jika mereka adalah vektor atau covectors, saya benar-benar belum memiliki satu contoh yang baik (belum!)
dari fungsi yang berbeda secara alami pada vektor dan matriks satu kolom.
(Seseorang tolong aku, pasti ada satu, bahkan banyak !!)

Saya juga selama beberapa tahun sekarang telah prihatin seperti @jutho vektor abstrak
Spaces belum menemukan jalan menuju julia, saya ingat mengobrol dengan @StefanKarpinski
tentang ini di papan tulis saya bertahun-tahun yang lalu. Masih kekhawatiran menyeluruh dari
1) pendatang baru di Julia harus memiliki pengalaman yang mudah dan
2) kinerja
harus mengalahkan barang mewah ini.

Sebagai hasil dari berbicara dengan @jiahao, saya benar-benar
Aljabar Linear (array dengan satu kontra, dan satu co) dan terdapat tensor sederhana
(semua orang adalah rekan, tidak ada contras). Yang terakhir bekerja dengan baik di APL an Mathematica.
Yang pertama adalah seluruh aljabar linier dan ditangkap paling baik di MATLAB sebelumnya
mereka mencangkok pada array dengan dimensi lebih tinggi dari 2. Ada keumuman yang lebih lengkap
yang setelah berbicara dengan @JeffBezanson sepertinya tidak terlalu gila.

ngomong-ngomong, menurut saya butuh waktu sekitar satu tahun jika tidak lebih, tetapi kami akhirnya menganggap ini serius :-)

Mengenai
A_ (v'_w) adalah matriks
(A_v '] _ w menghasilkan kesalahan

Hanya perkalian matriks "*" yang asosiatif. Matriks waktu skalar yang kelebihan beban tidak pernah
asosiatif. Bahkan dalam matematika, bahkan di MATLAB pun tidak.

A_ (v'_w) adalah matriks
(A_v '] _ w menghasilkan kesalahan

Tangkapan yang bagus. Apakah ada kasus dimana non-error menghasilkan jawaban yang berbeda? Sebuah pertanyaan terkait: apa yang harus dilakukan skalar * covector?

Matriks waktu skalar yang kelebihan beban tidak pernah asosiatif. Bahkan dalam matematika, bahkan di MATLAB pun tidak.

Operasi yang hanya melibatkan matriks dan skalar bersifat asosiatif (lihat poin 3). Karena kita dapat memperlakukan vektor sebagai larik 1 kolom, maka memasukkannya juga tidak menimbulkan masalah. Kerutan di sini adalah bahwa Covector adalah operator yang dapat mengurangi dimensi (memetakan vektor ke skalar), jadi saya tidak yakin bagaimana hal itu cocok.

Penambahan skalar-matriks adalah masalah yang lebih besar, karena itu merusak distribusi (meskipun jika saya mengingatnya dengan benar, saya pikir perdebatan itu diselesaikan untuk menyimpannya):

(A+s)*v != A*v + s*v

Ini adalah ringkasan yang sangat bagus:

Sebagai hasil dari berbicara dengan @jiahao, saya benar-benar
Aljabar Linear (array dengan satu kontra, dan satu co) dan terdapat tensor sederhana
(semua orang adalah rekan, tidak ada contras).

Jelas bahwa diskusi ini bukan tentang mendukung kasus yang lebih umum, itu terlalu membingungkan bagi orang-orang yang tidak memerlukan keumuman penuh, tidak dapat dimasukkan dalam hierarki AbstractArray saat ini dan lebih cocok untuk sebuah paket (yang sebenarnya saya kerjakan di). Tapi pembahasannya memang, mana dari dua dunia khusus ini yang ingin kita dukung, karena keduanya tidak cocok satu sama lain.

Dalam contoh sebelumnya, semua vektor v adalah kolom, semua v' adalah covectors dan semua matriks adalah operator linier V-> W (misalnya mereka tinggal di W ⊗ V_) Ini mengecualikan representasi misalnya bilinear memetakan V x V -> skalar (misalnya v ^ i A_ {i, j} w ^ j) karena ini memerlukan matriks dengan dua indeks lebih rendah (misalnya tinggal di V_ ⊗ W_). Tentu saja, Anda masih dapat menggunakannya dalam praktik dan menulisnya sebagai v'_A*w , tetapi ini agak bertentangan dengan nomenklatur objek yang dipilih. Selain itu, ia tidak menentukan di ruang mana array orde tinggi hidup.

Kasus terakhir menyelesaikan masalah itu karena memiliki (V == V *), tetapi mengarah ke hasil yang mengejutkan sebagai v' == v . Selain itu, solusi ini sebenarnya terbatas pada ruang vektor nyata, karena bahkan dalam ruang kompleks dengan hasil kali dalam standar Euclidean (yaitu 'ruang Cartesian kompleks'), ruang rangkap tidak secara alami isomorfik ke V tetapi untuk konj (V) (V bar), ruang vektor konjugasi (lihat spasi Hilbert di http://en.wikipedia.org/wiki/Complex_conjugate_vector_space)

Mengenai non-asosiatif, dalam hal perilaku saat ini, di mana v'*v tidak menghasilkan skalar tetapi sebuah array, sebenarnya lebih konsisten, sejak saat itu A*(v'*v) dan (A*v')*v menghasilkan kesalahan.

Sisi "Aljabar Linear" dari berbagai hal juga dapat diselesaikan menjadi pilihan berbeda tentang bagaimana merepresentasikan vektor dan covektor:

  • The Covector, alias "vektor baris lucu" yang telah kita diskusikan baru-baru ini.
  • Semantik "tidak ada vektor sebenarnya" yang menggabungkan (vektor-N sebagai matriks-Nx1), (vektor-baris-N sebagai matriks-matriks 1xN), yang didukung oleh Matlab dan sejenisnya.
  • Cara Julia saat ini - jangan menggabungkan matriks N dan matriks Nx1 padat, menggabungkan matriks N dan Nx1 renggang, merepresentasikan vektor baris-N sebagai matriks 1xN.

Saya ingin tahu apakah benar-benar perlu untuk menggabungkan (skalar, 1-vektor, dan 1x1-matriks) di dunia "tanpa vektor yang sebenarnya"; @alanedelman dan saya membahas hal ini kemarin dan dalam aljabar linear numerik, komutatifitas vektor * skalar dan skalar * vektor digunakan di mana-mana, namun produk skalar * vektor adalah salah satu yang tidak peduli jika melakukan (N,) * ( ,) atau (N, 1) * (1,1).

1) Pada akhirnya, hal terpenting adalah A) kemudahan penggunaan dan B) kinerja.
2) Kedua dunia harus dapat hidup berdampingan secara harmonis. Saat melakukan pekerjaan teknik, pendapat saya adalah tidak ada yang lebih intuitif dan mudah daripada notasi tensor. Satu saran, jika saya boleh, mungkin untuk mengaktifkan bendera lingkungan atau paket dapat diimpor di awal program. Ini akan memungkinkan kemudahan penggunaan dan logika pemrograman langsung. Bukankah ini mungkin atau haruskah kita memilih satu skema menyeluruh?

Sepertinya ada dua opsi
1) mengaktifkan impor kotak alat, tambalan, atau bendera lingkungan untuk bekerja secara bersamaan
2) membangun bahasa yang mampu mempersatukan dunia-dunia khusus, namun tetap mudah digunakan dan cepat

Saya tidak yakin seberapa menjanjikan hal ini, tetapi saya baru saja menemukan area penelitian yang berpotensi menarik.

Bolehkah saya mengarahkan perhatian Anda ke:

Kelompok penelitian Aljabar Geometris
http://www.mrao.cam.ac.uk/~clifford/pages/introduction.htm

Mata Kuliah Aljabar Geometris
http://www.mrao.cam.ac.uk/~clifford/ptIIIcourse/course99/

Aplikasi Fisik Aljabar Geometris
http://www.mrao.cam.ac.uk/~clifford/ptIIIcourse/

Bahasa matematika terpadu untuk fisika dan teknik di abad ke-21
http://www.mrao.cam.ac.uk/%7Eclifford/publications/ps/dll_millen.pdf

Aljabar Geometris
http://arxiv.org/pdf/1205.5935v1.pdf

Dasar-dasar Perhitungan Aljabar Geometris
http://link.springer.com/book/10.1007%2F978-3-642-31794-1

Perhitungan Aljabar Geometris
http://link.springer.com/book/10.1007%2F978-1-84996-108-0

Setelah melihat ini lebih dalam, tampaknya sangat menakjubkan.

Selama aljabar dan geometri dipisahkan, kemajuannya lambat dan penggunaannya terbatas; tetapi ketika dua ilmu ini telah bersatu, mereka telah meminjamkan kekuatan timbal balik, dan telah berbaris bersama menuju kesempurnaan.

  • Joseph Louis Lagrange

Bayangkan Anda membutuhkan kacamata dan tidak tahu bahwa Anda membutuhkan kacamata. Kemudian, saat Anda mendapatkan kacamata, dunia berubah secara tak terduga. GA itu seperti kacamata untuk bagian dalam otak Anda.

  • Pablo Colapinto

Orang ini sepertinya punya ide yang benar ... https://github.com/wolftype/versor

Library operasi matriks tipikal memiliki kerangka fungsi sebaris untuk perkalian Vektor dan Matriks. Aljabar Geometris menggabungkan banyak matematika lainnya (matriks, tensor, vektor, dan aljabar kebohongan). Versor serupa, tetapi pada steroid, di mana vektor dan matriks renggang dengan berbagai ukuran hanya disebut multivektor dan mewakili elemen geometris di luar arah xyz dan matriks transformasi. Lingkaran, garis, bola, bidang, titik adalah elemen aljabar, seperti operator yang memutar, memutar, melebarkan, dan menekuk variabel tersebut. Kedua elemen dan operator ini adalah multivektor yang berkembang biak bersama dalam banyak cara berbeda.

Video ini membahas beberapa detail bagus tentang Versor, bahasa matematika GA terprogram.
https://www.youtube.com/watch?v=W4p-e-g37tg

Ini adalah slide untuk ini. https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/generic_spaces.pdf

Anda dapat melakukan beberapa komputasi tensor yang menakjubkan, dengan sangat mudah, dioptimalkan untuk kecepatan saat Anda mengompilasi.

@ esd100 , menurut saya akan sangat membantu jika diskusi di utas ini tetap fokus pada masalah spesifik dalam judul.

@johnmyleswhite Saya menelusuri istilah "tensor" dan istilah itu disebutkan 171 kali (sekarang 172 kali). Meskipun saya setuju dengan pernyataan Anda, secara umum, utas ini memiliki 157 komentar (sekarang 158), beberapa di antaranya berhubungan langsung dan tidak langsung dengan judul postingan asli (Menyikapi transposisi vektor dengan serius). Saya pikir posting saya berhubungan secara tidak langsung dengan judul posting asli dengan menawarkan peningkatan perspektif tentang apa yang dapat dilakukan dengan aplikasi baru matematika tensor, melalui aljabar geometris. Pendapat saya adalah bahwa membangun jenis kekuatan berdimensi lebih tinggi yang dimiliki Versor ke dalam Julia akan menjadi fitur bermanfaat tambahan dari Julia. Judul video YouTube tersebut adalah "Pemrograman Generik Ruang Generik: Aljabar Geometris Waktu Kompilasi dengan C ++ 11". Saya tidak mengerti mengapa itu bukan Julia, bukan C ++. Lagi pula, saya bukan ahli matematika atau ilmuwan komputer.

@ esd100 Aljabar geometris menarik, tetapi bukan hal paling umum yang

Dalam pengaturan aljabar tensor, proposal " v' adalah no-op" di OP sangat masuk akal, karena ini menggeneralisasi secara konsisten ke antiautomorfisme pembalikan . Namun, ini hanya satu dari setidaknya tiga proposal di atas meja. Kita juga dapat mempertimbangkan ekstensi bialjabar yang mengarah ke tensor coalgebras di mana usulan "v 'menghasilkan covector" sangat alami. Saya tidak yakin bagaimana proposal "tidak ada vektor yang benar" digeneralisasi menjadi aljabar tensor.

@jiahao Terima kasih atas tanggapan Anda yang sangat informatif. Senang rasanya memiliki seseorang dengan beberapa penguasaan subjek menjelaskan beberapa. Saya akan tertarik untuk melihat lebih banyak topik tersebut untuk mendapatkan pemahaman yang lebih baik. Saya ingin tahu tentang mengapa kode yang sangat dioptimalkan untuk BLAS ada, tetapi kode yang sangat dioptimalkan untuk aljabar yang lebih kompleks, seperti Aljabar Clifford tidak.

Saya tidak yakin apakah diskusi ini masih berlangsung, tetapi saya ingin membagikan pendapat saya karena masalah ini adalah beberapa bagian terpenting (dan menjengkelkan) dari saya menggunakan Julia. Beberapa di atas saya setuju dengan dan beberapa tidak.

Pada dasarnya, saya pikir kita perlu menyadari ini: Semua pengguna Julia akan menginginkan array multidimensi yang cepat (untuk penyimpanan data) seperti yang telah diterapkan di Julia. Banyak / sebagian besar pengguna juga akan tertarik dengan aljabar linier, dan array yang disebutkan di atas adalah cara yang mudah untuk mengemas data yang terdapat dalam vektor dan matriks. Beberapa pengguna mungkin ingin mengerjakan aljabar tensor generik (multilinear).

Pertanyaannya adalah bagaimana memperluas array "telanjang" ini ke konsep matematika aljabar linier? Bagaimana Anda membuat sintaks terlihat seperti matematika biasa? Akankah orang merasa nyaman dengan v ''! = V? Dll, dll.

Hal pertama adalah, kami tidak ingin membuat Array menjadi lebih buruk, agar kami dapat mengerjakan aljabar linier. Kami tidak ingin menambahkan data tambahan ke Vektor atau argumen templat yang tidak perlu ke Array. Kami ingin secepat C / C ++ saat tidak mengerjakan aljabar linier (dan semoga secepat C / fortran, saat kami melakukannya).

Hal kedua yang harus kita sadari adalah bahwa kontraksi tensor multi-dimensi penuh memerlukan sejumlah besar informasi tambahan. Untuk tensor hingga 2 dimensi, tulis perkalian apa pun seperti A_B'_C * D ... sedangkan untuk tensor umum, lebih wajar jika memikirkan grafik untuk menentukan kontraksi (diagram jaringan tensor, atau grafik faktor - hal yang sama berlaku dengan banyak nama berbeda). Untuk tensor berdimensi tinggi, masuk akal untuk membungkus array kosong dan menghiasinya dengan ruang vektor, dll untuk melacak semuanya. Ini dapat dilakukan dalam paket-paket seperti yang Jutho (dan mungkin orang lain) kerjakan. Tidak ada gunanya mempertimbangkan arti 'pada tensor 3+ dimensi - tidak ada yang tertarik menggunakan fungsi itu saat permutedim ada, atau jika mereka menggunakan paket tensor khusus.

Pengguna inti perlu mengalikan matriks, menambahkan vektor, dan sebagainya. Mereka ingin mengubah urutan matriks. Mereka juga akan menginginkan produk dalam dan produk luar. Suka atau tidak, ini didefinisikan sehubungan dengan ruang ganda. Kita tahu ini untuk bilangan real dan bilangan kompleks, dan telah ditentukan sebelumnya. Dan ya, memang benar bahwa ruang ganda dari ruang vektor hingga yang nyata terasa pada dasarnya adalah hal yang sama, dan saya yakin inilah yang mengaburkan keseluruhan masalah. Masalah terbesar saat ini adalah kita tidak memiliki vektor ganda yang tepat. Tanpanya, kita tidak bisa "menulis" persamaan di Julia seperti yang kita lakukan di pena dan kertas - masalah besar! Yang lebih penting, kita tidak memiliki v '' = v. Ini sangat tidak intuitif.

Orang hanya ingin atau perlu membuat vektor ganda untuk melakukan produk dalam atau luar. Pembungkus dekoratif sederhana untuk memberi tahu kompiler apa yang harus dilakukan saat pertemuan berikutnya * adalah solusi yang masuk akal dan harus memiliki overhead waktu proses nol. Saya pikir vektor ganda / covectors ini harus diindeks, dapat ditambahkan / dikurangi, dikalikan dengan skalar, dikalikan dengan vektor (mengembalikan skalar) dan dikalikan dengan matriks (mengembalikan covector) - dan hanya itu! Saya bahkan tidak akan secara eksplisit melakukan konjugasi kompleks untuk vektor kompleks - yang dapat dibangun ke dalam produk titik, produk luar, pengindeksan, dll untuk peningkatan kecepatan / memori.

Saya tidak khawatir kami menambahkan kerumitan ke sistem tipe. Saya percaya ini perlu untuk merangkum matematika seperti yang dipelajari pengguna di sekolah menengah dan universitas: memiliki asosiatif * (jika didefinisikan dengan baik), memiliki v '' = v, memiliki "bra" dan "kets" (I saya menggunakan notasi Dirac dari aljabar linier di sini), dll.

BTW jika hal ini telah diterapkan di Julia 0.4, saya tidak menyadari! Saya masih berusaha memahami 0.3.4 ...

@andyferris , saya biasanya setuju dengan semua ini. Saya pikir proposal saya di M*v' menjadi kesalahan, buatlah itu menghasilkan covector dan bukannya v*M menjadi kesalahan, buatlah itu menghasilkan vektor. Bagi saya, ini secara konseptual berjumlah M menjadi agnostik tentang apakah dimensinya naik atau turun - Anda dapat menulis v'*M*w atau v*M*w' untuk produk dalam dan salah satunya akan berfungsi.

Satu pemikiran yang muncul adalah memiliki array baris-mayor dan kol-mayor dan memiliki M.' hanya berubah dari satu ke yang lain dan juga memiliki v' menjadi variasi baris-mayor pada v - yang memiliki bentuk yang sama tetapi secara konseptual disimpan dalam urutan lain. Tidak yakin tentang ini.

+1 untuk @andyferris . Saya juga berpikir kita hanya ingin tipe pembungkus sederhana Transpose dan ConjTranspose yang memungkinkan kita menggunakan sintaksis aljabar matriks ringkas untuk menulis produk vektor, matriks, dan transposesnya. Sehubungan dengan poin 2 dari proposal @StefanKarpinski , saya tidak akan membatasi pembungkus ini menjadi wadah dari objek AbstractArray dan saya tidak akan menjadikan tipe bagian dari hierarki tipe AbstractArray itu sendiri. Transpose(x) seharusnya hanya jenis yang dihasilkan dari penulisan x' dalam sebuah ekspresi dan memungkinkan untuk menunda evaluasinya / memiliki evaluasi malas, tergantung pada ekspresi lainnya, dengan mengirimkan Transpose untuk sisa operasi dalam ekspresi (yang mungkin akan menjadi operator perkalian * dalam 99.9% kasus). Namun, orang juga harus dapat memberikan sintaks ini arti untuk tipe baru yang mungkin bukan bagian dari hierarki AbstractArray , seperti objek faktorisasi matriks atau tipe lain untuk mendefinisikan misalnya operator linier.

Untuk kasus khusus matriks dan vektor, saya tidak benar-benar melihat kasus penggunaan untuk M*v' , tetapi saya tidak menentangnya secara intrinsik. Yang penting adalah memenuhi harapan dasar (yaitu aturan 2,4,5,6 dan 8 dari akhir proposal Stefan).

Poin terakhir utama dari diskusi mungkin adalah interaksi dengan pemotongan. Haruskah potongan baris dari sebuah matriks secara otomatis menjadi Transpose ? Pilihan saya di sini adalah pada aturan pemotongan APL di mana tidak demikian.

@Jutho , motivasinya adalah membuat * asosiatif - A*(v'w) dan (A*v')*w keduanya bekerja dan menghasilkan hasil yang sama, modulo non-asosiatif dari jenis elemen yang mendasarinya (mis. Floating- titik).

Agar (A*v')*w memberikan hasil yang sama seperti A*(v'*w) , A*v' harus berupa array N=3 . Itukah yang kamu pikirkan? Saya sangat merindukan ini.

Oke, sangat menarik, saya punya beberapa komentar.

Pertama kita perlu membahas pengguna inti. Pada dasarnya, pertama-dan-terpenting menggunakan Array{T,n} sebagai n -dimensi penyimpanan adalah fungsi utamanya. Ini harus masuk akal bagi programmer yang tidak tahu tentang aljabar linier tetapi ingin memanipulasi data di Julia. Karena itu, dalam keadaan apa pun irisan array tidak dapat mengembalikan vektor bersama! Ini adalah konsep aljabar linier ketat yang hanya berlaku untuk tipe data tertentu T yang dapat menentukan ruang vektor dan gandanya (misalnya data numerik atau "bidang").

Saya bisa memilih cara baik dengan mengiris APL. Sepertinya cukup intuitif. Ini adalah tipe stabil dan tidak melakukan sesuatu yang mengejutkan. Meskipun menurut saya tidak perlu membuat perubahan ini untuk membuat aljabar linier konsisten ... itu mungkin bagus (meskipun ini mungkin perubahan yang menghancurkan). Saya merasa tidak nyaman bahwa M[1,:] adalah ukuran 1xn dan M[:,1] adalah ukuran n (bukan nx1) ... sepertinya terlalu asimetris ... tapi saya rasa ini adalah pengingat yang baik tentang bagaimana keadaannya diletakkan dalam memori. Bagaimanapun .. perubahan ini hanya dapat dilakukan jika masuk akal untuk penyimpanan dan manipulasi data abstrak. Bagi saya, perubahan ini ortogonal terhadap pembahasan aljabar linier.

Jadi, bahkan jika kita tidak menerapkan aturan pemotongan APL, kita masih dapat menyelamatkan aljabar linier yang bermakna dengan lugas. Jika Anda menginginkan vektor kolom i th M call colvec(M,i) dan jika Anda ingin vektor co baris i th dari M call rowvec(M,i) . Jika i adalah tupel atau vektor, ia bisa mengembalikan tupel atau vektor atau (co) vektor (dapatkah ini berguna untuk penalaran tentang paralelisasi dalam beberapa kasus?). Jika Anda lebih suka matriks, cukup gunakan notasi pengindeksan normal. Jika kita menggunakan aturan pemotongan APL, hal yang sama sangat berguna untuk membedakan aksi irisan baris dan kolom dengan simbol * . (Kita perlu mempertimbangkan bagaimana konjugasi kompleks berperilaku dengan rowvec ).

Dengan begitu, jika Anda mengerjakan aljabar linier, semuanya akan masuk akal dan pengguna tidak perlu khawatir tentang aturan pemotongan yang diterapkan Julia. Operator ' hanya akan bekerja pada vektor dan covectors (untuk mengubah dekorasi) dan pada matriks (baik secara langsung atau malas). Mungkin lebih mudah mengingat cara mengekstrak vektor basis dari dekomposisi eigend, yang sepertinya selalu saya lupakan.

Untuk * , saya pikir matriks / vektor aljabar di Julia harus bekerja sehingga terlihat dan terasa seperti matematika sebagai operator perkalian dan tidak pernah menyukai operator perkalian M*v' , karena dalam matematika Anda hanya perlu menulis persamaan dengan simbol "\ otimes" (tanda waktu di dalam lingkaran) bukan simbol perkalian standar. Menggunakan simbol perkalian artinya tidak jelas! Kita tidak dapat memiliki w*M*v' == v'*M*w karena perkalian matriks tidak bersifat komutatif. Sekali lagi untuk M*v'*v tidak masuk akal untuk membicarakan tentang keterkaitan * . Anda dapat menafsirkan ini sebagai innerproduct(outerproduct(M,v'),v) yang membutuhkan dua simbol perkalian yang berbeda, atau sebagai perkalian skalar M * innerproduct(v',v) mana _does_ menggunakan * untuk keduanya. Dengan ungkapan ini kita mungkin memerlukan tanda kurung, atau mungkin kompilator dapat mencari urutan operasi yang berarti (perhatikan di sini bahwa urutan evaluasi tercepat juga merupakan satu-satunya urutan evaluasi yang valid).

Dengan vektor, covectors, dan matriks, kita dapat memiliki sistem aljabar yang konsisten dengan matematika standar. Setiap kali Anda ingin melakukan hasil kali luar antara dua vektor, atau dua covektor, atau dua matriks, Anda secara inheren berpindah ke aljabar multi-linier, atau aljabar tensor generik. Di sini Anda mungkin memiliki matriks dan vektor yang dikalikan seperti kron(M,N) menggunakan simbol baru. Atau Anda dapat meminta pengguna untuk menggunakan paket aljabar multi-linier lengkap. Atau apa pun ... sepertinya di luar cakupan pertanyaan awal (yang 14 bulan lalu, btw ...)

Jadi untuk meringkas, saya melihat empat hal yang hampir sepenuhnya berbeda terjadi di sini:

  1. Tingkatkan pemotongan Array s data arbitrer menggunakan aturan pemotongan APL.
  2. Jadikan aljabar linier di Julia lebih intuitif dan sepenuhnya konsisten dengan matematika dengan menambahkan beberapa konsep sederhana: covectors dan metode penggalian vektor dan covectors dari matriks, dan operasi antara covectors, matriks, dll. Banyak pengguna bahkan mungkin tidak memperhatikan covectors ada, karena menggunakan matriks 1xn dan nx1 akan terus berfungsi seperti yang diharapkan, dan vektor akan berperilaku sama.
  3. Untuk kecepatan, implementasikan evaluasi malas untuk transpose , conj , dll dengan menggunakan tipe pembungkusan seperti covector, tetapi juga untuk matriks.
  4. Kembangkan paket tensor tujuan umum dan mungkin tambahkan ke pustaka standar.

Mungkin hanya yang pertama akan menjadi perubahan besar? Yang lain meningkatkan atau menambah fungsionalitas saat ini. Mereka semua dapat diimplementasikan secara lebih-atau-kurang secara independen, dan mungkin semuanya adalah hal-hal yang bermanfaat untuk dilakukan. (PS jika Anda ingin mengiris APL, saya sarankan melakukannya segera , sebelum Julia menjadi terlalu "besar" dan merusak terlalu banyak paket, dll).

Ya, maaf, saran saya untuk mengizinkan M*v' tidak benar-benar masuk akal karena cara yang berbeda untuk mengaitkan produk menghasilkan bentuk yang sangat berbeda. Jadi, saya pikir jika kita akan mengubah ini, proposal asli saya adalah jalan yang harus ditempuh. Sejauh ini tampaknya kombinasi terbaik dengan perilaku pemotongan APL. Tentu saja, apakah kita ingin perilaku pemotongan APL atau tidak adalah pertimbangan yang lebih tinggi.

Saya hanya ingin mengatakan beberapa hal dan tolong anggap mereka dengan sebutir garam. Mereka hanya opini dan saya tahu opini saya tidak terlalu berpengaruh. Namun, ada satu hal yang mengejutkan saya ketika saya membaca komentar @andyferris . Saya rasa saya tidak setuju dengan komentar yang harus masuk akal bagi programmer yang tidak tahu tentang aljabar linier tetapi ingin memanipulasi data di Julia. Saya tidak berpikir programmer adalah audiens yang harus ditulis untuk program matematika. Jika seorang programmer ingin memanipulasi data, ada banyak bahasa yang memungkinkan mereka melakukan itu. Julia adalah bahasa untuk komputasi dan harus memungkinkan komputasi teknis yang canggih.

@ esd100 Benar, saya memang memikirkan itu. Tapi dengan Julia, saya pikir kami ingin menjadi _greedy _... ingin memenuhi banyak tujuan, dan unggul dalam banyak hal. Mungkin ada alasan ilmiah asli untuk memanipulasi data non-numerik. Mungkin ada ilmuwan saat ini atau mantan pengguna Julia yang ingin melakukan pemrograman yang lebih umum. Poin saya sebelumnya adalah bahwa kita tidak boleh membuat Array lebih lambat atau mengambil lebih banyak memori dengan memberinya bidang tambahan untuk membicarakan transpos / konjugasi.

Jika seseorang melakukan pemotongan APL, maka irisan baris atau kolom harus mengembalikan objek yang sama. Pertanyaannya adalah: tanpa pemotongan APL, apa hal terbaik untuk mengembalikan M[1,:] ? Nah, jika M[1,:,:,:,:] mengembalikan Array{T,n} , saya rasa akan membingungkan semua orang jika M[1,:] mengembalikan covector{T} . Bagaimana jika kita membiarkan M = zeros(3,3,3) dan memanggil M[1,:] , yang saat ini mengembalikan matriks 1x9? Haruskah kita menjadikan ini covector juga? Bagaimana jika M adalah Array{String,3} ?

Bagi saya ini akan tampak cukup mengejutkan dan membingungkan. Ini juga tidak konsisten dengan perubahan pemotongan APL, jika itu terjadi di masa depan. Jadi, saya menyarankan untuk menambahkan fungsi baru untuk tujuan aljabar linier, rowvec(M,i) dan colvec(M,i) . Ini tidak ideal, ini menambahkan fungsi baru ... tetapi setidaknya jelas apa yang harus dikembalikan untuk tujuan aljabar linier. Itu adalah satu-satunya hal yang dapat saya pikirkan yang memiliki properti bagus untuk array generik dan properti bagus untuk aljabar linier (bersama dengan tipe covector), sementara tidak mencoba memenuhi aljabar multi-linier. Jika ada yang memiliki notasi yang lebih bagus untuk mengekstraksi covectors dari matriks, itu akan bagus juga!

@ esd100 : Saya cukup yakin bahwa programmer adalah audiens yang dirancang untuk Julia. Komputasi ilmiah adalah kekuatan Julias tetapi ada banyak pengguna Julia yang menggunakannya hanya sebagai bahasa pemrograman tujuan umum.

Saya setuju dengan @andyferris bahwa seseorang harus memisahkan persyaratan tensor dari persyaratan container.

Tanpa membaca seluruh utas masalah pribadi saya adalah jika saya memiliki larik 3D A (mis. Data tomografi) dan melakukan

imagesc( data[1,:,:] )

ini tidak bekerja. IMHO data[1,:,:] , data[:,1,:] , dan data[:,:,1] harus berupa array 2D (atau subarray). Saat ini saya menggunakan fungsi squeeze ditentukan sendiri untuk mengatasi masalah ini.

Sekali lagi, ini hanya pendapat saya dan yang sangat tidak penting, mengingat saya jauh dari tindakan. Saya merasa ketika sebuah aplikasi dikembangkan harus memiliki seperangkat prinsip desain yang memandunya. Pembangun harus mengirimkan pesan yang jelas dan terpadu tentang tujuan dan identitasnya. Jika mengembangkan platform komputasi teknis yang cepat, intuitif, canggih, adalah tujuannya dan itulah kekuatan Julia, maka pertahankanlah. Jangan mengirimkan sinyal campuran dengan mencoba membuatnya sesuai dengan tujuannya untuk audiens programmer umum.

Intinya adalah bahwa bahkan untuk aplikasi ilmiah atau matematika murni, ada beberapa interpretasi yang saling bertentangan, misalnya ada beberapa objek matematika yang dapat Anda wakili dengan menggunakan vektor dan matriks, dan karenanya seseorang tidak boleh membuat pilihan yang terlalu spesifik.

Lebih baik memiliki paket khusus untuk memenuhi kebutuhan disiplin ilmu tertentu mengikuti serangkaian konvensi tertentu.

@jutho Perasaan saya adalah Anda benar, tetapi saya ingin tahu apa dasar kesimpulan Anda bahwa paket-paket itu "lebih baik" dan dibandingkan dengan alternatif apa?

Ini sangat sederhana. Fungsionalitas yang penting bagi sebagian besar pengguna Julia termasuk dalam Base. Fungsionalitas yang lebih istimewa menjadi milik sebuah paket.

Tentu tidak mudah untuk membuat garis di sini. Tetapi cara terbaik untuk memasukkan sesuatu ke dalam basis adalah dengan membuat sebuah paket sehingga banyak orang dapat mengujinya. Berbagai fungsi inti yang telah hadir di Base pertama kali dikembangkan dalam sebuah paket.

@ esd100 , saya tidak sepenuhnya memahami pertanyaan Anda. Pada akhirnya, yang harus disediakan oleh bahasa ilmiah adalah struktur data dan metode untuk merepresentasikan dan menghitung dengan objek khas yang digunakan dalam sains. Tetapi struktur data tertentu mungkin berguna untuk merepresentasikan struktur matematika yang berbeda, dan terkadang representasi yang berbeda mungkin cocok untuk objek dengan tipe yang sama. Oleh karena itu, mengaitkan struktur matematika tetap ke tipe data mungkin terlalu membatasi untuk beberapa disiplin ilmu, dan terlalu rumit untuk disiplin ilmu lainnya. Jadi ini tidak boleh dilakukan di basis Julia, tetapi dengan paket khusus yang hanya mencoba melayani kebutuhan satu disiplin.

Sehubungan dengan diskusi saat ini, setiap orang yang bekerja dengan vektor dan matriks akan mengharapkan kemungkinan untuk mengubah urutan vektor, dan memiliki v ^ T * w = skalar. Tetapi vektor dan matriks ini dapat digunakan untuk mewakili sejumlah hal yang berbeda, dan ini mungkin akan bergantung pada bidang / disiplin ilmu. Saya memberikan contoh di mana v ^ T mungkin bukan covector sebenarnya dalam posting di atas.

Pada 11 Jan 2015, pukul 18:10, esd100 [email protected] menulis:

@jutho https://github.com/jutho Perasaan saya adalah bahwa Anda benar, tetapi saya ingin tahu apa dasar kesimpulan Anda bahwa paket-paket itu "lebih baik" dan dibandingkan dengan alternatif apa?

-
Balas email ini secara langsung atau lihat di GitHub https://github.com/JuliaLang/julia/issues/4774#issuecomment -69501771.

Ini sangat sederhana. Fungsionalitas yang penting bagi sebagian besar pengguna Julia termasuk dalam Base. Fungsionalitas yang lebih istimewa menjadi milik sebuah paket.

Saya tidak berpikir itu sesederhana itu. Misalnya, ada fungsi Bessel di Base, dan kemungkinan besar fungsi tersebut tidak penting bagi sebagian besar pengguna Julia. Alasan mereka dapat berada di Base adalah karena ada satu standar yang cukup universal untuk fungsi Bessel, dan tidak ada yang mungkin menggunakan nama itu untuk hal lain, atau mengharapkan mereka melakukan sesuatu yang berbeda.

Melalui konvensi penamaan yang cermat (beberapa mungkin mengatakan verbose), Mathematica dapat menempatkan lebih dari 4000 fungsi dalam bahasa inti, dan saya merasa sangat nyaman untuk hampir tidak pernah harus memuat paket. Sebaliknya, saat saya menggunakan Python / Sage, bukan hal yang aneh jika satu file / notebook secara eksplisit mengimpor 200 fungsi di atas (menghindari sintaks "from ___ import *" yang tidak dapat dilacak). Setiap kali saya perlu menggunakan fungsi yang bukan bawaan, saya harus melalui banyak langkah tambahan:

(1) Coba ingat apakah saya sudah menggunakannya di file itu, dan / atau lakukan penelusuran teks untuk mengonfirmasi (membatasi ke seluruh kata jika namanya merupakan substring dari sesuatu yang lain)
(2) Salah satu: (a) menambahkan impor segera, kehilangan alur pemikiran saya dan menemukannya lagi; atau (b) mencoba mengingat untuk menambahkan impor setelah saya melakukan apa pun yang saya lakukan, menyimpan hal lain dalam memori
(3) Untuk fungsi yang kurang umum, mungkin harus mencari di paket mana

Ini bisa mengganggu dan melemahkan. Jadi saya pikir, seperti fungsi Bessel, apa pun yang dianggap standar --- dan karenanya tidak akan menyebabkan konflik nama atau kebingungan --- harus ada di Base, terlepas dari apakah banyak orang menggunakannya. Aljabar tentu saja linier.


Kembali ke topik, kita telah berbicara tentang beberapa lapisan fungsionalitas --- beralih dari array sebagai wadah kosong semantik (seperti yang diterapkan dalam Base.AbstractArray ), ke objek tensor Cartesian dengan semantik naik / turun (seperti yang dijelaskan oleh my AbstractTensorArray proposal , ke objek tensor yang lebih umum dengan indeks yang dipetakan ke ruang vektor (seperti di TensorToolbox @Jutho ) --- untuk meningkatkan keumuman dan mengurangi potensi pengoptimalan.

Saya pikir penting bagi pengguna untuk dapat beralih dengan mudah di antara lapisan-lapisan ini, paling tidak karena pengguna _mungkin tidak tahu_ tingkat keumuman apa yang sebenarnya mereka butuhkan ketika mereka memulai. Sebagai contoh sederhana, @Jutho menunjukkan bahwa dalam contoh pemrosesan gambar @jdbates , pengguna mungkin sangat ingin mengaitkan subset indeks yang berbeda ke geometri yang berbeda, untuk memproses koordinat gambar dengan satu cara dan ruang warna dengan cara lain; tetapi jika mereka mulai menggunakan hanya salah satu dari geometri ini, akan lebih mudah untuk beralih ke representasi yang lebih umum yang memungkinkan penggunaan masing-masing dengan geometrinya sendiri. Jika fungsi tambahan (atau pola pemanggilan fungsi) yang bekerja di setiap tingkat umum menggunakan default yang masuk akal --- misalnya, menaikkan / menurunkan indeks dan indeks netral dalam AbstractTensorArray s ke ruang vektor Cartesian default tunggal dan ruang "urutan", masing-masing --- kemudian menjadi hampir mulus. Pengguna dengan fungsionalitas lapisan bawah tidak perlu mengetahui atau peduli dengan lapisan yang lebih tinggi, sampai mereka membutuhkannya.

Setiap bagian dari ini yang jelas dan dapat diprediksi --- bagi pengguna yang relevan --- apa hierarki yang seharusnya, bisa masuk ke dalam Base. Pertanyaan sebenarnya haruslah --- apakah untuk operasi array, aljabar linier, atau aljabar tensor --- seberapa besar kemungkinan pengguna jenis fungsi ini mengharapkan atau menginginkannya dengan cara yang berbeda?

Banyak orang tidak menyukai perincian konyol tentang berapa banyak impor yang Anda butuhkan untuk menyelesaikan sesuatu di Python-land, saya rasa tidak ada orang yang mengusulkan untuk melakukan sejauh itu.

Tetapi ada argumen penting bahwa sejumlah besar dependensi dan library bloat tidak diinginkan untuk beberapa kasus penggunaan, bahasa Julia seharusnya tidak memerlukan library runtime Fortran yang diinstal di komputer Anda, tetapi saat ini library standar Julia melakukannya, baik atau tidak. kode yang ingin Anda jalankan adalah melakukan aljabar linier (atau fungsi Bessel, atau FFT, dll). Ini semua tercakup dengan baik oleh # 5155 dan masalah lainnya - "diinstal secara default" dan "minimum yang diperlukan untuk fungsionalitas apa pun" pada akhirnya harus dipisahkan menjadi kumpulan modul yang berbeda.

Terima kasih Tony, saya setuju. Lebih lanjut, dengan sistem paket kami, tidak ada masalah untuk memiliki "kotak alat" seperti paket yang mengelompokkan beberapa paket. Dengan makro @reexport ini bekerja dengan baik.

Tapi ada poin lain. Dalam sebuah paket, jauh lebih mudah untuk mendorong sebuah ide ke depan. Jika seseorang ingin mengubah sesuatu, dia cukup melakukannya. Dalam Basis satu jauh lebih terbatas.

Tampaknya sementara memiliki tambalan paket memang memungkinkan untuk kemandirian yang lebih besar, itu juga menciptakan platform terfragmentasi yang lebih sulit dinavigasi. Tampaknya menggunakan struktur yang lebih terpadu dan umum akan merampingkan dan memfasilitasi interaksi lintas disiplin dan eksplorasi domain baru.

Apa cara yang saat ini paling idiomatis untuk melakukan matriks vektor *?
Misalnya saya punya X dengan bentuk (K, N) dan b dengan bentuk (K,) , dan saya ingin mengalikan dengan b pada kiri untuk mendapatkan vektor dengan panjang (N,) .
Apakah saya menyebut BLAS.gemv('T',1.0,X,b)
Atau reshape(b'*X,size(x,2))
Keduanya agak jelek.

Saya kira Anda bisa melakukan X'b

13-03-2015 17:15 GMT-04.00 joschu [email protected] :

Apa cara yang saat ini paling idiomatis untuk melakukan matriks vektor *?
Misalnya katakanlah saya punya X dengan bentuk (K, N) dan b dengan bentuk (K,), dan saya mau
mengalikan dengan b di sebelah kiri untuk mendapatkan vektor panjang (N,).
Apakah saya memanggil BLAS.gemv ('T', 1.0, X, b)
Atau bentuk kembali (b '* X, ukuran (x, 2))
Keduanya agak jelek.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -79405868.

Ya, saya pikir itu akan memicu salinan X.
Tapi @time tampaknya menunjukkan bahwa tidak ada salinan, berdasarkan alokasi memori

julia> X = rand(1000,1000); y = rand(1000);

julia> <strong i="8">@time</strong> y'X;
elapsed time: 0.00177384 seconds (15 kB allocated)

julia> <strong i="9">@time</strong> X'y;
elapsed time: 0.000528808 seconds (7 kB allocated)

Kami melakukan parsing mewah 'jadi X'y berakhir sebagai Ac_mul_B(X,y) dan membuat
panggilan BLAS yang sama dengan yang Anda sarankan.

13-03-2015 17:28 GMT-04.00 joschu [email protected] :

Ya, meskipun saya pikir itu akan memicu salinan X.
(Tapi @time https://github.com/time tampaknya menunjukkan bahwa tidak ada
menyalin, berdasarkan alokasi memori

Julia> X = rand (1000,1000); y = rand (1000);

julia> @time y'X;
waktu berlalu: 0,00177384 detik (dialokasikan 15 kB)

julia> @time X'y;
waktu berlalu: 0,000528808 detik (dialokasikan 7 kB)

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -79421713.

Percaya atau tidak, tulisan dari seluruh utas ini semakin dekat untuk terwujud.

Satu poin terakhir: apakah ada yang mempertimbangkan itu. ' bisa jadi hewan yang sama sekali berbeda dari '? Yang terakhir memiliki struktur yang tepat untuk menjadi ganda, tetapi. ' tidak jika bidang yang mendasari bukan bilangan real. Apakah gila untuk menugaskan. ' gagasan "membalikkan semua indeks" dari transpos dan menyimpan semua gagasan dualitas menjadi ', yang menghasilkan "vektor baris lucu" / konjugat Hermitian?

Saya pikir bagaimanapun conj(transpose(x)) harus sama dengan ctranspose(x) .

Seperti yang dijelaskan di atas, saya berharap bahwa bukan jenis pembungkus yang akan dibuat oleh transpose dan ctranspose akan diberi nama yang berisi konsep matematika tertentu seperti dual . Bahasa ilmiah seperti Julia harus menyediakan satu set struktur data yang berguna dan harus menerapkan operasi umum, tetapi saya pikir akan menjadi kesalahan untuk mengaitkan struktur matematika yang ketat dengannya, karena ini tidak akan sesuai untuk beberapa aplikasi dan terlalu rumit untuk orang lain. Terserah pengguna untuk menggunakan struktur data dan operasi ini untuk mengimplementasikan operasi matematika dalam aplikasinya. Tentu ada aplikasi untuk z.' * A * z mengembalikan skalar di mana z adalah vektor kompleks dan A beberapa matriks, meskipun ini tidak ada hubungannya dengan produk dalam dan / atau ganda vektor.

@jutho dapatkah Anda memberikan kasus penggunaan untuk z.' * A * z ?

Jika z1 dan z2 adalah representasi dari dua vektor kompleks Z1 dan Z2 (misalnya vektor tangen di bagian holomorfik dari ruang singgung lipatan Kähler ) dan a adalah representasi matriks dari tensor A dengan dua indeks kovarian (misalnya bentuk kompleks (2,0) dari manifold Kähler) lalu A(Z1,Z2) = z.' * a * z .

Perhatikan bahwa saya tekankan di sini bahwa objek julia z1 , z2 dan a hanya membentuk _representation _ objek matematika tertentu (sehubungan dengan dasar / koordinasi yang dipilih) dan oleh karena itu operasi pada struktur data tidak dapat secara unik dikaitkan dengan operasi matematika tanpa mengetahui apa yang diwakili oleh struktur data ini.

@jutho terima kasih. Poin Anda tentang representasi diambil dengan baik, dan telah diwakili berkali-kali dalam diskusi ini. Saya mencoba untuk menemukan antarmuka minimal vektor dan matriks, dan melihat apakah antarmuka minimal itu secara fundamental tidak kompatibel dengan antarmuka minimal array, dan apa yang dapat kita lepas ke tipe data abstrak yang ditentukan pengguna.

Pada titik ini saya benar-benar mendukung proposal @StefanKarpinski , yang juga sebagian besar digaungkan oleh @andyferris di atas. Khususnya

  1. Pengindeksan gaya APL
  2. v 'memberikan semacam jenis Covector atau Transpose

Yang lainnya adalah detail. Mungkin menyenangkan untuk menambahkan fungsi row(M,i) dan col(M,i) . Jika tidak, untuk mengekstrak baris sebagai covector, saya kira Anda akan membutuhkan M[i,:].' ? IIUC, M[i,:]' akan melakukan conj tidak diinginkan dalam kasus ini?

Ya, saya harus menambahkan bahwa saya tidak sepenuhnya menghargai kebaikan pengindeksan gaya APL terakhir kali saya menulis tetapi sekarang saya mendukung penuh untuk membuat perubahan itu. Ini pada gilirannya membuat hal-hal vektor ganda menjadi lebih menarik, dan fungsi row / col .

Sejak itu saya mencoba bermain-main dengan implementasi dan satu-satunya hal yang paling membingungkan adalah apakah covector yang diekstrak dari matriks terkonjugasi atau tidak…

Saya pikir Anda ingin mengambil nilai literal dari matriks. Menggunakan notasi Dirac, perluas (ada) matriks M = sum_i | i>misal [0,0,1, ..., 0], kita ingin mengekstrakU kita mendapatkan row(U,i)' = col(U’,i) yang sangat masuk akal untuk mengekstraksi vektor eigen kiri dan kanan dari dekomposisi eigend.

Andy

Pada 15 Mar 2015, pukul 21:36, Jeff Bezanson [email protected] menulis:

Pada titik ini saya sepenuhnya mendukung proposal @StefanKarpinski https://github.com/StefanKarpinski , juga sebagian besar digaungkan oleh @andyferris https://github.com/andyferris di atas. Khususnya

Pengindeksan gaya APL
v 'memberikan semacam jenis Covector atau Transpose
Yang lainnya adalah detail. Mungkin bagus untuk menambahkan fungsi baris (M, i) dan col (M, i). Jika tidak, untuk mengekstrak baris sebagai covector saya rasa Anda akan membutuhkan M [i ,:]. ' ? IIUC, M [i ,:] 'akan melakukan conj yang tidak diinginkan dalam kasus ini?

-
Balas email ini secara langsung atau lihat di GitHub https://github.com/JuliaLang/julia/issues/4774#issuecomment -81228816.

Ada sukarelawan untuk mulai mengerjakan ini? misalnya @mbauman , @jakebolewski yang saya terkejut melihat belum ada di utas ini :)

Menemukan segala sesuatu yang perlu diubah mungkin membosankan, tetapi perubahan dasar pada perilaku pengindeksan seharusnya tidak terlalu buruk. Mungkin @jiahao dan @andreasnoack bisa mengatakan lebih lanjut tentang bagaimana Covectors harus dimasukkan, misalnya apa supertype mereka harus jika sesuatu.

Kami membutuhkan 9, tidak ada 8 komentar lagi sebelum kami dapat melanjutkan ini.

Saya dapat membantu dengan itu.

kami cukup dekat

Sebagai komentar yang relevan, jika akan ada tipe pembungkus Transpose dan CTranspose , haruskah mereka juga berupa tipe pembungkus Conjugate , sehingga conj(A) adalah juga malas. Untuk mengalikan matriks dengan BLAS, ini tidak terlalu berguna karena tidak ada dukungan khusus untuk itu (dan C dalam BLAS berarti konjugasi pertapa), tetapi jika ada implementasi Julia BLAS lengkap, akan sangat bagus juga untuk mendukung conj(A)*B tanpa konjugasi eksplisit.

Saya, untuk satu, merasa seperti sekarang saya mengambil alih vektor jauh lebih serius daripada yang saya lakukan sebelumnya.

Mungkin @andreasnoack dan @simonbyrne dapat memberitahu kami jika # 6837 harus ditinjau kembali.

Saya setuju dengan @simonbyrne bahwa kita tidak boleh memiliki Transpose{Array} <: AbstractArray .

Pikiran umum lainnya:

  • Saya menyadari bahwa perhitungan hasil luar saat ini berisi pengecualian untuk aturan "jangan secara otomatis menambahkan dimensi tunggal yang tertinggal". Jika u berukuran (n,) , u * u' adalah perhitungan yang melibatkan (n,) x (1, n) . Produk ini tidak dapat dihitung menggunakan aturan umum perkalian matriks _kecuali_ kami secara otomatis membentuk ulang argumen pertama menjadi (n, 1) .
  • Aturan "secara otomatis menambahkan dimensi tunggal tambahan" dari semantik pengindeksan MATLAB pada dasarnya tidak kompatibel dengan aturan "transpose membalikkan semua dimensi". Dengan aturan sebelumnya, array bentuk (n,) secara semantik identik dengan array yang dibentuk ulang dari bentuk (n,1) dan bentuk (n,1,1) , dll. Namun perlu diperhatikan bahwa jika transpos membalikkan semua dimensi, maka array yang dihasilkan memiliki bentuk (n,) , (1, n) , dan (1,1,n) , yang _cannot_ setara jika Anda hanya diizinkan untuk menambahkan lajang tertinggal. Mengambil ini ke logika ekstrim, transpos dari sebuah array dapat memiliki jumlah tunggal _leading_ yang sewenang-wenang dan oleh karena itu memiliki bentuk ambigu, yang secara logis tidak konsisten.

Saya juga melakukan survei literatur dan menemukan beberapa sejarah APL yang menarik. Apa yang kami sebut sebagai aturan pengindeksan APL tidak ada dalam buku Iverson tahun 1962, tetapi ada di APL \ 360 (1968; implementasi pertama APL). Namun, APL \ 360 menggabungkan skalar dan 1-vektor, sebuah inkonsistensi yang tidak dikenali dalam literatur sampai (Haegi, 1976). Sebuah diskusi tentang semantik formal array multidimensi pertama kali muncul dalam tesis PhD Brown (1972; ia kemudian menjadi arsitek APL2), dan mendorong serangkaian pekerjaan yang memformalkan semantik mereka.

Survei yang sangat baik tentang perkembangan yang mengarah ke APL2 adalah:

  • Karl Fritz Ruehr. "Survei perluasan ke APL." Dalam Proceedings of the International Conference on APL, APL '82, halaman 277–314, New York, NY, USA, 1982. ACM.

Penting dalam literatur untuk perhatian yang diberikan pada aturan pengindeksan adalah:

  • T. Lebih. "Aksioma dan teorema untuk teori array." Jurnal Penelitian dan Pengembangan IBM, 17 (Maret): 135–175, 1973.

    • Sebuah buku tebal raksasa yang memformalkan semantik array multidimensi menggunakan teori himpunan aksiomatik Quine, menunjukkan bagaimana skalar dapat digabungkan dengan array peringkat-0 dengan gagasan himpunan mandiri untuk membangun apa yang oleh literatur APL disebut "array mengambang". ([1] == 1, dibandingkan dengan "array ground" di mana [1]! = 1. Karya Sheila M. Singleton dalam tesis master tahun 1980-nya menunjukkan bahwa teori array More juga dapat diadaptasi untuk mendeskripsikan grounded array.)

    • More juga menyebutkan produk dalam yang mengembalikan skalar sebagai aturan penting untuk memandu semantik array.

    • Lebih lanjut juga menyinggung kompleksitas penanganan "atas / bawah" untuk array multidimensi umum:

      "Misalkan V adalah ruang vektor berdimensi-n di atas suatu bidang. Dengan mengabaikan pertimbangan kontravarian dan kovarians, tensor valensi q pada V adalah pemetaan multilinear dari perkalian Kartesius dari daftar VV ... V dengan panjang q menjadi vektor ruang. Jika V memiliki basa, maka tensor valensi q pada V dapat direpresentasikan oleh _component tensor_, yang merupakan larik pada sumbu q, masing-masing dengan panjang n. "

  • G. Lewis. "A new array indexing system for APL", Prosiding konferensi internasional ketujuh di APL - APL '75, 234-239, 1975.

    • Makalah ini adalah yang pertama menganjurkan indeks tupel dalam operasi pengindeksan menjadi objek kelas satu di APL, dan mencatat bahwa konstruksi yang konsisten dari hasil pengindeksan dapat dicapai dengan produk Cartesian sistematis di sepanjang setiap peringkat tupel indeks.

  • Hans R Haegi. "Perluasan APL menjadi struktur data seperti pohon." ACM SIGAPL APL Kutipan Quad, 7 (2): 8–18, 1976.

    • Makalah ini mengeluhkan inkonsistensi dalam APL \ 360 klasik, yang menggabungkan skalar dan 1-array, dan menganjurkan bahwa aturan pengindeksan APL mensyaratkan agar penggabungan ini tidak berlaku.

    • Makalah ini juga mengandung konstruksi yang sangat mirip dengan Lewis, 1975; pekerjaan itu tampaknya mandiri.

  • JA Gerth dan DL Orth. "Pengindeksan dan penggabungan di APL." Dalam Proceedings of the International Conference on APL, APL '88, halaman 156–161, New York, NY, USA, 1988. ACM.

    • Perlu diperhatikan bahwa aturan pengindeksan APL dapat dibenarkan dengan menganggap pengindeksan sebagai operasi penyiaran yang memetakan indeks yang ditetapkan ke kumpulan nilai. Interpretasi fungsional ini secara alami menyarankan aturan pelestarian peringkat dan konstruksi Cartesian dari Lewis dan Haegi.

Selain itu, tanpa aturan "dapat menambahkan dimensi tunggal yang tertinggal", kami tidak mematuhi identitas tersebut

image

karena sisi kiri adalah skalar (menurut definisi jejak) dan sisi kanan berbentuk (1, n) x (n, n) x (n,) = (1,) . Sebaliknya, kita dapat menggunakan identitas ini sebagai prinsip panduan untuk memilih semantik transposisi vektor. Poin utamanya adalah properti siklik dari operasi pelacakan yang mendefinisikan identitas pertama. Kuantitas di dalam jejak harus berupa skalar atau matriks (jejak vektor tidak ditentukan). Avv' sudah jelas merupakan matriks: (Av)v' dan A(vv') menghasilkan hasil yang sama. Tetapi juga dari kuantitas kedua, v'Av harus berupa matriks _atau_ skalar. (Jika skalar, identitas kedua juga berlaku.) v'Av dapat berupa 1-vektor jika aturan "dapat menambahkan dimensi tunggal tambahan" aktif, dalam hal ini dapat secara transparan dibentuk ulang menjadi matriks 1x1.

Jadi jika kita ingin jejaknya didefinisikan, maka itu perlu memberlakukan batasan pada bentuk yang diperbolehkan dari produk luar vv' dan bentuk kuadrat v'Av .

@jihao : Saya tidak begitu yakin apa yang Anda perdebatkan untuk kami lawan. Dapatkah Anda menyatakan "dapat menambahkan aturan dimensi tunggal setelahnya" sedikit lebih jelas? Kapan itu berlaku? Apakah menurut Anda kita harus mendukungnya?

Saya pikir beberapa argumen Anda dapat diambil untuk memperkuat posisi yang tidak dapat kita anggap transposisi sebagai membalikkan semua dimensi (vektor kolom akan ditransposisikan menjadi vektor kolom, atau mungkin array dengan jumlah acak dimensi singleton terkemuka). Agar tetap konsisten dengan aljabar matriks, saya pikir ini harus dianggap sebagai menukar dua dimensi pertama. Kemudian saya percaya bahwa beberapa kontradiksi yang Anda nyatakan menghilang. Mudah-mudahan, sisanya akan hilang jika kita tidak menambahkan dimensi tunggal saat melakukan transposisi (dimensi covector pertama yang tidak ada tidak dihitung).

Komentar umum saya di atas bukanlah untuk menganjurkan aturan-aturan ini, melainkan untuk membantu menggambarkan ruang desain aturan pengindeksan array dan interaksinya dengan identitas aljabar linier.

Aturan "dapat menambahkan dimensi tunggal yang tertinggal" digunakan oleh MATLAB dan (menurut @alanedelman) diperkenalkan untuk mendukung array multidimensi. Perhitungan indeks-ke-offset yang digunakan dalam array MATLAB ditentukan oleh sub2ind , yang mengembalikan indeks linier yang sama terlepas dari berapa banyak trailing 1 yang Anda lempar. Lebih lanjut, dokumentasi pengindeksan matriks MATLAB menyatakan bahwa untuk operasi pengindeksan:

Jumlah subskrip yang ditentukan untuk B, tidak termasuk subskrip tambahan yang sama dengan 1, tidak melebihi ndims (B).

Secara lebih formal menurut saya itu dapat dinyatakan sebagai:

Untuk operasi yang mengambil array sebagai input, (n,) -arrays, (n,1) -arrays, (n,1,1...) array semuanya dalam kelas ekivalen yang sama sehubungan dengan argumen yang valid untuk operasi ini. (Jika n=1 , maka kelas ekivalensi juga menyertakan skalar.)

Contoh:

  • A*b dan A\b dimana A adalah sebuah matriks dan b dapat berupa vektor atau matriks (semantik identik untuk matriks n x 1 ),
  • hcat(A, b) dimana A adalah sebuah matriks dan b dapat berupa vektor atau matriks

Untuk sebagian besar, Julia tidak memiliki aturan "dapat menambahkan aturan dimensi tunggal", kecuali untuk contoh produk luar. Mungkin ada orang lain juga tapi saya tidak bisa memikirkan mereka sekarang.

Selama Transpose{A<:AbstractArray} bukan subtipe dari AbstractArray Saya rasa saya tidak melihat masalah (tapi mungkin saya mengabaikan sesuatu karena saya belum terlalu memikirkannya seperti kalian) :
dengan

typealias AbstractVectorTranspose{A<:AbstractVector} Transpose{A}
typealias AbstractMatrixTranspose{A<:AbstractMatrix} Transpose{A}
typealias AbstractTMatrix Union(AbstractMatrix, AbstractMatrixTranspose} 

(dan juga untuk CTranspose ) yang bisa kita miliki

AbstractVectorTranspose * AbstractVector = Number
AbstractVector * AbstractVectorTranspose = AbstractMatrix
AbstractVectorTranspose * AbstractTMatrix = AbstractVectorTranspose
AbstractTMatrix * AbstractVector = AbstractVector
AbstractTMatrix * AbstractTMatrix = AbstractTMatrix

Satu-satunya pertanyaan terbuka adalah apakah AbstractVector * AbstractTMatrix harus didukung ketika AbstractTMatrix memiliki 1 sebagai ukuran pertama, atau apakah AbstractVector * AbstractVectorTranspose sudah cukup.

Juga, sistem tipe baru mungkin membantu mengekspresikan beberapa dari typealias dan union sa sedikit lebih hati-hati.

Juga, jika misalnya v.'*A dihitung sebagai (A.'*v).' , maka kebutuhan akan pembungkus Conjugate muncul jika A itu sendiri adalah misalnya A=B' .

Saya setuju dengan @simonbyrne bahwa kita tidak boleh memiliki Transpose{Array} <: AbstractArray .

Bisakah Anda menjelaskannya di sana? Saya pikir pendapat di https://github.com/JuliaLang/julia/issues/4774#issuecomment -59428215 adalah bahwa CoVector tidak boleh menjadi subtipe dari AbstractVector, tetapi akan tampak agak aneh bagi saya untuk tidak memiliki Transpose{Matrix} <: AbstractArray .

Untuk apa nilainya, saya pikir bahwa CoVector sebagian besar harus berperilaku seperti Vector kecuali bahwa Vector dikonversi menjadi Matrix sebagai matriks kolom sementara CoVector dikonversi menjadi Matrix sebagai matriks baris.

Saya kira itu berarti pengindeksan menjadi covector harus bekerja sama seperti menjadi matriks baris?

Itu pemikiran yang menarik. Apakah segala sesuatunya menjadi lebih mudah atau lebih rumit jika hanya dimensi _leading_ tunggal yang dibuang dalam jenis transpose / covector?

(Saya telah mengikuti masalah ini dengan minat tetapi aljabar linier saya cukup berkarat sehingga saya merasa tidak memenuhi syarat untuk berkontribusi).

@mbauman :

Apakah segala sesuatunya menjadi lebih mudah atau lebih rumit jika hanya dimensi tunggal utama yang dijatuhkan dalam jenis transpose / covector?

Jika Anda mengizinkan jumlah acak dimensi singleton terkemuka, maka indeks array tidak lagi tertata dengan baik dan tidak ada yang namanya dimensi pertama "", yang cukup aneh sehingga sebaiknya kita menganggap pengurutan dengan baik sebagai aksioma.

@tokopedia

Saya pikir pendapat di # 4774 (komentar) adalah bahwa CoVector tidak boleh menjadi subtipe dari AbstractVector, tetapi agak aneh bagi saya untuk tidak memiliki Transpose {Matrix} <: AbstractArray.

Menjadi jelas bagi saya bahwa masalah ini sepenuhnya tentang memisahkan semantik array (cf # 10064) dari semantik aljabar linier, dan mencari tempat yang saling bercampur.

  • semantik array didefinisikan oleh fungsi seperti size, length, getindex, setindex, hcat, vcat, reshape, rot90 ...
  • semantik aljabar linier ditentukan oleh fungsi seperti +, -, *, /,, ', trace ...

Jika kita mendefinisikan fungsi cat sebagai bagian dari antarmuka penting dari AbstractArray , maka Transpose{<:AbstractArray} jelas bukan AbstractArray karena perilaku penggabungannya berbeda . Jika kita menganggap hanya bentuk dan pengindeksan sebagai bagian dari antarmuka penting, maka situasinya menjadi kurang jelas.

Jika kita membutuhkan penggabungan sebagai bagian dari antarmuka penting dari AbstractArray , maka akan lebih mudah untuk menjelaskan mengapa tipe seperti SymTridiagonal bukan AbstractArray s, karena operasi penggabungan lebih dari SymTridiagonal s seperti [SymTridiagonal(randn(5), randn(4)) randn(5)] saat ini belum ditentukan.

@toivoh :

Saya kira itu berarti pengindeksan menjadi covector harus bekerja sama seperti menjadi matriks baris?

Ada identitas yang menyarankan bahwa perilaku pengindeksan Transpose{Vector} harus sama dengan Vector s biasa. Pertimbangkan bahwa untuk tipe numerik, v[1] menghasilkan hasil yang sama seperti v' * e₁ = v ⋅ e₁ dan v[1:2] menghasilkan hasil yang sama seperti v' * [e₁ e₂] , di mana e₁ adalah dasar kanonik Vector{Int} [1, 0, 0, ...] dan e₂ adalah [0, 1, 0, 0, ...] . Jika kami memerlukan identitas yang terkait dengan pengindeksan, produk dalam, dan transposisi ini untuk dipegang, orang dapat mengklaimnya

(v')[1] == (e₁' * v'') == (v' * e₁)' == (v ⋅ e₁)' == conj(v ⋅ e₁)* = conj(v[1])

(di mana langkah pertama adalah aksioma baru dan yang keempat menggunakan fakta bahwa mengubah skalar adalah tidak ada operasi) sehingga pengindeksan menjadi Transpose{Vector} pada dasarnya akan mengabaikan transposisi, dan mengindeks menjadi CTranspose{Vector} akan mengkonjugasikan elemen yang diindeks.

saya bahwa masalah ini sepenuhnya tentang memisahkan semantik array (cf # 10064) dari semantik aljabar linier, dan mencari tempat-tempat yang saling bercampur.

  • semantik array didefinisikan oleh fungsi seperti size, length, getindex, setindex, hcat, vcat, reshape, rot90 ...
  • semantik aljabar linier ditentukan oleh fungsi seperti +, -, *, /,, ', trace ...

+1 ke sudut pandang itu dan tidak memiliki Transpose <: AbstractArray . Juga, saat mengindeks covector, itu harus dengan indeks tunggal, karena jika tidak, hasil vektor covector * (berkontraksi melalui indeks tunggal) tidak dapat menghasilkan skalar (obyek dengan indeks nol).

@jihao : Saya tidak yakin saya mengerti mengapa kita membutuhkan atau menginginkan

(v')[1] == (e₁' * v'')

sebagai aksioma baru. Meskipun bahkan jika covector akan mengindeks sebagai matriks baris, saya pikir kita akan mendapatkan hasil yang sama di atas karena pengindeksan linier.

Dan +1 untuk melihat covectors yang berkaitan dengan aljabar linier.

Tetapi tidak ada alasan bahwa penggabungan dengan SymTridiagonal tidak harus didefinisikan, bukan?

Pengindeksan linier

Saya pikir pengindeksan linier adalah tentang urutan penyimpanan, dan sebenarnya tidak ada urutan yang masuk akal untuk pengindeksan linier vektor, bukan? (Dan maaf tentang kesalahan ejaannya.)

Tidak ada urutan traversal unik yang masuk akal dalam memori. Bahkan untuk array Fortran Anda dapat memilih untuk menyimpan elemen dalam kolom utama, baris utama, atau bahkan membalik urutan utama kolom (yang persis seperti yang dilakukan oleh compiler IBM Fortran I asli). Lebih lanjut, ada struktur data lain (lihat # 10064) seperti percobaan yang dapat digunakan sebagai larik dan memiliki lebih banyak opsi untuk urutan traversal.

Hal yang sama dapat dikatakan tentang vektor dan matriks. Karena pengindeksan linier mengakses elemen dalam urutan yang sama untuk matriks kolom dan transposenya (dan sama seperti untuk vektor kolom), mengapa covector harus berbeda? Jika harus berbeda, saya pikir seharusnya kita tidak mendefinisikan pengindeksan untuk covectors sama sekali.

@ Toivoh ya definisi yang sama berlaku untuk array biasa. Itu tidak mengubah fakta bahwa pengindeksan linier diturunkan dari pengindeksan biasa (tuple?) Dalam kedua kasus.

Mengindeks Transpose objek bisa jadi tidak diizinkan. Saya tidak mengatakan bahwa mereka harus dapat diindeks, tetapi jika demikian, mereka tidak harus memiliki perilaku pengindeksan yang sama. Agar konservatif, kita dapat membiarkan pengindeksan tidak ditentukan untuk saat ini dan melihat apakah ada kasus penggunaan yang muncul.

Banyak implementasi Julia murni dari fungsi aljabar linier akan ingin mengindeks ke dalam Transpose, bukan? Menulis perkalian matriks Julia murni (untuk jenis bilangan non-BLAS) menjadi mudah jika Anda tidak harus membedakan antara kasus yang mungkin (normal, transpos, ctranspose, konj?) Untuk kedua matriks yang terlibat, tetapi perlakukan saja sebagai matriks biasa. Metode cache-oblivious dapat dicoba untuk mendapatkan pola akses memori yang agak lokal.

Benar, ya.

@ Jutho : Saya setuju. Dan agar sesuai di sana, covectors harus mengindeks seperti matriks baris, bukan?

@toivoh , jika Anda bermaksud bahwa mereka harus memiliki indeks tambahan 1 di depan, saya tidak setuju dan tidak melihat bagaimana hal itu tersirat oleh pernyataan saya. Saya hanya berbicara tentang produk matriks matriks. Matriks * vektor atau kovektor * matriks adalah metode berbeda yang memerlukan definisi fungsi berbeda, tidak hanya karena keduanya memiliki pola akses memori yang berbeda, tetapi juga karena memiliki jenis kembalian yang berbeda (Matrix_vector = vektor atau covector_matrix = covector), jadi ada a alasan yang sangat praktis di Julia untuk tidak mencampur hal-hal ini.

Secara umum, saya bukan penggemar berat kemampuan untuk menambahkan indeks tambahan 1 saat mengindeks array berdimensi-N, atau misalnya alias tipe VecOrMat . Ini memungkinkan untuk pemrograman yang ceroboh, tetapi itu juga mengapa hal itu memudahkan untuk membuat kesalahan atau mendeteksi kesalahan lain lebih lambat. Saya hanya melihat dua cara yang berguna untuk memasukkan array berdimensi-N, yaitu dengan indeks N yang tepat, jika Anda menggunakannya sebagai objek multilinear, atau dengan indeks linier, saat Anda memperlakukannya sebagai vektor dalam produk tensor spasi (misalnya untuk menambahkan dua larik atau mengalikannya dengan skalar). Sementara itu cukup untuk saya gunakan, saya dapat menerima bahwa itu terbatas untuk orang lain.

@ Jutho : Ok, saya setuju bahwa itu mungkin tidak masalah karena tipe pengembalian harus berbeda pula.

Berikut adalah upaya untuk menjelaskan apa yang kami coba lakukan dan memberikan beberapa aksioma:

Saya pikir kita telah mencapai konsensus yang cukup jelas bahwa titik awalnya adalah aljabar matriks (yang hanya didasarkan pada matriks). Untuk sebagian besar operasi, kita tahu bagaimana perilakunya dalam pengaturan matriks murni.

Saya percaya bahwa apa yang kami coba lakukan adalah memperluas dan menyempurnakan pengaturan matriks murni secara konsisten untuk memiliki juga skalar dan vektor yang sebenarnya, dan karena tampaknya diperlukan untuk konsistensi, covectors.

Berikut pandangan saya tentang skalar dan vektor (dilihat dari sudut pandang matriks murni): Skalar adalah matriks, yang menurut jenisnya dibatasi menjadi 1 x 1. Vektor adalah matriks, yang menurut jenisnya dibatasi be nx 1. (Saya akan berpendapat di bawah bahwa covector adalah matriks yang menurut jenisnya dibatasi menjadi 1 x n.) Dari sudut pandang ini kita dapat memberikan dua aksioma: (tidak dijelaskan secara formal di bawah)

  • Ekstensi: Pertimbangkan fungsi dari matriks ke matriks. Jika akan selalu menghasilkan matriks keluaran dengan ukuran 1 dalam dimensi tertentu, dengan masukan jenis tertentu, fakta tersebut akan dikodekan dalam jenis keluaran (menjadikannya skalar / vektor / covector).
  • Penyempitan: Jika fungsi yang akan mengambil argumen matriks dalam pengaturan matriks murni mengharuskan masukan memiliki ukuran satu dalam satu atau beberapa dimensi, ia mungkin menolak untuk menerima masukan di mana fakta ini tidak dikodekan dalam tipe.

Jika kita setuju dengan hal di atas, transpos dari sebuah vektor haruslah jenis covector yang dijelaskan di atas: Transposisi matriks anx 1 menghasilkan matriks 1 xn. Jika kita menyandikan fakta bahwa ukuran sepanjang dimensi pertama hasilnya selalu satu, kita mendapatkan covector seperti yang dijelaskan di atas.

Jika Anda mulai dari sudut pandang aljabar matriks, maka apa yang Anda katakan adalah benar. Ini adalah model yang mungkin diimplementasikan MATlab dengan cukup sempurna. Semuanya adalah matriks. Ini adalah sistem tertutup, semua operasi pada matriks menghasilkan matriks baru.

Saya tentu mendapat kesan bahwa inti dari masalah ini (menganggap serius transposisi vektor, karena mereka bukan hanya matriks) adalah menjauh dari model aljabar matriks, karena model itu mulai menunjukkan ketidakkonsistenan jika Anda ingin memisahkan bilangan dari matriks 1x1 karena alasan tertentu efisiensi. Alternatifnya adalah mengikuti model aljabar linier , di mana terdapat perbedaan yang jelas antara bidang (skalar), ruang vektor (dan rangkapnya yang sesuai), dan ruang operator / transformasi linier (matriks).

Saya pikir operasi aljabar linier di Julia cukup berakar kuat pada tradisi matlab, dengan beberapa pengecualian penting seperti memiliki skalar dan vektor, dan tidak mencoba menebak-nebak pengguna. Apa pun yang bergerak terlalu jauh kemungkinan besar merupakan gangguan yang sangat besar.

Saya percaya bahwa aksioma saya di atas harus berjalan bersama untuk menyelesaikan inkonsistensi yang muncul saat Anda ingin memisahkan skalar dan vektor dari matriks (untuk alasan efisiensi dan kebenaran). Tapi saya benar-benar terbuka untuk mendengar tentang kemungkinan sistem lain.

Saya setuju dengan @Jutho di sini; inti dari masalah ini adalah untuk menjauh dari semantik MATLAB "everything is a matrix". MATLAB aturan "dapat menambahkan dimensi tunggal tertinggal" diperlukan agar alam semesta ditutup di bawah operasi aljabar linier, tetapi aturan itu mendefinisikan kelas kesetaraan yang berisi anggota tipe T dan jenis lain Array{T,N} untuk semua N , dan merupakan alasan utama mengapa sistem tipe MATLAB tidak dapat diputuskan. (Lihat Teorema 1 Joisha dan Banerjee, 2006 - meskipun hasilnya dinyatakan dalam bentuk, sebenarnya masalahnya adalah bagaimana mengubah peringkat array dapat mengubah semantik program.)

Tapi saya masih berpikir kami memiliki konsensus yang cukup bagus tentang perkalian skalar, vektor, covectors, dan matriks harus asosiatif (dengan pengecualian untuk hal-hal seperti (v'*v)*v mana dua non-skalar berkembang biak untuk menghasilkan skalar), dan itu misalnya v'*M*v harus menghasilkan skalar, M*v vektor dan v'*M covector. Saya tidak yakin seberapa jauh mungkin untuk menyimpang dari semantik everything-is-a-matrix sambil tetap memenuhi persyaratan ini.
Apa lagi yang ingin kita hindari, dan properti mana yang ingin kita dapatkan sebagai gantinya?

Seberapa burukkah jika kita hanya menggabungkan T dan Array{T,0} dalam beberapa kasus? (Misalnya pengindeksan: M[:,2] menghasilkan Array{T,1} , tetapi M[2,2] tidak menghasilkan Array{T,0} )

Kami masih dapat mempertahankan semantik yang valid dengan Transpose{Vector} .

Saya membaca ulang semua komentar tentang asosiatif dan menyimpulkan bahwa sebagian besar diskusi itu sebenarnya bukan tentang asosiatif itu sendiri, melainkan semantik produk dalam dan produk luar. Jika Anda menemukan ekspresi yang bukan tentang keduanya, harap tunjukkan.

Masalah dengan semantik tipe Matlab adalah bahwa M*v' dan v*M terkadang berfungsi meskipun seharusnya tidak. Jika M adalah m x 1 maka M*v' valid dan mengembalikan kuantitas seperti produk luar (karena v' adalah 1 x n ). Demikian pula, jika M adalah 1 x m dan kita memiliki aturan "can add trailing singletons" maka v*M dapat dievaluasi sebagai produk dari n x 1 dan 1 x m matriks, sekali lagi menghasilkan kuantitas seperti produk luar.

Pertanyaan tentang penggabungan T dan Array{T,0} juga diangkat dalam literatur APL - di APL, array multidimensi bertumpuk secara rekursif, yang menimbulkan pertanyaan apakah Array{T,0} dan T dapat dibedakan. Jika tidak, mereka adalah "array yang di-ground" (yang berulang ke T ), jika tidak, mereka adalah "array mengambang" (yang berulang ke Array{T,0} saja). Saya percaya More, 1973 benar-benar membuktikan bahwa pilihan mana pun secara aksiomatis konsisten. Saya tidak yakin apakah APL pernah menyelesaikan pertanyaan yang akan digunakan sebelum sebagian besar praktisi pensiun atau beralih ke hal lain.

@jiahao : Saya tidak menyadari betapa fundamental pengamatan Anda itu

v[i] = e_i' * v

untuk menyatukan aljabar linier dan semantik pengindeksan. Tetapi kemudian Anda juga harus mempertimbangkan

M[i,j] = e_i' * M * e_j

yang menunjukkan bahwa produk dalam dengan vektor basis dari kanan sesuai dengan pengindeksan sepanjang dimensi kedua. Jadi, saya akan mempertahankan bahwa entri i th dari covector v' harus diindeks sebagai

v' * e_i = v'[1, i]

di mana tentu saja kita ingin menulis sesuatu selain 1 sebagai indeks pertama, tapi apa?
Bagaimanapun, karena kami mengizinkan

e_i' * v = v[i] = v[i, 1]

maka 1 harus diizinkan sebagai placeholder juga dalam kasus di atas.

v' * e_i adalah skalar, jadi e_1' * (v' * e_i) adalah covector, bukan skalar. Jadi dimensinya tidak cocok dengan v'[1, i] = e_1' * v' * e_i

sunting: Saya pikir ini mungkin argumen yang menentang mengizinkan lajang tertinggal dalam pengindeksan?

Ya, pengindeksan matriks adalah langkah logis berikutnya, dan e_i' * M * e_j sebenarnya adalah salah satu ekspresi di mana aksioma asosiatif menjadi berguna, karena

(e_i' * M) * e_j = m_i' * e_j

e_i' * (M * e_j) = e_i' * m_j

harus sama. Pengindeksan matriks dapat diturunkan dari aturan pengindeksan vektor dan aturan pengindeksan covector.

Saya percaya bahwa resolusi yang konsisten dari masalah ini mungkin memerlukan ekspresi seperti v[i, 1] untuk tidak diizinkan, karena aturan yang memungkinkan perilaku pengindeksan ini
a) harus menyebabkan kasus palsu untuk A*v' dan v*A untuk bekerja (yang pertama bekerja tetapi yang terakhir tidak karena kita menerapkan aturan singleton yang tertinggal secara tidak konsisten), dan
b) jika kita mempertimbangkan persamaan dari v[i] = v[i, 1, 1, 1] maka aturan pengindeksan covector yang sesuai akan terlihat seperti (v')[1, 1, 1, i] dan harus memiliki aturan "izinkan nomor acak tunggal terkemuka" yang sesuai untuk covectors untuk konsistensi. Saya menemukan kurangnya dimensi pertama yang didefinisikan secara unik sangat mengganggu.

Saya tidak berpikir alasan indeks ini benar-benar ke mana-mana. Pengindeksan adalah properti umum dari N -dimensional array, dan mereka dapat ditulis sebagai ekspresi matriks sederhana untuk N=1 atau N=2 agak sepele dan tidak mengandung dasar apapun. informasi. Tapi ini tidak menggeneralisasi ke array peringkat yang lebih tinggi dan dengan demikian tidak boleh digunakan untuk memotivasi apakah covector memerlukan 1 di depan atau tidak saat diindeks. Ini dengan cepat menyebabkan ketidakkonsistenan seperti yang diamati pada posting sebelumnya.

Seperti yang dinyatakan di atas, saya tidak pernah menjadi penggemar mengandalkan indeks trailing dan tidak dapat memikirkan satu situasi pun yang perlu atau bahkan sangat berguna. Tetapi saya dapat menerima bahwa sudut pandang saya terlalu terbatas.

Saya belum sepenuhnya mencerna semua ini tetapi pertanyaan utama saya adalah: apakah size(covector) sama dengan (n,) atau (1,n) ?

Jika mereka bukan bagian dari keluarga AbstractArray , bahkan size tidak diwajibkan.

Meskipun untuk alasan praktis saya kira itu akan ditentukan (seperti untuk angka dll), dan suara saya pergi ke (n,) . Dari sudut pandang penyimpanan / wadah, saya akan mengatakan tidak ada perbedaan antara vektor dan covectors. Jadi tidak perlu menggunakan covectors sebagai container dan oleh karena itu mereka tidak termasuk dalam hierarki AbstractArray . Ini hanya jenis pembungkus sederhana untuk menyatakan bahwa mereka berperilaku berbeda dari vektor sehubungan dengan operasi aljabar linier.

"Selama aljabar dan geometri telah dipisahkan, kemajuannya lambat dan penggunaannya terbatas; tetapi ketika kedua ilmu ini telah disatukan, mereka telah meminjamkan kekuatan timbal balik masing-masing, dan telah berbaris bersama menuju kesempurnaan." - Joseph Louis Lagrange

Saya berharap saya dapat berkontribusi lebih banyak, tetapi saya pikir saya hanya akan mengatakan bahwa saya mendukung memiliki sistem yang mendukung pembuatan alat matematika canggih yang digunakan oleh fisikawan dan insinyur yang intuitif untuk digunakan dan akurat. Mungkin, sumber daya dari MIT ini, mungkin berguna ...

http://ocw.mit.edu/resources/res-8-001-applied-geometric-algebra-spring-2009/lecture-notes-contents/

Sebenarnya, kalau dipikir-pikir, lebih adil untuk mengatakan itu

e_i' * x = x[i, :] # x is a vector or matrix
x * e_j  = x[:, j] # x is a covector or matrix

Kemudian untuk pengindeksan matriks yang kami miliki

e_i' * M * e_j = e_i' * (M * e_j) = e_i' * M[:, j] = M[:, j][i, :] = M[i, j]
e_i' * M * e_j = (e_i' * M) * e_j = M[i, :] * e_j  = M[i, :][:, j] = M[i, j]

Saat ini ini tidak cukup berlaku di Julia, misalnya v[i, :] saat ini menghasilkan array 1x1 dan bukan skalar. (Tapi mungkin seharusnya tidak)
Keterkaitan perkalian matriks dalam e_i' * M * e_j sesuai dengan komutatifitas pemotongan sepanjang dimensi yang berbeda M[:, j][i, :] = M[i, :][:, j] , yang tampaknya merupakan fitur yang diinginkan untuk dimiliki.
Dengan kalimat di atas, kita seharusnya memiliki

v'[:,i] = conj(v[i])

@ Jutho : Saya pikir paradigma "pengindeksan sebagai pemotongan berulang" ini menggeneralisasi ke array / tensor dimensi yang lebih tinggi: Anda menerapkan satu pemotongan untuk setiap dimensi ke indeks, dalam urutan apa pun. Ini sesuai dengan serangkaian kontraksi dengan tensor urutan pertama sesuai dengan e_i , dll, juga dalam urutan apa pun (selama Anda melacak dimensi mana yang cocok).

Saya pikir paradigma "pengindeksan sebagai pengirisan berulang" ini menggeneralisasi ke array / tensor dimensi yang lebih tinggi: Anda menerapkan satu pemotongan untuk setiap dimensi ke indeks, dalam urutan apa pun. Ini sesuai dengan serangkaian kontraksi dengan tensor urutan pertama yang sesuai dengan e_i, dll., Juga dalam urutan apa pun (selama Anda melacak dimensi mana yang cocok).

Ya, saya sangat akrab dengan kontraksi tensor dll, dan memang mendapatkan elemen matriks / elemen tensor tidak sesuai dengan pengambilan nilai ekspektasi dalam basis komputasi standar, yaitu kontrak dengan beberapa vektor basis (selama Anda memiliki basis ortogonal setidaknya ), tetapi tidak ada asosiasi unik apakah indeks sesuai dengan kontraksi dengan e_i atau dengan e_i' . Itu sesuai dengan memutuskan apakah indeks yang sesuai muncul dalam posisi kovarian atau kontravarian, dan tidak ada keputusan khusus. Semua kemungkinan kombinasi indeks atas dan bawah memiliki aplikasi yang berguna. Tetapi membuat kontrak dengan e_i dan e_i' bahkan bukanlah cara yang benar untuk mengajukan pertanyaan ini dari sudut pandang matematika, karena, seperti yang telah saya nyatakan di atas, sebenarnya tidak ada pemetaan matematika seperti itu. transpos dari vektor. Transpos adalah operasi yang ditentukan untuk peta linier (matriks) dan bahkan di sana hanya sesuai dengan transpos matriks jika Anda juga menulis vektor ganda sebagai vektor kolom. Transposisi vektor hanyalah trik praktis yang telah diperkenalkan dalam aljabar matriks (di mana memang vektor adalah n x 1 matriks) dan ini hanya berfungsi karena Anda berada di ruang Euclidean di mana ada pemetaan kanonik dari (konjugasi ) ruang vektor ke ruang ganda.

Khususnya, jika Anda menginginkan properti yang Anda gambarkan di atas, Anda harus meminta M[i,:] mengembalikan objek yang berbeda (baik matriks 1xn atau covector) lalu M[:,i] (yang seharusnya menjadi matriks atau vektor nx1 ). Fakta bahwa hal ini tidak secara tepat digeneralisasikan ke dimensi yang lebih tinggi adalah salah satu pokok diskusi utama dari masalah ini, dan tampaknya sebagian besar orang mendukung pengindeksan APL, di mana dimensi yang diindeks dengan angka dihapus (yaitu keduanya M[:,i] dan M[i,:] menghasilkan array peringkat 1, oleh karena itu, vektor). Pengindeksan adalah properti array, dan pencampuran perilaku pengindeksan dengan operasi aljabar linier inilah yang menghasilkan semua kebingungan / ketidakkonsistenan di tempat pertama. Ini bisa konsisten selama Anda tetap berada dalam ekosistem tertutup objek peringkat N=2 , yaitu semuanya adalah matriks, juga vektor dan angka, dan Anda tidak pernah mempertimbangkan array dimensi yang lebih tinggi.

Saya juga baru menyadari bahwa M[i,:] harus menghasilkan covector dengan alasan saya di atas, seperti yang Anda katakan. Jadi tampaknya memiliki covectors pada tingkat tertentu secara fundamental tidak konsisten dengan pengindeksan APL. Jika kita menyukai pengindeksan APL (dan saya menyukainya), pertanyaannya menjadi di mana menarik garis antara dunia dan dunia tempat covectors tinggal. (Saya berharap bahwa akan mungkin untuk mendamaikan keduanya, mungkin kalian semua sudah menyadari bahwa kita harus menyerah?)

Konflik ini mungkin tidak terlalu mengejutkan jika Anda memikirkannya:

  • Dalam pengindeksan APL, hanya dimensi yang bermakna, dapat diindeks, yang disimpan dalam hasil; sisanya diperas.
  • Jika kita melakukannya dengan v' maka kita akan memiliki v' = conj(v) . Sebaliknya, covector dapat dilihat sebagai melacak dimensi pertama yang hilang.

Saya kira awal yang baik adalah membatasi covectors sebanyak mungkin, pada dasarnya hanya mendefinisikan perkalian, penambahan / pengurangan, dan pembagian kiri pada mereka.

Idenya tampaknya tidak membuat mereka <: AbstractArray . Apakah masuk akal untuk menjadikannya subtipe dari tipe LinearOperator ? (Yang saya tahu telah dibahas sebelumnya, tetapi tidak begitu ingat kesimpulannya.)

Saya pikir tidak adanya pewarisan ganda atau konstruksi bahasa untuk antarmuka (keduanya telah dibahas) mensyaratkan bahwa konsep tertentu hanya diimplementasikan oleh antarmuka 'implisit', yaitu sekumpulan metode yang perlu didefinisikan. Iterator adalah salah satu konsep seperti itu, operator linier mungkin akan menjadi yang lain yang perlu ditentukan oleh sekumpulan metode daripada hierarki tipe. Aneh jika memiliki tipe abstrak LinearOperator dan kemudian tidak memiliki Matrix sebagai subtipe dari itu.

@toivoh Itu adalah pertimbangan penting, itulah alasan saya menyarankan fungsi baru seperti row(M,i) dan col(M,i) untuk mengekstrak vektor atau covector i th dari matriks. Fungsi ini hanya untuk array dua dimensi M dan untuk orang yang tertarik dengan aljabar matriks. Awalnya mungkin tampak sedikit kurang jelas daripada pengindeksan gaya MATLAB tetapi, secara keseluruhan, memisahkan secara konseptual gagasan vektor dan itu dual / transpose / covector membantu memperjelas. Dalam kasus mekanika kuantum, seluruh bidang melompat ke notasi bra-ket Dirac hanya karena perbedaan antara vektor dan kovektor ini sangat penting untuk vektor kompleks, dan notasi Dirac membuatnya jelas. Harapan saya Julia akan melakukan ini juga, serta menjadi alat yang baik untuk array penyimpanan dimensi yang lebih tinggi dan aljabar linier dimensi yang lebih tinggi! (Karena kita rakus, kan?)

Saya harus mengatakan bahwa seseorang yang datang dengan pengalaman di MATLAB dan beberapa keakraban dengan sebagian besar matriks nyata (tetapi bukan fanatik aljabar linier hard-core) mungkin pada awalnya tidak menyadari mengapa apa yang beberapa dari kita memperdebatkan itu penting, tetapi saya percaya itu.

Saya telah mengatakan ini sebelumnya, tetapi saya akan mengulanginya: dari sudut pandang saya, kami memiliki daftar prioritas ini, dengan sebab-akibat mengalir ke bawah:

(1) Array pada dasarnya adalah wadah penyimpanan yang akan digunakan semua pengguna Julia, dan kami menginginkan semantik terbaik untuk ini. Aturan bergaya APL tampaknya, bagi saya, merupakan solusi yang sangat bagus. Di sisi lain, gaya MATLAB, array dua dimensi minimum dengan asumsi dengan indeks 1-dimensi yang membuntuti sepertinya tidak wajar, membingungkan, dan seperti yang dikatakan Jutho, mereka bahkan dapat menyebabkan pemrograman ceroboh di mana Anda tidak melacak dengan benar dimensi array Anda. Saya akan melangkah lebih jauh dengan mengatakan bahwa untuk vektor v , kode v[i,:] harus mengeluarkan kesalahan karena v adalah satu dimensi. Operasi berbasis elemen seperti + dan .* berguna untuk semua kelas container, tidak hanya dalam matriks atau aljabar multilinear. Satu-satunya konsesi wadah penyimpanan yang dibuat orang untuk barang-barang di bawah ini adalah titik ekstra pada .* dll.

(2) Sebagian besar, tetapi tidak semua, pengguna Julia akan menggunakan aljabar matriks, jadi kami menambahkan beberapa gula sintaksis untuk beberapa operasi vektor dan matriks, kebanyakan dengan simbol * (tetapi kami mungkin memiliki pembagian matriks, dll.). Dalam sistem ini kita mengambil array satu dan dua dimensi yang masing-masing adalah vektor kolom dan matriks. Untuk sistem matriks yang berfungsi penuh kita juga membutuhkan vektor baris (covectors) dan operasi transpose ' . Vektor baris dalam arti yang mungkin adalah array satu dimensi, dan saya menegaskan bahwa itu harus diindeks seperti itu (dan tentu saja tidak seperti covec[1,i] !!) Dengan aturan APL, kita dipaksa untuk membuat beberapa perbedaan antara vektor dan covectors, dan sistem tipe ideal untuk ini (ingat kita beruntung bahwa kita sudah dapat menggunakan kembali matriks dan vektor sebagai typealiases dari array satu dan dua dimensi daripada jenis pembungkus ... pada prinsipnya kita bisa bungkus mereka juga, tapi saya tidak mengerti intinya). Dengan sistem tipe kompilator dapat mengetahui bahwa CoVector * Vector adalah skalar dan Vector * CoVector adalah matriks, dan seterusnya. Seperti yang dikatakan oleh toivoh, _dari sudut pandang MATLAB, CoVector secara tepat melacak dimensi pertama yang "hilang "._ Pengguna biasa tidak perlu membuat objek ini; mereka hanya akan memasukkan vektor dan matriks dan menggunakan operasi * dan ' . Orang yang peduli akan memperhatikan dan menghargai perbedaannya. Perubahan _biggest_ untuk pengguna adalah keharusan mengubah M[i,:] menjadi menggunakan fungsi baru row(M,i) atau mengonversi ke kelas pembungkus dengan sesuatu seperti Transpose(M[i,:]) atau M[i,:]' - orang dapat menganggap ini sebagai keuntungan, karena seperti notasi Dirac Anda tidak pernah lupa objek mana yang vektor dan yang merupakan covectors, dan menugaskan ke objek dengan type-asserts akan menimbulkan kesalahan jika sesuai. Saya pikir itu layak untuk memperdebatkan notasi ini. Di masa mendatang, kami bahkan dapat memperluas sistem pembungkus untuk memungkinkan evaluasi tertunda yang efisien. Ini adalah win-win untuk semua orang, sejauh yang saya bisa lihat.

(3) Beberapa dari kita tertarik pada aljabar multi-linier, dan harus mempelajari perbedaan antara ruang ganda dan transposisi, dll. Jutho telah menyinggung hal ini. Array Julia sudah menjadi perangkat penyimpanan yang bagus untuk tensor berdimensi lebih tinggi, dan paket tambahan (yang mungkin atau mungkin tidak menemukan jalan ke Base) akan digunakan oleh orang-orang seperti kita. Kita tidak membutuhkan, atau menginginkan, operasi seperti ' atau * didefinisikan pada array dengan dimensi lebih besar dari dua. Saya tidak dapat melihat kasus penggunaan yang berorientasi pada penyimpanan untuk ' yang tidak dapat dilakukan lebih bersih dengan menyusun ulang indeks secara eksplisit. Seluruh gagasan untuk mengikuti indeks satu dimensi hanya membuat konsepnya kurang menarik ... jadi harap simpan ' untuk larik satu dan dua dimensi - seperti MATLAB :) (lihat, saya punya hal-hal bagus untuk katakan tentang MATLAB ...)

Untuk sistem matriks yang berfungsi penuh kita juga membutuhkan vektor baris (covectors) dan operasi transpos '.

Pernyataan ini benar-benar memotong inti masalah. Produk pengindeksan, transposisi, dan * semuanya bercampur. Selain itu, tidak mungkin untuk merekonsiliasi semantik penuh vektor baris dengan vektor covectors tanpa lebih jauh memperkenalkan fungsi seperti row(A, i) untuk mengembalikan baris i th A sebagai covector daripada array satu dimensi. Saat ini A[1, :] ingin berarti "ambil baris pertama A" dan "ambil potongan pertama di sepanjang dimensi kedua A", tetapi gagasan ini pada dasarnya tidak kompatibel dalam proposal covector.

Vektor baris dalam arti yang mungkin adalah array satu dimensi, dan saya menegaskan bahwa itu harus diindeks seperti itu.

Saya yakin Anda sedikit terlalu fasih dengan pernyataan ini. Pembahasan sebelumnya telah menetapkan dengan cukup jelas bahwa jika Anda menginginkan semantik aljabar linier penuh (dengan hasil kali dan transposisi yang benar), vektor baris tidak boleh memiliki tipe yang sama dengan larik satu dimensi. Pertama, pengindeksan ke dalam covector harus mengembalikan nilai terkonjugasi kompleks, (v')[1] = conj(v[1]) , untuk konsistensi wrt produk dalam dot . Kedua, covectors bukanlah vektor, mereka adalah fungsi linier yang menunggu untuk menghasilkan perkalian dalam dengan vektor. Ketiga, vektor dan covectors memiliki perilaku penggabungan array yang berbeda di bawah hcat dan vcat . Untuk semua alasan ini, vektor baris tidak dapat "dalam segala hal mungkin merupakan array satu dimensi".

Saya akan mendukung untuk menyingkirkan lajang yang tertinggal: Saya rasa saya tidak pernah melihat kode Julia yang memanfaatkannya. Awalnya saya akan mengatakan bahwa kita akan membutuhkannya untuk array 0 dimensi, tetapi saya melihat bahwa X[] berfungsi dengan baik.

Saya pikir pengindeksan APL, bersama dengan fungsi row(M,i) untuk vektor baris paling masuk akal, dan sepertinya kompromi yang baik. Saya tidak yakin tentang pengindeksan vektor baris, tetapi saya _tidak_ suka (v')[1,i] .

Keputusan besar lainnya, yang bahkan belum kita sentuh, adalah tipe. Satu temuan saya dari telah mencoba ini sebelumnya adalah bahwa sangat sulit untuk memiliki v' menjadi AbstractVector , karena hal itu membuat pengiriman menjadi berantakan.

Dua opsi yang memungkinkan:

  1. Kami menggunakan tipe terpisah untuk matriks dan vektor:

    • Transpose <: AbstractMatrix

    • CoVector <: Any

    • semacam transpos untuk objek Factorization .

  2. Kami menggunakan jenis yang sama untuk semua transposes, tetapi memiliki X' _not_ menjadi AbstractMatrix

    • Transpose <: Any

Untuk konjugasi, kita bisa

Sebuah. tentukan ConjugateTranspose (bersama dengan ConjugateCoVector jika kita menggunakan opsi 1 di atas)

b. gunakan tipe pembungkus Conjugate , dan susun dengan tepat: kita akan membutuhkan beberapa konvensi, apakah kita menggunakan Transpose{Conjugate{T}} atau Conjugate{Transpose{T}} .

Saya suka memiliki Transpose{Matrix} bukan subtipe dari AbstractMatrix . Saya pikir analog terdekat yang kita miliki di basis adalah jenis matriks khusus seperti Symmetric , yang berperilaku secara aljabar seperti matriks tetapi tidak dalam semantik pengindeksannya. (# 987 menetapkan bahwa tanpa banyak pewarisan atau sifat Suci, hierarki tipe harus menghormati semantik container di atas semantik aljabar.)

Masalah jenis penulisan yang pada dasarnya adalah "tag semantik" juga muncul di # 8240. Saya pikir Transpose{Conjugate{T}} akan lebih disukai, karena konjugasi adalah gagasan yang jatuh ke bidang elemen yang mendasarinya.

Berikut adalah contoh yang terkadang mengikuti aturan single trailing yang sama seperti MATLAB, dan di lain waktu tidak:

  • Trailing single diperbolehkan dalam operasi pengindeksan. (Seperti MATLAB)
julia> (1:5)[5,1,1,1,1,1,1]
5
  • Irisan trailing tidak diperbolehkan dalam operasi pengindeksan. (Tidak seperti MATLAB, yang memungkinkan mereka.)
julia> (1:5)[5,:]
ERROR: BoundsError()
 in getindex at abstractarray.jl:451
  • Untuk rank> = 3 array, singletons trailing implisit ditambahkan ke operasi penugasan yang diindeks saat indeks lebih sedikit daripada rank array dan indeks terakhir adalah skalar (seperti MATLAB):
julia> A=zeros(2,2,2); A[1,2]=5; A #Same as A[1,2,1]=5
2x2x2 Array{Float64,3}:
[:, :, 1] =
 0.0  5.0
 0.0  0.0

[:, :, 2] =
 0.0  0.0
 0.0  0.0
  • Untuk rank> = 3 array, _slices_ trailing implisit ditambahkan ke operasi penugasan yang diindeks saat indeks lebih sedikit daripada rank array dan indeks terakhir adalah _not scalar_ (seperti MATLAB):
julia> A[:,:]=3; A
2x2x2 Array{Float64,3}:
[:, :, 1] =
 3.0  3.0
 3.0  3.0

[:, :, 2] =
 3.0  3.0
 3.0  3.0
  • Untuk rank> = 3 array, singletons trailing implisit ditambahkan ke operasi pengindeksan saat indeks lebih sedikit daripada rank array dan indeks terakhir adalah skalar (seperti MATLAB):
julia> A=reshape(1:8,2,2,2); A[:,1]
2-element Array{Int64,1}:
 1
 2

julia> A[:,1,1]
2-element Array{Int64,1}:
 1
 2
  • Untuk rangking r> = 3 larik, operasi pengindeksan bila ada indeks k <r daripada rangking larik dan indeks terakhir adalah irisan yang secara implisit melinierisasi larik rk rangking yang tersisa. (seperti MATLAB):
julia> A=reshape(1:8,2,2,2); A[1,:]
1x4 Array{Int64,2}:
 1  3  5  7

julia> A=reshape(1:8,2,2,2); A[1,:,:]
1x2x2 Array{Int64,3}:
[:, :, 1] =
 1  3

[:, :, 2] =
 5  7
  • Trailing single tidak dijatuhkan dalam operasi penugasan. (Tidak seperti MATLAB)
julia> A=zeros(1); A[1] = randn(1,1)
ERROR: `convert` has no method matching convert(::Type{Float64}, ::Array{Float64,2})

You might have used a 2d row vector where a 1d column vector was required.
Note the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].
You can convert to a column vector with the vec() function.
 in setindex! at array.jl:307

julia> A=zeros(1,1); A[1,1] = randn(1)
ERROR: `convert` has no method matching convert(::Type{Float64}, ::Array{Float64,1})
 in setindex! at array.jl:308
  • Julia tidak secara otomatis menambahkan dimensi singleton trailing saat melakukannya memungkinkan untuk operasi yang valid. (Tidak seperti Matlab, yang melakukannya)
julia> 1/[1.0,] #In MATLAB, interpreted as the inverse of a 1x1 matrix
ERROR: `/` has no method matching /(::Int64, ::Array{Float64,1})
  • Produk luar berfungsi dan merupakan pengecualian dari aturan sebelumnya; semantiknya secara implisit menggunakan tanda singleton trailing di argumen pertama. (Seperti Matlab)
julia> [1:5]*[1:5]' # Shapes are (5,) and (1,5) - promoting to (5,1) x (1,5) works
5x5 Array{Int64,2}:
 1   2   3   4   5
 2   4   6   8  10
 3   6   9  12  15
 4   8  12  16  20
 5  10  15  20  25

Tampaknya hal-hal ini layak mendapatkan sedikit pembersihan, begitu kami menyimpulkan bagaimana kami ingin mereka berperilaku. Perilaku saat ini saat mengindeks dengan indeks yang terlalu sedikit di mana yang terakhir adalah potongan tampaknya sangat mencurigakan.

Wow. Contoh yang Jiahao berikan sangat mengganggu ... Saya tidak suka membuntuti lajang dalam operasi pengindeksan dan pengindeksan operasi tugas karena implikasinya dan ambiguitasnya. Jika Anda tidak menyadari perilaku ini sebelumnya, Anda bisa saja melakukan satu hal saat Anda benar-benar mencoba melakukan hal lain. Saya mendukung penggunaan bahasa yang tepat dan jelas dan menghindari jalan pintas yang ambigu.

Untuk benar-benar menerapkan ini, kita akan membutuhkan semacam pengiriman segitiga, jika tidak, saya tidak yakin bagaimana Anda akan mengekspresikan hal-hal seperti "matriks dengan entri Complex64 atau Complex128 , transposenya , atau transpos konjugatnya ". Apalagi jika kita menggunakan opsi 2 + b di atas.

@ esd100 ,

Vektor baris dalam arti yang mungkin adalah array satu dimensi, dan saya menegaskan bahwa itu harus diindeks seperti itu.

Saya yakin Anda sedikit terlalu fasih dengan pernyataan ini.

Benar! Maaf @jiahao , saya salahkan [] . Anda benar bahwa penggabungan adalah pertimbangan penting, dan menurut saya cara alami untuk melakukannya (untuk membuat matriks) cukup jelas (dengan menganggapnya sebagai ukuran 1 xn dalam contoh ini). Jelas seorang covector bukanlah "dalam segala hal" 1D Julia Array ... itulah intinya ...

Contoh jiahao juga mengganggu saya. Saya akan mendukung untuk menghapus kemungkinan perilaku tunggal yang tertinggal. Melakukan linierisasi dimensi selanjutnya mungkin berguna, tetapi juga dapat mendorong semacam kemalasan di mana Anda lupa berapa banyak dimensi yang dimiliki array Anda ... (Saya rasa inilah yang disiratkan oleh "ambigu" dan "berbahaya" ... Saya benar-benar ingin Julia melempar kesalahan ketika saya memperlakukan array 16 dimensi seperti array 15 dimensi, misalnya).

manakah dari berikut ini yang ambigu atau berbahaya?

Yang keempat tampak ambigu dan berbahaya bagi saya.

julia> A=zeros(2,2,2); A[:,:]=3; A
2x2x2 Array{Float64,3}:
[:, :, 1] =
 3.0  3.0
 3.0  3.0

[:, :, 2] =
 3.0  3.0
 3.0  3.0

Jelas (bagi saya) ini seharusnya menjadi kesalahan sintaks. A adalah peringkat-3 dan dimensi ke-3 tidak dirujuk sama sekali. Kemungkinan besar dimensi ketiga ditinggalkan karena kesalahan dan bug yang sulit ditemukan sekarang dimasukkan ke dalam kode. Saya akan berterima kasih untuk mendapatkan kesalahan pada poinnya (seperti pada IDL dan fortran).

Saya pikir yang terbaik adalah jika array hanya memungkinkan pengindeksan dengan jumlah indeks yang benar atau kasus khusus pengindeksan linier 1D (karena sangat berguna). Ini termasuk melarang lajang yang tertinggal juga.

atau kasus khusus pengindeksan linier 1D (karena sangat berguna)

Betapa mudahnya prinsip kita dijual! :)

Saya tidak pernah menyukai pengindeksan linier sebanyak itu; itu bagi saya sebagai sedikit retasan. Seringkali kita hanya menginginkan cara tercepat untuk melakukan iterasi pada sebuah array. Dan untuk semua, kecuali pengindeksan linier array padat yang sederhana bisa sangat lambat. Meskipun demikian, kami mungkin tidak dapat sepenuhnya menghilangkan pengindeksan linier (karena alasan performa, dan karena terlalu banyak memecah kode).

Ya, benar. Tetapi setidaknya pengindeksan 1D secara visual berbeda. Sedangkan mengindeks array 6D dengan 5D jauh lebih sedikit. Bagaimanapun, saya lebih suka memiliki aturan pengindeksan yang lebih ketat dan melepaskan pengindeksan linier 1D daripada pergi ke arah lain. Terutama karena seseorang dapat dengan mudah mendapatkan referensi yang dibentuk ulang ke array yang berbagi memori.

Bisakah kita menggunakan {} brackets (atau lainnya) untuk pengindeksan linier, dan menyimpan [] untuk pengindeksan multidimensi? Hanya sebuah ide...

Pada 23 Mar 2015, pada 14:36, Bob Portmann [email protected] menulis:

Ya, benar. Tetapi setidaknya pengindeksan 1D secara visual berbeda. Sedangkan mengindeks array 6D dengan 5D jauh lebih sedikit. Bagaimanapun, saya lebih suka memiliki aturan pengindeksan yang lebih ketat dan melepaskan pengindeksan linier 1D daripada pergi ke arah lain. Terutama karena seseorang dapat dengan mudah mendapatkan referensi yang dibentuk ulang ke array yang berbagi memori.

-
Balas email ini secara langsung atau lihat di GitHub https://github.com/JuliaLang/julia/issues/4774#issuecomment -84805310.

Saya juga berpikir bahwa alangkah baiknya jika kami dapat memisahkan sintaks
untuk pengindeksan linier dari sintaks pengindeksan biasa, tetapi saya setuju itu
mungkin perubahan yang sangat besar.

Meskipun masalah ini tampaknya menarik banyak perdebatan, sebagian besar pekerjaan aktual dalam meningkatkan pengindeksan telah terjadi di cukup banyak permintaan tarik selama siklus 0,4. Misalnya, sekarang kita memiliki CartesianIndex dan teman-teman, saya tidak mengerti mengapa orang perlu memisahkan sintaks untuk pengindeksan linier dan kartesian --- Anda sekarang dapat menggabungkannya (# 10524). Saya juga ingin menyingkirkan pengindeksan linier, tetapi terkadang lebih berkinerja (mungkin sebagian besar karena # 9080; enumerate dan zip mengalami masalah yang sama). Kita mungkin harus mengimplementasikan fastindex sebagai pembungkus sekitar eachindex , seperti pada # 10507.

Jika Anda tertarik untuk mengindeks aturan, alih-alih membanting masalah ini sampai mati, mari fokus pada batas yang paling menarik. Pada saat ini, itu tidak diragukan lagi # 10525. Khususnya https://github.com/JuliaLang/julia/pull/10525#issuecomment -84597488 memerlukan beberapa jenis resolusi.

@timholy Saya belum benar-benar mengikuti semua perkembangan pada pengindeksan kartesian cepat, dan baru saja melihat base / multidimensional.jl, saya melihat ada banyak metaprogramming yang terjadi. Adakah kemungkinan Anda punya waktu untuk menulis (atau memberikan ceramah JuliaCon) tentang cara kerja semua ini?

Dalam beberapa hal, tidak banyak yang perlu diketahui: sementara ada cukup banyak hal yang terjadi di bawah tenda, idenya adalah membuatnya sangat mudah digunakan. Secara harfiah

k = 0
for I in eachindex(A)
     B[k+=1] = A[I]   # B is being linearly-indexed, A is being cartesian-indexed
end

mungkin semua yang perlu Anda ketahui. (Dengan kata lain, bantuan pada eachindex mungkin merupakan semua dokumentasi yang dibutuhkan.) Namun, ternyata Anda dapat menulis sejumlah besar algoritme menggunakan beberapa ekstensi dari paradigma dasar ini; apa ekstensi itu dan mengapa mereka kuat mungkin, memang, kurang jelas.

Saya memang berencana untuk menuliskannya dalam beberapa bulan mendatang, tetapi jika orang benar-benar ingin mengetahui detailnya, mungkin pembicaraan tentang JuliaCon akan masuk akal. @Jutho atau @mbauman dapat

Saya akan menambahkan lebih banyak tentang ambiguitas, namun menurut saya beberapa diskusi lanjutan merangkum poin-poin penting tertentu. Mungkin saya lebih sensitif terhadap ambiguitas semacam ini sebagai orang luar atau karena takut, dengan risiko terdengar terlalu dramatis. Menurut pendapat saya, sejumlah latihan pemikiran yang sederhana dan penting dapat membawa Anda ke jalur di mana analisis biaya / manfaat dari kesalahan sederhana tidak sepadan.

Kita mungkin harus menerapkan fastindex sebagai pembungkus di sekitar setiap indeks, seperti di # 10507

@timholy Apakah ada alasan untuk tidak meminta eachindex mengembalikan UnitRange untuk array linier cepat? Ini masih akan menjadi tipe-stabil, dan jika pemanggil ingin memastikan mereka mendapatkan CartesianIndex, mereka dapat secara manual membuat CartesianRange (kita juga dapat menambahkan metode untuk eachindex(size(A)) karena CartesianRange tidak diekspor ).

Itulah yang awalnya dilakukannya, tapi menurut saya @Jutho mengubahnya. (Jika itu tidak benar, maka saya mungkin mengubahnya tanpa menyadarinya.) Saya berasumsi perubahan itu dimotivasi demi konsistensi (sehingga Anda dapat mengandalkan mendapatkan CartesianIndex ), yang memang memiliki arti tertentu. . Tapi seperti yang Anda tunjukkan, ada cara alternatif untuk memastikan hal ini.

@Jutho , ada pemikiran?

Saya tidak ingat mengubah eachindex , tetapi bisa jadi. Saya pasti tidak ingat alasan yang baik untuk itu, selain memiliki hasil yang konsisten terlepas dari jenis larik. Tetapi jika perbedaan antara array dengan dan tanpa pengindeksan linier yang efisien dijelaskan dengan jelas dalam dokumen, saya tidak melihat alasan mengapa eachindex tidak dapat mengembalikan rentang linier dalam kasus array dengan pengindeksan linier yang efisien.

@timholy , sebagai tanggapan atas posting Anda sebelumnya, saya tidak dapat menghadiri JuliaCon jadi jangan ragu untuk membicarakan tentang barang CartesianIndex (saya hanya memberikan beberapa sentuhan akhir). Saya sudah menantikan laporan dan video konferensi.

Sebuah pemikiran yang aneh: untuk array A dari dimensi apapun (termasuk dimensi> 2), seseorang dapat memiliki A' siklis mengubah indeks A . Jadi, A'[i, j, k] == A[j, k, i] . Ini akan mengurangi transposisi matriks biasa untuk array 2d, serta transpos biasa untuk "vektor" baris dan kolom ketika ditafsirkan seperti dalam MATLAB (yaitu sebagai array [n, 1] dan [1, n] 2d masing-masing). Dengan demikian ia tidak akan pernah memetakan kolom 2d "vektor" ke covector benar atau "vektor" baris 2d ke vektor sebenarnya. (Saya pikir properti ini bagus, tetapi yang lain mungkin tidak setuju.) Ini akan memberikan identitas A'' == A' dan v'' == v _untuk matriks dan vektor yang ditafsirkan sebagai objek array_. Mengingat jenis hierarki tipe seperti yang dibahas di atas (di mana vektor dan covectors benar cukup dibedakan dari array abstrak), ' masih dapat diberikan metode yang sama sekali berbeda untuk vektor dan covectors benar yang sesuai dengan konsep aljabar linier dan tidak perlu memenuhi v'' == v (tapi bisa jika itu yang diinginkan orang).

Untuk memperjelas: Saya tidak berpikir sejenak bahwa ' _needs_ memiliki metode apapun untuk array dimensi> 2, tapi saya belum melihat proposal ini di atas (kecuali itu yang dimaksud dengan "indeks terbalik ") dan mengira saya baru saja menyebutkannya. Kerusakan yang paling saya lihat (prima facie) adalah konseptual: menggabungkan operasi kombinatorial (sedikit sewenang-wenang) dengan operator yang biasanya diambil sebagai domain aljabar linier. Untuk yang satu ini mungkin menjawab bahwa setidaknya beberapa derajat dari penggabungan seperti itu tidak dapat dihindari ketika kita mencoba untuk memperluas konsep aljabar linier menjadi konsep yang murni data-sentris (sebagaimana dibuktikan oleh seluruh diskusi ini). Dengan demikian, kita mungkin juga menuai singkatan yang mudah digunakan untuk permutasi siklik dari array multi-dimensi sebagai produk sampingan dari menentukan apa yang harus dilakukan ' secara umum untuk dimensi array multidimensi selama itu mengurangi kasus yang diharapkan di 2 dimensi. Seseorang bahkan dapat menambahkan metode yang mengambil argumen bilangan bulat sehingga A'(k)[I] siklis mengijinkan indeks A[I] k kali, memberikan A'(ndims(A))[I] == A[I] dan A'(-k)[I] mengecilkan indeks ke arah yang berlawanan.

Hanya pemikiran saja.

Jika transpose didefinisikan untuk array multidimensi, saya lebih suka yang masih memenuhi A''=A , yaitu kebalikannya sendiri. Ini bertentangan langsung dengan proposal sebelumnya.

Itu adil. Seperti yang saya katakan, saran saya hanya (berpotensi) menarik jika seseorang merasa nyaman membiarkan keretakan tumbuh antara signifikansi aljabar linier dari transpos dan signifikansi berpusat-larik apa pun yang diterapkan dalam kasus d> 2. Alasan saya adalah bahwa selama keretakan itu sudah (jenis) terjadi, dan jika metode tidak akan digunakan sama sekali sebaliknya, akan lebih baik untuk memiliki singkatan untuk mengubah indeks - selama tidak memerlukan perlakuan khusus untuk membuat kasus d = 2 bekerja. Seperti yang Anda (@Jutho) sebutkan, itu adalah kebetulan yang nyaman bahwa mengubah dimensi dalam kasus 2d memiliki signifikansi aljabar linier yang dimilikinya (dan hanya setelah mengidentifikasi (co) vektor sebagai array 2d, dalam hal ini), jadi mungkin kita tidak tidak perlu pilih-pilih tentang properti matematika transpose (misalnya memerlukan A'' == A ) untuk d> 2. Jika seseorang ingin mengikuti rute ini, ada banyak metode yang berpotensi berguna ditugaskan, misalnya: A' berulang sekali, A'(k) berulang k kali, A'(I) untuk I::Array{Int, 1} dengan panjang <= ndims(A) siklis mengijinkan indeks yang terdaftar di I , dan A'(p) untuk p::Permutation dengan panjang <= ndims(A) mengijinkan indeks sesuai dengan p . Tapi saya kira mungkin hal terbaik untuk dilakukan adalah membuat paket dan melihat apakah itu cukup berguna untuk dipahami.

Saya mendukung dua perubahan / klarifikasi yang telah disebutkan, misalnya oleh StefanKarpinski pada 16 Okt 2014, dan simonbyrne pada 22 Mar 2015, namun dengan satu ketentuan:

  1. transpose seharusnya hanya digunakan untuk vektor dan matriks 2 dimensi, bukan untuk tensor umum.
  2. Operator * dan transpose harus menghapus dimensi singleton yang tertinggal di akhir komputasi. Jika tidak, dimensi tunggal tambahan dapat dipertahankan.

Kedua perubahan ini akan memberikan banyak kemudahan dan menyelesaikan banyak ambiguitas dalam pekerjaan aljabar linier tradisional. Mereka sengaja tidak mengatakan apa-apa tentang pengindeksan array umum atau aljabar tensor, yang dapat dipertimbangkan secara terpisah. (Secara khusus, transpose tensor harus dianggap sebagai operasi yang sepenuhnya terpisah dari transpos matriks / vektor.)

Di bawah proposal ini, ketika bekerja dengan perkalian matriks dan transpos, pada dasarnya tidak akan ada perbedaan antara vektor dan matriks satu kolom, juga tidak akan ada perbedaan yang berarti antara skalar, vektor dengan panjang 1, dan 1-kali. -1 matriks. Namun, x' akan menjadi matriks 1-kali-n, bukan vektor.

Di sisi lain, untuk tujuan menyimpan data, array dengan ukuran berapa pun dapat dibangun. Tidak ada dimensi tunggal yang akan dihapus karena konsep aljabar linier perkalian dan transpos tidak akan terlibat.

Di bawah ini adalah transkrip hipotetis sesi Julia dengan perubahan yang diusulkan.

Pertama, kita mendefinisikan skalar, dua vektor, dan matriks.

julia> alpha = 2.0
2.0

julia> x = [1.0; 2.0; 3.0]
3-element Array{Float64,1}:
 1.0
 2.0
 3.0

julia> y = [4.0; 5.0; 6.0]
3-element Array{Float64,1}:
 4.0
 5.0
 6.0

julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
3x3 Array{Float64,2}:
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

Perkalian vektor skalar dapat dilakukan meskipun terdapat dimensi asing, dan hasilnya selalu berupa vektor.

julia> alpha*x
3-element Array{Float64,1}:
 2.0
 4.0
 6.0

julia> alpha*x[:,[1]]
3-element Array{Float64,1}:
 2.0
 4.0
 6.0

Transpose adalah suatu involusi.

julia> x'
1x3 Array{Float64,2}:
 1.0  2.0  3.0

julia> x''
3-element Array{Float64,1}:
 1.0
 2.0
 3.0

julia> x==x''
true

julia> x'''
1x3 Array{Float64,2}:
 1.0  2.0  3.0

Mengalikan matriks dengan matriks satu kolom menghasilkan hasil yang identik dengan perkalian matriks-vektor.

julia> A*x
3-element Array{Float64,1}:
 14.0
 32.0
 50.0

julia> A*x[:,[1]]
3-element Array{Float64,1}:
 14.0
 32.0
 50.0

Matriks satu baris dikalikan matriks sama dengan matriks satu baris.

julia> x'*A
1x3 Array{Float64,2}:
 30.0  36.0  42.0

Hasil kali dalam adalah skalar dan dihasilkan oleh aturan yang lebih umum untuk produk matriks-vektor dan matriks-matriks.

julia> x'*y
32.0

julia> x'*y[:,[1]]
32.0

Produk luar tidak ada yang istimewa.

julia> x*y'
3x3 Array{Float64,2}:
  4.0   5.0   6.0
  8.0  10.0  12.0
 12.0  15.0  18.0

julia> x[:,[1]]*y'
3x3 Array{Float64,2}:
  4.0   5.0   6.0
  8.0  10.0  12.0
 12.0  15.0  18.0

Vektor dikali vektor adalah kesalahan.

julia> x*y
ERROR: `*` has no method matching *(::Array{Float64,1}, ::Array{Float64,1})

Vektor dikali matriks adalah kesalahan.

julia> x*A
ERROR: DimensionMismatch("*")
 in gemm_wrapper! at linalg/matmul.jl:270
 in * at linalg/matmul.jl:74

Perkalian matriks bersifat asosiatif.

julia> (x*x')*y
3-element Array{Float64,1}:
 32.0
 64.0
 96.0

julia> x'*y
32.0

julia> x*(x'*y)
3-element Array{Float64,1}:
 32.0
 64.0
 96.0

julia> norm((x*x')*y-x*(x'*y))
0.0

EDIT: Menghapus dua contoh yang melibatkan penurunan pangkat dimensi dalam dalam suatu produk. Mereka tidak banyak berpengaruh pada diskusi saat ini.

Saya khawatir ini akan kehilangan stabilitas tipe dari operasi yang terlibat, karena membuang dimensi tunggal yang tertinggal bukanlah operasi tipe stabil.

Menurut saya, keseluruhan bisnis covector adalah tentang memiliki dimensi tunggal yang diketahui berdasarkan jenisnya yang akan dihapus. Selain itu, kami telah berusaha cukup keras untuk mempertahankan perbedaan antara vektor dan matriks yang kebetulan memiliki satu kolom, tetapi saran ini akan menghapus perbedaan itu dalam beberapa kasus, seperti x'' .

Saran sesat: bagaimana jika kita menghapus dimensionalitas dari parameter tipe, dan melakukan semua pemeriksaan dimensionalitas / ukuran saat runtime? (Kami akhirnya melakukan cukup banyak hal tersebut.) Dan biarkan parameter dimensionalitas untuk tipe yang juga menyandikan ukuran sebagai parameter tipe. (Bebek, bersembunyi selama dua minggu, dan mengubah akun github-nya menjadi @SomeoneWhoCertainlyIsntTimHolyUhUhNoWay.)

(Tentu saja, saya benar-benar akan mengeluh pada diri saya sendiri karena # 10525 saja.)

FWIW, menurut saya itu bukan ide yang gila: begitulah cara kerja Torch, misalnya, dan pengembang Torch telah menyuarakan ketidakbahagiaan dengan pengkodean dimensi Julia di dalam sistem tipe.

@timholy Pertanyaan: dapatkah kita menggunakan ini untuk meningkatkan semantik mengenai aljabar linier dan transposes vektor?

Jika seseorang masih tertarik untuk menggunakan CoVector / DualVector / TransposeVector ini masih harus membungkus TimHolyArray{DataType} _and_ baru kami, kami harus memahaminya mengubah urutan array dimensi yang lebih besar dari dua (atau satu), atau melarang konstruksi TransposeVector(tharray) ketika tharray memiliki dimensi lebih besar dari dua (atau satu) ... Faktanya semua jenis Hal-hal harus memberikan kesalahan pada tingkat run-time yang saat ini merupakan kesalahan waktu kompilasi (seperti perkalian yang saat ini tidak ditentukan dan karenanya dilarang oleh sistem tipe).

Di sisi lain, mengimplementasikan flag transpose di dalam kelas baru ini mungkin buruk ... ini menambah kerumitan pada container yang seharusnya efisien dan ringan. Saya akan cenderung mengesampingkan opsi itu, dan menyerahkan kerja keras pada sistem compiler / type.

Saya tidak selalu menentang ide Anda - tetapi tampaknya ini merupakan masalah tambahan yang dapat dilakukan secara paralel dengan transposisi vektor.

@ Timholy : Saya sangat yakin apakah ini cara untuk pergi atau tidak. Ada situasi di mana saya merasa sangat berguna untuk mengirimkan dimensi.

Sarannya adalah membuat ini berlaku untuk semua larik. Tapi aku melawan proposal saya sendiri sekarang, hanya karena untuk banyak kasus multidimensi yang Anda butuhkan untuk menghasilkan N loop untuk N array dimensi. Kami tidak dapat melakukannya lagi jika N bukan merupakan parameter tipe.

Ya, bukankah ini keseluruhan inti makro Cartesian Anda (atau fungsi bertahap yang masih belum saya gunakan :-))?
Saya melakukan hal serupa di C ++ di mana sangat merepotkan untuk memiliki dimensi sebagai parameter template. Tetapi saya memiliki situasi di mana varian dinamis membatasi karena seseorang membutuhkan pernyataan if yang besar untuk mengkhususkan dimensi array yang berbeda.

Usul:

  1. Ubah nama perilaku perkalian matriks saat ini menjadi timesfast dan perilaku pengalihan saat ini menjadi transposefast .
  2. Ubah (*) dan transpose untuk memotong dimensi singleton yang tertinggal seperti pada komentar sebelumnya . Misalnya, u'*v akan menjadi skalar, v'' akan menjadi vektor, dan (v*v')/(v'*v) akan ditentukan.

Perilaku yang ada adalah tipe stabil. Perilaku yang diusulkan mengikuti konvensi banyak teks aljabar linier. Keduanya berharga. Mungkin Julia harus memiliki keduanya.

Saya ingin menggunakan Julia di ruang kelas, jadi saya memilih perilaku default untuk menghargai kenyamanan daripada efisiensi.

Terima kasih kepada beberapa kontributor yang telah membantu saya memahami utas yang sangat panjang ini!

@ Briansutton : Saya pikir Anda harus benar-benar mempertimbangkan kembali apa yang Anda minta. Saya akan mendorong Anda untuk menunggu sampai Anda memiliki pemahaman yang lebih dalam tentang cara kerja Julia sebelum mengusulkan agar kami mendefinisikan kembali arti perkalian.

Masalah ini adalah tentang bagaimana kita dapat menghindari kasus khusus sebanyak mungkin.

Aturan yang memungkinkan pemalsuan dimensi tunggal rusak saat salah satu dimensi tunggal adalah yang benar-benar Anda pedulikan. Dengan aturan "truncate [semua] jejak dimensi tunggal", maka jika v adalah vektor 1 elemen, maka v' adalah skalar, sehingga v'' juga merupakan skalar. Jadi, bahkan dalam proposal ini properti yang v == v'' tidak selalu dimiliki.

Anda dapat mencoba mengubah aturan untuk "memotong hanya dimensi tunggal terakhir yang tertinggal jika larik memiliki dimensi 2". Tetapi bahkan dengan aturan yang dimodifikasi ini, hasil luar v * w' tidak mengikuti secara otomatis dari definisi perkalian matriks, tetapi harus menjadi definisi kasing khusus Vector * Matrix , dan definisi harus menjadi "melempar kesalahan kecuali bentuknya adalah (N) x (1, M)".

@jiahao :

Saat mengerjakan aljabar linier dengan vektor dan matriks, saya tidak ingin membuat perbedaan antara skalar, vektor 1 elemen, dan matriks 1-kali-1. Saat ini, berbagai operasi menghasilkan salah satu dari tiga objek tersebut. Saran saya adalah, untuk operasi perkalian matriks dan transpose, pilih salah satu dari tiga yang akan menjadi representasi yang disukai.

Mengenai contoh pertama Anda ( v==v'' ), saya ingin menghindari pembuatan vektor 1-elemen v .

Mengenai contoh kedua Anda, ya, menurut saya v*w' harus ditangani seperti yang Anda gambarkan. Saat bekerja dengan perkalian matriks dan transpos, saya ingin vektor v dan matriks N-by-1 v[:,[1]] untuk menunjukkan objek matematika yang sama, meskipun mereka memiliki representasi internal yang berbeda. Ini akan membutuhkan kode khusus untuk menangani matriks N-vektor dikali 1-oleh-M.

Saya kira Anda masih belum yakin bahwa stabilitas tipe itu penting.

@briansutton : Saya rasa Anda akan merasa sangat informatif untuk mencoba menerapkan mesin yang diperlukan agar proposal Anda berjalan secepat sistem jenis saat ini mengizinkan kode Julia untuk dijalankan. Saya, untuk satu, percaya bahwa tujuan yang Anda nyatakan tidak dapat dicapai mengingat tujuan Julian memberikan kinerja yang dapat diprediksi dan kompatibilitas tata letak memori C.

Saya tidak yakin apakah saya memahami argumen bolak-balik, namun ada satu hal yang menarik perhatian saya. Mungkin angan-angan, tapi alangkah baiknya jika komputer bisa berpikir secepat otak manusia. Yang saya maksud adalah ketika Brian Sutton berbicara tentang program "memilih representasi yang disukai", saya membayangkan sebuah program yang dapat berpikir, seperti yang kita bisa, ketika kita mengerjakan matematika. Mungkin, itu tidak layak dengan teknologi saat ini dan akan terlalu memperlambat segalanya. Tapi, bukankah itu menyenangkan ...

Saya seorang fisikawan dan pengguna aktif Julia.

Saya tidak lagi memiliki preferensi kuat dalam menjaga cuaca atau membuang semua dimensi tunggal yang tertinggal

Namun di sini saya ingin mengangkat masalah yang terkait erat.

Implementasi Julia saat ini:

Misalkan V adalah tensor peringkat 1 3-dim (vektor)
V [1] akan memberi kita scaler, bukan tensor peringkat 1-dim

Misalkan A adalah tensor peringkat-3 3x4x5
B = A [1,:,:] akan memberi kita tensor rank-3 1x4x5.

Kedua perilaku di atas tidak cukup konsisten.

Saya sangat menyukai fitur pengindeksan / geser berikut:

Misalkan A adalah tensor peringkat-3 3x4x5
B = A [1,:,:] akan memberi kita tensor rank-2 4x5.
C = A [1: 1,:,:] akan memberi kita tensor rank-2 1x4x5.
(saat ini dua di atas memberikan hasil yang sama)

Misalkan V adalah tensor peringkat-1
B = V [1] akan memberi kita scaler
C = V [1: 1] akan memberi kita tensor peringkat 1-dim.

Fitur ini akan membantu kita mengubah bentuk tensor dengan lebih mudah, dan akan berguna jika kita mengizinkan indeks tunggal yang tertinggal.

Terbaik

Xiao-Gang


Dari: esd100 [[email protected]]
Dikirim: Selasa, 09 Juni 2015 21.46
Kepada: JuliaLang / julia
Cc: Xiao-Gang Wen
Subject: Re: [julia] Menyikapi transposisi vektor dengan serius (# 4774)

Saya tidak yakin apakah saya memahami argumen bolak-balik, namun ada satu hal yang menarik perhatian saya. Mungkin angan-angan, tapi alangkah baiknya jika komputer bisa berpikir secepat otak manusia. Yang saya maksud adalah ketika Brian Sutton berbicara tentang program "memilih representasi yang disukai", saya membayangkan sebuah program yang dapat berpikir, seperti yang kita bisa, ketika kita mengerjakan matematika. Mungkin, itu tidak layak dengan teknologi saat ini dan akan terlalu memperlambat segalanya. Tapi, bukankah itu menyenangkan ...

-
Balas email ini secara langsung atau lihat di Gi tHubhttps: //github.com/JuliaLang/julia/issues/4774#issuecomment -110554622.

Maksud saya: C = A [1: 1,:,:] akan memberi kita tensor rank-3 1x4x5.

Xiao-Gang


Dari: Xiao-Gang Wen [[email protected]]
Dikirim: Senin, 22 Juni 2015 12:01
Kepada: JuliaLang / julia; JuliaLang / julia
Cc: Xiao-Gang Wen
Subjek: RE: [julia] Menyikapi transposisi vektor dengan serius (# 4774)

Saya seorang fisikawan dan pengguna aktif Julia.

Saya tidak lagi memiliki preferensi kuat dalam menjaga cuaca atau membuang semua dimensi tunggal yang tertinggal

Namun di sini saya ingin mengangkat masalah yang terkait erat.

Implementasi Julia saat ini:

Misalkan V adalah tensor peringkat 1 3-dim (vektor)
V [1] akan memberi kita scaler, bukan tensor peringkat 1-dim

Misalkan A adalah tensor peringkat-3 3x4x5
B = A [1,:,:] akan memberi kita tensor rank-3 1x4x5.

Kedua perilaku di atas tidak cukup konsisten.

Saya sangat menyukai fitur pengindeksan / geser berikut:

Misalkan A adalah tensor peringkat-3 3x4x5
B = A [1,:,:] akan memberi kita tensor rank-2 4x5.
C = A [1: 1,:,:] akan memberi kita tensor rank-2 1x4x5.
(saat ini dua di atas memberikan hasil yang sama)

Misalkan V adalah tensor peringkat-1
B = V [1] akan memberi kita scaler
C = V [1: 1] akan memberi kita tensor peringkat 1-dim.

Fitur ini akan membantu kita mengubah bentuk tensor dengan lebih mudah, dan akan berguna jika kita mengizinkan indeks tunggal yang tertinggal.

Terbaik

Xiao-Gang


Dari: esd100 [[email protected]]
Dikirim: Selasa, 09 Juni 2015 21.46
Kepada: JuliaLang / julia
Cc: Xiao-Gang Wen
Subject: Re: [julia] Menyikapi transposisi vektor dengan serius (# 4774)

Saya tidak yakin apakah saya memahami argumen bolak-balik, namun ada satu hal yang menarik perhatian saya. Mungkin angan-angan, tapi alangkah baiknya jika komputer bisa berpikir secepat otak manusia. Yang saya maksud adalah ketika Brian Sutton berbicara tentang program "memilih representasi yang disukai", saya membayangkan sebuah program yang dapat berpikir, seperti yang kita bisa, ketika kita mengerjakan matematika. Mungkin, itu tidak layak dengan teknologi saat ini dan akan terlalu memperlambat segalanya. Tapi, bukankah itu menyenangkan ...

-
Balas email ini secara langsung atau lihat di Gi tHubhttps: //github.com/JuliaLang/julia/issues/4774#issuecomment -110554622.

Apa yang Anda minta adalah bagaimana slice saat ini bekerja. Menurut saya, A[stuff] akan menjadi sinonim untuk slice(A, stuff) , dan dengan demikian keinginan Anda mungkin akan tercapai.

Tim yang terhormat:

Terima kasih atas tipnya. Saya telah mencoba slice. Itu tidak sesuai dengan kebutuhan saya. Slice menghasilkan tipe data baru "subarray" yang tidak dapat saya gunakan dalam kode lain yang menggunakan :: Tipe data array.

Mungkin saya bisa mengubah kode saya yang lain sehingga mereka mengizinkan tipe data "subarray".

Xiao-Gang


Dari: Tim Holy [[email protected]]
Dikirim: Senin, 22 Juni 2015 17.32
Kepada: JuliaLang / julia
Cc: Xiao-Gang Wen
Subject: Re: [julia] Menyikapi transposisi vektor dengan serius (# 4774)

Yang Anda minta adalah cara kerja slice saat ini. Saya rasa bahwa A [barang] akan menjadi sinonim untuk slice (A, barang), dan Anda mungkin akan mendapatkan keinginan Anda.

-
Balas email ini secara langsung atau lihat di Gi tHubhttps: //github.com/JuliaLang/julia/issues/4774#issuecomment -114268796.

Apakah ada yang benar-benar bergantung pada penggunaan tipe konkret Array daripada AbstractArray dalam kode Anda? Mungkin memerlukan tidak lebih dari pencarian / penggantian Array dengan AbstractArray untuk membuat semuanya bekerja.

Scott terkasih

Terima kasih banyak atas tipnya.

Xiao-Gang


Dari: Scott P. Jones [[email protected]]
Dikirim: Kamis, 25 Juni 2015 09.55
Kepada: JuliaLang / julia
Cc: Xiao-Gang Wen
Subject: Re: [julia] Menyikapi transposisi vektor dengan serius (# 4774)

Apakah ada sesuatu yang benar-benar bergantung pada penggunaan tipe Array konkret daripada AbstractArray dalam kode Anda? Ini mungkin memerlukan tidak lebih dari pencarian / penggantian Array dengan AbstractArray untuk membuat semuanya bekerja.

-
Balas email ini secara langsung atau lihat di Gi tHubhttps: //github.com/JuliaLang/julia/issues/4774#issuecomment -115265047.

Apakah itu berhasil untuk Anda? Saya senang membantu!

@wenxgwen , sebagai alternatif, Anda dapat memanggil copy(slice(A,...)) untuk mendapatkan salinan potongan di Array yang kemudian akan bekerja secara native dengan fungsi yang sudah ada.

Memperbaiki masalah ini sekarang telah menjadi upaya yang menguntungkan

Sejak memperbaiki masalah ini sekarang penting di jalan saya ke 3 koma ...
image

Tapi dengan serius. Saya mencoba membaca diskusi sepenuhnya tetapi saya tidak dapat menjamin bahwa ini belum pernah disarankan sebelumnya:

Bisakah kita memperluas definisi AbstractArray agar memiliki sifat tambahan (mirip dengan LinearIndexing?) Yang menentukan apakah data yang mendasarinya adalah penyimpanan berbasis baris atau kolom? Penambahan ini akan membuka properti berikut (harap jangan fokus pada nama ... hanya konsep):

v --> length-2 Vector{Col}
  [ 1
    2 ]

v'  --> length-2 Vector{Row}
  [ 1 2 ]

m --> 2x2 Matrix{Col}
  [ 1 3 
    2 4 ]

m' --> 2x2 Matrix{Row}
  [ 1 2 
    3 4 ]

Some operations:
v'  --> length-2 Vector{Col}
v'' == v
v*v or v'*v'  --> either error, or do element-wise multiplication
v' * v --> scalar
v * v' --> 2x2 Matrix  (could be Row or Col??)
v' * m --> 2-length Vector{Row}
v * m --> either error or broadcasting operation
m * v --> either error or broadcasting operation
m * v' --> 2-length Vector{Col}

Indexing:
v[2] --> 2
v[1,2] --> error
v'[1,2] --> 2
m[1,2]  --> 3
m'[1,2]  --> 2

Size:
length(v)  --> 2
length(v')  --> 2
size(v)  --> (2,)
size(v')  --> (2,)
length(m)  --> 4
size(m)  --> (2,2)

Jelas proposal ini kehilangan banyak definisi, tapi mungkin bisa memulai pembahasan. Dapatkah kami memiliki dukungan untuk penyimpanan indeks kolom dan indeks baris pada saat yang sama, dan "memperbaiki" beberapa masalah selama proses tersebut?

Saya sangat berharap Julia adalah penyimpanan berbasis baris, karena memang begitulah cara saya memikirkan loop dan banyak operasi lainnya. (dan saya tidak berpikir saya satu-satunya yang berpikir seperti ini) Tolong beri komentar!

Ini adalah pemikiran yang menarik, meminta konstruktor juga mengambil baris atau kolom. Saya pikir ini telah dibahas sebelumnya di suatu tempat jauh di dalam sistem masalah GitHub. Saya bisa saja salah!

Saya pribadi lebih suka penyimpanan berbasis kolom karena sebagian besar buku teks saya menggunakan kolom untuk matematika mereka dan kemudian di Julia saya tidak perlu mengubah semuanya untuk menggunakan baris sebagai gantinya. Saya juga merasa aneh pada awalnya tetapi dengan cepat menjadi bukan masalah untuk pekerjaan saya. Ada algoritme yang lebih mudah diekspresikan dalam baris, namun itulah mengapa ini bagus untuk dapat menggunakan penyimpanan non-standar saat diperlukan. Saya berharap bahwa konvensi akan selalu mengembalikan matriks utama kolom atau vektor kolom ketika Anda memiliki fungsi yang diekspor sedemikian rupa sehingga tidak pernah ada pertanyaan tentang jenis apa yang Anda miliki saat memanggil fungsi. Jika tidak, itu bisa menjadi sangat berantakan dan menjadi tidak menyenangkan untuk digunakan ketika Anda harus selalu mencari jenis apa yang dikembalikan.

Berbasis kolom vs berbasis baris tidak berada dalam cakupan masalah ini.

@tbreloff Saya sangat menyukai ide itu. Akan sangat bagus untuk dapat lebih mudah berinteraksi dengan bahasa / pustaka yang merupakan baris utama.

Jiahao benar bahwa lebih memilih baris-mayor vs kolom-mayor adalah di luar topik. Nya
hanya efek samping yang bagus yang memecahkan masalah transpos dengan cara "julian"
(tipe parametrik dan fungsi bertahap) memberi orang lebih banyak fleksibilitas
format penyimpanan.

Jika Anda tidak menyukai gagasan menambahkan sifat baris / kolom ke array, maka
hal yang sama persis dapat dilakukan dengan TransposeView {T, N}, tapi saya
menduga akan lebih rumit untuk diterapkan dengan baik.

Kerugian terbesar dari sifat tambahan adalah kebingungan bagi pengguna baru,
dan itu adalah sesuatu yang sulit saya rujuk.

Pada hari Sabtu, 26 September 2015, Scott P. Jones [email protected]
menulis:

@tbreloff https://github.com/tbreloff Saya sangat menyukai ide itu. Itu
akan lebih baik jika dapat lebih mudah berinteraksi dengan bahasa / perpustakaan
itu baris-mayor.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment -143436947.

Apakah call-overloading mengubah ruang desain sama sekali? Kadang-kadang di atas tampaknya ada semacam ambiguitas dalam arti * . Khususnya, ketika kita ingin v::Covector * w::Vector mengembalikan skalar, apakah kita mengambil * sebenarnya untuk menjadi "map w bawah v " daripada perkalian matriks? Jika demikian, maka tidak bisakah orang yang sama menuntut agar w::Vector * v::Covector mengembalikan skalar, karena vektor itu sendiri adalah peta linier di atas covectors?

Mungkin akan lebih membantu daripada membebani call dan menulis v(w) untuk menunjukkan operasi "peta di bawah v " pada w , dan juga untuk w(v) - keduanya akan mengembalikan skalar. Apakah ini akan memungkinkan lebih banyak kelonggaran dalam mengakomodasi semantik yang dimiliki oleh operasi array dan operasi aljabar linier dalam kasus array 2d?

Jika demikian, maka tidak bisakah orang meminta agar w :: Vector * v :: Covector mengembalikan skalar, karena vektor itu sendiri adalah peta linier di atas covectors?

Saya pikir kami mencoba mengikuti konvensi matriks dan vektor yang banyak dilihat orang di universitas tahun pertama, yang non-komutatif dan memiliki vektor * vektor yang dialihkan -> matriks (dari peringkat-1, yaitu hanya memiliki satu (bukan nol) tunggal nilai). Apa yang Anda tulis terdengar lebih seperti konsep aljabar linier abstrak, di mana vektor dan co / vektor ganda adalah peta dari satu sama lain ke beberapa skalar, yang baik-baik saja tetapi sedikit berbeda dengan apa yang (IMHO) dicoba di Julia dan MATLAB. Saya pikir kita bisa menafsirkan apa yang Anda tulis sebagai produk dalam, dot() atau bekerja pada dua covectors (yang mungkin kami _should_ definisikan untuk covectors, saya rasa), tapi terkadang kita juga menginginkan outer -produk, dan saat ini non-kumutatif * memungkinkan kita untuk menulis dan mengekspresikan kedua perilaku.

Adapun konvensi panggilan v(w) , kita bisa juga mengatakan untuk produk titik kita menginginkan jumlah v ke arah w yang menyarankan kita menggunakan operator pengindeksan v[w] . (BTW, saya tidak mengatakan ini adalah pilihan desain bahasa yang bagus - hanya observasi!)

kita bisa juga mengatakan untuk produk titik kita menginginkan jumlah v ke arah w yang menyarankan kita menggunakan operator pengindeksan v[w] .

Saran ini hampir, tetapi tidak, sesuai dengan semantik pengindeksan. Ini juga bertentangan dengan dukungan kami saat ini untuk pengindeksan vektor jika v adalah Vector{<:Integer} .

Pertimbangkan bahwa untuk v :: Vector{T<:Real} , v[1] setara dengan produk titik v⋅e₁ , di mana e₁ adalah vektor basis kanonis sepanjang sumbu pertama. Oleh karena itu, pengindeksan sederhana benar-benar fungsinya

   v[n] : n :: Integer --> y = (v ⋅ eₙ) :: T

Untuk pengindeksan vektor, v[[1, 2]] menghasilkan [v⋅e₁, v⋅e₂] yang merupakan hasil dari memproyeksikan v ke dalam subruang yang direntangkan oleh {e₁, e₂} , atau setara dengan hasil dari v' * [e₁ e₂] .

Jadi pengindeksan vektor adalah fungsinya

   v[I] : I :: Vector{<:Integer} --> y = v' * [eₙ for n in I] :: Vector{T}

Proposal untuk menghasilkan v[w] = (w ⋅ v) v tidak konsisten dengan definisi ini karena menghilangkan pemetaan implisit dari kumpulan indeks n (sebagaimana ditentukan oleh w ) ke kumpulan vektor basis kanonis eₙ , yang diperlukan agar aturan pengindeksan kami saat ini berfungsi.

Membatasi ruang lingkup hanya untuk transpose vektor untuk saat ini, saya pikir kami memiliki dua opsi. Kami dapat membuatnya menjadi kesalahan atau kami dapat memperkenalkan jenis covector khusus. Mengingat sifat vektor kelas satu di Julia, saya pikir yang pertama akan menjadi penjualan yang sangat sulit… dan untuk melakukannya secara konsisten kita mungkin harus sepenuhnya melarang vektor berpartisipasi dalam aljabar matriks sepenuhnya.

Jadi saya mencoba covector. Ini banyak pekerjaan, dan sayangnya saya tidak akan bisa menghabiskan lebih banyak waktu untuk itu. Saya mempostingnya di sini dengan harapan seseorang akan menjalankannya atau kami akan belajar dari kesulitan dan memutuskan untuk melarikan diri. Tapi saya memiliki gedung cabang dengan transposes sebagai view, dan perkalian matriks diimplementasikan dengan covectors. Beberapa tes terpilih lulus, tetapi hanya tanpa depwarn=error (mis., ./julia -e 'using Base.Test; include("test/matmul.jl")' ). https://github.com/JuliaLang/julia/compare/mb/transpose

Saya mendefinisikan dua tipe tampilan baru yang akan digunakan untuk transpose dan ctranspose matriks dan vektor:

immutable MatrixTranspose{C,T,A} <: AbstractArray{T,2}
    data::A # A <: AbstractMatrix{T}
end
immutable Covector{C,T,V} 
    data::V # V <: AbstractVector{T}
end

Parameter C adalah boolean sederhana untuk merepresentasikan apakah transpose adalah transpose atau tidak. Perhatikan bahwa Covector _bukan_ subtipe dari AbstractArray ; ini adalah persyaratan yang cukup kuat agar pengiriman berfungsi secara wajar.

Beberapa kelemahan:

  • Sampul jelas rumit, dan akan menjadi tantangan untuk mendokumentasikan dengan cara yang mudah diakses dan ketat. Bahasa mungkin bisa membantu di sini - kita cukup menyebutnya RowVector s. Terlepas dari itu, kesulitan pertama yang Anda temui ketika mencoba menjelaskan perilaku ini adalah bagaimana Anda berbicara tentang bentuk covector ( size tidak ditentukan). Jika (m,n) adalah bentuk matriks, maka (m,) dapat mewakili bentuk vektor… dan jika kita menyalahgunakan notasi tuple, kita dapat mendeskripsikan covector dengan bentuk (,n) . Hal ini memungkinkan kita untuk mengekspresikan aturan aljabar vektor / matriks campuran dengan dimensi "hilang" yang menggabungkan dan menyebar secara masuk akal:

    • Matriks * Vektor adalah (m,n) × (n,) → (m,)

    • Covector * Matrix adalah (,m) × (m,n) → (,n)

    • Vector * Covector adalah (n,) × (,n) → (n,n)

    • Covector * Vector adalah (,n) × (n,) → α (skalar)

  • Jumlah operasi dan jenis biner di sini menyebabkan ledakan kombinatorial yang sangat besar dalam jumlah metode yang perlu ditentukan… hanya untuk perkalian yang kita miliki:

    • Mutasi: (Mutasi, tidak bermutasi)
    • Ubah urutan: (A, Aᵀ, Aᴴ) × (B, Bᵀ, Bᴴ).
    • Bentuk: (Mat × Mat; Vec × Mat; Mat × Vec, Vec × Vec). Perhatikan bahwa tidak semua ini didukung di semua kombinasi transpos, tetapi sebagian besar didukung.
    • Implementasi: (BLAS, Strided, generik, plus spesialisasi untuk matriks struktural)

    Meskipun beberapa dari operasi ini selaras dengan baik dengan beberapa perilaku pengiriman dan fallback, ini masih berupa sejumlah _huge_ metode untuk setiap operator. Menghapus sepenuhnya dukungan matriks campuran / vektor di sini pasti akan membantu menyederhanakan banyak hal.


  • Mereka tidak segera menyelesaikan kesulitan apa pun dengan menjatuhkan semua dimensi skalar. Mendukung segala jenis transpos vektor saat kita melepaskan dimensi skalar menempatkan kita di wilayah yang ambigu sehubungan dengan konjugasi kompleks (lihat https://github.com/JuliaLang/julia/pull/13612). Mungkin kita bisa memiliki A[1,:] mengembalikan covector, tetapi itu tidak menggeneralisasi dengan baik dan akan sangat aneh untuk mengembalikan non-AbstractArray dari sebuah slice. Akan sangat bagus jika orang dapat mencoba # 13612 dan secara khusus mencari kasus di mana transpos konjugat vektor menyebabkan masalah - itu akan sama buruknya dengan semantik transpos vektor saat ini dan tidak memerlukan Covectors untuk mengekspos.

Beberapa keuntungan:

  • Menggunakan pengiriman secara langsung alih-alih penguraian khusus ke Ax_mul_Bx adalah kemenangan besar. Ini disusun dengan sangat baik dengan BLAS 'API. Secara umum Anda ingin melakukan konjugasi pada tingkat paling dalam dari algoritme, jadi lebih masuk akal untuk menyimpan informasi ini dengan argumen. Untuk panggilan BLAS, fungsi sederhana dapat digunakan untuk mencari karakter transpose ( ntc ).
  • Perkalian antara vektor dan covectors sekarang bersifat asosiatif karena v'v mengembalikan skalar. Anda sekarang dapat mengevaluasi v'v*v dari kiri ke kanan dan menghindari pembentukan matriks.
  • Hal ini memungkinkan penghapusan Vector * Matrix, yang hanya berfungsi jika Anda memperlakukan semua vektor seolah-olah mereka memiliki dimensi tunggal yang tertinggal… dan ini merupakan langkah yang bagus untuk sepenuhnya menghapus dukungan untuk jejak dimensi tunggal secara umum.

Catatan lain:

  • Memiliki kompleksitas transpos yang diwakili oleh parameter tipe Boolean berfungsi dengan baik, tetapi saya sering merasa seperti saya telah menentukan parameter dalam urutan yang salah. Jarang sekali saya benar-benar ingin membatasi atau menangkap T dan C . Saya tidak yakin apakah melakukannya dengan cara lain akan lebih baik dalam hal jumlah placeholder typevars yang perlu Anda definisikan, tetapi paling tidak akan cocok dengan AbstractArray{T} .
  • Ini benar-benar memperburuk kesulitan StridedArray. Membaca tabel metode untuk * cukup menantang dengan tipe seperti ::Union{DenseArray{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},2},MatrixTranspose{C,T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},A<:Union{DenseArray{T,1},DenseArray{T,2},SubArray{T,1,A<:DenseArray{T,N},I<:Tuple{Vararg{Union{Colon,Int64,Range{Int64}}}},LD},SubArray{T,2,A<:DenseArray{T,N},I<:Tuple{Vararg{Union{Colon,Int64,Range{Int64}}}},LD}}},SubArray{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},2,A<:DenseArray{T,N},I<:Tuple{Vararg{Union{Colon,Int64,Range{Int64}}}},LD}} . Tentu, saya telah menulisnya sebagai typealias, tetapi bahkan hanya mengelola semua jenis nama alias yang berbeda ini sangat merepotkan ( StridedMatOrTrans , QRCompactWYQorTranspose , dll.).
  • Saya tidak memiliki kesempatan untuk mengintegrasikan ini dengan SparseVector, tetapi itu akan menjadi kemenangan besar karena akan mewakili transpose secara efisien tanpa memerlukan CSR.
  • Apakah kita perlu mendefinisikan pengindeksan skalar dan / atau non-skalar di Covectors? Jika ya, apa hasil dari r[:] atau r[1:end] ? Apakah itu vektor atau covector? Saya pikir saya akan mencoba melarikan diri tanpa menjelaskan ini jika kita bisa. Menariknya, Matlab memiliki aturan yang sangat khusus untuk mengindeks baris-vektor dengan vektor lain - mereka berusaha sangat keras untuk mempertahankan keributan mereka dengan mengorbankan beberapa kasus sudut aneh ( r((1:end)') adalah r(1:end) adalah r(:)' ). Saya memiliki pengindeksan skalar yang ditentukan di cabang saya untuk saat ini, tetapi mungkin itu juga harus dihapus. Itu akan memperjelas bahwa Covector hanya digunakan dengan operasi aljabar linier yang mengetahuinya.

Terakhir, saya hanya ingin menunjukkan bahwa sebagian besar keuntungan yang saya lihat di sini dapat diterapkan dengan sendirinya untuk tipe MatrixTranspose . Saya pikir ini menunjukkan bahwa Covector dapat bekerja dengan cukup baik tanpa menggali terlalu jauh ke dalam aljabar abstrak untuk mengaktifkan operasi Vektor / Matriks campuran. Ini pasti menambahkan fitur yang bagus (kemampuan untuk menggunakan Vektor secara konsisten dengan aljabar linier), tetapi saya tidak yakin itu sepadan dengan kerumitan tambahannya.

Karena penasaran, jika masih ingat @mbauman , apa yang memotivasi Anda untuk memperkenalkan parameter boolean C ? Tidak bisakah kamu memiliki (dalam pseudotraits)

transpose(::Matrix) -> MatrixTranspose
transpose(::MatrixTranspose) -> Matrix

? Saya tidak meragukan penilaian (luar biasa) Anda di sini, hanya ingin memahami kesadaran apa yang memaksa Anda untuk melakukan ini.

Agaknya seseorang dapat menggeneralisasi ini menjadi tipe PermutedDimensionArray , dengan parameter tuple yang mengkodekan permutasi. Jenis Covector jelas memiliki tujuan yang berbeda dan perlu menjadi hal yang terpisah.

Anda memerlukan beberapa cara untuk menangani transposes konjugasi (dan juga array konjugasi yang tidak ditransposisikan untuk (A').' ). Saya melihat tiga cara yang jelas untuk melakukan ini:

  • Simpan konjugasi sebagai bidang boolean hanya dalam satu tipe MatrixTranspose . Setelah direnungkan, saya pikir ini jelas merupakan pilihan terbaik untuk berinteraksi dengan BLAS eksternal. Dalam hal JuliaBLAS asli, saya ingin memastikan Julia / LLVM dapat menarik T.isconjugate ? conj(T[i,j]) : T[i,j] dari pengulangan.
  • Satu jenis dengan parameter konjugasi. Inilah yang saya pilih, dan saya rasa saya dipengaruhi oleh fakta bahwa saat ini kami melakukan pseudo-dispatch pada konjugasi dengan cara Ac_mul_Bt dan teman-teman. Ia juga memiliki jaminan yang lebih kuat tentang pengoptimalan pemindahan cabang yang dapat dilakukan Julia. Tapi saya tidak berpikir keras tentang itu… Saya hanya ingin memulai implementasi sketsa, dan saya lebih peduli tentang Covector.
  • Dua jenis terpisah, MatrixTranspose dan MatrixCTranspose . Isomorfik ke parameter tipe, tetapi saya menemukan dua jenis pembungkus terpisah mengganggu. Supertipe abstrak dan alias gabungan dapat membantu, tetapi saya tetap memilih parameter di atas opsi ini.

Saya kira sekarang ada opsi keempat dengan fungsi yang diketik, menyimpan fungsi transformasi apa pun dalam tipe transpose… tetapi itu juga memerlukan parameter tipe agar fungsinya cepat, dan itu kemudian merupakan parameter tipe yang tidak mudah dikirim, juga.

Saya ingin tahu apakah kita dapat memiliki pembungkus ConjugateView , dengan aturan conj dan transpose memastikan bahwa ConjugateView ditempatkan di dalam pembungkus MatrixTranspose . Yaitu, untuk A a Matrix ,
A' = conj(transpose(A)) = transpose(conj(A)) semua menghasilkan MatrixTranspose{ConjugateView{Matrix}} (menghilangkan parameter tipe yang tidak informatif).

Ah, ya, itu juga masuk akal. Saya cenderung menganggap transpos konjugat sebagai satu "benda" atom, jadi saya melewatkan opsi itu. Saya berpikir tentang bagaimana transposes non-konjugasi dapat diwakili oleh tipe indeks subarray khusus, seperti bentuk ulang.

Saya senang kalian masih mengerjakan ini! Ini adalah utas yang luar biasa! Tiga sorakan !!!

Apakah ini direncanakan untuk 1.0?

Dalam dua masalah (# 18056, # 18136) saya diarahkan ke utas raksasa ini.
Jadi saya mencobanya.

Sekarang Julia memiliki vektor 1 dimensi yang sebenarnya, _misalnya_ mx[row,:] bukan lagi matriks 1xn.
Ini adalah perubahan yang disambut baik!

Namun sebagai efek sampingnya, beberapa masalah yang ada menjadi lebih jelas.
Saya digigit oleh fakta bahwa v*mx tidak berfungsi untuk vektor 1 dimensi.
Secara matematis itu seharusnya bekerja dan mengembalikan vektor 1-d,
ketika produk a*b ditentukan oleh kontrak
indeks terakhir dari istilah pertama dan indeks pertama dari istilah kedua.

Saat ini tanda tangan metode dari produk Vector-Matrix adalah:
(*)(A::AbstractVector, B::AbstractMatrix) = reshape(A,length(A),1)*B
dan metode ini digunakan untuk kasus v*v' dan bukan untuk v*mx .
(Terima kasih @andreasnoack karena telah menunjukkan hal ini.)
Jelas, satu metode tidak dapat digunakan untuk keduanya.

Tampaknya Julia sedang berjuang dengan beberapa kesepakatan seperti Matlab.
Namun di Matlab tidak ada vektor 1-d, hanya matriks 1xn dan nx1,
begitu banyak hal alami yang bisa menjadi masalah di sini.
Julia memiliki vektor 1-d yang sebenarnya yang seharusnya menjadi keuntungan besar.
Akan menyenangkan mencapai keadaannya sendiri yang benar-benar konsisten.

Fortran adalah contoh yang jauh lebih baik dan lebih konsisten untuk diikuti dalam kasus ini.
Operasi transpose ditentukan hanya untuk matriks di Fortran,
membuat matriks 1xn dari vektor 1-d yang sebenarnya bukanlah transpose.
Untuk matmul lihat kutipan dari buku Metcalf yang dikutip di # 18056.

Saya rasa sebagian besar poin asli @alanedelman benar.

Jadi inilah saran yang hanya akan menyembuhkan beberapa masalah yang ada,
sambil menghormati keadaan saat ini sebanyak mungkin:

  • simpan v' seperti untuk membuat matriks 1xn dari vektor 1-d yang sebenarnya v
  • Fungsi rowmx dan colmx akan lebih baik, tetapi v' terlalu luas untuk mengubahnya
  • kita sudah memiliki fungsi vec untuk membuat vektor 1-d yang sebenarnya
  • meskipun kebalikan dari v' bukanlah v'' tetapi vec(v') , kita dapat menerimanya
  • produk a*b harus selalu berkontraksi dengan indeks terakhir a dan indeks pertama b
  • operator * tidak boleh digunakan baik untuk produk dalam maupun luar
  • untuk produk dalam kita sudah memiliki fungsi dot
  • untuk produk luar penggunaan * harus dihilangkan (_yaitu sintaks v*v' )
  • untuk produk luar fungsi baru harus digunakan
  • operator infix yang sesuai dapat menjaga sintaks tetap ringan

Kehilangan [sintaks matematika ringkas untuk] produk luar akan sangat disayangkan. Saya lebih suka menyerah vec * mat secara pribadi.

Bisakah PernutedDimsArray yang ada sudah menangani kasus di mana induk dan tampilan memiliki jumlah dimensi yang berbeda? Jika demikian, mungkin itu sudah dapat digunakan sebagai jenis pembungkus transpos non-konjugasi bahkan untuk induk vektor.

Saya tidak menemukan PermutedDimsArray di dokumentasi.

Tapi saya merasa bahwa alih-alih menemukan lebih banyak tipe data,
hanya tiga jenis produk larik yang harus dipisahkan dengan jelas.
Produk batin sudah terpisah.
Kami hanya perlu memisahkan produk normal dan luar.
Produk luar tidak akan hilang, hanya sintaksnya yang akan berubah.
Harap pertimbangkan kasus v*mx hanya sebagai gejala dari masalah yang lebih dalam.

Selain dari "masalah metode yang hilang", ini bukan tipe yang harus Anda khawatirkan, ini akan menjadi detail implementasi yang .' mengembalikan jenis pembungkus malas (dan ' versi konjugasi daripadanya). Kalau tidak, saya tidak berpikir kita bisa memiliki vec*mat dan vec*vec' keduanya menggunakan operator * . Jika saya melihat vec*mat di koran, itu akan terlihat salah bagi saya, tetapi saya cukup sering melihat vec*vec' .

Berpikir lebih banyak tentang itu, saya percaya PermutedDimsArray tidak secara rekursif mentranspos elemennya untuk array array, jadi itu tidak cukup cocok sebagai tipe pembungkus untuk digunakan di sini.

Alternatif lainnya adalah melarang transpose vektor sama sekali. Saya pikir diskusi di sini sudah terlalu menyeluruh, dan kami hanya menunggu implementasi komprehensif dari satu atau kedua opsi untuk mengevaluasi seperti apa dampaknya.

Saya sangat menghargai bahwa Anda siap untuk diskusi sementara utas ini hampir berakhir.

Meskipun v*mx mungkin terlihat aneh bagi Anda, ini banyak digunakan dalam kode kristalografi.
Ini juga ditangani dengan baik oleh Fortran matmul . (Lihat # 18056)

Kembali ke produk u*v' .
Ketika u dan v keduanya adalah matriks nx1, ini adalah produk matriks normal,
yang ternyata memberikan hasil yang sama dengan produk luarnya.
Tetapi ini hanya menggunakan hasil kali matriks untuk meniru hasil kali luarnya.
Ini mulus di dunia Matlab di mana semuanya adalah matriks.

Di Julia kita memiliki vektor 1-d yang lebih dekat dengan dunia Fortran.
Di Julia vektor yang dialihkan v' sudah menjadi masalah,
Pilihan Fortran adalah melarangnya, seperti yang sudah disarankan untuk Julia oleh orang lain.

Fortran tidak memiliki fungsi intrinsik untuk produk luar.
Julia dengan mudah mengubah v' menjadi matriks 1xn,
dan melakukan operasi * pada vektor 1-d dan matriks 1xn.
Karena beberapa pengiriman, ia dapat melakukan ini,
tapi di sini * jelas bukan produk matriks lagi.

Titik di mana Fortran dan Julia berperilaku serupa
adalah bahwa keduanya menggunakan fungsi dot untuk produk dalam.
Ada diskusi untuk menggabungkan dot juga ke operator * ,
tapi untungnya hal itu tidak terjadi.

Jadi kita harus menangani tiga produk aljabar linier:
hasil kali matriks normal, hasilkali dalam, dan hasilkali luar.
Saat ini operator * adalah sintaks gabungan untuk produk normal dan produk luar.
Yang saya sarankan adalah memisahkan ini dan mencapai keadaan yang lebih konsisten.

(Oh, saya meninggalkan produk silang, tetapi sudah dipisahkan dengan baik)

Saya tidak berpikir hasil kali dalam, hasil kali luar, dan perkalian matriks adalah cara yang tepat secara matematis untuk membagi / mengklasifikasikan produk. Berikut ini tentu saja merupakan pengulangan dari hal-hal yang telah dikemukakan di atas oleh berbagai orang, namun mengingat panjangnya topik ini, saya harap tidak apa-apa untuk menyertakan ringkasannya sesekali. Ini adalah ringkasan pribadi saya dan saya tentu saja bukan ahli jadi perbaiki saya jika saya salah.

Dalam pengaturan aljabar linier abstrak, pemain utamanya adalah vektor v (tinggal di ruang vektor V ), peta linier (bekerja pada satu ruang vektor V dan pemetaan ke ruang yang mungkin berbeda W ) dan komposisi peta ini, bentuk linier atau covectors (tinggal di ruang ganda V* dan pemetaan dari V ke skalar), produk dalam (dari V × V ke skalar), hasil kali tensor antar vektor (yaitu kron ). Hasil kali luar Saya lebih suka menganggap sebagai hasil kali tensor antara vektor dan covector.

Yang menarik untuk masalah ini adalah isomorfisme antara vektor dan bentuk linier jika produk dalam ditentukan, yaitu untuk setiap f memetakan vektor v ke skalar, terdapat w sedemikian rupa sehingga f(v) = dot(w,v) untuk v . Namun, penutup bisa ada tanpa mengacu pada hasil kali dalam (misalnya gradien fungsi multidimensi).

Untuk merepresentasikan semua objek tersebut di komputer, Anda biasanya memilih basis dan kemudian dapat merepresentasikan sebagian besar objek tersebut menggunakan aljabar matriks. Artinya, Anda hanya perlu perkalian matriks dan transposisi jika Anda ingin fleksibel dengan dimensi singleton yang tertinggal (vektor sebagai matriks nx1, skalar sebagai matriks 1x1, dll). Ini telah menjadi pendapat Matlab, serta cara banyak buku dan makalah ditulis, terutama dalam aljabar linear numerik.

Dalam hal ini, isomorfisme yang disebutkan di atas dari vektor ke covectors (secara implisit mengasumsikan hasil kali dalam Euclidean) sesuai dengan transpos (konjugat Hermitian dalam kasus kompleks) dari representasi matriks vektor. Namun, dalam pengertian abstrak, tidak ada gagasan tentang pengalihan vektor, yang mungkin mengapa tidak didefinisikan di Fortran, seperti yang dinyatakan oleh @GaborOszlanyi . Hanya transpos dari peta linier yang ditentukan (ini tidak memerlukan hasil kali dalam dan representasi matriksnya sesuai dengan matriks yang ditransposisikan bahkan dalam kasus yang kompleks), serta adjoint dari peta linier (ini memang memerlukan produk dalam) .

Karena pentingnya stabilitas jenis dalam kode Julia, pendekatan Matlab "only matrices" (dengan dimensi singleton trailing fleksibel) tidak berfungsi dengan baik. Tetapi kami juga tidak ingin beralih ke pengaturan yang sepenuhnya abstrak dan tetap bekerja dalam pengaturan tipikal (hasilkali dalam Euclidean, pemetaan sepele dari vektor ke covectors, ...). Karena pada akhirnya kita menulis kode dan ingin menggunakan karakter ASCII, kita perlu memeras sebanyak mungkin dari simbol * , ' dan .' . Untungnya, di sinilah beberapa pengiriman berguna dan mengarah ke berbagai proposal yang disebutkan di atas. Saya membuat tabel tentang ini, yaitu bagaimana operasi aljabar linier abstrak akan diterjemahkan ke metode julia tertentu (bukan fungsi).

Sebagai catatan terakhir untuk @GaborOszlanyi , saya masih tidak menemukan tempat untuk v*A dalam semua ini. Ini mungkin standar di bidang di mana vektor secara default dilambangkan sebagai matriks baris, tetapi secara pribadi saya pikir ini adalah pilihan yang aneh. Jika linear memetakan f dan g bertindak sebagai f(v) = v*A dan g(v) = v*B , maka ini berarti g(f(v)) = (g ◦ f)(v) = v*A*B yang ganjil sejak urutan komposisi dipertukarkan. Jika ada, saya bisa menafsirkan ini sebagai produk dalam yang tidak lengkap, seperti pada baris kedua hingga terakhir dari tabel tertaut.

Ringkasan Anda dalam dan meyakinkan.
Terima kasih telah menjelaskannya dengan baik.

Saya hanya punya dua pertanyaan tersisa:

  • Perubahan apa yang sebenarnya akan terjadi pada Julia sebagai hasil dari diskusi menyeluruh ini?
  • Mengapa Fortran menerapkan v*mx di matmul ?

Ada dua masalah yang diekspos oleh masalah ini:

A.Matematikawan terapan terikat pada notasi Householder, yang secara implisit menggunakan dua isomorfisme natural:

  1. Vektor dengan panjang N tidak dapat dibedakan dari matriks kolom _ Nx1_, karena matriks Nx1 membentuk ruang vektor. ("membentuk kolom", ▯)
  2. Matriks 1x1 tidak dapat dibedakan dari bilangan skalar, karena matriks 1x1 dapat ditentukan dengan semua sifat aljabar skalar. ("skalarisasi", ■)

Masalahnya adalah bahwa tidak satu pun dari isomorfisme ini alami untuk diekspresikan dalam tipe Julia dan keduanya melibatkan pemeriksaan waktu proses dari bentuk array. Aturan dimensi tunggal trailing MATLAB dapat dianggap sebagai implementasi dari kedua isomorfisme ini.

B. Larik dua dimensi dapat didefinisikan secara rekursif sebagai larik larik. Namun, matriks adalah baris kolom atau kolom baris, tetapi tidak pernah baris baris atau kolom kolom. Fakta bahwa matriks tidak dapat didefinisikan secara rekursif menyoroti struktur tensor matriks dan larik n-dimensi yang berbeda. Berbicara dengan benar, array multidimensi adalah jenis tensor yang sangat terbatas dan tidak memiliki mesin penuh yang diperlukan untuk mengimplementasikan yang terakhir. Karena kontraksi sebenarnya adalah operasi atas pasangan ruang vektor dengan gandanya, adalah keliru untuk membicarakan tentang mengontrak indeks array multidimensi, yang tidak pernah menggunakan konsep ruang vektor ganda. Kebanyakan orang _tidak_ menginginkan mesin penuh, yang memerlukan kekhawatiran tentang indeks bersama / kontravarian atau naik / turun dengan sifat baris / kolom. Sebaliknya, kebanyakan orang ingin array menjadi container lama yang polos, sepenuhnya bertentangan di semua dimensi, _kecuali dalam dua dimensi_, di mana sebagian besar pengguna ingin menganggap array dua dimensi memiliki aljabar matriks (yang merupakan tensor turun-atas), dan tidak pernah tensor bawah-bawah, atas-atas, atau atas-bawah. Dengan kata lain, array dua dimensi ingin diberi casing khusus.


Jika tidak, saya masih dapat diyakinkan, tetapi inilah proposal 3 bagian saya saat ini:

a) Larang transposisi vektor seluruhnya, mengharuskan pengguna untuk secara eksplisit mengonversi vektor ke matriks kolom untuk menulis ekspresi bergaya Householder seperti u'v , u*v' , u'*A*v dan u'*A*v/u'v . Semua ekspresi ini dapat dibangun hanya dari tiga operator uner dasar dan biner: matmul, transpos matriks, dan pembagian matriks. Sebaliknya, jika u dan v adalah vektor yang benar, maka tidak mungkin memberikan subekspresi seperti u' atau u'*A tanpa memasukkan TransposedVector khusus

Batasan (a) adalah bahwa semua ekspresi gaya-Householder akan menghasilkan matriks 1x1 alih-alih skalar sebenarnya (yang masih merupakan peningkatan besar lebih dari u'v mengembalikan 1-vektor), jadi ekspresi seperti (u'*v)*w masih tidak berfungsi. Dalam prakteknya saya tidak berpikir bahwa ungkapan "produk rangkap tiga" seperti ini sering muncul.

b) Perkenalkan notasi alternatif untuk operasi analogi pada vektor, seperti

  • u ⋅ v = scalarize(columnify(u)'*columnify(v)) untuk produk bagian dalam (titik)
  • u ⊗ v = columnify(u)*columnify(v)' untuk produk luar (Kronecker)
  • A(u, v) = scalarize(columnify(u)'*A*columnify(v)) , notasi lama untuk bentuk bilinear
  • A(u) = A(u, u) untuk bentuk kuadrat

Ekspresi dalam (b) berbeda dari persamaannya di (a) dengan secara otomatis menskalakan ekspresi untuk hasil kali dalam dan bentuk bilinear / kuadrat, sehingga menghindari pembentukan matriks 1x1.

c) Membuat matriks 1x1 dapat diubah menjadi skalar asli, sehingga kodenya seperti

M = Array(Int, 1, 1, 1)
a::Int = M

bisa bekerja. Semua yang diperlukan adalah melakukan pemeriksaan waktu proses untuk ukuran array dengan sesuatu seperti:

function convert{T}(::Type{T}, A::Array{T,N})
    if length(A) == 1
        return A[1]
    else
        error()
    end
end

Proposal ini merupakan modifikasi kecil dari apa yang diajukan oleh Folkmar Bornemann sekitar dua tahun lalu. Ketika kami mencobanya, biaya pemeriksaan run time tidak terlalu besar, dan hanya akan dipanggil pada penugasan yang dipaksakan tipe (yang sebenarnya adalah panggilan terselubung convert ), bukan penugasan umum.

@jiahao , keterbacaan posting ini dibatasi oleh karakter yang sulit dirender. Bahkan tidak terlihat benar di OS X, yang biasanya memiliki Unicode yang cukup lengkap dalam fontnya.

@jiahao , saya pasti setuju dengan sebagian besar / semua itu, meskipun saya ingin menantang dua poin:

tanpa memperkenalkan tipe khusus TransposedVector , yang sebagai konsekuensi logisnya memerlukan array multidimensi untuk mengkhawatirkan indeks naik / turun dalam struktur tensornya, yang tampaknya harga yang harus dibayar terlalu tinggi.

Ini hanya merupakan konsekuensi logis bagi saya jika Anda ingin membuat TransposedVector subtipe dari hierarki AbstractArray , yang saya asumsikan bukan rencananya (tidak seperti beberapa tipe LazyTranspose yang benar-benar hanyalah jenis lain dari AbstractMatrix ).

u ⊗ v untuk produk luar (Kronecker)

Jika tujuannya adalah untuk tidak bergantung pada isomorfisme implisit dan untuk memisahkan operasi matriks dari operasi vektor dan produk yang lebih abstrak dengan rapi, saya yakin ini gagal karena alasan berikut (saya tidak yakin tentang kesepakatan universal pada definisi matematika berikut):

  • Produk Kronecker A ⊗ B adalah operasi yang ditentukan pada matriks, bukan pada vektor.
  • Karenanya, alih-alih membaca u ⊗ v sebagai hasil kali tensor dua vektor, ini akan menghasilkan tensor dua dimensi dari tipe bawah. Satu-satunya cara untuk mendapatkan 'matriks' yang tepat adalah dengan mengambil hasilkali tensor sebuah vektor dengan covector. Tetapi karena Anda ingin menghindari perkenalan objek-objek ini, tampaknya tidak mungkin mendapatkan hasil dari operasi ini sebelum mengkolomisasi dua vektor yang terlibat.
  • Nama ketiga untuk u ⊗ v adalah produk luar yang biasanya didefinisikan secara sembarangan, dan saya tidak yakin apakah ada definisi ketat yang diterima dalam istilah naik dan turun. Beberapa sumber menyatakan itu setara dengan produk tensor dua vektor, oleh karena itu poin sebelumnya. Jika sebaliknya Anda menerima definisi di mana 'hasil kali luar' juga berarti secara implisit memetakan vektor kedua ke covector untuk mendapatkan tensor bawah ke atas, maka tidak ada masalah.

Sebaliknya kebanyakan orang ingin array menjadi wadah tua polos, sepenuhnya bertentangan di semua dimensi, kecuali dalam dua dimensi,

Sudahkah kita mempertimbangkan opsi nuklir? Kami memulai aljabar linier, sepenuhnya menghapus typealias untuk AbstractVector dan AbstractMatrix dan menggantinya dengan:

abstract AbstractVector{T} <: AbstractArray{T,1}
abstract AbstractMatrix{T} <: AbstractArray{T,2}

# and we could introduce:
abstract AbstractCoVector{T} <: AbstractArray{T,1}

Saya mengerti ada banyak dampak buruk, tetapi kita mungkin akan berakhir dengan pemisahan bersih antara larik penyimpanan multidimensi dan aljabar linier. Kita tidak _have_ untuk mengimplementasikan aljabar tensor multidimensi penuh, ruang vektor ganda, dll. Kita hanya perlu mengimplementasikan bit yang diinginkan banyak orang: vektor, covectors, dan matriks. Kami mendapatkan produk dalam, produk luar, produk covector-matrix, produk matriks-vektor dan produk matriks-matriks. Transpose didefinisikan pada semua hal di atas. Kita dapat memiliki implementasi AbstractMatrix yang benar-benar menggunakan array 1D dari array 1D (tentu saja bukan implementasi default). Kita tidak harus menggunakan notasi Householder (yang IMHO adalah salah satu kelemahan MATLAB!) Tetapi kita masih bisa mendapatkan semua kemudahan aljabar linier.

Saya agak gugup untuk menyarankan ini, tetapi saya yakin ini akan memungkinkan Julia untuk meniru model yang "benar" dari apa yang kebanyakan orang pelajari di misalnya tahun pertama aljabar linier tingkat universitas, tanpa perlu kembali ke konvensi Householder. Membuat perbedaan yang jelas juga dapat mempermudah pemindahan Base.LinAlg ke dalam paket "perpustakaan standar", yang menurut saya merupakan tujuan jangka panjang untuk Julia? Ini juga cocok dengan gagasan bahwa akan ada hal seperti daftar baru yang dapat diubah ukurannya 1D yang akan datang dengan perubahan Buffer dan implementasi asli Array , jadi jenis "daftar" generik ini dapat mengganti Vector untuk banyak bagian inti Julia dan membiarkan kita memuat paket LinAlg agak terlambat sementara Array dan "daftar" ditentukan cukup awal.

Ada banyak algoritme yang telah "dibodohi", dan yang diekspresikan dalam istilah larik Fortran dan bukan dalam aljabar linier yang tepat. Julia harus dapat mengimplementasikan algoritme ini tanpa harus menemukan kembali (atau memaksa) struktur aljabar linier di atas larik multi-dimensi.

Dalam pekerjaan saya, aljabar linier yang tepat yang memetakan tensor dan indeks co / contravariant dll. Ke array Fortran mungkin adalah yang terbaik. Untuk membuat ini bekerja - dan untuk tidak membingungkan orang - saya akan meninggalkan istilah "vektor" dan "matriks" dan "array", menjaga mereka pada tingkat yang rendah, dan menggunakan istilah lain (yang lebih menarik?) Untuk semua tingkat yang lebih tinggi . Level yang lebih tinggi tersebut juga harus opsi penyimpanan abstrak, baik melalui tipe abstrak atau melalui parametrization. Mungkin awalan LA adalah cara untuk mengekspresikan ini:

LA.Vector
LA.CoVector
LA.Tensor{... describing co/contravariance of indices ...}

Vektor dan matriks kemudian digunakan secara murni untuk penyimpanan. Di tingkat bawah, transposisi dikelola secara manual (sama seperti di BLAS); pada level tinggi, ini ditangani secara otomatis.

Ini mendekati saran @andyferris , kecuali itu tidak merusak kompatibilitas ke belakang dan tidak merusak ekspektasi konvert Matlab / Fortran / numpy.

@eschnett Saya pikir di awal utas ini diputuskan aljabar multi-linier akan ditinggalkan untuk paket, daripada basis Julia. Saya pikir banyak dari ide-ide seperti yang Anda sarankan dapat disempurnakan dalam paket baru yang menangani tensor, ruang vektor, co / kontra-varians, dan sebagainya dalam sistem tipe, agak berbeda dengan paket _TensorOperations.jl_ yang menyediakan fungsi kenyamanan untuk mengalikan array seolah-olah itu adalah tensor. Saya pikir itu akan menantang untuk dikembangkan tetapi berpotensi abstraksi yang bermanfaat!

Adapun menyisakan Matrix dan Vector saja - mungkin definisi saat ini sempurna, atau mungkin ada sesuatu yang lebih baik yang dapat kita lakukan untuk orang-orang yang ingin mengalikan matriks dan mengubah urutan vektor, menggunakan matematika standar notasi. Saya kira ini dapat menambah kurva belajar kecil untuk pengguna baru, meskipun saya berharap jika sistemnya jelas dan fasih dan _improvement_ pada bahasa lain maka itu akan mudah dipelajari.

Perhatikan bahwa ruang vektor kompleks non-Euclidean umum V memiliki 4 spasi terkait: V , conj(V) , dual(V) dan conj(dual(V)) . Jadi tensor umum than memiliki 4 jenis indeks (biasanya dilambangkan sebagai naik atau turun, dilarang atau tidak dilarang). Dalam ruang Euclidean yang kompleks (misalnya mekanika kuantum), dual(V) ≡ conj(V) dan conj(dual(V)) = V . Dalam ruang nyata (non-Euclidean) (misalnya relativitas umum), V ≡ conj(V) . Dalam kedua kasus terakhir, hanya diperlukan indeks naik dan turun.

Dalam ruang Euclidean nyata (sebagian besar aplikasi?), Semuanya setara, dan array biasa Julia cukup untuk mewakili tensor. Jadi setidaknya untuk bilangan real, dua operasi berikut memungkinkan untuk membangun aljabar tensor yang lengkap dan konsisten.

  • kontrak / produk dalam , yang dapat digeneralisasikan ke array arbitrer peringkat N menggunakan aturan: kontrak indeks terakhir dari array pertama dengan indeks pertama dari array kedua (atau numpy dot konvensi, meskipun saya menemukan itu kurang intuitif), sehingga A ∙ B mengembalikan array peringkat M+N-2 jika A dan B memiliki peringkat M dan peringkat N .
  • produk tensor : A ⊗ B mengembalikan array peringkat N+M

Dikhususkan untuk vektor v , w dan matriks A , B , ini memungkinkan untuk menulis semua hal berikut:

  • produk dalam vektor v ∙ w -> secara luar biasa mengembalikan skalar daripada array peringkat 0
  • perkalian vektor matriks A ∙ v
  • perkalian matriks matriks A ∙ B
  • tensor / hasil luar v ⊗ w
  • perkalian matriks covector (=== vektor) v ∙ A

Sementara seseorang mungkin ingin menggunakan * untuk , kesalahannya adalah bahwa definisi di atas dari tidak asosiatif: (A ∙ v) ∙ w ≠ A ∙ (v ∙ w) karena yang terakhir tidak akan sama didefinisikan.

Tapi sekali lagi, itu hanya jika Anda ingin mengabaikan array yang kompleks.

Adapun implementasi yang sepenuhnya umum dari tensor, saya memulai (dan meninggalkan) ini sejak lama, sebelum ada tumpukan tupel yang dialokasikan, fungsi yang dihasilkan, dan semua barang lainnya yang mungkin akan membuatnya lebih layak hari ini.

Pendekatan yang menarik, @Jutho. Sepertinya cukup intuitif. Saya _menebak_ bahwa definisi ini dapat ditambahkan terlepas dari apa yang kita lakukan dengan * dan ' , dan saya akan mendukungnya.

Tapi sekali lagi, itu hanya jika Anda ingin mengabaikan array yang kompleks.

conj() disisipkan secara manual untuk memperbaiki itu. Dan menurut saya Julia tidak ingin mengabaikan matriks yang rumit, bukan?

Saya memperhatikan beberapa hal tentang memiliki AbstractMatrix sebagai subtipe khusus daripada alias tipe:

matrix[:,i] -> AbstractVector{T}
matrix[i,:] -> AbstractCoVector{T}
array_2d[:,i] -> AbstractArray{T,1}
array_2d[i,:] -> AbstractArray{T,1}

Ini cukup keren - kita bisa mendapatkan vektor kolom dan baris dari indeks matriks. Jika itu hanya wadah penyimpanan 2D kita mendapatkan array penyimpanan 1D. Harus mencakup semua kasus penggunaan! Dan itu masih mematuhi antarmuka AbstractArray dengan aturan pemotongan APL sejak AbstractVector{T} <: AbstractArray{T,1} dan AbstractCoVector{T} <: AbstractArray{T,1} .

Satu fakta yang "menarik" adalah

array_3d[:,:,i] -> AbstractArray{T,2}
matrix(array_3d[:,:,i]) -> `AbstractMatrix {T}

jadi Anda harus membungkusnya secara manual sebagai matriks jika Anda ingin melakukan perkalian matriks dengan hasilnya. Apakah ini plus atau minus, saya tidak tahu? Tetapi ini tampaknya menjadi salah satu potensi komplikasi dan menyentuh apa yang disebutkan @eschnett tentang memudahkan pengguna dari bahasa lain yang menggabungkan penyimpanan dan aljabar linier.

Ini mungkin pertanyaan yang konyol, tetapi @jutho menyebutkan sebelumnya bahwa penulisan kode dibatasi oleh ASCII. Mengapa di dunia ini kita masih membatasi diri pada sekumpulan karakter 7-bit yang dikembangkan pada tahun 1963, dan terakhir diperbarui pada tahun 1986 (30 tahun yang lalu)? Ini adalah era ketika 640KB yang terkenal adalah RAM maksimum yang tersedia pada PC pada tahun 1981. Di pasar komputer saat ini, kami sekarang biasanya memiliki prosesor 64 bit dengan RAM 32GB yang dijual (50.000X max sebelumnya) dan kami sangat jauh dari itu. batas teoritis untuk prosesor 64 bit. Jadi, mengapa kita masih membatasi diri pada rangkaian karakter yang dikembangkan 40 tahun yang lalu?

Kita dapat menggunakan unicode, perlu diingat bahwa sayangnya ukuran keyboard tidak tumbuh dengan faktor yang sama dalam 40 tahun terakhir, begitu pula jumlah jari yang dimiliki orang normal (dalam 10.000+ tahun terakhir afaict).

IMHO, ASCII harus diistirahatkan. Keyboard matematika khusus untuk pemrograman simbol matematika yang cepat sebenarnya adalah ide yang bagus! Apakah ada alasan bagus untuk tidak menggunakan lebih banyak simbol yang disertakan dengan UTF? Bisakah Anda membenarkan rasa sakit mencoba jus semua yang Anda bisa dari ASCII?

@ esd100 : Harap jangan gunakan masalah GitHub ini untuk diskusi yang sangat spekulatif.

@Bayu_joo Saya tidak yakin apa yang Anda maksud dengan "spekulatif". Apakah Anda yakin itu kata yang ingin Anda gunakan? Saya pikir penggunaan ASCII vs sesuatu yang lain relevan dengan diskusi, karena tampaknya bahasa, operator, dan fungsionalitas terkait dengan simbol yang digunakan. Saya bukan ahli dengan cara apa pun tetapi sepertinya masalah dengan diskusi, atau setidaknya memperjelas, terkait dengan fungsionalitas yang ditangani.

Maksud saya, adakah alasan kita tidak dapat mendefinisikan bahasa seperti yang kita inginkan (dengan tujuan dasar: kemudahan penggunaan, kecepatan)? Bukankah penggunaan simbol / kata-kata khusus membuat bahasanya lebih kaya dan indah?

@ esd100 harap dicatat bahwa misalnya komentar terbaru @Jutho (menggunakan 2 simbol unicode) diterima dengan baik dan @yuyichao setuju bahwa kami dapat menggunakan unicode. Ada usulan lain tentang untuk memperkenalkan lebih banyak operator hanya-unicode (misalnya simbol tulis untuk membuat fungsi, # 17184). Saya tidak berpikir orang-orang tidak setuju dengan Anda (meskipun kami memiliki pertimbangan praktis yang perlu diingat) tetapi jika Anda memiliki _specific_, saran sesuai topik, beri tahu kami.

Saya agak bingung dengan perilaku baru di v0.5 yang saya yakini muncul dari diskusi ini:

julia> [ x for x in 1:4 ]' # this is fine
1×4 Array{Int64,2}:
 1  2  3  4

julia> [ Symbol(x) for x in 1:4 ]' # bit this isn't? What is special about symbols?
WARNING: the no-op `transpose` fallback is deprecated, and no more specific
`transpose` method for Symbol exists. Consider `permutedims(x, [2, 1])` or writing
a specific `transpose(x::Symbol)` method if appropriate.

Bagaimana cara membuat vektor baris (non-numerik) dari pemahaman daftar? Ini harus menjadi vektor baris. (Apakah ini lebih baik sebagai masalah terpisah atau dibahas di tempat lain? Tidak yakin di mana harus memposting ...)

Anda dapat menggunakan bentuk ulang: reshape(v, 1, length(v)) . Mungkin ini juga harus disebutkan dalam peringatan penghentian? Saya pikir idenya adalah bahwa transpose adalah operasi matematika dan dengan demikian hanya harus didefinisikan untuk vektor / matriks matematika.

Ini disebutkan di depwarn: permutedims(x, [2, 1]) .

permutedims tidak berfungsi untuk vektor. Lihat masalah baru ini: # 18320

Saya pikir idenya adalah bahwa transpose adalah operasi matematika dan dengan demikian hanya harus didefinisikan untuk vektor / matriks matematika.

Ini tidak masuk akal bagiku. Apakah ini untuk diskusi? Saya lebih suka transpose untuk bekerja pada array non-numerik kecuali ada pembenaran yang sangat bagus.

Saya pikir idenya adalah bahwa transpose adalah operasi matematika dan dengan demikian hanya harus didefinisikan untuk vektor / matriks matematika.

Ini tidak masuk akal bagiku. Apakah ini untuk diskusi? Saya lebih suka transpose untuk bekerja pada array non-numerik kecuali ada pembenaran yang sangat bagus.

Saya pikir itu relatif kompleks untuk memenuhi apa yang Anda inginkan _and_ masuk akal untuk matematika. Dalam pengertian matematis, transpos sering didefinisikan dengan menukar ruang vektor dan ruang rangkapnya dari vektor atau matriks (yah, ada beberapa komplikasi dengan transposisi vs konjugasi transpos, juga). Untuk matriks M bilangan biasa, kita memiliki transposenya sebagai permutedims(M, (2,1)) , tetapi secara umum Anda dapat mendefinisikan misalnya matriks "blok" dalam sub-matriks seperti ini:

M = [A B;
     C D]

di mana A dll adalah matriks itu sendiri. Pemahaman saya adalah bahwa Julia suka memiliki

M' = [A' C';
      B' D']

yang akan Anda lakukan dengan menggunakan matematika pena-dan-kertas dan karena itu "sintaks yang diinginkan".

Ini berarti elemen matriks harus menerima ' dan .' . Untuk bilangan, ini didefinisikan sebagai konjugasi kompleks dan tanpa operasi masing-masing. IMHO Saya pikir ini adalah pelesetan kenyamanan, tetapi berfungsi dan, yang paling penting, ini diimplementasikan dengan aturan _simple_ ("transpose adalah rekursif" - sebagai lawan dari membutuhkan kelas BlockMatrix dan sebagainya). Tapi pelesetan pada transpose ini telah dihapus dari tipe non-angka di 0,5, karena tidak masuk akal. Apa transpos dari Symbol ?

Jika Anda memiliki _data_, bukan angka, maka menggunakan permutedims didefinisikan dengan baik dalam arti dan perilakunya: ini non-rekursif. Menggunakan permainan matematika seperti .' dapat menghemat beberapa karakter yang Anda ketik - tetapi ini akan membuat _lot_ lebih masuk akal bagi orang lain (yang mungkin tidak terlalu paham dengan matematika atau MATLAB) untuk membaca kode Anda jika Anda menggunakan reshape dan permutedims sesuai kebutuhan. _Bagi saya, ini adalah_ poin yang paling _penting_.

IMHO masalah yang sangat panjang ini adalah tentang membuat antarmuka yang konsisten secara matematis untuk aljabar linier, dan tampaknya wajar bagi saya bahwa hasilnya adalah permainan kata-kata matematika yang lebih sedikit untuk array data.

Terima kasih atas tanggapan yang bijaksana. Saya masih sangat tidak setuju

Tapi pelesetan pada transpose ini telah dihapus dari tipe non-angka di 0,5, karena tidak masuk akal. Apa transpos dari sebuah Simbol?

Saya tidak yakin mendefinisikan transpos dari Symbol sebagai no-op lebih masuk akal daripada mendefinisikan transpos pada bilangan real. Saya mengerti bahwa "permainan kata" itu nyaman, tetapi tampaknya hal yang "tepat" untuk dilakukan adalah membuat transpos hanya didefinisikan untuk vektor dan matriks dan memiliki transpose(A::Matrix{Complex}) berlaku conj sebagai bagian dari pelaksanaannya.

Menggunakan permainan matematika seperti .' dapat menghemat beberapa karakter yang Anda ketik - tetapi akan lebih masuk akal bagi orang lain (yang mungkin tidak terlalu akrab dengan matematika atau MATLAB) untuk membaca kode Anda jika Anda menggunakan membentuk kembali dan mengubah tujuan seperlunya. Bagi saya, ini adalah poin terpenting.

Saya setuju bahwa .' harus digunakan dengan bijaksana dan bahwa panggilan yang lebih eksplisit ke transpose seringkali lebih baik. Saya pikir reshape dan permutedims dapat memerlukan sejumlah overhead kognitif yang tidak sepele untuk membaca dan membuat kode di tempat pertama. Jujurlah, mana yang lebih cepat diurai:

transpose([ f(x) for x = 1:length(A) ])
reshape([ f(x) for x = 1:length(A) ], 1, length(A))

Bahkan dalam kasus sederhana seperti ini Anda perlu memantul dari awal baris (untuk membaca reshape ) hingga akhir (untuk membaca length(A) ) untuk memahami apa yang sedang terjadi. (Anda kemudian mungkin bekerja kembali ke tengah untuk memahami mengapa length(A) ada di tempat pertama.)

Bagi saya, masalah yang lebih besar adalah jika saya seorang Julia baru (artinya saya mungkin pernah menggunakan numpy dan MATLAB sebelumnya) dan saya melihat bahwa ini berfungsi:

[ x for x = 1:10 ]'

Saya secara alami akan berasumsi bahwa hal yang sama akan bekerja untuk array string, simbol, dll. Saya tidak akan membaca diskusi online yang panjang untuk mengetahui semantik .' - I'm akan mencoba beberapa hal dan menggeneralisasi / menyimpulkan berdasarkan pengalaman masa lalu. Mungkin memiliki pesan kesalahan yang lebih baik akan membantu di sini.

Secara keseluruhan, saya tidak melihat bagaimana menjaga transpose no-op pada Symbol dan input non-numerik lainnya mengganggu kerangka kerja matematika bagus yang diusulkan di sini (tujuan yang layak!). Tapi mempertahankan no-op tampaknya tidak berbahaya.

Tapi mempertahankan no-op tampaknya tidak berbahaya.

Anda tidak dapat benar-benar mendefinisikan apa pun secara bermakna untuk Any karena semuanya adalah subtipe dari Any . Definisi transpose(x)=x jelas salah untuk semua jenis matriks dan untuk menghindari beberapa kesalahan diam kami harus menambahkan definisi ini . Jadi ini adalah tradeoff antara kenyamanan memungkinkan sintaks yang relatif aneh ' untuk operasi yang sepenuhnya non-matematis dan menghindari kesalahan diam.

Saya tidak yakin mendefinisikan transpos dari Simbol sebagai no-op lebih masuk akal daripada mendefinisikan transpos pada bilangan real. Saya mengerti bahwa "permainan kata" itu nyaman, tetapi tampaknya hal yang "tepat" untuk dilakukan adalah membuat transpos hanya didefinisikan untuk vektor dan matriks dan memiliki transpose(A::Matrix{Complex}) apply conj sebagai bagian dari pelaksanaannya.

Saya tidak sepenuhnya tidak setuju, tetapi kita perlu menerapkan beberapa jenis BlockMatrix atau memiliki metode khusus yang ditentukan untuk Matrix{M<:Matrix} . Saya tidak yakin apakah salah satunya adalah ide yang populer atau tidak? (Ini adalah pertanyaan serius bagi mereka yang telah mengikuti karena dapat menyederhanakan beberapa masalah terkait ini).

Jujurlah, mana yang lebih cepat diurai:

transpose([ f(x) for x = 1:length(A) ])
reshape([ f(x) for x = 1:length(A) ], 1, length(A))

Yang kedua, karena saya tidak berhubungan dengan / menyukai transposisi vektor Julia saat ini (jelas, _Saya mengambil alih vektor_ terlalu _serius_ :)) Jika saya harus melakukan yang kedua, saya akan menulis secara verbal rowvec = reshape(colvec, (1, n)) , atau mungkin hanya [f(x) for _ = 1:1, x = 1:n] untuk memaksa pemahaman membuat bentuk yang benar untuk memulai, atau jika Anda benar-benar menyukai .' maka map(f, (1:n).') dan f.((1:n).') saat ini juga berfungsi.

ini adalah tradeoff antara kenyamanan mengizinkan sintaksis yang relatif aneh 'untuk operasi yang sepenuhnya non-matematika dan menghindari kesalahan diam

Jika ini menyebabkan kesalahan diam dan masalah lain, maka saya rasa saya mungkin akan kehilangan argumen ini. (Saya tidak mengerti mengapa itu akan menyebabkan kesalahan - tapi saya percaya Anda.) Di sisi lain ....

kita perlu mengimplementasikan beberapa jenis BlockMatrix atau memiliki metode khusus yang ditentukan untuk Matrix {M <: Matrix}

Saya mungkin salah, tetapi saya pikir Anda hanya perlu melakukan yang kedua, yang tampaknya merupakan pilihan yang masuk akal bagi saya. Tapi ini mulai di atas paygrade saya.

[f (x) untuk _ = 1: 1, x = 1: n]

Saya lupa tentang ini! Ini mungkin yang akhirnya akan saya lakukan. Secara keseluruhan, saya masih tidak setuju dengan selera Anda untuk kode yang dapat dibaca, tetapi untuk masing-masing / nya sendiri! ¯\_(ツ)_/¯

jelas, saya menganggap transposisi vektor terlalu serius

Iya. Aku pikir begitu. 😉

Ini (https://github.com/JuliaLang/julia/issues/16790) juga akan membuat penggunaan reshape sebagai ganti transpose sedikit lebih enak bagi saya.

Saya mungkin salah, tetapi saya pikir Anda hanya perlu melakukan yang kedua (edit: memiliki metode transpos khusus yang ditentukan untuk Matrix{M<:Matrix} ), yang tampaknya merupakan opsi yang masuk akal bagi saya.

Sayangnya, sekarang kita kembali ke perbedaan antara data dan aljabar linier lagi. Anda ingin matriks blok aljabar linier memiliki transpose rekursif tetapi array data 2D generik dari array data 2D tidak memiliki transpose rekursif ... tetapi sementara Matrix{T} dan Array{T,2} adalah hal yang sama kita tidak bisa lakukan itu.

Ini (# 16790) juga akan membuat penggunaan bentuk ulang sebagai pengganti transpos sedikit lebih cocok bagi saya.

Benar!!

Anda ingin matriks blok aljabar linier memiliki transpose rekursif tetapi array data 2D generik dari array data 2D tidak memiliki transpose rekursif

Ini sepertinya bukan sesuatu yang jelas saya inginkan ... Mengapa tidak hanya memiliki dua fungsi berbeda untuk menangani jenis transposes yang berbeda ini? Saya kira saya melewatkan memo tentang adanya perbedaan yang sangat ketat antara objek aljabar linier dan objek data.

Membaca seluruh utas ini sepertinya tugas yang menakutkan, tetapi mungkin saya harus melakukannya sebelum berkomentar lebih lanjut. Saya tidak ingin menambahkan suara tanpa informasi.

Saya kira saya melewatkan memo tentang adanya perbedaan yang sangat ketat antara objek aljabar linier dan objek data.

Tidak ada perbedaan tegas antara objek Aljabar Linear, dan objek Data.
Tidak dalam implementasi saat ini, atau dalam penggunaan yang ideal.

Jika ada, maka mengubah ukuran (dengan push! ) atau bahkan nilai objek Aljabar Linear tidak akan didukung (dan pengguna tersebut akan menggunakan StaticArrays.jl dll), dan broadcast hanya akan didukung pada objek Aljabar Linear.
Objek Data akan dapat dimodifikasi, diperluas, dan akan mendukung map , (dan reduce , dan filter ) tetapi tidak broadcast .

Tapi kita tidak hidup di dunia di mana orang berpikir biner objek Data, vs objek Aljabar Linear.
Jadi 2,5 tahun ini, 340 utas komentar.


Re the no-op transpos.
Kita bisa menambahkan, sangat tinggi hierarki tipe Scalar dan Nonscalar tipe abstrak.
Scalars semua fallback ke transpose no-op.
Nonscalars tidak memiliki fallback, (tetapi untuk saat ini kembali ke peringatan penghentian)

Angka, karakter, String, dan bahkan mungkin Tuple akan menjadi Scalar dan tidak memiliki transposisi yang ditentukan. Beberapa skalar, misalnya Bilangan Kompleks akan menulis berlebihan definisi transpos ini.

Array (matriks, vektor, dan lainnya) akan menjadi subtipe dari Nonscalar dan akan memiliki transpose rekursif.

Saya tidak yakin apakah saya suka itu, atau tidak.

Serentetan pos baru-baru ini mengulangi diskusi tentang _matrix transpose_ dan jenis "skalar" di # 18320 # 13171 # 13157 # 8974.

Saya benar-benar ingin menghilangkan anggapan bahwa fallback no-op transpose(x)=x tidak berbahaya. Dalam pikiran saya, fallback harus tetap menghasilkan hasil yang benar, hanya lebih lambat daripada algoritme yang dioptimalkan. Berbahaya jika metode fallback secara diam-diam menghitung jawaban yang salah, karena ini berarti fallback tidak memiliki semantik yang benar: transpose(x) berarti hal yang berbeda tergantung pada jenis x .

Fallback transpose no-op tidak hanya salah untuk matriks matriks, tetapi juga salah untuk semua objek mirip matriks yang bukan subtipe AbstractMatrix (yang oleh # 987 berarti bahwa mereka memiliki entri yang disimpan secara eksplisit, _not_ bahwa mereka memiliki aljabar matriks). Berikut adalah satu contoh poster child (yang kami punya beberapa):

julia> A = rand(5,5); F = qrfact(A); R = F[:R]; Q = F[:Q] #Q is an example of a matrix-like object
5x5 Base.LinAlg.QRCompactWYQ{Float64,Array{Float64,2}}:
 -0.518817    0.0315127   0.749223    0.410014  -0.0197446
 -0.613422   -0.16763    -0.609716    0.33472   -0.3344   
 -0.0675866   0.686142    0.0724006  -0.302066  -0.654336 
 -0.582362   -0.0570904   0.010695   -0.735632   0.341065 
 -0.104062    0.704881   -0.248103    0.295724   0.585923 

julia> norm(A - Q*R) #Check an identity of the QR factorization
8.576118402884728e-16

julia> norm(Q'A - R) #Q'A is actually an Ac_mul_B in disguise
8.516860792899701e-16

julia> Base.ctranspose(Q::Base.LinAlg.QRCompactWYQ)=Q; #Reintroduce no-op fallback

julia> norm(ctranspose(Q)*A - R) #silently wrong 
4.554067975428161

Contoh ini menunjukkan bahwa hanya karena sesuatu adalah subtipe dari Any tidak berarti Anda dapat menganggapnya sebagai skalar dan memiliki transpose no-op. Ini juga menggambarkan mengapa masalah induk di OP sangat sulit untuk diselesaikan. Untuk objek Q non-array seperti matriks, Q' tidak memiliki arti sebenarnya sebagai operasi array tetapi ia memiliki arti aljabar yang tidak ambigu: ekspresi seperti Q'A didefinisikan dengan baik. Orang lain yang bekerja dengan array dan bukan aljabar linier hanya menginginkan permutedim non-rekursif dan tidak peduli dengan non-array seperti matriks. Namun demikian, faktanya tetap bahwa Anda tidak dapat memiliki ejaan yang konsisten dari semantik aljabar dan pertukaran sumbu untuk semua jenis.

Mungkin saya orang yang padat, tetapi saya mengira perbandingannya adalah seperti ini:

julia> A = rand(5,5); F = qrfact(A); R = F[:R]; Q = F[:Q]
julia> Base.ctranspose(Q::Any) = Q;
WARNING: Method definition ctranspose(Any) in module Base at operators.jl:300 overwritten in module Main at REPL[6]:1.
julia> norm(ctranspose(Q)*A - R) # still works fine
4.369698239720409e-16

Menimpa transpose dengan cara ini tampaknya memungkinkan transpose([ :x _=1:4 ]) - yaitu apa yang saya posting. Saya akan berpikir bahwa selama Anda menerapkan transpose / ctranspose dengan benar untuk semua yang membutuhkannya (misalnya QRCompactWYQ ) fallback tidak akan pernah dipanggil (karena panggilan yang lebih spesifik dapat di buat).

Kode Anda tidak memanggil metode ctranspose yang Anda tulis (Anda dapat memverifikasi ini dengan @which ). Ini memanggil metode fallback yang berbeda di Julia v0.5 (yang tidak ada di v0.4) yang pada dasarnya menghasilkan ctranspose(full(Q)) . Pengembalian lain ini benar, tetapi mengalahkan alasan utama mengapa kita memiliki tipe-Q yang mewah ini (sehingga mengalikannya dapat dilakukan secara akurat). Komentar saya bahwa fallback harus benar masih berlaku.

Ya, selama Anda menerapkan transposisi dengan benar untuk semua itu
membutuhkannya, fallback tentu saja tidak merugikan. Kerugiannya adalah Anda tidak melakukannya
dapatkan kesalahan metode tidak jika Anda lupa melakukannya, tetapi diam-diam salah
hasil.

Terima kasih @toivoh yang membuatnya cocok untuk saya. Saya sangat menghargai penjelasannya.

Tetapi jika Anda mendefinisikan fungsi fallback transpose(X::AbstractMatrix) dan transpose(X::AbstractVector) maka kiranya Anda akan selalu mendapatkan hasil yang benar (meskipun lambat ... memanggil full misalnya) bukan? Dan Anda selalu dapat menulis fungsi yang lebih terspesialisasi untuk melakukannya dengan lebih baik / lebih cepat. Maka transpose(::Any) seharusnya tidak menyebabkan kesalahan diam selain "permainan kata-kata" yang disebutkan sebelumnya (yaitu ketika menangani Complex angka ... mungkin kasus penggunaan skalar lain yang tidak saya ketahui?)

Untuk alasan historis QRCompactWYQ <: AbstractMatrix , tetapi menurut # 987 # 10064 hubungan subtipe ini tidak benar dan harus dihapus.

Contoh lain dari non-array seperti matriks adalah IterativeSolvers.AbstractMatrixFcn , yang bukan merupakan subtipe dari AbstractMatrix . Untuk jenis ini, fallback yang Anda rujuk tidak akan pernah dikirim, yang lagi-lagi merupakan poin utama saya.

Kita harus melanjutkan diskusi ini di https://github.com/JuliaLang/julia/issues/13171. Masalahnya sebenarnya terutama tentang vektor dengan elemen seperti angka.

Seseorang dari "aljabar linier tim" perlu melangkah maju dan berkomitmen untuk melakukan sesuatu tentang hal ini selama 0,6 atau akan gagal lagi.

Jadi untuk reboot, apa rencana sebenarnya?

Pemikiran saya membawa saya ke: transpose(v::AbstractVector) = TransposedVector(v) dimana TransposedVector <: AbstractVector . Satu-satunya hal semantik yang akan membedakan TransposedVector dari AbstractVector adalah bagaimana perilakunya di bawah * (dan semua A_mul_B s, \ , / , ...). Yaitu, penghias untuk menentukan indeks mana yang akan dikontrak di bawah * (dll ...). Transposisi akan menjadi konsep aljabar linier dan jika Anda ingin mengatur ulang array "data", reshape dan permutedims harus didorong.

Satu-satunya hal semantik yang akan membedakan TransposedVector dari AbstractVector adalah bagaimana perilakunya di bawah *

Jadi v'==v tapi v'*v != v*v' ? Meskipun masuk akal, ini juga terlihat berpotensi membingungkan.

Jadi v'==v tapi v'*v != v*v' ? Meskipun masuk akal, ini juga terlihat berpotensi membingungkan.

IMO ini tidak bisa dihindari (meski mungkin disayangkan).

Rangkap vektor juga merupakan vektor. Transpos juga masih merupakan struktur data satu dimensi dengan elemen yang terdefinisi dengan baik yang seharusnya bisa didapat, bermutasi, memetakan, mengurangi, dll.

Kecuali jika kita memisahkan aljabar linier dari array (misalnya, buat Matrix{T} baik subtipe dan pembungkus permanen Array{T,2} , dengan lebih banyak metode (khusus aljabar linier) yang ditentukan), maka saya tidak yakin di sana adalah banyak pilihan yang konsisten dengan properti array dan aljabar liniernya.

Pertanyaan yang membingungkan (bagi saya) adalah apakah ia menyiarkan seperti vektor, atau melalui dimensi keduanya. Jika ukurannya (1, n) maka perubahan ini secara keseluruhan tidak benar-benar melakukan banyak hal kecuali menyatakannya seperti matriks di mana dimensi pertama diketahui panjangnya 1 . Pengalihan dari Vector{T} harus tetap menjadi Array{T,2} (yaitu Matrix ...), namun pengalihannya bisa menjadi Vector lagi ( misalnya kita dapat memiliki v'' === v ).

Apakah itu ide yang lebih baik? Ini akan mengurangi kerusakan dan masih meningkatkan semantik dengan aljabar linier. EDIT: dan berperilaku berbeda wrt == seperti yang ditampilkan @martinholters ).

Bagi saya, memiliki TransposedVector{T <: AbstractVector{Tv}} <: AbstractMatrix{Tv} *) dengan size(::TransposedVector, 1)==1 tetapi transpose(::TransposedVector{T})::T kedengarannya seperti pendekatan yang paling waras, tetapi ada begitu banyak perdebatan sehingga mungkin ada beberapa argumen yang bagus untuk menentang ini?

*) Saya tahu ini secara sintaksis tidak valid, tetapi saya harap semantik yang dimaksud jelas.

Ya, setelah bermain-main dengan ide dalam kode, saya merasa saya setuju dengan Anda @martinholters.

Saya memulai di https://github.com/andyferris/TransposedVectors.jl. Ini semua dapat dicapai hanya dengan sejumlah kecil pembajakan tipe dan metode overides dari paket di luar basis, dan saya membuat paket yang kompatibel dengan Julia 0.5. Jika ternyata baik, kita mungkin bisa mem-portingnya ke Base? (Atau pelajari beberapa pelajaran).

Satu pertanyaan besar adalah apakah kita dapat hidup tanpa tipe CTransposedVector untuk konjugasi kompleks, atau bagaimanapun itu akan ditangani.

Saya tidak akan menggunakan CTransposedVector , karena itu menggabungkan dua konsep (konjugasi dan pembentukan kembali) menjadi satu objek. Jauh lebih mudah disusun untuk mempertahankan kedua konsep tersebut diimplementasikan sebagai entitas yang terpisah. Misalnya, dengan MappedArrays.jl semudah itu

conjview(A) = mappedarray((conj,conj), A)

dan Anda juga mendapatkan kinerja yang hebat.

Benar, Terima kasih Tim. Saya sedang memikirkan / mengharapkan sesuatu seperti itu - satu-satunya perhatian saya adalah bagaimana Anda dapat memastikan kedua pembungkus selalu muncul dalam urutan yang "benar", tetapi saya pikir apa yang telah saya terapkan sejauh ini dapat mengatasinya. Kami juga perlu mendukung BLAS untuk semua kombinasi ini, yang sejauh ini berhasil saya hindari.

Satu hal yang indah adalah bahwa perubahan terpisah yang default conj menjadi conjview akan independen terhadap perubahan ini (saya pikir mereka berdua bisa diotak-atik dalam paket independen dan mereka akan menyusun bersama dengan benar). Apakah ada keinginan untuk membuat tampilan conj ? Apakah kita menunggu inmutables non-isbit inline untuk membuat tampilan seperti itu gratis? Atau tidak perlu menunggu?

@andyferris : Saya pikir pendekatan Anda bagus - terima kasih telah mendorongnya ke depan. Jika implementasinya berhasil, kita bisa menggunakan kode itu di Base. Satu hal yang perlu diingat adalah kami mungkin juga menginginkan TransposedMatrix juga untuk https://github.com/JuliaLang/julia/issues/5332. Di luar dimensi 1 dan 2, menurut saya transposes tidak masuk akal jadi ini adalah kumpulan tipe yang terbatas.

Sekarang setelah kita melanjutkan konversi, saya akan menyebutkan lagi bahwa kita harus mencoba menghindari jenis vektor yang dialihkan. Ini telah disebutkan beberapa kali di atas, tetapi saya ragu bahwa ada orang yang dapat membaca semua komentar tentang masalah ini lagi. Memperkenalkan tipe transpose untuk vektor benar-benar memperumit banyak hal sehingga hampir tidak ada manfaatnya. Jika Anda benar-benar berpikir bahwa vektor memiliki arah maka buatlah matriks dan semuanya akan berfungsi. Tidaklah masuk akal untuk memiliki vektor aljabar linier yang berbeda dari matriks dan kemudian memperkenalkan jenis pembungkus baru untuk membuat vektor berperilaku seperti matriks 1xn .

Saat ini asimetri adalah bahwa x' mempromosikan x ke matriks sedangkan A*x tidak mempromosikan x ke matriks. Jika operasi aljabar linier hanya untuk 2D maka A*x harus dipromosikan dan x'x akan menjadi matriks 1x1 . Alternatifnya, kita dapat membiarkan vektor menjadi vektor dan oleh karena itu juga A*x menjadi vektor tetapi kemudian x' harus berupa noop atau kesalahan. Memperkenalkan vektor yang ditransposisikan akan membutuhkan banyak definisi metode baru dan satu-satunya manfaat tampaknya adalah x'x menjadi skalar.

Saya pikir matriks transpose sangat berbeda. Ini akan memungkinkan kita untuk menyingkirkan semua metode Ax_mul_Bx dan perilakunya tidak dapat diperdebatkan dengan cara yang sama seperti perilaku transpos vektor.

Saya tidak begitu mengerti bagaimana memperkenalkan jenis TransposedVector menyebabkan lebih banyak masalah daripada memperkenalkan jenis TransposedMatrix.

Ya, konsensus yang kuat di suatu tempat di tengah-tengah karya ini adalah bahwa transpose vektor itu aneh, dan bahwa, jika diterapkan, itu pasti tidak boleh menjadi subtipe AbstractArray - saya bahkan akan melarang size seluruhnya. Ringkasan saya di conj atas array daripada memasukkannya sebagai tipe parameter).

Tapi ada panggilan yang lebih kuat untuk transpos vektor hanya menjadi kesalahan. Jika itu masalahnya, maka saya pikir itu benar-benar bisa hidup dalam satu paket.

Memiliki transpos vektor menjadi kesalahan sepertinya membuang bayi dengan air mandi. Tidak dapat menulis v' untuk mengubah urutan vektor akan sangat, sangat mengganggu. Saya tidak benar-benar mengerti apa yang buruk tentang memiliki jenis TransposedVector yang berperilaku seperti matriks baris selain dari cara mengalikan dengan vektor dan matriks.

Itu tergantung pada berapa banyak perilaku yang ingin Anda tangani dengan transpose vektor. Jika Anda hanya ingin v'' == v , maka tidak masalah untuk typeof(v') <: AbstractMatrix . Tetapi jika Anda menginginkan hal-hal lain yang telah kita bicarakan di utas ini seperti typeof(v'v) <: Scalar atau typeof(v'A) <: AbstractVector , maka itu harus binatang yang berbeda, lebih rumit,.

Ide untuk menjadikan TransposedVector semacam Vektor tampaknya menjadi akar dari banyak masalah. Tampaknya akan jauh lebih tidak mengganggu untuk menjadikannya semacam matriks dan kemudian memiliki size(v.') == (1,length(v)) seperti yang kita lakukan sekarang. Satu-satunya perbedaan adalah bahwa transpos ganda memberi Anda vektor kembali dan v'v akan menghasilkan skalar. Jika seseorang ingin memperlakukan transpos sebagai vektor, ia dapat karena length(v') memberikan jawaban yang benar dan pengindeksan linier berfungsi seperti yang diharapkan.

Saya setuju 110% dengan @StefanKarpinski. Saya bermain-main dengan membuatnya menjadi sejenis vektor tetapi itu tidak terlalu masuk akal dan agak rusak, untuk jenis alasan yang telah dibahas sebelumnya di utas ini.

Pendekatan membuatnya memiliki ukuran (1, n) berarti dalam hal perilaku Array itu berperilaku persis seperti sekarang. Operasi _only_ yang akan membedakannya dari operasi 1-by-N Matrix adalah perilaku di bawah ' , .' , * , \ . dan / .

Tak satu pun dari mereka adalah operator "mirip larik". Mereka ada murni untuk mengimplementasikan aljabar linier antara matriks dan vektor, dan datang langsung dari MATLAB ("laboratorium matriks"). Perbaikan terakhir ini hanya mengatakan bahwa size(tvec, 1) = 1 secara statis ke compiler _and_ yang saya inginkan v'' menjadi v . (Saya agak menganggapnya seperti StaticArray mana satu dimensi diperbaiki dan yang lainnya berukuran dinamis).

Jika Anda hanya menginginkan v '' == v, maka tidak masalah untuk typeof (v ') <: AbstractMatrix.

Baik.

Tetapi jika Anda menginginkan hal-hal lain yang telah kita bicarakan di utas ini seperti typeof (v'v) <: Scalar or typeof (v'A) <: AbstractVector, maka itu harus beast yang berbeda, lebih rumit,.

Mengapa? Kami tidak melanggar salah satu properti yang mirip lariknya, jadi itu masih bisa berupa larik. Setiap dot-call akan berfungsi seperti sebelumnya, dan operasi vektor lainnya sedang dihapus. Saya pikir * adalah "terspesialisasi" pada pengetahuan tentang berbagai bentuk dari Vector dan Matrix dan ini karena kami mencoba meniru perilaku aljabar linear tertulis. Membuat v' * v menjadi skalar adalah _very_ matematika standar dan itu adalah interpretasi saya bahwa satu-satunya alasan mengapa tidak begitu dari awal adalah karena tidak sepele untuk diterapkan secara konsisten (dan inspirasi yang diambil Julia MATLAB), tapi Stefan bisa menjelaskannya. Menjadikan produk dalam sebagai skalar adalah satu-satunya perubahan besar di sini untuk dibicarakan (ada banyak hal kecil lainnya) - Saya tidak mengerti mengapa itu saja tidak akan membuatnya tidak cocok untuk menjadi Array (ada banyak jenis dari Array yang tidak memiliki ' valid, .' , * , \ dan / ditentukan _at all_ , khususnya peringkat 3+)

Salah satu masalah yang saya hadapi tahun lalu adalah ambiguitas; IIRC mereka jauh lebih sederhana untuk diselesaikan ketika vektor transpose bukan sebuah array.

Ya, saya sedikit khawatir betapa dalamnya jadinya sebelum saya selesai ... :)

Sebagai catatan umum, alangkah baiknya jika / ketika kita menghasilkan Base lebih sedikit monolitik dan memfaktorkannya ke dalam pustaka standar. Memiliki paket atau modul mandiri yang hanya menentukan AbstractArray dan Array akan membuat pengembangan semacam ini lebih sederhana.

Apa sebenarnya masalah dengan proposal @Jutho ? Tidak dapatkah * secara otomatis (mengkonjugasikan) mengubah urutan vektor di sebelah kiri?

Jika kita memiliki * perkalian matriks, ' matriks (konjugasi) transposisi (membiarkan vektor tidak berubah), dan dua operator promote yang menambahkan tanda singleton dan demote yang menghapus jejak tunggal, kemudian kita dapat membangun aplikasi yang benar *: (n,m) -> (m,) -> (n,) , aplikasi kiri *: (n,) -> (n,m) -> (m,) , produk skalar *: (n,) -> (m,) -> (,) dan produk luar ×: (n,) -> (m,) -> (n,m) sedemikian rupa:

(*)(A::AbstractMatrix, v::AbstractVector) = demote(A*promote(v))
(*)(u::AbstractVector, A::AbstractMatrix) = demote((promote(u)'*A)')
(*)(u::AbstractVector, v::AbstractVector) = demote(demote(promote(u)'*promote(v)))
(×)(u::AbstractVector, v::AbstractVector) = promote(u)*promote(v)'

Saya tidak yakin saya perlu mengubah urutan vektor dengan operator ini. Apakah saya melewatkan sesuatu?

Edit: Tidak persis seperti proposal

@Armavica , saya tidak begitu yakin bahwa itu persis dengan proposal saya untuk menetapkan makna ini ke * melainkan ke operator (unicode) baru , yang saat ini setara dengan dot . Selain itu, saya tidak berpikir Anda akan dapat menerapkan pendekatan promote dan demote dengan cara yang stabil.

Purist dalam diri saya setuju dengan @andreasnoack bahwa transposisi vektor itu sendiri harus dihindari (saya pribadi lebih suka menulis dot(v,w) lebih dari v'w atau v'*w kapan saja), tetapi saya juga dapat menghargai fleksibilitas membuatnya berfungsi dengan cara yang diusulkan oleh @andyferris . Oleh karena itu saya tidak akan menambahkan apa pun lebih jauh ke diskusi ini dan mendukung setiap upaya waras untuk menjalankan implementasi yang sebenarnya.

Benar, @Jutho. Menariknya, keduanya tidak saling eksklusif: tidak memiliki transpos pada vektor yang ditentukan secara default berarti fungsi ini dapat secara sah hidup dalam paket, modul, atau "pustaka standar" yang terpisah (yaitu tanpa "pembajakan tipe").

(Saya pribadi lebih suka menulis titik (v, w) daripada v'w atau v '* w kapan saja)

Jutho - di sisi lain, saya yakin Anda tidak menulis | ψ> ⋅ | ψ> di selembar kertas atau papan tulis, melainkan <ψ | ψ> (dan analogi yang sama berlaku untuk cara kita menggambar produk dalam dengan diagram jaringan tensor).

Tentu saja saya ingin melihat notasi braket Dirac sebagai formulasi standar aljabar linier di semua matematika atau bahkan sains, dan dengan ekstensi di Julia, tapi mungkin itu tidak akan terjadi.

Sekarang Anda memaksa saya untuk ngelantur, yang tidak akan saya lakukan lagi. Saya tentu setuju untuk lebih memilih <ψ | ψ> untuk produk dalam, tapi itu terlepas dari fakta bahwa saya tidak memikirkan <ψ | sebagai konjugasi Hermitian dari | ψ>. Konjugasi pertapa didefinisikan untuk operator. Isomorfisme natural antara vektor dan vektor ganda yang terkait (covectors, fungsi linier, ...) dikenal sebagai teorema representasi Riesz , meskipun yang pertama tentu saja setara dengan konjugasi Hermitian ketika menafsirkan panjang n vektor sebagai peta linier dari C ke C ^ n, yaitu sebagai matriks dengan ukuran (n,1) .

Tentu saja saya ingin melihat notasi braket Dirac sebagai formulasi standar aljabar linier di semua matematika atau bahkan sains, dan dengan ekstensi di Julia, tapi mungkin itu tidak akan terjadi.

Lol

Sekarang Anda memaksa saya untuk ngelantur, yang tidak akan saya lakukan lagi.

Maaf ... Saya seharusnya tidak menyebutkannya ... :)

Saya tidak memikirkan <ψ | sebagai konjugasi Hermitian dari | ψ>. Konjugasi pertapa didefinisikan untuk operator.

Benar, saya tidak mempertimbangkan itu.

Isomorfisme natural antara vektor dan vektor ganda yang terkait (covectors, fungsi linier, ...) dikenal sebagai teorema representasi Riesz, meskipun yang pertama tentu saja setara dengan konjugasi Hermitian ketika menafsirkan panjang n vektor sebagai peta linier dari C ke C ^ n, yaitu sebagai matriks ukuran (n, 1).

Saya mencoba untuk tidak menyimpang (tapi saya buruk dalam hal itu), tetapi saya pikir kita mendapatkan sedikit dari bit terakhir ini karena kita mengaitkan AbstractVector dengan 1D Array . Dengan kata lain AbstractVector tidak berarti "vektor abstrak" dalam pengertian matematis, tetapi berarti "elemen numerik dari sebuah vektor dengan beberapa dasar yang telah ditentukan sebelumnya". MATLAB keluar dari ini dengan mudah karena vektor berukuran (n,1) .

Sebagai bahan pemikiran, apa yang Anda sebut sebagai operator (antilinear) yang mengambil semua tensor dari bentuk |a>|b><c| dan memetakannya menjadi |c><a|<b| ? Saya selalu menggabungkan ini bersama-sama dengan vektor ganda dan konjugasi operator standar, sebagai "konjugasi pertapa" tapi mungkin itu terlalu blas.

Berbincang dengan

  • perkenalkan Covector atau RowVector type;
  • untuk operasi aljabar linier ( * , ' , .' , / , \ , mungkin norm ? lainnya? ) tipe ini bertindak sebagai covector dalam aljabar linier;
  • untuk operasi array (yang lainnya) tipe ini bertindak sebagai array 2 dimensi 1 × n;
  • khususnya, size(v') dari covector adalah (1, length(v)) .

Pendekatan ini membutuhkan pengklasifikasian semua fungsi generik dalam Basis sebagai aljabar linier atau tidak. Secara khusus, size adalah fungsi array dan tidak masuk akal dalam domain aljabar linier, yang pada dasarnya hanya memiliki vektor (yang tidak memiliki "bentuk", hanya kardinalitas dimensi), transformasi linier (yang mungkin terjadi diwakili oleh array 2-dimensi), dan skalar. Satu contoh khusus yang muncul adalah cumsum , yang saat ini beroperasi pada array 2 dimensi seolah-olah argumen dimensi 1 disediakan. Ini tidak konsisten dengan sum , yang daripada default ke argumen dimensi 1 mengembalikan jumlah dari seluruh array. Ini juga mencegah cumsum beroperasi pada covectors dengan cara yang sesuai dengan bagaimana beroperasi pada vektor. Saya pikir bahwa cumsum harus beroperasi pada array umum dengan menjumlahkan secara kumulatif dalam urutan utama kolom-dimensi N. Secara umum, argumen dimensi tidak boleh default ke 1.

Saya akan sedikit khawatir jika tidak ada antarmuka untuk mengidentifikasi covectors. Kebanyakan operasi, misalnya size dan ndims, akan mengatakan mereka seperti array 2d atau 1d lainnya. Hanya dengan mencoba, misalnya produk titik, Anda melihat perbedaan. AFAICT Anda harus memeriksa apakah objek tersebut adalah RowVector, tetapi sangat jarang membutuhkan objek untuk memiliki tipe tertentu untuk memiliki properti umum tertentu.

@StefanKarpinski Saya setuju dengan semua itu. Terutama fungsi yang bisa berupa operasi "larik" atau operasi "aljabar linier".

Saya memulai dengan ukuran = (1, n) TransposedVector sini yang persis seperti yang Anda katakan. Butuh beberapa saat bagi saya untuk mendapatkan cakupan pengujian yang baik dan semua kombinasi * , \ , / untuk setiap kemungkinan c dan t metode dan metode mutasi, sambil menghindari ambiguitas dengan metode lain dalam basis. Ini pekerjaan yang lambat tapi sistematis, dan dari situ saya pikir kami bisa menariknya ke pangkalan ketika sudah siap (mungkin mengganti nama hal-hal).

Mereka adalah perbedaan dengan Covector mana itu harus menjadi transpos konjugasi (atau bahkan transformasi yang lebih umum, dalam kasus umum!), Sedangkan RowVector atau TransposedVector lebih sederhana secara konseptual.

@JeffBezanson Adakah yang bisa kita lakukan dengan indices() untuk memiliki dimensi "tunggal"?

tetapi sangat jarang membutuhkan objek untuk memiliki tipe tertentu untuk memiliki properti umum tertentu.

Benar, akan keren jika ini adalah sifat atau sesuatu. Saya berharap bahwa kita bisa menguraikan aljabar linier dari array secara lebih umum, tetapi itu adalah perubahan besar. dan mungkin tidak bisa rapi tanpa sintaks sifat yang bagus yang diterapkan di Julia. Saya pikir di sini masalahnya adalah kita memetakan 3 hal (vektor, covectors, dan matriks) menjadi dua jenis ( AbstractArray{1} dan AbstractArray{2} ), dan salah satunya (covectors) menjadi subtipe khusus dari yang lain.

Saya akan memasukkan AbstractTransposedVector ke dalam paket jika saya dapat memikirkan tempat di mana seseorang akan membutuhkan sesuatu selain implementasi "pembungkus" dasar.

@ JeffBezanson : Saya tidak mendapatkan perhatian Anda. Idenya adalah bahwa ia berperilaku seperti larik abstrak 1 × n 2d kecuali untuk operasi aljabar linier, yang berperilaku seperti ruang ganda vektor kolom (yang isomorfik ke larik abstrak 1 × n 2d). Jika Anda ingin memeriksa covector, Anda dapat memeriksa jenisnya misalnya dengan mengirimkannya.

Pembaruan pada upaya saya menangani ini:

TransposedVectors.jl sekarang, saya yakin, "fitur lengkap". Ini berisi semua mesin yang diperlukan untuk melakukan apa yang telah dibicarakan @StefanKarpinski di sini - transpose vektor adalah pembungkus vektor yang berperilaku sebagai larik abstrak berukuran 1xn 2 dimensi - tetapi untuk operasi aljabar linier ( * , / , \ , ' , .' dan norm ) berperilaku sebagai vektor baris (atau vektor ganda).

Anda dapat memeriksanya seperti ini:

julia> Pkg.clone("https://github.com/andyferris/TransposedVectors.jl")
...

julia> using TransposedVectors
WARNING: Method definition transpose(AbstractArray{T<:Any, 1}) in module Base at arraymath.jl:416 overwritten in module TransposedVectors at /home/ferris/.julia/v0.5/TransposedVectors/src/TransposedVector.jl:28.
WARNING: Method definition ctranspose(AbstractArray{#T<:Any, 1}) in module Base at arraymath.jl:417 overwritten in module TransposedVectors at /home/ferris/.julia/v0.5/TransposedVectors/src/TransposedVector.jl:29.
WARNING: Method definition *(AbstractArray{T<:Any, 1}, AbstractArray{T<:Any, 2}) in module LinAlg at linalg/matmul.jl:86 overwritten in module TransposedVectors at /home/ferris/.julia/v0.5/TransposedVectors/src/mul.jl:9.
WARNING: Method definition At_mul_B(AbstractArray{#T<:Real, 1}, AbstractArray{#T<:Real, 1}) in module LinAlg at linalg/matmul.jl:74 overwritten in module TransposedVectors at /home/ferris/.julia/v0.5/TransposedVectors/src/mul.jl:37.
WARNING: Method definition Ac_mul_B(AbstractArray{T<:Any, 1}, AbstractArray{T<:Any, 1}) in module LinAlg at linalg/matmul.jl:73 overwritten in module TransposedVectors at /home/ferris/.julia/v0.5/TransposedVectors/src/mul.jl:64.

julia> v = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> vt = v'
1×3 TransposedVectors.TransposedVector{Int64,Array{Int64,1}}:
 1  2  3

julia> vt*v
14

julia> vt*eye(3)
1×3 TransposedVectors.TransposedVector{Float64,Array{Float64,1}}:
 1.0  2.0  3.0

Mungkin ada beberapa penurunan kinerja - pembandingan akan berguna. Dalam beberapa kasus ini akan membuat lebih sedikit salinan (transposenya malas) dan dalam kasus lain itu membuat lebih banyak salinan (terkadang salinan terkonjugasi dari vektor (tidak pernah matriks) dibuat dalam Ac_mul_Bc misalnya). Dan pembungkusnya sendiri memiliki sedikit biaya sampai kita menyebariskan bidang yang bisa berubah menjadi tidak berubah (untungnya bagi saya, ini sudah berfungsi dengan baik dengan StaticArrays.jl : smile :). Ada juga masalah untuk memastikan itu adalah semacam StridedArray bila perlu.

Jika orang-orang menyukai pendekatan ini, kita dapat melihat tentang membuat PR segera untuk memindahkan kode ke Base (paket sudah memiliki pengujian unit dan semua ambiguitas diselesaikan). (juga, @jiahao telah menyebutkan keinginan untuk bereksperimen dengan versi larik abstrak 1 dimensi dari vektor ganda, tidak yakin apakah ada kemajuan?)

Apakah orang mengira bahwa PR seperti itu akan masuk akal di v0.6 tanpa jenis pembungkus untuk matriks yang dialihkan? Sementara vektor yang ditransposisikan adalah perubahan semantik, matriks yang ditransposisi lebih merupakan pengoptimalan, jadi saya kira mereka bisa masuk secara terpisah. Tentu saja, mungkin tampak "aneh" jika beberapa transposisi adalah pandangan dan beberapa salinan - opini? Hal lain yang perlu dipertimbangkan adalah bahwa setelah matriks dan vektor yang ditransposisikan masuk, banyak pekerjaan yang perlu dilakukan untuk menghapus semua fungsi At_mul_Bt , diganti dengan metode pada * , untuk menyelesaikan transisi (meskipun penyederhanaan akan bermanfaat!) - Saya ragu ada orang yang mampu atau mau melakukan semua itu pada akhir bulan ini ...

Kerja bagus, @andyferris! Apakah Anda bereksperimen dengan pembungkus lazy Conjugate sama sekali?

@andyferris Saya menendang ban, dan agak menyukai ini. Tampaknya benar-benar perbaikan, dan saya berharap masalah kinerja dapat ditangani saat kami menemukannya. Mari kita lihat apa yang orang lain katakan.

Terima kasih semuanya :)

Apakah Anda bereksperimen dengan pembungkus lazy Conjugate sama sekali?

Belum, meskipun mungkin tanpa terlalu banyak usaha, tapi sejujurnya saya khawatir tidak menyelesaikan sebanyak ini pada akhir Desember. Melihat ke masa depan, saya sedang mempertimbangkan bahwa pada akhirnya kita mungkin memiliki tipe "unionall" berikut untuk digunakan pada aljabar linier:

  • AbstractVector
  • Conjugate{V where V <: AbstractVector} (atau Conj{V} , bahkan mungkin ConjArray ? Tentu saja itu akan menerima array dari dimensi apapun)
  • TransposedVector (atau RowVector ?)
  • TransposedVector{Conjugate{V where V <: AbstractVector}}
  • AbstractMatrix
  • Conjugate{M where M <: AbstractMatrix}
  • TransposedMatrix (atau cukup Transpose{M} ?)
  • TransposedMatrix{Conjugate{M where M<:AbstractMatrix}}

(ditambah semua ciri yang diberikan dari penyimpanan yang mendasarinya, seperti apa yang sekarang kita sebut DenseArray dan StridedArray - Saya berharap # 18457 mungkin membuatnya sedikit lebih mudah untuk mengungkapkannya juga).

Selain penamaan, apakah itu terdengar seperti rencana yang masuk akal?

Adapun bikeshedding langsung, untuk PR ke Pangkalan dari apa yang saat ini ada dalam paket, apakah kita lebih suka TransposedVector , RowVector , pembungkus generik Transpose untuk vektor dan matriks , atau sesuatu yang lain?

Menurut saya perilaku yang diberikan oleh implementasi @andyferris cukup bagus, dan merupakan peningkatan. Tapi izinkan saya mencoba mengungkapkan kekhawatiran saya sedikit lebih baik.

Masalahnya adalah dengan mendefinisikan tipe array baru. Misalnya DArray adalah subtipe dari AbstractArray , jadi DArray juga bisa menjadi AbstractVector atau AbstractMatrix . Idealnya, kita hanya akan memperluas perbedaan Vektor / Matriks ke Baris / Kolom / Matriks, jadi DArray bisa menjadi AbstractRow , AbstractCol , atau AbstractMatrix . Hierarki tipe akan menjadi seperti

AbstractArray
    AbstractVector
        AbstractRowVector
        AbstractColumnVector
    AbstractMatrix
    ...

Bicara dengan

Mungkin ada beberapa prioritas di sini, karena tidak semua AbstractVector s dapat digunakan sebagai kolom, misalnya:

julia> isa(1.0:10.0, AbstractVector)
true

julia> randn(10,10) * 1.0:10.0
ERROR: MethodError: no method matching colon(::Array{Float64,2}, ::Float64)

yang dapat mengatasi masalah yang saya alami di https://github.com/JuliaLang/julia/issues/4774#issuecomment -59428215

Itu hanya tanda kurung yang hilang di sekitar rentang?

Itu hanya masalah prioritas:

julia> randn(10,10) * (1.0:10.0)
10-element Array{Float64,1}:
 -22.4311
  ⋮

Saya setuju bahwa solusi optimal di sini tampaknya memerlukan ciri-ciri, tetapi menurut saya itu tidak akan menghambat pekerjaan @andyferris .

ah, poin yang bagus. Akan sangat senang jika prioritas spasi yang salah menjadi kesalahan sintaks, mirip dengan Fortress.

Grup MIT menunjukkan bahwa salah satu cara untuk mengimplementasikan hierarki tipe yang saya jelaskan di atas adalah dengan menambahkan parameter tipe ke hierarki array:

abstract AbstractArray{T,N,row}

type Array{T,N,row} <: AbstractArray{T,N,row}
end

typealias AbstractVector{T} AbstractArray{T,1}
typealias AbstractRowVector{T} AbstractArray{T,1,true}
typealias AbstractColVector{T} AbstractArray{T,1,false}
typealias AbstractMatrix{T} AbstractMatrix{T,2}

typealias Vector{T} Array{T,1,false}
typealias Matrix{T} Array{T,2,false}

Saya belum mengetahui semua implikasi dari ini --- mungkin yang terburuk adalah bahwa Array{Int,1} menjadi tipe abstrak --- tetapi ini tampaknya mendapatkan tipe hierarki dan abstraksi yang dibutuhkan cukup tepat.

Untuk apa nilainya, ini persis kasus penggunaan untuk supertipe yang tidak diparameterisasi secara lengkap; mereka bisa menjadi parameter default implisit.

abstract AbstractArray{T,N,row}

type Array{T,N} <: AbstractArray{T,N}
end

isrow{T,N,row}(::AbstractArray{T,N,row}) = row
isrow{T,N}(::AbstractArray{T,N}) = false

julia> isrow(Array{Int,2}())
false

Tentu saja, hal itu membuat pengiriman sedikit berantakan… dan mungkin tidak ada gunanya mendukung. Itu hanya bola ludah.

Bagi saya itu sepertinya setara dengan mendefinisikan

type Array{T,N} <: AbstractArray{T,N,false}
end

Yang mungkin kita inginkan di sini adalah semacam "parameter tipe default", sehingga membuat tipe Array{X,Y} mana X dan Y tidak memiliki variabel bebas akan menghasilkan Array{X,Y,false} .

Ide lain: pertahankan notasi Householder untuk produk dalam v'v dan covector kiri kalikan v'A dengan membuat infix ' sebagai operatornya sendiri alih-alih menguraikannya sebagai v'*v dan v'*A . Ditambah dengan membuat v' identitas, v*v kesalahan, dan v*A kesalahan, ini bisa memberikan banyak hal yang diinginkan. Anda harus menulis hasil luar sebagai outer(v,v) .

Dalam skema seperti itu, v' akan menjadi noop atau bahkan kesalahan - karena tidak ada alasan untuk mengubah urutan vektor dalam skema seperti itu, ini hanya masuk akal untuk matriks.

@JeffBezanson Saya setuju memiliki AbstractRowVector akan menjadi yang terbaik (tapi sejujurnya saya tidak dapat memikirkan kasus penggunaan, jadi saya tidak menerapkannya dalam paket). Saya juga ingin menunjukkan ini bisa hidup sebagai subtipe dari AbstractMatrix . Alasan saya pindah ke arah ini adalah bahwa broadcast tampaknya lebih merupakan konsep inti bagi Julia daripada aljabar linier, dan orang akan mengharapkan vektor baris menjadi, ya, satu baris!

Tentu saja memiliki RowVector <: AbstractMatrix adalah penggunaan terminologi yang tidak menguntungkan! Saya pikir ini hasil dari memiliki array 2D dan matriks abstrak diberi nama yang sama.

Saya telah mengatakan ini sebelumnya, jauh di atas, tetapi karena masalah ini berlangsung lama, saya akan mengulanginya: dalam bahasa umum seperti Julia, properti "array data" harus menjadi pertimbangan utama untuk AbstractArray . Menjawab bagaimana Anda ingin broadcast berperilaku untuk vektor "dialihkan" memberi tahu Anda apakah itu 1D atau 2D. Jika Anda ingin berpikir dalam kerangka baris dan kolom, maka 1 x n vektor baris paling masuk akal. Jika Anda ingin mempertimbangkan vektor ganda, maka 1D paling masuk akal - dan saya juga senang dengan itu! Tetapi mengambil dua vektor lebih rumit daripada membentuk kembali data (misalnya kita harus setidaknya mendukung konjugasi).

Saya kira gambar "baris" akan sesuai dengan harapan pemrogram "biasa", sementara orang dengan pelatihan matematika tingkat lanjut mungkin akan mendapatkan penggunaan yang lebih baik dari vektor ganda karena ini adalah abstraksi yang lebih baik (meskipun saya yakin mereka akan dapat bersimpati dengan mereka yang hanya memiliki pengetahuan aljabar linier dasar). Jadi - audiens mana yang ditargetkan Julia - orang-orang dengan lebih banyak kemahiran matematika daripada banyak pengguna MATLAB pada umumnya, atau orang-orang dengan lebih sedikit?

(Menurut saya, karena Julia bertujuan menjadi bahasa pemrograman "umum", audiens terakhir adalah targetnya).

Karena kita membahas pohon jenis yang mungkin - di masa depan, dengan Buffer dan "daftar" yang dapat diubah ukurannya, saya membayangkan pohon abstrak dari antarmuka yang berjalan di sepanjang baris

AbstractArray{T,N} # interface includes broadcast, Cartesian, getindex, setindex!, etc.
    AbstractArray{T,1}
        AbstractList{T} # resizeable, overloaded with `push!` and so-on
        AbstractVector{T} # non-resizeable, overloaded for *, /, \, ', .', etc
    AbstractArray{T,2}
        AbstractRowVector{T} # non-resizeable, overloaded for *, /, \, ', .', etc
        AbstractMatrix{T} # non-resizeable, overloaded for *, /, \, ', .', etc

Tentu saja, kita bisa memiliki AbstractDualVector{T} <: AbstractArray{T,1} bukannya AbstractRowVector .

Memiliki tipe Array fleksibel dan konkret agar sesuai dengan semua ini akan sulit (dan mungkin tidak perlu). Ciri-ciri tentu akan memungkinkan kami mengekspresikan perbedaan ini dalam antarmuka yang didukung dengan lebih mudah.

Memiliki AbstractVector menjadi C ++ std::vector dan vektor aljabar linier tampak agak kurang ajar bagi saya :) (terutama karena antarmuka array berarti bahwa ia tidak pernah bisa benar-benar menjadi "vektor abstrak" di pengertian aljabar linier (misalnya bebas basis))

Ya, sebaiknya pisahkan perilaku pengubahan ukuran. Saya siap untuk itu.

Hierarki tipe itu sepertinya menyiratkan bahwa kita akan memiliki tipe beton "matriks" dan "array 2-d" yang terpisah di Basis. Kita dapat mencoba untuk menyiasatinya misalnya dengan memiliki konstruktor untuk Array{T,2} sebenarnya mengembalikan beberapa jenis matriks lain, tetapi tampaknya cukup jelek. Mungkin aku salah paham.

Hierarki tipe itu sepertinya menyiratkan bahwa kita akan memiliki tipe beton "matriks" dan "array 2-d" yang terpisah di Basis.

Benar ... Saya pikir untuk melakukan ini dengan baik, kita membutuhkan sifat. Perlu diingat saya menyebutnya sebagai "pohon antarmuka abstrak". Mencoba ini saat ini akan membutuhkan sesuatu yang jelek seperti yang Anda katakan. Tapi kita mungkin bisa memasukkan AbstractList <: AbstractVector (dan memindahkan metode terkait) segera setelah Buffer selesai.

Saat ini, koneksi antara antarmuka yang didukung dan pohon tipe cukup longgar. Sulit untuk mencari tahu saat pengiriman jika array (abstrak) dapat berubah (yaitu mendukung setindex! ), apakah dapat diubah ukurannya, melangkah hanya berfungsi untuk jenis yang ditentukan dalam Base , dll. Ini membuatnya sulit bagi pengguna untuk menyediakan fungsi dengan metode yang berfungsi dan efisien dengan berbagai input (ini pengalaman saya dari StaticArrays ).

Pemikiran untuk percakapan tentang wilayah matematika dari hierarki jenis dan peran yang wajar untuk abstraksi berparameter. Jika memungkinkan, adalah kebijakan yang baik bagi Julia untuk menyederhanakan dan meringankan setiap pemisahan tentang bagaimana kode ditulis untuk melakukan apa yang diinginkan oleh keahlian dari apa yang dimaksudkan oleh ahli.

Satu konvensi yang mungkin kita pilih untuk digunakan membuat praktik umum menggunakan jenis abstrak selain Any untuk membentuk wilayah ontotopologis di tengah-tengah jenis beton yang bersamaan merasa mudah berbagi istirahat. Itu akan membawa, dengan biaya yang sangat sedikit, kepekaan multi-kontekstual yang lebih besar - memahami beberapa bagian dari hierarki tipe membantu seseorang mendekati bagian lain.

Seperti yang saya lihat, ini adalah pembawa hubungan yang digeneralisasikan. Sebuah abstraksi yang menjelaskan menerangi sebagai konkresi yang mengarah pada lingkungan, kesamaan generatif yang membangun. Dengan parameterisasi yang menghadirkan kejelasan intuisi yang sederhana, Julia mendapatkan lebih banyak pencapaian dengan waktu yang lebih sedikit.

Oke, komentar lainnya tentang TransposedVectors akan kami hargai. Saya merasa sudah cukup solid dan siap untuk dijadikan PR, tapi ada beberapa isu relevan yang saya cantumkan di sini .

(misalnya: Apakah RowVector nama yang lebih baik daripada TransposedVector ? Apakah [1 2 3] a RowVector atau Matrix ? Apakah indices(row, 1) ?)

1 untuk RowVector

Pada 20 Des 2016 7:01 AM, "Andy Ferris" [email protected] menulis:

Oke, komentar lainnya tentang TransposedVectors akan kami hargai. saya rasa
Sudah cukup solid dan siap untuk dijadikan PR, tapi ada
beberapa masalah relevan yang saya cantumkan di sini
https://github.com/andyferris/TransposedVectors.jl/issues .

(misalnya: Apakah RowVector merupakan nama yang lebih baik daripada TransposedVector? Apakah [1 2
3] RowVector atau Matrix? Apa itu indeks (baris, 1)?)

-
Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/JuliaLang/julia/issues/4774#issuecomment-268170323 ,
atau nonaktifkan utasnya
https://github.com/notifications/unsubscribe-auth/AAm20YYqsXmprI23GgI5PYyWStpTOq5qks5rJ309gaJpZM4BMOXs
.

Saya benar-benar ingin menjaga konvensi baris- / kolom- darinya, dan menurut saya kedengarannya aneh memiliki Vector dan RowVector (atau bahkan ColVector dan RowVector ). +1 untuk TransposedVector atau DualVector

@felixrehren Saya merasa bahwa DualVector harus memiliki semantik yang berbeda dengan apa yang telah saya terapkan, terutama 1 dimensi (secara matematis, rangkap vektor adalah vektor) dan memiliki sifat dualitas lainnya (misalnya konjugasi kompleks) . Tidak apa-apa, tetapi saya merasa sedikit lebih sulit untuk diterapkan dan kurang kompatibel ke belakang.

Nama TransposedVector tidak apa-apa. Tapi itu agak lama. Selain itu, ini menunjukkan bahwa objek jenis itu hanya dapat diperoleh dengan mengubah urutan Vector . Tapi saya kira Anda bisa menghasilkan TransposedVector dengan cara lain juga, katakanlah, dengan mengekstrak satu baris matriks?

Saya pikir RowVector akan menjadi nama yang bagus - ringkas, akurat, dan intuitif. @felixrehren , menurut saya gambar baris / kolom sangat membantu. Ini bahkan mungkin tidak dapat dihindari, karena setiap kali Anda melakukan penggabungan atau operasi array umum lainnya (selain perkalian) Anda perlu memikirkan ke arah mana vektor itu berorientasi.

DualVector juga tidak buruk, tapi CoVector akan terdengar kurang formal.

PR yang saya ancam sebelumnya sekarang diserahkan pada # 19670. Saya menggunakan RowVector untuk saat ini.

Tapi saya kira Anda bisa membuat TransposedVector dengan cara lain juga, katakanlah, dengan mengekstrak satu baris matriks?

Ini sebenarnya adalah satu hal penting - saya belum memikirkan sintaks yang bagus untuk itu. Ada ide?

Tapi saya kira Anda bisa membuat TransposedVector dengan cara lain juga, katakanlah, dengan mengekstrak satu baris matriks?

Ini sebenarnya adalah satu hal penting - saya belum memikirkan sintaks yang bagus untuk itu. Ada ide?

Meskipun pada awalnya tampak menarik memiliki matrix[scalar,range] (dan konstruksi serupa lainnya) menghasilkan vektor baris, itu akan menjadi penyimpangan yang signifikan dari semantik pengindeksan saat ini untuk array multidimensi, dan kasus khusus membuat saya curiga.

Alih-alih, saya ingin melihat RowVector (dan Vector dalam hal ini) mengonversi jenis iterable apa pun ke dalam jenis vektor yang sesuai. Kemudian Anda dapat melakukan sesuatu seperti RowVector(matrix[scalar,range]) yang akan cukup jelas dan tidak mengganggu perilaku pengindeksan array saat ini.

Benar, baris i th dapat diekstraksi dalam bentuk baris oleh A[i,:].' , saat ini dalam v0.5 dan akan terus melakukannya di masa mendatang (untuk menghasilkan RowVector atau Transpose{V<:AbstractVector} atau apa pun yang akhirnya kita selesaikan (lihat di sini untuk diskusi berkelanjutan)). Mungkin itulah jawabannya.

Bagaimana dengan menambahkan dua fungsi baru ke Basis?
row(A,i) dan col(A,i)
Yang terakhir tidak diperlukan, tetapi hanya untuk simetri. Singkat, jelas, dan karakter sebanyak A[i,:].'

@benninkrs yang masuk akal. Sebaliknya, interpretasi intuitif saya adalah aljabar linier, di mana vektor tidak memiliki orientasi sama sekali. Semua sudut pandang ini masuk akal, saya hanya tidak suka Vector dan RowVector bersama-sama karena penamaannya terlihat seperti mencampurkan paradigma abstrak dan konkret.

Pada titik ini, saya pikir kita perlu menggunakan sesuatu yang didasarkan pada implementasi @andyferris atau memutuskan untuk tidak menganggap serius transposisi vektor. Sebagai contoh alternatif, berikut adalah pendekatan yang menangani gejala terburuk: biarkan v' seperti saat ini - yaitu menghasilkan matriks baris - tetapi parsing a'b sebagai operator infiks dengan prioritas tepat di bawah perkalian. Dengan kata lain kita akan memiliki perilaku berikut:

  1. v' adalah matriks baris (transposisi)
  2. v'v adalah skalar (produk titik)
  3. v'*v adalah vektor 1 elemen (matriks baris * vektor)
  4. v*v' adalah matriks hasil kali luar (matriks baris * vektor)
  5. v'A adalah matriks baris ("vecmat")
  6. v'*A adalah matriks baris (matmat)
  7. v'A*v adalah skalar (matvec A * v lalu produk titik)
  8. (v'A)*v adalah vektor 1 elemen (vecmat lalu matvec)
  9. v'*A*v adalah vektor 1 elemen (matmat lalu matvec)
  10. v'' adalah matriks kolom (transposisi vektor, kemudian matriks transposisi)

Dalam pengaturan saat ini, 2 dan 3 adalah setara dan 7, 8, dan 9 adalah setara, yang rusak oleh perubahan ini. Tapi yang terpenting, item yang berani adalah yang biasanya akan dijangkau orang karena merupakan yang terpendek dan paling nyaman dari bentuk serupa - dan semuanya melakukan apa yang kita inginkan. Tidak ada tipe baru, hanya satu operator infix baru. Kelemahan utamanya adalah 10 - v'' masih berupa matriks kolom. Bisa dibilang, ini bisa dilihat sebagai keuntungan karena postfix '' adalah operator untuk mengubah vektor menjadi matriks kolom.

Mengambil langkah mundur, saya pikir apa yang telah kita pelajari adalah bahwa tanpa fungsi pelabelan dimensi atau naik-turun tambahan atau memperlakukan ≤ 2 dimensi sebagai sepadan seperti yang dilakukan Matlab, array multidimensi tidak dapat benar-benar dibuat agar sesuai dengan mulus dengan aljabar linier. Jadi yang tersisa adalah pertanyaan kenyamanan - dapatkah kita membiarkan orang mengekspresikan operasi aljabar linier umum pada vektor dan matriks dengan nyaman tanpa membuat array yang terlalu rumit? Saya tidak mati-matian dalam pendekatan ini, tetapi saya pikir kita harus secara serius mempertimbangkan ini dan pendekatan lain yang membahas kenyamanan sintaksis tanpa terlalu banyak mengacaukan hierarki tipe array kita.

Pendekatan lain adalah mengurai infix a'b secara khusus (tepat di bawah * ) dan meminta v' mengembalikan vektor terkonjugasi. Secara lebih umum, postfix A' dapat mengkonjugasikan sebuah array dan dengan malas membalikkan dimensinya sementara A.' akan dengan malas membalikkan dimensi dari sebuah array sehingga bertindak sebagai identitas pada vektor. Dalam skema ini, daftar properti bisa jadi sebagai berikut:

  1. v' adalah vektor (terkonjugasi)
  2. v'v adalah skalar (produk titik)
  3. v'*v adalah kesalahan (rekomendasikan v'v untuk produk dalam dan outer(v,v) untuk produk luar) †
  4. v*v' adalah kesalahan (rekomendasikan v'v untuk produk dalam dan outer(v,v) untuk produk luar) †
  5. v'A adalah vektor (vecmat)
  6. v'*A adalah kesalahan (rekomendasikan v'A untuk vecmat)
  7. v'A*v adalah skalar (matvec A * v lalu produk titik)
  8. (v'A)*v adalah kesalahan (rekomendasikan v'v untuk produk dalam dan outer(v,v) untuk produk luar) †
  9. v'A'v adalah skalar ( v'(A'v) - konjugasi matvec lalu produk dalam)
  10. v'' adalah vektor ( v'' === v dan v.' === v )

Sekarang saya menulis semua properti ini, ini mungkin opsi yang lebih disukai: semua kasus kesalahan benar-benar berfungsi untuk membantu orang menemukan dan menggunakan sintaks yang disesatkan, dan tentu saja itu memiliki properti v'' === v diinginkan (dan cocok dengan baik dengan .' menjadi operator pembalikan dimensi generik). Memiliki sintaks yang sangat mirip yang hanya sedikit berbeda mungkin lebih membingungkan.

† Kami berpotensi menangkap ini pada waktu parse untuk kesalahan yang lebih tepat dengan risiko memberikan kesalahan untuk kasus di mana kode pengguna kelebihan beban ' dan * sehingga operasi ini berfungsi. Saya percaya memiliki pembungkus konjugasi malas mungkin diperlukan untuk membuat rekomendasi ini benar, tetapi kita tetap membutuhkannya untuk # 5332.

Mengambil langkah mundur, saya pikir apa yang telah kita pelajari adalah bahwa tanpa fungsi pelabelan dimensi atau naik-turun tambahan atau memperlakukan ≤ 2 dimensi sebagai sepadan seperti yang dilakukan Matlab, array multidimensi tidak dapat benar-benar dibuat agar sesuai dengan mulus dengan aljabar linier. Jadi yang tersisa adalah pertanyaan kenyamanan - dapatkah kita membiarkan orang mengekspresikan operasi aljabar linier umum pada vektor dan matriks dengan nyaman tanpa membuat array yang terlalu rumit? Saya tidak mati-matian dalam pendekatan ini, tetapi saya pikir kita harus secara serius mempertimbangkan ini dan pendekatan lain yang membahas kenyamanan sintaksis tanpa terlalu banyak mengacaukan hierarki tipe array kita.

: 100:

Secara eksplisit membuat postfix ' dan .' array generik (daripada aljabar linier) operasi dengan baik menghindari penggandaan penyimpanan dan tipe aljabar linier, dan membiarkan pintu terbuka untuk kerangka kerja yang melibatkan lebih sedikit kompromi. Untuk sementara, kemampuan operasi tersebut untuk mensimulasikan notasi Householder dalam banyak kasus umum harus memberikan sebagian besar kemudahan yang diinginkan. Juga lebih sedikit kode dan kerumitan. Terbaik!

Satu masalah dengan v.' menjadi no-op adalah bahwa A .+ v.' akan mengubah arti dari menambahkan nilai v ke setiap kolom A untuk menambahkan nilai ke baris A . Ini umumnya akan mempersulit untuk melakukan operasi seperti baris dengan vektor dan pasti akan membutuhkan siklus penghentian penuh untuk menghindari membuat kode diam-diam melakukan hal yang salah (dalam kasus seperti ini di mana A kebetulan persegi).

Pada titik ini, saya pikir kita perlu menggunakan sesuatu yang didasarkan pada implementasi @andyferris atau memutuskan untuk tidak menganggap serius transposisi vektor.

Saya menyadari batas waktu untuk v0.6 hampir tiba, tetapi saya akan berhati-hati agar tidak membuang bayi dengan air mandi. Pada tahap ini, tampak bahwa tampilan RowVector plus yang disebutkan untuk transpose matriks dan konjugasi array akan membuat kita mendapatkan:

  • IMO, jenis aljabar linier yang agak lebih masuk akal (kami tidak menyangkal keberadaan vektor ganda seperti sekarang, meskipun vektor baris dapat dilihat sebagai kasus khusus vektor ganda)
  • v'' === v
  • Beberapa hal di daftar Stefan seperti v1'v2 adalah produk titik
  • Semantik array yang kompatibel hampir mundur - misalnya hasil dari size(v') tidak berubah, tetapi kami memiliki v'' sebagai 1-dimensi
  • Lazy conj dan pembungkus transpose dapat meningkatkan kinerja dalam keadaan tertentu dan tetap berguna
  • Penghapusan semua fungsi Ac_mul_Bc untuk mendukung * dan A_mul_B! saja (dan juga untuk \ , / ).

Mendapatkan semua ini bekerja untuk Array sejujurnya tidak akan membutuhkan terlalu banyak usaha (bagi saya masalahnya adalah menemukan waktu pada saat ini tahun ini, dan mengejar semua jenis lain yang kita miliki dalam rangkaian aljabar linier kita). Dan poin terakhir adalah desahan lega.

Di sisi lain - IMHO aturan-aturan itu tampaknya sedikit rumit parsing dan mungkin sedikit membingungkan dan / atau mengejutkan bagaimana mereka menyusun ' dengan * (3, 4, 6 dan 8 akan bekerja dengan RowVector ).

Dan ya kami harus menghentikan v.' atau sesuatu untuk menyorot potensi bug, pada titik mana tampaknya lebih baik untuk membuat v.' kesalahan metode yang hilang (kami tidak akan mendukung baris / dua vektor, tetapi tidak akan menghentikan paket yang melakukannya jika diinginkan)

19670 tampak siap atau dekat dengannya, jika ada keinginan untuk menyelinap ke v0.6.

BAM

Woot.

Apakah ini utas masalah terpanjang kami?

Tidak, # 11004 memiliki lebih banyak

Maaf. Anda benar, saya harus menentukan utas masalah terbuka .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

musm picture musm  ·  3Komentar

omus picture omus  ·  3Komentar

felixrehren picture felixrehren  ·  3Komentar

wilburtownsend picture wilburtownsend  ·  3Komentar

manor picture manor  ·  3Komentar