Julia: أخذ المصفوفة ينقل على محمل الجد

تم إنشاؤها على ١٠ مارس ٢٠١٧  ·  141تعليقات  ·  مصدر: JuliaLang/julia

حاليًا ، transpose تكراري. هذا غير بديهي إلى حد ما ويؤدي إلى سوء الحظ:

julia> A = [randstring(3) for i=1:3, j=1:4]
3×4 Array{String,2}:
 "J00"  "oaT"  "JGS"  "Gjs"
 "Ad9"  "vkM"  "QAF"  "UBF"
 "RSa"  "znD"  "WxF"  "0kV"

julia> A.'
ERROR: MethodError: no method matching transpose(::String)
Closest candidates are:
  transpose(::BitArray{2}) at linalg/bitarray.jl:265
  transpose(::Number) at number.jl:100
  transpose(::RowVector{T,CV} where CV<:(ConjArray{T,1,V} where V<:(AbstractArray{T,1} where T) where T) where T) at linalg/rowvector.jl:80
  ...
Stacktrace:
 [1] transpose_f!(::Base.#transpose, ::Array{String,2}, ::Array{String,2}) at ./linalg/transpose.jl:54
 [2] transpose(::Array{String,2}) at ./linalg/transpose.jl:121

منذ بعض الوقت ، كنا نطلب من الأشخاص القيام بـ permutedims(A, (2,1)) بدلاً من ذلك. لكن أعتقد أننا جميعًا نعلم ، في أعماقنا ، أن هذا أمر مروع. كيف وصلنا إلى هنا؟ حسنًا ، من المفهوم جيدًا أن المرء يريد أن يكون ctranspose أو "المساعد" لمصفوفة من المصفوفات عودية. أحد الأمثلة المحفزة هو أنه يمكنك تمثيل الأعداد المركبة باستخدام مصفوفات 2 × 2 ، وفي هذه الحالة يكون "اتحاد" كل "عنصر" (في الواقع مصفوفة) هو المرتبط به كمصفوفة - وبعبارة أخرى ، إذا كان التحويل c تعاوديًا ، فكل شيء يعمل. هذا مجرد مثال ولكنه معمم.

يبدو أن المنطق كان كما يلي:

  1. يجب أن يكون ctranspose تعاوديًا
  2. ctranspose == conj ∘ transpose == conj ∘ transpose
  3. لذلك يجب أن يكون transpose عوديًا أيضًا

أعتقد أن هناك بعض المشاكل هنا:

  • لا يوجد سبب لضرورة الاحتفاظ بـ ctranspose == conj ∘ transpose == conj ∘ transpose ، على الرغم من أن الاسم يجعل هذا يبدو أمرًا لا مفر منه تقريبًا.
  • إن سلوك تشغيل عنصر conj على المصفوفات هو نوع من الاستبقاء المؤسف من Matlab وليس في الحقيقة عمليات مبررة رياضيًا ، مثل exp عنصر التشغيل ليس صحيحًا من الناحية الرياضية وما هو expm سيكون تعريفًا أفضل.
  • إنه يأخذ في الواقع مرافق (أي مساعد) لكل عنصر مما يعني أن ctranspose يجب أن يكون تكراريًا ؛ في حالة عدم وجود الاقتران ، لا يوجد سبب وجيه لجعل منقول العودية.

وفقًا لذلك ، أقترح التغييرات التالية لتصحيح الوضع:

  1. إعادة تسمية ctranspose (المعروف أيضًا باسم ' ) إلى adjoint - هذا هو ما تفعله هذه العملية حقًا ، وتحررنا من الإيحاء بأنه يجب أن يكون ما يعادل conj ∘ transpose .
  2. تم إهمال المتجه conj(A) على المصفوفات لصالح conj.(A) .
  3. أضف وسيطة الكلمة الأساسية recur::Bool=true إلى adjoint (née ctranspose ) للإشارة إلى ما إذا كان يجب استدعاء نفسها بشكل متكرر. بشكل افتراضي ، يفعل ذلك.
  4. أضف وسيطة الكلمة الأساسية recur::Bool=false إلى transpose للإشارة إلى ما إذا كان يجب استدعاء نفسها بشكل متكرر. بشكل افتراضي ، لا يفعل ذلك.

على أقل تقدير ، سيسمح لنا هذا بكتابة ما يلي:

julia> A.'
4×3 Array{String,2}:
 "J00"  "Ad9"  "RSa"
 "oaT"  "vkM"  "znD"
 "JGS"  "QAF"  "WxF"
 "Gjs"  "UBF"  "0kV"

ما إذا كان بإمكاننا تقصير ذلك إلى A' يعتمد على ما نريد فعله بـ conj و adjoint للأرقام غير (أو بشكل أكثر تحديدًا ، غير حقيقية ، غير - القيم المعقدة).

[هذا العدد هو الثاني من سلسلة ω₁ جزء.]

breaking decision linear algebra

التعليق الأكثر فائدة

(الوقت الإضافي: أنا أتطلع بالفعل إلى "أخذ 7 موترات على محمل الجد" ، الدفعة التالية في المسلسل القصير الناجح للغاية المكون من 6 أجزاء ...)

ال 141 كومينتر

الخلف المنطقي لإصدار سابق ... 👍

إن سلوك عوامل الربط التي تعمل بشكل عنصري على المصفوفات هو نوع من الاستبقاء المؤسف من Matlab وليس في الحقيقة عمليات مبررة رياضيًا

هذا ليس صحيحًا على الإطلاق ، ولا يشبه على الإطلاق exp . فضاءات المتجهات المعقدة ، والاقتران بها ، هي مفهوم رياضي راسخ تمامًا. راجع أيضًا https://github.com/JuliaLang/julia/pull/19996#issuecomment -272312876

المساحات المتجهية المعقدة ، واقترانها ، مفهوم رياضي راسخ تمامًا.

ما لم أكن مخطئًا ، فإن عملية الاقتران الرياضي الصحيحة في هذا السياق هي ctranspose بدلاً من conj (والتي كانت وجهة نظري تحديدًا):

julia> v = rand(3) + rand(3)*im
3-element Array{Complex{Float64},1}:
 0.0647959+0.289528im
  0.420534+0.338313im
  0.690841+0.150667im

julia> v'v
0.879291582684847 + 0.0im

julia> conj(v)*v
ERROR: DimensionMismatch("Cannot multiply two vectors")
Stacktrace:
 [1] *(::Array{Complex{Float64},1}, ::Array{Complex{Float64},1}) at ./linalg/rowvector.jl:180

تكمن مشكلة استخدام كلمة رئيسية لـ recur أنه ، في آخر مرة تحققت فيها ، كانت هناك عقوبة كبيرة على الأداء لاستخدام الكلمات الرئيسية ، وهي مشكلة إذا انتهى بك الأمر إلى استدعاء هذه الوظائف بشكل متكرر مع حالة أساسية تنتهي في عددي.

نحن بحاجة إلى إصلاح مشكلة أداء الكلمات الرئيسية في 1.0 على أي حال.

@ StefanKarpinski ، أنت مخطئ. يمكن أن يكون لديك اقتران معقد في فضاء متجه دون وجود نقاط مساعدة - تعتبر النقاط المساعدة مفهومًا يتطلب مساحة هيلبرت وما إلى ذلك ، وليس مجرد مساحة متجهية معقدة.

علاوة على ذلك ، حتى عندما يكون لديك مساحة هيلبرت ، فإن الاقتران المركب يختلف عن المساعد. على سبيل المثال ، يعتبر اتحاد متجه عمود معقد في ℂⁿ متجهًا معقدًا آخر ، ولكن العامل المساعد هو عامل خطي ("متجه صف").

(لا يعني الاقتران مجمع أنه يمكنك مضاعفة conj(v)*v !)

إن إهمال vectorized conj مستقل عن باقي الاقتراح. هل يمكنك تقديم بعض المراجع لتعريف الاقتران المعقد في مساحة متجهية؟

https://en.wikipedia.org/wiki/Complexification#Complex_conjugation

(هذا العلاج رسمي إلى حد ما ؛ ولكن إذا بحثت في Google عن "مصفوفة مترافقة معقدة" أو "متجه مترافق معقد" ، فستجد عددًا من الاستخدامات.

إذا كان تعيين متجه معقد إلى المتجه المقترن (ما يفعله conj الآن) هو عملية مهمة تختلف عن تعيينها إلى covector (ما يفعله ' ) ، فيمكننا بالتأكيد الاحتفاظ بـ conj للتعبير عن هذه العملية على المتجهات (والمصفوفات ، والمصفوفات الأعلى ، على ما أعتقد). يوفر هذا تمييزًا بين conj و adjoint لأنهم سيتفقون على الحجميات لكنهم يتصرفون بشكل مختلف في المصفوفات.

في هذه الحالة ، هل يجب على conj(A) استدعاء conj على كل عنصر أم استدعاء adjoint ؟ تمثيل الأعداد المركبة كمثال مصفوفات 2 × 2 يشير إلى أن conj(A) يجب أن يستدعي بالفعل adjoint لكل عنصر ، بدلاً من استدعاء conj . سيؤدي ذلك إلى جعل adjoint و conj و conj. جميع العمليات المختلفة:

  1. adjoint : قم بتبديل مؤشرات i و j وقم بتعيين adjoint على العناصر بشكل متكرر.
  2. conj : رسم خريطة adjoint فوق العناصر.
  3. conj. : رسم خريطة conj فوق العناصر.

conj(A) باستدعاء conj على كل عنصر. إذا كنت تمثل الأعداد المركبة بواسطة مصفوفات 2 × 2 ، فلديك مساحة متجهية معقدة مختلفة.

على سبيل المثال ، هناك استخدام شائع لاقتران المتجهات في تحليل القيم الذاتية للمصفوفات الحقيقية : تأتي القيم الذاتية والمتجهات الذاتية في أزواج مترافقة معقدة. الآن ، لنفترض أن لديك مصفوفة كتلة ممثلة بمصفوفة ثنائية الأبعاد A من مصفوفات 2x2 حقيقية ، تعمل على متجهات محظورة v ممثلة بمصفوفات 1d لمتجهات مكونة من مكونين. لأي قيمة eigenvalue λ A مع eigenvector v ، نتوقع قيمة eigenvector ثانية conj(λ) مع eigenvector conj(v) . لن يعمل هذا إذا كان conj يستدعى adjoint بشكل متكرر.

(لاحظ أن النقطة المساعدة ، حتى بالنسبة لمصفوفة ، قد تكون مختلفة عن التحويل المترافق ، لأن المقارن من عامل خطي محدد بالطريقة الأكثر عمومية يعتمد أيضًا على اختيار المنتج الداخلي. هناك الكثير من التطبيقات الحقيقية حيث نوع المنتج الداخلي الموزون مناسب ، وفي هذه الحالة الطريقة المناسبة لأخذ التغييرات المرافقة لمصفوفة! لكنني أوافق على أنه ، في ضوء Matrix ، يجب أن نأخذ المقابل المقابل للمنتج الداخلي القياسي المعطى بواسطة dot(::Vector,::Vector) . ومع ذلك ، فمن المحتمل تمامًا أن بعض أنواع AbstractMatrix (أو غيرها من عوامل التشغيل الخطية) قد ترغب في تجاوز adjoint للقيام بشيء مختلف.)

بالمقابل ، هناك أيضًا بعض الصعوبة في تحديد adjoint(A) معقول جبريًا للمصفوفات ثلاثية الأبعاد ، لأننا لم نحدد المصفوفات ثلاثية الأبعاد كمعاملين خطيين (على سبيل المثال ، لا توجد عملية مضمنة array3d * array2d ) . ربما يجب تحديد adjoint بشكل افتراضي فقط للمصفوفات الحجمية و 1 d و 2 d؟

تحديث: حسنًا: لم نحدد ctranspose الآن للمصفوفات ثلاثية الأبعاد أيضًا. الاستمرار في.

(الوقت الإضافي: أنا أتطلع بالفعل إلى "أخذ 7 موترات على محمل الجد" ، الدفعة التالية في المسلسل القصير الناجح للغاية المكون من 6 أجزاء ...)

إذا كنت تمثل الأعداد المركبة بواسطة مصفوفات 2 × 2 ، فلديك مساحة متجهية معقدة مختلفة.

أنا لا أتبع هذا - يجب أن يتصرف تمثيل المصفوفة 2 × 2 للأعداد المركبة تمامًا مثل وجود مقاييس معقدة كعناصر. أعتقد ، على سبيل المثال ، إذا حددنا

m(z::Complex) = [z.re -z.im; z.im z.re]

ولدينا متجه معقد تعسفي v ثم نريد أن تحمل هذه الهوية:

conj(m.(v)) == m.(conj(v))

أود توضيح المثال أكثر وإجراء مقارنة مع ' الذي من المفترض أن يتنقل بالفعل بـ m لكن لا يمكنني ذلك بسبب https://github.com/JuliaLang/julia/ القضايا / 20979 ، الذي يكسر بطريق الخطأ هذا التخفيف. بمجرد إصلاح هذا الخطأ ، سيظل m.(v)' == m.(v') صامدًا ، ولكن إذا كنت أفهمك بشكل صحيح ، conj(m.(v)) == m.(conj(v)) كذلك؟

conj(m(z)) يجب == m(z) .

m(z) هو تماثل للأعداد المركبة تحت الجمع والضرب ، لكنه ليس نفس الكائن بطرق أخرى للجبر الخطي ، ولا ينبغي لنا أن نتظاهر بأنه مقابل conj . على سبيل المثال ، إذا كان z عددًا معقدًا ، فعندئذٍ eigvals(z) == [z] ، لكن eigvals(m(z)) == [z, conj(z)] . عندما تمتد خدعة m(z) إلى مصفوفات معقدة ، فإن مضاعفة الطيف هذه لها عواقب صعبة على سبيل المثال الطرق التكرارية (انظر على سبيل المثال هذه الورقة ).

هناك طريقة أخرى لوضعها وهي أن z هو بالفعل مساحة متجهية معقدة (مساحة متجه على الأرقام المركبة) ، لكن المصفوفة الحقيقية 2x2 m(z) هي مساحة متجهية فوق الأرقام الحقيقية (أنت يمكن مضاعفة m(z) في رقم حقيقي)… إذا قمت "بتعقيد" m(z) بضربها في رقم مركب مثل m(z) * (2+3im) ( وليس m(z) * m(2+3im) ) فأنت احصل على مساحة متجهية معقدة مختلفة ليست متشابهة بعد الآن إلى مساحة المتجه المعقدة الأصلية z .

يبدو أن هذا الاقتراح سيؤدي إلى تحسين حقيقي: +1: أفكر في الجانب الرياضي:

  • كما أفهم ، فإن الاقتران هو إجراء على الحلقة (اقرأ: الأرقام) التي توفر معاملات فضاء / متجهات المتجهات. يحث هذا الإجراء على إجراء آخر على مساحة المتجه (وعلى التعيينات الخاصة به ، اقرأ: المصفوفات) ، والتي تسمى أيضًا الاقتران ، من خلال خطية بناء مساحة المتجه فوق الحلقة. ومن ثم ، فإن الاقتران يعمل بالضرورة عن طريق تطبيق العناصر على المعاملات. بالنسبة إلى Julia ، هذا يعني أنه في جوهر المتجه v ، conj(v) = conj.(v) ، وهو اختيار تصميم سواء كان conj يحتوي على طرق أيضًا للمصفوفات أو فقط للكميات ، وكلاهما يبدو بخير؟ (نقطة ستيفن حول مثال المصفوفات المركبة مثل 2 × 2 هي أن هذا فضاء متجه تكون معاملاته حقيقية رسميًا / فعليًا ، لذلك لا يوجد تأثير للاقتران هنا.)
  • adjoint له معنى جبري أساسي في الكثير من المجالات المهمة التي تتضمن الجبر الخطي بشكل وثيق (انظر 1 و 2 و 3 ، وكلها لها تطبيقات كبيرة في الفيزياء أيضًا). إذا تمت إضافة adjoint ، فيجب أن تسمح باستخدام وسيطات الكلمات الرئيسية للإجراء قيد الدراسة - في مسافات متجهية / تحليل وظيفي ، يحدث هذا الإجراء عادةً بواسطة المنتج الداخلي ، وبالتالي يمكن أن تكون وسيطة الكلمة الأساسية هي النموذج بدلاً من ذلك. أيًا كان ما تم تصميمه لعمليات نقل جوليا ، يجب أن يتجنب التعارض مع هذه التطبيقات ، لذلك أعتقد أن adjoint باهظ الثمن بعض الشيء؟

felixrehren ، لا أعتقد أنك ستستخدم وسيطة الكلمة الأساسية لتحديد المنتج الداخلي الذي يحث على المساعد. أعتقد أنك ستستخدم نوعًا مختلفًا بدلاً من ذلك ، تمامًا كما لو كنت تريد تغيير معنى dot للمتجه.

سيكون مفضلتي أبسط قليلاً:

  • احتفظ ب conj كما هو (بشكل أساسي).
  • اجعل a' يتوافق مع adjoint(a) ، واجعله متكررًا دائمًا (وبالتالي يفشل لمصفوفات السلاسل وما إلى ذلك حيث adjoint غير معرّف للعناصر).
  • اجعل a.' يتوافق مع transpose(a) ، واجعله لا يتكرر أبدًا (فقط permutedims ) ، وبالتالي تجاهل نوع العناصر.

لا أرى حقًا حالة استخدام لـ adjoint غير متكرر. كامتداد ، يمكنني أن أتخيل نوعًا من حالات الاستخدام لعودة transpose ، ولكن في أي تطبيق حيث يتعين عليك تغيير a.' إلى transpose(a, recur=true) يبدو الأمر بنفس السهولة استدعاء وظيفة أخرى transposerecursive(a) . يمكننا تحديد transposerecursive في الأساس ، لكنني أعتقد أن الحاجة إلى ذلك ستكون نادرة جدًا لدرجة أننا يجب أن ننتظر لنرى ما إذا كانت ستظهر بالفعل.

أنا شخصياً أشعر أن الحفاظ على هذا بسيط سيكون هو الأكثر وضوحًا للمستخدمين (وللتنفيذ) ، وسيظل قابلاً للدفاع تمامًا في مقدمة الجبر الخطي.

حتى الآن (معظم) إجراءات الجبر الخطية لدينا متجذرة بقوة في هياكل المصفوفات القياسية والمنتج الداخلي القياسي. في كل فتحة من المصفوفة أو المتجه ، تضع عنصرًا في "مجالك". سوف أزعم أنه بالنسبة لعناصر الحقول ، فإننا نهتم بـ + ، * ، إلخ ، و conj ، لكن ليس transpose . إذا كان مجال عملك تمثيل معقدة خاص والتي تبدو قليلا مثل مصفوفة 2X2 حقيقية ولكن يتغير تحت conj ، ثم أن لOK - انها خاصية conj . إذا كان الأمر مجرد 2x2 AbstractMatrix حقيقي ولا يتغير تحت conj ، فيمكن القول إذن أن عناصر المصفوفة هذه لا يجب أن تتغير تحت المرافقة (

على أي حال ، فإن المثال المركب 2 × 2 يبدو لي قليلاً من الرنجة الحمراء. كان السبب الحقيقي لسلوك المصفوفة العودية بمثابة اختصار لعمل الجبر الخطي على مصفوفات الكتلة. لماذا لا نتعامل مع هذه الحالة الخاصة برعاية مناسبة ، ونبسط النظام الأساسي؟

لذا فإن اقتراحي "المبسط" سيكون:

  • احتفظ بـ conj كما هو (أو اجعله طريقة عرض مقابل AbstractArray s)
  • اجعل a' عرضًا غير متكرر مثل (a')[i,j] == conj(a[j,i])
  • اجعل a.' طريقة عرض غير متكررة مثل (a.')[i,j] == a[j,i]
  • قم بتقديم نوع BlockArray للتعامل مع مصفوفات الكتلة وما إلى ذلك (في Base ، أو ربما في حزمة مدعومة جيدًا). يمكن القول أن هذا سيكون أكثر قوة ومرونة من Matrix{Matrix} لهذا الغرض ، ولكن بنفس الكفاءة.

أعتقد أن هذه القواعد ستكون بسيطة بما يكفي ليتبناها المستخدمون والبناء عليها.

ملاحظة -StefanKarpinski لأسباب عملية ، لن تعمل وسيطة الكلمات الأساسية المنطقية

لقد ذكرت أيضًا في مكان آخر ، لكنني سأضيفها هنا للتأكد من اكتمالها: تتميز طرق العرض العودية بالخاصية المزعجة التي قد يتغير بها نوع العنصر مقارنة بالمصفوفة التي يتم تغليفها. على سبيل المثال ، transpose(Vector{Vector}) -> RowVector{RowVector} . لم أفكر في طريقة للحصول على هذا النوع من العناصر مقابل RowVector بدون عقوبة وقت التشغيل أو عن طريق استدعاء الاستدلال لحساب نوع المخرجات. أظن أن السلوك الحالي (استدعاء الاستدلال) غير مرغوب فيه من وجهة نظر اللغة.

ملحوظة: لا يوجد أيضًا ما يمنع المستخدمين من تحديد conj لإرجاع نوع مختلف - لذا فإن عرض ConjArray يعاني أيضًا من هذه المشكلة ، سواء كان التحويل متكررًا أم لا.

stevengj - لقد تثير هذه النقطة andyferris أفضل (تبديل غير تكراري وضبط). أعتقد أن كلاً من مثال 2x2 المركب وتمثيل مصفوفة الكتلة "يريد" أن يكون المساعد متكررًا هو إيحائي ، ولكن بالنظر إلى تعليقاتك حول هذا المثال الأول ، يجب أن أتساءل عما إذا لم تكن هناك حالات أخرى حيث أكثر صحة / ملائمة.

إذا لم يكن الضبط المساعد تعاوديًا ، فهو ليس مساعدًا. إنه مجرد خطأ.

هل يمكنك تقديم المزيد من المبررات لذلك عندما يكون لديك لحظة؟

يجب أن تكون النقطة المساعدة للمتجه عاملًا خطيًا يرسمه إلى عدد قياسي. أي أن a'*a يجب أن يكون عددًا إذا كان a متجهًا. ويؤدي هذا إلى إحداث ملحق مناظر في المصفوفات ، نظرًا لأن الخاصية المحددة هي a'*A*a == (A'*a)'*a .

إذا كان a متجهًا للمتجهات ، فهذا يعني أن a' == adjoint(a) يجب أن يكون تكراريًا.

حسنًا ، أعتقد أنني أتابع هذا.

لدينا أيضًا منتجات داخلية متكررة:

julia> norm([[3,4]])
5.0

julia> dot([[3,4]], [[3,4]])
25

من الواضح أن "المساعد" أو "الثنائي" أو أي شيء يجب أن يكون عوديًا بالمثل.

أعتقد أن السؤال المركزي إذن هو ، هل نطلب ذلك a' * b == dot(a,b) لجميع المتجهات a ، b ؟

البديل هو أن نقول أن ' لا يعيد بالضرورة النقطة المساعدة - إنها مجرد عملية مصفوفة تنقل العناصر وتمررها عبر conj . هذا يحدث فقط ليكون المساعد للعناصر الحقيقية أو المعقدة.

هناك سبب واحد فقط لأن لدينا اسمًا خاصًا ورموزًا خاصة للملحقات في الجبر الخطي ، وهي العلاقة مع المنتجات الداخلية. هذا هو السبب في أن "التحويل المترافق" عملية مهمة و "الدوران المترافق للمصفوفات بمقدار 90 درجة" ليس كذلك. ليست هناك جدوى في وجود شيء ما هو "مجرد عملية صفيف مقايضة الصفوف والأعمدة وتقارن" إذا كان غير متصل لمنتجات نقطة.

يمكن للمرء تحديد علاقة مماثلة بين transpose و "منتج نقطي" غير مقترن ، والذي قد يجادل في تبديل تكراري. ومع ذلك ، فإن "المنتجات النقطية" غير المقترنة للبيانات المعقدة ، والتي ليست في الحقيقة منتجات داخلية على الإطلاق ، لا تظهر تقريبًا مثل المنتجات الداخلية الحقيقية - فهي تنشأ من علاقات ثنائية التعامد عندما يتم كتابة عامل في معقد- شكل متماثل (غير هرميتاني) - ولا يحتوي حتى على دالة جوليا مضمنة أو مصطلحات شائعة في الجبر الخطي ، في حين أن الرغبة في تبديل الصفوف والأعمدة من المصفوفات غير الرقمية العشوائية تبدو أكثر شيوعًا ، خاصة مع البث. لهذا السبب يمكنني دعم جعل transpose غير متكرر مع ترك adjoint متكررًا.

أنا أرى. لذا فإن إعادة تسمية ' إلى adjoint ستكون جزءًا من التغيير ، لتوضيح أنه ليس conj ∘ transpose ؟

الشيء الذي دائمًا ما يربكني مع المصفوفات العودية هو: ما هو العدد القياسي في هذا السياق؟ في جميع الحالات التي أعرفها ، يقال إن عناصر المتجه هي سلالم. حتى في الحالة التي يكتب فيها عالم رياضيات بنية كتلة متجه / مصفوفة على قطعة من الورق ، ما زلنا نعرف أن هذا مجرد اختصار لمتجه / مصفوفة أكبر حيث تكون العناصر على الأرجح أرقامًا حقيقية أو معقدة (أي BlockArray ). تتوقع أن تكون المقاييس قادرة على الضرب تحت * ، ولا يختلف نوع الحجم القياسي عادةً بين المتجه والثنائي.

andyferris ، بالنسبة لمساحة متجه عامة ، فإن الحجميات عبارة عن حلقة (أرقام) يمكنك ضرب المتجهات بها. يمكنني أن أفعل 3 * [[1,2], [3,4]] ، لكن لا يمكنني فعل [3,3] * [[1,2], [3,4]] . لذا ، حتى بالنسبة إلى Array{Array{Number}} ، فإن النوع القياسي الصحيح هو Number .

متفق عليه - ولكن عادة ما يقال إن العناصر (نفس) الحجميات ، أليس كذلك؟

العلاجات التي رأيتها ، على أي حال ، تبدأ بحلقة ، وتبني منها مساحة متجهة. تدعم الحلقة + ، * ، لكنني لم أر علاجًا يتطلب دعمه adjoint ، dot ، أو أيًا كان.

(آسف ، أنا فقط أحاول فهم الكائن الرياضي الأساسي الذي نقوم بنمذجه).

يعتمد ذلك على ما تقصده بكلمة "اختصار" وما تقصده بكلمة "عناصر".

على سبيل المثال ، من الشائع جدًا وجود متجهات ذات حجم محدود من الوظائف ، و "مصفوفات" لمشغلي الأبعاد اللانهائية. على سبيل المثال ، ضع في اعتبارك الشكل التالي من معادلات ماكسويل العيانية :

image

في هذه الحالة ، لدينا مصفوفة 2 × 2 من العوامل الخطية (مثل الضفائر) تعمل على متجهات مكونة من مكونين والتي تكون "عناصرها" حقول متجهية مكونة من 3 مكونات. هذه نواقل فوق المجال القياسي للأعداد المركبة. بمعنى ما ، إذا قمت بالبحث بشكل كافٍ ، فإن "عناصر" المتجهات تكون أعدادًا معقدة - مكونات فردية للحقول في نقاط فردية في الفضاء - لكن هذا غامض نوعًا ما.

أو ربما بشكل أكثر دقة ، ألا يمكننا دائمًا استخدام الحلقة لوصف معاملات المتجه في بعض الأساس (نظرًا لطبيعة مصفوفة الأشياء في جوليا ، لن نذهب بدون أساس)؟

على أي حال ، لا تزال النتيجة أن المساعد يجب أن يكون تعاوديًا ، أليس كذلك؟ أنا لا أفهم إلى أي نقطة وصلت.

(أعتقد أننا يمكن أن نكون بلا أساس مطلقًا ، نظرًا لأن كائنات أو عناصر المصفوفات يمكن أن تكون تعبيرات رمزية على SymPy أو بعض بنية البيانات الأخرى التي تمثل كائنًا رياضيًا مجردًا ، ويمكن للنقطة المجاورة إرجاع كائن آخر عند ضربه متكامل ، على سبيل المثال.)

أنا فقط أحاول أن أفهم بشكل أفضل ، وليس توضيح نقطة معينة :)

بالتأكيد ، في ما سبق ، يكون المساعد تكراريًا. كنت أتساءل عما إذا كان من الأفضل ، على سبيل المثال ، التفكير في [E, H] أنه BlockVector الذي (بلا حدود؟) العديد من العناصر معقدة ، أو كمتجه 2 عناصره هي حقول متجه. أعتقد أنه في هذه الحالة ، لن يكون نهج BlockVector عمليًا.

شكرا على أي حال.

لذا ، ربما يمكنني استخلاص أفكاري بهذا الشكل:

بالنسبة إلى المتجه v ، أتوقع نوعًا ما أن يصف length(v) أبعاد فضاء المتجه ، أي عدد المعاملات العددية التي أحتاجها (بالكامل) لوصف عنصر من مساحة المتجه ، و كما أن هذا v[i] يُرجع المعامل القياسي i th. حتى الآن ، لم أفكر في AbstractVector أنه "متجه مجردة" ، ولكن بالأحرى كائن يحمل معاملات عنصر في مساحة متجهية معينة نظرًا لبعض الأسس التي يعرفها المبرمج.

بدا وكأنه نموذج عقلي بسيط ومفيد ، ولكن ربما يكون هذا مقيدًا جدًا / غير عملي.

(تحرير: إنه مقيد لأنه في Vector{T} ، يجب أن يتصرف T كقياس لعدد عمليات الجبر الخطي لتعمل.)

لكن لا يمكنني فعل [3,3] * [[1,2], [3,4]]

يمكننا إصلاح ذلك. لست متأكدًا مما إذا كانت فكرة جيدة أم لا ، ولكن من المؤكد أنها يمكن أن تعمل.

لست متأكدًا من أنه مرغوب فيه ... في هذه الحالة ، [3,3] ليس في الواقع عددًا قياسيًا. (لدينا أيضًا بالفعل القدرة على القيام بـ [3,3]' * [[1,2], [3,4]] - وهو ما لا أعرف حقًا كيفية تفسيره بمعنى الجبر الخطي).

يُظهر هذا حالة زاوية مثيرة للاهتمام: يبدو أننا نقول أن v1' * v2 هو المنتج الداخلي (وبالتالي يُرجع "عددًا") ، ولكن [3,3]' * [[1,2], [3,4]] == [12, 18] . مثال مفتعل ، أفترض.

في هذه الحالة [3,3] هو العددية: سكالارس عناصر في الحلقة الأساسية، وهناك الكثير من الطرق الجيدة لجعل العناصر من النموذج [a,b] في حلقة (وبالتالي التي تحدد ناقلات / المصفوفات فوقها). حقيقة أنها مكتوبة كمتجهات ، أو حقيقة أن هذه الحلقة نفسها تشكل فراغًا متجهًا فوق حلقة أساسية أخرى ، لا يغير ذلك. (يمكنك أن تأخذ أي تدوين آخر قد يخفي المتجهات! أو يجعله يبدو مختلفًا تمامًا.) كما كان andyferris يقترب ، ما هو العددي يعتمد على السياق.

بشكل رسمي ، العودية ليست جزءًا من المساعد. بدلاً من ذلك ، فإن اقتران العناصر العددية يقوم بهذا الجزء من العمل - وغالبًا ، إذا تم تمثيل العدد القياسي s كمصفوفة ، فإن اقتران s سيتضمن نقل المصفوفة التي نستخدمها للإشارة عليه. ولكن هذا ليس هو الحال دائمًا ، فهو يعتمد على البنية التي يمنحها المستخدم لحلقة الحجميات.

أعتقد أن فرض العودية الإضافية يمكن أن يكون حل وسط عملي ، نموذجي للتطبيقات من نوع matlab. ولكن بالنسبة لي ، فإن أخذ الأمر على محمل الجد يعني أنه لا يوجد تكرارات تكرارية واستخدام مقاسات مكتوبة + إرسال للسماح بدولار conj يعمل السحر الضروري مهما كان هيكل الحلقة الأساسية.

في هذه الحالة ، يكون [3،3] عدديًا: الحجميات هي عناصر في الحلقة السفلية

باستثناء مثل هذا الحجم ، ليس عنصرًا في الحلقة محددًا بواسطة + ، * . لا يدعم * ؛ لا أستطيع فعل [3,3] * [3,3]

أعتقد أن فرض العودية الإضافية يمكن أن يكون حل وسط عملي ، نموذجي للتطبيقات من نوع matlab. ولكن بالنسبة لي ، فإن أخذ الأمر على محمل الجد يعني أنه لا يوجد تكرارات تكرارية واستخدام مقاسات مكتوبة + إرسال للسماح بدولار conj يعمل السحر الضروري مهما كان هيكل الحلقة الأساسية.

أوافق ، إذا أردنا القيام بتضمين عملي ، فهذا جيد تمامًا وهذا ما فعلناه حتى الآن ، ولكن يبدو لي أن المقاييس الأساسية هي تلك الخاصة بالمصفوفة المسطحة بالكامل وهذا ما يُعرّف الجبر الخطي عليه . لدينا التكنولوجيا لجعل BlockVector و BlockMatrixBlockDiagonal ، إلخ) التي تقدم عرضًا فعالاً ومسطّحًا للمصفوفة الموسعة بالكامل ، لذا فإن "الجدية الفائقة "يجب أن يكون النهج ، على الأقل ، قابلاً للتنفيذ. كما أنني أعتقد أنه سيكون سهل الاستخدام تمامًا مثل النهج التكراري (بعض الأحرف الإضافية لكتابة BlockMatrix([A B; C D]) في مقابل ما قد يكون رمزًا دلاليًا أجمل وربما أكثر قابلية للقراءة - أنا متأكد من هذه النقاط للمناقشة). ومع ذلك ، فإن تنفيذ كل ذلك يتطلب المزيد من العمل.

andyferris أنت على حق ، فهم ليسوا حلقة لأن * غير معرّف - لكن أعتقد أننا في نفس الصفحة التي يمكن تعريف * بسهولة ، وهناك العديد من الطرق المختلفة للقيام بذلك والتي ستعطي بنية الحلقة. لذلك أفترض أننا في نفس الصفحة: الكتابة هي الطريقة الأكثر قابلية للتوسع لحل هذا.

(حول الحجميات: الحجميات ليست بالضرورة عناصر البنية المسطحة بالكامل! السبب هو هذا. فضاء متجه مركب أحادي البعد هو بعد واحد فوق الأعداد المركبة وثاني الأبعاد فوق الأرقام الحقيقية ؛ ولا يمثل أي منهما خاص. الرباعية هي ثنائية الأبعاد فوق الأعداد المركبة. الأوكتونات هي ثنائية الأبعاد فوق المحاجر ، و 4 أبعاد فوق الأعداد المركبة ، و 8 أبعاد فوق القيم الحقيقية. ولكن لا يوجد سبب للإصرار على أن الثماني أبعاد "8 أبعاد" بعد الآن من الإصرار على أن مقاييسهم هي الأرقام الحقيقية وليست معقدة ؛ هذه اختيارات لا تفرضها المنطق. إنها مسألة تمثيل بحت ، يجب أن يُسمح للمستخدم بهذه الحرية لأن الجبر الخطي هو نفسه في كل حالة. وتحصل على سلاسل أطول بكثير من هذه المساحات مع حلقات متعددة الحدود [مقطوعة] ، أو امتدادات جبرية لحقول الأرقام ، وكلاهما له تطبيقات حية مع المصفوفات. ليس على جوليا أن تذهب بعيدًا إلى هذا الحد في حفرة الأرانب يجب أن تتذكر أنها موجودة ، حتى لا تمنعها. ربما موضوع الخطاب؟ :))

felixrehren ، من الأفضل فهم متجه النواقل فوق حلقة R على أنه فضاء إجمالي مباشر ، وهو أيضًا فضاء متجه فوق R. ومن غير المنطقي تسمية المتجهات نفسها "الحلقة الأساسية" ، لأنها بشكل عام ليست حلقة. ينطبق هذا المنطق تمامًا على [[1,2], [3,4]] .

عادة ما يكون الاقتران والمساعدات مفاهيم منفصلة ؛ إن القول بأن "اقتران العناصر العددية" يجب أن يؤدي العمل هنا يبدو غير صحيح تمامًا بالنسبة لي - على عكس "الجاد" - إلا في الحالة الخاصة المذكورة أدناه.

ضع في اعتبارك حالة "متجهات العمود المكونة من عنصرين" (| u⟩ ، | v⟩) لعنصرين | u⟩ و | v⟩ في بعض مساحة هيلبرت H فوق بعض الحلقات (مثل الأرقام المركبة ℂ) ، في تدوين ديراك: "نواقل النواقل". هذه مساحة هيلبرت ذات المجموع المباشر H⊕H مع المنتج الداخلي الطبيعي ⟨(| u⟩، | v⟩)، (| w⟩، | z⟩)⟩ = ⟨u | w⟩ + ⟨v | z⟩. لذلك يجب أن ينتج المساعد الخطي المشغل الخطي الذي يتكون من "متجه الصف" (⟨u | ⟨v |) ، التي تكون عناصرها بحد ذاتها عوامل تشغيل خطية: العامل المساعد هو"متكرر" . هذا يختلف تمامًا عن الاتحاد المعقد ، الذي ينتج عنصرًا من نفس فضاء هيلبرت H⊕H ، الناجم عن اقتران الحلقة السفلية.

أنت تخلط في الأمر بالإشارة إلى المتجهات على المربعات ، إلى آخره. إذا كانت "عناصر" المتجه هي أيضًا عناصر من الحلقة "المعقدة" الكامنة ، فإن اقتران هذه العناصر ومقارنتها بالطبع هما نفس الشيء. ومع ذلك ، لا ينطبق ذلك على جميع مساحات المنتج المباشر.

بعبارة أخرى ، يجب أن يشير نوع الكائن إلى قسمين مختلفين من المعلومات:

  • الحلقة العددية (ومن هنا اقتران ، والتي تنتج عنصرًا من نفس المساحة).
  • المنتج الداخلي (ومن هنا العنصر المساعد ، والذي ينتج عنصرًا من الفضاء المزدوج ).

بالنسبة إلى Vector{T<:Number} ، يجب أن نقرأه على أنه يشير إلى أن الحلقة العددية هي T (أو complex(T) لمساحة المتجه المعقدة) ، وأن المنتج الداخلي هو المنتج الإقليدي المعتاد .

إذا كان لديك متجه من المتجهات ، فهو عبارة عن مساحة هيلبرت ذات مجموع مباشر والحلقة هي ترقية الحلقات العددية للمتجهات الفردية ، ويكون حاصل الضرب النقطي هو مجموع حاصل الضرب النقطي للعناصر. (إذا كان لا يمكن الترويج للقياسات أو لم يتم جمع المنتجات النقطية ، فهذا يعني أنها ليست متجهًا / مساحة هلبرت على الإطلاق).

إذا كان لديك الحجم القياسي T<:Number ، إذن conj(x::T) == adjoint(x::T) .

لذا ، إذا حاولت تمثيل الأعداد المركبة z::Complex{T} بمصفوفات 2x2 m(z)::Array{T,2} ، فنوعك يشير إلى حلقة مختلفة T ومنتج داخلي مختلف مقارنة بـ z ، وبالتالي لا يجب أن تتوقع إما conj أو adjoint لإعطاء نتائج مكافئة.

أنا نوع من رؤية ما تقوله @ felixrehren. إذا كان العدد القياسي حقيقيًا ، فيمكن اعتبار الثماني على أنه فضاء متجه ثماني الأبعاد. ولكن إذا كان المعامل العددي ثمانيًا ، فهناك بعد تافه - 1 يمثل جميع الأوكتيرانيين. لست متأكدًا مما إذا كان هذا مختلفًا عما قلته (أو ما قصدته: ابتسامة :) ، إذا كان لدينا AbstractVector{T1} فقد يكون متشابهًا إلى AbstractVector{T2} بأبعاد مختلفة ( length ). لكن T1 و T2 يجب أن يكونا حلقتين تحت عامل تشغيل Julia + و * (وقد يحافظ التماثل على سلوك + ولكن ليس * ، أو المنتج الداخلي أو الملحق).

stevengj لقد فكرت دائمًا في المبلغ المباشر تمامًا مثل BlockVector . لديك قاعدتان (منفصلتان) غير مكتملة. داخل كل أساس ، قد تكون قادرًا على تكوين تراكبات مثل c₁ | X₁⟩ + c₂ | X₂⟩ في الأساس الأول أو c₃ | Y₁⟩ + c₄ | Y₂⟩ في الثانية. يمثل "المجموع المباشر" مساحة الحالات التي تبدو مثل (c₁ | X₁⟩ + c₂ | X₂⟩) + (c₃ | Y₁⟩ + c₄ | Y₂⟩). يبدو لي أن الشيء المميز الوحيد الذي يفصل هذا عن أساس البعد الرابع على الأعداد المركبة (أي حالات مثل c₁ | X₁⟩ + c₂ | X₂⟩ + c₃ | Y₁⟩ + c₄ | Y₂⟩) هو الأقواس - بالنسبة لي ، يبدو أنه تدويني ؛ المجموع المباشر هو مجرد طريقة ملائمة لكتابتها على الورق أو باستخدام المصفوفات على الكمبيوتر (وقد يكون مفيدًا على سبيل المثال للسماح لنا بفهرسة التماثلات والاستفادة منها ، أو تقسيم المشكلة (ربما لموازنتها) ، إلخ. ). في هذا المثال ، لا يزال X⊕Y عبارة عن فضاء متجه رباعي الأبعاد حيث تكون المقاييس القياسية معقدة.

هذا ما يجعلني أريد eltype(v) == Complex{...} و length(v) == 4 بدلاً من eltype(v) == Vector{Complex{...}} و length(v) == 2 . إنه يساعدني على رؤية الحلقات الكامنة والفضاء المتجه والسبب في ذلك. أليست هذه المساحة "المسطحة" أيضًا حيث يمكنك إجراء تبديل "شامل" والعنصر conj أجل حساب المقابل؟

(لقد حصلت على منشورين بينما كنت أكتب واحدة فقط ، stevengj : ابتسم :)

بطبيعة الحال، إذا نحن نفضل استخدام المصفوفات المتداخلة كما اتفاقية لمبلغ المباشر (كما نفعل الآن) بدلا من BlockArray ، وهذا يمكن أن يكون لطيفا ومتسقة للغاية! قد نستفيد من بعض الوظائف الإضافية لتحديد المجال القياسي (نوع من النوع التكراري) وما يمكن أن تكون عليه الأبعاد المسطحة الفعالة (نوع من الحجم العودي) لتسهيل التفكير في الجبر الخطي الذي نقوم به.

لأكون واضحًا ، أنا سعيد بكلا النهجين وقد تعلمت الكثير من هذه المناقشة. شكر.

andyferris ، لمجرد أن مسافتين

مرة أخرى ، لست متأكدًا من وجهة نظرك. هل تقترح بجدية أن eltype(::Vector{Vector{Complex}}) في جوليا يجب أن يكون Complex ، أو أن length يجب أن يُرجع مجموع الأطوال؟ هل يجب إجبار كل شخص في جوليا على تبني تشابه الشكل "المسطح" بالنسبة للمساحات ذات المجموع المباشر؟ إذا لم يكن كذلك ، فيجب أن تكون عملية الضبط متكررة.

وإذا كنت "تحاول فقط أن تفهم بشكل أفضل ، لا تطرح نقطة معينة" ، فهل يمكنك نقلها إلى منتدى آخر؟ هذه القضية مربكة بدرجة كافية بدون الحجج الميتافيزيقية حول معنى فضاءات المجموع المباشر

لا يعني مجرد وجود مسافتين متشابهين أنهما نفس المساحة

بالتأكيد لم أقترح ذلك على الإطلاق.

مرة أخرى ، لست متأكدًا من وجهة نظرك

أنا أقترح بجدية أنه إذا كنت تريد إجراء الجبر الخطي باستخدام AbstractArray ، فمن الأفضل أن يكون eltype حلقة (دعم + ، * و conj ) الذي يستبعد ، على سبيل المثال ، الأنواع الإلكترونية من Vector لأن [1,2] * [3,4] لا يعمل. ويمثل length للمتجه في الواقع أبعاد الجبر الخطي. نعم ، هذا يستبعد مسافات المتجه اللانهائية ، ولكن بشكل عام في Julia AbstractVector لا يمكن أن يكون حجمه غير محدود. أشعر أن هذا سيجعل من السهل التفكير في كيفية تنفيذ واستخدام وظيفة الجبر الخطي في جوليا. ومع ذلك ، سيتعين على المستخدمين الإشارة صراحةً إلى مبلغ مباشر عبر BlockArray أو ما شابه ذلك بدلاً من استخدام هياكل المصفوفات المتداخلة.

هذا اقتراح كسر تمامًا ، وله جوانب سلبية ملحوظة (بعضها قد ذكرته) ، لذلك لن أكون حزينًا إذا قلنا "هذه فكرة جيدة ، لكنها لن تكون عملية". ومع ذلك ، كنت أحاول أيضًا أن أشير إلى أن نهج المصفوفة المتداخلة يجعل بعض الأشياء حول الجبر الخطي الأساسي أكثر غموضًا.

يبدو كل هذا وثيق الصلة مباشرة بـ OP. مع فرض نهج بالارض كنا خندق متكررة تبديل / adjoints، وإذا كنا سقطت متكررة تبديل / adjoints، بالارض فقط الهياكل يمكن أن يكون قابلا للتطبيق الجبر الخطي. إذا لم نفرض نهجًا مسطحًا ، فيجب أن نحافظ على مساعد تعاودي. بالنسبة لي ، بدا أنه قرار مرتبط.

هل تقترح بجدية أن eltype(::Vector{Vector{Complex}}) في جوليا يجب أن يكون Complex ، أو أن length يجب أن يُرجع مجموع الأطوال؟

لا ، آسف ، ربما لم يكن ما كتبته هناك واضحًا - كنت أقترح فقط أن وظيفتين جديدتين للراحة لهذا الغرض قد تكون مفيدة في ظروف معينة. في بعض الأحيان قد ترغب في zero أو one لهذا الخاتم ، على سبيل المثال.

هل تقول أنه يجب إجبار كل شخص في جوليا على تبني تشابه الشكل "المسطح" للمسافات ذات المجموع المباشر؟

كنت أقترح ذلك كاحتمال ، نعم. لست مقتنعًا بنسبة 100٪ بأنها أفضل فكرة ، لكني أشعر أن هناك بعض المزايا (وبعض العيوب).

بالعودة إلى مجال التغييرات القابلة للتنفيذ هنا ، يبدو أن النسخة المبسطة من stevengj لاقتراحي هي السبيل للذهاب هنا ، على سبيل

  • احتفظ ب conj كما هو (بشكل أساسي).
  • اجعل a' يتوافق مع adjoint(a) ، واجعله تكراريًا دائمًا (وبالتالي يفشل لمصفوفات السلاسل وما إلى ذلك حيث لم يتم تحديد المقارنات للعناصر).
  • اجعل a.' يتوافق مع transpose(a) ، واجعله لا يتكرر أبدًا (فقط permutedims ) ، وبالتالي تجاهل نوع العناصر.

أهم "المهام" الفعلية التي يمكن استخلاصها من هذا هي:

  1. [] أعد تسمية ctranspose إلى adjoint .
  2. [] تغيير transpose ليكون غير متكرر.
  3. [] اكتشف كيف يتناسب هذا مع متجهات الصف.

أظن أن الاعتماد على التحويل العودي نادر بدرجة كافية بحيث يمكننا تغيير هذا في 1.0 وسرده على أنه كسر في NEWS. يمكن أن يمر تغيير ctranspose إلى adjoint خلال إهمال عادي (لكننا نفعل ذلك لـ 1.0). هل هناك أي شيء آخر يجب القيام به؟

StefanKarpinski ، سنحتاج أيضًا إلى إجراء التغيير المقابل على RowVector . أحد الاحتمالات هو تقسيم RowVector إلى Transpose و Adjoint لأنواع transpose الكسولة غير العودية adjoint على التوالي ، وللتخلص من Conj (كسول conj ).

عدد قليل من التغييرات ذات الصلة على الأقل بشكل عرضي

  • بعض أنواع طرق العرض لـ transpose و adjoint من AbstractMatrix
  • اجعل adjoint(::Diagonal) متكررًا (يمكن القول إننا يجب أن نصلح هذا "الخطأ" في Diagonal مقابل transpose و ctranspose قبل إصدار Julia v0.6.0)
  • استخدم النوع "الحجمي" المناسب في أشياء مثل: v = Vector{Vector{Float64}}(); dot(v,v) (يوجد خطأ حاليًا - يحاول إرجاع zero(Vector{Float64}) )

حسنًا ، لقد كنت أحاول أن آخذ مصفوفات الكتل العودية بجدية أكبر ، ولدعم هذا ، أحاول أيضًا تحسين سلوك Diagonal هنا (توجد بالفعل بعض الطرق التي تتوقع كتلة قطرية بنية ، مثل getindex ، لذلك يبدو من الطبيعي جعل التحويل متكررًا في هذه الحالة).

حيث أعلق ، وما الذي حفز بشكل مباشر جميع نقاط المناقشة أعلاه ، هو كيفية إجراء عمليات الجبر الخطي على مثل هذا الهيكل ، بما في ذلك inv ، det ، expm ، eig ، وهكذا. على سبيل المثال ، هناك طريقة لـ det(::Diagonal{T}) where T تأخذ فقط حاصل ضرب كل العناصر القطرية. يعمل ببراعة مقابل T <: Number ، كما أنه يعمل أيضًا إذا كانت جميع العناصر عبارة عن مصفوفات مربعة من نفس الحجم . (بالطبع ، إذا كانت مصفوفات مربعة من نفس الحجم ، فإن العناصر تشكل حلقة ، وكلها منطقية تمامًا - كما أن التبديل العودي (تعديل: معايرة) هو الشيء الصحيح).

ومع ذلك ، إذا فكرنا في مصفوفة كتلة قطرية عامة Diagonal{Matrix{T}} ، أو أي مصفوفة كتلة Matrix{Matrix{T}} ، فيمكننا بشكل عام التحدث عن محددها على أنه T قياسي (3 ⊕ 4) × (3 ⊕ 4) (مصفوفة 2 × 2 مع عناصر قطرية عبارة عن مصفوفات أبعاد 3 × 3 ، 4 × 4 ، وعناصر خارج القطر متطابقة) ، يجب أن يعيد det محدد للبنية "المسطحة" 7 × 7 ، أم يجب أن تحاول ببساطة مضاعفة عناصر 2 × 2 كما هي (والخطأ ، في هذه الحالة)؟

(عدل: لقد غيرت الأبعاد أعلاه لتكون كلها مختلفة ، مما يجب أن يتجنب اللغة الغامضة)

ليس لدي مشكلة في أن يكون a' متكررًا ، لكنني شخصيًا أجد الترميز الجديد a.' محيرًا للغاية. إذا أظهرت لي بناء الجملة a.' ، فسأخبرك ، استنادًا إلى نموذجي العقلي لـ Julia ، أنه يؤدي transpose.(a) ie تبديل العنصر a ، وسأكون كذلك خطأ. بدلاً من ذلك ، إذا أوضحت لي أن a' و a.' كلاهما خياران لمحول ، وأن أحدهما يتكرر أيضًا بطريقة أخرى ، فسأخبرك أن a.' يجب أن يحتوي على العودية ، وسأكون مخطئا مرة أخرى.

بالطبع ، نموذجي العقلي لما يعنيه . خاطئ تمامًا في هذه الحالة. لكنني أظن أنني لست الوحيد الذي يفسر بناء الجملة بطريقة خاطئة تمامًا. تحقيقا لهذه الغاية ، أود أن أقترح استخدام شيء آخر غير .' للتبديل غير العودي.

rdeits أخشى أن هذا النحو مستمد من MATLAB. أصبح هذا مؤسفًا بعض الشيء بمجرد تقديم بناء الجملة (رائع جدًا) لبث dot-call لـ v0.5.

يمكننا صياغة طريقنا الخاص بعيدًا عن MATLAB وتغيير هذا - لكنني أعتقد أنه كان هناك مناقشة منفصلة في مكان ما حول ذلك (أي شخص يتذكر أين؟).

آه ، هذا مؤسف. شكر!

مهمة أخرى:

  • [] إصلاح issymmetric و ishermitian لمطابقة transpose و adjoint - الأول من كل زوج غير متكرر ، والثاني من كل زوج متكرر.

بناء جملة Matlab .' هو بالتأكيد أمر مؤسف للغاية في سياق بناء الجملة الجديد . . لن أعارض تغيير هذا ، ولكن بعد ذلك نحتاج إلى بناء جملة جديد للتبديل ، ولست متأكدًا من توفر صيغة لدينا. أي شخص لديه أي اقتراحات للتبديل؟

دعنا ننقل مناقشة بناء الجملة هنا: https://github.com/JuliaLang/julia/issues/21037.

ليس لدي أي رأي قوي حول transpose / ctranspose / adjoint كونه تكراريًا ، لكنني أفضل عدم التعامل مع A::Matrix{Matrix{T}} مثل مصفوفة الكتلة في شعور كسول بـ hvcat ، والذي يبدو أن andyferris يشير إليه على الأقل جزئيًا. أي ، إذا كانت عناصر A كلها مصفوفات مربعة من نفس الحجم (أي تشكل حلقة) ، أتوقع أن يقوم det(A) بإرجاع مربع بهذا الحجم مرة أخرى. إذا كانت مستطيلة أو ذات أحجام مختلفة ، فأنا أتوقع خطأ.

ومع ذلك ، قد يكون نوع القطة الكسولة / مصفوفة الكتلة مفيدًا ، ولكن يجب أن يتم ذلك على طول الطريق وأيضًا تحديد على سبيل المثال getindex للعمل على البيانات المسطحة. لكنني بالتأكيد لا أرغب في رؤية هذا المفهوم يتم امتصاصه بواسطة Matrix أو أي نوع آخر من أنواع المصفوفات الحالية مثل Diagonal .

هذا يريحك ، مارتينهولترز. ما كنت أفزع بشأنه سابقًا في هذا الموضوع هو فكرة أنه يجب علينا بطريقة ما أن نكون قادرين على تطبيق إطار جوليا الكامل للجبر الخطي على Matrix{Matrix} لمصفوفات الكتلة التعسفية (حيث يكون للقوالب الفرعية أحجام مختلفة).

ما كنت أدافع عنه مع "التسطيح" هو عدم القيام بأي استبطان خيالي لماهية العناصر ، بل مجرد التعامل مع العناصر على أساس مزاياها كعناصر حلقة. ومع ذلك ، فإن العودية ctranspose / adjoint توسع هذا للسماح للعناصر التي تعمل مثل عوامل التشغيل الخطية ، والتي تبدو صحيحة ومفيدة. (الحالة الأخرى هي عناصر متجه تعمل كمتجه ، حيث يكون المساعد العودي صحيحًا أيضًا).

للعودة إلى الوراء قليلاً - ما هو الدافع الأصلي لإزالة سلوك عدم التشغيل الافتراضي لـ transpose(x) = x و ctranpsose(x) = conj(x) ؟ بدت هذه دائما مفيدة جدا بالنسبة لي.

للعودة إلى الوراء قليلاً - ما هو الدافع الأصلي لإزالة سلوك عدم التشغيل الافتراضي للتبديل (x) = x و ctranpsose (x) = conj (x)؟ بدت هذه دائما مفيدة جدا بالنسبة لي.

كان الدافع وراء ذلك هو أنواع عوامل التشغيل الخطية المخصصة (والتي لا يمكن أن تكون أنواعًا فرعية من AbstractArray) التي فشلت في التخصص ctranspose . هذا يعني أنهم ورثوا سلوك عدم التشغيل الخاطئ من الرجوع. لقد حاولنا هيكلة إرسال بحيث لا تكون الاحتياطيات غير صحيحة أبدًا (ولكن قد يكون لها تعقيد متشائم). https://github.com/JuliaLang/julia/issues/13171

يبدو أن لدينا خيارين - في كلا الخيارين ، يصبح transpose غير متكرر ، وإلا:

  1. غير متكرر ctranspose .
  2. متكرر ctranspose .

stevengj ، jiahao ، andreasnoack - ما هي تفضيلاتك هنا؟ الآخرين؟

لقد كنت أفكر كثيرًا في هذا منذ حديثjiahao لـ JuliaCon 2017.

بالنسبة لي ، ما زلت أشعر بضرورة تعريف الجبر الخطي فيما يتعلق بالحقل "القياسي" كنوع عنصر T . إذا كان T حقلاً (يدعم + ، * و conj (أيضًا - ، / ، .. .)) ثم لا أرى سبب فشل الأساليب في Base.LinAlg .

OTOH من الشائع (والصحيح) التحدث عن تحويل مصفوفة الكتلة ، على سبيل المثال. أعتقد أنه يمكننا التعلم من نظرية النوع "الرياضية" هنا ، والتي تحاول على سبيل المثال التعامل مع عبارات غريبة ناشئة عن مناقشة مجموعات مجموعات من خلال وجود مجموعات "من الدرجة الأولى" من الحجميات ، ومجموعات من "الدرجة الثانية" من مجموعات الحجميات ، وثالثًا ترتيب "مجموعات من مجموعات الحجميات ، وما إلى ذلك. أعتقد أننا نواجه نفس المشكلة (والفرصة) هنا عند التعامل مع مصفوفات من المصفوفات - يمكننا استخدام نظام نوع جوليا لوصف مصفوفات "من الدرجة الأولى" من الحجميات "الحقيقية" ، ومصفوفات "الدرجة الثانية" من مصفوفات الحجميات ، إلخ. . أعتقد أن المناقشات الطويلة بين stevengj ، وأنا ، والآخرين ، نتجت عن حقيقة أنه ، نعم ، يمكنك الخروج بمجموعة متسقة ذاتيًا من العمليات على مصفوفات من "النظام" التعسفي ، وفي هذا الإطار (c) إن التحويل هو تكراري واضح وصحيح ، ولكن مع ذلك ، ليس عليك القيام بذلك. كما أشار حديث Jiahao بوضوح ، فإن لغات / أطر البرمجة تقوم باختيارات دلالية حول التمييز بين الحجميات من المصفوفات (أو لا) ، وتمييز المتجهات من المصفوفات (أو لا) وما إلى ذلك ، وأعتقد أن هذا خيار ذو صلة يمكننا القيام به.

بالنسبة لي ، النقطة الحاسمة هنا هي أنه لجعل مصفوفة "الترتيب التعسفي" تعمل ، عليك تعليم "الحجميات" بعض العمليات التي يتم تحديدها عادةً فقط على المتجهات والمصفوفات. طريقة جوليا الحالية التي تقوم بذلك هي transpose(x::Number) = x . ومع ذلك ، فإنني أفضل حقًا إذا قمنا بتوسيع تمييزنا الدلالي بين المصفوفات والقياسات من خلال إزالة هذه الطريقة - وأعتقد أنه قد يكون ممكنًا تمامًا.

ستكون الخطوة التالية هي تعليم Base.LinAlg الفرق بين مصفوفة من الدرجة الأولى ومصفوفة من الدرجة الثانية وما إلى ذلك. لقد فكرت في خيارين قابلين للتطبيق ، قد يكون هناك المزيد ، لا أعرف حقًا:

  • لديك نوع من سمة التمكين إلى "المصفوفة" ، بحيث يكون transpose(::AbstractMatrix{T}) متكررًا عندما يكون T AbstractMatOrVec ، وليس عندما يكون T Number ، واجعله قابلاً للتكوين بطريقة ما (الاشتراك ، إلغاء الاشتراك ، أيًا كان) بخلاف ذلك. (في بعض النواحي كان هذا ويتم حاليًا عن طريق التحكم في سلوك طريقة transpose للعناصر ، لكنني أعتقد أنه من الأنظف التحكم في سلوك طريقة transpose لـ (الخارجي) ) مجموعة مصفوفة).
  • بدلاً من ذلك ، تأكد من أن معظم AbstractArray s بما في ذلك Array s هي الترتيب الأول (عناصرها هي حقول عددية) ، واستخدم نوع AbstractArray مختلفًا (على سبيل المثال NestedArray ) لف المصفوفات و "تحديد" معاملة عناصرها كمصفوفات وليست قياسية. حاولت التلاعب بهذا قليلاً ، لكن يبدو أن الخيار أعلاه ربما يكون أقل عبئًا على المستخدمين.

أشعر أن جوليا تقوم بفصل دلالي قوي بين المصفوفات والكميات ، وأن الوضع الحالي يبدو (بالنسبة لي) غير متسق قليلاً مع ذلك ، حيث يجب "تعليم" الحجميات حول خاصية المصفوفة transpose . يمكن للمستخدم أن يخبر بوضوح أن Matrix{Float64} عبارة عن مصفوفة من الحجميات (مصفوفة من الدرجة الأولى) و Matrix{Matrix{Float64}} هي مصفوفة كتلة (مصفوفة من الدرجة الثانية). قد يكون من الأكثر اتساقًا بالنسبة لنا استخدام نظام النوع أو السمات لتحديد ما إذا كانت المصفوفة "من الدرجة الأولى" أو أي شيء آخر. أعتقد أيضًا أن الخيار الأول الذي أدرجته سيجعل جوليا أكثر سهولة في الاستخدام (لذا يمكنني أن أفعل ["abc", "def"].' ) مع الاحتفاظ بالمرونة للقيام ببعض الأشياء الافتراضية المعقولة / المفيدة باستخدام مصفوفات الكتلة.

آسف على العزف على القيثارة لفترة طويلة ، ولكن بعد التحدث مع jiahao في JuliaCon ، شعرت أنه يمكننا القيام بعمل أفضل قليلاً هنا. أنا متأكد من أنه يمكننا جعل الخيارات الأخرى التي ذكرها StefanKarpinski أعلى "العمل" ، ولكن بالنسبة لي سيكون "العمل" تمامًا كما كان جبر المصفوفة / المتجه "يعمل" قبل تقديم RowVector .

كان TLDR - لا تجعل ( c ) transpose إما تكراريًا أم لا - دعه يقوم بالأمرين (أي أن يكون قابلاً للتكوين).

هذه نقاط جيدة ، لكن أريد فقط أن أشير إلى أن جميع الشكاوى تقريبًا (إن لم يكن كلها) حول (c)transpose متكررة تتعلق باستخدام غير متعلق بالرياضيات لـ ' و .' عند إعادة تشكيل مثل Vector{String} و Vector{PyObject} في مصفوفات 1xn. من السهل إصلاح النوع حسب النوع ولكن يمكنني أن أرى أنه أمر مزعج. ومع ذلك ، كان التفكير هو أن التعريف التكراري كان صحيحًا رياضيًا وأن "الصحيح ولكنه مزعج في كثير من الحالات" كان أفضل من "مناسب ولكنه خاطئ في حالات نادرة".

يمكن أن يكون الحل المحتمل هو اقتراحك في الرمز النقطي الأول ، أي أن يكون لديك عمليات تبديل متكررة لعناصر تشبه المصفوفة. أعتقد أن T<:AbstractVecOrMat سيغطي معظم الحالات بتغيير الحالة إلى "مناسب لكن خاطئ في حالات نادرة جدًا ". السبب وراء احتمال استمرار الخطأ هو أن بعض الأنواع التي تشبه عامل التشغيل لا تناسب فئة AbstractMatrix لأن الواجهة AbstractArray تدور بشكل أساسي حول دلالات المصفوفة ( getindex ) ، ليس الجبر الخطي.

andyferris ، والمقارن للعددي محدد بشكل جيد ، و ctranspose(x::Number) = conj(x) صحيح

أشعر أن معظم استخدامات transpose هي "non-mathy" ، ومعظم استخدامات ctranspose (أي الاستخدامات التي يكون فيها سلوك الاقتران مطلوبًا) هي mathy (نظرًا لعدم وجود سبب آخر للاقتران ). ومن ثم ، فإنني أميل إلى تفضيل استخدام transpose التكراري و ctranspose .

أنا شخصياً أعتقد أن محاولة النظر إلى مصفوفات الكتلة على أنها متداخلة Arrays تصبح معقدة للأسباب هنا وربما يكون من الأفضل أن يكون لديك نوع مخصص à la https://github.com/KristofferC/BlockArrays.jl لـ هذه.

يبدو لطيفا ، كريستوفر.

هناك نقطة واحدة صحيحة للغاية يوضحهاstevengj أعلاه ، وهي أنه في بعض الأحيان قد تكون AbstractArray s. نحن بالتأكيد بحاجة إلى طريقة للقيام بالتكرار (ج) للتبديل لهذه الأشياء - لست متأكدًا مما إذا كنت قد فكرت في هذا أم لا ، لكنني اعتقدت أنني سأذكره.

يسلط الضوء على slack / # linalg محادثة حول هذا الموضوع. يلخص بعض الخيط أعلاه. يركز على الدلالات ويتجنب الهجاء. (شكرا لكل من شارك في تلك المحادثة! :))

توجد ثلاث عمليات متميزة لغويًا:
1) "مساعد رياضي" (متكرر وكسول)
2) "تبديل رياضي" (من الناحية المثالية متكرر وكسول)
3) "النقل الهيكلي" (من الناحية المثالية غير متكرر و "حريص؟)

الوضع الحالي: خرائط "المرافقة الرياضية" إلى ctranspose ، و "التحويل الرياضي" إلى transpose ، و "النقل الهيكلي" إلى permutedims(C, (2, 1)) لثنائي الأبعاد C و reshape(C, 1, length(C)) مقابل نصف C . المشكلة: "التحويل الهيكلي" عملية شائعة ، والقصة permutedims / reshape مربكة إلى حد ما / غير طبيعية / مزعجة في الممارسة.

كيف نشأ ذلك: تم الخلط سابقًا بين "النقل الهيكلي" و "التحويل الرياضي" / "التحويل الرياضي" عبر احتياطيات عامة غير عملية مثل transpose(x::Any) = x ، ctranspose(x::Any) = conj(x) ، و conj(x::Any) = x . جعلت هذه العناصر الاحتياطية [c]transpose ومعاملات postfix ' / .' تعمل من أجل "التحويل الهيكلي" في معظم الحالات. عظيم. لكنهم قاموا أيضًا بإجراء عمليات تتضمن [c]transpose على بعض الأنواع العددية التي يحددها المستخدم تفشل بصمت (إرجاع نتائج غير صحيحة) مع عدم وجود تعريف لتخصصات [c]transpose لهذه الأنواع. أوتش. ومن ثم تمت إزالة تلك الإجراءات الاحتياطية العامة ، مما أسفر عن الوضع الحالي.

السؤال هو ماذا نفعل الآن.

النتيجة المثالية: توفير تعويذة موحدة وطبيعية ومضغوطة لـ "النقل الهيكلي". دعم في نفس الوقت المرافقة والتبديل الرياضي الصحيح لغويًا. تجنب إدخال حالات ركن صعبة في الاستخدام أو التنفيذ.

يوجد اقتراحان عريضان:

(1) توفير عمليات معايرة رياضية ، ونقل رياضي ، وتبديل بنيوي كثالث عمليات متميزة نحويًا ودلالة. الإيجابيات: يجعل كل شيء يعمل ، ويفصل المفاهيم بشكل واضح ، ويتجنب حالات الزاوية الصعبة. السلبيات: ثلاث عمليات للشرح والتنفيذ.

(2) بوق الحذاء العمليات الثلاث إلى قسمين. توجد ثلاثة أشكال من هذا الاقتراح:

(2 أ) اجعل transpose "تبديل هيكلي" لغويًا ، كما يعمل أيضًا كـ "تبديل رياضي" في الحالات الشائعة. الجوانب الإيجابية: عمليتان. يعمل كما هو متوقع للحاويات ذات العناصر العددية الواضحة. الجوانب السلبية: أي شخص يتوقع دلالات "تبديل رياضي" سيتلقى بصمت نتائج غير صحيحة على كائنات أكثر تعقيدًا من الحاويات التي تحتوي على عناصر عددية لا لبس فيها. إذا اكتشف المستخدم هذه المشكلة ، فإن تحقيق دلالات "النقل الرياضي" يتطلب تحديد أنواع و / أو طرق جديدة.

(2 ب) إدخال سمة تشير إلى "رياضيات" النوع. عند تطبيق الضبط / التبديل على كائن ، إذا كانت أنواع الحاوية / العناصر "mathy" ، يتكرر ؛ إذا لم يكن كذلك ، فلا تتكرر. الجوانب الإيجابية: عمليتان. يمكن أن تغطي مجموعة متنوعة من الحالات الشائعة. الجوانب السلبية: المعاناة من نفس المشكلة مثل البدائل الاحتياطية العامة لعدم التشغيل [c]transpose ، أي يمكن أن تسفر بصمت عن نتائج غير صحيحة للأنواع الرقمية التي يحددها المستخدم والتي تفتقر إلى تعريفات السمات الضرورية. لا يسمح بتطبيق التحويل البنيوي إلى نوع "رياضي" أو التحويل الرياضي إلى نوع "غير رياضي". ليس من الواضح كيف تقرر ما إذا كان الكائن "رياضي" في جميع الحالات. (على سبيل المثال ، ماذا لو كان نوع العنصر مجردًا؟ هل القرار التكراري / غير التكراري هو وقت التشغيل والعنصر ، أو وقت التشغيل ويتطلب مسحًا أولًا لجميع العناصر في الحاوية للتحقق من نوعها الجماعي؟)

(2 ج) احتفظ بـ adjoint ( ctranspose ) "مرافقة رياضية" و transpose "تبديل رياضي" ، وإدخال طرق متخصصة (وليست احتياطية عامة) مقابل adjoint / transpose للأنواع العددية غير الرقمية (مثل adjoint(s::AbstractString) = s ). الجوانب الإيجابية: عمليتان. تصحيح دلالات الرياضيات. الجوانب السلبية: يتطلب تعريفًا مجزأًا adjoint / transpose للأنواع غير الرقمية ، مما يعوق البرمجة العامة. لا يُمكِّن من تطبيق التحويل البنيوي لأنواع "الرياضيات".

تمتعت المقترحات (1) و (2 أ) بتأييد أوسع بكثير من (2 ب) و (2 ج).

يرجى الاطلاع على مزيد من المناقشة في # 19344 و # 21037 و # 13171 و slack / # linalg. الأفضل!

شكرا على الكتابة الرائعة!

أود أن أضع احتمالًا آخر على الجدول يتماشى مع الخيار 1: وجود أنواع مختلفة من الحاويات للمصفوفات الرياضية والبيانات الجدولية. ثم يمكن تحديد معنى A' بنوع A (ملاحظة: ليس نوع العنصر كما هو موضح أعلاه). السلبيات هنا هي أن هذا قد يتطلب الكثير من convert s بين الاثنين (أليس كذلك؟) وبالطبع ، سيكون مدمرًا للغاية. من المسلم به أنني أكثر من متشكك فيما إذا كانت الفوائد تبرر هذا الاضطراب ، لكنني ما زلت أريد ذكر ذلك.

شكرا ، كتابة ممتازة. أنا أصوت لـ (1).

كتابة رائعة. لاحظ أن الهجاء (1) يمكن أن يكون:

  • Adjoint: a' (متكرر ، كسول)
  • تبديل رياضي: conj(a') (متكرر ، كسول)
  • النقل الهيكلي: a.' (غير متكرر ، حريص)

لذلك لن تكون هناك حاجة بالضرورة إلى إدخال أي عامل جديد - سيكون النقل الرياضي مجرد تركيبة (كسولة وبالتالي فعالة) من الاقتران والاقران. أكبر مشكلة هي أنها تجعل عاملين متشابهين ، على سبيل المثال postfix ' و .' ، مميزان تمامًا من الناحية الدلالية. ومع ذلك ، أفترض أنه في أكثر الرموز العامة الصحيحة ، سواء استخدم شخص ما ' أو .' هو مؤشر دقيق بنسبة 99٪ لما إذا كان يقصد "أعطني نقطة قريبة من هذا الشيء" أو "مبادلة أبعاد هذا الشيء ". علاوة على ذلك ، في الحالات التي يستخدم فيها شخص ما ' ويعني في الواقع "تبديل أبعاد هذا الشيء" ، فإن الكود الخاص به سيكون بالفعل غير صحيح لأي مصفوفة تحتوي على عناصر يكون المقارب القياسي لها غير تافه ، مثل الأعداد المركبة. في الحالات القليلة المتبقية حيث شخص ما يعني في الواقع "أعطني المرافق للadjoint من هذا"، وأنا أزعم أن الكتابة conj(a') يجعل هذا يعني أكثر وضوحا منذ الناس في ممارسة استخدامها في الواقع a.' ل يعني "مبادلة أبعاد a ".

العمل على جميع الأنواع العامة الأساسية التي سنحتاجها لهذا لم يتم تحديده بعد ، لكن andreasnoack لديهما بالفعل بعض الأفكار حول هذه المسألة ويبدو أن ذلك ممكن.

اعتقدت أنه يجب علي التحديث أيضًا ، لأن هذه المناقشة جرت في مكان آخر. أعترف أن هناك شيئًا واحدًا (واضحًا؟) في هذا الاقتراح قد فاتني تمامًا وهو أنني افترضت أننا سنستمر في استخدام .' للجبر الخطي ، لكن كان علي أن أدرك أن هذا ليس هو الحال !

على سبيل المثال ، لن يحتاج vector.' بعد الآن إلى أن يكون RowVector (نظرًا لأن RowVector هو مفهوم الجبر الخطي ، محاولتنا الأولى في المتجه "المزدوج") - يمكن ببساطة يكون Matrix . عندما أرغب في "التحويل غير المقترن" في الجبر الخطي ، فإن ما أفعله حقًا هو أخذ conj(adjoint(a)) ، وهذا ما سنستخدمه ونوصي باستخدام جميع مستخدمي الجبر الخطي (حتى الآن لدي اعتاد MATLAB على استخدام عادة "سيئة" منذ فترة طويلة لاستخدام a.' بدلاً من a' لنقل أي مصفوفة (أو متجه) كنت أعرف أنها حقيقية ، عندما كان ما أريده حقًا هو adjoint (أو مزدوج) - التغيير في الاسم سيكون مساعدة كبيرة هنا).

سأشير أيضًا بإيجاز إلى أن هذا يترك مساحة مثيرة للاهتمام مفتوحة. في السابق كان على vector' و vector.' تلبية الاحتياجات المزدوجة للقيام بـ "تبديل البيانات" وأخذ شيء مثل المتجه المزدوج. الآن بعد أن أصبح .' لمعالجة أحجام المصفوفات و ' هو مفهوم الجبر الخطي ، قد نتمكن من تغيير RowVector إلى 1D DualVector أو أي شيء آخر تماما. (ربما لا ينبغي أن نناقش هذا هنا - إذا كان لدى أي شخص الرغبة في ذلك ، فلنقم بمسألة منفصلة).

أخيرًا ، سأقوم بنسخ خطة عمل مقترحة من Slack:

1) انقل transpose من LinAlg إلى Base وأضف مستنبطات (0.7 فقط) حول أنه لم يعد يصنع RowVector أو أنه متكرر (إذا كان ذلك ممكنًا)
2) أعد تسمية ctranspose إلى adjoint كل مكان
3) تأكد من عمل Vector و ConjVector و RowVector مع مجموعات من ' و conj و * ، ربما إعادة تسمية RowVector . (هنا أيضًا نجعل conj(vector) كسول).
4) تقديم مصفوفة مصفوفة كسولة تتفاعل أيضًا بشكل جيد مع conj و ConjMatrix
5) إزالة A_mul_Bc إلخ. أعد تسمية A_mul_B! إلى mul! (أو *! ).
6) الربح

