rust 0.7 → 0.9
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.
- checksums.yaml +4 -4
- data/bin/ruby-rust +3 -0
- data/lib/{rust-csv.rb → rust/core/csv.rb} +2 -1
- data/lib/rust/core/rust.rb +157 -0
- data/lib/rust/core/types/all.rb +4 -0
- data/lib/{rust-core.rb → rust/core/types/dataframe.rb} +17 -335
- data/lib/rust/core/types/datatype.rb +161 -0
- data/lib/rust/core/types/factor.rb +131 -0
- data/lib/rust/core/types/language.rb +166 -0
- data/lib/rust/core/types/list.rb +81 -0
- data/lib/rust/core/types/matrix.rb +132 -0
- data/lib/rust/core/types/s4class.rb +59 -0
- data/lib/rust/core/types/utils.rb +109 -0
- data/lib/rust/core.rb +7 -0
- data/lib/rust/models/all.rb +4 -0
- data/lib/rust/models/anova.rb +60 -0
- data/lib/rust/models/regression.rb +205 -0
- data/lib/rust/plots/all.rb +4 -0
- data/lib/rust/plots/basic-plots.rb +111 -0
- data/lib/{rust-plots.rb → rust/plots/core.rb} +1 -169
- data/lib/rust/plots/distribution-plots.rb +62 -0
- data/lib/rust/stats/all.rb +4 -0
- data/lib/{rust-basics.rb → rust/stats/correlation.rb} +2 -2
- data/lib/{rust-descriptive.rb → rust/stats/descriptive.rb} +24 -4
- data/lib/{rust-effsize.rb → rust/stats/effsize.rb} +7 -13
- data/lib/{rust-probabilities.rb → rust/stats/probabilities.rb} +1 -1
- data/lib/{rust-tests.rb → rust/stats/tests.rb} +84 -90
- data/lib/rust.rb +4 -9
- metadata +31 -13
- data/lib/rust-calls.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aaa404db11033ff42b529516ae4a3f3e252bdddf7677d082847ee06625144f8e
|
4
|
+
data.tar.gz: f72ebc2c95385b87a445f3fb8de3e517579b002e0606209903acd2327616befd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00567c9b6216f7e9dc1a4135dbea263eecae2178273851c023980233531729313e15147e1bec8e9521df2d4fee15e2c4c8bf9bd4a0e2d1475f1d383339a17c21
|
7
|
+
data.tar.gz: 89800fff95be559e6f6bbbc05b6b5f5b52b7d59c54c61cd76ef679876ce5de0c08b405d88eadf0b254c95306ad98f38120e5960a92ce8358fca19ed6cc5c181d
|
data/bin/ruby-rust
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'code-assertions'
|
2
|
+
require 'stringio'
|
3
|
+
require 'rinruby'
|
4
|
+
|
5
|
+
module Rust
|
6
|
+
CLIENT_MUTEX = Mutex.new
|
7
|
+
R_MUTEX = Mutex.new
|
8
|
+
|
9
|
+
R_ENGINE = RinRuby.new(echo: false)
|
10
|
+
|
11
|
+
private_constant :R_ENGINE
|
12
|
+
private_constant :R_MUTEX
|
13
|
+
private_constant :CLIENT_MUTEX
|
14
|
+
|
15
|
+
@@debugging = $RUST_DEBUG || false
|
16
|
+
@@in_client_mutex = false
|
17
|
+
|
18
|
+
def self.debug
|
19
|
+
@@debugging = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.debug?
|
23
|
+
return @@debugging
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.exclusive
|
27
|
+
result = nil
|
28
|
+
CLIENT_MUTEX.synchronize do
|
29
|
+
@@in_client_mutex = true
|
30
|
+
result = yield
|
31
|
+
@@in_client_mutex = false
|
32
|
+
end
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[]=(variable, value)
|
37
|
+
if value.is_a?(RustDatatype)
|
38
|
+
value.load_in_r_as(variable.to_s)
|
39
|
+
elsif value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(Array) || value.is_a?(::Matrix)
|
40
|
+
R_ENGINE.assign(variable, value)
|
41
|
+
else
|
42
|
+
raise "Trying to assign #{variable} with #{value.class}; expected RustDatatype, String, Numeric, or Array"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.[](variable)
|
48
|
+
return RustDatatype.pull_variable(variable)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self._eval_big(r_command, return_warnings = false)
|
52
|
+
r_command = r_command.join("\n") if r_command.is_a?(Array)
|
53
|
+
|
54
|
+
self._rexec(r_command, return_warnings) do |cmd|
|
55
|
+
result = true
|
56
|
+
instructions = cmd.lines
|
57
|
+
|
58
|
+
while instructions.size > 0
|
59
|
+
current_command = ""
|
60
|
+
|
61
|
+
while (instructions.size > 0) && (current_command.length + instructions.first.length < 10000)
|
62
|
+
current_command << instructions.shift
|
63
|
+
end
|
64
|
+
|
65
|
+
result &= R_ENGINE.eval(current_command)
|
66
|
+
end
|
67
|
+
|
68
|
+
result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self._pull(r_command, return_warnings = false)
|
73
|
+
self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.pull(cmd) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def self._eval(r_command, return_warnings = false)
|
77
|
+
self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.eval(cmd) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def self._rexec(r_command, return_warnings = false)
|
81
|
+
puts "Calling _rexec with command: #{r_command}" if @@debugging
|
82
|
+
R_MUTEX.synchronize do
|
83
|
+
assert("This command must be executed in an exclusive block") { @@in_client_mutex }
|
84
|
+
|
85
|
+
result = nil
|
86
|
+
begin
|
87
|
+
$stdout = StringIO.new
|
88
|
+
if return_warnings
|
89
|
+
R_ENGINE.echo(true, true)
|
90
|
+
else
|
91
|
+
R_ENGINE.echo(false, false)
|
92
|
+
end
|
93
|
+
result = yield(r_command)
|
94
|
+
ensure
|
95
|
+
R_ENGINE.echo(false, false)
|
96
|
+
warnings = $stdout.string
|
97
|
+
$stdout = STDOUT
|
98
|
+
end
|
99
|
+
|
100
|
+
if return_warnings
|
101
|
+
puts " Got #{warnings.size} warnings, with result #{result.inspect[0...100]}" if @@debugging
|
102
|
+
return result, warnings.lines.map { |w| w.strip.chomp }
|
103
|
+
else
|
104
|
+
puts " Result: #{result.inspect[0...100]}" if @@debugging
|
105
|
+
return result
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.check_library(name)
|
111
|
+
self.exclusive do
|
112
|
+
result, _ = self._pull("require(\"#{name}\", character.only = TRUE)", true)
|
113
|
+
return result
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.load_library(name)
|
118
|
+
self.exclusive do
|
119
|
+
self._eval("library(\"#{name}\", character.only = TRUE)")
|
120
|
+
end
|
121
|
+
|
122
|
+
return nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.install_library(name)
|
126
|
+
self.exclusive do
|
127
|
+
self._eval("install.packages(\"#{name}\", dependencies = TRUE)")
|
128
|
+
end
|
129
|
+
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.prerequisite(library)
|
134
|
+
self.install_library(library) unless self.check_library(library)
|
135
|
+
self.load_library(library)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
module Rust::RBindings
|
140
|
+
def data_frame(*args)
|
141
|
+
Rust::DataFrame.new(*args)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module Rust::TestCases
|
146
|
+
def self.sample_dataframe(columns, size=100)
|
147
|
+
result = Rust::DataFrame.new(columns)
|
148
|
+
size.times do |i|
|
149
|
+
result << columns.map { |c| yield i, c }
|
150
|
+
end
|
151
|
+
return result
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def bind_r!
|
156
|
+
include Rust::RBindings
|
157
|
+
end
|
@@ -1,123 +1,20 @@
|
|
1
|
-
|
2
|
-
require 'stringio'
|
3
|
-
require 'rinruby'
|
4
|
-
require 'csv'
|
1
|
+
require_relative 'datatype'
|
5
2
|
|
6
3
|
module Rust
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
R_ENGINE = RinRuby.new(echo: false)
|
11
|
-
|
12
|
-
private_constant :R_ENGINE
|
13
|
-
private_constant :R_MUTEX
|
14
|
-
private_constant :CLIENT_MUTEX
|
15
|
-
|
16
|
-
@@debugging = false
|
17
|
-
@@in_client_mutex = false
|
18
|
-
|
19
|
-
def self.debug
|
20
|
-
@@debugging = true
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.exclusive
|
24
|
-
result = nil
|
25
|
-
CLIENT_MUTEX.synchronize do
|
26
|
-
@@in_client_mutex = true
|
27
|
-
result = yield
|
28
|
-
@@in_client_mutex = false
|
29
|
-
end
|
30
|
-
return result
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.[]=(variable, value)
|
34
|
-
if value.is_a?(RustDatatype)
|
35
|
-
value.load_in_r_as(variable.to_s)
|
36
|
-
elsif value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(Array)
|
37
|
-
R_ENGINE.assign(variable, value)
|
38
|
-
else
|
39
|
-
raise "Given #{value.class}, expected RustDatatype, String, Numeric, or Array"
|
4
|
+
class DataFrame < RustDatatype
|
5
|
+
def self.can_pull?(type, klass)
|
6
|
+
return [klass].flatten.include?("data.frame")
|
40
7
|
end
|
41
8
|
|
42
|
-
|
43
|
-
|
44
|
-
def self.[](variable, type=RustDatatype)
|
45
|
-
return type.pull_variable(variable)
|
46
|
-
end
|
47
|
-
|
48
|
-
def self._eval_big(r_command, return_warnings = false)
|
49
|
-
r_command = r_command.join("\n") if r_command.is_a?(Array)
|
50
|
-
|
51
|
-
self._rexec(r_command, return_warnings) do |cmd|
|
52
|
-
result = true
|
53
|
-
instructions = cmd.lines
|
54
|
-
|
55
|
-
while instructions.size > 0
|
56
|
-
current_command = ""
|
57
|
-
|
58
|
-
while (instructions.size > 0) && (current_command.length + instructions.first.length < 10000)
|
59
|
-
current_command << instructions.shift
|
60
|
-
end
|
61
|
-
|
62
|
-
result &= R_ENGINE.eval(current_command)
|
63
|
-
end
|
64
|
-
|
65
|
-
result
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def self._pull(r_command, return_warnings = false)
|
70
|
-
self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.pull(cmd) }
|
71
|
-
end
|
72
|
-
|
73
|
-
def self._eval(r_command, return_warnings = false)
|
74
|
-
self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.eval(cmd) }
|
75
|
-
end
|
76
|
-
|
77
|
-
def self._rexec(r_command, return_warnings = false)
|
78
|
-
puts "Calling _rexec with command: #{r_command}" if @@debugging
|
79
|
-
R_MUTEX.synchronize do
|
80
|
-
assert("This command must be executed in an exclusive block") { @@in_client_mutex }
|
81
|
-
|
82
|
-
result = nil
|
83
|
-
begin
|
84
|
-
$stdout = StringIO.new
|
85
|
-
if return_warnings
|
86
|
-
R_ENGINE.echo(true, true)
|
87
|
-
else
|
88
|
-
R_ENGINE.echo(false, false)
|
89
|
-
end
|
90
|
-
result = yield(r_command)
|
91
|
-
ensure
|
92
|
-
R_ENGINE.echo(false, false)
|
93
|
-
warnings = $stdout.string
|
94
|
-
$stdout = STDOUT
|
95
|
-
end
|
96
|
-
|
97
|
-
if return_warnings
|
98
|
-
return result, warnings.lines.map { |w| w.strip.chomp }
|
99
|
-
else
|
100
|
-
return result
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class RustDatatype
|
106
|
-
def self.pull_variable(variable)
|
107
|
-
return Rust._pull(variable)
|
9
|
+
def self.pull_priority
|
10
|
+
1
|
108
11
|
end
|
109
12
|
|
110
|
-
def
|
111
|
-
raise "Not implemented"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class DataFrame < RustDatatype
|
116
|
-
def self.pull_variable(variable)
|
13
|
+
def self.pull_variable(variable, type, klass)
|
117
14
|
hash = {}
|
118
|
-
colnames = Rust
|
15
|
+
colnames = Rust["colnames(#{variable})"]
|
119
16
|
colnames.each do |col|
|
120
|
-
hash[col] = Rust
|
17
|
+
hash[col] = Rust["#{variable}$\"#{col}\""]
|
121
18
|
end
|
122
19
|
return DataFrame.new(hash)
|
123
20
|
end
|
@@ -373,6 +270,14 @@ module Rust
|
|
373
270
|
row_index += 1
|
374
271
|
end
|
375
272
|
|
273
|
+
self.column_names.each do |name|
|
274
|
+
column = self.column(name)
|
275
|
+
|
276
|
+
if column.is_a?(Factor)
|
277
|
+
command << "#{variable_name}[,#{name.to_R}] <- factor(#{variable_name}[,#{name.to_R}], labels=#{column.levels.to_R})"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
376
281
|
Rust._eval_big(command)
|
377
282
|
end
|
378
283
|
|
@@ -586,82 +491,6 @@ module Rust
|
|
586
491
|
end
|
587
492
|
end
|
588
493
|
|
589
|
-
class Matrix < RustDatatype
|
590
|
-
def self.pull_variable(variable)
|
591
|
-
return Rust._pull(variable)
|
592
|
-
end
|
593
|
-
|
594
|
-
def initialize(data)
|
595
|
-
if data.flatten.size == 0
|
596
|
-
raise "Empty matrices are not allowed"
|
597
|
-
else
|
598
|
-
raise TypeError, "Expected array of array" unless data.is_a?(Array) && data[0].is_a?(Array)
|
599
|
-
raise TypeError, "Only numeric matrices are supported" unless data.all? { |row| row.all? { |e| e.is_a?(Numeric) } }
|
600
|
-
raise "All the rows must have the same size" unless data.map { |row| row.size }.uniq.size == 1
|
601
|
-
@data = data.clone
|
602
|
-
end
|
603
|
-
end
|
604
|
-
|
605
|
-
def [](i, j)
|
606
|
-
return @data[i][j]
|
607
|
-
end
|
608
|
-
|
609
|
-
def rows
|
610
|
-
@data.size
|
611
|
-
end
|
612
|
-
|
613
|
-
def cols
|
614
|
-
@data[0].size
|
615
|
-
end
|
616
|
-
|
617
|
-
def []=(i, j, value)
|
618
|
-
raise "Wrong i" unless i.between?(0, @data.size - 1)
|
619
|
-
raise "Wrong j" unless j.between?(0, @data[0].size - 1)
|
620
|
-
@data[i][j] = value
|
621
|
-
end
|
622
|
-
|
623
|
-
def load_in_r_as(variable_name)
|
624
|
-
Rust._eval("#{variable_name} <- matrix(c(#{@data.flatten.join(",")}), nrow=#{self.rows}, ncol=#{self.cols}, byrow=T)")
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
class Sequence < RustDatatype
|
629
|
-
attr_reader :min
|
630
|
-
attr_reader :max
|
631
|
-
|
632
|
-
def initialize(min, max, step=1)
|
633
|
-
@min = min
|
634
|
-
@max = max
|
635
|
-
@step = step
|
636
|
-
end
|
637
|
-
|
638
|
-
def step(step)
|
639
|
-
@step = step
|
640
|
-
end
|
641
|
-
|
642
|
-
def each
|
643
|
-
(@min..@max).step(@step) do |v|
|
644
|
-
yield v
|
645
|
-
end
|
646
|
-
end
|
647
|
-
|
648
|
-
def to_a
|
649
|
-
result = []
|
650
|
-
self.each do |v|
|
651
|
-
result << v
|
652
|
-
end
|
653
|
-
return result
|
654
|
-
end
|
655
|
-
|
656
|
-
def to_R
|
657
|
-
"seq(from=#@min, to=#@max, by=#@step)"
|
658
|
-
end
|
659
|
-
|
660
|
-
def load_in_r_as(variable_name)
|
661
|
-
Rust._eval("#{variable_name} <- #{self.to_R}")
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
665
494
|
class DataFrameArray < Array
|
666
495
|
def bind_all
|
667
496
|
return nil if self.size == 0
|
@@ -689,151 +518,4 @@ module Rust
|
|
689
518
|
return result
|
690
519
|
end
|
691
520
|
end
|
692
|
-
|
693
|
-
class MathArray < Array
|
694
|
-
def -(other)
|
695
|
-
raise ArgumentError, "Expected array or numeric" if !other.is_a?(::Array) && !other.is_a?(Numeric)
|
696
|
-
raise ArgumentError, "The two arrays must have the same size" if other.is_a?(::Array) && self.size != other.size
|
697
|
-
|
698
|
-
result = self.clone
|
699
|
-
other = [other] * self.size if other.is_a?(Numeric)
|
700
|
-
for i in 0...self.size
|
701
|
-
result[i] -= other[i]
|
702
|
-
end
|
703
|
-
|
704
|
-
return result
|
705
|
-
end
|
706
|
-
|
707
|
-
def *(other)
|
708
|
-
raise ArgumentError, "Expected array or numeric" if !other.is_a?(::Array) && !other.is_a?(Numeric)
|
709
|
-
raise ArgumentError, "The two arrays must have the same size" if other.is_a?(::Array) && self.size != other.size
|
710
|
-
|
711
|
-
result = self.clone
|
712
|
-
other = [other] * self.size if other.is_a?(Numeric)
|
713
|
-
for i in 0...self.size
|
714
|
-
result[i] *= other[i]
|
715
|
-
end
|
716
|
-
|
717
|
-
return result
|
718
|
-
end
|
719
|
-
|
720
|
-
def +(other)
|
721
|
-
raise ArgumentError, "Expected array or numeric" if !other.is_a?(::Array) && !other.is_a?(Numeric)
|
722
|
-
raise ArgumentError, "The two arrays must have the same size" if other.is_a?(::Array) && self.size != other.size
|
723
|
-
|
724
|
-
result = self.clone
|
725
|
-
other = [other] * self.size if other.is_a?(Numeric)
|
726
|
-
for i in 0...self.size
|
727
|
-
result[i] += other[i]
|
728
|
-
end
|
729
|
-
|
730
|
-
return result
|
731
|
-
end
|
732
|
-
|
733
|
-
def /(other) #To recover the syntax highlighting but in Kate: /
|
734
|
-
raise ArgumentError, "Expected array or numeric" if !other.is_a?(::Array) && !other.is_a?(Numeric)
|
735
|
-
raise ArgumentError, "The two arrays must have the same size" if other.is_a?(::Array) && self.size != other.size
|
736
|
-
|
737
|
-
result = self.clone
|
738
|
-
other = [other] * self.size if other.is_a?(Numeric)
|
739
|
-
for i in 0...self.size
|
740
|
-
result[i] /= other[i]
|
741
|
-
end
|
742
|
-
|
743
|
-
return result
|
744
|
-
end
|
745
|
-
|
746
|
-
def **(other)
|
747
|
-
raise ArgumentError, "Expected numeric" if !other.is_a?(Numeric)
|
748
|
-
|
749
|
-
result = self.clone
|
750
|
-
for i in 0...self.size
|
751
|
-
result[i] = result[i] ** other
|
752
|
-
end
|
753
|
-
|
754
|
-
return result
|
755
|
-
end
|
756
|
-
end
|
757
|
-
end
|
758
|
-
|
759
|
-
class TrueClass
|
760
|
-
def to_R
|
761
|
-
"TRUE"
|
762
|
-
end
|
763
|
-
end
|
764
|
-
|
765
|
-
class FalseClass
|
766
|
-
def to_R
|
767
|
-
"FALSE"
|
768
|
-
end
|
769
|
-
end
|
770
|
-
|
771
|
-
class Object
|
772
|
-
def to_R
|
773
|
-
raise TypeError, "Unsupported type for #{self.class}"
|
774
|
-
end
|
775
|
-
end
|
776
|
-
|
777
|
-
class NilClass
|
778
|
-
def to_R
|
779
|
-
return "NULL"
|
780
|
-
end
|
781
|
-
end
|
782
|
-
|
783
|
-
class Numeric
|
784
|
-
def to_R
|
785
|
-
self.inspect
|
786
|
-
end
|
787
|
-
end
|
788
|
-
|
789
|
-
class Float
|
790
|
-
def to_R
|
791
|
-
return self.nan? ? "NA" : super
|
792
|
-
end
|
793
|
-
end
|
794
|
-
|
795
|
-
class Array
|
796
|
-
def to_R
|
797
|
-
return "c(#{self.map { |e| e.to_R }.join(",")})"
|
798
|
-
end
|
799
|
-
|
800
|
-
def distribution
|
801
|
-
result = {}
|
802
|
-
self.each do |value|
|
803
|
-
result[value] = result[value].to_i + 1
|
804
|
-
end
|
805
|
-
return result
|
806
|
-
end
|
807
|
-
end
|
808
|
-
|
809
|
-
class String
|
810
|
-
def to_R
|
811
|
-
return self.inspect
|
812
|
-
end
|
813
|
-
end
|
814
|
-
|
815
|
-
class Range
|
816
|
-
def to_R
|
817
|
-
[range.min, range.max].to_R
|
818
|
-
end
|
819
|
-
end
|
820
|
-
|
821
|
-
module Rust::RBindings
|
822
|
-
def data_frame(*args)
|
823
|
-
Rust::DataFrame.new(*args)
|
824
|
-
end
|
825
|
-
end
|
826
|
-
|
827
|
-
module Rust::TestCases
|
828
|
-
def self.sample_dataframe(columns, size=100)
|
829
|
-
result = Rust::DataFrame.new(columns)
|
830
|
-
size.times do |i|
|
831
|
-
result << columns.map { |c| yield i, c }
|
832
|
-
end
|
833
|
-
return result
|
834
|
-
end
|
835
|
-
end
|
836
|
-
|
837
|
-
def bind_r!
|
838
|
-
include Rust::RBindings
|
839
521
|
end
|