www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - cloning array

reply Sean <seany eclipso.de> writes:
Hello

I have seen this : 
https://forum.dlang.org/thread/1473526717.1917.20.camel winder.org.uk

Now, please consider this code:


import std.stdio;
import std.math;
import std.stdio;
import std.conv;
import std.format;
import std.math;
import std.algorithm;
import std.net.curl;
import std.json;
import std.path;
import std.array;
import std.net.curl;
import core.stdc.stdlib;
import std.datetime;
import std.file;





void main() {

         auto a = new double[][] (0,0);
         a ~= [ 1.0, 2.45];
         a ~= [ 4.9 ,28, 9];



         auto b = a.dup;

         a[1] = remove(a[1],1);

         writeln(b);
}



I compile with dmd version :

DMD64 D Compiler v2.096.1

Copyright (C) 1999-2021 by The D Language Foundation, All Rights 
Reserved written by Walter Bright


Output :


[[1, 2.45], [4.9, 9, 9]]


What I would expect :

[[1, 2.45], [4.9, 28, 9]], because i am copying the array `a` to 
a different place - at `b`.


Is this normal behavior of dup? if so, how can I get the behavior 
i am searching for? Thank you.
Jun 02 2021
next sibling parent reply Basile.B <b2.temp gmx.com> writes:
On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote:
 Hello

 I have seen this : 
 https://forum.dlang.org/thread/1473526717.1917.20.camel winder.org.uk

 Now, please consider this code:


 import std.stdio;
 import std.math;
 import std.stdio;
 import std.conv;
 import std.format;
 import std.math;
 import std.algorithm;
 import std.net.curl;
 import std.json;
 import std.path;
 import std.array;
 import std.net.curl;
 import core.stdc.stdlib;
 import std.datetime;
 import std.file;





 void main() {

         auto a = new double[][] (0,0);
         a ~= [ 1.0, 2.45];
         a ~= [ 4.9 ,28, 9];



         auto b = a.dup;

         a[1] = remove(a[1],1);

         writeln(b);
 }



 I compile with dmd version :

 DMD64 D Compiler v2.096.1

 Copyright (C) 1999-2021 by The D Language Foundation, All 
 Rights Reserved written by Walter Bright


 Output :


 [[1, 2.45], [4.9, 9, 9]]


 What I would expect :

 [[1, 2.45], [4.9, 28, 9]], because i am copying the array `a` 
 to a different place - at `b`.


 Is this normal behavior of dup? if so, how can I get the 
 behavior i am searching for? Thank you.
it's rather an unintuitive behavior. `.dup` is not a deep copy: --- import std; void main() { auto a = new double[][] (0,0); a ~= [ 1.0, 2.45]; a ~= [ 4.9 ,28, 9]; auto b = [a[0].dup, a[1].dup]; a[1] = remove(a[1],1); writeln(b); } --- works as you expect
Jun 02 2021
next sibling parent reply Basile.B <b2.temp gmx.com> writes:
On Wednesday, 2 June 2021 at 15:59:38 UTC, Basile.B wrote:
 On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote:
 works as you expect
On Wednesday, 2 June 2021 at 15:59:38 UTC, Basile.B wrote: ```d import std; void main() { auto a = new double[][] (0,0); a ~= [ 1.0, 2.45]; a ~= [ 4.9 ,28, 9]; auto b = [a[0].dup, a[1].dup]; a[1] = remove(a[1],1); writeln(b); } ``` works a expected. The reason why is that your array elements are fat pointers, so when you dup a, you dup some fats pointer, so you got the same elements as "a" but accessible from another chunck of memory.
Jun 02 2021
parent reply Gavin Ray <gavinray site.com> writes:
On Wednesday, 2 June 2021 at 16:07:35 UTC, Basile.B wrote:
 works a expected. The reason why is that your array elements 
 are fat pointers, so when you dup a, you dup some fats pointer, 
 so you got the same elements as "a" but accessible from another 
 chunck of memory.
Would it be worth modifying the docs for `.dup()` so that this behavior is clear? I would have been confused by this as well. It's probably a no-brainer if you understand general memory principles but not everyone does.
Jun 02 2021
parent Basile.B <b2.temp gmx.com> writes:
On Wednesday, 2 June 2021 at 16:50:16 UTC, Gavin Ray wrote:
 On Wednesday, 2 June 2021 at 16:07:35 UTC, Basile.B wrote:
 works a expected. The reason why is that your array elements 
 are fat pointers, so when you dup a, you dup some fats 
 pointer, so you got the same elements as "a" but accessible 
 from another chunck of memory.
Would it be worth modifying the docs for `.dup()` so that this behavior is clear?
yes, I think so, it's worth a dlang.org change.
 I would have been confused by this as well.
