Vector

Vectors in ScienceSuit is extremely flexible to work with. You can read from or change elements of a vector in several ways. For accessing the elements of a vector the following are the possible cases:

  1. Accessing to single values
  2. Accessing to multiple values

The first case is fairly simple; however, the 2nd one requires attention.

Let's start working with the following vector, v: v = 1    2    3    4    5    6    7    8    9    10


Case 1: Accessing to single values

To change a single entry in the vector:

>>v[1]=11
>>v

11   
2    3    4    5    6    7    8    9    10


To read a single entry from the vector:

>>v[1]     or    >>v(1)
11

 

 

Case 2: Accessing to multiple values

Changing the 2nd and the 3rd entries in the vector to number 20:

>>v[{2, 3}] = 20
11   20    20    4    5    6    7    8    9    10

 

To change all entries to 30:

>>v[{}] = 30
30    30    30    30    30    30    30    30    30    30

 

Following command changes entries starting from 8th element to 10:

>>v[ { from=8} ] = 10
30    30    30    30    30    30    30    10    10    10


To change entries starting from 2nd element to 4th element to 20:

>>v[ {from=2, to=4} ] = 20
>>v
30    20    20    20    30    30    30    10    10    10


To change entries from 1st element to 10th element changing by every 2nd element to 20:

>>v[ {from=1, to=10, by=2} ] = 40
>>v
40   
20    40    20    40    30    40    10    40    10


Let v = 1 2 3 4 5 6 7 8 9 10

Changing 1st and 2nd elements to 20 and 30, respectively:

>>v[ {1, 2} ] = {10, 20}
>>v
10    20   
3    4    5    6    7    8    9    10


In the following 2 commands, the number of indices are different than the number of values to be assigned. In such cases, the number of assignment that occurs is the minimum of number of indices and values, i.e. if there are 3 indices and 2 values then only the first 2 indices will be assigned to the 2 values.

>>v[{1, 2, 3}] = {100, 200}
>>v
100    200   
3    4    5    6    7    8    9    10

>>v[{1, 2}] = {1, 2, 100}
>>v

1    2   
3    4    5    6    7    8    9    10


In a similar fashion, in the following example we request all elements to be changed; however, provide only 3 values. Therefore, only the first 3 entries have been changed.

>>v[{}] = {11, 12,13}
>>v

11    12    13   
4    5    6    7    8    9    10

 

Let's provide 3 values on the right-hand side and request to change to the 3rd element (including the 3rd)

>>v[{to=3}] = {1, 2, 3}
>>v

1    2    3   
4    5    6    7    8    9    10


In the following command, we want to change 3 entries starting from 5th element, namely 5th, 6th and 7th entries, but provide 4 values on the right-hand side:

>>v[{from=5, to=7}] = {50, 60, 70, 80}
>>v
1    2    3    4    50    60    70    8    9    10

 

Similar to the previous one, in the following command, we want to change 3 entries; however, this time starting from 7th element, namely 7th, 6th and 5th entries:

>>v[{from=7, to=5}] = {7, 6, 5} -- note the order of the assignment, v[7]=7...
>>v
1    2    3    4    5    6    7    8    9    10


Thus far we provided multiple values using a Lua table. However, we can also use a Vector on the right-hand side. The way assignments work is same as the previous examples. Please note that in the following example the vectors v and a have different sizes.

v = [1 2 3 4 5 6 7 8 9 10]        a = [10 20 30 40 50]

>>v[{1, 2}] = a
v = 10    20    3    4    5    6    7    8    9    10

>>v[{}] = a
v= 10 20 30 40 50 6 7 8 9 10

 

 

Arithmetic Operations

Vector class supports essential arithmetic operations: Let v1, v2 and v3 denote vectors of same size, m a matrix and a an arbitrary number.

  1. Addition: v1+v2=v3 v1+ a=a+v1=v2

  2. Subtraction: v1-v2=v3 v1-a=v2 a-v1=v3

  3. Multiplication: v1*v2=a v1*v2=m a*v1=v2 v1*v2=v3

  4. Division: v1/v2=v3 v1/a=v2 a/v1=v3

  5. Exponentiation: v1^a=v2 a^v1=v3

Note: Since a vector can have two shapes, namely column and row, during multiplication the order matters. A row*column=number, whereas a column*row=matrix. If both vectors are of same shape, then the return vector is an element-wise multiplication of both vectors.

Vector data type also supports __pairs and next methods, therefore is an iteratable container.

 


Member Functions


clone(): Makes a deep copy of the vector itself. The following two commands are equivalent:

>>v1=v:clone()

>>v1=v({})

Both will make a deep copy of v and assign the result to v1.

 

capacity(): Shows the current capacity of the vector. This is different than member function size. Capacity shows how much memory is allocated for the Vector before it automatically resizes (therefore allocates new memory space).


equal(arg, tol=1E-5): Tests whether the elements of the Vector is equal to a number (vi==a) or elements of the Vector is equal to the elements of another Vector (v1i==v2i). The equality test is done using a predefined tolerance, which is 1E-5. The tolerance level can be specified by the user.

