Block Vectors

Summary

Here we show how to use blocked vectors and blocked dual vectors.

Blocked vectors and dual vectors in the algebra package are wrappers around Stream[(Long, DenseVector[Double])] each partition consists of an ordered index and the partition content which is in the form of a breeze vector.

The relevant API endpoints are PartitionedVector and PartitionedDualVector. In order to access these objects, you must do import io.github.mandar2812.dynaml.algebra._ (already loaded by default in the DynaML shell).

Creation

Block vectors can be created in a number of ways. PartitionedVector and PartitionedDualVector are column row vectors respectively and treated as transposes of each other.

From Input Blocks

//Create the data blocks
val data_blocks: Stream[(Long, DenseVector[Double])] =
  (0L until 10L).toStream.map(index => (index, DenseVector.ones[Double](500)))

//Instantiate the partitioned vector

val part_vector = PartitionedVector(data_blocks)

//Optionally you may also provide the total length
//of the partitioned vector

val part_vector = PartitionedVector(data_blocks, num_rows: Long = 5000L)


//Created Block Dual Vector

val part_dvector = PartitionedDualVector(data_blocks)

//Optionally you may also provide the total length
//of the partitioned dual vector

val part_dvector = PartitionedDualVector(data_blocks, num_rows: Long = 5000L)

From Tabulating Functions

val tabFunc: (Long) => Double =
  (index: Long) => math.sin(2d*math.Pi*index/5000d)

//Instantiate the partitioned vector
val part_vector = PartitionedVector(
  length = 5000L, numElementsPerBlock = 500,
  tabFunc)

//Instantiate the partitioned dual vector
val part_dvector = PartitionedDualVector(
  length = 5000L, numElementsPerBlock = 500,  tabFunc)

From a Stream

//Create the data stream
val data: Stream[Double] = Stream.fill[Double](5000)(1.0)

//Instantiate the partitioned vector
val part_vector = PartitionedVector(data, length = 5000L, num_elements_per_block = 500)

From a Breeze Vector

//Create the data blocks
val data_vector = DenseVector.ones[Double](5000)

//Instantiate the partitioned vector
val part_vector = PartitionedVector(data_vector, num_elements_per_block = 500)

Apart from the above methods of creation there are a number of convenience functions available.

Vector with Filled Values

Vector of zeros

val ones_vec = PartitionedVector.zeros(5000L, 500)

Vector of Ones

val ones_vec = PartitionedVector.ones(5000L, 500)

Vector of Random Values

val random_var = RandomVariable(new Beta(1.5, 2.5))

val rand_vec = PartitionedVector.rand(5000L, 500, random_var)

Vector Concatenation

val random_var = RandomVariable(new Beta(1.5, 2.5))

val rand_vec1 = PartitionedVector.rand(2000L, 500, random_var)
val rand_vec2 = PartitionedVector.rand(2000L, 500, random_var)

//Vector of length 4000, having 8 blocks of 500 elements each
val vec = PartitionedVector.vertcat(rand_vec1, rand_vec2)

Tip

A PartitionedDualVector can be created via the transpose operation on a PartitionedVector instance and vice versa.

val random_var = RandomVariable(new Beta(1.5, 2.5))

val p_vec = PartitionedVector.rand(5000L, 500, random_var)

val p_dvec = p_vec.t

Algebraic Operations

Partitioned vectors and dual vectors have a number of algebraic operations available in the API.

val beta_var = RandomVariable(Beta(1.5, 2.5))
val gamma_var = RandomVariable(Gamma(1.5, 2.5))

val p_vec_beta = PartitionedVector.rand(5000L, 500, beta_var)
val p_vec_gamma = PartitionedVector.rand(5000L, 500, gamma_var)

val dvec_beta = p_vec_beta.t
val dvec_gamma = p_vec_gamma.t

//Addition
val add_vec = p_vec_beta + p_vec_gamma
val add_dvec = dvec_beta + dvec_gamma

//Subtraction
val sub_vec = p_vec_beta - p_vec_gamma
val sub_dvec = dvec_beta - dvec_gamma

//Element wise multiplication
val mult_vec = p_vec_beta :* p_vec_gamma

//Element wise division
val div_vec = p_vec_beta :/ p_vec_gamma

//Inner Product
val prod = dvec_gamma*p_vec_beta

//Scaler multiplication
val sc_vec = add_vec*1.5
val sc_dvec = add_dvec*2.5

Misc. Operations

Map Partitions

Map each index, partition pair by a scala function.

val vec: PartitionedVector = _

val other_vec = vec.map(
   (pair: (Long, DenseVector[Double])) => (pair._1, pair._2*1.5)
)

Slice

Obtain subset of elements, the new vector is repartitioned and re-indexed accordingly.

val vec: PartitionedVector = PartitionedVector.ones(5000L, 500)

val other_vec = vec(999L until 2000L)

Reverse

Reverse a block vector

val vec: PartitionedVector = PartitionedVector.ones(5000L, 500)

val reverse_vec = vec.reverse

Convert to Breeze Vector

val vec: PartitionedVector = PartitionedVector.ones(5000L, 500)

//Do not use on large vectors as
//it might lead to overflow of memory.
val breeze_vec = vec.toBreezeVector

Comments