Julia: تستنكر "تلك"؟

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

الآن بعد أن تميزنا بين one و oneunit و ones(T, sz) يبدو أنه تسمية خاطئة. الاستنكار لصالح fill(oneunit(T), sz) ؟ إذا كان الأمر كذلك ، فهل يجب أن نتخلى عن zeros أيضًا؟

decision linear algebra stdlib

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

بالنسبة لي ، يبدو أن fill(oneunit(T), sz) خسارة غير بسيطة في قابلية القراءة مقارنة بـ ones(T, sz) .

ال 46 كومينتر

xref https://github.com/JuliaLang/julia/issues/11557#issuecomment -339776065 وأقل ، وأيضًا @ Sacha0 's PR # 24389

لدي عمل جارٍ لهذا الغرض وآمل أن أنشره في اليوم أو اليومين التاليين :). أفضل!

بالنسبة لي ، يبدو أن fill(oneunit(T), sz) خسارة غير بسيطة في قابلية القراءة مقارنة بـ ones(T, sz) .

لاحظ أنك نادرًا ما تحتاج إلى كتابة شيء مطول مثل fill(oneunit(T), sz) ، فعادة ما تكفي كلمة حرفية أو شيء مضغوط مشابه بدلاً من oneunit(T) . قد تصبح التعويذات الأقصر ممكنة أيضًا مع التغييرات المستقبلية لمنشئات المصفوفات. بالإضافة إلى ذلك ، بمجرد أن تنتقل إلى fill ، فأنت مغرم بذلك وأنا أؤكد لك :). أفضل!

يمكننا فقط اختيار ما إذا كان ones يستخدم one أو oneunit . يجب اعتبار ones و zeros من الوظائف الملائمة ، وهو أمر جيد طالما أن لديهم معاني واضحة من حيث الوظائف العامة.

خطة لكل فرز: قم بإعادة الزيارة الأسبوع المقبل ، على وجه التحديد التفكير في نقل ones و zeros إلى طبقة التوافق MATLAB ، لصالح fill في الأساس. أفضل!

ones و oneunits الخيارين.

لست متأكدًا من شعوري حيال نقل هذا و zeros لتوافق MATLAB. فقط لأن Mathworks اخترعت هذا لا يعني أنها ليست واجهة برمجة تطبيقات ملائمة جيدة يمكننا أن نفخر بها. فقط بإيجاز - ما هي الأسباب الكامنة وراء هذا الفكر؟ (آسف ، يجب أن أقول إن الفرز يبدو أكثر فاعلية ، لكنه أقل شفافية بشكل ملحوظ عندما لا يتم إعطاء المنطق).

إنه ليس تغييرًا أنا سعيد به أيضًا ، لكنني أثرته لأنه تناقض منطقي. أعتقد أنه من العدل أن نقول إن ones(T, sz) يعني fill(one(T), sz) لكن ما يفعله حقًا تحت الغطاء هو fill(oneunit(T), sz) .

قد يكون أحد الخيارات هو إعادة تسميته إلى oneunits . قد يكون البديل هو إجراء مقايضة مروعة: one -> algebraic_one و oneunit -> one . هذا كسر ولا يمكن القيام به عن طريق الإهمال ، ولهذا السبب أقول "مرعب".

نعم ، أود أن أقول إن إضافة oneunits وتغيير ones لإعطاء fill(one(T), ...) سيكون الحل الواضح لذلك ، أليس كذلك؟

سأكون بخير مع ذلك. بدافع الفضول ، ما هي استخدامات fill(one(T), sz) ؟ هل نحتاج حتى إلى ones على الإطلاق؟

Haha :) كنت سأطرح السؤال - لماذا تستخدم fill(oneunits(T), sz) أجل؟ (على سبيل المثال ، ما الذي يمكن استخدام المصفوفة المملوءة بـ 1 متر ، أو 1 كيلوغرام ، أو ثانية واحدة؟)

