cumo 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +18 -37
  3. data/3rd_party/mkmf-cu/lib/mkmf-cu/cli.rb +28 -21
  4. data/CHANGELOG.md +28 -0
  5. data/Dockerfile +34 -0
  6. data/cumo.gemspec +1 -1
  7. data/docker-build.sh +4 -0
  8. data/docker-launch.sh +4 -0
  9. data/docs/src-tree.md +1 -1
  10. data/ext/cumo/cuda/cudnn_impl.cpp +25 -3
  11. data/ext/cumo/cuda/driver.c +8 -0
  12. data/ext/cumo/depend.erb +1 -1
  13. data/ext/cumo/extconf.rb +1 -1
  14. data/ext/cumo/include/cumo/cuda/cumo_thrust.hpp +14 -7
  15. data/ext/cumo/include/cumo/cuda/cumo_thrust_complex.hpp +3 -3
  16. data/ext/cumo/include/cumo/narray.h +2 -0
  17. data/ext/cumo/include/cumo/types/complex.h +2 -2
  18. data/ext/cumo/include/cumo/types/complex_macro_kernel.h +15 -4
  19. data/ext/cumo/include/cumo/types/real_accum_kernel.h +15 -4
  20. data/ext/cumo/include/cumo/types/xint_macro_kernel.h +11 -3
  21. data/ext/cumo/include/cumo.h +2 -2
  22. data/ext/cumo/narray/array.c +5 -3
  23. data/ext/cumo/narray/data.c +25 -26
  24. data/ext/cumo/narray/gen/tmpl/accum.c +2 -2
  25. data/ext/cumo/narray/gen/tmpl/accum_binary.c +1 -1
  26. data/ext/cumo/narray/gen/tmpl/alloc_func.c +4 -1
  27. data/ext/cumo/narray/gen/tmpl/allocate.c +1 -0
  28. data/ext/cumo/narray/gen/tmpl/aref.c +18 -18
  29. data/ext/cumo/narray/gen/tmpl/aset.c +16 -16
  30. data/ext/cumo/narray/gen/tmpl/batch_norm.c +4 -1
  31. data/ext/cumo/narray/gen/tmpl/batch_norm_backward.c +4 -1
  32. data/ext/cumo/narray/gen/tmpl/bincount.c +7 -7
  33. data/ext/cumo/narray/gen/tmpl/clip.c +11 -15
  34. data/ext/cumo/narray/gen/tmpl/complex_accum_kernel.cu +12 -12
  35. data/ext/cumo/narray/gen/tmpl/cum.c +1 -1
  36. data/ext/cumo/narray/gen/tmpl/each.c +4 -2
  37. data/ext/cumo/narray/gen/tmpl/each_with_index.c +5 -2
  38. data/ext/cumo/narray/gen/tmpl/fixed_batch_norm.c +4 -1
  39. data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +12 -12
  40. data/ext/cumo/narray/gen/tmpl/logseq.c +6 -5
  41. data/ext/cumo/narray/gen/tmpl/map_with_index.c +5 -6
  42. data/ext/cumo/narray/gen/tmpl/median.c +2 -2
  43. data/ext/cumo/narray/gen/tmpl/minmax.c +1 -1
  44. data/ext/cumo/narray/gen/tmpl/poly.c +4 -4
  45. data/ext/cumo/narray/gen/tmpl/rand.c +8 -6
  46. data/ext/cumo/narray/gen/tmpl/rand_norm.c +18 -16
  47. data/ext/cumo/narray/gen/tmpl/seq.c +5 -4
  48. data/ext/cumo/narray/gen/tmpl/sort.c +2 -2
  49. data/ext/cumo/narray/gen/tmpl/sort_index.c +2 -2
  50. data/ext/cumo/narray/gen/tmpl_bit/allocate.c +1 -0
  51. data/ext/cumo/narray/gen/tmpl_bit/aref.c +26 -32
  52. data/ext/cumo/narray/gen/tmpl_bit/aset.c +18 -30
  53. data/ext/cumo/narray/index.c +1 -1
  54. data/ext/cumo/narray/narray.c +116 -21
  55. data/lib/cumo/narray/extra.rb +160 -156
  56. data/test/cuda/device_test.rb +2 -1
  57. data/test/cudnn_test.rb +2 -2
  58. data/test/narray_test.rb +80 -0
  59. data/test/ractor_test.rb +5 -3
  60. metadata +5 -2
