МАТЛАБ: Можно ли перегрузить операторы на нативных конструкциях (ячейках, структурах и т. Д.)? - PullRequest
17 голосов
/ 20 марта 2011

Я использую ячейки для управления данными в некоторых вещах, над которыми я работаю. Я хотел бы иметь возможность делать такие вещи, как:

A = cellfun( @(X)( randn( 5,5 ) ), cell( 5,1 ), 'UniformOutput', 0 );
B = cellfun( @(X)( randn( 5,5 ) ), cell( 5,1 ), 'UniformOutput', 0 );
%#
%# Each of the following would fail if cell member dimensions
%# don't match up
%#
%# matrix sums for each cell entry
%# C = A + B;
C = cellfun( @(X,Y)( X + Y ), A, B, 'UniformOutput', 0 );
%#
%# direct/hadamard product
%# D = A .* B;
D = cellfun( @(X,Y)( X .* Y ), A, B, 'UniformOutput', 0 );
%#
%# matrix-matrix products (not across all entries)
%# E = A * B;
E = cellfun( @(X,Y)( X * Y ), A, B, 'UniformOutput', 0 );

Однако я не хочу, чтобы это делал чрезвычайно подробный синтаксис. Создание нового класса для этого кажется слишком сложным, когда все, что я хочу сделать, это предоставить определение математических операторов для ячеек.

Вопрос: является ли класс единственным способом?

Если я напишу для этого класс, это, безусловно, облегчит написание кода. Самые большие негативы, которые я вижу, связаны с оптимизацией, хотя есть несколько других вещей, которые меня беспокоят ...

Любая оптимизация, происходящая за кулисами (например, когда Jacket компилирует что-то для запуска на графическом процессоре), будет потенциально труднее определить, какие оптимизации следует выполнить. В качестве примера, предположим, у меня есть две ячейки (A, B), содержащие несколько матриц соответствующего размера. Если я напишу код для создания новой ячейки:

Z = c1*A + c2*B

... со скалярами {c1, c2}, я могу написать это так, чтобы Jacket (или что-то еще) легко определило, что оно должно выполнять вычисления как:

Z{kk} = c1*A{kk} + c2*B{kk}

или, возможно, даже лучшая оптимизация, чем эта. Иначе. в результате может получиться что-то более медленное и / или менее эффективное использование памяти, например:

temp1 = cellfun( @(X)( c1*X ), A );
temp2 = cellfun( @(X)( c2*X ), B );
Z     = cellfun( @plus, temp1, temp2 );

Предполагая, что MATLAB или Jacket не могут оптимизировать его, это приведет к чрезмерному использованию памяти.

1 Ответ

25 голосов
/ 21 марта 2011

Фактически можно создавать новые операторы или перегружать существующие для встроенных типов данных в MATLAB. Я описываю один пример этого в моем ответе на другой вопрос SO о изменении стандартного поведения переполнения целочисленных типов .

Во-первых, вы можете посмотреть, какие методы существуют в настоящее время для массивов ячеек. Вы можете сделать это, используя функцию МЕТОДЫ , и вот что я получаю в MATLAB R2010b:

>> methods cell

Methods for class cell:

aa2nt            issorted         regexptranslate  strfind          
accumarray       newdepfun        reshape          strjust          
cell2struct      nt2aa            rna2dna          strmatch         
ctranspose       nwalign          seq2regexp       strtok           
display          permute          setdiff          transpose        
dna2rna          regexp           setxor           union            
intersect        regexpi          sort             unique           
ismember         regexprep        strcat           

Методы арифметических операторов будут отображаться в приведенном выше списке как их эквиваленты функций , например plus для оператора + или times для оператора .*. Только метод transpose (оператор .') определен для массивов ячеек. Вы должны будете создать остальное самостоятельно, определяя, как данный оператор будет вести себя для аргументов массивов ячеек.

Вы можете сделать это, сначала создав новую папку с именем @cell и поместив ее в существующую папку по пути MATLAB . Затем вы поместите ваши новые методы в папку @cell. Например, очень простая реализация метода plus для массивов ячеек (без какой-либо проверки ввода, проверки ошибок и т. Д.) Будет выглядеть так:

function C = plus(A,B)
  C = cellfun(@plus,A,B,'UniformOutput',false);  %# Apply plus cell-wise
end

В приведенном выше коде вы, вероятно, сначала захотите проверить, что операнды A и B являются массивами ячеек одинакового размера. Однако вы можете создать любую уникальную функциональность, какую захотите, например, разрешить B быть скалярным значением, которое будет добавлено в каждую ячейку A. Вам решать, как будет вести себя оператор + для массивов ячеек.

Это позволит вам писать код гораздо более компактно, как в этом примере:

>> A = {[1 2 3] [4 5] 6};  %# One 3-element cell array
>> B = {5 [4 5] 2};        %# Another 3-element cell array
>> C = A+B;                %# Use the new plus operator
>> C{:}                    %# Display the cell contents

ans =

     6     7     8

ans =

     8    10

ans =

     8

Я не могу говорить о закулисной оптимизации и о том, как это может повлиять на них. Я знаю, что в документации "Методы повышения производительности" конкретно упоминается это о перегрузке встроенных функций :

Перегрузка встроенных функций MATLAB на любой из стандартных данных MATLAB классы могут негативно повлиять спектакль. Например, если вы перегрузить функцию plus для обработки любой из целочисленных классов иначе, вы можете помешать определенному оптимизации во встроенном в MATLAB код функции для plus, и, следовательно, может замедлять любые программы, которые используют этой перегрузки.

Однако в вашем случае вы не перегружаете существующие функции для класса. Вы просто создаете новые, которых не было для этого класса, поэтому трудно сказать, как это в конечном итоге может повлиять на производительность.

...