spatial_stats 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c754e131546cc4aa0bcb8ba0cadc2dc1230d5e6c08a29f142e3e3692ef8da02d
4
- data.tar.gz: 05a6a60a79bc29f93586a53f6c60856b885e97331f34b3791f4ea76a1af8dd4a
3
+ metadata.gz: '08787d83d402843b9d711fd88cdc5f22cbdacfb7a960d8bdb185591f10215f85'
4
+ data.tar.gz: 96241b1ef7099ce6371f24dee56258121e0d6686ec746ac0411c4ed8ccaf5cad
5
5
  SHA512:
6
- metadata.gz: 1ff203ee049060a41843cc463bcac36db59ab2b697dbef7a6a671fc70b316e66f5e65d1bb40d3a4a3604f68e9697330b26c505c3ca3304beacd5b2ced8b1b2be
7
- data.tar.gz: dc66e81605de0b33871376858a097294d0f7f85a6332c8c35c1ff92b8af41e81a58a5a79e8c28589f2b25a34f783c642c89575fc1333404d13d17b6bf003ed12
6
+ metadata.gz: 4ec63da930afeae2b68e3f821e82c8c18f18b11ffa3296ad34e56706b54db11170e5319133d84e9440360e984776cdc5adbd6193d7de252f6f618136a431696b
7
+ data.tar.gz: 13964eb6a903e5ba0881b0ea2dfeab5e10fcfe51722d9e8a3342f2084200a60bc046d7375e29f651a5267d04a7b9b3a571f26b1ecf13ebf1c3fa2a3211ac6d8c
data/README.md CHANGED
@@ -64,14 +64,14 @@ Example: Define WeightsMatrix and get the matrix in row_standardized format.
64
64
 
65
65
  ```ruby
66
66
  weights = {
67
- 1 => [{ j_id: 2, weight: 1 }, { j_id: 4, weight: 1 }],
68
- 2 => [{ j_id: 1, weight: 1 }],
69
- 3 => [{ j_id: 4, weight: 1 }],
70
- 4 => [{ j_id: 1, weight: 1 }, { j_id: 3, weight: 1 }]
67
+ 1 => [{ id: 2, weight: 1 }, { id: 4, weight: 1 }],
68
+ 2 => [{ id: 1, weight: 1 }],
69
+ 3 => [{ id: 4, weight: 1 }],
70
+ 4 => [{ id: 1, weight: 1 }, { id: 3, weight: 1 }]
71
71
  }
72
72
  keys = weights.keys
73
73
  wm = SpatialStats::Weights::WeightsMatrix.new(keys, weights)
74
- # => #<SpatialStats::Weights::WeightsMatrix:0x0000561e205677c0 @keys=[1, 2, 3, 4], @weights={1=>[{:j_id=>2, :weight=>1}, {:j_id=>4, :weight=>1}], 2=>[{:j_id=>1, :weight=>1}], 3=>[{:j_id=>4, :weight=>1}], 4=>[{:j_id=>1, :weight=>1}, {:j_id=>3, :weight=>1}]}, @n=4>
74
+ # => #<SpatialStats::Weights::WeightsMatrix:0x0000561e205677c0 @keys=[1, 2, 3, 4], @weights={1=>[{:id=>2, :weight=>1}, {:id=>4, :weight=>1}], 2=>[{:id=>1, :weight=>1}], 3=>[{:id=>4, :weight=>1}], 4=>[{:id=>1, :weight=>1}, {:id=>3, :weight=>1}]}, @n=4>
75
75
 
76
76
  wm.standardized
77
77
  # => Numo::DFloat#shape=[4,4]
@@ -118,6 +118,26 @@ moran.i
118
118
  # => 0.834
119
119
  ```
120
120
 
121
+ #### Compute Moran's I without Querying Data
122
+
123
+ To calculate the statistic by using an array of data and not querying a database field. The order of the data must correspond to the order of `weights.keys`.
124
+
125
+ ```ruby
126
+ scope = County.all
127
+ weights = SpatialStats::Weights::Contiguous.rook(scope, :geom)
128
+
129
+ field = nil
130
+ moran = SpatialStats::Global::Moran.new(scope, field, weights)
131
+ # => <SpatialStats::Global::Moran>
132
+
133
+ # important to standardize the data!
134
+ data = [1,2,3,4,5,6].standardize
135
+ moran.x = data
136
+
137
+ moran.stat
138
+ # => 0.521
139
+ ```
140
+
121
141
  #### Compute Moran's I Z-Score