@@ -18,10 +18,10 @@ static void
18
18
  }
19
19
 
20
20
  /*
21
- Polynomial.: a0 + a1*x + a2*x**2 + a3*x**3 + ... + an*x**n
22
- @overload <%=name%> a0, a1, ...
23
- @param [Cumo::NArray,Numeric] a0
24
- @param [Cumo::NArray,Numeric] a1 , ...
21
+ Calculate polynomial.
22
+ `x.poly(a0,a1,a2,...,an) = a0 + a1*x + a2*x**2 + ... + an*x**n`
23
+ @overload <%=name%> a0, a1, ..., an
24
+ @param [Cumo::NArray,Numeric] a0,a1,...,an
25
25
  @return [Cumo::<%=class_name%>]
26
26
  */
27
27
  static VALUE
@@ -115,14 +115,16 @@ static void
115
115
  @return [Cumo::<%=class_name%>] self.
116
116
  @example
117
117
  Cumo::DFloat.new(6).rand
118
- => Cumo::DFloat#shape=[6]
119
- [0.0617545, 0.373067, 0.794815, 0.201042, 0.116041, 0.344032]
118
+ # => Cumo::DFloat#shape=[6]
119
+ # [0.0617545, 0.373067, 0.794815, 0.201042, 0.116041, 0.344032]
120
+
120
121
  Cumo::DComplex.new(6).rand(5+5i)
121
- => Cumo::DComplex#shape=[6]
122
- [2.69974+3.68908i, 0.825443+0.254414i, 0.540323+0.34354i, 4.52061+2.39322i, ...]
122
+ # => Cumo::DComplex#shape=[6]
123
+ # [2.69974+3.68908i, 0.825443+0.254414i, 0.540323+0.34354i, 4.52061+2.39322i, ...]
124
+
123
125
  Cumo::Int32.new(6).rand(2,5)
124
- => Cumo::Int32#shape=[6]
125
- [4, 3, 3, 2, 4, 2]
126
+ # => Cumo::Int32#shape=[6]
127
+ # [4, 3, 3, 2, 4, 2]
126
128
  */
127
129
  static VALUE
128
130
  <%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
@@ -77,24 +77,26 @@ static void
77
77
  @return [Cumo::<%=class_name%>] self.
78
78
  @example
79
79
  Cumo::DFloat.new(5,5).rand_norm
80
- => Cumo::DFloat#shape=[5,5]
81
- [[-0.581255, -0.168354, 0.586895, -0.595142, -0.802802],
82
- [-0.326106, 0.282922, 1.68427, 0.918499, -0.0485384],
83
- [-0.464453, -0.992194, 0.413794, -0.60717, -0.699695],
84
- [-1.64168, 0.48676, -0.875871, -1.43275, 0.812172],
85
- [-0.209975, -0.103612, -0.878617, -1.42495, 1.0968]]
80
+ # => Cumo::DFloat#shape=[5,5]
81
+ # [[-0.581255, -0.168354, 0.586895, -0.595142, -0.802802],
82
+ # [-0.326106, 0.282922, 1.68427, 0.918499, -0.0485384],
83
+ # [-0.464453, -0.992194, 0.413794, -0.60717, -0.699695],
84
+ # [-1.64168, 0.48676, -0.875871, -1.43275, 0.812172],
85
+ # [-0.209975, -0.103612, -0.878617, -1.42495, 1.0968]]
86
+
86
87
  Cumo::DFloat.new(5,5).rand_norm(10,0.1)
