grnexus 1.0.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.
@@ -0,0 +1,591 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+ require 'rbconfig'
5
+
6
+ module GRNEXUSMachineLearning
7
+ extend FFI::Library
8
+
9
+ # Detect and load appropriate library
10
+ def self.detect_library
11
+ script_dir = File.dirname(File.expand_path(__FILE__))
12
+ case RbConfig::CONFIG['host_os']
13
+ when /mswin|mingw|cygwin/
14
+ File.join(script_dir, '..', 'exports', 'Windows', 'machine_learning.dll')
15
+ when /darwin/
16
+ File.join(script_dir, '..', 'exports', 'Mac', 'machine_learning.dylib')
17
+ when /linux/
18
+ File.join(script_dir, '..', 'exports', 'Linux', 'machine_learning.so')
19
+ else
20
+ raise "Sistema operativo no soportado: #{RbConfig::CONFIG['host_os']}"
21
+ end
22
+ end
23
+
24
+ ffi_lib detect_library
25
+
26
+ # Define GRNexusData structure
27
+ class GRNexusData < FFI::Struct
28
+ layout :data, :pointer,
29
+ :type, :int,
30
+ :size, :size_t,
31
+ :stride, :size_t,
32
+ :dims, [:size_t, 3]
33
+ end
34
+
35
+ # Attach C functions
36
+ attach_function :knn_predict, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr, :int, GRNexusData.ptr], :int
37
+ attach_function :kmeans_fit, [GRNexusData.ptr, :int, :int, GRNexusData.ptr, GRNexusData.ptr], :int
38
+ attach_function :kmeans_predict, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
39
+ attach_function :linear_regression_fit, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
40
+ attach_function :linear_regression_predict, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
41
+ attach_function :logistic_regression_fit, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr, :double, :int], :int
42
+ attach_function :logistic_regression_predict, [GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
43
+ attach_function :naive_bayes_fit, [GRNexusData.ptr, GRNexusData.ptr, :int, GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
44
+ attach_function :naive_bayes_predict, [GRNexusData.ptr, :int, GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr, GRNexusData.ptr], :int
45
+
46
+ # Helper method to create GRNexusData from Ruby array
47
+ def self.create_data(array, dims)
48
+ data = GRNexusData.new
49
+ flat_array = array.flatten
50
+ buffer = FFI::MemoryPointer.new(:double, flat_array.size)
51
+ buffer.write_array_of_double(flat_array)
52
+
53
+ data[:data] = buffer
54
+ data[:type] = 3 # GRNEXUS_MATRIX
55
+ data[:size] = flat_array.size
56
+ data[:stride] = 1
57
+ data[:dims][0] = dims[0]
58
+ data[:dims][1] = dims[1] || 0
59
+ data[:dims][2] = dims[2] || 0
60
+
61
+ data
62
+ end
63
+
64
+ # K-Nearest Neighbors
65
+ class KNeighborsClassifier
66
+ attr_reader :n_neighbors
67
+
68
+ def initialize(n_neighbors: 5)
69
+ @n_neighbors = n_neighbors
70
+ @x_train = nil
71
+ @y_train = nil
72
+ end
73
+
74
+ def fit(x, y)
75
+ @x_train = x
76
+ @y_train = y
77
+ self
78
+ end
79
+
80
+ def save(filepath)
81
+ require 'json'
82
+ require 'zlib'
83
+
84
+ # Ensure .lnexus extension
85
+ filepath = filepath.sub(/\.nexus$/, '.lnexus') unless filepath.end_with?('.lnexus')
86
+
87
+ model_data = {
88
+ model_type: 'KNeighborsClassifier',
89
+ framework: 'GRNexus',
90
+ language: 'Ruby',
91
+ version: '1.0',
92
+ n_neighbors: @n_neighbors,
93
+ x_train: @x_train,
94
+ y_train: @y_train
95
+ }
96
+
97
+ json_data = JSON.generate(model_data)
98
+ compressed_data = Zlib::Deflate.deflate(json_data)
99
+ File.write(filepath, compressed_data, mode: 'wb')
100
+ puts "Model saved to #{filepath}"
101
+ end
102
+
103
+ def self.load(filepath)
104
+ require 'json'
105
+ require 'zlib'
106
+
107
+ raise "File not found: #{filepath}" unless File.exist?(filepath)
108
+ raise "Invalid file format. Expected .lnexus for ML models, got .nexus (Neural Network format)" if filepath.end_with?('.nexus')
109
+
110
+ compressed_data = File.read(filepath, mode: 'rb')
111
+ json_data = Zlib::Inflate.inflate(compressed_data)
112
+ model_data = JSON.parse(json_data)
113
+
114
+ raise "Invalid model type. Expected KNeighborsClassifier" unless model_data['model_type'] == 'KNeighborsClassifier'
115
+
116
+ model = new(n_neighbors: model_data['n_neighbors'])
117
+ model.instance_variable_set(:@x_train, model_data['x_train'])
118
+ model.instance_variable_set(:@y_train, model_data['y_train'])
119
+ model
120
+ end
121
+
122
+ def inspect
123
+ trained = @x_train ? 'trained' : 'not trained'
124
+ n_samples = @x_train ? @x_train.length : 0
125
+ n_features = @x_train && @x_train.length > 0 ? @x_train[0].length : 0
126
+
127
+ "#<KNeighborsClassifier n_neighbors=#{@n_neighbors}, status=#{trained}, samples=#{n_samples}, features=#{n_features}>"
128
+ end
129
+
130
+ def predict(x)
131
+ raise "Model not trained" unless @x_train && @y_train
132
+
133
+ n_samples = x.length
134
+ n_features = x[0].length
135
+ n_train = @x_train.length
136
+
137
+ x_train_data = GRNEXUSMachineLearning.create_data(@x_train, [n_train, n_features])
138
+ y_train_data = GRNEXUSMachineLearning.create_data(@y_train.map { |v| [v] }, [n_train, 1])
139
+ x_test_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
140
+
141
+ output_buffer = FFI::MemoryPointer.new(:double, n_samples)
142
+ output_data = GRNEXUSMachineLearning::GRNexusData.new
143
+ output_data[:data] = output_buffer
144
+ output_data[:size] = n_samples
145
+ output_data[:dims][0] = n_samples
146
+ output_data[:dims][1] = 1
147
+
148
+ result = GRNEXUSMachineLearning.knn_predict(x_train_data, y_train_data, x_test_data, @n_neighbors, output_data)
149
+ raise "KNN prediction failed" if result != 0
150
+
151
+ output_buffer.read_array_of_double(n_samples)
152
+ end
153
+ end
154
+
155
+ # K-Means Clustering
156
+ class KMeans
157
+ attr_reader :centroids, :labels, :n_clusters
158
+
159
+ def initialize(n_clusters: 3, max_iter: 300)
160
+ @n_clusters = n_clusters
161
+ @max_iter = max_iter
162
+ @centroids = nil
163
+ @labels = nil
164
+ end
165
+
166
+ def save(filepath)
167
+ require 'json'
168
+ require 'zlib'
169
+
170
+ filepath = filepath.sub(/\.nexus$/, '.lnexus') unless filepath.end_with?('.lnexus')
171
+
172
+ model_data = {
173
+ model_type: 'KMeans',
174
+ framework: 'GRNexus',
175
+ language: 'Ruby',
176
+ version: '1.0',
177
+ n_clusters: @n_clusters,
178
+ centroids: @centroids,
179
+ labels: @labels
180
+ }
181
+
182
+ json_data = JSON.generate(model_data)
183
+ compressed_data = Zlib::Deflate.deflate(json_data)
184
+ File.write(filepath, compressed_data, mode: 'wb')
185
+ puts "Model saved to #{filepath}"
186
+ end
187
+
188
+ def self.load(filepath)
189
+ require 'json'
190
+ require 'zlib'
191
+
192
+ raise "File not found: #{filepath}" unless File.exist?(filepath)
193
+ raise "Invalid file format. Expected .lnexus for ML models, got .nexus (Neural Network format)" if filepath.end_with?('.nexus')
194
+
195
+ compressed_data = File.read(filepath, mode: 'rb')
196
+ json_data = Zlib::Inflate.inflate(compressed_data)
197
+ model_data = JSON.parse(json_data)
198
+
199
+ raise "Invalid model type. Expected KMeans" unless model_data['model_type'] == 'KMeans'
200
+
201
+ model = new(n_clusters: model_data['n_clusters'])
202
+ model.instance_variable_set(:@centroids, model_data['centroids'])
203
+ model.instance_variable_set(:@labels, model_data['labels'])
204
+ model
205
+ end
206
+
207
+ def inspect
208
+ trained = @centroids ? 'trained' : 'not trained'
209
+ n_features = @centroids && @centroids.length > 0 ? @centroids[0].length : 0
210
+
211
+ "#<KMeans n_clusters=#{@n_clusters}, status=#{trained}, features=#{n_features}>"
212
+ end
213
+
214
+ def fit(x)
215
+ n_samples = x.length
216
+ n_features = x[0].length
217
+
218
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
219
+
220
+ centroids_buffer = FFI::MemoryPointer.new(:double, @n_clusters * n_features)
221
+ centroids_data = GRNEXUSMachineLearning::GRNexusData.new
222
+ centroids_data[:data] = centroids_buffer
223
+ centroids_data[:size] = @n_clusters * n_features
224
+ centroids_data[:dims][0] = @n_clusters
225
+ centroids_data[:dims][1] = n_features
226
+
227
+ labels_buffer = FFI::MemoryPointer.new(:int, n_samples)
228
+ labels_data = GRNEXUSMachineLearning::GRNexusData.new
229
+ labels_data[:data] = labels_buffer
230
+ labels_data[:size] = n_samples
231
+ labels_data[:dims][0] = n_samples
232
+
233
+ result = GRNEXUSMachineLearning.kmeans_fit(x_data, @n_clusters, @max_iter, centroids_data, labels_data)
234
+ raise "KMeans fit failed" if result != 0
235
+
236
+ @centroids = centroids_buffer.read_array_of_double(@n_clusters * n_features).each_slice(n_features).to_a
237
+ @labels = labels_buffer.read_array_of_int(n_samples)
238
+
239
+ self
240
+ end
241
+
242
+ def predict(x)
243
+ raise "Model not trained" unless @centroids
244
+
245
+ n_samples = x.length
246
+ n_features = x[0].length
247
+
248
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
249
+ centroids_data = GRNEXUSMachineLearning.create_data(@centroids, [@n_clusters, n_features])
250
+
251
+ labels_buffer = FFI::MemoryPointer.new(:int, n_samples)
252
+ labels_data = GRNEXUSMachineLearning::GRNexusData.new
253
+ labels_data[:data] = labels_buffer
254
+ labels_data[:size] = n_samples
255
+ labels_data[:dims][0] = n_samples
256
+
257
+ result = GRNEXUSMachineLearning.kmeans_predict(x_data, centroids_data, labels_data)
258
+ raise "KMeans prediction failed" if result != 0
259
+
260
+ labels_buffer.read_array_of_int(n_samples)
261
+ end
262
+ end
263
+
264
+ # Linear Regression
265
+ class LinearRegression
266
+ attr_reader :weights
267
+
268
+ def initialize
269
+ @weights = nil
270
+ end
271
+
272
+ def save(filepath)
273
+ require 'json'
274
+ require 'zlib'
275
+
276
+ filepath = filepath.sub(/\.nexus$/, '.lnexus') unless filepath.end_with?('.lnexus')
277
+
278
+ model_data = {
279
+ model_type: 'LinearRegression',
280
+ framework: 'GRNexus',
281
+ language: 'Ruby',
282
+ version: '1.0',
283
+ weights: @weights
284
+ }
285
+
286
+ json_data = JSON.generate(model_data)
287
+ compressed_data = Zlib::Deflate.deflate(json_data)
288
+ File.write(filepath, compressed_data, mode: 'wb')
289
+ puts "Model saved to #{filepath}"
290
+ end
291
+
292
+ def self.load(filepath)
293
+ require 'json'
294
+ require 'zlib'
295
+
296
+ raise "File not found: #{filepath}" unless File.exist?(filepath)
297
+ raise "Invalid file format. Expected .lnexus for ML models, got .nexus (Neural Network format)" if filepath.end_with?('.nexus')
298
+
299
+ compressed_data = File.read(filepath, mode: 'rb')
300
+ json_data = Zlib::Inflate.inflate(compressed_data)
301
+ model_data = JSON.parse(json_data)
302
+
303
+ raise "Invalid model type. Expected LinearRegression" unless model_data['model_type'] == 'LinearRegression'
304
+
305
+ model = new
306
+ model.instance_variable_set(:@weights, model_data['weights'])
307
+ model
308
+ end
309
+
310
+ def inspect
311
+ trained = @weights ? 'trained' : 'not trained'
312
+ n_features = @weights ? @weights.length - 1 : 0
313
+
314
+ "#<LinearRegression status=#{trained}, features=#{n_features}, weights=#{@weights ? @weights.length : 0}>"
315
+ end
316
+
317
+ def fit(x, y)
318
+ n_samples = x.length
319
+ n_features = x[0].length
320
+
321
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
322
+ y_data = GRNEXUSMachineLearning.create_data(y.map { |v| [v] }, [n_samples, 1])
323
+
324
+ weights_buffer = FFI::MemoryPointer.new(:double, n_features + 1)
325
+ weights_data = GRNEXUSMachineLearning::GRNexusData.new
326
+ weights_data[:data] = weights_buffer
327
+ weights_data[:size] = n_features + 1
328
+ weights_data[:dims][0] = n_features + 1
329
+
330
+ result = GRNEXUSMachineLearning.linear_regression_fit(x_data, y_data, weights_data)
331
+ raise "Linear regression fit failed" if result != 0
332
+
333
+ @weights = weights_buffer.read_array_of_double(n_features + 1)
334
+
335
+ self
336
+ end
337
+
338
+ def predict(x)
339
+ raise "Model not trained" unless @weights
340
+
341
+ n_samples = x.length
342
+ n_features = x[0].length
343
+
344
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
345
+ weights_data = GRNEXUSMachineLearning.create_data([@weights], [n_features + 1, 1])
346
+
347
+ output_buffer = FFI::MemoryPointer.new(:double, n_samples)
348
+ output_data = GRNEXUSMachineLearning::GRNexusData.new
349
+ output_data[:data] = output_buffer
350
+ output_data[:size] = n_samples
351
+ output_data[:dims][0] = n_samples
352
+
353
+ result = GRNEXUSMachineLearning.linear_regression_predict(x_data, weights_data, output_data)
354
+ raise "Linear regression prediction failed" if result != 0
355
+
356
+ output_buffer.read_array_of_double(n_samples)
357
+ end
358
+ end
359
+
360
+ # Logistic Regression
361
+ class LogisticRegression
362
+ attr_reader :weights, :learning_rate, :max_iter
363
+
364
+ def initialize(learning_rate: 0.01, max_iter: 1000)
365
+ @learning_rate = learning_rate
366
+ @max_iter = max_iter
367
+ @weights = nil
368
+ end
369
+
370
+ def save(filepath)
371
+ require 'json'
372
+ require 'zlib'
373
+
374
+ filepath = filepath.sub(/\.nexus$/, '.lnexus') unless filepath.end_with?('.lnexus')
375
+
376
+ model_data = {
377
+ model_type: 'LogisticRegression',
378
+ framework: 'GRNexus',
379
+ language: 'Ruby',
380
+ version: '1.0',
381
+ learning_rate: @learning_rate,
382
+ max_iter: @max_iter,
383
+ weights: @weights
384
+ }
385
+
386
+ json_data = JSON.generate(model_data)
387
+ compressed_data = Zlib::Deflate.deflate(json_data)
388
+ File.write(filepath, compressed_data, mode: 'wb')
389
+ puts "Model saved to #{filepath}"
390
+ end
391
+
392
+ def self.load(filepath)
393
+ require 'json'
394
+ require 'zlib'
395
+
396
+ raise "File not found: #{filepath}" unless File.exist?(filepath)
397
+ raise "Invalid file format. Expected .lnexus for ML models, got .nexus (Neural Network format)" if filepath.end_with?('.nexus')
398
+
399
+ compressed_data = File.read(filepath, mode: 'rb')
400
+ json_data = Zlib::Inflate.inflate(compressed_data)
401
+ model_data = JSON.parse(json_data)
402
+
403
+ raise "Invalid model type. Expected LogisticRegression" unless model_data['model_type'] == 'LogisticRegression'
404
+
405
+ model = new(learning_rate: model_data['learning_rate'], max_iter: model_data['max_iter'])
406
+ model.instance_variable_set(:@weights, model_data['weights'])
407
+ model
408
+ end
409
+
410
+ def inspect
411
+ trained = @weights ? 'trained' : 'not trained'
412
+ n_features = @weights ? @weights.length - 1 : 0
413
+
414
+ "#<LogisticRegression lr=#{@learning_rate}, max_iter=#{@max_iter}, status=#{trained}, features=#{n_features}>"
415
+ end
416
+
417
+ def fit(x, y)
418
+ n_samples = x.length
419
+ n_features = x[0].length
420
+
421
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
422
+ y_data = GRNEXUSMachineLearning.create_data(y.map { |v| [v] }, [n_samples, 1])
423
+
424
+ weights_buffer = FFI::MemoryPointer.new(:double, n_features + 1)
425
+ weights_data = GRNEXUSMachineLearning::GRNexusData.new
426
+ weights_data[:data] = weights_buffer
427
+ weights_data[:size] = n_features + 1
428
+ weights_data[:dims][0] = n_features + 1
429
+
430
+ result = GRNEXUSMachineLearning.logistic_regression_fit(x_data, y_data, weights_data, @learning_rate, @max_iter)
431
+ raise "Logistic regression fit failed" if result != 0
432
+
433
+ @weights = weights_buffer.read_array_of_double(n_features + 1)
434
+
435
+ self
436
+ end
437
+
438
+ def predict(x)
439
+ raise "Model not trained" unless @weights
440
+
441
+ n_samples = x.length
442
+ n_features = x[0].length
443
+
444
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
445
+ weights_data = GRNEXUSMachineLearning.create_data([@weights], [n_features + 1, 1])
446
+
447
+ output_buffer = FFI::MemoryPointer.new(:double, n_samples)
448
+ output_data = GRNEXUSMachineLearning::GRNexusData.new
449
+ output_data[:data] = output_buffer
450
+ output_data[:size] = n_samples
451
+ output_data[:dims][0] = n_samples
452
+
453
+ result = GRNEXUSMachineLearning.logistic_regression_predict(x_data, weights_data, output_data)
454
+ raise "Logistic regression prediction failed" if result != 0
455
+
456
+ output_buffer.read_array_of_double(n_samples)
457
+ end
458
+
459
+ def predict_proba(x)
460
+ predict(x)
461
+ end
462
+
463
+ def predict_class(x)
464
+ predict(x).map { |prob| prob >= 0.5 ? 1 : 0 }
465
+ end
466
+ end
467
+
468
+ # Naive Bayes
469
+ class GaussianNB
470
+ attr_reader :means, :variances, :priors, :n_classes
471
+
472
+ def initialize
473
+ @means = nil
474
+ @variances = nil
475
+ @priors = nil
476
+ @n_classes = nil
477
+ end
478
+
479
+ def save(filepath)
480
+ require 'json'
481
+ require 'zlib'
482
+
483
+ filepath = filepath.sub(/\.nexus$/, '.lnexus') unless filepath.end_with?('.lnexus')
484
+
485
+ model_data = {
486
+ model_type: 'GaussianNB',
487
+ framework: 'GRNexus',
488
+ language: 'Ruby',
489
+ version: '1.0',
490
+ n_classes: @n_classes,
491
+ means: @means,
492
+ variances: @variances,
493
+ priors: @priors
494
+ }
495
+
496
+ json_data = JSON.generate(model_data)
497
+ compressed_data = Zlib::Deflate.deflate(json_data)
498
+ File.write(filepath, compressed_data, mode: 'wb')
499
+ puts "Model saved to #{filepath}"
500
+ end
501
+
502
+ def self.load(filepath)
503
+ require 'json'
504
+ require 'zlib'
505
+
506
+ raise "File not found: #{filepath}" unless File.exist?(filepath)
507
+ raise "Invalid file format. Expected .lnexus for ML models, got .nexus (Neural Network format)" if filepath.end_with?('.nexus')
508
+
509
+ compressed_data = File.read(filepath, mode: 'rb')
510
+ json_data = Zlib::Inflate.inflate(compressed_data)
511
+ model_data = JSON.parse(json_data)
512
+
513
+ raise "Invalid model type. Expected GaussianNB" unless model_data['model_type'] == 'GaussianNB'
514
+
515
+ model = new
516
+ model.instance_variable_set(:@n_classes, model_data['n_classes'])
517
+ model.instance_variable_set(:@means, model_data['means'])
518
+ model.instance_variable_set(:@variances, model_data['variances'])
519
+ model.instance_variable_set(:@priors, model_data['priors'])
520
+ model
521
+ end
522
+
523
+ def inspect
524
+ trained = @means ? 'trained' : 'not trained'
525
+ n_features = @means && @means.length > 0 ? @means[0].length : 0
526
+
527
+ "#<GaussianNB n_classes=#{@n_classes || 0}, status=#{trained}, features=#{n_features}>"
528
+ end
529
+
530
+ def fit(x, y)
531
+ n_samples = x.length
532
+ n_features = x[0].length
533
+ @n_classes = y.max.to_i + 1
534
+
535
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
536
+ y_data = GRNEXUSMachineLearning.create_data(y.map { |v| [v] }, [n_samples, 1])
537
+
538
+ means_buffer = FFI::MemoryPointer.new(:double, @n_classes * n_features)
539
+ means_data = GRNEXUSMachineLearning::GRNexusData.new
540
+ means_data[:data] = means_buffer
541
+ means_data[:size] = @n_classes * n_features
542
+ means_data[:dims][0] = @n_classes
543
+ means_data[:dims][1] = n_features
544
+
545
+ vars_buffer = FFI::MemoryPointer.new(:double, @n_classes * n_features)
546
+ vars_data = GRNEXUSMachineLearning::GRNexusData.new
547
+ vars_data[:data] = vars_buffer
548
+ vars_data[:size] = @n_classes * n_features
549
+ vars_data[:dims][0] = @n_classes
550
+ vars_data[:dims][1] = n_features
551
+
552
+ priors_buffer = FFI::MemoryPointer.new(:double, @n_classes)
553
+ priors_data = GRNEXUSMachineLearning::GRNexusData.new
554
+ priors_data[:data] = priors_buffer
555
+ priors_data[:size] = @n_classes
556
+ priors_data[:dims][0] = @n_classes
557
+
558
+ result = GRNEXUSMachineLearning.naive_bayes_fit(x_data, y_data, @n_classes, means_data, vars_data, priors_data)
559
+ raise "Naive Bayes fit failed" if result != 0
560
+
561
+ @means = means_buffer.read_array_of_double(@n_classes * n_features).each_slice(n_features).to_a
562
+ @variances = vars_buffer.read_array_of_double(@n_classes * n_features).each_slice(n_features).to_a
563
+ @priors = priors_buffer.read_array_of_double(@n_classes)
564
+
565
+ self
566
+ end
567
+
568
+ def predict(x)
569
+ raise "Model not trained" unless @means && @variances && @priors
570
+
571
+ n_samples = x.length
572
+ n_features = x[0].length
573
+
574
+ x_data = GRNEXUSMachineLearning.create_data(x, [n_samples, n_features])
575
+ means_data = GRNEXUSMachineLearning.create_data(@means, [@n_classes, n_features])
576
+ vars_data = GRNEXUSMachineLearning.create_data(@variances, [@n_classes, n_features])
577
+ priors_data = GRNEXUSMachineLearning.create_data([@priors], [@n_classes, 1])
578
+
579
+ output_buffer = FFI::MemoryPointer.new(:double, n_samples)
580
+ output_data = GRNEXUSMachineLearning::GRNexusData.new
581
+ output_data[:data] = output_buffer
582
+ output_data[:size] = n_samples
583
+ output_data[:dims][0] = n_samples
584
+
585
+ result = GRNEXUSMachineLearning.naive_bayes_predict(x_data, @n_classes, means_data, vars_data, priors_data, output_data)
586
+ raise "Naive Bayes prediction failed" if result != 0
587
+
588
+ output_buffer.read_array_of_double(n_samples).map(&:to_i)
589
+ end
590
+ end
591
+ end