122
142
 
123
143
  ```ruby
@@ -144,6 +164,20 @@ moran.mc(999, 123_456)
144
164
  # => 0.003
145
165
  ```
146
166
 
167
+ #### Get Summary of Permutation Test
168
+
169
+ All stat classes have the `summary` method which takes `permutations` and `seed` as its parameters. `summary` runs `stat` and `mc` then combines the results into a hash.
170
+
171
+ ```ruby
172
+ scope = County.all
173
+ weights = SpatialStats::Weights::Contiguous.rook(scope, :geom)
174
+ moran = SpatialStats::Global::Moran.new(scope, :avg_income, weights)
175
+ # => <SpatialStats::Global::Moran>
176
+
177
+ moran.summary(999, 123_456)
178
+ # => {stat: 0.834, p: 0.003}
179
+ ```
180
+
147
181
  ### Local Stats
148
182
 
149
183
  Local stats compute a value each observation in the dataset, like how similar its neighbors are to itself. Local stats operate similarly to global stats, except that almost every operation will return an array of length `n` where `n` is the number of observations in the dataset.
@@ -165,6 +199,26 @@ moran.i
165
199
  # => [0.888, 0.675, 0.2345, -0.987, -0.42, ...]
166
200
  ```
167
201
 
202
+ #### Compute Moran's I without Querying Data
203
+
204
+ To calculate the statistic by using an array of data and not querying a database field. The order of the data must correspond to the order of `weights.keys`.
205
+
206
+ ```ruby
207
+ scope = County.all
208
+ weights = SpatialStats::Weights::Contiguous.rook(scope, :geom)
209
+
210
+ field = nil
211
+ moran = SpatialStats::Local::Moran.new(scope, field, weights)
212
+ # => <SpatialStats::Local::Moran>
213
+
214
+ # important to standardize the data!
215
+ data = [1,2,3,4,5,6].standardize
216
+ moran.x = data
217
+
218
+ moran.stat
219
+ # => [0.521, 0.123, -0.432, -0.56,. ...]
220
+ ```
221
+
168
222
  #### Compute Moran's I Z-Scores
169
223
 
170
224
  Note: Many classes do not have a variance or expectation method implemented and this will raise a `NotImplementedError`.
@@ -193,6 +247,20 @@ moran.mc(999, 123_456)
193
247
  # => [0.24, 0.13, 0.53, 0.023, 0.65, ...]
194
248
  ```
195
249
 
250
+ #### Get Summary of Permutation Test
251
+
252
+ All stat classes have the `summary` method which takes `permutations` and `seed` as its parameters. `summary` runs `stat`, `mc`, and `groups` then combines the results into a hash array indexed by `weight.keys`.
253
+
254
+ ```ruby
255
+ scope = County.all
256
+ weights = SpatialStats::Weights::Contiguous.rook(scope, :geom)
257
+ moran = SpatialStats::Local::Moran.new(scope, :avg_income, weights)
258
+ # => <SpatialStats::Local::Moran>
259
+
260
+ moran.summary(999, 123_456)
261
+ # => [{key: 1, stat: 0.521, p: 0.24, group: 'HH'}, ...]
262
+ ```
263
+
196
264
  ## Contributing
197
265
 
198
266
  Once cloned, run the following commands to setup the test database.
@@ -240,16 +308,20 @@ RGeo::Geos.supported?
240
308
  - ~~Make star a parameter to getis-ord class~~
241
309
  - ~~Add examples/usage to docs~~
242
310
  - ~~Create RDocs~~
243
- - Refactor Global Moran and BVMoran
244
- - Support non-numeric keys in WeightsMatrix/General refactor
245
- - Write SparseMatrix C ext
311
+ - ~~Refactor Global Moran and BVMoran~~
312
+ - ~~Support non-numeric keys in WeightsMatrix/General refactor~~
313
+ - ~~Write SparseMatrix C ext~~
314
+ - ~~Change instances of `standardized` and `windowed` to `standardize` and `window`, respectively.~~
315
+ - ~~Add `positive` and `negative` groups for `GetisOrd` and `Geary`, similar to how `#quads` is implemented.~~
316
+ - ~~Add `#summary` method to statistics that will combine stat vals with p-vals, and quads or hot/cold spot info.~~
317
+ - ~~Add ability to assign `x` or `z` on stat classes so users are not forced to query data to input it into models. Add example to README.~~
246
318
 
247
319
  ## Future Work