87
- => Cumo::DFloat#shape=[5,5]
88
- [[9.9019, 9.90339, 10.0826, 9.98384, 9.72861],
89
- [9.81507, 10.0272, 9.91445, 10.0568, 9.88923],
90
- [10.0234, 9.97874, 9.96011, 9.9006, 9.99964],
91
- [10.0186, 9.94598, 9.92236, 9.99811, 9.97003],
92
- [9.79266, 9.95044, 9.95212, 9.93692, 10.2027]]
88
+ # => Cumo::DFloat#shape=[5,5]
89
+ # [[9.9019, 9.90339, 10.0826, 9.98384, 9.72861],
90
+ # [9.81507, 10.0272, 9.91445, 10.0568, 9.88923],
91
+ # [10.0234, 9.97874, 9.96011, 9.9006, 9.99964],
92
+ # [10.0186, 9.94598, 9.92236, 9.99811, 9.97003],
93
+ # [9.79266, 9.95044, 9.95212, 9.93692, 10.2027]]
94
+
93
95
  Cumo::DComplex.new(3,3).rand_norm(5+5i)
94
- => Cumo::DComplex#shape=[3,3]
95
- [[5.84303+4.40052i, 4.00984+6.08982i, 5.10979+5.13215i],
96
- [4.26477+3.99655i, 4.90052+5.00763i, 4.46607+2.3444i],
97
- [4.5528+7.11003i, 5.62117+6.69094i, 5.05443+5.35133i]]
96
+ # => Cumo::DComplex#shape=[3,3]
97
+ # [[5.84303+4.40052i, 4.00984+6.08982i, 5.10979+5.13215i],
98
+ # [4.26477+3.99655i, 4.90052+5.00763i, 4.46607+2.3444i],
99
+ # [4.5528+7.11003i, 5.62117+6.69094i, 5.05443+5.35133i]]
98
100
  */
99
101
  static VALUE
100
102
  <%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
@@ -80,11 +80,12 @@ static void
80
80
  @return [Cumo::<%=class_name%>] self.
81
81
  @example
82
82
  Cumo::DFloat.new(6).seq(1,-0.2)
83
- => Cumo::DFloat#shape=[6]
84
- [1, 0.8, 0.6, 0.4, 0.2, 0]
83
+ # => Cumo::DFloat#shape=[6]
84
+ # [1, 0.8, 0.6, 0.4, 0.2, 0]
85
+
85
86
  Cumo::DComplex.new(6).seq(1,-0.2+0.2i)
86
- => Cumo::DComplex#shape=[6]
87
- [1+0i, 0.8+0.2i, 0.6+0.4i, 0.4+0.6i, 0.2+0.8i, 0+1i]
87
+ # => Cumo::DComplex#shape=[6]
88
+ # [1+0i, 0.8+0.2i, 0.6+0.4i, 0.4+0.6i, 0.2+0.8i, 0+1i]
88
89
  */
89
90
  static VALUE
90
91
  <%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
@@ -22,10 +22,10 @@ static void
22
22
  <% else %>
23
23
  @overload <%=name%>(axis:nil)
24
24
  <% end %>
25
- @param [Numeric,Array,Range] axis Affected dimensions.
25
+ @param [Numeric,Array,Range] axis Performs <%=name%> along the axis.
26
26
  @return [Cumo::<%=class_name%>] returns result of <%=name%>.
27
27
  @example
28
- Cumo::DFloat[3,4,1,2].sort => Cumo::DFloat[1,2,3,4]
28
+ Cumo::DFloat[3,4,1,2].sort # => Cumo::DFloat[1,2,3,4]
29
29
  */
30
30
  static VALUE
31
31
  <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
@@ -52,10 +52,10 @@ static void
52
52
  <% else %>
53
53
  @overload <%=name%>(axis:nil)
54
54
  <% end %>
55
- @param [Numeric,Array,Range] axis Affected dimensions.
55
+ @param [Numeric,Array,Range] axis Performs <%=name%> along the axis.
56
56
  @return [Integer,Cumo::Int] returns result index of <%=name%>.
