Jump to page: 1 2
Thread overview
Assign to Array Column
Jan 31, 2023
Paul
Feb 01, 2023
Salih Dincer
Feb 01, 2023
Salih Dincer
Feb 01, 2023
Paul
Feb 02, 2023
Salih Dincer
Feb 01, 2023
Siarhei Siamashka
Feb 01, 2023
jmh530
Feb 02, 2023
Paul Backus
Feb 02, 2023
Salih Dincer
Feb 02, 2023
Siarhei Siamashka
Feb 02, 2023
Salih Dincer
January 31, 2023

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!

February 01, 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:

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

February 01, 2023

Sorry, I forget this:

enum : size_t {
  ROW = 3,
  COL = 3,
  SUM = ROW * COL
}

SDB@79

February 01, 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:

>

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.

February 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.

February 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:

>

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.

/+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);
}
February 02, 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 😀

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

February 02, 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

February 02, 2023

On Thursday, 2 February 2023 at 05:47:34 UTC, Paul Backus wrote:

>

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[]);
    }

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.

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

February 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.

« First   ‹ Prev
1 2