Reputation: 423
I would like to write this operation
Matrix.Multiply(source,target)
target.Add(offsets)
in this mathematical style
target = Matrix * source + offsets;
However, I'm also concerned about performance. (In fact, the above operation will be run in a tight loop.) I don't want to create a new vector for each matrix-vector multiplication and another new vector for the vector addition.
How can I implement the above operation in C# or F# (or any functional language that you know) so that style and performance can be both achieved?
Sorry for this naive question. I'm sure this desire is so fundamental.
Upvotes: 3
Views: 276
Reputation: 67898
Making the assumption that the Matrix
class is yours, you can overload the operators:
public static Matrix operator *(Matrix x, Matrix y)
{
return Matrix.Multiply(x, y);
}
public static Matrix operator +(Matrix x, OffsetsType offsets)
{
x.Add(offsets);
return x;
}
So, this expression (which is a modification of the one in your question because in your question you are multiplying Matrix
by source
and that doesn't make sense):
target = target * source + offsets;
broken out, would look like this:
var z = Matrix.Multiply(target, source);
z.Add(offsets);
target = z;
Upvotes: 2
Reputation: 31459
A well-known technique, that is for example at the heart of the Repa library of high-performance numeric arrays, is to define on top of the basic "2D array of integer" structure a higher-level data structure that delays the operations you want to perform, along with an intepretation/normalization function that will finally perform those operations, applying any optimization it deems profitable.
Concretely, in your example, and I think most current answers have missed this, you want A * B + C
to be rewritten not into
add(multiply(A,B), C)
or in OO styl e
A.multiply(B).add(C)
but instead
multiply_and_add(A,B,C)
where multiply_and_add
is a specialez, lower-level operation that does both operations at once and is more optimized. Similarly, it is well-known that for arbitrary matrices A, B, C, D
, the product A * B * C * D
may be more efficiently computed as A * ((B * C) * D)
rather than A * (B * (C * D)))
, depending on the operand dimensions. So a purely local approach (expressing each operation on arrays of integers) does not work, you need expression-global rewrites for optimal efficiency -- as done by the hackish template libraries in C++.
The solution is to move from int array array
to a refined datatype, for example:
type matrix =
| Raw of int array array
| Add of matrix * matrix
| Mult of matrix * matrix
and then provide a eval : matrix -> int array array
function that "interprets" those matrix descriptions (in essence abstract syntax trees of matrix operations) by possibly applying domain-specific optimizations. For a naive example:
let rec eval = function
| Raw m -> m
| Add(Mult(a,b), c) | Add(c, Mult(a,b)) ->
multiply_and_add (eval a) (eval b) (eval c)
| Add (a, b) -> add (eval a) (eval b)
| Mult (a, b) -> mult (eval a) (eval b)
You can then define the syntactic sugar of your liking to make the matrix
constructors easier to read.
module Matrix = struct
let (!) m = Raw m
let (+) a b = Add (a, b)
let (*) a b = Mult (a, b)
end
let ... = eval Matrix.(!A * !B + !C)
Upvotes: 10
Reputation: 14678
If performance is your largest concern, the fastest way to do this is to define Matrix as a struct if it isn't already, then use ref/out parameters instead of ones that create a lot of copies.
public void Multiply(ref Matrix left, ref Matrix right, out Matrix result)
This is the approach taken by a number of C# game/graphics frameworks.
There's also this very interesting article about optimizing OpenTK's matrix multiplication, which might give you ideas about how to further speed up matrix operations: Making OpenTK matrix multiplication faster
Of course, if you matrix class isn't of a fixed size, then this information is largely useless.
Upvotes: 0
Reputation: 3742
You can create custom operators for your classes:
http://msdn.microsoft.com/en-us/library/8edha89s.aspx
This gives you the syntax you want, but still functional programming behind the scenes. Performance will be no different since .NET will just compile your operator-using code to be function-calling instead.
Upvotes: -1