أعتقد أن fill(one(T), sz) يُستخدم لنفس السبب إلى حد كبير مثل zeros(T, sz) ، وهو تهيئة مصفوفة لعملية نوع تقليل مخصصة. المصفوفة z = zeros(T, sz) جاهزة لإضافة عناصرها إلى z[i] += x بينما o = fill(one(T), sz) جاهزة لتضاعف عناصرها o[i] *= x . على سبيل المثال ، أفكر في المواقف التي قد تمثل فيها عناصر المصفوفة الاحتمال (النسبي). في هاتين الحالتين ، أبحث عن هوية عامل التشغيل + أو * على التوالي (وليس المولدات الإضافية).

راجع أيضًا # 23544

Haha :) كنت سأطرح السؤال - ما الذي تستخدمه لملء (وحدة واحدة (T) ، sz)؟ (على سبيل المثال ، ما الذي يمكن استخدام المصفوفة المملوءة بـ 1 متر ، أو 1 كيلوغرام ، أو ثانية واحدة؟)

المتغيرات التابعة لـ ODE. سيكون من الغريب أن يتم تقطيع الوحدات بشكل عشوائي عندما طلبت مصفوفة من النوع T ؟

السبب الأساسي لتفضيل fill هو أن مجموعة ضيقة من الأدوات القوية والمتعامدة والقابلة للتركيب تقدم أفضل من مجموعة أكبر من الأدوات المخصصة والمحدودة والمتداخلة مثل ones / zeros / trues / falses . توضح المناقشة أعلاه هذه النقطة: بينما يستوعب fill جميع حالات الاستخدام المذكورة أعلاه بشكل لا لبس فيه و (في معظم الاستخدامات الحقيقية) بإيجاز ، ones / zeros / trues يتطلب أسلوب / falses وظيفة جديدة لكل حالة استخدام.

بعض الأمثلة ذات الصلة من إعادة الكتابة في القاعدة:

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

يصبح

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

و

2ones(Int, 2, 2, 2)

يصبح

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

يرجى ملاحظة أن هذه التعويذات fill أبسط ، وأكثر قابلية للقراءة ، وأكثر إحكاما ، وأكثر كفاءة من نظرائهم غير fill ، و base/ و test/ هي تعج بأمثلة مثل هذه. كما هو الحال مع كل التغييرات ، يتطلب الانتقال إلى fill بعض التعديل العقلي الأولي. لكن بعد التعديل تجد أن لديك المزيد من القوة والأناقة في متناول يدك :). أفضل!

@ Sacha0 : trues / falses غير قابلة للاستبدال مباشرة بـ fill ، لكن تحتاج إلى استخدام fill! مع مُهيئ BitArray . كما أنها ليست مدرجة في الغموض بين one و oneunit . لذلك لا أعتقد أنهم مناسبون لهذه المناقشة على الإطلاق.

بالنسبة إلى ones ، فأنا أعارض عمومًا إهماله على أي حال ، ولا أرى فائدة. الحجة القائلة بأن بعض التعبيرات يمكن كتابتها بشكل أكثر فاعلية باستخدام fill ليست مقنعة جدًا في رأيي ، حيث تستخدم كل هذه الأمثلة ones كخطوات وسيطة للقيام بشيء آخر ؛ ولكن ماذا عن عندما تريد بالفعل مجموعة من تلك؟ ثم الاضطرار إلى استخدام fill يعد أطول وأقل وضوحًا وأكثر إزعاجًا. أفضل اقتراح JeffBezanson . إذا كان من الممكن إعادة كتابة أجزاء من base أو test بشكل أكثر فاعلية باستخدام fill بدلاً من ones فلا يوجد ما يمنع ذلك الآن.

carlobaldassi بينما هذا صحيح ، يكشف بحث سريع على GitHub أن جميع استخدامات ones يجب أن تستخدم fill لتجنب التخصيصات المتوسطة ...

استخدام fill لهذه الحالات أمر منطقي بالنسبة لي. لاحظ أننا نريد طريقة fill(x, A) = fill!(x, copymutable(A)) جديدة لتحل محل الطرق المقابلة لـ ones وما إلى ذلك.

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

(لدي أيضًا تحفظات بالفعل حول وسيطة القراءة ، أعتقد أنه من المشكوك فيه الادعاء بأن مثل fill(2, 2, 2, 2) أكثر قابلية للقراءة من 2 * ones(Int, 2, 2, 2) ، أو على سبيل المثال ، fill(k * 1.0, 3) سيكون أكثر يمكن قراءتها أكثر من k * ones(3) ؛ لست مقتنعًا على الإطلاق بأنها مجرد مسألة عادة. هذه نقطة ثانوية.)