57
57
  @example
58
- Cumo::NArray[3,4,1,2].sort_index => Cumo::Int32[2,3,0,1]
58
+ Cumo::NArray[3,4,1,2].sort_index # => Cumo::Int32[2,3,0,1]
59
59
  */
60
60
  static VALUE
61
61
  <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
@@ -12,6 +12,7 @@ static VALUE
12
12
  if (na->size > 0 && ptr == NULL) {
13
13
  ptr = cumo_cuda_runtime_malloc(((na->size-1)/8/sizeof(CUMO_BIT_DIGIT)+1)*sizeof(CUMO_BIT_DIGIT));
14
14
  CUMO_NA_DATA_PTR(na) = ptr;
15
+ CUMO_NA_DATA_OWNED(na) = TRUE;
15
16
  }
16
17
  break;
17
18
  case CUMO_NARRAY_VIEW_T:
@@ -2,42 +2,36 @@ static VALUE
2
2
  <%=c_func(-1)%>_cpu(int argc, VALUE *argv, VALUE self);
3
3
 
4
4
  /*
5
- Array element referenece or slice view.
5
+ Array indexing.
6
6
  @overload [](dim0,...,dimL)
7
- @param [Numeric,Range,etc] dim0,...,dimL Multi-dimensional Index.
8
- @return [Numeric,NArray::<%=class_name%>] Element object or NArray view.
7
+ @param [Numeric,Range,Array,Cumo::Bit,Cumo::Int32,Cumo::Int64] dim0,...,dimL Multi-dimensional Index.
8
+ @return [Cumo::Bit,Numeric] Element value or NArray view.
9
9
 
10
- --- Returns the element at +dim0+, +dim1+, ... are Numeric indices
11
- for each dimension, or returns a NArray View as a sliced subarray if
12
- +dim0+, +dim1+, ... includes other than Numeric index, e.g., Range
13
- or Array or true.
10
+ --- Returns an element at `dim0`, `dim1`, ... are Numeric indices for each dimension, or returns a NArray View as a sliced array if `dim0`, `dim1`, ... includes other than Numeric index, e.g., Range or Array or true.
11
+
12
+ @see #[]=
14
13
 
15
14
  @example
16
- a = Cumo::DFloat.new(4,5).seq
17
- => Cumo::DFloat#shape=[4,5]
18
- [[0, 1, 2, 3, 4],
19
- [5, 6, 7, 8, 9],
20
- [10, 11, 12, 13, 14],
21
- [15, 16, 17, 18, 19]]
22
-
23
- a[1,1]
24
- => 6.0
25
-
26
- a[1..3,1]
27
- => Cumo::DFloat#shape=[3]
28
- [6, 11, 16]
29
-
30
- a[1,[1,3,4]]
31
- => Cumo::DFloat#shape=[3]
32
- [6, 8, 9]
33
-
34
- a[true,2].fill(99)
35
- a
36
- => Cumo::DFloat#shape=[4,5]
37
- [[0, 1, 99, 3, 4],
38
- [5, 6, 99, 8, 9],
39
- [10, 11, 99, 13, 14],
40
- [15, 16, 99, 18, 19]]
15
+ a = Cumo::Int32.new(3,4).seq
16
+ # => Cumo::Int32#shape=[3,4]
17
+ # [[0, 1, 2, 3],
18
+ # [4, 5, 6, 7],
19
+ # [8, 9, 10, 11]]
20
+
21
+ b = (a%2).eq(0)
22
+ # => Cumo::Bit#shape=[3,4]
23
+ # [[1, 0, 1, 0],
24
+ # [1, 0, 1, 0],
25
+ # [1, 0, 1, 0]]
26
+
27
+ b[true,(0..-1)%2]
28
+ # => Cumo::Bit(view)#shape=[3,2]
29
+ # [[1, 1],
30
+ # [1, 1],
31
+ # [1, 1]]
32
+
33
+ b[1,1]
34
+ # => 0
41
35
  */
