carray-calculus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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