كتب stevengj :

andyferris ، والمقارن للعددي محدد بشكل جيد ، و ctranspose(x::Number) = conj(x) صحيح

للتسجيل ، أنا بالتأكيد أتفق مع هذا.

أشعر أن معظم استخدامات النقل هي "non-mathy" ، ومعظم استخدامات ctranspose (...) هي mathy

لذا فإن الفكرة ستكون إضفاء الطابع الرسمي على هذا: جميع استخدامات transpose تصبح "non-mathy" والاستخدام الوحيد لـ adjoint سيكون "mathy".

على سبيل المثال ، لن يحتاج vector.' بعد الآن إلى أن يكون RowVector (نظرًا لأن RowVector هو مفهوم الجبر الخطي ، محاولتنا الأولى في المتجه "المزدوج") - يمكن ببساطة يكون Matrix .

ما زلنا نريد أن يكون .' كسولًا. على سبيل المثال ، يجب أن يظل X .= f.(x, y.') غير مخصص.

إليك سؤال: كيف يمكننا تنفيذ issymmetric(::AbstractMatrix{<:AbstractMatrix}) ؟ هل سيكون شيكًا غير متكرر ، ليطابق transpose ؟ أنا أبحث في التنفيذ. يفترض أن العناصر يمكن أن transpose . OTOH يبدو أنه من الصحيح التحقق مما إذا كان issymmetric(::Matrix{String}) ...