42
36
  static VALUE
43
37
  <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
@@ -1,41 +1,29 @@
1
1
  /*
2
- Array element(s) set.
2
+ Array element(s) assignment.
3
3
  @overload []=(dim0,..,dimL,val)
4
- @param [Numeric,Range,etc] dim0,..,dimL Multi-dimensional Index.
4
+ @param [Numeric,Range,Array,Cumo::Bit,Cumo::Int32,Cumo::Int64] dim0,..,dimL Multi-dimensional Index.
5
5
  @param [Numeric,Cumo::NArray,etc] val Value(s) to be set to self.
6
- @return [Numeric] returns val (last argument).
6
+ @return [Numeric] returns `val` (last argument).
7
7
 
8
- --- Replace element(s) at +dim0+, +dim1+, ... (index/range/array/true
9
- for each dimention). Broadcasting mechanism is applied.
8
+ Replaces element(s) at `dim0`, `dim1`, ... . Broadcasting mechanism is applied.
10
9
 
11
- @example
12
- a = Cumo::DFloat.new(3,4).seq
13
- => Cumo::DFloat#shape=[3,4]
14
- [[0, 1, 2, 3],
15
- [4, 5, 6, 7],
16
- [8, 9, 10, 11]]
17
-
18
- a[1,2]=99
19
- a
20
- => Cumo::DFloat#shape=[3,4]
21
- [[0, 1, 2, 3],
22
- [4, 5, 99, 7],
23
- [8, 9, 10, 11]]
10
+ @see #[]
24
11
 
25
- a[1,[0,2]] = [101,102]
26
- a
27
- => Cumo::DFloat#shape=[3,4]
28
- [[0, 1, 2, 3],
29
- [101, 5, 102, 7],
30
- [8, 9, 10, 11]]
12
+ @example
13
+ a = Cumo::Bit.new(4,5).fill(0)
14
+ # => Cumo::Bit#shape=[4,5]
15
+ # [[0, 0, 0, 0, 0],
16
+ # [0, 0, 0, 0, 0],
17
+ # [0, 0, 0, 0, 0],
18
+ # [0, 0, 0, 0, 0]]
31
19
 
32
- a[1,true]=99
20
+ a[(0..-1)%2,(1..-1)%2] = 1
33
21
  a
34
- => Cumo::DFloat#shape=[3,4]
35
- [[0, 1, 2, 3],
36
- [99, 99, 99, 99],
37
- [8, 9, 10, 11]]
38
-
22
+ # => Cumo::Bit#shape=[4,5]
23
+ # [[0, 1, 0, 1, 0],
24
+ # [0, 0, 0, 0, 0],
25
+ # [0, 1, 0, 1, 0],
26
+ # [0, 0, 0, 0, 0]]
39
27
  */
40
28
  static VALUE
41
29
  <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
@@ -799,7 +799,7 @@ VALUE cumo_na_aref_md_protected(VALUE data_value)
799
799
  int keep_dim = data->keep_dim;
800
800
  int at_mode = data->at_mode;
801
801
 
802
- int ndim_new;
802
+ size_t ndim_new;
803
803
  VALUE view;
804
804
  cumo_narray_view_t *na2;
805
805
  ssize_t elmsz;
@@ -34,6 +34,7 @@ static ID cumo_id_count_false_cpu;
34
34
  static ID cumo_id_axis;
35
35
  static ID cumo_id_nan;
36
36
  static ID cumo_id_keepdims;
37
+ static ID cumo_id_source;
37
38
 
38
39
  VALUE cumo_sym_reduce;
39
40
  VALUE cumo_sym_option;
@@ -324,19 +325,19 @@ cumo_na_setup(VALUE self, int ndim, size_t *shape)
324
325
 
325
326
  @example
326
327
  i = Cumo::Int64.new([2,4,3])
327
- #=> Cumo::Int64#shape=[2,4,3](empty)
328
+ # => Cumo::Int64#shape=[2,4,3](empty)
328
329
 
