www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 2D matrix operation (subtraction)

reply Andre Pany <andre s-e-a-p.de> writes:
Hi,

I have a 2D double array and I want to subtract from the first 
column a value,
is this possible with matrix operation in D?

```
void main()
{
     double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]];

     // subtract -2.0 from the first column for every value

     // Expected output
     // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]];

}
```

Kind regards
André
Feb 21 2020
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 2/21/20 12:51 AM, Andre Pany wrote:
 Hi,
=20
 I have a 2D double array and I want to subtract from the first column a=
=20
 value,
 is this possible with matrix operation in D?
=20
 ```
 void main()
 {
  =C2=A0=C2=A0=C2=A0 double[][] data =3D [[0.0, 1.4], [1.0, 5.2], [2.0, =
0.8]];
=20
  =C2=A0=C2=A0=C2=A0 // subtract -2.0 from the first column for every va=
lue
=20
  =C2=A0=C2=A0=C2=A0 // Expected output
  =C2=A0=C2=A0=C2=A0 // data =3D [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]];=
=20
 }
 ```
=20
 Kind regards
 Andr=C3=A9
=20
=20
I don't have experience with it but mir's ndslice is designed for this: https://github.com/libmir/mir-algorithm Although it feels like something similar is probably already in Phobos,=20 I've come up with the following solution just now for fun: import std.stdio; import std.algorithm; import std.range; // At least something similar to this exists in Phobos? struct ElementReference(R) { ElementType!(ElementType!R) * p; ref reference() { return *p; } alias reference this; } struct Column(R) { R range; size_t n; auto empty() { return range.empty; } auto front() { return ElementReference!R(&(range.front[n])); } auto popFront() { return range.popFront(); } } auto byColumn(R)(R range, size_t n) { return Column!R(range, n); } void main() { double[][] data =3D [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; data.byColumn(0).each!(a =3D> a -=3D 2.0); writeln(data); } Ali
Feb 21 2020
next sibling parent reply Andre Pany <andre s-e-a-p.de> writes:
On Friday, 21 February 2020 at 11:53:02 UTC, Ali Çehreli wrote:
 On 2/21/20 12:51 AM, Andre Pany wrote:
 Hi,
 
 I have a 2D double array and I want to subtract from the first 
 column a value,
 is this possible with matrix operation in D?
 
 ```
 void main()
 {
      double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]];
 
      // subtract -2.0 from the first column for every value
 
      // Expected output
      // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]];
 
 }
 ```
 
 Kind regards
 André
 
 
I don't have experience with it but mir's ndslice is designed for this: https://github.com/libmir/mir-algorithm Although it feels like something similar is probably already in Phobos, I've come up with the following solution just now for fun: import std.stdio; import std.algorithm; import std.range; // At least something similar to this exists in Phobos? struct ElementReference(R) { ElementType!(ElementType!R) * p; ref reference() { return *p; } alias reference this; } struct Column(R) { R range; size_t n; auto empty() { return range.empty; } auto front() { return ElementReference!R(&(range.front[n])); } auto popFront() { return range.popFront(); } } auto byColumn(R)(R range, size_t n) { return Column!R(range, n); } void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; data.byColumn(0).each!(a => a -= 2.0); writeln(data); } Ali
Thanks a lot. Mir is great and actually I try to rewrite some Python Pandas Dataframe index logic. For my current project any dependency less is a little headache less, therefore I try to avoid Mir at the moment, but will definitely will have a look whether I can use it. Thanks for the example, I will use it. Kind regards André
Feb 21 2020
parent reply 9il <ilyayaroshenko gmail.com> writes:
On Friday, 21 February 2020 at 13:42:24 UTC, Andre Pany wrote:
 Mir is great and actually I try to rewrite some Python Pandas 
 Dataframe index logic.
Maybe mir.series [1] can work for you. Series!(Key*, Value*) - is a pair of two 1D ndslices, they can be sorted according to the first one ndslice (keys). Series has `get` methods. Series!(Key*, Value*, 2) is a pair of 1D ndslice (keys) and 2D ndslice (values matrix). Series has slicing primitives. Keys corresponds to the first dimension. http://mir-algorithm.libmir.org/mir_series.html#Series
Feb 22 2020
next sibling parent Andre Pany <andre s-e-a-p.de> writes:
On Saturday, 22 February 2020 at 08:29:32 UTC, 9il wrote:
 On Friday, 21 February 2020 at 13:42:24 UTC, Andre Pany wrote:
 Mir is great and actually I try to rewrite some Python Pandas 
 Dataframe index logic.
