Creating SciCom Vectors
In R, every number is a one dimensional vector with a single element. In order to work with SciCom, users need to convert Ruby numbers to R vectors. For this, SciCom provides methods eval, i and d. Method .eval return an object of type SEXP, the root of all types in SciCom. Method i converts an integer to an int vector and method d converts a double to a double vector.
Users can create variables both in the Ruby namespace as in the R namespace. In SciCom, we will be mostly interested in working in the Ruby namespace, and in future sections we will stop using method eval.
Creating a variable in R namespace can be done inside an eval clause.
In the following code we create variable r.i in R namespace. This variable is not directly availabe in Ruby namespace
R.eval("i1 = 10L")
R.eval("print(i1)") # will print the R int vector
p i1 # results in an error in the Ruby script
Will output:
[1] 10
NameError: undefined local variable or method `i1' for main:Object
(root) at T:\Rodrigo\Desenv\SciCom\examples\tmp.rb:7
In order to access the i vector, we need to access it through the R namespace. Method pp prints an R vector and is equivalent to R.eval("print(vector)")
> R.i1.pp
[1] 10
Instead of using method eval method i creates an int vector and returns it as a Ruby object:
i2 = R.i(10)
In this case, variable i2 is available in the Ruby namespace and not in the R namespace. Method r can be used in a Renjin::Vector to make it available in the R namespace
> R.eval("print(#{i2.r})")
[1] 10
> i2.pp
[1] 10
In order to convert a Renjin vector of size one to a scalar, SciCom provides method .gz:
# Integer nuberic Vectors are created with method .i
# the returned value is a Renjin::Vector
my_int = R.i(10)
# prints my_int vector
my_int.pp
# To retrieve the first element of the vector (Ruby value) use method .gz
p my_int.gz
# method typeof returns the type of this vector
p my_int.typeof.gz
Will output:
[1] 10
10
"integer"
Creating a double vector can be done either by calling eval or by using method .d
# create a double vector of size one
> d1 = R.d("10.2387")
> d1.pp
[1] 10.2387
> p d1.gz
10.2387
> p d1.typeof.gz
"double"
Method assign will can also be used to convert a Ruby variable into a variable in the R namespace:
> # Assign to variable d2 an Ruby double variable
> R.assign("d2", 11.57)
> R.eval("print(d2)")
[1] 11.57
> # variable d2 is defined in the R namespace:
> R.d2.pp
[1] 11.57
> # create variable d2 in the Ruby namespace and print it
> d2 = R.d2
> d2.pp
[1] 11.57
R also allows vectors of type Logical. In order to create a logical vector, method c can be used. Method c is a general method in R to concatenate elements into a vector.
> # concatenate a single TRUE value into a vector, crating a logical vector
> log = R.c(TRUE)
> log.pp
[1] TRUE
Returning the truth value of a vector in Ruby is done by use of method gt.
> p log.gt
true
Complex variables can be created by calling method complex. The real and imaginary parts of a complex vector can be obtained by use of methods Re and Im:
> # complex vector: created by calling R.complex. Real and imaginary parts are obtained
> # by calling R.Re and R.Im functions on the variable.
> comp_var = R.complex(real: 2, imaginary: 1)
> comp_var.pp
[2.0+1.0i]
> p R.Re(comp_var).gz
2.00
> p R.Im(comp_var).gz)
1.00
http://www.johnmyleswhite.com/notebook/2009/12/18/using-complex-numbers-in-r/
The (x, y) representation of complex numbers is easier to understand at first, but a polar coordinates representation is often more practical. You can get the relevant components of this representation by finding the modulus and complex argument of a complex number. In R, you would use Mod and Arg:
> z = R.complex(real: 0, imaginary: 1)
> z.Mod.pp
[1] 1
> z.Arg.pp
[1] 1.570796
Finally, you’ll want to be able to take the complex conjugate of a complex number; to do that in R, you can use Conj:
> z.Conj.pp
[1] 0-1i
Obtain components of a complex number in polar coordinates
> comp = R.complex(imaginary: 1, real: 0)
> comp.Mod.pp
> comp.Arg.pp
String vectors can be created by using method c. We will see more on c on the following section, but here is the use of c to create a simple string vector:
> str = R.c("hello there")
> str.pp
[1] "hello there"
String vectors can also be created by assigning a string to an R variable, but in this case the variable will be defined in the R namespace and needs to be made available to the Ruby namespace if desired:
> R.str1 = "hello there;"
> str = R.str1
> str.pp
[1] "hello there;"
Up to this point, only vectors with one element were created. R provides some methods to create vectors with more than one element. Metods c, seq and rep are three basic functions to create vectors with more than one element.
Method c concatenates all its argumets into a flat vector:
# To create vectors in R, one uses the 'c' function. Use R.c to created vectors
# in SciCom
> vec = R.c(1, 2, 3, 4, 5)
> vec.pp
[1] 1 2 3 4 5
In R and SciCom, differently than in Ruby, vector indexing starts at 1 and not 0. Another important point is that the result of indexing a vector is still a vector:
> vec[2].pp
[1] 2
In order to obtain a scalar value instead of a vector, in SciCom, as we have already seen, we use method gz. This method is not an R method and is exclusive to SciCom:
> p vec[3].gz
3.0
Indexing a SciCom vector with index 0 returns numeric(0). While indexing with a number greater than the size of the vector returns NA (not a number):
# In R, indexing a vector with zero returns Vector numeric(0)
> oops1 = vec[0]
> oops1.pp
numeric(0)
> oops2 = vec[10]
> oops2.pp
[1] NA
Trying to use gz on numeric(0), will raise an exception, while using it in a vector with NA will return NaN:
# Calling get on numeric(0) raises an exception
> oops1.gz
RuntimeError: Cannot convert Vector to MDArray
> oops2.gz
NaN
Method gz, does actually stand for get zero, i.e., it gets the zeroth element of an array. In this case using a Ruby indexing that starts with 0. This method is actually just a call to method get passing it argument 0: get(0). We can pass other arguments to method get to get the other elements in the array.
# Method get can be used with an index, to get a given element of a vector
> p vec.get(0)
1.0
> p vec.get(3)
4.0
In R ranges can be represented by using operator :, for example, (1:5) represents a range from 1 to 5 inclusive. In SciCom we cannot use the : operator, but we can use instead the standar Ruby range operators .. and ...:
# Vectors can be created using (from..to) or (from...to) operators in place where
# R uses ':' notation. (1..4) is a range that goes from 1 to 4 and (1...4) is a
# range that goes from 1 to 3.
> vec1 = R.c((1..4))
> vec1.pp
[1] 1 2 3 4
> vec2 = R.c((1...4))
> vec2.pp
[1] 1 2 3
# Method length return the number of elements in a vector
assert_equal(4, vec1.length)
# The same can be obtained by calling length in R, but remember that R always returns
# a vector.
R.length(vec1).pp
# to use assert_equal, we need to get the vector's content
assert_equal(4, R.length(vec1).gz)
# We can also acess a Ruby vector in R by calling the .r method in this vector
R.eval("print(#{vec1.r})")
vec2 = R.c((1...4))
vec2.pp
# vec2 has only three elements
assert_equal(3, vec2.length)
end
#--------------------------------------------------------------------------------------
#
#--------------------------------------------------------------------------------------
should "create vectors with method seq" do
# create a sequence (from, to)
seq1 = R.seq(2, 10)
seq1.pp
# R options can also be used, although the notation is a little different. In
# R we would call seq(2, 10, by = 3). In SciCom the same call is R.seq(2, 10, by: 3)
seq2 = R.seq(2, 10, by: 3)
seq2.print
# giving the number of required elements in the sequence
seq3 = R.seq(2, 100, length: 12)
seq3.pp
end
#--------------------------------------------------------------------------------------
#
#--------------------------------------------------------------------------------------
should "create vectors with method rep" do
vec = R.rep(R.c(1, 2, 3), 3)
vec.pp
end