ndslice: convert a sliced object to T[]

Seb via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Jun 15 07:14:23 PDT 2016


On Wednesday, 15 June 2016 at 13:13:05 UTC, data pulverizer wrote:
> On Wednesday, 15 June 2016 at 12:10:32 UTC, Seb wrote:
>> As said you can avoid the copy (see below). I also profiled it 
>> a bit and it was interesting to see that 50% of the runtime 
>> are spent on generating the random matrix. On my machine now 
>> both scripts take 1.5s when compiled with
>
> I didn't benchmark the RNG but I did notice it took a lot of 
> time to generate the matrix but for now I am focused on the 
> BLAS side of things.
>
> I am puzzled about how your code works:
>
> Firstly:
> I didn't know that you could substitute an array for its first 
> element in D though I am aware that a pointer to an array's 
> first element is equivalent to passing the array in C.
>>
>> auto matrix_mult(T)(T[] A, T[] B, Slice!(2, T*) a, Slice!(2, 
>> T*) b){
>> 	...
>>     gemm(Order.ColMajor, Transpose.NoTrans, Transpose.NoTrans, 
>> M, N, K, 1., A.ptr, K, B.ptr, N, 0, C.ptr, N);
>> 	return C.sliced(M, N);
>> }
>>

You wrote that too :-)
For more infos see:

https://dlang.org/spec/arrays.html

However that's very dangerous, so use just slices wherever you 
can.

> Secondly:
> I am especially puzzled about using the second element to stand 
> in for the slice itself. How does that work? And where can I 
> find more cool tricks like that?
>
>> void main()
>> {
>> 	...
>> 	auto C = matrix_mult(ta[0], tb[0], ta[1], tb[1]);
>> 	sw.stop();
>> 	writeln("Time taken: \n\t", sw.peek().msecs, " [ms]");
>> }
>>
>
> Many thanks!


Btw you don't even need to save tuples, the pointer is already 
saved in the slice ;-)
N.b: afaik you need the latest version of mir, because 
std.experimental.ndslice in 2.071 doesn't expose the `.ptr` (yet).


// Random matrix
auto rmat(T)(ulong nrow, ulong ncol, T min, T max){
	return runif(nrow*ncol, min, max).sliced(nrow, ncol);
}

auto matrix_mult(T)(Slice!(2, T*) a, Slice!(2, T*) b){
	int M = to!int(a.shape[0]);
	int K = to!int(a.shape[1]);
	int N = to!int(b.shape[1]);
	int n_el = to!int(a.elementsCount);
	T[] C = new T[M*N];
     gemm(Order.ColMajor, Transpose.NoTrans, Transpose.NoTrans, M, 
N, K, 1., a.ptr, K, b.ptr, N, 0, C.ptr, N);
	return C.sliced(M, N);
}

void main()
{
	int n = 4000;
	auto A = rmat(n, n, 0., 1.);
	auto B = rmat(n, n, 0., 1. );
	StopWatch sw;
	sw.start();
	auto C = matrix_mult(A, B);
	sw.stop();
	writeln("Time taken: \n\t", sw.peek().msecs, " [ms]");
}

If you really want to get the original T[] back, you could use 
something like

```
T[] a = slice.ptr[0.. slice.elementsCount];
```

but for most cases `byElement` would be a lot better, because all 
transformations etc are of course only applied to your view.

> And where can I find more cool tricks like that?

Browse the source code and the unittests. Phobos is an amazing 
resource :)


More information about the Digitalmars-d-learn mailing list