لا يمكن استبدال trues / falses مباشرة بالتعبئة ، ولكن يجب استخدام التعبئة! باستخدام مُهيئ BitArray. كما أنها ليست مدرجة في الغموض بين وحدة واحدة. لذلك لا أعتقد أنهم مناسبون لهذه المناقشة على الإطلاق.

في الواقع ، لا يمكن استبدال trues و falses مباشرة بـ fill :). بدلاً من ذلك ، فإن trues و falses هي أمثلة إضافية للمشكلة العامة الموضحة أعلاه / المرتبطة بـ # 11557 (والتي نأمل أن يعالجها الاتجاه الأخير لمنشئي المصفوفات). تتضمن الأمثلة الأخرى وجود مثل bones و bzeros و brand و brandn و beye في BandedMatrices.jl وما يماثلها مع البادئة d في DistributedArrays.jl.

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

بعد إعادة كتابة بضع مئات من استخدامات ones في الأساس ، يمكنني تأكيد تصريحTotalVerb

يكشف البحث السريع على GitHub أن جميع استخدامات تلك التطبيقات يجب أن تستخدم التعبئة لتجنب التخصيصات المتوسطة ...

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

ولكن ماذا عن عندما تريد بالفعل مجموعة من تلك؟ ثم الاضطرار إلى استخدام التعبئة يكون أطول وأقل وضوحًا وأكثر إزعاجًا.

... هذا من ناحية أخرى ، fill غالبًا أقصر وأبسط في هذه الحالة: كثيرًا ما لا تكون الطلبات المطلوبة Float64 (بدلاً من ذلك ، على سبيل المثال ones(Int, n...) و ones(Complex{Float64}, n...) ) ، وفي هذه الحالة يكون fill أقصر وأبسط من خلال قبول حرف (على سبيل المثال fill(1, n...) و fill(1.0 + 0im, n...) ). بعبارات قابلة للقياس ، الفرع الذي أعيد كتابة ones للمكالمات في الأساس هو حوالي 5٪ أقصر بعدد الأحرف من ones -> fill يعيد كتابته. أفضل!

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

