MatLabとOOP、最適化

この投稿は、MatLabで書くことを余儀なくされた運命の意志により、OOPプログラミングの練習をしている人(トートロジーについてはごめんなさい)を対象としています。 言語は快適ですが、レーキは非常に大きく、誰もがそれらすべてを踏む必要はありません。



この記事は、MatLabでのコードの最適化に関する最近の投稿や、トピックに関するより深い洞察を必要とするコメントに触発されました。



だから...



物語



長い間、MatLabにはOOPがまったくありませんでした。

2005年、最初の怖い見た目が登場しました:クラス-フォルダー、メソッド-個別のファイル、プロパティ-パラメーター「プロパティ名」を持つ単一のアクセスメソッド。

「美しい」始まり、幸いなことに、彼らはすぐにそれを放棄しました。



数年後、OOPはより身近な形式で作成されました。クラス、継承、すべてが人間のようなものです。 いくつかの詳細に加えて。



いくつかの詳細



過負荷


同じ名前で複数のメソッドを定義することはまだできません。 MatLab自身は、変数のタイピングの欠如(異なるメソッド間の唯一の違いはパラメーターの数になります)およびパラメーターを関数に渡すオプション(到着)によってこれを説明します。



解決策は、状況を分析してこれらの関数の1つを呼び出すディスパッチャ関数とともに、類似した名前の多くの関数を記述することです。



抽象静的


抽象静的メソッドまたはプロパティを定義できません。 そして時々私は本当にしたい。



私はまだ方法を見つけていません、MatLabは知っています、それをバグと見なしません。



値または参照によるパラメーターの受け渡し


すべてのパラメーターは値で渡されます(多くのユーザーは、ホラー、ホラーなどの関数を使用することから遠ざかります)。しかし、レイジーメソッドを使用します。 つまり、コピーは変数が変更された場合にのみ行われます。 このメカニズムが十分に理解されていれば、計算の速度で勝つことができます(または、参照による変数の通常の転送と比較して負けることはありません)。



「通常の」クラスのオブジェクトも値で渡されます。

ただし、クラスがハンドルクラスの標準MatLabクラスを継承する場合、そのオブジェクトは参照によって渡されます。



生成されたドキュメント


java / C ++の後、コードに残したコメントに基づいてドキュメントが自動的に作成されることに慣れます。 MatLabはPublisherと呼ばれるミュータントを提供します。これは不安定で、スクリプトレベルでタスクに迅速に対応します。 クラスでは機能しないという事実に加えて、私が望むものだけでなく、すべてのコメントがドキュメントに含まれているという事実に注意します。 これは、コメントを拒否することを意味します(「ただし、この関数は緊急に書き換えられます!」)。また、セルのコードにある非常に便利なナビゲーションシステムも、何らかの理由でコメントの構文に関連付けられています。



幸いなことに、職人は、MatLabクラスをC ++(もちろん宣言とコメントのみ)に変換するperlスクリプトを台無しにしました。これにより、内部リンク、画像、LaTeXなどの「標準」DOxygenをすべて使用できます。



プロジェクト(私はそれとは何の関係もありませんが、私は宣伝しています)はMatLab Centralで利用可能です。



OOP速度


通常のスクリプト/関数からクラスに移行するときに、40倍のパフォーマンス低下を発見しました。 クラスのように見えるようにするためのいくつかのコームを使用した単純なコピーアンドペースト-それだけで、コードは40倍遅くなります。



掘り下げてみると、同じクラスのメソッドからクラス変数にアクセスしているときにMatLabの速度が低下することがわかりました。 次のクラスを使用します。このメソッドは、同様の関数よりも何倍も遅いだけです。

 classdef Toto < handle properties RatingDepart TauxRecouv Weight FluxScenario end methods function obj = CollectionTaux2() end function corrigerFluxScenario(obj, Survie, CoefRedGov, CoefRedCredit) nbScenario = size(obj.FluxScenario, 3); for i = 1 : nbScenario for j = 1 : numel(obj.Weight) obj.FluxScenario(i, j, :) = repmat(obj.Weight(j), 1, nbScenario) .* ... reshape(obj.FluxScenario(i, j, :), 1, nbScenario) .* ... (CoefRedGov' .* obj.TauxRecouv(j) + ... CoefRedCredit(:, obj.RatingDepart(j))' .* ... Survie(i, :, obj.RatingDepart(j)) .* (1 - obj.TauxRecouv(j))); end end end end end
      
      







MatLabは、OOPに切り替えるときにこの「合理的なオーバーヘッド」を考慮します。 つまり、各反復で、いくつかのサードパーティプロセスによって変数が変更されたかどうか、まだアクセスできるかどうか(誰かが実際にそのようなモーフコードをMatLabで記述できるかのように)などをチェックします。 「便利な」操作。



いくつかの正気な人々との長い会話の後、MatLabはより適切な実装について考えることに同意したようです。



奇跡を見越して、解決策はメソッド入力でローカル変数を決定することです。



 function corrigerFluxScenario(obj, Survie, CoefRedGov, CoefRedCredit) localFluxScenario = obj.FluxScenario; localWeight = obj.Weight; localRatingDepart = obj.RatingDepart; localTauxRecouv = obj.TauxRecouv; nbScenario = size(localFluxScenario, 3); for i = 1 : nbScenario for j = 1 : numel(localWeight) localFluxScenario(i, j, :) = repmat(localWeight(j), 1, nbScenario) .* ... reshape(localFluxScenario(i, j, :), 1, nbScenario) .* ... (CoefRedGov' .* localTauxRecouv(j) + ... CoefRedCredit(:, localRatingDepart(j))' .* ... Survie(i, :, localRatingDepart(j)) .* (1 - localTauxRecouv(j))); end end obj.FluxScenario = localFluxScenario; end
      
      







スクリプトと比較したパフォーマンスの低下は無視できます。



All Articles