إنه غير متكرر حاليًا إذا تم لفه في Symmetric بالمقارنة مع

julia> A = [rand(2, 2) for i in 1:2, j in 1:2]; A[1, 2] = A[2, 1]; As = Symmetric(A);

julia> issymmetric(A)
false

julia> issymmetric(As)
true

julia> A == As
true

نعم ، أنا أعمل على إنشاء علاقات عامة لهذا وهناك الكثير من هذه الأنواع من التناقضات. (صادفت ذلك منذ وقت ليس ببعيد أثناء البحث عن كل مثيل transpose و adjoint و conj في كود المصفوفة).

ما لم يتم التوجيه بخلاف ذلك ، سأقوم بتنفيذ سلوك مثل issymmetric(a) == (a == a.') و ishermitian(a) == (a == a') . هذه تبدو بديهية جدًا في حد ذاتها ، واستخدام AFAICT الحالي لـ issymmetric هو لأنواع العناصر Number (أو غالبًا ما يحتوي على أخطاء / افتراضات أخرى لن يكون لها معنى كبير للمصفوفات المتداخلة) .

(التطبيق البديل هو issymmetric(a) == (a == conj(adjoint(a))) ... ليس كـ "جميل" ولن يعمل مع مصفوفات "data" (من String ، إلخ) ، لكنه يتزامن مع مصفوفات Number )

