راجع ترتيب أزواج المحاور. [1]
اقرأ زوج المحاور
تتقابل محاور قائمتَي axes بالترتيب؛ axes=2 تربط آخر محورين للأول بأول محورين للثاني. [1]
حين تكون أطوال محاور مختلفة متساوية، قد ينجح أكثر من طلب دون أن يحسب المقارنة التي أردناها. ندوّن أي محور في A يقابل أي محور في B، ثم نقرأ ناتجًا عدديًا معلومًا بدل الاكتفاء بالشكل.
الأعداد مؤلفة بلا وحدة وليست قياسات. نقصر المثال على مدخلين بثلاثة محاور، ونثبت ترتيب الفهارس في كل قائمة.
مدخلان ومطابقتان
أنشأنا A=np.array([[[2,1],[4,-3]],[[0,5],[-2,6]]],dtype=np.int64)، وB=np.array([[[1,3],[2,-1]],[[5,0],[-4,2]]],dtype=np.int64)، في NumPy 2.3.5 على CPython 3.12.14. شكل كل مدخل (2,2,2).
نفهرس A[i,l,m] وB[l,m,k]، حيث كل فهرس من 0 إلى 1. الاستدعاء np.tensordot(A,B,axes=2) أعاد [[36,−1],[−24,7]] من int64 وشكل (2,2). وإعادة الاستدعاء مع axes=([1,2],[0,1]) أعطت القائمة نفسها بالنوع والشكل نفسيهما.
نقرأ الخانة الأولى بجمع أربعة نواتج: 2×1+1×2+4×5+(−3)×(−4)=2+2+20+12=36. الفهرسان الباقيان i وk يحددان صف الناتج وعموده في هذا المثال.
ثم غيّرنا طلب المحاور إلى axes=([1,2],[1,0])، دون تغيير A أو B. سجلنا [[27,−4],[−3,14]] من int64 وشكل (2,2). التقابل صار مع B[m,l,k] بدل B[l,m,k].
الخانة الأولى الآن 2×1+1×5+4×2+(−3)×(−4)=2+5+8+12=27. تغير العنصران اللذان قابلناهما مع 1 و4 في A، فاختلاف مجموعيهما يفسر فرق 9 بين الجوابين.
كلا الطلبين قابل أبعادًا بطول 2، ولم يرفع تشغيلنا خطأ. نجاح الاستدعاء وتطابق شكل الخرج لا يثبتان أنهما جمعا نواتج الضرب نفسها.
تحكمان يثبتان التقابل
اخترنا axes=([2,1],[1,0])، أي قلبنا ترتيب القائمتين معًا. أعاد [[36,−1],[−24,7]] من int64 وشكل (2,2). الأزواج هي A2 مع B1 ثم A1 مع B0؛ إنها أزواج الطلب الأول بترتيب عرض مختلف.
لذلك نفرق بين قلب قائمة واحدة وتغيير ترتيب الأزواج في القائمتين معًا. الحالة الثانية لم تعط جواب الحالة ذات القلب المفرد في هذا المثال.
transpose تعيد ترتيب المحاور؛ المحور i في الناتج يقابل محور axes[i] في المدخل. [2]
أنشأنا C=np.transpose(B,(1,0,2))، ثم شغّلنا np.tensordot(A,C,axes=2). أعاد [[27,−4],[−3,14]] من int64 وشكل (2,2)، وهو جواب القلب المفرد في التشغيل السابق.
راجعنا في التحكم أن C[l,m,k]=B[m,l,k] لكل فهرس في المثال، وشكل C بقي (2,2,2). تغير مصدر القيم التي تقرأها خانة معينة رغم بقاء الأبعاد؛ لا نسميه تغييرًا مخفيًا في B الأصلية.
قارنا بايتات A وB قبل المسارات وبعدها، فكانت متطابقة. لم نعدل C ولم نفحص نتائج الكتابة عبر ذاكرة مشتركة؛ هذا فحص مخرجات ومواضع، لا ضمان نسخ أو استقلال ذاكرة.

مرجع ونطاق محدود
مرجعنا يبسط كل خانة إلى أربعة نواتج ضرب بأعداد Python، بحسب مطابقة المحاور المختارة. [1]
للخانة (i,k) في التقابل الأول نكتب A[i,0,0]B[0,0,k]+A[i,0,1]B[0,1,k]+A[i,1,0]B[1,0,k]+A[i,1,1]B[1,1,k]. في القلب المفرد نبدل عنواني B في الحدين الأوسطين، فيصيران B[1,0,k] ثم B[0,1,k].
المرجع يعمل على قوائم Python الأصلية ولا يستدعي tensordot أو einsum أو dot أو matmul أو transpose أو اختزال مكتبة. صنعنا المكعبات بقوائم وصفوف معلنة، لا باستدعاء reshape داخل المرجع.
عددنا كل المكعبات الثمانية العناصر التي تأخذ عناصر A من {−1,2} وعناصر B من {−2,3}. لكل مدخل 2**8=256 احتمالًا؛ لدينا 256×256=65536 زوجًا. القيم صغيرة، ونواتجنا تدخل int64 في النطاق المختبر.
لكل زوج ستة فحوص: خرج axes=2؛ والصيغة الصريحة المناظرة؛ وقلب B وحدها؛ وقلب القائمتين؛ وتحكم transpose مع مواضع C؛ وثبات بايتات A وB. قارنّا القيم والنوع int64 والشكل (2,2) في المسارات الخمسة.
أضفنا الفحوص الستة نفسها للمثال العددي المعروض. الإجمالي 65536×6+6=393222، ومرت جميع الفحوص. تساوي جوابين في حالات من الشبكة لا يجعل كل المطابقات متكافئة؛ مثالنا المعروض يبين اختلافًا فعليًا.
استبعدنا الأشكال والمحاور والأنواع الأخرى، وتجاوز المجال والعائمة والمركبة وNaN والبث والمحاور المكررة والمصفوفات الفارغة، وآثار تعديل ذاكرة مشتركة والأداء والتنفيذ الداخلي. احفظ مطابقة المحاور مع الجواب، لا عدد الخانات وحده.
| المسار | القيم المسجلة | النوع والشكل |
|---|---|---|
| axes=2 أو ([1,2],[0,1]) | [[36,-1],[-24,7]] | int64 / (2,2) |
| ([1,2],[1,0]) | [[27,-4],[-3,14]] | int64 / (2,2) |
| ([2,1],[1,0]) | [[36,-1],[-24,7]] | int64 / (2,2) |
| A مع transpose(B,(1,0,2)) / axes=2 | [[27,-4],[-3,14]] | int64 / (2,2) |
للتوسع: المصفوفات والتحويلات.
المراجع
أُعدّ هذا المقال بمساعدة الذكاء الاصطناعي، وخضع لمراجعة ذاتية بالأداة نفسها. لا يُنسب إلى مراجع بشري أو خبير مستقل. منهجية المحتوى.
