scicom 0.2.0-java

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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +674 -0
  3. data/README.md +66 -0
  4. data/README.md~ +290 -0
  5. data/Rakefile +51 -0
  6. data/config.rb +163 -0
  7. data/doc/PypeR.pdf +0 -0
  8. data/doc/Stat 133 Class Notes (Phil Spector).pdf +29905 -45
  9. data/doc/The R interface.docx +0 -0
  10. data/lib/JRubyR/as_mdarray.rb +60 -0
  11. data/lib/JRubyR/attributes.rb +74 -0
  12. data/lib/JRubyR/dataframe.rb +35 -0
  13. data/lib/JRubyR/environment.rb +60 -0
  14. data/lib/JRubyR/function.rb +61 -0
  15. data/lib/JRubyR/index.rb +278 -0
  16. data/lib/JRubyR/list.rb +56 -0
  17. data/lib/JRubyR/list_orig.rb +111 -0
  18. data/lib/JRubyR/logical_value.rb +56 -0
  19. data/lib/JRubyR/rbsexp.rb +386 -0
  20. data/lib/JRubyR/renjin.rb +431 -0
  21. data/lib/JRubyR/ruby_classes.rb +58 -0
  22. data/lib/JRubyR/sequence.rb +56 -0
  23. data/lib/JRubyR/vector.rb +493 -0
  24. data/lib/env.rb +12 -0
  25. data/lib/rinruby.rb +795 -0
  26. data/lib/scicom.rb +29 -0
  27. data/target/helper.jar +0 -0
  28. data/test/baseball.csv +1 -0
  29. data/test/env.rb +7 -0
  30. data/test/test_R_interface.rb +165 -0
  31. data/test/test_array.rb +191 -0
  32. data/test/test_attributes.rb +261 -0
  33. data/test/test_basic.rb +156 -0
  34. data/test/test_column-major.rb +114 -0
  35. data/test/test_complete.rb +49 -0
  36. data/test/test_creation.rb +299 -0
  37. data/test/test_dataframe.rb +248 -0
  38. data/test/test_distribution.rb +320 -0
  39. data/test/test_double_assign.rb +240 -0
  40. data/test/test_double_receive.rb +106 -0
  41. data/test/test_environment.rb +57 -0
  42. data/test/test_factor.rb +285 -0
  43. data/test/test_functions.rb +67 -0
  44. data/test/test_linear_model.rb +64 -0
  45. data/test/test_list.rb +220 -0
  46. data/test/test_matrix.rb +205 -0
  47. data/test/test_mdarray.rb +258 -0
  48. data/test/test_operators.rb +227 -0
  49. data/test/test_sequence.rb +63 -0
  50. data/test/test_subsetting.rb +67 -0
  51. data/test/test_tmp.rb +67 -0
  52. data/test/test_vector.rb +227 -0
  53. data/vendor/Renjin.pdf +0 -0
  54. data/vendor/renjin-script-engine-0.7.0-RC7-SNAPSHOT-jar-with-dependencies.jar +0 -0
  55. data/version.rb +2 -0
  56. metadata +196 -0