ما لم يتم التوجيه بخلاف ذلك ، سأقوم بتنفيذ سلوك مثل issymmetric(a) == (a == a.') و ishermitian(a) == (a == a')

يبدو أنه الحل الصحيح بالنسبة لي.

تحديث: غيرت رأيي. من المحتمل أن يكون المتماثل أساسًا للجبر الخطي

مجرد اقتراح صغير: غالبًا ما يكون من المفيد عمل مجموع على ناتج متجهين ( dotu ) ، و x.’y إرجاع العددية هي طريقة ملائمة للقيام بذلك. لذلك أؤيد عدم إرجاع Matrix من transpose(::Vector)

نعم ، سيكون RowVector لذا يجب أن تحصل على رقم قياسي. (لاحظ أن التحويل لن يكون تكراريًا).

نأسف للتعليق العرضي المحتمل ، لكن العديد من الأشخاص في هذا الموضوع يستمرون في الحديث عن "حلقة متجهية من الحجميات". بحكم التعريف ، يجب أن تشكل مقاييس الفضاء المتجه حقلاً ، وليس مجرد حلقة. يُطلق على البنية الجبرية التي تشبه إلى حد بعيد فضاء المتجه ولكن حجمها فقط حلقة بدلاً من حقل "وحدة نمطية" ، لكنني أعتقد أن الوحدات النمطية مقصورة على فئة معينة بحيث لا يمكن التعامل معها في القاعدة ... إيه. .. وحدة.

نظرًا لأننا ندعم المصفوفات الصحيحة ، فإننا ندعم الوحدات النمطية بشكل فعال ، وليس فقط مسافات المتجهات. بالطبع ، يمكننا أيضًا مشاهدة المصفوفات الصحيحة على أنها مضمنة في مصفوفات الفاصلة العائمة بشكل سلوكي ، لذا فهي تمثيل جزئي لمساحة متجه. لكن يمكننا أيضًا إنشاء مصفوفات من الأعداد الصحيحة المعيارية (على سبيل المثال) ، ومع المعامل غير الأولي ، سنعمل مع حلقة غير مضمنة بشكل طبيعي في أي مجال. باختصار ، نريد في الواقع النظر في الوحدات بشكل عام بدلاً من مجرد مسافات متجهة ، لكنني لا أعتقد أن هناك أي اختلاف كبير في أغراضنا (نحن نتحدث عمومًا فقط عن + و * ) لذا فإن "vector space" تعمل كمختصر مألوف أكثر لـ "module" لأغراضنا.

نعم ، جوليا بالتأكيد تدعم (ويجب عليها) أن تدعم العمليات الجبرية على الوحدات العامة وكذلك على المساحات المتجهة الحقيقية. ولكن كما أفهمها ، فإن الفلسفة العامة للمجتمع هي أن الدالات في Base يجب أن تُصمم مع مراعاة إجراءات الجبر الخطي العامة "العادية" - لذلك ، على سبيل المثال ، حسابات الجبر الخطي الدقيقة على المصفوفات الصحيحة لا تنتمي إلى Base - لذلك عند اتخاذ قرارات التصميم الأساسية ، يجب أن نفترض أن المقاييس تشكل حقلاً. (على الرغم من أنه كما قلت ، من الناحية العملية ، لا يهم حقًا.)

Crossposting https://github.com/JuliaLang/julia/pull/23424#issuecomment -346678279

إنني أقدر كثيرًا الجهد المبذول لتحريك # 5332 و 20978 للأمام الذي يمثله طلب السحب هذا ، وأنا موافق على معظم الخطة المرتبطة. أود أيضًا أن أكون على دراية بخيارات المصطلحات وتأثير المصب الذي يتقدم به طلب السحب هذا ، وبالتالي أحاول بانتظام إقناع نفسي بأن هذه الخيارات تحقق أفضل مجموعة من المقايضات المتاحة.

في كل مرة أحاول فيها إقناع نفسي بهذا الموقف ، أواجه نفس مجموعة الهواجس. أحد هذه الهواجس هو التعقيد الكبير في التنفيذ الذي يفرضه هذا الاختيار على LinAlg : دمج قوى النقل وقلب المصفوفة LinAlg للتعامل مع كليهما ، مما يتطلب دعم LinAlg لمجموعة أكبر بكثير من مجموعات النوع في العمليات المشتركة.

للتوضيح ، ضع في اعتبارك mul(A, B) حيث A و B مكشوفان ، ملفوفان معا ، ملفوفان ، أو مصفوفان ملفوفان Matrix s. بدون الخلط بين تبديل الموضع وقلب المصفوفة ، يمكن أن يكون A Matrix ، أو ملفًا إضافيًا Matrix ، أو ملفوفًا مبدلًا Matrix (وبالمثل B ). لذلك يحتاج mul(A, B) إلى دعم تسع مجموعات من الأنواع. ولكن الخلط بين تبديل ومجموعة الوجه، A يمكن أن يكون Matrix ، وهو الملفوفة adjoint Matrix ، وهو الملفوفة تبديل Matrix ، أو array- ملفوفة بالقلب Matrix (وبالمثل B ). حتى الآن mul(A, B) تحتاج إلى دعم ستة عشر نوعًا من المجموعات.

هذه المشكلة تتفاقم بشكل كبير مع عدد الحجج. على سبيل المثال ، بدون خلط mul!(C, A, B) تحتاج إلى دعم سبعة وعشرين تركيبة من النوع ، بينما مع الخلط mul!(C, A, B) تحتاج إلى دعم 64 تراكيب من النوع. وإضافة مسار Vector الصورة وغير Matrix أنواع مصفوفة / المشغل إلى مزيج يزيد من تعقيد الأمور.

يبدو أن هذا التأثير الجانبي يستحق النظر قبل المضي قدمًا في هذا التغيير. الأفضل!

يقوم هذا المنشور بدمج / مراجعة المناقشات الأخيرة حول github و Slack و Triage ، ويحلل المسارات المحتملة للأمام. (الخليفة الروحي لـ https://github.com/JuliaLang/julia/issues/20978#issuecomment-315902532 ولد من التفكير في كيفية الوصول إلى 1.0.)

هناك ثلاث عمليات متميزة لغويًا قيد المناقشة:

  • مساعد (جبري خطي ، متكرر ، مثالي كسول افتراضيًا)
  • تبديل (جبري خطي ، متكرر ، مثالي كسول افتراضيًا)
  • صفيف-فليب (مصفوفة مجردة ، غير متكررة ، من الناحية المثالية؟ كسول؟ افتراضيًا)

حالة هذه العمليات على الماجستير

  • يُطلق على Adjoint اسم adjoint / ' (ولكنه متلهّف بعيدًا عن التعبيرات المتضمنة ' تم تخفيضها بشكل خاص إلى A[c|t]_(mul|rdiv|ldiv)_B[c|t][!] المكالمات ، والتي تتجنب عمليات الإضافات / التبديلات المتوسطة الشغوفة) .

  • يُطلق على التحويل اسم transpose / .' (مع نفس التحذير مثل adjoint ).

  • يسمى Array-flip permutedims(C, (2, 1)) لثنائي الأبعاد C و reshape(C, 1, length(C)) للبعد الواحد C .