Maybe mir.series [1] can work for you. Series!(Key*, Value*) - is a pair of two 1D ndslices, they can be sorted according to the first one ndslice (keys). Series has `get` methods. Series!(Key*, Value*, 2) is a pair of 1D ndslice (keys) and 2D ndslice (values matrix). Series has slicing primitives. Keys corresponds to the first dimension. http://mir-algorithm.libmir.org/mir_series.html#Series
Thanks a lot for all the answers. Kind regards Andre
Feb 22 2020
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Saturday, 22 February 2020 at 08:29:32 UTC, 9il wrote:
 [snip]

 Maybe mir.series [1] can work for you.
I had a few other thoughts after looking at septc's solution of using y[0..$, 0] *= 100; to do the calculation. 1) There is probably scope for an additional select function to handle the use case of choosing a specific row/column. For instance, what if instead of y[0..$, 0] you want y[0..$, b, 0..$] for some arbitrary b. I think you would need to do something like y.select!1(b, b + 1); which doesn't have the best API, IMO, because you have to repeat b. Maybe just an overload for select that only takes one input instead of two? 2) The select series of functions does not seem to work as easily as array indexing does. When I tried to use the select/selectFront functions to do what he is doing, I had to something like auto z = y.selectFront!1(1); z[] *= 100; This would adjust y as expected (not z). However, I couldn't figure out how to combine these together to one line. For instance, I couldn't do y.selectFront!1(1) *= 100; or auto y = x.selectFront!1(1).each!(a => a * 100); though something like y[0..$, 0].each!"a *= 100"; works without issue. It got a little frustrating to combine those with any kind of iteration. TBH, I think more than the select functions, the functionality I would probably be looking for is more what I was doing with byDim!1[0] in the prior post. I could imagine some very simple version looking like below auto selectDim(size_t dim, T)(T x, size_t a, size_t b) { return byDim!dim[a .. b]; } with a corresponding version auto selectDim(size_t dim, T)(T x, size_t a) { return byDim!dim[a .. (a + 1)]; } This simple version would only work with one dimension, even though byDim can handle multiple.
Feb 25 2020
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 21 February 2020 at 11:53:02 UTC, Ali Çehreli wrote:
 [snip]
 auto byColumn(R)(R range, size_t n) {
   return Column!R(range, n);
 }
mir has byDim for something similar (numir also has alongDim). This is how you would do it: import mir.ndslice; void main() { auto x = [0.0, 1.4, 1.0, 5.2, 2.0, 0.8].sliced(3, 2); x.byDim!1.front.each!"a -= 2"; } My recollection is that it is a little bit trickier if you want to subtract a vector from each column of a matrix (the sweep function in R).
Feb 21 2020
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 21 February 2020 at 14:43:37 UTC, jmh530 wrote:
 [snip]
Actually, I kind of prefer the relevant line as x.byDim!1[0].each!"a -= 2"; which makes it a little clearer that you can easily change [0] to [1] to apply each to the second column instead.
Feb 21 2020
prev sibling parent septc <septcolor7 gmail.com> writes:
On Friday, 21 February 2020 at 08:51:49 UTC, Andre Pany wrote:
 Hi,

 I have a 2D double array and I want to subtract from the first 
 column a value,
 is this possible with matrix operation in D?

 ```
 void main()
 {
     double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]];

     // subtract -2.0 from the first column for every value

     // Expected output
     // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]];

 }
 ```

 Kind regards
 André
I've recently learning Mir and so interested in this topic. For the above purpose, I am wondering if this Numpy-like approach is also valid: y[ 0..$, 0 ] *= 100; The online editor (https://run.dlang.io/) seems to give the expected result. // (the below code is based on the post by jmh530) import std.stdio; import mir.ndslice; void main() { auto x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0].sliced(3, 2); auto y = x.dup; writeln( x ); // [[0, 1], [2, 3], [4, 5]] writeln( y ); // [[0, 1], [2, 3], [4, 5]] x.byDim!1.front.each!"a *= 100"; y[ 0..$, 0 ] *= 100; writeln( x ); // [[0, 1], [200, 3], [400, 5]] writeln( y ); // [[0, 1], [200, 3], [400, 5]] }
Feb 21 2020