>>v=std.tovector{1, 2, 3.1, 3, 5, 5}
>>v
1    2    3.1    3    5    5    COL

To obtain the elements in the vector that is equal to 3 using the default tolerance level, in other words ScienceSuit performs the following check:

| v [ i ] 3.0 | 10 5 lline v[ i ]-3.0 rline <=10^{ -5 }

>>v:equal(3)
3

Since only one element satisfied the condition, the return value is that element's value, a number.

 

In the following command, we arbitrarily set the tolerance level to 0.2:

>>v:equal(3, 0.2)
3.1    3    COL

Now, it is seen that more than 1 element satisfied the condition due to a greater tolerance value, therefore, the return value is a vector containing the elements satisfying the condition.

 

If we want to test whether elements of the two vectors are equal with default tolerance level:

>>v1=std.tovector{1, 2, 3.1, 3, 5, 5}
>>v2=std.tovector{1, 2, 3, 3, 4, 5}

>>v1:equal(v2)
1    1    0    1    0    1    COL

In the above command, ScienceSuit performed the following check:and if the condition is satisfied the returning vector's ith element is set to 1, otherwise to 0. If v and v2 were of different sizes, then an error would be thrown.

 

If we were to set the tolerance level to 0.2:

>>v1:equal(v2, 0.2)
1    1    1    1    0    1    COL

 

greater(arg): Works the same way as member function equal, except there is no tolerance defined. Tests for > operator.

 

greater_equal(arg): Works the same way as member function equal, except there is no tolerance defined. Tests for >= operator.

 

insert(pos, elem): A number or another vector is inserted to the specified position.

To insert number 10 to the 1st position in the vector:

>>v=std.tovector{1, 2, 3}
>>v:insert(1, 10)
>>v
10   1    2    3    COL

 

To be able to insert another vector in to a specified position:

>>v=std.tovector{1, 2, 3}
>>v2=std.tovector{10, 20, 30}

>>v:insert(1, v2)
>>v
10    20    30    1    2    3    COL

 

less(arg): Works the same way as member function equal, except there is no tolerance defined. Tests for the < operator.

 

less_equal(arg): Works the same way as member function equal, except there is no tolerance defined. Tests for the <= operator.

 

push_back(arg): Adds an element to the end of the vector. Let v= [1 2 3] and v1=[100 200]

To add a single number at the end of the vector:

>>v:push_back(4)
>>v
1    2    3    4

 

To append a Lua table (made up of only numbers) to the previously changed vector:

>>t={10, 20, 30}

>>v:push_back(t)
>>v
1    2    3   4    10    20    30

 

To append another vector to the previously modified vector:

>>v:push_back(v1)
>>v
1    2    3    4    10    20    30   100    200

 

reserve(num): Reserves memory for the vector to be used. If any operation, such as push_back, that changes the number of elements in the vector is greater than the current capacity then the Vector will automatically reallocate new memory and copy the elements to the new location. The default is 1000.

>>v:capacity()
1000

 

In the following command, we attempt to reserve number of elements less than the current capacity:<

>>v:reserve(500)
>>v:capacity()
1000

 

It is seen that the command was not successful since the capacity of the vector is still 1000. However, if we attempt to reserve number of elements greater than the current capacity, the command will succeed:

>>v:reserve(5000)
>>v:capacity()
5000

 

resize(num): Changes the size of the vector. If the requested new size is less than the current size, elements from the end will be deleted. However, if the requested new size is greater than the current size 0 will be appended. Let v=10 20 30

The original vector v is of size 3. The following command resizes the vector to 2, therefore, the last entry of the vector, number 30, is deleted:

>>v:resize(2)
10    20

 

Now the size of the vector is 2. If we resize the vector to 4, 0s will be appended:

>>v:resize(4)
10    20   0    0

 

 

reverse(): Reverses the order of elements.

>>v=std.tovector{1, 2, 3, 4, 5}
>>v:reverse()
>>v
5    4    3    2    1    COL

 

shape(): Returns the shape of the Vector. There are 3 different shapes, namely col, row and lnk. The lnk arises only when referred from a Matrix data structure. The default shape for Vector is col.

>>v=std.tovector{1, 2, 3}
>>v:shape()
col

 

By default, the shape of vectors are col. If we take the transpose of the vector, the shape changes to a row vector as evidenced by the following commands:

>>v2=std.trans(v)
>>v2:shape()

row

 

shuffle(): Randomly shuffles the positions of the elements in the vector. The size of the vector is not affected. Let v=1 2 3 4 5

>>v:shuffle()
4    1    5    2    3

 

slice (pos): Slices the vector into two from the given position. The vector is not affected.

>>v=std.tovector{1, 2, 3, 4, 5}
>>v1,v2=v:slice(3)

>>v1
1    2    3    COL

>>v2
4    5    COL

 

sort (order): The order can be either "A" or "D" for ascending and descending order sorts, respectively.

>>v=std.tovector{1,5,2,7,4}
>>v
1    5    2    7    4    COL

>>v:sort("A")
>>v
1    2    4    5    7    COL