القضايا ذات الصلة

  1. 5332: يجب أن يختفي التخفيض الخاص إلى A[c|t]_(mul|rdiv|ldiv)_B[c|t] والمجموعة التوافقية المرتبطة بأسماء الطرق بمقدار 1.0. تتطلب إزالة هذا التخفيض الخاص / الأسماء المرتبطة بالطرق المساعدة البطيئة والتبديل.

  2. 13171: تم دمج Adjoint (née ctranspose ) وتغيير موضعها سابقًا مع array-flip عبر احتياطيات عامة غير عملية مثل transpose(x::Any) = x و ctranspose(x::Any) = conj(x) و conj(x::Any) = x . جعلت هذه الإجراءات الاحتياطية عمليات تتضمن [c]transpose على بعض الأنواع العددية المعرفة من قبل المستخدم تفشل بصمت (إرجاع نتائج غير صحيحة) في غياب تخصصات [c]transpose لهذه الأنواع. يعد إرجاع النتائج غير الصحيحة بصمت أمرًا سيئًا ، لذلك تمت إزالة تلك العناصر الاحتياطية (# 17075). إن عدم تقديم المزيد من الإخفاقات الصامتة سيكون أمرًا رائعًا.

  3. 17075 ، # 17374 ، # 19205: إزالة العناصر الاحتياطية السابقة جعل قلب الصفيف أقل ملاءمة. وبالاقتران مع (اعتذاري ، خطئي) تحذيرات أقل من كبيرة مرتبطة بالإيقاف ، تسبب هذا الإزالة (بشكل عابر؟) في شكاوى. سيكون من الجيد استخدام تعويذة أكثر ملاءمة لقلب المصفوفة.

  4. 21037: إزالة بناء جملة .' المربك الآن لـ 1.0 سيكون أمرًا رائعًا. يجب إزالة التخفيض الخاص المذكور أعلاه لتمكين هذا التغيير.

أهداف التصميم لحل هذه القضايا

قم بإزالة أسماء الطرق الخاصة والمرتبطة بها ، وتجنب إدخال حالات فشل صامتة ، ووفر تعويذات بديهية ومريحة للتبديل وقلب الصفيف ، وإزالة .' . تحقيق ما سبق بأقل قدر من التعقيد الإضافي والكسر.

مقترحات التصميم

تم تقليص المجال إلى اقتراحين للتصميم:

  1. تبديل الاستدعاء adjoint ، تبديل conjadjoint ("اقتران معاون") ، و array-flip transpose . يعيش adjoint و conjadjoint في LinAlg ، و transpose في Base .

  2. تبديل استدعاء adjoint ، تبديل transpose ، و array-flip flip . يعيش adjoint و transpose في LinAlg ، و flip في Base .

للوهلة الأولى ، تبدو هذه الاقتراحات مختلفة بشكل سطحي فقط. لكن المزيد من الفحص يكشف عن اختلافات عملية عميقة. لتجنب المناقشة حول المزايا السطحية النسبية لمخططات التسمية هذه ، دعنا نلقي نظرة على تلك الاختلافات العملية العميقة.

الاختلافات ، عرض رفيع المستوى

  1. تعقيد:

    الاقتراح الأول ، من خلال استدعاء array-flip transpose ، يفرض LinAlg للتعامل مع انعكاس المصفوفة بالإضافة إلى التبديل والمقارنة. وبالتالي ، يجب أن يقوم LinAlg بتوسيع مجموعة تركيبات الأنواع التي تدعمها العمليات العامة بشكل كبير ؛ https://github.com/JuliaLang/julia/pull/23424#issuecomment -346678279 يوضح هذا التعقيد الإضافي على سبيل المثال ، وتؤكد المناقشة التالية ضمنيًا وجود هذا التعقيد الإضافي.

    يتطلب الاقتراح الثاني دعم LinAlg فقط للتبديل والربط ، وهو ما يفعله الآن LinAlg .

  2. الكسر:

    يغير الاقتراح الأول الدلالات الأساسية للعمليات الحالية: يصبح transpose مصفوفة انعكاس بدلاً من تبديلها ، ويجب أن تتغير جميع الوظائف المرتبطة بـ transpose وفقًا لذلك. (على سبيل المثال ، تتطلب جميع عمليات الضرب والقسم الأيسر / الأيمن في LinAlg المرتبطة بالاسم transpose مراجعة دلالية.) اعتمادًا على كيفية تحقيق هذا التغيير ، يتسبب هذا التغيير في حدوث كسر صامت حيثما يتم الاعتماد على الدلالات الحالية (عمدا أو عن غير قصد).

    يحتفظ الاقتراح الثاني بالدلالات الأساسية لجميع العمليات الحالية.

  3. اقتران:

    يقدم الاقتراح الأول مفهومًا جبريًا خطيًا (تبديل) إلى Base ، ومفهوم مصفوفة مجردة (array-flip) إلى LinAlg ، يقترن بقوة Base و LinAlg .

    يفصل الاقتراح الثاني بشكل واضح بين المصفوفة المجردة والجبر الخطي ، مما يسمح للأول بالعيش فقط في الأساس والأخير فقط بـ LinAlg ، بدون اقتران جديد.

  4. صامت مقابل فشل عالٍ:

    يؤدي الاقتراح الأول إلى نتيجة غير صحيحة بشكل صامت عندما يستدعي المرء transpose متوقعًا تبديل دلالات (ولكن بدلاً من ذلك يحصل على دلالات مصفوفة).

    يستدعي التناظرية تحت الاقتراح الثاني transpose على مصفوفة غير رقمية تتوقع دلالات لقلب الصفيف. في هذه الحالة ، يمكن أن يؤدي transpose ظهور خطأ مفيد في توجيه المستخدم إلى flip .

  5. .' : الوسيطة الأساسية لعدم إهمال .' هي طول transpose . يستبدل الاقتراح الأول .' بالأسماء transpose و conjadjoint ، الأمر الذي لا يحسن هذا الموقف. في المقابل ، يقدم الاقتراح الثاني الأسماء flip و transpose ، لتحسين هذا الموقف.

الاختلافات في المسارات إلى 1.0

ما الذي يتطلبه الوصول إلى 1.0 ضمن كل عرض؟ الطريق إلى 1.0 أبسط في إطار الاقتراح الثاني ، لذا فلنبدأ من هناك.

الطريق إلى 1.0 بموجب الاقتراح الثاني

  1. قدم أنواع أغلفة بديلة كسولة في LinAlg ، قل Adjoint و Transpose . قم بتقديم طرق mul[!] / ldiv[!] / rdiv[!] للإرسال على أنواع الغلاف هذه وتحتوي على كود A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] المقابل. أعد تطبيق الأساليب الأخيرة كأطفال مختصرين للطرق السابقة.

    هذه الخطوة لا تكسر شيئًا ، وتتيح على الفور إزالة كل من التخفيض الخاص وإيقاف العمل .' :

  2. قم بإزالة التخفيض الخاص الذي ينتج عنه A[c|t]_{mul|ldiv|rdiv}_B[c|t] ، بدلاً من خفض ' / .' إلى Adjoint / Transpose ؛ التعبيرات التي كانت مخفضة بشكل خاص سابقًا تؤدي إلى مكالمات A[c|t]_{mul|ldiv|rdiv}_B[c|t] ثم تصبح بدلاً من ذلك ما يعادل mul / ldiv / rdiv المكالمات. استبعد A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] rdiv[!] للطرق المقابلة mul[!] / ldiv[!] / rdiv[!] . استنفد .' .

    يمكن القيام بهذه الخطوات في 0.7. إنهم يكسرون شيئين فقط: (1) الكود الذي يعتمد على التخفيض الخاص لتصل إلى طرق A[c|t]_{mul|ldiv|rdiv}_B[c|t] لأنواع غير Base / LinAlg سوف تنكسر. سيصدر مثل هذا الرمز MethodError s بشكل صريح يشير إلى ما ينتج عن خفض العائد الجديد / ما يحتاج الكود المكسور إلى الانتقال إليه. (2) الكود الذي يعتمد على ' s / .' s المعزول بشكل صارم سوف ينكسر. يجب أن يكون وضع الفشل الشائع أيضًا صريحًا MethodError s. في كل مكان ، يكون الكسر محصورًا وبصوت عال.

    وهذا كل شيء بالنسبة للتغييرات الضرورية تمامًا لـ 1.0.

    في هذه المرحلة ، سينتج عن Adjoint(A) / Transpose(A) وضعًا مترابطًا كسولًا وتغيير موضع ، و adjoint(A) / transpose(A) سينتج عنه توافد شغوف و تبديل. يمكن أن تظل الأسماء الأخيرة إلى أجل غير مسمى أو ، إذا رغبت في ذلك ، يتم إهمالها لبعض التهجئة الأخرى في 0.7 ، على سبيل المثال eagereval(Adjoint(A)) / eagereval(Transpose(A)) modulo spelling eagereval أو eageradjoint(A) / eagertranspose(A) . في حالة الإيقاف ، يمكن إعادة توظيف adjoint / transpose في 1.0 (على الرغم من وجود Adjoint(A) / Transpose(A) ، لست متأكدًا مما إذا كان ذلك ضروري).

    أخيرا...

  3. قدم flip و / أو Flip في Base . نظرًا لكونه إضافة ميزة ، يمكن أن يحدث هذا التغيير في 1.x إذا لزم الأمر.

الطريق إلى 1.0 بموجب الاقتراح الأول

ماذا عن اقتراح واحد؟ يوضح ما يلي مسارين محتملين. المسار الأول يدمج التغييرات في 0.7 ولكنه يتضمن كسرًا صامتًا. يتجنب المسار الثاني الانكسار الصامت ، ولكنه يتضمن المزيد من التغيير 0.7-> 1.0. كلا المخططين يطوران قاعدة الكود باستمرار ؛ قد تعمل المعادلات الأقل استمرارًا على توحيد / تجنب بعض العمل / الاضطراب ، ولكن من المحتمل أن تكون أكثر صعوبة وعرضة للخطأ. يبدو أن العمل الجاري يتبع المسار الأول.

المسار الأول تحت الاقتراح الأول (مع كسر صامت)
  1. قم بتغيير دلالات transpose من التحويل إلى انعكاس المصفوفة ، وكذلك بالضرورة دلالات جميع الوظائف المرتبطة بـ transpose . على سبيل المثال ، قد تحتاج جميع طرق A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] تبدأ من At_... أو تنتهي بـ ..._Bt[!] إلى مراجعة دلالية. يجب أيضًا تغيير تعريفات وسلوك Symmetric / issymmetric . انقل transpose نفسها إلى Base .

    هذه التغييرات سوف تنكسر بصمت وعلى نطاق واسع.

  2. قدم conjadjoint في LinAlg . تتطلب هذه الخطوة استعادة جميع الأساليب التي تم التطرق إليها في الخطوة السابقة ، ولكن في شكلها الدلالي الأصلي ، والآن بأسماء مختلفة مرتبطة بـ conjadjoint (مثل أسماء Aca_... و ..._Bca[!] ) . يتطلب أيضًا إضافة طرق لمجموعات الأنواع الإضافية التي تدعم في نفس الوقت array-flip (الآن transpose conjadjoint ) ، وتغيير موضعها (الآن LinAlg يتطلب (على سبيل المثال ، المتغيرات ca بين A[c|t|ca]_{mul|ldiv|rdiv}_B[c|t|ca][!] ).

  3. قم بتقديم وظيفة التعيين الكسول والتبديل (تسمى conjadjoint ) في LinAlg ، قل Adjoint و ConjAdjoint . قدم نوع غلاف مصفوفة كسول (يسمى transpose ) في Base ، لنقل Transpose . قدم mul[!] / ldiv[!] / rdiv[!] طرق الإرسال على أنواع الغلاف هذه وتحتوي على كود A[c|t|ca]_{mul|ldiv|rdiv}_B[c|t|ca][!] المقابل. أعد تطبيق الأساليب الأخيرة كأطفال مختصرين للطرق السابقة.

  4. قم بإزالة التخفيض الخاص الذي ينتج عنه A[c|t]_{mul|ldiv|rdiv}_B[c|t] ، بدلاً من خفض ' / .' إلى Adjoint / Transpose ؛ كانت التعبيرات التي تم تخفيضها سابقًا بشكل خاص تؤدي إلى مكالمات A[c|t]_{mul|ldiv|rdiv}_B[c|t] ثم بدلاً من ذلك تصبح مكافئة mul / ldiv / rdiv (على الرغم من تذكر أن الدلالات ستتغير بصمت). استبعد A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] rdiv[!] للطرق المقابلة mul[!] / ldiv[!] / rdiv[!] . وبالمثل ، قم بإزالة طرق Aca_... / ...Bca[!] تم تقديمها مؤخرًا لصالح mul[!] / ldiv[!] / rdiv[!] مكافئات. استهلاك .' .

يجب أن تذهب هذه التغييرات في 0.7. ستؤدي التغييرات الدلالية في العمليات الحالية إلى كسر واسع وصامت. ستؤدي إزالة الخفض الخاصة إلى نفس الكسر المحدود بصوت عالٍ الموصوف أعلاه.

في هذه المرحلة ، سينتج Adjoint(A) / Transpose(A) / ConjAdjoint(A) على التوالي معايرة كسولة ، وقلب الصفيف ، والتبديل ، و adjoint(A) / transpose(A) / conjadjoint(A) سينتج على التوالي معايرة شغوفة وقلب مصفوفة وتبديل. يمكن أن تظل الأسماء الأخيرة إلى أجل غير مسمى أو ، إذا رغبت في ذلك ، يتم إهمالها لبعض التهجئة الأخرى أيضًا في 0.7 (المرجع أعلاه).

يمكن للمرء تقديم ConjAdjoint في وقت سابق في هذه العملية لدمج / تجنب بعض العمل / الاضطراب ، على الرغم من أن هناك احتمالات بأن هذا النهج سيكون أكثر صعوبة وعرضة للخطأ.

المسار الثاني تحت الاقتراح الأول (تجنب الكسر الصامت)
  1. تقديم conjadjoint في LinAlg . قم بترحيل جميع الوظائف والأساليب المرتبطة حاليًا بـ transpose (بما في ذلك على سبيل المثال A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] الطرق التي تتضمن t ) إلى conjadjoint والأسماء المشتقة. اجعل جميع الأسماء ذات الصلة بـ transpose توابع قصيرة للمكافئات الجديدة conjadjoint . تجاهل جميع الأسماء المرتبطة بـ transpose لـ conjadjoint المكافئة.

  2. قدم أنواع أغلفة بديلة كسولة (تسمى conjadjoint ) في LinAlg ، لنقل Adjoint و ConjAdjoint . قدم mul[!] / ldiv[!] / rdiv[!] طرق الإرسال على أنواع الغلاف هذه وتحتوي على رمز طرق A[c|ca]_{mul|ldiv|rdiv}_B[c|ca][!] المقابل. أعد تطبيق الأساليب الأخيرة كأطفال مختصرين للطرق السابقة.

  3. قم بإدخال نوع غلاف مصفوفة كسول في Base ، يسمى Transpose (بشكل مربك إلى حد ما ، حيث يتم إهمال transpose نفس الوقت إلى conjadjoint مع تبديل دلالات) أضف جميع التوابع العامة الضرورية لـ array-flip ( Transpose ) لتعمل على Base . ثم أضف طرقًا إلى LinAlg لجميع مجموعات الأنواع الإضافية التي تدعم في نفس الوقت array-flip (الآن Transpose ، لكن ليس transpose ) ، بدّل (الآن conjadjoint و ConjAdjoint ) ، والمقارنة بـ LinAlg يتطلب (على سبيل المثال mul[!] / rdiv[!] / ldiv[!] ما يعادل A[c|t|ca]_{mul|ldiv|rdiv}_B[c|t|ca][!] غير موجودة حاليًا).

  4. قم بإزالة التخفيض الخاص الذي ينتج عنه A[c|t]_{mul|ldiv|rdiv}_B[c|t] ، بدلاً من خفض ' / .' إلى Adjoint / Transpose ؛ التعبيرات التي كانت مخفضة بشكل خاص سابقًا تؤدي إلى مكالمات A[c|t]_{mul|ldiv|rdiv}_B[c|t] ثم تصبح بدلاً من ذلك ما يعادل mul / ldiv / rdiv المكالمات. استبعد A[c|t]_{mul|ldiv|rdiv}_B[c|t][!] rdiv[!] للطرق المقابلة mul[!] / ldiv[!] / rdiv[!] . استهلاك .' .

يجب أن تذهب التغييرات السابقة في 0.7. لا يوجد كسر صامت ، فقط الكسر العالي من إزالة التخفيض الخاصة كما هو موضح أعلاه.

في هذه المرحلة ، سينتج عن Adjoint(A) / Transpose(A) / ConjAdjoint(A) على التوالي معايرة كسولة ، وقلب مصفوفة ، وتبديل. سينتج عن adjoint(A) / conjadjoint(A) على التوالي معايرة شغوفة وتبديلًا. سيتم إهمال transpose(A) إلى conjadjoint ؛ يمكن إعادة توجيه transpose في 1.0 إذا رغبت في ذلك. يمكن أن يظل adjoint إلى أجل غير مسمى أو يتم إهماله لصالح تهجئة أخرى في 0.7. طريقة أخرى لتهجئة conjadjoint يمكن أن تذهب مباشرة إلى 0.7.

يمكن للمرء دمج الخطوتين 1 و 2 إلى حد ما ، وتجنب بعض العمل / الاضطراب ، على الرغم من أن هناك احتمالية أن يكون هذا النهج أكثر صعوبة وعرضة للخطأ.

#

شكرا للقراءة!

شكرا على الكتابة الرائعة. أتفق أيضًا بشكل عام مع الاقتراح 2 ، لسبب إضافي هو أن المرافقة المترافقة ليست على الإطلاق المصطلحات القياسية وأنا شخصياً أجدها مربكة للغاية (حيث يُستخدم هذا المصطلح أحيانًا كمصطلحات للتبديل البسيط في بعض فروع الرياضيات ، والصفة الإضافية المقترنة يبدو أنه يعني أن الاقتران يحدث).

حاولت قراءة المناقشات التفصيلية أعلاه ، لكنني فشلت في معرفة النقطة التي تقرر / حفزنا أن يكون transpose رياضيًا متكررًا. يبدو أن هذا يتبع بعض المناقشات الخاصة (في مكان ما بين 14 و 18 يوليو) ، وبعد ذلك تم تقديم تبديل رياضي وبنيوي فجأة.
@ Sacha0 يصفها بأنها

كيف نشأ ذلك: تم الخلط سابقًا بين "النقل الهيكلي" و "المرافقة الرياضية" / "النقل الرياضي"

أوافق على أن التبديل (البنيوي) قد تم خلطه مع "معايرة" ، ولكن هنا يظهر "تبديل رياضي" من العدم؟ من أجل الاكتمال / الاكتفاء الذاتي ، هل يمكن إعادة / تلخيص هذا المفهوم ولماذا يجب أن يكون تكراريًا بإيجاز؟

فيما يتعلق بذلك ، أعتقد أنه لا أحد يستخدم حقًا transpose بالمعنى الرياضي المجرد ، كعملية على الخرائط الخطية ، لسبب بسيط هو أن تبديل المصفوفة سيكون كائنًا لا يعمل على المتجهات ولكن على RowVector s ، أي أنه سيتم تعيين RowVector إلى RowVector . بالنظر إلى الافتقار إلى الحجة للتبديل العودي ، فأنا لا أرى حقًا أي تمييز بين تبديل المصفوفة العادي الذي يتم تعريفه عادةً كمفهوم (يعتمد على الأساس) ، والعملية المقترحة حديثًا flip .

شكرا @ Sacha0 على الكتابة الرائعة. أفضل الاقتراح 2 (تبديل الاستدعاء adjoint ، تبديل transpose ، و array-flip flip . adjoint و transpose مباشر في LinAlg و flip في Base .). بالنسبة لي ، يبدو أن هذا يعطي أفضل نتيجة نهائية (والتي يجب أن تكون الشغل الشاغل) ، ويسمح أيضًا بطريقة أنظف للإصدار 1.0. أنا أتفق مع نقاطك أعلاه ، لذا لن أكررها ، ولكن إليك بعض التعليقات الإضافية.

إحدى الحجج المؤيدة للتكرار غير التكراري transpose هي أن بناء الجملة .' مناسب جدًا ، وبالتالي يمكن استخدامه على سبيل المثال Matrix{String} . بافتراض أن بناء الجملة سيختفي (# 21037) ويجب على المرء استخدام transpose(A) بدلاً من A.' ، فأعتقد أن وظيفة flip ستكون إضافة مرحب بها (أقصر وأوضح من transpose(A) ، وبالتأكيد أجمل من permutedims(A, (2,1)) ).

يعتبر الفصل بين LinAlg و Base الذي يقدمه الاقتراح 2 لطيفًا جدًا أيضًا. ليس فقط لأن LinAlg يحتاج فقط إلى الاهتمام بكيفية التعامل مع Transpose و Adjoint ، ولكن أيضًا يوضح أننا نعتبر transpose و adjoint ليكون LinAlg عمليات ، و flip ليكون شيئًا عامًا AbstractMatrix يقلب أبعاد المصفوفة.