329
330
  f = Cumo::DFloat.new(3,4)
330
- #=> Cumo::DFloat#shape=[3,4](empty)
331
+ # => Cumo::DFloat#shape=[3,4](empty)
331
332
 
332
333
  f.fill(2)
333
- #=> Cumo::DFloat#shape=[3,4]
334
+ # => Cumo::DFloat#shape=[3,4]
334
335
  # [[2, 2, 2, 2],
335
336
  # [2, 2, 2, 2],
336
337
  # [2, 2, 2, 2]]
337
338
 
338
339
  x = Cumo::NArray.new(5)
339
- #=> in `new': allocator undefined for Cumo::NArray (TypeError)
340
+ # => in `new': allocator undefined for Cumo::NArray (TypeError)
340
341
  # from t.rb:9:in `<main>'
341
342
 
342
343
  */
@@ -420,10 +421,10 @@ cumo_na_initialize_copy(VALUE self, VALUE orig)
420
421
  * but for typed NArray subclasses, e.g., DFloat, Int64.
421
422
  * @example
422
423
  * a = Cumo::DFloat.zeros(3,5)
423
- * => Cumo::DFloat#shape=[3,5]
424
- * [[0, 0, 0, 0, 0],
425
- * [0, 0, 0, 0, 0],
426
- * [0, 0, 0, 0, 0]]
424
+ * # => Cumo::DFloat#shape=[3,5]
425
+ * # [[0, 0, 0, 0, 0],
426
+ * # [0, 0, 0, 0, 0],
427
+ * # [0, 0, 0, 0, 0]]
427
428
  */
428
429
  static VALUE
429
430
  cumo_na_s_zeros(int argc, VALUE *argv, VALUE klass)
@@ -471,8 +472,8 @@ cumo_na_s_ones(int argc, VALUE *argv, VALUE klass)
471
472
 
472
473
  @example
473
474
  a = Cumo::DFloat.linspace(-5,5,7)
474
- => Cumo::DFloat#shape=[7]
475
- [-5, -3.33333, -1.66667, 0, 1.66667, 3.33333, 5]
475
+ # => Cumo::DFloat#shape=[7]
476
+ # [-5, -3.33333, -1.66667, 0, 1.66667, 3.33333, 5]
476
477
  */
477
478
  static VALUE
478
479
  cumo_na_s_linspace(int argc, VALUE *argv, VALUE klass)
@@ -510,11 +511,12 @@ cumo_na_s_linspace(int argc, VALUE *argv, VALUE klass)
510
511
 
511
512
  @example
512
513
  Cumo::DFloat.logspace(4,0,5,2)
513
- => Cumo::DFloat#shape=[5]
514
- [16, 8, 4, 2, 1]
514
+ # => Cumo::DFloat#shape=[5]
515
+ # [16, 8, 4, 2, 1]
516
+
515
517
  Cumo::DComplex.logspace(0,1i*Math::PI,5,Math::E)
516
- => Cumo::DComplex#shape=[5]
517
- [1+4.44659e-323i, 0.707107+0.707107i, 6.12323e-17+1i, -0.707107+0.707107i, ...]
518
+ # => Cumo::DComplex#shape=[5]
519
+ # [1+4.44659e-323i, 0.707107+0.707107i, 6.12323e-17+1i, -0.707107+0.707107i, ...]
518
520
  */
519
521
  static VALUE
520
522
  cumo_na_s_logspace(int argc, VALUE *argv, VALUE klass)
@@ -548,10 +550,10 @@ cumo_na_s_logspace(int argc, VALUE *argv, VALUE klass)
548
550
  @return [Cumo::NArray] created NArray.
549
551
  @example
550
552
  a = Cumo::DFloat.eye(3)