248
320
 
249
321
  #### General
250
322
 
251
323
  - ~~Refactor stats to inherit an abstract class.~~
252
- - Change WeightsMatrix class and Stat classes to utilize sparse matrix methods.
324
+ - ~~Change WeightsMatrix class and Stat classes to utilize sparse matrix methods.~~
253
325
  - Split into two separate gems spatial_stats and spatial_stats-activerecord
254
326
 
255
327
  #### Weights
@@ -261,7 +333,7 @@ RGeo::Geos.supported?
261
333
  - Rate smoothing
262
334
  - Bayes smoothing
263
335
 
264
- ### Global
336
+ #### Global
265
337
 
266
338
  - Geary class
267
339
  - GetisOrd class
@@ -270,7 +342,7 @@ RGeo::Geos.supported?
270
342
 
271
343
  - Join Count Statistic
272
344
 
273
- ### PPA
345
+ #### PPA
274
346
 
275
347
  - Add descriptive stat methods for point clusters.
276
348
 
data/Rakefile CHANGED
@@ -18,6 +18,12 @@ end
18
18
 
19
19
  require 'bundler/gem_tasks'
20
20
 
21
+ require 'rake/extensiontask'
22
+
23
+ Rake::ExtensionTask.new 'spatial_stats' do |ext|
24
+ ext.lib_dir = 'lib/spatial_stats'
25
+ end
26
+
21
27
  require 'rake/testtask'
22
28
 
23
29
  Rake::TestTask.new(:test) do |t|
@@ -27,4 +33,5 @@ Rake::TestTask.new(:test) do |t|
27
33
  t.warning = false # shut up annoying warnings
28
34
  end
29
35
 
36
+ task test: :compile
30
37
  task default: :test