أخيرًا ، لم أر الكثير من الشكاوى حول transpose(::Matrix{String}) إلخ. هل هي حقًا حالة استخدام شائعة؟ في معظم الحالات ، من الأفضل بناء المصفوفة المعكوسة من البداية على أي حال.

قد يكون مخطط التسمية هذا (الاقتراح 2) أفضل بالفعل. يعتبر كل من Adjoint and Transpose من المصطلحات القياسية في الجبر الخطي ، وهو أقل تكسرًا ...

لكنه فشل في معرفة النقطة التي تقرر / دافعها أن يكون التحويل الرياضي متكررًا

Jutho هي نفس الوسيطة مثل المرافقة (المرافقة للرقم المركب هي مترافقة (نظرًا لأن الأرقام المركبة هي مسافات متجهية من الرتبة الأولى صالحة .' لـ "نقطة مصفوفة حقيقية أو متجه" ، وكنت أيضًا أفعل ذلك. هنا ، لن يكون ' صالحًا فحسب ، بل سيكون أيضًا أكثر عمومية (يعمل مع المصفوفات التي قد تكون ذات قيمة معقدة و / أو متداخلة). يحدث المزيد من الاستخدام الحقيقي للمحول العودي في المصفوفات المعقدة المتداخلة عندما تمنحك المعادلات conj(adjoint(a)) ، وهو أمر نادر نسبيًا ولكنه لا يزال يحدث (من النادر أن أشعر بالسعادة إذا لم تكن هناك وظيفة مرتبطة به - في المناقشات أعلاه وفي أماكن أخرى بدأ العديد من الأشخاص يطلقون عليها أشياء مختلفة مثل "تبديل رياضي" ، اخترت conjadoint ، لكن لا شيء من هذا هو IMO رائع ، باستثناء ربما transpose نفسه). في الجبر الخطي ، لا تظهر العملية غير التكرارية التي تعيد ترتيب كتل مصفوفة الكتلة ولكنها لا تفعل شيئًا للكتل نفسها بشكل عام.

أخيرًا ، لم أر الكثير من الشكاوى حول عدم عمل transpose(::Matrix{String}) إلخ. هل هي حقًا حالة استخدام شائعة؟ في معظم الحالات ، من الأفضل بناء المصفوفة المعكوسة من البداية على أي حال.

أعتقد أن هذا النوع من الأشياء مرغوب فيه تمامًا مع عمليات بث جوليا. على سبيل المثال ، من الشائع جدًا أن تأخذ المنتج الخارجي (الديكارتي) لبعض البيانات وربما ترسمه عبر دالة. لذلك بدلاً من شيء مثل map(f, product(a, b)) يمكننا استخدام broadcast(f, a, transpose(b)) أو ببساطة f.(a, b.') . إنها قوة كبيرة في عدد قليل من الشخصيات.

أفكاري: لتجنب إضافة المزيد من أسماء الوظائف إلى هذه المساحة (مثل flip ) ، أتساءل عما إذا كان بإمكاننا الحصول على قيمة افتراضية للتبديل في permutedims(a) = permutedims(a, (2,1)) . لسوء الحظ ، هذا ليس قصيرًا مثل flip ، ولكنه أقل بغيضًا بشكل ملحوظ من نموذج permutedims(a, (2,1)) الكامل (وله تأثير جانبي لتعليم المستخدمين حول الوظيفة الأكثر عمومية).

( @ Sacha0 شكرًا جزيلاً لك على Adjoint و Transpose ، أو RowVector + MappedArray + أي شيء مقلوب المصفوفات كما هو مخطط سابقًا (ربما فقط PermutedDimsArray ) ، ما زلت أميل إلى تفضيل الأخير ...)

يحدث المزيد من الاستخدام الحقيقي للمحول العودي في المصفوفات المعقدة المتداخلة عندما تمنحك المعادلات conj(adjoint(a))

بمجرد حصولك على conj(adjoint(a)) في معادلاتك ، كيف تعرف أنه في الواقع conj الذي تريد تطبيقه على إدخالات المصفوفة وربما ليس adjoint ، أي ربما تريد بالفعل adjoint.(adjoint(a)) .

من المحتمل أن يؤدي هذا إلى حظر / طرد ، لكنني لست معجبًا كبيرًا بالفكرة العودية بأكملها. أنا لست بالضرورة معارضًا لذلك أيضًا ، لا أعتقد أن هناك سببًا صارمًا رياضيًا لذلك ، حيث لا يتم تعريف المتجهات والعوامل / المصفوفات بشكل متكرر ، يتم تحديدها عبر حقول العددية (وبحلقات التمديد إذا كنت تريد للعمل أيضًا مع الوحدات بدلاً من المساحات المتجهة). ولذا يجب أن يعمل Base.LinAlg فقط في هذه الحالة. الحجة الرئيسية

يجب أن تكون النقطة المساعدة للمتجه عاملًا خطيًا يرسمه إلى عدد قياسي. بمعنى ، يجب أن يكون '* a عددًا إذا كان a متجهًا.

لا يتوافق مع طريقة عمل Julia Base: ارسم a=[rand(2,2),rand(2,2)] ولاحظ a'*a . إنه ليس عددي. إذن هل a مصفوفة الآن ، لأنها متجه مملوء بالمصفوفات؟ ما ورد أعلاه ليس سوى عدد قياسي إذا كنت تنوي بالفعل استخدام حلقة مصفوفات 2 × 2 كأعدادات قمت بتعريف وحدة نمطية عليها. لكن في هذه السياقات ، ليس من الواضح بالنسبة لي أن النتيجة أعلاه هي النتيجة المقصودة. نادرًا ما يتم استخدام المنتج الداخلي الإقليدي في سياق الوحدات النمطية وما إلى ذلك ، لذلك لا أعتقد أن Base يجب أن يكلف نفسه عناء تحديد السلوك الصحيح له.

لذلك حقًا ، على الرغم من أن العبارة أعلاه قد تكون محاولة لتوسيع الحافز إلى ما بعد تفسير المصفوفات المليئة بالمصفوفات كمصفوفات كتلة ، في النهاية أعتقد أن تفسير مصفوفة الكتلة كان الدافع الحقيقي الوحيد لتحقيق adjoint والآن حتى transpose (الذي لا يستخدم أبدًا بالمعنى الرياضي ولكن دائمًا بمعنى مؤشرات مصفوفة الوجه) عودي في المقام الأول. إذا قمت بتعريف حقل رقمي جديد ، فاكتب بنفسك ، فهذا مجرد عبء غريب عليك أن تحدد adjoint و transpose له بالإضافة إلى conj ، قبل أن تتمكن من استخدامه في مصفوفة.

فلماذا ، مع نظام كتابة قوي مثل جوليا ، ليس فقط مجرد نوع مخصص لمصفوفات الكتلة. وهكذا يلعب دور محامي الشيطان:

  • كم عدد الأشخاص الذين يستخدمون / يعتمدون بالفعل على السلوك العودي الحالي للوضع المساعد لأي عمل عملي؟
  • هل هناك أي لغات أخرى تستخدم مثل هذا النهج العودي؟ (ماتلاب ، باستخدام خلايا المصفوفات ، لا)

كما قيل ، أنا لست بالضرورة معارضًا ، فقط أشكك في الصلاحية (حتى بعد قراءة كل المناقشة أعلاه) ، خاصة بالنسبة للحالة transpose .

من المحتمل أن يؤدي هذا إلى حظر / طرد

أدرك أن هذه مزحة ولكن وجود رأي غير شعبي لن يؤدي إلى حظر أي شخص. فقط السلوك السيئ الذي يستمر لفترة طويلة يمكن أن يؤدي إلى الحظر. ومع ذلك ، فإن الحظر ليس دائمًا .

لا أعتقد أن هناك سببًا صارمًا رياضيًا لهذا ، حيث لا يتم تعريف المتجهات والعوامل / المصفوفات بشكل متكرر ، يتم تحديدها عبر حقول العددية (وبحلقات التمديد إذا كنت تريد أيضًا العمل مع الوحدات بدلاً من مسافات المتجهات ).

هذا البيان لا معنى له بالنسبة لي. متجه من المتجهات ، أو متجه من الوظائف ، أو متجه المصفوفات ، لا يزال يشكل مساحة متجه (فوق حقل عددي أساسي) مع تعريف + و * scalar بشكل متكرر ، وبالمثل يتشكل مساحة داخلية للمنتج مع تعريف المنتج الداخلي بشكل متكرر. تتحدى فكرة أن النواقل يمكن أن تكون "أعمدة من الحجميات" كلاً من التعريفات والاستخدام الشائع في الرياضيات والفيزياء والهندسة.

اربح a=[rand(2,2),rand(2,2)] ولاحظ a'*a . إنه ليس عددي.

في هذه الحالة ، "الحلقة العددية" لـ a هي حلقة المصفوفات 2x2. إذن فهذه مشكلة لغوية ، وليست مشكلة في طريقة عمل التوليفات.

الجدل حول كيفية a'*a يجب أن تعمل من كيف يعمل حاليا (أو لا يعمل) في جوليا يبدو دائري نوعا ما.

إذا قمت بتعريف حقل رقمي جديد ، فاكتب بنفسك ، فهذا مجرد عبء غريب تحتاج إلى تعريف adjoint و transpose له بالإضافة إلى conj ، قبل أن تتمكن من استخدامه في مصفوفة

أعتقد أن هذا العبء جمالي أكثر من كونه عمليًا. إذا كنت موافقًا على جعله نوعًا فرعيًا من Number فلن تضطر إلى تعريف أي شيء ، وحتى إذا كنت تعتقد أن Number ليس هو الشيء الصحيح بالنسبة لك ، فإن التعريفات تافهة للغاية إضافتهم بالكاد عبء.

فلماذا ، مع نظام كتابة قوي مثل جوليا ، ليس فقط مجرد نوع مخصص لمصفوفات الكتلة.

https://github.com/KristofferC/BlockArrays.jl/ نرحب بالمساهمين :)

اعتذاري عن نكتة "المنع". سيكون هذا هو رد فعلي الأخير حتى لا أخرج هذه المناقشة عن مسارها أكثر من ذلك. من الواضح أن المضاعفات العودية (ولكن ربما لا يتم تبديلها) تمت تسويتها ، وأنا لا أحاول التراجع عن هذا القرار. أحاول فقط أن أشير إلى بعض التناقضات.

StefanKarpinski : مثال الحلقة العددية يتناقض تمامًا مع العودية: هل المصفوفات 2 × 2 هي نفسها المقاييس ، أم أن التعريف متكرر وهل النوع الأساسي Number هو العدد القياسي؟

في الحالة الأولى ، لديك بالفعل وحدة نمطية بدلاً من مساحة متجه ، وربما يعتمد ذلك على حالة الاستخدام سواء كنت تريد conj أو adjoint على تلك "الحجميات" ، إذا كنت تريد ذلك باستخدام المنتجات الداخلية والملحقات على الإطلاق.

أنا بخير مع قبول التعريف الأخير. أنا أستخدم عناصر اعتباطية في فضاءات فرعية ثابتة للمجموعة لمنتجات موتر متدرجة لمسافات متجهية فائقة في وظيفتي ، لذا فأنا لست مقيدًا بأعمدة الأرقام في تعريفي للمتجهات. لكن نواقل المصفوفات ، هل هي مجرد نواقل نقية أم أنها ترث أيضًا بعض سلوك المصفوفة. في الحالة الأولى ، يجب أن ينتج dot(v,w) عددًا قياسيًا ، ربما عن طريق استدعاء vecdot على عناصره بشكل متكرر. في الحالة الأخيرة ، يجب أن ينتج على الأقل vecdot(v,w) عددًا قياسيًا من خلال العمل بشكل متكرر. لذلك سيكون هذا إصلاحًا ضئيلًا ليكون متسقًا مع المساعد العودي.

ولكن يبدو أنه من الأسهل ألا يكون لديك عودي transpose والسماح باستخدامه للتطبيقات غير الرياضية أيضًا ، لأنني أعتقد أنه حتى في معادلات المصفوفة النموذجية ، لا علاقة له بالمبدل الرياضي الفعلي من خريطة خطية.

أعتقد أن dot يجب أن يستدعي dot بشكل متكرر ، وليس vecdot ، لذلك سيكون خطأ لمتجه المصفوفات لأننا لا نحدد المنتج الداخلي الأساسي للمصفوفات.

أنا دائما مندهش من أن التحويل هو تكراري .. ولا أستطيع أن أتخيل أن أي شخص ليس كذلك. (أظن أن وجهات النظر حول "تبديل خريطة خطية" مقالة ويكيبيديا قد تضاعفت ثلاث مرات على الأقل بسبب هذه المناقشة.)

لقد وجدت في كثير من الأحيان أن التعريفات العودية مقلقة ، وعموماً شاركت الرأي الذي عبر عنه Jutho أعلاه (ولكن مرة أخرى لدينا تدريب مشابه جدًا).

أعتقد أنني اكتشفت التناقض الذي كان يزعجني هنا - نستمر في استخدام الحلقات والحقول مثل تضمين مصفوفة 2 × 2 للأرقام المركبة كمثال هنا ، لكنها لا تعمل في الواقع ولا تحفز التحويل العودي (وإعادة الربط) ).

دعني أوضح. الأشياء التي أتفق معها على نطاق واسع

  1. Scalars هي عوامل خطية صالحة من المرتبة الأولى. نظرًا لنظام جوليا القوي من النوع ، لا يوجد سبب لعدم تطبيق مفاهيم LinAlg مثل adjoint ، على سبيل المثال ، يجب علينا تحديد adjoint(z::Complex) = conj(z) . (ما وراء المتجهات ومصفوفات الحجميات ، يمكن أيضًا توسيع مفاهيم LinAlg (بواسطة المستخدمين ، أفترض) لتشمل كائنات أخرى - تم ذكر
  2. يجب أن نكون قادرين على التعامل بطريقة ما مع الحجميات ذات التمثيلات المختلفة. المثال النموذجي هنا هو رقم مركب z = x + y*im يمكن تصميمه كـ Z = x*[1 0; 0 1] + y*[0 1; -1 0] والعمليات + ، - ، * ، / يتم الحفاظ على \ في هذا التماثل. (لاحظ مع ذلك أن conj(z) ينتقل إلى adjoint(Z) / transpose(Z) / flip(Z) - المزيد عن ذلك لاحقًا).
  3. يجب أن تكون مصفوفات الكتل ممكنة بطريقة ما (الأسلوب الحالي يعتمد على عودية adjoint افتراضيًا ، إلخ).

يبدو من المعقول أن يكون Base.LinAlg متوافقًا مع 1 و 2 ، ولكن يجب أن يتم إجراء IMO 3 فقط في Base إذا كان مناسبًا بشكل طبيعي (وإلا سأميل إلى التأجيل للحزم الخارجية مثل https: / /github.com/KristofferC/BlockArrays.jl).

أدرك الآن أننا نخلط بين 2 و 3 وهذا يؤدي إلى بعض التناقضات (أشار Jutho إلى هذا أيضًا). أدناه، أود أن تبين أن 3. باستخدام عودي adjoint وغيرها من العمليات وفقا للمصفوفات كتلة لا يعطينا 2. وأسهل طريقة هي عن طريق القدوة. دعنا نحدد مصفوفة 2x2 للأرقام المركبة كـ m = [z1 z2; z3 z4] ، التمثيل المتماثل M = [Z1 Z2; Z3 Z4] ، ومصفوفة الكتلة القياسية 2x2 b = [m1 m2; m3 m4] حيث m1 إلخ متساوية الحجم مصفوفات Number . الإجابات الصحيحة لغويًا للعمليات الشائعة مذكورة أدناه:

| عملية | z | Z | m | M | b |
| - | - | - | - | - | - |
| + ، - ، * | متكرر | متكرر | متكرر | متكرر | متكرر |
| conj | conj(z) | Z' أو Z.' أو flip(Z) | conj.(m) | adjoint.(M) (أو transpose.(M) ) | conj.(b) |
| adjoint | conj(z) | Z' أو Z.' أو flip(Z) | flip(conj.(m)) أو متكرر | flip(transpose.(m)) أو متكرر | متكرر |
| trace | z | Z | z1 + z4 | Z1 + Z4 | trace(m1) + trace(m4) |
| det | z | Z | z1*z4 - z2*z3 | Z1*Z3 - Z2*Z3 | det(m1) * det(m4 - m2*inv(m1)*m3) (إذا كان m1 قابل للانعكاس ، انظر على سبيل المثال ويكيبيديا ) |

بالنظر إلى عمليات مثل trace و det التي ترجع الحجميات ، أعتقد أنه من الواضح تمامًا أن نظام Julia الخاص بنا مقابل LinAlg لا يمكنه التعامل مع تضمين مصفوفة 2x2 Complex بطريقة "تلقائية" ، استنتاج ما نعنيه بكلمة "عددية" في أي لحظة معينة. مثال صارخ هو trace(Z) حيث Z = [1 0; 0 1] هو 2 ، بينما هذا هو تمثيلنا 1 . وبالمثل مقابل rank(Z) .

تتمثل إحدى طرق استعادة التناسق في تحديد تمثيلنا 2 × 2 بشكل صريح باعتباره عددًا ، على سبيل المثال عن طريق التصنيف الفرعي Number كما هو موضح أدناه:

struct CNumber{T <: Real} <: Number
    m::Matrix{T}
end
CNumber(x::Real, y::Real) = CNumber([x y; -y x])

+(c1::CNumber, c2::CNumber) = CNumber(c1.m + c2.m)
-(c1::CNumber, c2::CNumber) = CNumber(c1.m - c2.m)
*(c1::CNumber, c2::CNumber) = CNumber(c1.m * c2.m)
/(c1::CNumber, c2::CNumber) = CNumber(c1.m / c2.m)
\(c1::CNumber, c2::CNumber) = CNumber(c1.m \ c2.m)
conj(c::CNumber) = CNumber(transpose(c.m))
zero(c::CNumber{T}) where {T} = CNumber(zero(T), zero(T))
one(c::CNumber{T}) where {T} = CNumber(one(T), one(T))

باستخدام هذا التعريف ، من المحتمل أن تعمل الطرق العامة LinAlg بشكل جيد.

الاستنتاج الذي استخلصته من هذا: العودية adjoint هي ملاءمة لمصفوفات الكتلة ومتجهات المتجهات. لا ينبغي أن يكون الدافع وراء ذلك هو الصواب الرياضي لأنواع المصفوفات "العددية" 2 × 2 التي أشرت إليها أعلاه Z . أرى أنه اختيارنا سواء كنا ندعم مصفوفات الكتلة أم لا بشكل افتراضي ، مع الإيجابيات والسلبيات التالية:

الايجابيات

  • الراحة لمستخدمي كتلة المصفوفة
  • متجهات المتجهات هي مسافات متجهة صالحة ، ومصفوفات الكتلة هي عوامل تشغيل خطية صالحة ، تحت + ، * ، conj ، إلخ. إذا كان من الممكن جعل هذا تماثلًا طبيعيًا (على عكس المثال Z أعلاه ، والذي يتطلب CNumber ) ، فلماذا لا؟

سلبيات

  • تعقيد إضافي كبير لتنفيذنا لـ LinAlg (يمكن أن يعيش في حزمة أخرى).
  • من الصعب بعض الشيء (ولكن ليس من المستحيل) دعم أشياء مثل eig(block_matrix) . إذا قلنا أن LinAlg يدعم eig و LinAlg يدعم مصفوفات الكتلة ، فأنا أعتبر هذا خطأ حتى يتم إصلاحه. نظرًا للكم الهائل من الوظائف التي يوفرها LinAlg فمن الصعب أن نرى أننا "انتهينا".
  • إزعاج مستخدمي البيانات الذين يرغبون في استخدام عمليات مثل transpose بطريقة غير متكررة ،

بالنسبة لي فإن السؤال هو - لا نختار أن أقول أن افتراضيا LinAlg تتوقع عناصر AbstractArray الصورة أن تكون "العددية" (فرعية أو بطة typings من Number ) واستخراج تعقيد مصفوفات الكتل للحزم الخارجية؟ أم أننا نتبنى التعقيد في Base و LinAlg ؟

كانت الخطة حتى يوم مضى هي الأخيرة.

@ Sacha0 لقد كنت أحاول إكمال RowVector العمل الضروري لدعم التغييرات هنا (سابقاً: غير متكرر transpose ، RowVector دعم السلاسل والبيانات الأخرى) والآن أتساءل ما الذي كان يدور في ذهنك من حيث التصميم.

من المناقشات الأخيرة ، أرى هذه الحالات مع تخمين ما قد يكون مطلوبًا

| | ناقل | ماتريكس |
| - | - | - |
| adjoint | RowVector مع عودي adjoint | AdjointMatrix أو TransposedMatrix بالعودة adjoint |
| transpose | RowVector مع عودي transpose | TransposeMatrix مع عودي transpose |
| flip | نسخة أو PermutedDimsArray ؟ | نسخة أو PermutedDimsArray ؟ |
| conj من AbstractArray | كسول أو حريص؟ | كسول أو حريص؟ |
| conj من RowVector أو TransposedMatrix | كسول | كسول |

(المحاولات المذكورة أعلاه لفصل مخاوف الجبر الخطي عن أبعاد التباديل لمصفوفات البيانات.)

لذا بعض الأسئلة الأساسية لإزالتي:

  • هل نقوم بالعودة transpose أم لا؟ ماذا عن adjoint ؟
  • إذا كان الأمر كذلك ، فهل نستمر في افتراض conj(transpose(array)) == adjoint(array) ؟
  • يبدو أن بعض عمليات الاقتران المعقدة على الأقل ستكون كسولة ، لدعم على سبيل المثال جميع عمليات BLAS الحالية بدون نسخ إضافية. هل نجعل conj كسول لجميع المصفوفات؟
  • إذا قدمنا flip ، فهل هو كسول أم متحمس؟

لمعلوماتك لقد جربت أسلوبًا منخفض الاحتكاك لـ "قلب" أبعاد مصفوفة عند # 24839 ، باستخدام نموذج أقصر مقابل permutedims .

أؤيد بشدة اقتراح @ Sacha0 2. لم نقم بفرز كامل الأسس النظرية conj∘adjoint ) في هذا الصدد ، إذا كان مطلوبًا على الإطلاق.

FWIW، Mathematica لا تقوم بالعودة Transpose ولا ConjugateTranspose :

untitled

حاولت قراءة المناقشات التفصيلية أعلاه ، لكنني فشلت في معرفة النقطة التي تقرر / دافع فيها أن يكون التحويل الرياضي تكراريًا. [...] من أجل الاكتمال / الاكتفاء الذاتي ، هل يمكن تكرار / تلخيص هذا المفهوم ولماذا يجب أن يكون تكراريًا بإيجاز؟

إنني أتفهم هذا الشعور وأقدره ، وأود معالجته بقدر ما يسمح به الوقت. إن التفسير الذي يسهل الوصول إليه وبوضوح لماذا يجب أن يكون التوفيق والتبديل متكررًا بالتعريف يمثل تحديًا للأسف في أفضل الأحوال ومن المحتمل ألا يكون ممكنًا باختصار. تستغرق عمليات الكتابة المتسقة والشاملة مثل تلك الموضحة أعلاه وقتًا هائلاً لتكوينها. لكون الوقت قصيرًا ، سأحاول على مدار اليوم بدلاً من ذلك معالجة بعض الالتباس في المشاركات القليلة السابقة من خلال الرد على نقاط / أسئلة معينة فيها ؛ يرجى تحمل معي بينما أفعل ذلك بشكل تدريجي :). الأفضل!

شرح لماذا يجب أن يكون المساعد ... متكررًا بالتعريف ...

أوافق كل من ساهم في هذه المناقشة على أن adjoint(A) يجب أن يكون متكررًا. نقطة الخلاف الوحيدة هي ما إذا كان يجب أن يكون transpose(A) أيضًا تكراريًا (وما إذا كان يجب تقديم وظيفة جديدة flip(A) للتبديل غير المتكرر).

أنا جميلة كل من ساهم في هذه المناقشة يوافق على أن المساعد (A) يجب أن يكون متكررًا.

انظر ، على سبيل المثال ، https://github.com/JuliaLang/julia/issues/20978#issuecomment-347777577 والتعليقات السابقة :). الأفضل!

إن حجة المضاعفة العودية أساسية جدًا في التعريفات. يجب أن يكون dot(x,y) منتجًا داخليًا ، أي ينتج مقياسًا ، وتعريف المرافقة هو أن dot(A'*x, y) == dot(x, A*y) . العودية (لكل من dot و adjoint ) يتبع من هاتين الخاصيتين.

(العلاقة بالمنتجات النقطية هي السبب الكامل وراء كون عمليات الربط والتبديل عمليات مهمة في الجبر الخطي. ولهذا السبب لدينا اسم لها ، وليس لعمليات أخرى مثل تدوير المصفوفات بمقدار 90 درجة ( rot90 في Matlab ).)

لاحظ أن إحدى المشكلات في استخدام flip للتبديل غير العودي هي أن كلا من Matlab و Numpy يستخدمان flip لما نسميه flipdim .

أعتقد أنه لا يوجد أحد يستخدم التحويل بالمعنى الرياضي المجرد ، كعملية على الخرائط الخطية ، لسبب بسيط هو أن تبديل المصفوفة سيكون كائنًا لا يعمل على المتجهات ولكن على متجهات الصف ، أي أنه سيعمل على مخطط RowVector إلى RowVector.

ولكن يبدو أنه من الأسهل عدم وجود تبديل متكرر والسماح باستخدامه للتطبيقات غير الرياضية أيضًا ، بما أنني أعتقد أنه حتى في معادلات المصفوفات النموذجية لا علاقة له بالمدور الرياضي الفعلي للخريطة الخطية.

تبديل (الذي لا يستخدم أبدًا بالمعنى الرياضي ولكن دائمًا بمعنى مؤشرات مصفوفة الوجه)

سيبدو هذا ملتوًا بعض الشيء ، لذا احمل معي :).

يشير جوليا adjoint تحديدًا إلى المساعد Hermitian . بشكل عام ، بالنسبة لـ U و V مساحات متجهة معيارية كاملة (مساحات Banach) مع مسافات مزدوجة خاصة بها U * و V ، وللخريطة الخطية A: U -> V ، فإن النقطة المجاورة لـ A ، التي يشار إليها عادةً A ، هي خريطة خطية A *: V * -> U * . هذا يعني ، بشكل عام ، أن النقطة المجاورة هي خريطة خطية بين مسافات مزدوجة ، تمامًا كما هو الحال بشكل عام ، فإن تبديل A ^ t عبارة عن خريطة خطية بين مسافات مزدوجة كما هو مذكور أعلاه. إذن كيف يمكن للمرء أن يوفق بين هذه التعريفات مع المفهوم المألوف للملحق Hermitian؟ :)