551
- => Cumo::DFloat#shape=[3,3]
552
- [[1, 0, 0],
553
- [0, 1, 0],
554
- [0, 0, 1]]
553
+ # => Cumo::DFloat#shape=[3,3]
554
+ # [[1, 0, 0],
555
+ # [0, 1, 0],
556
+ # [0, 0, 1]]
555
557
  */
556
558
  static VALUE
557
559
  cumo_na_s_eye(int argc, VALUE *argv, VALUE klass)
@@ -576,6 +578,87 @@ cumo_na_s_eye(int argc, VALUE *argv, VALUE klass)
576
578
  #define READ 1
577
579
  #define WRITE 2
578
580
 
581
+ static void
582
+ cumo_na_set_pointer(VALUE self, char *ptr, size_t byte_size)
583
+ {
584
+ VALUE obj;
585
+ cumo_narray_t *na;
586
+
587
+ if (OBJ_FROZEN(self)) {
588
+ rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
589
+ }
590
+
591
+ CumoGetNArray(self,na);
592
+
593
+ switch(CUMO_NA_TYPE(na)) {
594
+ case CUMO_NARRAY_DATA_T:
595
+ if (CUMO_NA_SIZE(na) > 0) {
596
+ if (CUMO_NA_DATA_PTR(na) != NULL && CUMO_NA_DATA_OWNED(na)) {
597
+ xfree(CUMO_NA_DATA_PTR(na));
598
+ }
599
+ CUMO_NA_DATA_PTR(na) = ptr;
600
+ CUMO_NA_DATA_OWNED(na) = FALSE;
601
+ }
602
+ return;
603
+ case CUMO_NARRAY_VIEW_T:
604
+ obj = CUMO_NA_VIEW_DATA(na);
605
+ if (OBJ_FROZEN(obj)) {
606
+ rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
607
+ }
608
+ CumoGetNArray(obj,na);
609
+ switch(CUMO_NA_TYPE(na)) {
610
+ case CUMO_NARRAY_DATA_T:
611
+ if (CUMO_NA_SIZE(na) > 0) {
612
+ if (CUMO_NA_DATA_PTR(na) != NULL && CUMO_NA_DATA_OWNED(na)) {
613
+ xfree(CUMO_NA_DATA_PTR(na));
614
+ }
615
+ CUMO_NA_DATA_PTR(na) = ptr;
616
+ CUMO_NA_DATA_OWNED(na) = FALSE;
617
+ }
618
+ return;
619
+ default:
620
+ rb_raise(rb_eRuntimeError,"invalid NA_TYPE of view: %d",CUMO_NA_TYPE(na));
621
+ }
622
+ default:
623
+ rb_raise(rb_eRuntimeError,"invalid NA_TYPE: %d",CUMO_NA_TYPE(na));
624
+ }
625
+ }
626
+
627
+ static void
628
+ cumo_na_pointer_copy_on_write(VALUE self)
629
+ {
630
+ cumo_narray_t *na;
631
+ void *ptr;
632
+ VALUE velmsz;
633
+ size_t byte_size;
634
+
635
+ CumoGetNArray(self,na);
636
+ if (CUMO_NA_TYPE(na) == CUMO_NARRAY_VIEW_T) {
637
+ self = CUMO_NA_VIEW_DATA(na);
638
+ CumoGetNArray(self,na);
639
+ }
640
+
641
+ ptr = CUMO_NA_DATA_PTR(na);
642
+ if (ptr == NULL) {
643
+ return;
644
+ }
645
+
646
+ if (CUMO_NA_DATA_OWNED(na)) {
647
+ return;
648
+ }
649
+
650
+ velmsz = rb_const_get(rb_obj_class(self), cumo_id_element_byte_size);
651
+ if (FIXNUM_P(velmsz)) {
652
+ byte_size = CUMO_NA_SIZE(na) * NUM2SIZET(velmsz);
653
+ } else {
654
+ byte_size = ceil(CUMO_NA_SIZE(na) * NUM2DBL(velmsz));
655
+ }
656
+ CUMO_NA_DATA_PTR(na) = NULL;
657
+ rb_funcall(self, cumo_id_allocate, 0);
658
+ memcpy(CUMO_NA_DATA_PTR(na), ptr, byte_size);
659
+ rb_ivar_set(self, cumo_id_source, Qnil);
660
+ }
661
+
579
662
  static char *
