سؤال

لنفترض لدي AxBxC مصفوفة X و BxD مصفوفة Y.

هل هناك غير حلقة الطريقة التي أنا يمكن أن تتضاعف كل من ج AxB مع المصفوفات Y?

هل كانت مفيدة؟

المحلول

يمكنك أن تفعل هذا في سطر واحد باستخدام وظائف NUM2CELL لكسر مصفوفة X في مجموعة الخلايا ، CELLFUN تعمل في جميع الخلايا:

Z = cellfun(@(x) x*Y,num2cell(X,[1 2]),'UniformOutput',false);

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

Z = cat(3,Z{:});



ملاحظة: بلادي القديمة الحل MAT2CELL بدلا من NUM2CELL, الذي لم يكن مقتضبة:

[A,B,C] = size(X);
Z = cellfun(@(x) x*Y,mat2cell(X,A,B,ones(1,C)),'UniformOutput',false);

نصائح أخرى

كما تفضيل شخصي ، أنا أحب بلدي رمز إلى أن تكون موجزة و مقروء ممكن.

هنا ما كنت قد فعلت ، على الرغم من أنه لا يجتمع الخاص بك لا-الحلقات متطلب:

for m = 1:C

    Z(:,:,m) = X(:,:,m)*Y;

end

هذه النتائج في أ س د ج مصفوفة Z.

وبالطبع يمكنك دائما قبل تخصيص Z لتسريع الأمور باستخدام Z = zeros(A,D,C);.

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

A = 2;
B = 3;
C = 4;
D = 5;

X = rand(A,B,C);
Y = rand(B,D);

%# calculate result in one big matrix
Z = reshape(reshape(permute(X, [2 1 3]), [A B*C]), [B A*C])' * Y;