تكمن الإجابة في الهيكل الإضافي الذي تمتلكه المساحات التي يعمل بها المرء عادةً ، أي مساحات المنتج الداخلية الكاملة (مساحات هيلبرت). يحرض المنتج الداخلي على معيار ، لذا فإن مساحة المنتج الداخلية الكاملة (هلبرت) هي مساحة معيارية كاملة (باناخ) ، وبالتالي تدعم مفهوم (Hermitian) المساعد. إليكم المفتاح: وجود منتج داخلي بدلاً من مجرد قاعدة ، تنطبق واحدة من أجمل النظريات في الجبر الخطي ، وهي نظرية تمثيل Riesz. باختصار ، تنص نظرية تمثيل Riesz على أن فضاء هيلبرت متماثل بشكل طبيعي مع مساحته المزدوجة. وبالتالي ، عند العمل مع فضاءات هلبرت ، فإننا نحدد بشكل عام المساحات وثنائياتها ونسقط التمييز. إن تحديد هذا التعريف هو كيفية وصولك إلى المفهوم المألوف لـ Hermitian المساعد كـ A *: V -> U بدلاً من A *: V * -> U * .

ويتم إجراء نفس التعريف بشكل عام للتبديل عند النظر في فضاءات هلبرت ، مثل A ^ t: V -> U ، مما ينتج عنه المفهوم المألوف للتبديل. لتوضيح ذلك ، نعم ، المفهوم الشائع للتبديل هو المفهوم العام للتبديل المطبق على الإعداد الأكثر شيوعًا (هيلبرت) ، تمامًا كما أن المفهوم العام للإضافات Hermitian هو المفهوم العام للمعايرة المطبقة على هذا الإعداد. الأفضل!

أعتذر عن ضرب حصان خاسر ، لكنني اعتقدت أنني سألخص بإيجاز قضايا الارتباك الرياضي بطريقة مختلفة. النقطة الرئيسية في الخلاف هي كيفية تفسير كائن Vector{T} رياضيًا عندما لا يكون T مجرد نوع فرعي من Number بدون بنية فرعية تشبه المصفوفة.

تقبل مدرسة فكرية واحدة ادعاء

يُفهم متجه النواقل فوق حلقة R بشكل أفضل على أنه فضاء إجمالي مباشر ، وهو أيضًا مساحة متجه فوق R.

Modulo بعض التفاصيل الدقيقة فيما يتعلق بالمساحات المتجهية اللانهائية ، وما إلى ذلك ، وهذا يعني في الأساس أننا يجب أن نفكر في متجهات المتجهات كمتجهات كتلة. لذلك يجب "تسوية" Vector{Vector{T<:Number}} عقليًا إلى Vector{T} بسيط. ضمن هذا النموذج ، يجب أيضًا اعتبار العوامل الخطية التي يتم تمثيلها كمصفوفات من المصفوفات كمصفوفات كتلة ، ويجب بالتأكيد أن تكون adjoint عودية ، كما يجب أن تكون transpose إذا كنا نستخدم الكلمة في المعنى الرياضي . من فضلك صححني إذا كنت مخطئًا ، لكنني أعتقد أن الأشخاص الذين يتبنون وجهة النظر هذه يعتقدون أن شيئًا مثل Vector{Matrix{T}} ليس لديه تفسير طبيعي كافٍ يجب أن نصممه له. (على وجه الخصوص ، لا يجب أن نفترض ببساطة أن Matrix الداخلي هو تمثيل مصفوفة لعدد مركب ، لأنه كما قال stevengj ،

إذا كنت تمثل الأعداد المركبة بواسطة مصفوفات 2 × 2 ، فلديك مساحة متجهية معقدة مختلفة.

)

المدرسة الفكرية الأخرى هي أن Vector{T} يجب دائمًا التفكير فيه لتمثيل متجه في مساحة متجه مجردة فوق مقاييس (بمعنى الجبر الخطي للكلمة) من النوع T ، بغض النظر عن النوع T . في هذا النموذج ، يجب ألا يُنظر إلى Vector{Vector{T'}} كعنصر من مساحة المجموع المباشر ، ولكن بدلاً من ذلك كمتجه فوق الكميات Vector{T'} . في هذه الحالة ، لا يجب أن يكون transpose(Matrix{T}) تعاوديًا ، ولكن يجب ببساطة قلب المصفوفة الخارجية. تتمثل إحدى المشكلات في هذا التفسير في أنه لكي تشكل العناصر من النوع T حلقة صالحة من الحجميات ، يجب أن يكون هناك مفهوم محدد جيدًا للإضافة (التبادلية) والضرب. بالنسبة إلى متجه مثل Vector{Vector{T'}} ، سنحتاج إلى قاعدة لضرب اثنين من "الحجميات" Vector{T'} في Vector{T'} . في حين أنه يمكن للمرء بالتأكيد التوصل إلى مثل هذه القاعدة (على سبيل المثال ، الضرب الأولي ، الذي يقسم المشكلة إلى كيفية مضاعفة T' ) ، لا توجد طريقة طبيعية عالمية للقيام بذلك. هناك مشكلة أخرى تتعلق بكيفية عمل adjoint ظل هذا التفسير. لا يتم تحديد النقطة المساعدة Hermitian إلا على المشغلين الخطيين على مساحة هيلبرت ، والتي يجب أن يكون المجال القياسي بحكم التعريف إما الأرقام الحقيقية أو المركبة. لذلك إذا أردنا تطبيق adjoint على مصفوفة Matrix{T} ، يجب أن نفترض أن T يمثل بعض تمثيل الأعداد المركبة (أو الأرقام الحقيقية ، لكنني سألتزم فقط مع التعقيد لأن هذه الحالة أكثر دقة). في هذا التفسير ، لا يجب أن يكون adjoint تعاوديًا ولكن يجب أن يقلب المصفوفة الخارجية ثم يطبق conjugate . ولكن هناك المزيد من المشاكل هنا ، لأن الإجراء الصحيح لـ conjugate(T) يعتمد على طبيعة التمثيل. إذا كان التمثيل 2x2 موصوفًا في Wikipedia ، فيجب أن يقلب conjugate المصفوفة. ولكن لأسباب المذكورة أعلاه، conjugate بالتأكيد لا ينبغي دائما مصفوفات الوجه. لذا فإن هذا النهج سيكون قليل الفوضى عند تنفيذه.

ها هي أفكاري الخاصة: لا توجد إجابة "صحيحة موضوعياً" حول ما إذا كان يجب أن يكون transpose متكررًا عند تطبيقه على المصفوفات التي تحتوي عناصرها على بنية أساسية أكثر تعقيدًا. يعتمد ذلك على الطريقة التي يختارها المستخدم بالضبط لتمثيل البنية الجبرية المجردة في جوليا. ومع ذلك ، فإن دعم الحلقات الاعتباطية تمامًا من الحجميات يبدو أنه سيكون صعبًا للغاية ، لذلك أعتقد من أجل التطبيق العملي أننا لا يجب أن نحاول أن نكون بهذا الطموح ويجب أن ننسى الرياضيات الباطنية للوحدات على الحلقات غير القياسية. يجب أن يكون لدينا بالتأكيد دالة في Base (ببنية أبسط من permutedims(A, (2,1)) ) لا علاقة لها بمفهوم الجبر الخطي للتبديل وتقلب المصفوفات ببساطة ولا تفعل شيئًا تكراريًا ، بغض النظر عما إذا كانت يُسمى transpose أو flip أو ماذا. سيكون من الجيد أن يكون adjoint ووظيفة تبديل منفصلة (ربما باسم مختلف) في LinAlg متكررة ، لأنه بعد ذلك يمكنهم التعامل مع متجهات / مصفوفات الكتلة والتنفيذ البسيط للمجموع المباشر كناقلات للناقلات ، ولكن هذا ليس مطلوبًا من خلال "الصحة الرياضية الموضوعية" ، وسيكون من الجيد اتخاذ هذا القرار على أساس سهولة التنفيذ فقط.

على الرغم من وعدي السابق بعدم التعليق بعد الآن ، إلا أنه يتعين علي للأسف الرد على هذا التعليق.

يشير ملحق جوليا على وجه التحديد إلى مساعد هيرميت. بشكل عام ، بالنسبة لـ U و V مساحات متجهية معيارية كاملة (مساحات Banach) مع مسافات مزدوجة خاصة بها U * و V ، وللخريطة الخطية A: U -> V ، فإن النقطة المساعدة Hermitian لـ A ، التي يشار إليها عادةً A ، هي خريطة خطية أ *: V * -> U *. هذا يعني ، بشكل عام ، أن الضلع المجاور Hermitian عبارة عن خريطة خطية بين مسافات مزدوجة ، تمامًا كما هو الحال بشكل عام ، فإن تبديل A ^ t عبارة عن خريطة خطية بين مسافات مزدوجة كما هو مذكور أعلاه. إذن كيف يمكنك التوفيق بين هذه التعريفات والمفهوم المألوف للملحق Hermitian؟ :)

حقا هذا ليس صحيحا. ما تصفه هنا هو في الواقع تبديل ، ولكن (كما ذكرت سابقًا) ، يشار إلى هذا في بعض الحقول على أنه المساعد (بدون Hermitian) ويشار إليه على أنه A ^ t أو A ^ * (أبدًا A ^ dagger). في الواقع ، يمتد إلى ما هو أبعد من المسافات المتجهية ، وفي نظرية الفئة يوجد مثل هذا المفهوم في أي فئة أحادية (على سبيل المثال cateogory Cob من المشعبات الموجهة ذات البعد n مع cobordisms كخرائط خطية) ، حيث يشار إليها على أنها رفيقة مساعد (في حقيقة يمكن أن يكون هناك نوعان مختلفان A و A ، حيث أن المساحة المزدوجة اليسرى واليمنى ليست بالضرورة هي نفسها). لكن لاحظ أن هذا لا ينطوي أبدًا على اقتران معقد. عناصر V * هي بالفعل الخرائط الخطية f: V-> Scalar ، وبالنسبة للخريطة الخطية A: U-> V والمتجه v من U ، لدينا f (Av) = (A ^ tf) (v) . بما أن فعل f لا يتضمن اقترانًا معقدًا ، فلا تعريف لـ A ^ t.

تكمن الإجابة في البنية الإضافية التي تمتلكها المساحات التي تعمل فيها عادةً ، أي مساحات المنتج الداخلية الكاملة (مساحات هيلبرت). يحرض المنتج الداخلي على معيار ، لذا فإن مساحة المنتج الداخلية الكاملة (هيلبرت) هي مساحة معيارية كاملة (باناخ) ، وبالتالي تدعم مفهوم هيرميتان المساعد. إليكم المفتاح: وجود منتج داخلي بدلاً من مجرد قاعدة ، تنطبق واحدة من أجمل النظريات في الجبر الخطي ، وهي نظرية تمثيل Riesz. باختصار ، تنص نظرية تمثيل Riesz على أن فضاء هيلبرت متماثل بشكل طبيعي مع مساحته المزدوجة. وبالتالي ، عند العمل مع فضاءات هلبرت ، فإننا نحدد بشكل عام المساحات وثنائياتها ونسقط التمييز. إن تحديد هذا التعريف هو كيفية وصولك إلى المفهوم المألوف لـ Hermitian المساعد كـ A *: V -> U بدلاً من A *: V * -> U *.

مرة أخرى ، لا أعتقد أن هذا صحيح تمامًا. في فضاءات المنتج الداخلية ، المنتج الداخلي عبارة عن شكل خطي dot من اقتران (V) x V -> Scalar (مع (V) مساحة المتجه المقترنة). هذا يسمح بالفعل بإنشاء خريطة من V إلى V * (أو تقنيًا من con (V) إلى V *) ، والتي هي بالفعل نظرية تمثيل Riesz. ومع ذلك ، لسنا بحاجة إلى ذلك لتقديم المساعد Hermitian. حقًا ، المنتج الداخلي dot بحد ذاته كافٍ ، والنقطة المجاورة Hermitian للخريطة الخطية A هي تلك
dot(w, Av) = dot(A' w, v) . هذا ينطوي على الاقتران المعقد.

حقا هذا ليس صحيحا. ما تصفه هنا هو في الواقع تبديل ، ولكن (كما ذكرت سابقًا) ، يشار إلى هذا في بعض الحقول على أنه المساعد (بدون Hermitian) ويشار إليه على أنه A ^ t أو A ^ * (أبدًا A ^ dagger). [...]

Jutho ، يرجى الاطلاع ، على سبيل المثال ، على صفحة Wikipedia على Hermitian الملحق .

ربما هناك تناقضات بين مختلف مجالات الرياضيات ، ولكن:
https://en.wikipedia.org/wiki/Transpose_of_a_linear_map
وعلى وجه الخصوص
https://en.wikipedia.org/wiki/Transpose_of_a_linear_map#Relation_to_the_Hermitian_adjoint
والعديد من المراجع بشكل غير معدود في نظرية الفئات ، على سبيل المثال
https://arxiv.org/pdf/0908.3347v1.pdf

https://en.wikipedia.org/wiki/Transpose_of_a_linear_map
وعلى وجه الخصوص
https://en.wikipedia.org/wiki/Transpose_of_a_linear_map#Relation_to_the_Hermitian_adjoint

Jutho ، لا أرى أي تضارب بين قسم الصفحة هذا والتعريفات الواردة في الصفحة التي ربطتها أعلاه ، ولا أرى أي تعارض مع ما نشرته أعلاه. الأفضل!

سأقوم أيضًا بتسجيل الدخول إلى permutedims في الوقت الحالي أيضًا ؛ أعتقد أن هذا أفضل من flip .

@ Sacha0 ، إذن لدينا طريقة مختلفة لتفسير ذلك. قرأت هذا ك
بالنسبة إلى A معطى: U-> V ،
تبديل (A) = مزدوج (A) = (أحيانًا أيضًا) معاور (A): V * -> U *
المساعد المحكم (A) = خنجر (A) = (عادةً فقط) المجاور (A): V-> U
والعلاقة بين الاثنين يتم الحصول عليها بالضبط باستخدام الخريطة من الفضاء إلى الفضاء المزدوج (مثل Riesz ...) ، والتي تتضمن اقترانًا معقدًا. ومن ثم ، فإن المساعد المحكم يتضمن الاقتران ، ولا ينطبق التحويل.

إذا كنت تريد أيضًا استدعاء أول محكم مساعد ، فماذا تسميه تبديل؟ أنت لم تحدد حقًا ما كان ذلك في وصفك ، لقد ذكرت للتو

الضلع المجاور Hermitian لـ A ، عادةً ما يُشار إليه A ، هو خريطة خطية A : V * -> U *. وهذا يعني ، بشكل عام ، أن الضلع المجاور Hermitian هو خريطة خطية بين مسافات مزدوجة ، تمامًا كما هو الحال بشكل عام ، فإن تبديل A ^ t عبارة عن خريطة خطية بين مسافات مزدوجة

إذاً ، هل يُقارن Transpos و Hermitian بطريقتين مختلفتين لتحويل A: U-> V إلى خريطة من V -> U ؟ سأكون سعيدًا حقًا لمناقشة المزيد حول هذا الأمر ، لكن أعتقد أنه من الأفضل القيام بذلك في مكان آخر. لكن في الحقيقة ، اتصل بي لأنني مهتم حقًا بمعرفة المزيد عن هذا الأمر.

انظر أيضًا http://staff.um.edu.mt/jmus1/banach.pdf للحصول على مرجع يشير إلى أن المراجع كما هو مستخدم في سياق مساحات Banach هو عبارة عن تبديل وليس مساعد Hermitian (على وجه الخصوص هو خطي وليس معاكس للخط تحويل). تقوم ويكيبيديا (ومراجع أخرى) بخلط هذين المفهومين حقًا ، وذلك باستخدام فكرة المساعد الهرميت في فضاءات هلبرت كدافع لتعريف معمم للمساعد في فضاءات باناخ. ومع ذلك ، فإن هذا الأخير هو في الواقع تبديل (ولا يحتاج إلى منتج داخلي ، ولا معيار). ولكن هذا هو التحويل الذي كنت أتحدث عنه ، والذي لا يستخدمه أحد بالفعل في كود الكمبيوتر.

بالنسبة لجوليا بيس: أنا لا أعارض الاقتران الهرمي العودي ؛ أوافق على أنه غالبًا ما يكون الشيء الصحيح الذي يجب القيام به. لست متأكدًا من أن Base يجب أن يحاول القيام بأشياء ذكية عندما لا يكون نوع العنصر Number . حتى مع T هو رقم ، لا يوجد دعم في Base للاستخدام الأكثر شيوعًا للمنتجات الداخلية غير الإقليدية (والتعريفات المعدلة المرتبطة بها) ، ولا أعتقد أنه يجب أن يكون هناك. لذلك أعتقد أن الدافع الرئيسي كان مصفوفات الكتلة ، ولكن هناك أعتقد أن نوع الغرض الخاص (في الأساس أو في حزمة) هو أكثر من جوليان ، وكما ذكر andyferris أيضًا ، فهو ليس مثل بقية LinAlg يدعم inv (ناهيك عن تحليل عوامل المصفوفة ، إلخ).

ولكن إذا كان الاقتران الهرمي العودي موجودًا ليبقى (جيد من قبلي) ، فأنا أعتقد أنه من أجل الاتساق dot و vecdot يجب أن يعمل بشكل متكرر على العناصر. في الوقت الحالي ، ليس هذا هو الحال: dot يستدعي x'y على العناصر (وهو ليس نفسه عندما تكون العناصر مصفوفات) و vecdot يستدعي dot على العناصر. لذلك بالنسبة لمتجه المصفوفات ، لا توجد طريقة للحصول على نتيجة عددية. سأكون سعيدًا بإعداد العلاقات العامة إذا اتفق الناس على أن التنفيذ الحالي لا يتعارض حقًا مع التكرار adjoint .

بالنسبة إلى transpose ، يبدو من الأسهل جعلها غير متكررة وكذلك السماح باستخدامها من قبل أولئك الذين لا يعملون مع البيانات الرقمية. أعتقد أن معظم الأشخاص الذين يعملون مع المصفوفات يعرفون المصطلح transpose وسيبحثون عنه. لا يزال هناك conj(adjoint()) لأولئك الذين يحتاجون إلى عودية transpose .

يعتقد الفرز أن @ Sacha0 يجب أن يمضي قدمًا في الاقتراح 2 حتى نتمكن من تجربته.

أتفق بشدة مع ttparker على أن

1 - إلى LinAlg ، AbstractVector v هو متجه الأبعاد length(v) مع أوزان أساس (عددي) v[1] ، v[2] ، ... ، v[length(v)] .

(وبالمثل مقابل AbstractMatrix ).

من المحتمل أن يكون هذا هو الافتراض الذي قد يفترضه العديد من الأشخاص من مكتبات أخرى ، وأن وجود مثل هذا التعريف البسيط لمتجهات الأساس ، والرتبة ، وما إلى ذلك ، يساعد في الحفاظ على بساطة التنفيذ. (قد يقول الكثيرون أن الجبر الخطي العددي ممكن التنفيذ على جهاز كمبيوتر على وجه التحديد لأن لدينا أساسًا جيدًا تم إعداده للعمل فيه.)

نهجنا الحالي يشبه إلى حد كبير:

2 - إلى LinAlg ، فإن AbstractVector v هو مجموع مباشر لمتجهات مجردة length(v) . نقوم أيضًا بتضمين تعريفات كافية للأنواع العددية مثل Number بحيث تكون عوامل تشغيل / متجهات خطية صالحة أحادية البعد حتى LinAlg .

وبالمثل للمصفوفات (الكتلة). هذا أكثر عمومية من تطبيقات الجبر الخطي في MATLAB و numpy و eigen وما إلى ذلك ، وهو انعكاس لنظام جوليا للنوع / الإرسال القوي حتى أن هذا ممكن.

السبب الشامل الذي أرى أن الخيار 2 مرغوب فيه هو مرة أخرى أن نظام جوليا من النوع / الإرسال يسمح لنا بالحصول على هدف أوسع بكثير ، والذي يشبه بشكل غامض:

3 - في LinAlg ، نحاول إنشاء واجهة جبر خطي عامة تعمل مع الكائنات التي ترضي الخطية (إلخ) تحت + ، * ، conj (إلخ) ، التعامل مع مثل هذه الأشياء مثل المشغلين الخطيين / أعضاء فضاء هلبرت / أيًا كان ما هو مناسب.

وهو هدف رائع حقًا (بالتأكيد يتجاوز كثيرًا أي لغة / مكتبة برمجة أخرى أعلمها) ، يحفز تمامًا التكرار adjoint و 2 (لأن + ، * و conj هي في حد ذاتها عودي) وهذا هو السبب @ Sacha0 الصورة اقتراح 2 وقرار الفرز هو خيار جيد :)

سأكون سعيدًا حقًا لمناقشة المزيد حول هذا الأمر ، لكن أعتقد أنه من الأفضل القيام بذلك في مكان آخر. لكن في الحقيقة ، اتصل بي لأنني مهتم حقًا بمعرفة المزيد عن هذا الأمر.

في صحتك ، لنفعل! أتطلع إلى مزيد من الدردشة دون اتصال :). الأفضل!

