www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Assign to Array Column

reply Paul <phshaffer gmail.com> writes:
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
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
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
next sibling parent Salih Dincer <salihdb hotmail.com> writes:
Sorry, I forget this:

```d
enum : size_t {
   ROW = 3,
   COL = 3,
   SUM = ROW * COL
}
```
SDB 79
Jan 31 2023
prev sibling parent reply Paul <phshaffer gmail.com> writes:
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:
 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:
Thanks Salih. Much appreciated.
Jan 31 2023
parent Salih Dincer <salihdb hotmail.com> writes:
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: 18446145113651518915
SDB79
Feb 01 2023
prev sibling next sibling parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
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
parent jmh530 <john.michael.hall gmail.com> writes:
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:
 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.
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); } ```
Feb 01 2023
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
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
parent reply Salih Dincer <salihdb hotmail.com> writes:
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/orernGc9b
Thank 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
parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
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
parent Salih Dincer <salihdb hotmail.com> writes:
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 %0
Yes, 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 -O2
SDB 79
Feb 02 2023