تضمن التحليل 156 ones للمكالمات. من تلك المكالمات ،

  • 84 مكالمة (~ 54٪) كانت مخصصة fill s. (على سبيل المثال ، يتم تبسيط ones(100)/sqrt(100)*7 إلى fill(7/sqrt(100), 100) أو ، الأفضل من ذلك ، fill(.7, 100) . كان المفضل لدي هو kron(0.997, ones(1, J*J*s) -> fill(0.997, 1, J*J*s) .)

  • 3 مكالمات (حوالي 2٪) كانت عمليات بث مخصصة. (على سبيل المثال ، يتم تبسيط A - ones(n,n) إلى A .- 1. .)

  • 5 مكالمات (حوالي 3٪) كانت عبارة عن ناقلات حرفية مخصصة. (على سبيل المثال ، يتم تبسيط ones(1) إلى [1.] .)

  • كانت المكالمة الأولى (حوالي 0.5٪) عبارة عن بناء مصفوفة غير مهمة بشكل جوهري. (على الرغم من أنه غير شائع نسبيًا في البرية ، إلا أن هذا النمط شائع جدًا في test/ لأننا لا نملك مُنشئ ملائم موجزًا ​​لـ Array s غير المهيأة ، كما في على سبيل المثال <strong i="32">@test_throws</strong> DimensionMismatch BLAS.trsv(...,Vector{elty}(n+1)) مقابل <strong i="34">@test_throws</strong> DimensionMismatch BLAS.trsv(...,ones(elty,n+1)) .)

كانت المكالمات المتبقية معقولة لغويًا مثل ones ، على الرغم من أنه غالبًا ما يرى ones استخدامه لمجرد أنه قصير ، بدلاً من أن one s ضروري على وجه التحديد. من تلك المكالمات المتبقية ،

  • 13 مكالمة (~ 8٪) كانت أقصر قليلاً مثل fill . (على سبيل المثال ، ones(Int, n, n) -> fill(1, n, n) أو ones(Float64, n) -> fill(1., n) .)

  • 50 مكالمة (~ 32٪) كانت أطول قليلاً مثل fill . (على سبيل المثال ، ones(n, n) -> fill(1., n, n) .)

بشكل عام ، في الحياة البرية ، يتم كتابة 60٪ من ones المكالمات بشكل أفضل بطريقة أخرى ، حوالي 8٪ تكون ذات مغزى معقول ones وأقصر قليلاً مثل fill ، و ~ 32٪ هي من المعقول المعقول ones وأطول قليلاً مثل fill .

ملاحظة إضافية:

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

مناقشة ممتعة حقًا ... انتقلت من كونها في الجانب المقابل إلى الجانب المؤيد ... أيضًا كسابقة لغة أخرى ، يستخدم R rep و matrix بطريقة تعادل fill (يتوافق فقط مع الحالتين 1d و 2d) وستعتاد عليه بسرعة كبيرة - على الرغم من أنني جئت من عالم الأصفار / الآحاد.

واو ، شكرًا لك Sacha0 @ على بذل هذا الجهد!

السؤال الذي يطرح نفسه بطبيعة الحال هو "ماذا عن zeros "؟ أعتقد أنه سيكون هناك استخدام أكثر بشكل ملحوظ ، وعدد قليل من فئات الاستخدام (بما في ذلك أشياء مثل "أنا ببساطة لا أثق في المصفوفات غير المهيأة" أو "لا أعرف كيفية استخدام Array ").

لأي سبب من الأسباب (أعتقد أنه تناظر one و zero ) ، أنا منجذبة إلى حد ما لاستبدال كل من ones و zeros بـ fill ، أو لا شيء.

الشيء مع الأصفار هو أنك قد تبدو في إحدى هذه المواقف:

  1. تحتاج إلى استبدال معظم الأصفار - في هذه الحالة من الأفضل لك استخدام الفهم ؛
  2. لا تحتاج إلى استبدال معظم الأصفار - في هذه الحالة من الأفضل لك استخدام مصفوفة متفرقة ؛
  3. أنت في الواقع بحاجة إلى مصفوفة صفرية بالكامل - في هذه الحالة من الأفضل لك استخدام 0I .

ليس هناك حقًا حالة استخدام حيث يكون تخصيص مصفوفة من الأصفار الكثيفة فكرة جيدة في الواقع.

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

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

الفرز: قررنا الاحتفاظ بالطرق غير العامة تمامًا مثل zeros(dims...) و ones(dims...) وربما zeros(dims) و ones(dims) أيضًا.

StefanKarpinski لتوصيات الاستخدام هل هذا يعني أننا نوصي zeros(3, 3) على fill(0.0, 3, 3) للرمز العادي (عندما يكون مطلوبًا مصفوفة كثيفة ، إلخ)؟ بعض تفاصيل الكفاءة وما إلى ذلك بعيد المنال ، أنا أفكر فقط في كيفية تدريس أفضل الممارسات / الاصطلاحية في جوليا للمضي قدمًا.

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

الفرز: قررنا الاحتفاظ بالطرق غير العامة تمامًا فقط

ما هو السبب وراء؟

علاوة على ذلك ، هل هذه المشكلة مرتبطة بطريقة ما بالمشكلة العامة لبناء المصفوفات التي يبدو أنها قيد الدراسة الآن ، وإذا كان الأمر كذلك ، فكيف يساعد ذلك؟ أم أننا نحاول تقليل عدد الطرق المصدرة من Base ؟ (أم شيء آخر تمامًا؟)

اكتب قريبًا في https://github.com/JuliaLang/julia/issues/24595 :). أفضل!

قام 24595 بتفصيل السياق الأوسع لهذه المشكلة ، والآن تتناول المتابعة في # 24595 على وجه التحديد منشئي الملاءمة ones ، zeros ، و fill في العمق. قراءة الأول قيمة في تقدير الأخير. أفضل!

حسنًا ، إن توفير حالة Float64 على الأقل أفضل من لا شيء.
أعتقد أن حالة الأصفار الصحيحة هي أيضًا مناسبة تمامًا ، والتي - أفترض - هي في الأساس النقطة التي هنا .

وتجدر الإشارة أيضًا إلى أن zeros ليس لديه "مشكلة" السماح للنمط المضاد لـ 3 * ones(n) . في الواقع ، لا أرى حقًا سبب ارتباط ones و zeros معًا ، باستثناء المعنى الواسع لكونهم منشئين مناسبين. لا يوجد "تناسق" حقيقي بين هذين.

تعليقان إضافيان على التحليل الإحصائي ، حيث يبدو أنه أساس المناقشات التالية وكتابة # 24595. أولاً ، عشر صفحات ليست كافية حقًا للحصول على استنتاجات دقيقة لما يحدث في البرية ، يمكنهم تقديم فكرة تقريبية في أحسن الأحوال. بعض الملفات جاءت مباشرة من matlab ، على سبيل المثال ، كما هو واضح من اسمها / نمطها. ثانيًا ، كما توقعت ، حتى هذا التحليل يُظهر أن ما يقرب من نصف استخدامات ones هناك كانت "مشروعة". ثالثًا ، إن النظر إلى رمز مثل هذا لا يخبرنا بأي شيء عند كتابة 3 * ones(...) هو حقًا نمط مضاد ينتج عنه مشكلات في الأداء ، أو أنه جزء من التعليمات البرمجية ليس له أي آثار على الأداء على الإطلاق (ويمكن للكاتب أن قررت أنه مكتوب بهذه الطريقة أكثر قابلية للقراءة - وهو ما أشعر بشدة أنه ليس من شأن أي شخص آخر أن يقرر خلاف ذلك ، في هذه الحالة).

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

بخصوص

أعتقد أن حالة الأصفار الصحيحة هي أيضًا مناسبة تمامًا ، والتي - أفترض - هي في الأساس النقطة التي كان يشير إليها @vtjnash هنا.

الذي يشير إلى

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

لاحظ أن fill يخدم أيضًا أو أفضل في هذه الحالة: fill(0, shape...) مقابل zeros(Int, shape...) .

فيما يتعلق بالنقاط الأخرى ، قد يكون # 24595 يستحق القراءة :). أفضل!

أجد ببساطة أن zeros(Int, 10, 10) أكثر قابلية للقراءة / صراحة من fill(0, 10, 10) ، و zeros(T, k) أفضل من fill(zero(T), k) . لماذا لا يمكننا الحصول على كليهما فقط؟ أنا لا أشتري الحجة القائلة بأن zeros يعاني من نفس مشكلة الغموض مثل ones .

فيما يتعلق بالنقاط الأخرى ، قد يكون # 24595 جديرًا بالقراءة

لقد قرأته. (حتى أنني ربطته).

لقد قرأته. (حتى أنني ربطته).

بعد قراءة # 24595 بالكامل وإعطائها الاعتبار الواجب ، فأنت تدرك حينئذٍ أن # 24595: (1) تتعلق بمسألة أوسع نطاقًا لا يكون منشئو الملاءمة سوى جزء منها ؛ و (2) يأخذ في الاعتبار أكثر من مجرد التحليل الإحصائي المنشور أعلاه والنقاط التي تركز عليها هنا.

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

هل هناك fill وارد مع تغيير zeros ؟ zeros كان له استخدام شرعي جدًا للبرمجة العامة لأنه أكثر أمانًا من similar ، لذا فإن كل DiffEq ، ثم أعرف مؤخرًا أن Optim و NLsolve انتقلتا من التخصيص بـ similar إلى zeros نظرًا لأن معرفة كل شيء مخصص لوجود أصفار فيه يوقف الكثير من الأخطاء. ومع ذلك ، يبدو الآن أنه لن تكون هناك طريقة لـ:

zeros(X)

بعد الآن ، بخلاف:

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

لأن fill يبني فقط Array s وبالتالي لا يطابق النوع مثل similar أو zeros يفعل. أعلم أن بعض الأشخاص أساءوا استخدام zeros للتخصيص عندما لا ينبغي لهم ذلك ، لكن التخصيص zeros أمر معقول جدًا في كثير من الحالات. آمل أن تتم إضافة الاختصار fill(0,X) لملء هذا الفراغ.

شكرا جزيلا على المنشور المدروس كريس! :) كبديل مؤقت للاختزال ، هل يقوم zero(X) بالمهمة؟

لاحظ أن حالات الاستخدام هذه هي بالضبط حيث الغموض في zeros و ones يمكن أن يكون مشكلة: هل ينتج zeros(X) كائنًا بـ eltype(X) ويمتلئ بـ eltype(X) الهوية المضافة لـ fill!(similar(X), 0) ) ، أو بدلاً من ذلك كائن مملوء بصفر مضاعف لـ eltype(X) (ربما ليس من eltype(X) )؟ (للتوسع انظر # 24595.)

يرى مفهوم fill(0, X) القليل من النقاش في # 11557 ، وأنا أوافق على أنه قد يكون تعميمًا مفيدًا لـ fill . شكرا وأفضل!

المشكلة الأخرى هي أن المصفوفات ذات المؤشرات غير التقليدية قد ترغب في إنشائها بشيء مثل zeros(inds...) (لأن نوع الفهرس يحدد نوع المصفوفة ). لكن بالنسبة للحالة أحادية الأبعاد ، هل X "المصفوفة التي تريد أن تكون مشابهًا لها" أو "مؤشرات المصفوفة المطلوبة"؟ (بعد كل شيء ، AbstractUnitRange <: AbstractArray .) بشكل ملموس ، هل يعني zeros(3:5) fill!(similar(3:5), 0) أو fill!(OffsetArray(Vector{Float64}(3), 3:5), 0) ؟

ربط https://github.com/JuliaLang/julia/pull/24656 ، والذي يحتوي على مناقشة إضافية لمنشئي الراحة {ones|zeros }(A::AbstractArray, ...) . أفضل!

أنا مندهش من أنه من الغريب استخدام zeros لعمل متغيرات ذاكرة التخزين المؤقت وفقًا لـ # 24656. أعتقد أنه إذا تم تخفيض zeros إلى ما يقرب من الصفر ، فإن أي حالة تقريبًا يستخدم فيها الأشخاص similar يجب أن تكون بدلاً من ذلك zeros لأن ذلك يميل إلى إصلاح عدد قليل جدًا البق. أعتقد أننا يجب أن نشجع المزيد من الأشخاص على القيام بذلك لأن similar يمكن أن يكون غير آمن تمامًا ، وليس لديه وظيفة ، وبدلاً من ذلك ، فإن تجميع fill! + similar يجعل الأمر أقل وضوحًا ما يجب أن يفعله الناس. إليك تعليق حول هذا الذي ظهر في Optim.jl:

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

ومع ذلك ، فأنا أتفق مع timholy في أنه من غير الواضح كيف ينبغي تفسير ذلك. اسمح لي بتوجيهك إلى مثال غير بسيط حقًا في DiffEq.

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

قام MultiScaleArrays.jl بإنشاء مصفوفات مجردة وهي هياكل شبيهة بالرسوم البيانية العودية يمكن استخدامها في أدوات حل الاختلافات (وأعتقد أنها قد تكون متوافقة مع Optim.jl و NLsolve.jl الآن؟). إنها ملائمة لطيفة للنماذج البيولوجية من بين أشياء أخرى. عندما نضعها في أداة حل ODE ، هناك سؤال: ما الذي يجب أن نصنعه مصفوفات ذاكرة التخزين المؤقت؟ في بعض الحالات ، من المهم أن يستعيد المستخدم المصفوفة التي يريدها لأنها ستظهر في وظيفة ODE f(t,u,du) وسيريدون التعامل معها وفقًا لذلك. ومع ذلك ، في حالات أخرى ، يظهر فقط كشيء يتم بثه داخليًا ضده. لذلك هناك نوعان مختلفان من متغيرات ذاكرة التخزين المؤقت.

للتعامل مع هذا ، ألق نظرة على ذاكرة التخزين المؤقت لإحدى الخوارزميات:

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

هنا ، rate_prototype = similar(u,first(u)/t,indices(u) مشابه ولكن مع نوع eltype مختلف للوحدات. لكن لاحظ أن هناك نوعين منفصلين هنا: similar(u) مقابل similar(u,indices(u)) . لقد فسرت ذلك على أنه يعني "تطابق النوع والشكل" مقابل "يتطابق مع الشكل والنوع ، ولكن لا يلزم أن يكونا من نفس النوع". لذلك بالنسبة لـ AbstractMultiScaleArray ، سينشئ الأول AbstractMultiScaleArray بينما الآخر ، للسرعة نظرًا لعدم رؤيتها من قبل المستخدم ، سيقوم فقط بإنشاء Array من القيمة المناسبة بحجم. ثم يتم تمديد هذا إلى similar(u,T) و similar(u,T,indices(u)) .

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

لاحظ أن هؤلاء يستخدمون similar لأنني كنت كسولًا جدًا بحيث لم أتمكن من ابتكار إصدار zeros منه. لدي في الواقع مكان منفصل لا يمكنه استبعاد بعض هذه المصفوفات لأنه إذا قام المستخدم بتعيين du في حساب المشتق f(t,u,du) ، فإنهم يميلون إلى شيء ضمني "ما لم أحدده يعني صفر "، وهذا صحيح فقط عندما تم تخصيصه zeros ، لذلك أحاول التخصيص المسبق باستخدام zeros قدر الإمكان (تظهر نفس المشكلة في NLsolve.jl لهذا الغرض) .

آمل ألا يكون هذا التفسير محيرًا جدًا بحيث يتعذر اتباعه. في جميع حالاتي ، يمكنني فقط التبديل إلى similar متبوعًا بـ fill! ، لكنني أعلم أن بعض الحزم لن تكون مصدرًا للأخطاء.

مثير للإعجاب. أنت محق في أن similar(A, inds) قد يُنشئ نوعًا مختلفًا عن similar(A) ، لكن بشكل عام كنت أعتقد دائمًا أنه من المحتمل إنشاء نفس النوع ولكن بمؤشرات مختلفة. على سبيل المثال ، إذا كنت بحاجة إلى ذاكرة تخزين مؤقت أحادية الأبعاد لعملية عمودية على كائن ثنائي الأبعاد ، فسأستخدم similar(A, first(inds)) . (بالطبع هو نوع مختلف لأن الأبعاد هي معلمة نوع ، لكنها قد تكون نفس نوع الحاوية المجردة.) يمكنك أيضًا استخدامها لإنشاء ذاكرة تخزين مؤقت بحجم 5 × 5 من تجانب صغير ، إلخ.

بشكل عام ، يبدو أن هذه مشكلة صعبة. لقد تأخر الوقت قليلاً في اللعبة ، لكن هل يجب أن نقدم same ؟ يمكن أن يكون لها نفس الوسائط مثل similar ، لكن العقد سيكون مطلوبًا لإرجاع نفس الحاوية المجردة.

يمكنني دعم صيغة وسيطة واحدة same ، ولكن حتى هذا صعب - لاحظ أن same(a) لا يمكنه إرجاع نفس نوع المصفوفة إذا كان a لا يدعم setindex! لأن same و similar مفيدان فقط إذا كنت ستكتب إلى المصفوفة بعد ذلك. يمكننا جعل هذا خطأ بالنسبة إلى a غير القابل للتغيير ، ولكن كواجهة لـ AbstractArray يبدو هذا غير ضروري (وربما غير مفيد) لعمل كود عام صحيح.

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

ولكن بالنسبة للحالة أحادية البعد ، هل X "المصفوفة التي تريد أن تكون مشابهًا لها" أم "مؤشرات المصفوفة المطلوبة"؟

وهذا سبب آخر أنا في صالح keys العودة وعاء مع مؤشرات متطابقة والقيم، ومن ثم جعل هذا شرطا من similar (إلا إذا توفر واحد (بعض) صحيح (ق) في أي حالة يتم افتراض Base.OneTo (CartesianRange)).

هذه المناقشة تنحرف نحو # 18161 ، وربما يجب أن تستمر هناك :).

كان الفرز الأخير يميل فقط نحو الاحتفاظ بـ ones .

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

يتم الإغلاق نظرًا لأننا نحتفظ بـ ones و zeros .

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