ملخص لطيف آندي! :)

موافق تمامًا على Andy ، على الأقل مقابل adjoint (والذي كان موضوع تعليقك).

ومع ذلك ، هناك نداء أخير للحصول على transpose غير متكرر ، قبل أن أحافظ على سلامتي إلى الأبد (على أمل).
أرى أن التحويل غير العودي له المزايا التالية:

  • يمكن استخدامه من قبل جميع الأشخاص الذين يعملون مع المصفوفات ، حتى إذا كانت تحتوي على بيانات غير رقمية. هذه أيضًا هي الطريقة التي سيعرفون بها على الأرجح هذه العملية ويبحثون عنها ، من اللغات الأخرى ومن الرياضيات الأساسية المستقرأة إلى حالة الاستخدام غير الرقمية الخاصة بهم
  • لا حاجة لكتابة رمز إضافي حتى يتفاعل النوع flip البطيء أو PermutedDimsArray مع LinAlg . ماذا لو كان لدي مصفوفة عددية قلبتها بدلاً من تبديلها ؛ هل سأظل قادرًا على ضربها بمصفوفات أخرى (يفضل استخدام BLAS)؟

  • مع transpose غير متكرر و adjoint متكرر ، يمكننا بسهولة الحصول على ملحق غير متكرر مثل conj(transpose(a)) و تحويل عودي conj(adjoint(a)) . وسيظل كل شيء يتفاعل بشكل جيد مع LinAlg .

إذن ما هي العيوب. لا أرى أحدا. ما زلت متمسكًا بوجهة نظري التي مفادها أن لا أحد يستخدم transpose بالمعنى الرياضي. ولكن بدلاً من محاولة المزيد من الجدل ، هل يمكن لأي شخص أن يعطيني مثالًا ملموسًا حيث يلزم أو يكون التحويل العودي مفيدًا ، وأين يكون حقًا tanspose رياضيًا؟ يستثني هذا أي مثال كنت تنوي فيه بالفعل استخدام adjoint لكنك تمتلك فقط أرقامًا حقيقية. إذن تطبيق حيث يوجد سبب رياضي لنقل متجه أو مصفوفة مليئة بمصفوفات أكثر هي نفسها ذات قيمة معقدة.

أستطيع أن أقول إن ماثيماتيكا على الأقل (التي يتوقع المرء أن يكرسها قدرًا كبيرًا من التفكير لهذا الأمر) لا تفعل التحويل العودي:

A = Array[1 &, {2, 3, 4, 5}];
Dimensions[A]  # returns {2, 3, 4, 5}
Dimensions[Transpose[A]] # returns {3, 2, 4, 5}

تحرير: عفوًا ، تم التعليق على هذا أيضًا أعلاه ، آسف

لذلك أنا في حيرة من أمري. يبدو أن هناك إجماعًا قويًا على أن transpose يجب أن يكون غير متكرر - على سبيل المثال https://github.com/JuliaLang/julia/issues/20978#issuecomment -285865225 ، https://github.com/ JuliaLang / julia / issue / 20978 # issuecomment -285942526 ، https://github.com/JuliaLang/julia/issues/20978#issuecomment -285993057 ، https://github.com/JuliaLang/julia/issues/20978#issuecomment - 348464449 و https://github.com/JuliaLang/julia/pull/23424. ثم قدم @ Sacha0 اقتراحين ، أحدهما سيترك التحويل متكررًا ولكنه يقدم دالة flip غير متكررة ، والتي حصلت على دعم قوي على الرغم من (بقدر ما أستطيع أن أقول) لم يتم طرحها بالفعل كاحتمال من قبل . ثم اقترح JeffBezanson أننا لسنا بحاجة إلى flip بعد كل شيء إذا قدمنا permutedims وسيطة ثانية افتراضية ، والتي حصلت أيضًا على دعم قوي.

لذا يبدو أن الإجماع الآن هو أن التغييرات الحقيقية الوحيدة إلى transpose يجب أن تكون "خلف الكواليس": فيما يتعلق بالتخفيض الخاص والتقييم البطيء مقابل التقييم المتلهف ، والذي ربما لن يعرفه المستخدم النهائي العادي أو يهتم به . التغييرات الوحيدة المرئية حقًا هي في الأساس مجرد تغييرات إملائية (إهلاك .' وإعطاء permutedims وسيطة ثانية افتراضية).

لذلك يبدو أن إجماع المجتمع قد تغير تقريبًا 180 درجة في وقت قصير جدًا (في وقت قريب من مشاركة @ Sacha0 https://github.com/JuliaLang/julia/issues/20978#issuecomment-347360279). هل كانت مشاركة ساشا بليغة لدرجة أنها غيرت رأي الجميع؟ (لا بأس إذا كان الأمر كذلك ، فأنا أريد فقط أن أفهم لماذا يبدو أننا نمضي قدمًا على طريق كان يبدو أننا جميعًا قبل أيام قليلة متفقون على أنه المسار الخطأ).

نسيت ما إذا كان أي شخص قد اقترح هذا ، ولكن هل يمكننا جعل transpose(::AbstractMatrix{AbstractMatrix}) (وربما transpose(::AbstractMatrix{AbstractVector}) أيضًا) متكررًا و transpose غير متكرر بخلاف ذلك؟ يبدو أن هذا سيغطي جميع القواعد ولا يمكنني التفكير في أي حالة استخدام أخرى حيث تريد أن يكون tranpose متكررًا.

لذا يبدو أن إجماع المجتمع قد تغير تقريبًا 180 درجة في وقت قصير جدًا (في وقت قريب من مشاركة @ Sacha0 # 20978 (تعليق)). هل كانت مشاركة ساشا بليغة لدرجة أنها غيرت رأي الجميع؟ (لا بأس إذا كان الأمر كذلك ، فأنا أريد فقط أن أفهم لماذا يبدو أننا نمضي قدمًا على طريق كان يبدو أننا جميعًا قبل أيام قليلة متفقون على أنه المسار الخطأ).

لو كنت فقط بليغة جدا 😄. ما تراه هو أن الإجماع لم يتشكل بالفعل. بدلاً من ذلك ، (1) عاد المشاركون الذين يفضلون الوضع الراهن ، ولكنهم انسحبوا من المناقشة بسبب التناقص ، للتعبير عن رأيهم ؛ و (2) الأطراف الأخرى التي لم تأخذ بعين الاعتبار ما قد يترتب على الابتعاد عن الوضع الراهن في الممارسة العملية (وكيف يمكن أن يلعب ذلك مع اعتبارات الإفراج) شكلت رأيًا أقوى لصالح الوضع الراهن وأعربت عن هذا الرأي.

يرجى النظر أن هذه المناقشة ما زالت مستمرة في شكل واحد أو آخر على جيثب منذ عام 2014، وعلى الأرجح في وقت سابق حاليا. بالنسبة للمشاركين على المدى الطويل ، تصبح هذه المناقشات مرهقة ودورية. هناك عمل هادف للقيام به بخلاف المشاركة في هذه المناقشة - مثل كتابة التعليمات البرمجية ، وهو أكثر متعة - والنتيجة هي الاستنزاف بين هؤلاء المشاركين على المدى الطويل وبالتالي ، تبدو المحادثة غير متوازنة خلال فترة أو أخرى. أنا شخصياً على وشك الوصول إلى عتبة الاستنزاف ، لذلك سأركز على كتابة الكود الآن بدلاً من مواصلة المشاركة في هذه المناقشة. شكرا لكم جميعا وأفضل! :)

سأدلي بصوت صغير لصالح تبديل غير متكرر و ctranspose لـ AbstractArrays ، حيث يكون كلاهما متكررًا في AbstractArray {T} حيث T <: AbstractArray.

أوافق على أن السلوك العودي "صحيح" في بعض الحالات ، وأرى أن السؤال هو كيف نحقق السلوك الصحيح بأقل قدر من المفاجأة لأولئك الذين يستخدمون الحزم ويطورونها.
في هذا الاقتراح ، يتم الاشتراك في سلوك التحويل العودي للأنواع المخصصة: يمكنك الاشتراك عن طريق جعل الكتابة على AbstractArray أو عن طريق تحديد الطريقة المناسبة
Base.transpose(AbstractArray{MyType}) أو Base.transpose(AbstractArray{T}) where T<: MyAbstractType .
أعتقد أن إستراتيجية كتابة البطة لعمليات النقل العودية (التكرار دون طلب) تنتج بعض المفاجآت كما هو موثق أعلاه. إذا قمت بتقديم عروض مختلفة ctranspose و advoint ، أو مقترحات أكثر تعقيدًا مثل اقتران ووجه ، سيواجه المستخدمون هذه المقترحات ويحاولون استخدامها ، وسيحاول مشرفو الحزم دعمهم جميعًا.

كمثال على شيء يصعب دعمه في إطار المقترحات الجديدة: المصفوفات العادية ، والتبديل ، والمصفوفة ، والجمع ، يجب أن تكون جميعها قادرة على الحصول على وجهات نظر (أو تقييم كسول) تتداخل مع طرق عرض ReshapedArray و SubArray. (لا أعلم ما إذا كانت هذه العروض تنتج بشكل افتراضي أو فقط عند استخدام @view .) هذا يتصل بالعمل على تخفيض A*_mul_B* وفي مكالمات BLAS ذات المستوى الأدنى مع العلامات 'N' ، "T" و "C" للمصفوفات الكثيفة ، كما لوحظ في مكان آخر. سيكون من الأسهل تفسير هذه الأمور إذا تعاملوا مع normal ، transpose ، ctranspose ، و conj
على قدم المساواة. لاحظ أن BLAS نفسه يدعم فقط "N" للعادي ، و "T" للتبديل ، و "C" لـ ctranspose وليس له إشارة للترافق ، وهو ما أعتقد أنه خطأ.

أخيرًا ، من أجل التناسق مع المصفوفات وإعادة التشكيل ذات الأبعاد الأعلى ، أعتقد أن التعميم المناسب للتبديل والتحويل هو عكس جميع الأبعاد ، أي
تبديل (A :: Array {T، 3}) = permutedims (A، (3، 2، 1)).

في صحتك!

أنا أقدر كثيرا الأشخاص الذين يقومون بهذا العمل. ما تمت مناقشته كثيرًا جدًا هو العناصر المساعدة / التحويل المتجه (ولكن لم يكن الجانب التكراري منه أبدًا) ، حتى قام andyferris بتنفيذ هذا الأمر ، وهو يعمل بشكل رائع. وبالمثل ، فإنني أقدر بشدة إعادة التصميم المستمرة لمنشئي المصفوفات. ممتاز لكل ذلك.

ومع ذلك ، فإن تبديل المصفوفة والمعايرة / التحويل لم يحظ بالكثير من النقاش ، لا سيما الجانب التكراري منه ، والذي تم تقديمه بصمت تقريبًا في https://github.com/JuliaLang/julia/pull/7244 كمصفوفات كتلة دافعة واحدة . تم تقديم أسباب ودوافع مختلفة للمعايرة العودية (بعد الحقائق) ، ويمكن لمعظم الناس الاتفاق على أن هذا الخيار جيد (ولكن ليس الخيار الوحيد). ومع ذلك ، يفتقر التحويل إلى دافع واحد أو حالة استخدام فعلية.

هناك بعض الأشياء المنفصلة التي تحدث في هذه المناقشات ، ويحدث الآن أننا بحاجة إلى خطة يمكن تنفيذها بسرعة.

  • لقد ناقشنا ما إذا كان دعم مصفوفات الكتلة (والمزيد من الهياكل الغريبة) مفيدًا في LinAlg . خيارات التنفيذ هي: لا توجد عناصر متكررة على الإطلاق (باستثناء + ، * و conj لأن هذه هي طبيعة الدوال العامة في Julia) ، كل شيء متكرر (الوضع الراهن) ، أو محاولة نوع من التحقق من النوع أو السمة لمعرفة ما إذا كان العنصر يجب أن يقوم بالجبر الخطي العودي أو معاملته على أنه عدد.
  • نريد طريقة لطيفة للمستخدمين لتبديل أبعاد مجموعة ثنائية الأبعاد من البيانات. لقد حصلنا على transpose ، flip ، اختصار permutedims (تم إرسال PR هذا أولاً لأنه أقل عدد من الأحرف التي يجب تنفيذها ، وربما يكون منطقيًا حتى إذا فعلنا شيئًا آخر أيضًا) ، نوعًا من فحص النوع أو السمة لمعرفة ما إذا كان يجب على العنصر إجراء تبديل متكرر (ربما حتى إعادة تقديم transpose(x::Any) = x ...).
  • محلل جوليا لديه سلوك غريب مثل x' * y -> Ac_mul_B(x, y) وهو نوع من الثؤلول ، والذي لن يكون موجودًا بشكل مثالي في الإصدار 1.0. لم يُنظر إلى هذا على أنه ممكن حتى نتمكن من دعم BLAS السريع (بدون نسخ إضافية) بدونه ، وبالتالي نقل المصفوفة الكسولة والمعايرة.
  • الكود الموجود في LinAlg كبير جدًا وقد تم إنشاؤه على مدار عدد من السنوات. يمكن إعادة هيكلة العديد من الأشياء مثل مضاعفة المصفوفة لتكون أكثر ملاءمة للسمات ، ربما باستخدام نظام إرسال أشبه بـ broadcast . أعتقد أن هذا هو المكان الذي يمكننا من خلاله تسهيل إرسال المصفوفات الصحيحة (أفكر في PermuteDimsArray من وجهات نظر مترافقة معاد تشكيلها للمصفوفات المتتالية) إلى BLAS. ومع ذلك ، فإن هذا لن يجعل الإصدار 1.0 ونحاول أيضًا تجنب تراجع الأداء دون جعل الكود أسوأ بكثير. كما أشار ساشا (وأنا أكتشف) أن وجود تغيير في وجهات النظر مع مجموعة واسعة من السلوكيات على العناصر (التكرار المتكرر ، التحويل العودي ، الاقتران ، لا شيء) يؤدي إلى تعقيد إضافي ومجموعة من الأساليب الجديدة لإبقاء الأشياء تعمل كما هي هي.

إذا فكرنا في الإصدار 1.0 على أنه يعمل على استقرار اللغة إلى حد ما ، ففي بعض النواحي ، تكون الأولوية الأكبر لإجراء تغيير في السلوك هي الأولوية الثالثة. أود أن أقول: يجب أن تكون اللغة (بما في ذلك المحلل اللغوي) أكثر استقرارًا ، متبوعة بـ Base ، متبوعًا بـ stdlib (والذي قد يتضمن أو لا يتضمن LinAlg ، لكنني أعتقد أنه من المؤكد تقريبًا أنه سيتضمن BLAS ، Sparse ، إلخ يومًا ما). إنه تغيير لا يؤثر حقًا على المستخدمين (معظمهم من مطوري المكتبات) ، لذلك لن أتفاجأ إذا اختلفت آراء الناس هنا.

بقعة على أندي! :)

أعتقد أن الشيء الوحيد المتبقي هنا هو جعل adjoint و transpose كسولًا بشكل افتراضي؟

هل يمكن إغلاق هذا الآن؟

المتابعة التالية: "التعامل بجدية مع التحويلات القياسية"

ولكن بجدية ، هل يمكننا الحصول على واجهة جيدة لتحديد عمليات النقل ثلاثية الأبعاد المختلفة ومضاعفات الموتر التي تُستخدم في أدوات حل PDE؟ نوع من الجدية ، لكنني لست متأكدًا مما إذا كان بإمكاني التعامل مع كوني OP للتكرار التالي لهذا الجنون.

لا

:)

هل يمكننا الحصول على واجهة جيدة لتحديد عمليات النقل ثلاثية الأبعاد المختلفة ومضاعفات الموتر المستخدمة في أدوات حل PDE

بالتأكيد يبدو وكأنه موضوع جيد لحزمة.

واجهة جيدة لتحديد مختلف عمليات النقل ثلاثية الأبعاد ومضاعفات الموتر

هل TensorOperations.jl لا تفعل ما تحتاجه هنا؟ (لاحظ أنه في هذا المستوى تعني "الواجهة الجيدة" شيئًا مثل مخطط شبكة موتر ، والذي يعد أمرًا صعبًا بعض الشيء للكتابة في التعليمات البرمجية بشكل أكثر إيجازًا من بناء جملة عمليات Tensor ).

نعم ، يبدو TensorOperations.jl جيدًا. كنت أمزح قليلاً ، لكني حصلت على ما احتاجه منها 👍.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات