Here is a compilable function that demonstrates how to use Map
to produce a tensor of intermediate results from the set of input matrices. The intermediate results are then processed together to produce a final result:
myCompiledFunc1 =
Compile[
{{flat, _Real, 1},
{dims, _Integer, 2}},
Block[{first, last, matrix, tensor},
last = 0;
tensor = (
(* Get the next matrix *)
first = last + 1;
last = last + #[[1]] #[[2]];
matrix = Partition[flat[[first ;; last]], #[[2]]];
(*
Get some appropriate intermediate result of fixed dimensions \
from this matrix, e.g.
with Dimensions \[Rule] {2} *)
{Max[Mean /@ matrix],
Min[Mean /@ Transpose@matrix]}
) & /@ dims;
(* Process the contents of the intermediate tensor *)
{Min@
tensor[[All, 1]],
Max@tensor[[All, 2]]}
]
]
And here is another compilable function, computing the same thing, that demonstrates how to use Fold
to deal with the matrices in pairs, in case there might not be a way to compute a nice tensor of intermediate results to get the final result:
myCompiledFunc2 =
Compile[
{{flat, _Real, 1},
{dims, _Integer, 2}},
Block[{first, last, prevMatrix, currMatrix},
last = 0;
prevMatrix = (
first = last + 1;
last = last + dims[[1, 1]] dims[[1, 2]];
Partition[flat[[first ;; last]], dims[[1, 2]]]
);
Block[{minMaxRowMean, maxMinColMean, currMaxRowMean,
currMinColMean},
Fold[
Function[{acc, dim},
currMatrix = (
first = last + 1;
last = last + dim[[1]] dim[[2]];
Partition[flat[[first ;; last]], dim[[2]]]
);
(* This contrived processing doesn't do anything with \
prevMatrix, but if you wanted to, you could.
This is just a "frame" to modify and fill in as you see fit. *)
\
{minMaxRowMean, maxMinColMean} = acc;
currMaxRowMean = Max[Mean /@ currMatrix];
currMinColMean = Min[Mean /@ Transpose@currMatrix];
prevMatrix = currMatrix;
{Min[minMaxRowMean, currMaxRowMean],
Max[maxMinColMean, currMinColMean]}
],
{Max[Mean /@ prevMatrix], Min[Mean /@ Transpose@prevMatrix]},
Rest@dims
]
]
]
]
E.g., an accumulator could be used for any intermediate value you might like (as long as it has a consistent Compile
-type throughout evaluation), and the approach could also be modified to deal with triples of matrices rather than just pairs.
The main "trick" in using a compiled function to deal with all your matrices at once is that they'd have to be stored in an array, and arrays in Compile
must be tensors (basically not "ragged" in any way). This is essentially the Compile
-typing problem you originally encountered that I believe prompted you to go this route, flattening and passing the dimensions of each matrix.
Another "trick" that is not so easy to come by without this site is a list of compilable top-level functions. Fortunately, we have some of this information here:
List of compilable functions
I think the functions I've provided here are good examples of being compilable, but they may not be very efficient. I was mainly going for the former quality, since I don't know the details of the computation you'll be doing.
For convenient reference from this answer:
http://reference.wolfram.com/mathematica/Compile/tutorial/Overview.html
http://reference.wolfram.com/mathematica/Compile/tutorial/Operation.html
The former is where to go for all things Compile
, and the latter (a child section of the former) describes the type system and other details of operation for Compile
in Mathematica.
Finally, note that you actually could manage to deal with all matrices at once if you were to handle them "virtually", i.e. dynamically indexing into the flattened list based on which matrix and which indexed element you wanted. That probably wouldn't be very efficient, but I haven't tried it.
Unflattening a list
? $\endgroup$Compile
it will generate a callback to the main evaluator. $\endgroup$For
loops with a number of sequential matrix operations per iteration of the loop. Each subsequent iteration depends on the result of the previous iteration and each iteration requires modification of the shape of the resultant matrix from the calculations. I felt that adding this detail would have been a distraction from my main question. Happy to add it or start another question if you would like. $\endgroup$CompiledFunction
block without losing (some of?) the advantage of compiling. I am wondering if instead it is possible to create a series of separate compiled functions, perhaps dynamically generated (meta-programming), then pass the data from one to another. I am surely not an expert on compilation so I'm not sure if there is any merit to this idea (e.g. overhead may be significant) but is one possible approach. $\endgroup$