digitalmars.D.learn - Assign to Array Column
- Paul (8/8) Jan 30 2023 Greetings,
- Salih Dincer (73/75) Jan 31 2023 Of course, this question has a short answer and a long answer. So
- Salih Dincer (9/9) Jan 31 2023 Sorry, I forget this:
- Paul (2/9) Jan 31 2023 Thanks Salih. Much appreciated.
- Salih Dincer (85/97) Feb 01 2023 It's my pleasure to solve this problem...
- Siarhei Siamashka (8/15) Feb 01 2023 This works fine for small arrays, but for large arrays such
- jmh530 (19/37) Feb 01 2023 If the code is slow, then profile and try to speed up parts that
- Paul Backus (26/34) Feb 01 2023 Here's a solution using standard-library functions:
- Salih Dincer (39/55) Feb 02 2023 Thank you for your contribution. In this way, we can find the
- Siarhei Siamashka (8/11) Feb 02 2023 Except that it isn't. How did you manage to get such ridiculous
- Salih Dincer (5/18) Feb 02 2023 Yes, there is a difference between O1 and O2 that cannot be
Greetings, for an array byte[3][3] myArr, I can code myArr[0] = 5 and have: 5,5,5 0,0,0 0,0,0 Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work. Thanks!
Jan 30 2023
On Tuesday, 31 January 2023 at 01:04:41 UTC, Paul wrote:Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work.Of course, this question has a short answer and a long answer. So the issue is more about column-major. I am someone who likes to talk with codes. In fact, everything is side by side in memory. This example (something like array) covers the issue: ```d import std.stdio; void main() { int[COL][ROW] sample = [ [ 5, 5, 5 ], [ 0, 0, 0 ], [ 0, 0, 0 ], ]; auto arrayish = Arrayish!int(ROW, COL); assert(arrayish.length == SUM); // copy array... foreach(r; 0..ROW) { foreach(c; 0..COL) { arrayish[r, c] = sample[r][c]; } } arrayish.print(); foreach(n; 0..COL) { //arrayish.columnMajor(n).writeln;/* arrayish[n].writeln;//*/ } // clear and set... arrayish.elements[] = 0; foreach(r; 0..ROW) arrayish[r] = 5; arrayish.print(); } struct Arrayish(T) { private { T[] elements; const size_t row, col; } this(size_t row, size_t col) { this.elements = new T[row * col]; this.row = row; this.col = col; } ref T opIndex(size_t row = 0, size_t col = 0) { return elements[row * this.col + col]; } ref T columnMajor(size_t row = 0, size_t col = 0) { return elements[col * this.row + row]; } auto length() { return row * col; } void print() { foreach(r; 0..row) { foreach(c; 0..col) this[r, c].write; writeln; } } } /* Prints: 555 000 000 5 0 0 500 500 500 */ ``` SDB 79
Jan 31 2023
Sorry, I forget this: ```d enum : size_t { ROW = 3, COL = 3, SUM = ROW * COL } ``` SDB 79
Jan 31 2023
On Wednesday, 1 February 2023 at 03:45:11 UTC, Salih Dincer wrote:On Tuesday, 31 January 2023 at 01:04:41 UTC, Paul wrote:Thanks Salih. Much appreciated.Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work.Of course, this question has a short answer and a long answer. So the issue is more about column-major. I am someone who likes to talk with codes. In fact, everything is side by side in memory. This example (something like array) covers the issue:
Jan 31 2023
On Wednesday, 1 February 2023 at 05:51:31 UTC, Paul wrote:Thanks Salih. Much appreciated.It's my pleasure to solve this problem... I have struck upon an idea that would not affect (i think) the speed of the processor requesting memory from the heap on a page-by-page basis but limited 😀 ```d import std.stdio, std.algorithm, std.range; enum : size_t { ROW = 11, COL = 4, SUM = ROW * COL } void main() { // 4 ushort x 11 ulong: auto arr = LimitedArray!COL(ROW); assert(arr.cell[0].elements.length >= COL); assert(arr.length == SUM); alias T = typeof(arr.cell[0].elements[0]); auto range = iota!T(T.max/2, T.max, 762).array; assert(range.length == SUM); range.each!((i, T x) => arr[i] = x);/* foreach(i, x; range) { arr[i] = x; writeln(x); }//*/ arr.print; // 8 ubyte x 99 ulong: auto minMaxTest = LimitedArray!8(99); auto testLength = minMaxTest.length; minMaxTest[0] = ubyte.min + 1; minMaxTest[testLength - 1] = ubyte.max; minMaxTest.print; } template LimitedArray(size_t col) { enum error = "Not Possible Capacity!"; enum size = (col + 1) >> 1; static if(size >= 3) { alias T = ubyte; // min value, but max column } else static if(size == 2) { alias T = ushort;// average array } else static if(size == 1) { alias T = uint; // max value, but min column } enum s = ulong.sizeof/T.sizeof; struct LimitedArray { invariant(uint.sizeof > size, error); private { union Cell { ulong element; T[s] elements; } Cell[] cell; const size_t row; } this(size_t row) { this.cell = new Cell[row]; this.row = cell.length; } ref T opIndex(size_t i) in(i < length, "Range overflow!") { auto len = cell.length; size_t y, x = i % len; y = i / len; return cell[x].elements[y]; } auto length() { return row * col; } void print() { foreach(i, c; cell) { i.writef!"row %2s =>"; foreach(e; c.elements) e.writef!"%6s"; writeln(": ", c.element); } } } } ```row 0 => 32767 41149 49531 57913: 16301273062966132735 row 1 => 33529 41911 50293 58675: 16515760268034671353 row 2 => 34291 42673 51055 59437: 16730247473103209971 row 3 => 35053 43435 51817 60199: 16944734678171748589 row 4 => 35815 44197 52579 60961: 17159221883240287207 row 5 => 36577 44959 53341 61723: 17373709088308825825 row 6 => 37339 45721 54103 62485: 17588196293377364443 row 7 => 38101 46483 54865 63247: 17802683498445903061 row 8 => 38863 47245 55627 64009: 18017170703514441679 row 9 => 39625 48007 56389 64771: 18231657908582980297 row 10 => 40387 48769 57151 65533: 18446145113651518915SDB79
Feb 01 2023
On Tuesday, 31 January 2023 at 01:04:41 UTC, Paul wrote:Greetings, for an array byte[3][3] myArr, I can code myArr[0] = 5 and have: 5,5,5 0,0,0 0,0,0 Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work.This works fine for small arrays, but for large arrays such access pattern is cache unfriendly. It's usually best to redesign the code to avoid assignments to columns if possible (for example, by working with a transposed array). The language is not providing a convenient shortcut for something that is usually undesirable and expensive. And I think that this is actually reasonable.
Feb 01 2023
On Wednesday, 1 February 2023 at 13:14:47 UTC, Siarhei Siamashka wrote:On Tuesday, 31 January 2023 at 01:04:41 UTC, Paul wrote:If the code is slow, then profile and try to speed up parts that need it. The slowness may be due to a problem like this, but not always. The OP could also try mir's slices. ```d /+dub.sdl: dependency "mir-algorithm" version="*" +/ import mir.ndslice.fuse; import std.stdio: writeln; void main() { auto x = [[0, 0, 0], [0, 0, 0]].fuse; x[0, 0 .. $] = 5; x[0 .. $, 1] = 5; writeln(x); } ```Greetings, for an array byte[3][3] myArr, I can code myArr[0] = 5 and have: 5,5,5 0,0,0 0,0,0 Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work.This works fine for small arrays, but for large arrays such access pattern is cache unfriendly. It's usually best to redesign the code to avoid assignments to columns if possible (for example, by working with a transposed array). The language is not providing a convenient shortcut for something that is usually undesirable and expensive. And I think that this is actually reasonable.
Feb 01 2023
On Tuesday, 31 January 2023 at 01:04:41 UTC, Paul wrote:Greetings, for an array byte[3][3] myArr, I can code myArr[0] = 5 and have: 5,5,5 0,0,0 0,0,0 Can I perform a similar assignment to the column? This, myArr[][0] = 5, doesn't work. Thanks!Here's a solution using standard-library functions: import std.range: transversal; import std.algorithm: map, fill; import std.stdio: writefln; void main() { byte[3][3] myArr; myArr[] .map!((ref row) => row[]) .transversal(0) .fill(byte(5)); writefln("%(%s\n%)", myArr[]); } The only tricky part here is the call to `map`, which is necessary to change the type of the rows from `byte[3]` (which is not a range type) to `byte[]` (which is one). Once we've done that, `transversal(0)` lets us iterate over the items at index 0 in each row (in other words, over the first column), and `fill` sets each of those items to the specified value. By the way, if we use Godbolt to look at the generated code, we can see that LDC with optimizations enabled compiles this very efficiently--it is able to inline all the range functions and unroll the loop: https://d.godbolt.org/z/orernGc9b
Feb 01 2023
On Thursday, 2 February 2023 at 05:47:34 UTC, Paul Backus wrote:Here's a solution using standard-library functions: ```d import std.range: transversal; import std.algorithm: map, fill; import std.stdio: writefln; void main() { byte[3][3] myArr; myArr[] .map!((ref row) => row[]) .transversal(0) .fill(byte(5)); writefln("%(%s\n%)", myArr[]); } ``` https://d.godbolt.org/z/orernGc9bThank you for your contribution. In this way, we can find the opportunity to compare. It can be seen below that the structure (LimitedArray) implemented with union is at least 15 times and at most 20 times faster. ```d import std.stdio, std.algorithm, std.range; import std.datetime.stopwatch; enum set { COL = 8, ROW = 65535 } void main() { ubyte[set.COL][set.ROW] sArray; auto lArray = LimitedArray!(set.COL)(set.ROW); auto ds = [ Duration.zero, Duration.zero ]; auto sw = StopWatch(AutoStart.yes); #line 1 sArray[].map!((ref row) => row[]).transversal(0).fill(byte.max); ds[0] = sw.peek(); #line 2 lArray.cell.each!((ref c) => c.elements[0] = byte.max); sw.stop(); /* sArray.writefln!"%(%s\n%)"; lArray.print();//*/ writefln!"#line1 %s µs"(ds[0].total!"usecs"); ds[1] = sw.peek - ds[0]; writefln!"#line2 %s µs"(ds[1].total!"usecs"); "Percent %".writeln(ds[0]/ds[1]); } /* #line1 3362 µs #line2 233 µs Percent %14 */ ``` SDB 79
Feb 02 2023
On Thursday, 2 February 2023 at 10:47:19 UTC, Salih Dincer wrote:It can be seen below that the structure (LimitedArray) implemented with union is at least 15 times and at most 20 times faster.Except that it isn't. How did you manage to get such ridiculous results? Even running your program compiled by LDC with optimizations gives me the following: #line1 31 µs #line2 33 µs Percent %0 This isn't a proper way to do benchmarks.
Feb 02 2023
On Thursday, 2 February 2023 at 13:49:18 UTC, Siarhei Siamashka wrote:On Thursday, 2 February 2023 at 10:47:19 UTC, Salih Dincer wrote: #line1 31 µs #line2 33 µs Percent %0Yes, there is a difference between O1 and O2 that cannot be understood with a benchmark!#line1 6005 µs #line2 122 µs Percent %49 user debian:~/Documents/Ddili/sdb$ ldc2 LimitedStaticArray.d -O1#line1 34 µs #line2 36 µs Percent %0 user debian:~/Documents/Ddili/sdb$ ldc2 LimitedStaticArray.d -O2SDB 79
Feb 02 2023