carray-calculus 1.0.0

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.
@@ -0,0 +1,357 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ carray/carray_interp.c
4
+
5
+ This file is part of Ruby/CArray extension library.
6
+ You can redistribute it and/or modify it under the terms of
7
+ the Ruby Licence.
8
+
9
+ Copyright (C) 2005 Hiroki Motoyoshi
10
+
11
+ ---------------------------------------------------------------------------- */
12
+
13
+ #include "ruby.h"
14
+ #include "carray.h"
15
+ #include <math.h>
16
+
17
+ static int
18
+ find_index (ca_size_t n, double *y, double yy, ca_size_t *major, double *frac)
19
+ {
20
+ ca_size_t a, b, c, x1;
21
+ double ya, yb, yc;
22
+ double y1, y2;
23
+
24
+ if ( yy <= y[0] ) {
25
+ x1 = 0;
26
+ goto label;
27
+ }
28
+
29
+ if ( yy >= y[n-1] ) {
30
+ x1 = n-2;
31
+ goto label;
32
+ }
33
+
34
+ /* check for equally spaced scale */
35
+
36
+ a = (ca_size_t)((yy-y[0])/(y[n-1]-y[0])*(n-1));
37
+
38
+ if ( a >= 0 && a < n-1 ) {
39
+ if ( (y[a] - yy) * (y[a+1] - yy) <= 0 ) {
40
+ x1 = a;
41
+ goto label;
42
+ }
43
+ }
44
+
45
+ /* binary section method */
46
+
47
+ a = 0;
48
+ b = n-1;
49
+
50
+ ya = y[a];
51
+ yb = y[b];
52
+
53
+ if ( ya > yb ) {
54
+ return -1; /* input scale array should have accending order */
55
+ }
56
+
57
+ while ( (b - a) >= 1 ) {
58
+ c = (a + b)/2;
59
+ yc = y[c];
60
+ if ( a == c ) {
61
+ break;
62
+ }
63
+
64
+ if ( yc == yy ) {
65
+ a = c;
66
+ break;
67
+ }
68
+ else if ( (ya - yy) * (yc - yy) <= 0 ) {
69
+ b = c;
70
+ yb = yc;
71
+ }
72
+ else {
73
+ a = c;
74
+ ya = yc;
75
+ }
76
+
77
+ if ( ya > yb ) {
78
+ return -1; /* input scale array should have accending order */
79
+ }
80
+ }
81
+
82
+ x1 = a;
83
+
84
+ label:
85
+
86
+ y1 = y[x1];
87
+ y2 = y[x1+1];
88
+
89
+ *major = x1;
90
+
91
+ if ( y2 - y1 == 0 ) {
92
+ *frac = 0.0;
93
+ }
94
+ else {
95
+ *frac = (yy-y1)/(y2-y1);
96
+ }
97
+
98
+ return 0;
99
+ }
100
+
101
+
102
+ /*
103
+
104
+ n-dimensional linear interpolation
105
+
106
+ y[i+fi, j+fj, ..., n+fn]
107
+
108
+ 1 1 1
109
+ = Sigma Sigma ... Sigma wi[si]*wj[sj]*...*wn[sn]*y[i+si,j+sj,...,n+sn]
110
+ si=0 sj=0 sn=0
111
+
112
+ i , j, ..., n : major integer value
113
+ fi, fj, ..., fn : fractional value
114
+
115
+ wi[0] = 1-fi, wj[0] = 1-fj, ..., wn[0] = 1-fn
116
+ wi[1] = fi, wj[1] = fj, ..., wn[1] = fn
117
+
118
+ */
119
+
120
+ static int
121
+ linear_interp_loop (CArray *ca, ca_size_t *major, double *frac,
122
+ int level, ca_size_t *idx, double wt, double *valp)
123
+ {
124
+ double tmp;
125
+
126
+ if ( level == ca->ndim-1 ) {
127
+
128
+ idx[level] = major[level];
129
+ ca_fetch_index(ca, idx, &tmp);
130
+ *valp += (1.0 - frac[level]) * wt * tmp;
131
+
132
+ idx[level] = major[level] + 1;
133
+ ca_fetch_index(ca, idx, &tmp);
134
+ *valp += frac[level] * wt * tmp;
135
+
136
+ }
137
+ else {
138
+
139
+ if ( frac[level] != 1.0 ) { /* condition for performance issue */
140
+ idx[level] = major[level];
141
+ linear_interp_loop(ca, major, frac,
142
+ level+1, idx, (1.0 - frac[level])*wt, valp);
143
+ }
144
+
145
+ if ( frac[level] != 0.0 ) { /* condition for performance issue */
146
+ idx[level] = major[level] + 1;
147
+ linear_interp_loop(ca, major, frac,
148
+ level+1, idx, frac[level]*wt, valp);
149
+ }
150
+
151
+ }
152
+
153
+ return 0;
154
+ }
155
+
156
+ static double
157
+ linear_interp (CArray *ca, ca_size_t *major, double *frac)
158
+ {
159
+ ca_size_t idx[CA_RANK_MAX];
160
+ double value = 0;
161
+ linear_interp_loop(ca, major, frac, 0, idx, 1, &value);
162
+ return value;
163
+ }
164
+
165
+ /*
166
+
167
+ If value[n] is NaN, the interpolation will be made for each index of the dimension n. So you must prepare the buffer sufficient to store these values.
168
+
169
+ */
170
+
171
+ static int
172
+ ca_interpolate_loop (CArray *ca, double **scale,
173
+ CArray **value,
174
+ ca_size_t *major, double *frac,
175
+ int level, double **dstp)
176
+ {
177
+ double val, frc;
178
+ ca_size_t maj;
179
+ ca_size_t i;
180
+
181
+ if ( level == ca->ndim-1 ) {
182
+ if ( ! value[level] ) {
183
+ for (i=0; i<ca->dim[level]; i++) {
184
+ major[level] = i;
185
+ frac[level] = 0.0;
186
+ **dstp = linear_interp(ca, major, frac);
187
+ *dstp += 1;
188
+ }
189
+ }
190
+ else {
191
+ for (i=0; i<value[level]->elements; i++) {
192
+ ca_fetch_addr(value[level], i, &val);
193
+ find_index(ca->dim[level], scale[level], val, &maj, &frc);
194
+ major[level] = maj;
195
+ frac[level] = frc;
196
+ **dstp = linear_interp(ca, major, frac);
197
+ *dstp += 1;
198
+ }
199
+ }
200
+ }
201
+ else {
202
+ if ( ! value[level] ) {
203
+ for (i=0; i<ca->dim[level]; i++) {
204
+ major[level] = i;
205
+ frac[level] = 0.0;
206
+ ca_interpolate_loop(ca, scale, value, major, frac, level+1, dstp);
207
+ }
208
+ }
209
+ else {
210
+ for (i=0; i<value[level]->elements; i++) {
211
+ ca_fetch_addr(value[level], i, &val);
212
+ find_index(ca->dim[level], scale[level], val, &maj, &frc);
213
+ major[level] = maj;
214
+ frac[level] = frc;
215
+ ca_interpolate_loop(ca, scale, value, major, frac, level+1, dstp);
216
+ }
217
+ }
218
+ }
219
+ return 0; /* normal exit */
220
+ }
221
+
222
+ int
223
+ ca_interpolate (CArray *ca, double **scale, CArray **value, double *outp)
224
+ {
225
+ ca_size_t major[CA_RANK_MAX];
226
+ double frac[CA_RANK_MAX];
227
+ int status;
228
+
229
+ status = ca_interpolate_loop(ca, scale, value, major, frac, 0, &outp);
230
+
231
+ return status;
232
+ }
233
+
234
+
235
+ static VALUE
236
+ rb_ca_interpolate_bilinear (int argc, VALUE *argv, volatile VALUE self)
237
+ {
238
+ volatile VALUE vscales, vvalues, vs, out;
239
+ CArray *ca, *co, *cs;
240
+ double *scales[CA_RANK_MAX];
241
+ CArray *values[CA_RANK_MAX];
242
+ CArray *scales_ca[CA_RANK_MAX];
243
+ int8_t out_ndim;
244
+ ca_size_t out_dim[CA_RANK_MAX];
245
+ int i;
246
+
247
+ rb_scan_args(argc, argv, "2", &vscales, &vvalues);
248
+
249
+ Check_Type(vscales, T_ARRAY);
250
+ Check_Type(vvalues, T_ARRAY);
251
+
252
+ if ( RARRAY_LEN(vscales) != RARRAY_LEN(vvalues) ) {
253
+ rb_raise(rb_eArgError, "invalid number of values or scales");
254
+ }
255
+
256
+ ca = ca_wrap_readonly(self, CA_DOUBLE);
257
+
258
+ if ( ca->ndim != RARRAY_LEN(vvalues) ) {
259
+ rb_raise(rb_eArgError, "invalid number of values");
260
+ }
261
+
262
+ for (i=0; i<ca->ndim; i++) {
263
+ vs = rb_ary_entry(vscales, i);
264
+ if ( NIL_P(vs) ) {
265
+ scales[i] = NULL;
266
+ }
267
+ else {
268
+ cs = ca_wrap_readonly(vs, CA_DOUBLE);
269
+ scales_ca[i] = cs;
270
+ ca_attach(cs);
271
+ scales[i] = (double *) cs->ptr;
272
+ rb_ary_store(vscales, i, vs);
273
+ }
274
+ }
275
+
276
+ out_ndim = 0;
277
+ for (i=0; i<ca->ndim; i++) {
278
+ vs = rb_ary_entry(vvalues, i);
279
+ if ( NIL_P(vs) ) {
280
+ out_dim[out_ndim++] = ca->dim[i];
281
+ values[i] = NULL;
282
+ }
283
+ else {
284
+ values[i] = ca_wrap_readonly(vs, CA_DOUBLE);
285
+ if ( values[i]->obj_type != CA_OBJ_SCALAR ) {
286
+ out_dim[out_ndim++] = values[i]->elements;
287
+ }
288
+ rb_ary_store(vvalues, i, vs);
289
+ }
290
+ }
291
+
292
+ if ( out_ndim == 0 ) {
293
+ out = rb_cscalar_new(CA_DOUBLE, 0, NULL);
294
+ }
295
+ else {
296
+ out = rb_carray_new(CA_DOUBLE, out_ndim, out_dim, 0, NULL);
297
+ }
298
+
299
+ Data_Get_Struct(out, CArray, co);
300
+
301
+ for (i=0; i<ca->ndim; i++) {
302
+ if ( values[i] ) {
303
+ ca_attach(values[i]);
304
+ }
305
+ }
306
+
307
+ ca_attach(ca);
308
+ ca_interpolate(ca, scales, values, (double*) co->ptr);
309
+ ca_detach(ca);
310
+
311
+ for (i=0; i<ca->ndim; i++) {
312
+ if ( values[i] ) {
313
+ ca_detach(values[i]);
314
+ }
315
+ if ( scales[i] ) {
316
+ ca_detach(scales_ca[i]);
317
+ }
318
+ }
319
+
320
+ if ( out_ndim == 0 ) {
321
+ return rb_ca_fetch_addr(out, 0);
322
+ }
323
+ else {
324
+ return out;
325
+ }
326
+ }
327
+
328
+ void
329
+ Init_carray_interpolate ()
330
+ {
331
+ rb_define_method(rb_cCArray, "interp_nd_linear",
332
+ rb_ca_interpolate_bilinear, -1);
333
+ }
334
+
335
+ /*
336
+
337
+ scales = [nil, nil, sza, vza, saz]
338
+ values = [nil, nil, 60, 60, 120]
339
+ brdf.interp_linear_nd(scales, values)
340
+
341
+ interp_1d_linear
342
+ interp_1d_parabolic
343
+ interp_1d_cubic
344
+ interp_1d_akima
345
+ interp_1d_akima2
346
+ interp_1d_curv
347
+
348
+ interp_2d_natgrid
349
+ interp_2d_fitpack
350
+ interp_nd_linear
351
+
352
+ gridding_2d_natgrid
353
+
354
+
355
+ */
356
+
357
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "mkmf"
2
+ require "carray/mkmf"
3
+
4
+ if have_carray()
5
+ create_makefile("carray_calculus")
6
+ end
7
+
data/ext/mkmf.log ADDED
@@ -0,0 +1,24 @@
1
+ have_header: checking for carray.h... -------------------- yes
2
+
3
+ "clang -o conftest -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0/x86_64-darwin16 -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0/ruby/backward -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0 -I. -I/Users/himotoyoshi/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/carray-1.5.0/lib -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include -I/usr/local/opt/qt/include: -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wno-tautological-compare -Wno-parentheses-equality -Wno-constant-logical-operand -Wno-self-assign -Wunused-variable -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens -pipe conftest.c -L. -L/Users/himotoyoshi/.rbenv/versions/2.4.2/lib -L/Users/himotoyoshi/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/carray-1.5.0/lib -L. -L/Users/himotoyoshi/.rbenv/versions/2.4.2/lib -L/usr/local/opt/qt/lib: -fstack-protector -L/usr/local/lib -lruby-static -framework CoreFoundation -lpthread -lgmp -ldl -lobjc "
4
+ ld: warning: directory not found for option '-L/usr/local/opt/qt/lib:'
5
+ checked program was:
6
+ /* begin */
7
+ 1: #include "ruby.h"
8
+ 2:
9
+ 3: int main(int argc, char **argv)
10
+ 4: {
11
+ 5: return 0;
12
+ 6: }
13
+ /* end */
14
+
15
+ "clang -E -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0/x86_64-darwin16 -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0/ruby/backward -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include/ruby-2.4.0 -I. -I/Users/himotoyoshi/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/carray-1.5.0/lib -I/Users/himotoyoshi/.rbenv/versions/2.4.2/include -I/usr/local/opt/qt/include: -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wno-tautological-compare -Wno-parentheses-equality -Wno-constant-logical-operand -Wno-self-assign -Wunused-variable -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens -pipe conftest.c -o conftest.i"
16
+ checked program was:
17
+ /* begin */
18
+ 1: #include "ruby.h"
19
+ 2:
20
+ 3: #include <carray.h>
21
+ /* end */
22
+
23
+ --------------------
24
+
@@ -0,0 +1,3 @@
1
+ require "carray"
2
+ require "carray_calculus"
3
+ require "carray-calculus/core"
@@ -0,0 +1,119 @@
1
+ # ----------------------------------------------------------------------------
2
+ #
3
+ # carray/base/calculus.rb
4
+ #
5
+ # This file is part of Ruby/CArray extension library.
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Ruby Licence.
8
+ #
9
+ # Copyright (C) 2005 Hiroki Motoyoshi
10
+ #
11
+ # ----------------------------------------------------------------------------
12
+
13
+ class CArray
14
+
15
+ def normalize (scale = nil)
16
+ if scale
17
+ return self / self.integrate(scale)
18
+ else
19
+ return self / self.sum
20
+ end
21
+ end
22
+
23
+ def normalize! (scale = nil)
24
+ self[] = normalize(scale)
25
+ return self
26
+ end
27
+
28
+ def solve (sc, val, type: "cubic", eps: 100 * Float::EPSILON)
29
+ func = self - val
30
+ list, output = [], []
31
+ (0...dim0-1).each do |i|
32
+ if func[i] == UNDEF
33
+ elsif func[i].abs < eps and not list.include?(i-1)
34
+ output.push(sc[i])
35
+ elsif func[i+1] == UNDEF
36
+ elsif i < dim0 - 1 and func[i]*func[i+1] < 0
37
+ list.push(i)
38
+ end
39
+ end
40
+ list.each do |i|
41
+ sx = CArray.double(4)
42
+ sy = CArray.double(4)
43
+ sx[0], sx[3] = sc[i], sc[i+1]
44
+ sy[0], sy[3] = func[i], func[i+1]
45
+ sx[1], sx[2] = (2.0*sx[0]+sx[3])/3.0, (sx[0]+2.0*sx[3])/3.0
46
+ sy[1], sy[2] = func.interpolate(sc, sx[1], type: type), func.interpolate(sc, sx[2], type: type)
47
+ output.push(sx.interpolate(sy, 0, type: type))
48
+ end
49
+ return output.uniq
50
+ end
51
+
52
+ def solve2 (sc, eps: 100 * Float::EPSILON)
53
+ retvals = []
54
+ self.dim1.times do |j|
55
+ func = self[nil,j].to_ca
56
+ list, output = [], []
57
+ (0...dim0-1).each do |i|
58
+ if func[i] == UNDEF
59
+ elsif func[i].abs < eps and not list.include?(i-1)
60
+ output.push(sc[i])
61
+ elsif func[i+1] == UNDEF
62
+ elsif i < dim0 - 1 and func[i]*func[i+1] < 0
63
+ list.push(i)
64
+ end
65
+ end
66
+ list.each do |i|
67
+ sx = CArray.double(4)
68
+ sy = CArray.double(4)
69
+ sx[0], sx[3] = sc[i], sc[i+1]
70
+ sy[0], sy[3] = func[i], func[i+1]
71
+ sx[1], sx[2] = (2*sx[0]+sx[3])/3, (sx[0]+2*sx[3])/3
72
+ sy[1], sy[2] = func.interpolate(sc, sx[1], :type=>"linear"), func.interpolate(sc, sx[2], :type=>"linear")
73
+ output.push(sx.interpolate(sy, 0))
74
+ end
75
+ retvals << output.uniq
76
+ end
77
+ retvals = retvals.map{|s| s.empty? ? [nil] : s}
78
+ return retvals
79
+ end
80
+
81
+ private
82
+
83
+ def _interpolate2 (x, y, x0, y0)
84
+ case x.size
85
+ when 1
86
+ return self[0, nil].interpolate(y, y0)
87
+ when 2, 3
88
+ return self[:i,nil].interpolate(y, y0).interpolate(x, x0)
89
+ end
90
+ ri = x.section(x0)
91
+ i0 = ri.floor - 1
92
+ if i0 < 0
93
+ i0 = 0
94
+ elsif i0 + 3 > x.size - 1
95
+ i0 = x.size - 4
96
+ end
97
+ return self[i0..i0+3,nil][:i,nil].interpolate(y, y0).
98
+ interpolate(x[i0..i0+3],x0)
99
+ end
100
+
101
+ public
102
+
103
+ def interpolate2 (x, y, x0, y0)
104
+ if x0.is_a?(Numeric) and y0.is_a?(Numeric)
105
+ return _interpolate2(x, y, x0, y0)
106
+ else
107
+ x0 = CArray.wrap_readonly(x0)
108
+ y0 = CArray.wrap_readonly(y0)
109
+ out = CArray.double(x0.size, y0.size)
110
+ x0.each_with_index do |xi, i|
111
+ y0.each_with_index do |yj, j|
112
+ out[i,j] = _interpolate2(x, y, xi, yj)
113
+ end
114
+ end
115
+ return out.compact
116
+ end
117
+ end
118
+
119
+ end