@@ -0,0 +1,365 @@
1
+ #include <ruby.h>
2
+ #include <stdlib.h>
3
+ #include <stdio.h>
4
+ #include "csr_matrix.h"
5
+
6
+ void csr_matrix_free(void *mat)
7
+ {
8
+ csr_matrix *csr = (csr_matrix *)mat;
9
+
10
+ if (csr->init == 1)
11
+ {
12
+ free(csr->values);
13
+ free(csr->col_index);
14
+ free(csr->row_index);
15
+ }
16
+ free(mat);
17
+ }
18
+
19
+ size_t csr_matrix_memsize(const void *ptr)
20
+ {
21
+ const csr_matrix *csr = (const csr_matrix *)ptr;
22
+ return sizeof(*csr);
23
+ }
24
+
25
+ VALUE csr_matrix_alloc(VALUE self)
26
+ {
27
+ csr_matrix *csr = malloc(sizeof(csr_matrix));
28
+ return TypedData_Wrap_Struct(self, &csr_matrix_type, csr);
29
+ }
30
+
31
+ void mat_to_sparse(csr_matrix *csr, VALUE data, VALUE num_rows, VALUE num_cols)
32
+ {
33
+ int nnz = 0;
34
+ int m = NUM2INT(num_rows);
35
+ int n = NUM2INT(num_cols);
36
+
37
+ double *values;
38
+ int *col_index;
39
+ int *row_index;
40
+
41
+ int nz_idx;
42
+ double entry;
43
+
44
+ int i;
45
+ int j;
46
+ int index;
47
+
48
+ // first get number non zero count so we can alloc values and col_index
49
+ for (i = 0; i < m; i++)
50
+ {
51
+ for (j = 0; j < n; j++)
52
+ {
53
+ index = i * n + j;
54
+ if (NUM2DBL(rb_ary_entry(data, index)) != 0)
55
+ {
56
+ nnz++;
57
+ }
58
+ }
59
+ }
60
+
61
+ values = malloc(sizeof(double) * nnz);
62
+ col_index = malloc(sizeof(int) * nnz);
63
+ row_index = malloc(sizeof(int) * (m + 1));
64
+
65
+ // for every non-zero, record value, column and then get values per row
66
+ nz_idx = 0;
67
+ for (i = 0; i < m; i++)
68
+ {
69
+ row_index[i] = nz_idx;
70
+ for (j = 0; j < n; j++)
71
+ {
72
+ index = i * n + j;
73
+ entry = NUM2DBL(rb_ary_entry(data, index));
74
+ if (entry != 0)
75
+ {
76
+ values[nz_idx] = entry;
77
+ col_index[nz_idx] = j;
78
+ nz_idx++;
79
+ }
80
+ }
81
+ }
82
+ row_index[m] = nnz;
83
+
84
+ csr->m = m;
85
+ csr->n = n;
86
+ csr->nnz = nnz;
87
+ csr->values = values;
88
+ csr->col_index = col_index;
89
+ csr->row_index = row_index;
90
+ csr->init = 1;
91
+ }
92
+
93
+ /**
94
+ * A new instance of CSRMatrix.
95
+ * Uses a 1-D representation of a 2-D array as input.
96
+ * @example
97
+ * dummy_data = [
98
+ * [0, 1, 2]
99
+ * [3, 4, 5],
100
+ * [6, 7, 8]
101
+ * ]
102
+ * num_rows = 3
103
+ * num_cols = 3
104
+ * data = dummy_data.flatten
105
+ * # => [0, 1, 2, 3, 4, 5, 6, 7, 8]
106
+ *
107
+ * csr = CSRMatrix.new(data, num_rows, num_cols)
108
+ *
109
+ * @param [Array] data in 1-D format
110
+ * @param [Integer] num_rows in the 2-D representation
111
+ * @param [Integer] num_cols in the 2-D representation
112
+ *
113
+ * @return [CSRMatrix]
114
+ */
115
+ VALUE csr_matrix_initialize(VALUE self, VALUE data, VALUE num_rows, VALUE num_cols)
116
+ {
117
+
118
+ csr_matrix *csr;
119
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
120
+ csr->init = 0;
121
+
122
+ Check_Type(data, T_ARRAY);
123
+ Check_Type(num_rows, T_FIXNUM);
124
+ Check_Type(num_cols, T_FIXNUM);
125
+
126
+ // check dimensions are correct
127
+ if (NUM2INT(num_rows) * NUM2INT(num_cols) != rb_array_len(data))
128
+ {
129
+ rb_raise(rb_eArgError, "n_rows * n_cols != data.size, check your dimensions");
130
+ }
131
+
132
+ mat_to_sparse(csr, data, num_rows, num_cols);
133
+
134
+ rb_iv_set(self, "@m", num_rows);
135
+ rb_iv_set(self, "@n", num_cols);
136
+ rb_iv_set(self, "@nnz", INT2NUM(csr->nnz));
137
+
138
+ return self;
139
+ }
140
+
141
+ /**
142
+ * Non-zero values in the matrix.
143
+ *
144
+ * @return [Array] of the non-zero values.
145
+ */
146
+ VALUE csr_matrix_values(VALUE self)
147
+ {
148
+ csr_matrix *csr;
149
+ VALUE result;
150
+
151
+ int i;
152
+
153
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
154
+
155
+ result = rb_ary_new_capa(csr->nnz);
156
+ for (i = 0; i < csr->nnz; i++)
157
+ {
158
+ rb_ary_store(result, i, DBL2NUM(csr->values[i]));
159
+ }
160
+
161
+ return result;
162
+ }
163
+
164
+ /**
165
+ * Column indices of the non-zero values.
166
+ *
167
+ * @return [Array] of the column indices.
168
+ */
169
+ VALUE csr_matrix_col_index(VALUE self)
170
+ {
171
+ csr_matrix *csr;
172
+ VALUE result;
173
+
174
+ int i;
175
+
176
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
177
+
178
+ result = rb_ary_new_capa(csr->nnz);
179
+ for (i = 0; i < csr->nnz; i++)
180
+ {
181
+ rb_ary_store(result, i, INT2NUM(csr->col_index[i]));
182
+ }
183
+
184
+ return result;
185
+ }
186
+
187
+ /**
188
+ * Row indices of the non-zero values. Represents the start index
189
+ * of values in a row. For example [0,2,3] would represent a matrix
190
+ * with 2 rows, the first containing 2 non-zero values and the second
191
+ * containing 1. Length is num_rows + 1.
192
+ *
193
+ * Used for row slicing operations.
194
+ *
195
+ * @return [Array] of the row indices.
196
+ */
197
+ VALUE csr_matrix_row_index(VALUE self)
198
+ {
199
+ csr_matrix *csr;
200
+ VALUE result;
201
+
202
+ int i;
203
+
204
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
205
+
206
+ result = rb_ary_new_capa(csr->m + 1);
207
+ for (i = 0; i <= csr->m; i++)
208
+ {
209
+ rb_ary_store(result, i, INT2NUM(csr->row_index[i]));
210
+ }
211
+
212
+ return result;
213
+ }
214
+
215
+ /**
216
+ * Multiply matrix by the input vector.
217
+ *
218
+ * @see https://github.com/scipy/scipy/blob/53fac7a1d8a81d48be757632ad285b6fc76529ba/scipy/sparse/sparsetools/csr.h#L1120
219
+ *
220
+ * @param [Array] vec of length n.
221
+ *
222
+ * @return [Array] of the result of the multiplication.
223
+ */
224
+ VALUE csr_matrix_mulvec(VALUE self, VALUE vec)
225
+ {
226
+ csr_matrix *csr;
227
+ VALUE result;
228
+
229
+ int i;
230
+ int jj;
231
+ double tmp;
232
+
233
+ Check_Type(vec, T_ARRAY);
234
+
235
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
236
+
237
+ if (rb_array_len(vec) != csr->n)
238
+ {
239
+ rb_raise(rb_eArgError, "Dimension Mismatch CSRMatrix.n != vec.size");
240
+ }
241
+
242
+ result = rb_ary_new_capa(csr->m);
243
+
244
+ // float *vals = (float *)DATA_PTR(result);
245
+
246
+ for (i = 0; i < csr->m; i++)
247
+ {
248
+ tmp = 0;
249
+ for (jj = csr->row_index[i]; jj < csr->row_index[i + 1]; jj++)
250
+ {
251
+ tmp += csr->values[jj] * NUM2DBL(rb_ary_entry(vec, csr->col_index[jj]));
252
+ }
253
+ rb_ary_store(result, i, DBL2NUM(tmp));
254
+ }
255
+
256
+ return result;
257
+ }
258
+
259
+ /**
260
+ * Compute the dot product of the given row with the input vector.
261
+ * Equivalent to +mulvec(vec)[row]+.
262
+ *
263
+ * @param [Array] vec of length n.
264
+ * @param [Integer] row of the dot product.
265
+ *
266
+ * @return [Float] of the result of the dot product.
267
+ */
268
+ VALUE csr_matrix_dot_row(VALUE self, VALUE vec, VALUE row)
269
+ {
270
+ csr_matrix *csr;
271
+ VALUE result;
272
+
273
+ int i;
274
+ int jj;
275
+ double tmp;
276
+
277
+ Check_Type(vec, T_ARRAY);
278
+ Check_Type(row, T_FIXNUM);
279
+
280
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
281
+
282
+ if (rb_array_len(vec) != csr->n)
283
+ {
284
+ rb_raise(rb_eArgError, "Dimension Mismatch CSRMatrix.n != vec.size");
285
+ }
286
+
287
+ i = NUM2INT(row);
288
+ if (!(i >= 0 && i < csr->m))
289
+ {
290
+ rb_raise(rb_eArgError, "Index Error row_idx >= m or idx < 0");
291
+ }
292
+
293
+ tmp = 0;
294
+ for (jj = csr->row_index[i]; jj < csr->row_index[i + 1]; jj++)
295
+ {
296
+ tmp += csr->values[jj] * NUM2DBL(rb_ary_entry(vec, csr->col_index[jj]));
297
+ }
298
+
299
+ result = DBL2NUM(tmp);
300
+ return result;
301
+ }
302
+
303
+ /**
304
+ * A hash representation of the matrix with coordinates as keys.
305
+ * @example
306
+ * data = [
307
+ * [0, 1, 0]
308
+ * [0, 0, 0],
309
+ * [1, 0, 1]
310
+ * ]
311
+ * num_rows = 3
312
+ * num_cols = 3
313
+ * data = data.flatten!
314
+ * csr = CSRMatrix.new(data, num_rows, num_cols)
315
+ *
316
+ * csr.coordinates
317
+ * # => {
318
+ * [0,1] => 1,
319
+ * [2,0] => 1,
320
+ * [2,2] => 1
321
+ * }
322
+ *
323
+ * @return [Hash]
324
+ */
325
+ VALUE csr_matrix_coordinates(VALUE self)
326
+ {
327
+ csr_matrix *csr;
328
+ VALUE result;
329
+
330
+ int i;
331
+ int k;
332
+
333
+ VALUE key;
334
+ VALUE val;
335
+ int row_end;
336
+
337
+ TypedData_Get_Struct(self, csr_matrix, &csr_matrix_type, csr);
338
+
339
+ result = rb_hash_new();
340
+
341
+ // iterate through every value in the matrix and assign it's coordinates
342
+ // [x,y] as the key to the hash, with the value as the value.
343
+ // Use i to keep track of what row we are on.
344
+ i = 0;
345
+ row_end = csr->row_index[1];
346
+ for (k = 0; k < csr->nnz; k++)
347
+ {
348
+ if (k == row_end)
349
+ {
350
+ i++;
351
+ row_end = csr->row_index[i + 1];
352
+ }
353
+
354
+ // store i,j coordinates j is col_index[k]
355
+ key = rb_ary_new_capa(2);
356
+ rb_ary_store(key, 0, INT2NUM(i));
357
+ rb_ary_store(key, 1, INT2NUM(csr->col_index[k]));
358
+
359
+ val = DBL2NUM(csr->values[k]);
360
+
361
+ rb_hash_aset(result, key, val);
362
+ }
363
+
364
+ return result;
365
+ }
@@ -0,0 +1,35 @@
1
+ #ifndef CSR_MATRIX
2
+ #define CSR_MATRIX
3
+
4
+ typedef struct csr_matrix
5
+ {
6
+ char init;
7
+ int m;
8
+ int n;
9
+ int nnz;
10
+ double *values;
11
+ int *col_index;
12
+ int *row_index;
13
+ } csr_matrix;
14
+
15
+ void csr_matrix_free(void *mat);
16
+ size_t csr_matrix_memsize(const void *ptr);
17
+
18
+ // ruby VALUE for csr_matrix
19
+ static const rb_data_type_t csr_matrix_type = {
20
+ "SpatialStats::Weights::CSRMatrix",
21
+ {NULL, csr_matrix_free, csr_matrix_memsize},
22
+ 0,
23
+ 0,
24
+ RUBY_TYPED_FREE_IMMEDIATELY};
25
+
26
+ void mat_to_sparse(csr_matrix *csr, VALUE data, VALUE num_rows, VALUE num_cols);
27
+ VALUE csr_matrix_alloc(VALUE self);
28
+ VALUE csr_matrix_initialize(VALUE self, VALUE data, VALUE num_rows, VALUE num_cols);
29
+ VALUE csr_matrix_values(VALUE self);
30
+ VALUE csr_matrix_col_index(VALUE self);
31
+ VALUE csr_matrix_row_index(VALUE self);
32
+ VALUE csr_matrix_mulvec(VALUE self, VALUE vec);
33
+ VALUE csr_matrix_dot_row(VALUE self, VALUE vec, VALUE row);
34
+ VALUE csr_matrix_coordinates(VALUE self);
35
+ #endif
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ create_header
6
+ create_makefile 'spatial_stats/spatial_stats'
@@ -0,0 +1,32 @@
1
+ #include <ruby.h>
2
+ #include "csr_matrix.h"
3
+
4
+ /**
5
+ * Document-class: SpatialStats::Weights::CSRMatrix
6
+ *
7
+ * CSRMatrix partially implements a compressed sparse row matrix to perform
8
+ * spatial lag and other calculations. This will generally be used
9
+ * to store the weights of an observation set.
10
+ *
11
+ * @see https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format)
12
+ *
13
+ */
14
+ void Init_spatial_stats()
15
+ {
16
+ VALUE spatial_stats_mod = rb_define_module("SpatialStats");
17
+ VALUE weights_mod = rb_define_module_under(spatial_stats_mod, "Weights");
18
+ VALUE csr_matrix_class = rb_define_class_under(weights_mod, "CSRMatrix", rb_cData);
19
+
20
+ rb_define_alloc_func(csr_matrix_class, csr_matrix_alloc);
21
+ rb_define_method(csr_matrix_class, "initialize", csr_matrix_initialize, 3);
22
+ rb_define_method(csr_matrix_class, "values", csr_matrix_values, 0);
23
+ rb_define_method(csr_matrix_class, "col_index", csr_matrix_col_index, 0);
24
+ rb_define_method(csr_matrix_class, "row_index", csr_matrix_row_index, 0);
25
+ rb_define_method(csr_matrix_class, "mulvec", csr_matrix_mulvec, 1);
26
+ rb_define_method(csr_matrix_class, "dot_row", csr_matrix_dot_row, 2);
27
+ rb_define_method(csr_matrix_class, "coordinates", csr_matrix_coordinates, 0);
28
+
29
+ rb_define_attr(csr_matrix_class, "m", 1, 0);
30
+ rb_define_attr(csr_matrix_class, "n", 1, 0);
31
+ rb_define_attr(csr_matrix_class, "nnz", 1, 0);
32
+ }