%'# split into third dimension
Z = permute(reshape(Z',[D A C]),[2 1 3]);

وبالتالي الآن: Z(:,:,i) يحتوي على نتيجة X(:,:,i) * Y


التفسير:

المذكورة أعلاه قد تبدو مربكة ، ولكن الفكرة بسيطة.أولا أبدأ تأخذ البعد الثالث X و هل العمودية سلسلة على طول خافت أولا:

XX = cat(1, X(:,:,1), X(:,:,2), ..., X(:,:,C))

...الصعوبة التي C هو متغير, وبالتالي لا يمكن تعميم هذا التعبير باستخدام القط أو vertcat.القادم ضربنا هذا من قبل Y:

ZZ = XX * Y;

أخيرا تقسيم ذلك إلى البعد الثالث:

Z(:,:,1) = ZZ(1:2, :);
Z(:,:,2) = ZZ(3:4, :);
Z(:,:,3) = ZZ(5:6, :);
Z(:,:,4) = ZZ(7:8, :);

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

أنا تقترب من نفس المشكلة مع العين الأسلوب الأكثر فعالية.هناك ما يقرب من ثلاثة النهج الذي أراه في جميع أنحاء قصيرة من استخدام خارج المكتبات (أي ، mtimesx):

  1. حلقة من خلال شرائح 3D مصفوفة
  2. repmat و بدل ترتيب كذا سحر
  3. cellfun الضرب

أنا في الآونة الأخيرة مقارنة كل ثلاث طرق لمعرفة من الذي كان أسرع.حدسي هو أن (2) يكون الفائز.هنا كود:

% generate data
A = 20;
B = 30;
C = 40;
D = 50;

X = rand(A,B,C);
Y = rand(B,D);

% ------ Approach 1: Loop (via @Zaid)
tic
Z1 = zeros(A,D,C);
for m = 1:C
    Z1(:,:,m) = X(:,:,m)*Y;
end
toc

% ------ Approach 2: Reshape+Permute (via @Amro)
tic
Z2 = reshape(reshape(permute(X, [2 1 3]), [A B*C]), [B A*C])' * Y;
Z2 = permute(reshape(Z2',[D A C]),[2 1 3]);
toc


% ------ Approach 3: cellfun (via @gnovice)
tic
Z3 = cellfun(@(x) x*Y,num2cell(X,[1 2]),'UniformOutput',false);
Z3 = cat(3,Z3{:});
toc

كل ثلاثة أساليب إنتاج نفس الناتج (تفو!), ولكن من المستغرب أن الحلقة كانت أسرع:

Elapsed time is 0.000418 seconds.
Elapsed time is 0.000887 seconds.
Elapsed time is 0.001841 seconds.

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

% pretty big data...
A = 200;
B = 300;
C = 400;
D = 500;
Elapsed time is 0.373831 seconds.
Elapsed time is 0.638041 seconds.
Elapsed time is 0.724581 seconds.

% even bigger....
A = 200;
B = 200;
C = 400;
D = 5000;
Elapsed time is 4.314076 seconds.
Elapsed time is 11.553289 seconds.
Elapsed time is 5.233725 seconds.

ولكن حلقة طريقة يمكن يكون أبطأ من (2) إذا كان يحلق بعدا أكبر بكثير من الآخرين.

A = 2;
B = 3;
C = 400000;
D = 5;
Elapsed time is 0.780933 seconds.
Elapsed time is 0.073189 seconds.
Elapsed time is 2.590697 seconds.

لذلك (2) يفوز عامل كبير في هذا (ربما المتطرفة) حالة.قد لا يكون هناك نهج الأمثل في جميع الحالات ، لكن الحلقة لا تزال جيدة جدا و أفضل في كثير من الحالات.بل هو أيضا أفضل من حيث القراءة.حلقة بعيدا!

لا.هناك عدة طرق ولكن دائما يخرج في حلقة مباشرة أو غير مباشرة.

فقط لإرضاء فضولي, لماذا تريد ذلك على أي حال ؟

للإجابة على هذا السؤال ، و ل يتيح إمكانية قراءة, يرجى الاطلاع على:

  • ndmult, ، ajuanpi (خوان بابلو كارباخال), 2013, GNU GPL

المدخلات

  • 2 المصفوفات
  • خافت

على سبيل المثال

 nT = 100;
 t = 2*pi*linspace (0,1,nT)’;

 # 2 experiments measuring 3 signals at nT timestamps
 signals = zeros(nT,3,2);
 signals(:,:,1) = [sin(2*t) cos(2*t) sin(4*t).^2];
 signals(:,:,2) = [sin(2*t+pi/4) cos(2*t+pi/4) sin(4*t+pi/6).^2];

 sT(:,:,1) = signals(:,:,1)’;
 sT(:,:,2) = signals(:,:,2)’;
   G = ndmult (signals,sT,[1 2]);

المصدر

المصدر الأصلي.أضفت تعليقات مضمنة.

function M = ndmult (A,B,dim)
  dA = dim(1);
  dB = dim(2);

  # reshape A into 2d
  sA = size (A);
  nA = length (sA);
  perA = [1:(dA-1) (dA+1):(nA-1) nA dA](1:nA);
  Ap = permute (A, perA);
  Ap = reshape (Ap, prod (sA(perA(1:end-1))), sA(perA(end)));

  # reshape B into 2d
  sB = size (B);
  nB = length (sB);
  perB = [dB 1:(dB-1) (dB+1):(nB-1) nB](1:nB);
  Bp = permute (B, perB);
  Bp = reshape (Bp, sB(perB(1)), prod (sB(perB(2:end))));

  # multiply
  M = Ap * Bp;

  # reshape back to original format
  s = [sA(perA(1:end-1)) sB(perB(2:end))];
  M = squeeze (reshape (M, s));
endfunction

أنا نوصي بشدة لك استخدام MMX الأدوات من matlab.يمكن أن تتضاعف الابعاد المصفوفات في أسرع وقت ممكن.

مزايا MMX هي:

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

هذه المشكلة تحتاج فقط إلى كتابة هذا الأمر:

C=mmx('mul',X,Y);

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

    1.6571 # FOR-loop
    4.3110 # ARRAYFUN
    3.3731 # NUM2CELL/FOR-loop/CELL2MAT
    2.9820 # NUM2CELL/CELLFUN/CELL2MAT
    0.0244 # Loop Unrolling
    0.0221 # MMX toolbox  <===================

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

هل يمكن أن "انبسط" حلقة ، أي كتابة كل الضرب بالتتابع التي يمكن أن تحدث في حلقة

أود أن حصة جوابي إلى مشاكل:

1) جعل موتر المنتج اثنين من التنسورات (أي التكافؤ);

2) جعل انكماش اثنين من التنسورات على أي البعد.

هنا هي بلدي subroutines الأول والثاني المهام:

1) موتر المنتج:

function [C] = tensor(A,B)
   C = squeeze( reshape( repmat(A(:), 1, numel(B)).*B(:).' , [size(A),size(B)] ) );
end

2) الانكماش:هنا A و B هي التنسورات أن يكون التعاقد على طول ديميسيونس i و j على التوالي.أطوال هذه الأبعاد يجب أن تكون متساوية ، بالطبع.لا يوجد التحقق من هذا (هذا من شأنه أن يحجب رمز) ولكن بصرف النظر عن هذا أنه يعمل بشكل جيد.

   function [C] = tensorcontraction(A,B, i,j)
      sa = size(A);
      La = length(sa);
      ia = 1:La;
      ia(i) = [];
      ia = [ia i];

      sb = size(B);
      Lb = length(sb);
      ib = 1:Lb;
      ib(j) = [];
      ib = [j ib];

      % making the i-th dimension the last in A
      A1 = permute(A, ia);
      % making the j-th dimension the first in B
      B1 = permute(B, ib);

      % making both A and B 2D-matrices to make use of the
      % matrix multiplication along the second dimension of A
      % and the first dimension of B
      A2 = reshape(A1, [],sa(i));
      B2 = reshape(B1, sb(j),[]);

      % here's the implicit implication that sa(i) == sb(j),
      % otherwise - crash
      C2 = A2*B2;

      % back to the original shape with the exception
      % of dimensions along which we've just contracted
      sa(i) = [];
      sb(j) = [];
      C = squeeze( reshape( C2, [sa,sb] ) );
   end

أي المنتقدين ؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top