580
663
  cumo_na_get_pointer_for_rw(VALUE self, int flag)
581
664
  {
@@ -591,6 +674,9 @@ cumo_na_get_pointer_for_rw(VALUE self, int flag)
591
674
 
592
675
  switch(CUMO_NA_TYPE(na)) {
593
676
  case CUMO_NARRAY_DATA_T:
677
+ if (flag & WRITE) {
678
+ cumo_na_pointer_copy_on_write(self);
679
+ }
594
680
  ptr = CUMO_NA_DATA_PTR(na);
595
681
  if (CUMO_NA_SIZE(na) > 0 && ptr == NULL) {
596
682
  if (flag & READ) {
@@ -607,6 +693,9 @@ cumo_na_get_pointer_for_rw(VALUE self, int flag)
607
693
  if ((flag & WRITE) && OBJ_FROZEN(obj)) {
608
694
  rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
609
695
  }
696
+ if (flag & WRITE) {
697
+ cumo_na_pointer_copy_on_write(self);
698
+ }
610
699
  CumoGetNArray(obj,na);
611
700
  switch(CUMO_NA_TYPE(na)) {
612
701
  case CUMO_NARRAY_DATA_T:
@@ -1312,7 +1401,6 @@ static VALUE
1312
1401
  cumo_na_store_binary(int argc, VALUE *argv, VALUE self)
1313
1402
  {
1314
1403
  size_t size, str_len, byte_size, offset;
1315
- char *ptr;
1316
1404
  int narg;
1317
1405
  VALUE vstr, voffset;
1318
1406
  VALUE velmsz;
@@ -1342,8 +1430,13 @@ cumo_na_store_binary(int argc, VALUE *argv, VALUE self)
1342
1430
  rb_raise(rb_eArgError, "string is too short to store");
1343
1431
  }
1344
1432
 
1345
- ptr = cumo_na_get_pointer_for_write(self);
1346
- memcpy(ptr, RSTRING_PTR(vstr)+offset, byte_size);
1433
+ if (OBJ_FROZEN(vstr)) {
1434
+ cumo_na_set_pointer(self, RSTRING_PTR(vstr)+offset, byte_size);
1435
+ rb_ivar_set(self, cumo_id_source, vstr);
1436
+ } else {
1437
+ void *ptr = cumo_na_get_pointer_for_write(self);
1438
+ memcpy(ptr, RSTRING_PTR(vstr)+offset, byte_size);
1439
+ }
1347
1440
 
1348
1441
  return SIZET2NUM(byte_size);
1349
1442
  }
@@ -1455,6 +1548,7 @@ cumo_na_marshal_load(VALUE self, VALUE a)
1455
1548
  ptr = cumo_na_get_pointer_for_write(self);
1456
1549
  memcpy(ptr, RARRAY_PTR(v), CUMO_NA_SIZE(na)*sizeof(VALUE));
1457
1550
  } else {
1551
+ rb_str_freeze(v);
1458
1552
  cumo_na_store_binary(1,&v,self);
1459
1553
  if (CUMO_TEST_BYTE_SWAPPED(self)) {
1460
1554
  rb_funcall(cumo_na_inplace(self),cumo_id_to_host,0);
@@ -2022,6 +2116,7 @@ Init_cumo_narray()
2022
2116
  cumo_id_axis = rb_intern("axis");
2023
2117
  cumo_id_nan = rb_intern("nan");
2024
2118
  cumo_id_keepdims = rb_intern("keepdims");
2119
+ cumo_id_source = rb_intern("source");
2025
2120
 
2026
2121
  cumo_sym_reduce = ID2SYM(rb_intern("reduce"));
2027
2122
  cumo_sym_option = ID2SYM(rb_intern("option"));