TL; DR:いくつかの凝ったOOPMコードのトリックでそれは可能です。の動作の変更は()
、Javaラッパークラスの上に.
定義するMatlabラッパークラスを使用して行うことができます。subsref
しかし、MatlabからJavaへの固有のオーバーヘッドのため、通常のMatlabコードよりも高速になることはおそらくなく、はるかに複雑で面倒です。ロジックをJavaにも移行しない限り、このアプローチではおそらくスピードアップにはなりません。
お手数をおかけして申し訳ございません。
これを完全に理解する前に、Matlabコードから呼び出されたJava構造のパフォーマンスをベンチマークすることができます。Javaフィールドアクセスとメソッド呼び出しは、それ自体でMatlabのものよりもはるかに高速ですが、Mコードから呼び出すにはかなりのオーバーヘッドがあるため、多くのロジックをJavaにプッシュダウンしない限り、最終的には終了する可能性があります。速度が大幅に低下します。MコードをJavaレイヤーにクロスするたびに、料金が発生します。この答えでベンチマークを見てください:MATLAB OOPは遅いですか、それとも私は何か間違ったことをしていますか?規模のアイデアを得るために。(完全な開示:それは私の答えの1つです。)Javaフィールドアクセスは含まれていませんが、オートボクシングのオーバーヘッドのため、おそらくメソッド呼び出しの順序になっています。また、例のように、パブリックフィールドの代わりにgetterメソッドとsetterメソッドを使用して(つまり、「適切な」Javaスタイルで)Javaクラスをコーディングしている場合は、アクセスごとにJavaメソッド呼び出しのコストが発生します。純粋なMatlab構造に比べて悪くなるでしょう。
x = [foo(1:2).bar]
とはいえ、Java配列であるMコード内でその構文を機能させたい場合foo
は、基本的に可能です。()
とは両方とも、.
Javaを呼び出す前にMatlabで評価されます。できることは、Java配列ラッパークラスに対応するMatlab OOPで独自のカスタムJavaArrayWrapperクラスを定義し、その中で(おそらくラップされた)Java配列をラップすることです。オーバーライドsubsref
して、とsubsasgn
の両方を処理する()
ようにします.
。の場合()
、配列の通常のサブセット化を実行し、JavaArrayWrapperでラップして返します。場合.
:
- ラップされたオブジェクトがスカラーの場合は、通常どおりJavaメソッドを呼び出します。
- ラップされたオブジェクトが配列の場合は、そのオブジェクトをループし、各要素でJavaメソッドを呼び出して、結果を収集します。結果がJavaオブジェクトの場合は、JavaArrayWrapperでラップされたものを返します。
だが。Matlab / Javaの障壁を越えるオーバーヘッドのため、これは遅く、おそらく純粋なMatlabコードよりも桁違いに遅くなります。
これを高速に動作させるには、Java配列をラップし、Java Reflection APIを使用して選択した各配列メンバーオブジェクトのプロパティを抽出し、それらを配列に収集する、対応するカスタムJavaクラスを提供できます。x = foo(1:3).a.b.c
重要なのは、Matlabで「連鎖」参照を実行し、オブジェクトである場合、を評価して結果を呼び出すなどfoo
の段階的な評価を行わないことです。実際には、参照全体を解析し、それを構造化された引数に変換し、チェーン全体を解釈する責任があるのメソッドにすべてを渡します。暗黙の呼び出しは次のようになります。foo(1:3)
.a
(1:3).a.b.c
subsref
foo
x = subsref(foo, [ struct('type','()','subs',{{[1 2 3]}}), ...
struct('type','.', 'subs','a'), ...
struct('type','.', 'subs','b'), ...
struct('type','.', 'subs','c') ] )
したがって、参照「チェーン」全体に事前にアクセスできる場合foo
、定義されたMコードラッパークラスであればsubsasgn
、その参照全体をJava引数に変換し、Javaラッパーへの単一のメソッド呼び出しで渡すことができます。次に、Java Reflectionを使用して、ラップされた配列を動的に調べ、参照要素を選択し、連鎖参照をすべてJavaレイヤー内で実行するクラス。たとえば、getNestedFields()
このようなJavaクラスを呼び出します。
public class DynamicFieldAccessArrayWrapper {
private ArrayList _wrappedArray;
public Object getNestedFields(int[] selectedIndexes, String[] fieldPath) {
// Pseudo-code:
ArrayList result = new ArrayList();
if (selectedIndexes == null) {
selectedIndexes = 1:_wrappedArray.length();
}
for (ix in selectedIndexes) {
Object obj = _wrappedArray.get(ix-1);
Object val = obj;
for (fieldName in fieldPath) {
java.lang.reflect.Field field = val.getClass().getField(fieldName);
val = field.getValue(val);
}
result.add(val);
}
return result.toArray(); // Return as array so Matlab can auto-unbox it; will need more type detection to get array type right
}
}
次に、Mコードラッパークラスが結果を調べて、それがプリミティブっぽく、Matlab配列またはコンマ区切りリスト(つまり、で収集される複数のargout)として返されるか[...]
、別のJavaArrayWrapperでラップされるかを決定します。 Mコードオブジェクト。
Mコードラッパークラスは次のようになります。
classdef MyMJavaArrayWrapper < handle
% Inherit from handle because Java objects are reference-y
properties
jWrappedArray % holds a DynamicFieldAccessArrayWrapper
end
methods
function varargout = subsref(obj, s)
if isequal(s(1).type, '()')
indices = s(1).subs;
s(1) = [];
else
indices = [];
end
% TODO: check for unsupported indexing types in remaining s
fieldNameChain = parseFieldNamesFromArgs(s);
out = getNestedFields( jWrappedArray, indices, fieldNameChain );
varargout = unpackResultsAndConvertIfNeeded(out);
end
end
end
subsasgn呼び出しの値のマーシャリングとアンマーシャリングに伴うオーバーヘッドは、おそらくJavaビットからの速度の向上を圧倒するでしょう。
subsasgn
のMコード実装をCで構造のマーシャリングとアンマーシャリングを行うMEX実装に置き換え、JNIを使用してJavaオブジェクトを構築し、getNestedFieldsを呼び出し、結果をMatlab構造に変換することで、このオーバーヘッドをおそらくなくすことができます。これは私が例をあげることができるものをはるかに超えています。
これがあなたにとって少し恐ろしいように見えるなら、私は完全に同意します。あなたはここで言語の端にぶつかっています、そしてユーザーランドから言語を拡張しようとすること(特に新しい構文上の振る舞いを提供するために)は本当に難しいです。私は本番コードでこのようなことを真剣に行うことはしません。あなたが見ている問題の領域を概説しようとしているだけです。
これらの深くネストされた構造の同種の配列を扱っていますか?おそらく、それらを「平面組織化」構造に変換することが可能であり、スカラーフィールドを持つ構造体の配列の代わりに、配列フィールドを持つスカラー構造体があります。次に、純粋なMコードでそれらに対してベクトル化された操作を実行できます。これにより、特にオーバーヘッドがmxarrayごとにスケーリングする、save
およびを使用すると、処理が大幅に高速化されます。load