@@ -0,0 +1,431 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##########################################################################################
4
+ # @author Rodrigo Botafogo
5
+ #
6
+ # Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
7
+ # and distribute this software and its documentation, without fee and without a signed
8
+ # licensing agreement, is hereby granted, provided that the above copyright notice, this
9
+ # paragraph and the following two paragraphs appear in all copies, modifications, and
10
+ # distributions.
11
+ #
12
+ # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
13
+ # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
14
+ # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
15
+ # POSSIBILITY OF SUCH DAMAGE.
16
+ #
17
+ # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
19
+ # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
20
+ # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
21
+ # OR MODIFICATIONS.
22
+ ##########################################################################################
23
+
24
+ require 'java'
25
+ require 'securerandom'
26
+
27
+ require_relative 'rbsexp'
28
+ require_relative 'index'
29
+
30
+
31
+ #==========================================================================================
32
+ #
33
+ #==========================================================================================
34
+
35
+ class Renjin
36
+ include_package "javax.script"
37
+ include_package "org.renjin"
38
+
39
+ @stack = Array.new
40
+
41
+ class << self
42
+ attr_accessor :stack
43
+ end
44
+
45
+ #----------------------------------------------------------------------------------------
46
+ #
47
+ #----------------------------------------------------------------------------------------
48
+
49
+ attr_reader :engine
50
+
51
+ # Parse error
52
+ ParseError=Class.new(Exception)
53
+
54
+ #----------------------------------------------------------------------------------------
55
+ # R is invoked within a Ruby script (or the interactive "irb" prompt denoted >>) using:
56
+ #
57
+ # >> require "scicom"
58
+ #
59
+ # The previous statement reads the definition of the RinRuby class into the current Ruby
60
+ # interpreter and creates an instance of the RinRuby class named R. There is a second
61
+ # method for starting an instance of R which allows the user to use any name for the
62
+ # instance, in this case myr:
63
+ #
64
+ # >> require "scicom"
65
+ # >> myr = RinRuby.new
66
+ # >> myr.eval "rnorm(1)"
67
+ #
68
+ # Any number of independent instances of R can be created in this way.
69
+ #----------------------------------------------------------------------------------------
70
+
71
+ def initialize
72
+
73
+ @platform =
74
+ case RUBY_PLATFORM
75
+ when /mswin/ then 'windows'
76
+ when /mingw/ then 'windows'
77
+ when /bccwin/ then 'windows'
78
+ when /cygwin/ then 'windows-cygwin'
79
+ when /java/
80
+ require 'java' #:nodoc:
81
+ if java.lang.System.getProperty("os.name") =~ /[Ww]indows/
82
+ 'windows-java'
83
+ else
84
+ 'default-java'
85
+ end
86
+ else 'default'
87
+ end
88
+
89
+ factory = Java::JavaxScript.ScriptEngineManager.new()
90
+ @engine = factory.getEngineByName("Renjin")
91
+
92
+ end
93
+
94
+ #----------------------------------------------------------------------------------------
95
+ # Converts an MDArray shape or index onto an equivalent R shape or index
96
+ #----------------------------------------------------------------------------------------
97
+
98
+ def ri(shape)
99
+
100
+ rshape = shape.clone
101
+
102
+ if (rshape.size > 2)
103
+ rshape.reverse!
104
+ rshape[0], rshape[1] = rshape[1], rshape[0]
105
+ end
106
+ rshape.map{ |val| (val + 1) }
107
+
108
+ end
109
+
110
+ #----------------------------------------------------------------------------------------
111
+ #
112
+ #----------------------------------------------------------------------------------------
113
+
114
+ def nan?(x)
115
+ is__nan(x)
116
+ end
117
+
118
+ #----------------------------------------------------------------------------------------
119
+ # The integer constant used to designate elements or values that are
120
+ # missing in the statistical sense, or literally "Not Available".
121
+ # For integers (Fixnum) this is represented as the minimum integer from Java
122
+ # Integer.MIN_VALUE
123
+ #----------------------------------------------------------------------------------------
124
+
125
+ def na?(x)
126
+ R.is__na(x)
127
+ end
128
+
129
+ #----------------------------------------------------------------------------------------
130
+ #
131
+ #----------------------------------------------------------------------------------------
132
+
133
+ def finite?(x)
134
+ R.is__finite(x)
135
+ end
136
+
137
+ #----------------------------------------------------------------------------------------
138
+ #
139
+ #----------------------------------------------------------------------------------------
140
+
141
+ def method_missing(symbol, *args)
142
+
143
+ name = symbol.id2name
144
+ name.gsub!(/__/,".")
145
+ # Method 'rclass' is a substitute for R method 'class'. Needed, as 'class' is also
146
+ # a Ruby method on an object
147
+ name.gsub!("rclass", "class")
148
+
149
+ if name =~ /(.*)=$/
150
+ super if args.length != 1
151
+ ret = assign($1,args[0])
152
+ else
153
+ # super if args.length != 0
154
+ if (args.length == 0)
155
+ # is_var = false
156
+ # Try to see if name is a variable or a method.
157
+ ret = (eval("\"#{name}\" %in% ls()").gt)? eval("#{name}") : eval("#{name}()")
158
+ else
159
+ params = parse(*args)
160
+ # p "#{name}(#{params})"
161
+ ret = eval("#{name}(#{params})")
162
+ end
163
+ end
164
+
165
+ ret
166
+
167
+ end
168
+
169
+ #----------------------------------------------------------------------------------------
170
+ # R built-in constants
171
+ #----------------------------------------------------------------------------------------
172
+
173
+ def pi
174
+ R.eval("pi")
175
+ end
176
+
177
+ def LETTERS
178
+ R.eval("LETTERS")
179
+ end
180
+
181
+ def letters
182
+ R.eval("letters")
183
+ end
184
+
185
+ def month__abb
186
+ R.eval("month.abb")
187
+ end
188
+
189
+ def month__name
190
+ R.eval("month.name")
191
+ end
192
+
193
+ def i(value)
194
+ R.eval("#{value}L")
195
+ end
196
+
197
+ def d(value)
198
+ R.eval("#{value}")
199
+ end
200
+
201
+ #----------------------------------------------------------------------------------------
202
+ #
203
+ #----------------------------------------------------------------------------------------
204
+
205
+ def eval(expression)
206
+ begin
207
+ ret = Renjin::RubySexp.build(@engine.eval(expression))
208
+ rescue Java::OrgRenjinEval::EvalException => e
209
+ p e.message
210
+ rescue Java::OrgRenjinParser::ParseException => e
211
+ p e.message
212
+ ensure
213
+ Renjin.stack.each do |sexp|
214
+ sexp.destroy
215
+ end
216
+ end
217
+
218
+ ret
219
+
220
+ end
221
+
222
+ #----------------------------------------------------------------------------------------
223
+ # Evaluates an expression but does not wrap the return in a RubySexp. Needed for
224
+ # intermediate evaluation done by internal methods. In principle, should not be
225
+ # called by users.
226
+ #----------------------------------------------------------------------------------------
227
+
228
+ def direct_eval(expression)
229
+ begin
230
+ ret = @engine.eval(expression)
231
+ rescue Java::OrgRenjinEval::EvalException => e
232
+ p e.message
233
+ ensure
234
+ =begin
235
+ Renjin.stack.each do |sexp|
236
+ sexp.destroy
237
+ end
238
+ =end
239
+ end
240
+
241
+ ret
242
+
243
+ end
244
+
245
+ #----------------------------------------------------------------------------------------
246
+ #
247
+ #----------------------------------------------------------------------------------------
248
+
249
+ def parse(*args)
250
+
251
+ params = Array.new
252
+
253
+ args.each do |arg|
254
+ if (arg.is_a? Numeric)
255
+ params << arg
256
+ elsif(arg.is_a? String)
257
+ params << "\"#{arg}\""
258
+ elsif (arg.is_a? Symbol)
259
+ var = eval("#{arg.to_s}")
260
+ params << var.r
261
+ elsif (arg.is_a? TrueClass)
262
+ params << "TRUE"
263
+ elsif (arg.is_a? FalseClass)
264
+ params << "FALSE"
265
+ elsif (arg == nil)
266
+ params << "NULL"
267
+ elsif (arg.is_a? NegRange)
268
+ final_value = (arg.exclude_end?)? (arg.end - 1) : arg.end
269
+ params << "-(#{arg.begin}:#{final_value})"
270
+ elsif (arg.is_a? Range)
271
+ final_value = (arg.exclude_end?)? (arg.end - 1) : arg.end
272
+ params << "(#{arg.begin}:#{final_value})"
273
+ elsif (arg.is_a? Hash)
274
+ arg.each_pair do |key, value|
275
+ params << "#{key.to_s} = #{parse(value)}"
276
+ end
277
+ elsif ((arg.is_a? Renjin::RubySexp) || (arg.is_a? Array) || (arg.is_a? MDArray))
278
+ params << arg.r
279
+ # elsif
280
+ # params << arg.inspect
281
+ else
282
+ raise "Unknown parameter type for R: #{arg}"
283
+ end
284
+
285
+ end
286
+
287
+ params.join(",")
288
+
289
+ end
290
+
291
+ #----------------------------------------------------------------------------------------
292
+ # Data is copied from Ruby to R using the assign method or a short-hand equivalent. For
293
+ # example:
294
+ #
295
+ # >> names = ["Lisa","Teasha","Aaron","Thomas"]
296
+ # >> R.assign "people", names
297
+ # >> R.eval "sort(people)"
298
+ #
299
+ #produces the following :
300
+ #
301
+ # [1] "Aaron" "Lisa" "Teasha" "Thomas"
302
+ #
303
+ # The short-hand equivalent to the assign method is simply:
304
+ #
305
+ # >> R.people = names
306
+ #
307
+ # Some care is needed when using the short-hand of the assign method since the label
308
+ # (i.e., people in this case) must be a valid method name in Ruby. For example,
309
+ # R.copy.of.names = names will not work, but R.copy_of_names = names is permissible.
310
+ #
311
+ # The assign method supports Ruby variables of type Fixnum (i.e., integer), Bignum
312
+ # (i.e., integer), Float (i.e., double), String, and arrays of one of those three
313
+ # fundamental types. Note that Fixnum or Bignum values that exceed the capacity of R's
314
+ # integers are silently converted to doubles. Data in other formats must be coerced
315
+ # when copying to R.
316
+ #
317
+ # <b>Parameters that can be passed to the assign method:</b>
318
+ #
319
+ # * name: The name of the variable desired in R.
320
+ # * value: The value the R variable should have.
321
+ #
322
+ # The assign method is an alternative to the simplified method, with some additional
323
+ # flexibility. When using the simplified method, the parameters of name and value are
324
+ # automatically used, in other words:
325
+ #
326
+ # >> R.test = 144
327
+ #
328
+ # is the same as:
329
+ #
330
+ # >> R.assign("test",144)
331
+ #
332
+ # Of course it would be confusing to use the shorthand notation to assign a variable
333
+ # named eval, echo, or any other already defined function. RinRuby would assume you were
334
+ # calling the function, rather than trying to assign a variable.
335
+ #
336
+ # When assigning an array containing differing types of variables, RinRuby will follow
337
+ # R’s conversion conventions. An array that contains any Strings will result in a
338
+ # character vector in R. If the array does not contain any Strings, but it does contain
339
+ # a Float or a large integer (in absolute value), then the result will be a numeric
340
+ # vector of Doubles in R. If there are only integers that are suffciently small (in
341
+ # absolute value), then the result will be a numeric vector of integers in R.
342
+ #----------------------------------------------------------------------------------------
343
+
344
+ def assign(name, value)
345
+
346
+ original_value = value
347
+
348
+ if ((value.is_a? MDArray) || (value.is_a? RubySexp))
349
+ if (value.sexp != nil)
350
+ # MDArray already represented in R
351
+ value = value.sexp
352
+ else
353
+ value = build_vector(value)
354
+ end
355
+ elsif (value == nil)
356
+ value = NULL
357
+ end
358
+
359
+ @engine.put(name, value)
360
+ original_value
361
+
362
+ end
363
+
364
+ #----------------------------------------------------------------------------------------
365
+ #
366
+ #----------------------------------------------------------------------------------------
367
+
368
+ def pull(name)
369
+ eval(name)
370
+ end
371
+
372
+ #----------------------------------------------------------------------------------------
373
+ # function is either a function name alone represented by a ruby symbol or a hash
374
+ # with the function name and its arguments or indexes
375
+ # Ex:
376
+ # fassign(sexp, :rowname, "x1")
377
+ # fassign(sexp, {f: :rowname, index: [[1]]}, "x1")
378
+ # fassign(sexp, {f: :somefunc, params: "(2, 3, 4)"}, "x1")
379
+ #----------------------------------------------------------------------------------------
380
+
381
+ def fassign(sexp, function, value)
382
+
383
+ if (function.is_a? Hash)
384
+ index = function[:index]
385
+ params = function[:params]
386
+ function = function[:f]
387
+ if (index)
388
+ R.eval("#{function.to_s}(#{sexp.r})#{index} = #{value.r}")
389
+ else
390
+ end
391
+ else
392
+ R.eval("#{function.to_s}(#{sexp.r}) = #{value.r}")
393
+ end
394
+
395
+ end
396
+
397
+ #----------------------------------------------------------------------------------------
398
+ # Builds a Renjin vector from an MDArray. Should be private, but public for testing.
399
+ #----------------------------------------------------------------------------------------
400
+
401
+ def build_vector(array)
402
+
403
+ shape = array.shape
404
+ index = array.nc_array.getIndex()
405
+ # index = MDArray.index_factory(shape)
406
+ # representation of shape in R is different from shape in MDArray. Convert MDArray
407
+ # shape to R shape.
408
+ if (shape.size > 2)
409
+ shape.reverse!
410
+ shape[0], shape[1] = shape[1], shape[0]
411
+ end
412
+ # AttributeMap attributes = AttributeMap.builder().setDim(new IntVector(dim)).build();
413
+ attributes = Java::OrgRenjinSexp::AttributeMap.builder()
414
+ .setDim(Java::OrgRenjinSexp::IntArrayVector.new(*(shape))).build()
415
+ vector = Java::RbScicom::MDDoubleVector.new(array.nc_array, attributes, index,
416
+ index.stride)
417
+
418
+ end
419
+
420
+
421
+ end
422
+
423
+ # Create a new R interpreter
424
+ R = Renjin.new
425
+ NA = R.eval("NA")
426
+ NaN = R.eval("NaN")
427
+ Inf = R.eval("Inf")
428
+ MInf = R.eval("-Inf")
429
+ NULL = R.direct_eval("NULL")
430
+ # EPSILON = R.eval("EPSILON")
431
+ # NA_integer = R.eval("NA_integer")
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##########################################################################################
4
+ # @author Rodrigo Botafogo
5
+ #
6
+ # Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
7
+ # and distribute this software and its documentation, without fee and without a signed
8
+ # licensing agreement, is hereby granted, provided that the above copyright notice, this
9
+ # paragraph and the following two paragraphs appear in all copies, modifications, and
10
+ # distributions.
11
+ #
12
+ # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
13
+ # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
14
+ # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
15
+ # POSSIBILITY OF SUCH DAMAGE.
16
+ #
17
+ # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
19
+ # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
20
+ # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
21
+ # OR MODIFICATIONS.
22
+ ##########################################################################################
23
+
24
+ #==========================================================================================
25
+ #
26
+ #==========================================================================================
27
+
28
+ class Range
29
+ include Renjin::RBSexp
30
+
31
+ #----------------------------------------------------------------------------------------
32
+ # Defines unary minus operation for ranges
33
+ #----------------------------------------------------------------------------------------
34
+
35
+ def -@
36
+ NegRange.new(self.begin, self.end)
37
+ end
38
+
39
+ end
40
+
41
+ #==========================================================================================
42
+ # Class NegRange exists to represent a negative range, e.g., -(1...10). Such a range is
43
+ # used to index vectors and means all elements but the ones in the given range. Class
44
+ # NegRange is parsed to become "-(1:10)" in R.
45
+ #==========================================================================================
46
+
47
+ class NegRange < Range
48
+
49
+ end
50
+
51
+ #==========================================================================================
52
+ #
53
+ #==========================================================================================
54
+
55
+ class Array
56
+ include Renjin::RBSexp
57
+
58
+ end