Me too actually. the reason why this did not work as expected was not immediate.
 It's probably a no-brainer if you understand general memory 
 principles but not everyone does.
Jun 02 2021
prev sibling parent reply Sean <seany eclipso.de> writes:
On Wednesday, 2 June 2021 at 15:59:38 UTC, Basile.B wrote:
 works as you expect
Okey, so I have to copy every (N-1) dimensional element - one after one - if the array is N dimensional, with N > 1, and repeat it for every element if they themselves are arrays with dimension M > 1 ? This becomes very difficult if we have large tensors, 16 - 85 dimensions ( I am doing AI with d ) and eash element itself is a dynamic array.
Jun 02 2021
parent reply Basile.B <b2.temp gmx.com> writes:
On Wednesday, 2 June 2021 at 16:08:14 UTC, Sean wrote:
 On Wednesday, 2 June 2021 at 15:59:38 UTC, Basile.B wrote:
 works as you expect
Okey, so I have to copy every (N-1) dimensional element - one after one - if the array is N dimensional, with N > 1, and repeat it for every element if they themselves are arrays with dimension M > 1 ? This becomes very difficult if we have large tensors, 16 - 85 dimensions ( I am doing AI with d ) and eash element itself is a dynamic array.
you should use library types for this kind of operations, for example they can provide virtually N dim arrays that are actually flattened. Maybe Mir would help.
Jun 02 2021
parent Sean <seany eclipso.de> writes:
On Wednesday, 2 June 2021 at 16:18:03 UTC, Basile.B wrote:
  Maybe Mir would help.
Tried. However, I am more of a mathematician, than a software developer. So writing my own code was easier than to follow through the design philosophy and internalize the idioms and styles of Mir. When this project is done, I will study Mir more in detail
Jun 02 2021
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/2/21 11:32 AM, Sean wrote:
 Is this normal behavior of dup? if so, how can I get the behavior i am 
 searching for? Thank you.
 
Yes. `dup` is a shallow copy. To get the behavior you want: ```d auto deepdup(T)(T[] arr) { import std.algorithm, std.array; static if(is(T == U[], U)) return arr.map!(x => .deepdup(x)).array; else return arr.dup; } // use like arr.deepdup where you would normally put arr.dup ``` Note that this is going to be pretty inefficient allocation-wise, but will work with minimal code. -Steve
Jun 02 2021
prev sibling next sibling parent reply Sean <seany eclipso.de> writes:
On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote:
 if so, how can I get the behavior i am searching for? Thank you.
My current solution, if anyone wonders : https://github.com/patefacio/d-help/blob/master/d-help/opmix/dup.d
Jun 02 2021
parent cc <cc nevernet.com> writes:
On Wednesday, 2 June 2021 at 17:50:13 UTC, Sean wrote:
 On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote:
 if so, how can I get the behavior i am searching for? Thank 
 you.
My current solution, if anyone wonders : https://github.com/patefacio/d-help/blob/master/d-help/opmix/dup.d
You may find the `hasIndirections` template from std.traits useful. ```d import std.traits : hasIndirections, ValueType; import std.range.primitives : ElementType; int[] a; int[][] b; int[string] x; int[][string] y; struct S { int s; } struct T { int[] t; } assert(!hasIndirections!( ElementType!(typeof(a)) )); assert( hasIndirections!( ElementType!(typeof(b)) )); assert(!hasIndirections!( ValueType!(typeof(x)) )); assert( hasIndirections!( ValueType!(typeof(y)) )); assert(!hasIndirections!S); assert( hasIndirections!T); ```
Jun 03 2021
prev sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote:
 ...
You can implement deep copy using template recursion: import std; T[] rdup(T : U[], U)(T[] duped) { return duped.map!(arr => arr.rdup).array; } T[] rdup(T)(T[] duped) { return duped.dup; } void main() { int[][][] dupeable = [[[1], [2]], [[3]]]; auto duped = dupeable.rdup; duped[0][0][0] = 9; writeln("Hello D-eep copy of ", dupeable, " to ", duped); } Best regards, Alexandru.
Jun 03 2021
parent Alain De Vos <devosalain ymail.com> writes:
```
import std.stdio;
void main(){
auto a=new int[][] (0,0);
a~=[1,2];
a~=[3,4];
auto b= a.dup;
a[0]=[5,6];
a[1][1]=7;
writeln(b);
}
```

Program above outputs [[1, 2], [3, 7]]
Which means a[1][1] and b[1][1] point to the same memory location.
But a[0] occupies a different memory location as b[0].
It is a shallow copy and is the expected behaviour.
Maybe there is need for a library function dupdeep ?
Jun 03 2021