em-rserve 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+
2
+ require 'em-rserve/qap1/rpack'
3
+
4
+ module EM::Rserve
5
+ module QAP1
6
+ class Message
7
+ extend Rpack
8
+
9
+ def self.from_bin(dat)
10
+ new decode_parameters(dat)
11
+ end
12
+
13
+ attr_reader :parameters
14
+
15
+ def initialize(params=[])
16
+ @parameters = params
17
+ end
18
+
19
+ def pack_parameters
20
+ parameters.map{|p| self.class.encode_parameter(p)}.join
21
+ end
22
+
23
+ alias :to_bin :pack_parameters
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,127 @@
1
+
2
+ require 'em-rserve/qap1/constants'
3
+ require 'em-rserve/r/sexp'
4
+
5
+ module EM::Rserve
6
+ module QAP1
7
+ module Rpack
8
+ include Constants
9
+ include R
10
+
11
+ def parameter_head(type, len)
12
+ #TODO: support long parameter, type: 0xbf + DT_LARGE if len overflows
13
+ (type & 0x000000ff) | ((len << 8) & 0xffffff00)
14
+ end
15
+
16
+ def pack_parameter(type, len, val, rule)
17
+ [parameter_head(type, len), val].flatten.pack('V'+rule)
18
+ end
19
+
20
+ def encode_parameter(param, type=nil)
21
+ type ||= param
22
+ case param
23
+ when Integer, :int
24
+ encode_int param
25
+ when :char
26
+ encode_char param
27
+ when Float, :double
28
+ encode_double param
29
+ when String, :string
30
+ encode_string param
31
+ when Sexp::Node
32
+ encode_sexp_node param
33
+ when :bytestream
34
+ encode_bytestream param
35
+ #XXX Array and rest
36
+ end
37
+ end
38
+
39
+ def encode_int(val)
40
+ pack_parameter(DT_INT, 4, val, 'V')
41
+ end
42
+
43
+ def encode_char(val)
44
+ pack_parameter(DT_CHAR, 1, val, 'C')
45
+ end
46
+
47
+ def encode_double(val)
48
+ pack_parameter(DT_DOUBLE, 8, val, 'D')
49
+ end
50
+
51
+ def encode_string(val, len=nil, has_null=false)
52
+ if has_null
53
+ len ||= val.length
54
+ pack_parameter(DT_STRING, len, val, 'a*')
55
+ else
56
+ len ||= val.length + 1
57
+ pack_parameter(DT_STRING, len, [val, 0], 'a*C')
58
+ end
59
+ end
60
+
61
+ def encode_bytestream(val, len=nil)
62
+ len ||= val.length
63
+ pack_parameter(DT_BYTESTREAM, len, val, 'a*')
64
+ end
65
+
66
+ def encode_large(val, len=nil)
67
+ end
68
+
69
+ def encode_sexp_node(node, len=nil)
70
+ dat = node.dump_sexp
71
+ len ||= dat.length
72
+ pack_parameter(DT_SEXP, len, dat, 'a*')
73
+ end
74
+
75
+ def encode_array(val, len=nil)
76
+ end
77
+
78
+ def head_parameter(head)
79
+ type = head & 0x000000bf
80
+ large = (head & DT_LARGE) > 0
81
+ len = (head & 0xffffff00) >> 8
82
+ [type, len, large]
83
+ end
84
+
85
+ def decode_sexp(dat)
86
+ Sexp.parse(dat)
87
+ end
88
+
89
+ def decode_int(dat)
90
+ dat.unpack('i').first
91
+ end
92
+
93
+ def decode_bytestream(dat)
94
+ dat
95
+ end
96
+
97
+ def decode_parameter(type, dat, len=nil)
98
+ case type
99
+ when DT_SEXP
100
+ decode_sexp dat
101
+ when DT_INT
102
+ decode_int dat
103
+ when DT_BYTESTREAM
104
+ decode_bytestream dat
105
+ else
106
+ p "missing decode: #{type}"
107
+ end
108
+ end
109
+
110
+ def decode_parameters(buffer)
111
+ params = []
112
+ until buffer.empty? do
113
+ head, buffer = buffer.unpack('Va*')
114
+ type, len, large = head_parameter(head)
115
+ raise NotImplementedError, "too long QAP1 message" if large
116
+ if buffer.size < len
117
+ raise RuntimeError, "cannot decode #{buffer} (not enough bytes)"
118
+ end
119
+ param_data = buffer.slice(0, len)
120
+ buffer = buffer.slice(len .. -1)
121
+ params << decode_parameter(type, param_data, len)
122
+ end
123
+ params
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,152 @@
1
+
2
+ require 'em-rserve/r/sexp'
3
+
4
+ module EM::Rserve
5
+ module R
6
+ module RtoRuby
7
+ class Translator
8
+ def self.r_to_ruby(root)
9
+ node = root.children.first
10
+ attR = node.attribute
11
+
12
+ pair = [node.class, attR.class]
13
+ klass = case pair
14
+ when [Sexp::Node::ArrayInt, NilClass]
15
+ ArrayTranslator
16
+ when [Sexp::Node::ArrayBool, NilClass]
17
+ ArrayTranslator
18
+ when [Sexp::Node::ArrayString, NilClass]
19
+ ArrayTranslator
20
+ when [Sexp::Node::ArrayDouble, NilClass]
21
+ ArrayTranslator
22
+ when [Sexp::Node::ArrayComplex, NilClass]
23
+ ArrayTranslator
24
+ when [Sexp::Node::ArrayDouble, Sexp::Node::ListTag]
25
+ DateTranslator
26
+ when [Sexp::Node::ArrayInt, Sexp::Node::ListTag]
27
+ FactorTableTranslator
28
+ when [Sexp::Node::Vector, Sexp::Node::ListTag]
29
+ DataFrameTranslator
30
+ when [Sexp::Node::Closure, NilClass]
31
+ ClosureTranslator
32
+ else
33
+ DefaultTranslator
34
+ end
35
+ klass.new(node).translate
36
+ end
37
+
38
+ attr_reader :node
39
+
40
+ def initialize(node=nil)
41
+ @node = node
42
+ end
43
+
44
+ def translate
45
+ throw :cannot_translate
46
+ end
47
+
48
+ class DefaultTranslator < Translator
49
+ end
50
+
51
+ class ArrayTranslator < Translator
52
+ def translate
53
+ node.rb_val
54
+ end
55
+ end
56
+
57
+ class DateTranslator < Translator
58
+ def translate
59
+ case node.attribute.rb_val['class']
60
+ when 'Date'
61
+ Time.at(node.rb_val * 86400) # R gives days Ruby wants secs
62
+ else
63
+ super
64
+ end
65
+ end
66
+ end
67
+
68
+ class FactorTableTranslator < Translator
69
+ # Symbols represented by ints
70
+ class Factor < Array
71
+ attr_accessor :levels
72
+ end
73
+
74
+ # Frequency table
75
+ class Table < Hash
76
+ end
77
+
78
+ def translate_factor
79
+ levels = node.attribute.rb_val['levels']
80
+ levels = levels.map{|str| str.to_sym}
81
+ ret = Factor.new.replace(node.rb_val.map{|i| levels[i-1]})
82
+ end
83
+
84
+ def translate_table
85
+ keys = node.attribute.rb_val['dimnames'].first
86
+ vals = node.rb_val
87
+ Table[ keys.zip(vals) ]
88
+ end
89
+
90
+ def translate
91
+ case node.attribute.rb_val['class']
92
+ when 'factor'
93
+ translate_factor
94
+ when 'table'
95
+ translate_table
96
+ else
97
+ super
98
+ end
99
+ end
100
+ end
101
+
102
+ class DataFrameTranslator < Translator
103
+ class DataFrame < Hash
104
+ attr_accessor :rows, :r_class
105
+
106
+ def inspect
107
+ super.sub(/}$/," @r_class: #{r_class}, @rows: #{rows}")
108
+ end
109
+
110
+ def each_struct
111
+ if block_given?
112
+ all_keys = keys #not sure keys will always return the same order
113
+ struct = Struct.new(*all_keys.map(&:to_sym))
114
+ #XXX when we map and transpose, we actually do computation before they
115
+ #are needed, could improve with true-style iterators
116
+ all_keys.map{|k| self[k]}.transpose.each do |values|
117
+ yield struct.new(*values)
118
+ end
119
+ else
120
+ Enumerator.new(:self, :each_struct)
121
+ end
122
+ end
123
+ end
124
+
125
+ def translate_data_frame
126
+ attrs = node.attribute.rb_val
127
+ cols = [attrs['names']].flatten
128
+ rows = case attrs['row.names']
129
+ when [-2147483648, -8]
130
+ nil
131
+ else
132
+ [attrs['row.names']].flatten
133
+ end
134
+
135
+ dfrm = DataFrame[ cols.zip(node.rb_val) ]
136
+ dfrm.rows = rows if rows
137
+ dfrm
138
+ end
139
+
140
+ def translate
141
+ h = translate_data_frame
142
+ h.r_class = node.attribute.rb_val['class']
143
+ h
144
+ end
145
+ end
146
+
147
+ class ClosureTranslator < Translator
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,131 @@
1
+ require 'em-rserve/r/sexp'
2
+
3
+ module EM::Rserve
4
+ module R
5
+ module RubytoR
6
+ class Translator
7
+
8
+ def self.translator_klass_for(obj)
9
+ case obj
10
+ when Array
11
+ ArrayTranslator
12
+ when Hash
13
+ HashTranslator
14
+ else
15
+ SingleObjectTranslator
16
+ end
17
+ end
18
+
19
+ def self.ruby_to_r(obj)
20
+ translator_klass_for(obj).new(obj).translate
21
+ end
22
+
23
+ attr_reader :obj
24
+
25
+ def initialize(obj=nil)
26
+ @obj = obj
27
+ end
28
+
29
+ def translate
30
+ throw :cannot_translate
31
+ end
32
+
33
+ class SingleObjectTranslator < Translator
34
+ def translate
35
+ Translator.ruby_to_r [obj]
36
+ end
37
+ end
38
+
39
+ class ArrayTranslator < Translator
40
+ MAPPING = {String => EM::Rserve::R::Sexp::Node::ArrayString,
41
+ Integer => EM::Rserve::R::Sexp::Node::ArrayInt,
42
+ Float => EM::Rserve::R::Sexp::Node::ArrayDouble,
43
+ NilClass => EM::Rserve::R::Sexp::Node::ArrayBool,
44
+ TrueClass => EM::Rserve::R::Sexp::Node::ArrayBool,
45
+ FalseClass => EM::Rserve::R::Sexp::Node::ArrayBool,
46
+ }
47
+
48
+ def array_node_class
49
+ classes = obj.map(&:class).uniq
50
+ if classes.size == 1
51
+ obj_klass = classes.first
52
+ MAPPING.each_pair do |klass, node|
53
+ return node if obj_klass.ancestors.include?(klass)
54
+ end
55
+ elsif (classes - [TrueClass,NilClass,FalseClass]).empty?
56
+ EM::Rserve::R::Sexp::Node::ArrayBool
57
+ elsif (classes - [Float, Fixnum]).empty?
58
+ EM::Rserve::R::Sexp::Node::ArrayDouble
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def translate
65
+ klass = array_node_class
66
+ throw :cannot_translate unless klass
67
+ EM::Rserve::R::Sexp::Node::Root.new do |root|
68
+ klass.new do |array|
69
+ array.rb_raw = obj
70
+ root.children << array
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ class HashTranslator < Translator
77
+ def list_node_class
78
+ EM::Rserve::R::Sexp::Node::Vector
79
+ end
80
+
81
+ def list_node_attribute_class
82
+ EM::Rserve::R::Sexp::Node::ListTag
83
+ end
84
+
85
+ def translate
86
+ klass = list_node_class
87
+ attr_klass = list_node_attribute_class
88
+ throw :cannot_translate unless klass and attr_klass
89
+ raise :cannot_translate if obj.empty?
90
+ pairs = obj.each_pair.to_a
91
+ size = pairs.first.last.size
92
+ #TODO: check if sizes differ and raise
93
+ EM::Rserve::R::Sexp::Node::Root.new do |root|
94
+ klass.new do |vector|
95
+ vector.attribute = attr_klass.new do |taglist|
96
+ # add ArrayString with keys as strings for column names
97
+ # add SymName "names"
98
+ taglist.children << ArrayTranslator.new(pairs.map(&:first).map(&:to_s)).translate.children.first
99
+ sym = EM::Rserve::R::Sexp::Node::SymName.new
100
+ sym.rb_raw = "names"
101
+ taglist.children << sym
102
+ # add ArrayInt -2147483648, -(size) for rows
103
+ # add SymName "row.names"
104
+ taglist.children << ArrayTranslator.new([-2147483648, 0 - size]).translate.children.first
105
+ sym = EM::Rserve::R::Sexp::Node::SymName.new
106
+ sym.rb_raw = "row.names"
107
+ taglist.children << sym
108
+
109
+ # add ArrayString "data.frame"
110
+ # add SymName "class"
111
+ taglist.children << ArrayTranslator.new(["data.frame"]).translate.children.first
112
+ sym = EM::Rserve::R::Sexp::Node::SymName.new
113
+ sym.rb_raw = "class"
114
+ taglist.children << sym
115
+ end #attribute
116
+
117
+ pairs.each do |k,values|
118
+ array_node = ArrayTranslator.new(values).translate.children.first
119
+ vector.children << array_node
120
+ end #children
121
+ root.children << vector
122
+ end #vector
123
+ end
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+ end
131
+