Skip to content

Creating SciCom Vectors

Rodrigo Botafogo edited this page Jan 9, 2015 · 4 revisions

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.

Integer vectors

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"

Double Vectors

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 Vectors

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

More on complex vectors (copied from the internet from John Myles White)

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

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;"

Vectors with more than one element

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

The (from..to) and (from...to) operators

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