ndslice: convert a sliced object to T[]
How do I unravel a sliced item T[].sliced(...) to an array T[]? For instance: import std.experimental.ndslice; auto slice = new int[12].sliced(3, 4); int[] x = ??; Thanks
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 02:43:37 UTC, data pulverizer wrote: How do I unravel a sliced item T[].sliced(...) to an array T[]? For instance: import std.experimental.ndslice; auto slice = new int[12].sliced(3, 4); int[] x = ??; Thanks A slice is just a _view_ on your memory, the easiest way is to save a reference to your array like this: ``` int[] arr = new int[12]; auto slice = arr.sliced(3, 4); slice[1, 1] = 42; arr // [0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0] ``` For a general case, you should give `byElement` a try: https://dlang.org/phobos/std_experimental_ndslice_selection.html#byElement
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 02:50:30 UTC, Seb wrote: On Wednesday, 15 June 2016 at 02:43:37 UTC, data pulverizer wrote: How do I unravel a sliced item T[].sliced(...) to an array T[]? For instance: import std.experimental.ndslice; auto slice = new int[12].sliced(3, 4); int[] x = ??; Thanks A slice is just a _view_ on your memory, the easiest way is to save a reference to your array like this: ``` int[] arr = new int[12]; auto slice = arr.sliced(3, 4); slice[1, 1] = 42; arr // [0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0] ``` For a general case, you should give `byElement` a try: https://dlang.org/phobos/std_experimental_ndslice_selection.html#byElement in that case: import std.array : array; int[] x = slice.byElement.array; thanks, now I can go to bed!
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 03:11:23 UTC, data pulverizer wrote: in that case: import std.array : array; int[] x = slice.byElement.array; Are you sure you want to create a _copy_ of your data? In most cases you don't need that ;-) thanks, now I can go to bed! You are welcome. Sleep tight!
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 03:17:39 UTC, Seb wrote: On Wednesday, 15 June 2016 at 03:11:23 UTC, data pulverizer wrote: in that case: import std.array : array; int[] x = slice.byElement.array; Are you sure you want to create a _copy_ of your data? In most cases you don't need that ;-) thanks, now I can go to bed! You are welcome. Sleep tight! Thanks, I did. I definitely don't want to create a copy! I thought .byElement would provide a range which I assume is a reference am I forcing it to copy by using .array?
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 07:24:23 UTC, data pulverizer wrote: On Wednesday, 15 June 2016 at 03:17:39 UTC, Seb wrote: On Wednesday, 15 June 2016 at 03:11:23 UTC, data pulverizer wrote: in that case: import std.array : array; int[] x = slice.byElement.array; Are you sure you want to create a _copy_ of your data? In most cases you don't need that ;-) thanks, now I can go to bed! You are welcome. Sleep tight! Thanks, I did. I definitely don't want to create a copy! I thought .byElement would provide a range which I assume is a reference am I forcing it to copy by using .array? Yes. You're forcing it to read all elements and copy them in a new array.
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 07:45:12 UTC, Andrea Fontana wrote: On Wednesday, 15 June 2016 at 07:24:23 UTC, data pulverizer wrote: On Wednesday, 15 June 2016 at 03:17:39 UTC, Seb wrote: On Wednesday, 15 June 2016 at 03:11:23 UTC, data pulverizer wrote: in that case: import std.array : array; int[] x = slice.byElement.array; Are you sure you want to create a _copy_ of your data? In most cases you don't need that ;-) thanks, now I can go to bed! You are welcome. Sleep tight! Thanks, I did. I definitely don't want to create a copy! I thought .byElement would provide a range which I assume is a reference am I forcing it to copy by using .array? Yes. You're forcing it to read all elements and copy them in a new array. I guess foreach would not copy the elements? for example: foreach(el; slice.byElement) x ~= el; But it feels wrong to be doing work pulling elements that already exists by using foreach. I feel as if I am missing something obvious but can't get it.
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 08:25:35 UTC, data pulverizer wrote: I guess foreach would not copy the elements? for example: foreach(el; slice.byElement) x ~= el; But it feels wrong to be doing work pulling elements that already exists by using foreach. I feel as if I am missing something obvious but can't get it. The question is: why you need to put them inside an array? If you can, leave them in the lazy range and work on it.
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 08:53:22 UTC, Andrea Fontana wrote: On Wednesday, 15 June 2016 at 08:25:35 UTC, data pulverizer wrote: I guess foreach would not copy the elements? for example: foreach(el; slice.byElement) x ~= el; But it feels wrong to be doing work pulling elements that already exists by using foreach. I feel as if I am missing something obvious but can't get it. The question is: why you need to put them inside an array? If you can, leave them in the lazy range and work on it. I need this to work with external libraries that only deal with one dimensional arrays.
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 08:56:15 UTC, data pulverizer wrote: On Wednesday, 15 June 2016 at 08:53:22 UTC, Andrea Fontana wrote: On Wednesday, 15 June 2016 at 08:25:35 UTC, data pulverizer wrote: I guess foreach would not copy the elements? for example: foreach(el; slice.byElement) x ~= el; But it feels wrong to be doing work pulling elements that already exists by using foreach. I feel as if I am missing something obvious but can't get it. The question is: why you need to put them inside an array? If you can, leave them in the lazy range and work on it. I need this to work with external libraries that only deal with one dimensional arrays. Then I think the slice.byElement.array is the right solution.
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 09:32:21 UTC, Andrea Fontana wrote: Then I think the slice.byElement.array is the right solution. The problem with that is that it slows down the code. I compared matrix multiplication between R and D's cblas adaptor and ndslice. n = 4000 Matrices: A, B Sizes: both n by n Engine: both call openblas R Elapsed Time: 2.709 s D's cblas and ndslice: 3.593 s The R code: n = 4000; A = matrix(runif(n*n), nr = n); B = matrix(runif(n*n), nr = n) system.time(C <- A%*%B) The D code: import std.stdio : writeln; import std.experimental.ndslice; import std.random : Random, uniform; import std.conv : to; import std.array : array; import cblas; import std.datetime : StopWatch; T[] runif(T)(ulong len, T min, T max){ T[] arr = new T[len]; Random gen; for(ulong i = 0; i < len; ++i) arr[i] = uniform(min, max, gen); return arr; } // 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[] A = a.byElement.array; T[] B = b.byElement.array; 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]"); } In my system monitor I can see the copy phase in the D process as as single core process. There should be a way to do go from ndslice to T[] without copying. Using a foreach loop is even slower
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 11:19:20 UTC, data pulverizer wrote: On Wednesday, 15 June 2016 at 09:32:21 UTC, Andrea Fontana wrote: Then I think the slice.byElement.array is the right solution. The problem with that is that it slows down the code. I compared matrix multiplication between R and D's cblas adaptor and ndslice. n = 4000 Matrices: A, B Sizes: both n by n Engine: both call openblas R Elapsed Time: 2.709 s D's cblas and ndslice: 3.593 s The R code: n = 4000; A = matrix(runif(n*n), nr = n); B = matrix(runif(n*n), nr = n) system.time(C <- A%*%B) The D code: import std.stdio : writeln; import std.experimental.ndslice; import std.random : Random, uniform; import std.conv : to; import std.array : array; import cblas; import std.datetime : StopWatch; T[] runif(T)(ulong len, T min, T max){ T[] arr = new T[len]; Random gen; for(ulong i = 0; i < len; ++i) arr[i] = uniform(min, max, gen); return arr; } // 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[] A = a.byElement.array; T[] B = b.byElement.array; 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]"); } In my system monitor I can see the copy phase in the D process as as single core process. There should be a way to do go from ndslice to T[] without copying. Using a foreach loop is even slower 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 DFLAGS="-release -O3 -boundscheck=off" dub foo2.d --compiler=ldc (`-b release` would also work) #!/usr/bin/env dub /+ dub.sdl: name "matrix_mult" dependency "cblas" version="~master" dependency "mir" version="~>0.15" +/ import std.stdio : writeln; import mir.ndslice; import std.random : Random, uniform; import std.conv : to; import std.array : array; import cblas; import std.datetime : StopWatch; T[] runif(T)(ulong len, T min, T max){ T[] arr = new T[len]; Random gen; for(ulong i = 0; i < len; ++i) arr[i] = uniform(min, max, gen); return arr; } // Random matrix auto rmat(T)(ulong nrow, ulong ncol, T min, T max){ import std.typecons : tuple; auto arr = runif(nrow*ncol, min, max); return tuple(arr, arr.sliced(nrow, ncol)); } auto matrix_mult(T)(T[] A, T[] B, 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 ta = rmat(n, n, 0., 1.); auto tb = rmat(n, n, 0., 1. ); StopWatch sw; sw.start(); auto C = matrix_mult(ta[0], tb[0], ta[1], tb[1]); sw.stop(); writeln("Time taken: \n\t", sw.peek().msecs, " [ms]"); } For performance issues, you should definitely open an issue at mir (the development library of ndslice): https://github.com/libmir/mir
Re: ndslice: convert a sliced object to T[]
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); } 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!
Re: ndslice: convert a sliced object to T[]
Oh, I didn't see that runif now returns a tuple.
Re: ndslice: convert a sliced object to T[]
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 :)
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 14:14:23 UTC, Seb wrote: On Wednesday, 15 June 2016 at 13:13:05 UTC, data pulverizer And where can I find more cool tricks like that? Browse the source code and the unittests. Phobos is an amazing resource :) Very true! That's great many thanks!
Re: ndslice: convert a sliced object to T[]
On Wednesday, 15 June 2016 at 14:14:23 UTC, Seb wrote: ``` T[] a = slice.ptr[0.. slice.elementsCount]; ``` This would work only for slices with continuous memory representation and positive strides. -- Ilya