//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** @author John Miller * @version 1.3 * @date Tue Feb 2 15:55:24 EST 2016 * @see LICENSE (MIT style license file). */ // U N D E R D E V E L O P M E N T // Issue 1 - thread-safety with minimal performance hit // Issue 2 - make all methods parallel // Issue 3 - move to .par package and integrate with the rest of code package scalation.linalgebra.par import scala.collection.{breakOut, Traversable} import scala.collection.mutable.{IndexedSeq, WrappedArray} import scala.util.Sorting.quickSort import math.{abs => ABS, max => MAX, sqrt} import scalation.linalgebra.{MatriD, VectoD, VectorI, VectorL} import scalation.math.double_exp import scalation.util.Error import scalation.util.SortingD.{iqsort, qsort2} //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `VectorD` class stores and operates on Numeric Vectors of base type `Double`. * It follows the framework of `gen.VectorN [T]` and is provided for performance. * This is the parallel version. * @param dim the dimension/size of the vector * @param v the 1D array used to store vector elements */ class VectorD (val dim: Int, protected var v: Array [Double] = null) extends VectoD // extends Traversable [Double] with PartiallyOrdered [VectorD] with Vec with Error with Serializable { if (v == null) { v = Array.ofDim [Double] (dim) } else if (dim != v.length) { flaw ("constructor", "dimension is wrong") } // if //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Construct a vector from an array of values. * @param u the array of values */ def this (u: Array [Double]) { this (u.length, u) } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Construct a vector and assign values from vector 'u'. * @param u the other vector */ def this (u: VectorD) { this (u.dim) // invoke primary constructor for (i <- range.par) v(i) = u(i) } // constructor //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create an exact copy of 'this' vector. */ def copy: VectorD = new VectorD (this) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a zero vector (all elements are zero) of length 'size'. * @param size the number of elements in the vector */ def zero (size: Int = dim): VectorD = new VectorD (size) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a one vector (all elements are one) of length 'size'. * @param size the number of elements in the vector */ def one (size: Int = dim): VectorD = new VectorD (size, Array.fill (size)(1.0)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Expand the size (dim) of 'this' vector by 'more' elements. * @param more the number of new elements to add */ def expand (more: Int = dim): VectorD = { if (more < 1) this // no change else new VectorD (dim + more, Array.concat (v, new Array [Double] (more))) } // expand //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a vector of the form (0, ... 1, ... 0) where the 1 is at position j. * @param j the position to place the 1 * @param size the size of the vector (upper bound = size - 1) */ def oneAt (j: Int, size: Int = dim): VectorD = { val c = new VectorD (size) c.v(j) = 1.0 c } // oneAt //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a vector of the form (0, ... -1, ... 0) where the -1 is at position j. * @param j the position to place the -1 * @param size the size of the vector (upper bound = size - 1) */ def _oneAt (j: Int, size: Int = dim): VectorD = { val c = new VectorD (size) c.v(j) = -1.0 c } // _oneAt //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Convert 'this' `VectorD` into a `VectorI`. */ def toInt: VectorI = { val c = new VectorI (dim) for (i <- range.par) c(i) = v(i).toInt c } // toInt //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Convert 'this' `VectorD` into a `VectorL`. */ def toLong: VectorL = { val c = new VectorL (dim) for (i <- range.par) c(i) = v(i).toLong c } // toLong //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Convert 'this' `VectorD` into a `VectorD`. */ def toDouble: VectorD = { val c = new VectorD (dim) for (i <- range.par) c(i) = v(i).toDouble c } // toDouble //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Convert 'this' `VectoD` into a dense `VectorD`. */ def toDense: scalation.linalgebra.VectorD = null // FIX //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Get 'this' vector's element at the 'i'-th index position. * @param i the given index */ def apply (i: Int): Double = v(i) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Get 'this' vector's elements within the given range (vector slicing). * @param r the given range */ def apply (r: Range): VectorD = slice (r.start, r.end) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Get 'this' vector's entire array. */ def apply (): WrappedArray [Double] = v //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Set 'this' vector's element at the 'i'-th index position. * @param i the given index * @param x the value to assign */ def update (i: Int, x: Double) { v(i) = x } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Set 'this' vector's elements over the given range (vector slicing). * @param r the given range * @param x the value to assign */ def update (r: Range, x: Double) { for (i <- r) v(i) = x } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Set 'this' vector's elements over the given range (vector slicing). * @param r the given range * @param u the vector to assign */ def update (r: Range, u: VectoD) { for (i <- r) v(i) = u(i - r.start) } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Set each value in 'this' vector to 'x'. * @param x the value to be assigned */ def set (x: Double) { for (i <- range.par) v(i) = x } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Set the values in 'this' vector to the values in sequence 'u'. * @param u the sequence of values to be assigned */ def set (u: Seq [Double]) { for (i <- range.par) v(i) = u(i) } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Iterate over 'this' vector element by element. * @param f the function to apply */ def foreach [U] (f: Double => U) { var i = 0 while (i < dim) { f (v(i)); i += 1 } } // foreach //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Filter the elements of 'this' vector based on the predicate 'p', returning * a new vector. * @param p the predicate (Boolean function) to apply */ override def filter (p: Double => Boolean): VectorD = VectorD (v.filter (p)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Filter the elements of 'this' vector based on the predicate 'p', returning * the index positions. * @param p the predicate (Boolean function) to apply */ def filterPos (p: Double => Boolean): IndexedSeq [Int] = { (for (i <- range if p (v(i))) yield i) (breakOut) } // filterPos //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Map the elements of 'this' vector by applying the mapping function 'f'. * @param f the function to apply */ def map (f: Double => Double): VectorD = new VectorD (v.map (f)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Slice 'this' vector 'from' to 'end'. * @param from the start of the slice (included) * @param till the end of the slice (excluded) */ override def slice (from: Int, till: Int): VectorD = new VectorD (till - from, v.slice (from, till)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Select a subset of elements of 'this' vector corresponding to a 'basis'. * @param basis the set of index positions (e.g., 0, 2, 5) */ def select (basis: Array [Int]): VectorD = { val c = new VectorD (basis.length) for (i <- c.range.par) c.v(i) = v(basis(i)) c } // select //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Concatenate 'this' vector and vector' b'. * @param b the vector to be concatenated */ def ++ (b: VectoD): VectorD = { val c = new VectorD (dim + b.dim) for (i <- c.range.par) c.v(i) = if (i < dim) v(i) else b(i - dim) c } // ++ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Concatenate 'this' vector and scalar 's'. * @param s the scalar to be concatenated */ def ++ (s: Double): VectorD = { val c = new VectorD (dim + 1) for (i <- c.range.par) c.v(i) = if (i < dim) v(i) else s c } // ++ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Add 'this' vector and vector 'b'. * @param b the vector to add */ def + (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) + b(i) c } // + //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Add 'this' vector and scalar 's'. * @param s the scalar to add */ def + (s: Double): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) + s c } // + //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Add 'this' vector and scalar 's._2' only at position 's._1'. * @param s the (position, scalar) to add */ def + (s: Tuple2 [Int, Double]): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = if (i == s._1) v(i) + s._2 else v(i) c } // + //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Add in-place 'this' vector and vector 'b'. * @param b the vector to add */ def += (b: VectoD): VectorD = { for (i <- range.par) v(i) += b(i); this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Add in-place 'this' vector and scalar 's'. * @param s the scalar to add */ def += (s: Double): VectorD = { for (i <- range.par) v(i) += s; this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the negative of 'this' vector (unary minus). */ def unary_- (): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = -v(i) c } // unary_- //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** From 'this' vector subtract vector 'b'. * @param b the vector to subtract */ def - (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) - b(i) c } // - //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** From 'this' vector subtract scalar 's'. * @param s the scalar to subtract */ def - (s: Double): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) - s c } // - //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** From 'this' vector subtract scalar 's._2' only at position 's._1'. * @param s the (position, scalar) to subtract */ def - (s: Tuple2 [Int, Double]): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = if (i == s._1) v(i) - s._2 else v(i) c } // - //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** From 'this' vector subtract in-place vector 'b'. * @param b the vector to add */ def -= (b: VectoD): VectorD = { for (i <- range.par) v(i) -= b(i); this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** From 'this' vector subtract in-place scalar 's'. * @param s the scalar to add */ def -= (s: Double): VectorD = { for (i <- range.par) v(i) -= s; this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Multiply 'this' vector by vector 'b'. * @param b the vector to multiply by */ def * (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) * b(i) c } // * //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Multiply 'this' vector by scalar 's'. * @param s the scalar to multiply by */ def * (s: Double): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) * s c } // * //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Multiply 'this' (row) vector by matrix 'm'. * @param m the matrix to multiply by */ def * (m: MatriD): VectorD = null // m.t * this // FIX //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Multiply in-place 'this' vector and vector 'b'. * @param b the vector to add */ def *= (b: VectoD): VectorD = { for (i <- range.par) v(i) *= b(i); this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Multiply in-place 'this' vector and scalar 's'. * @param s the scalar to add */ def *= (s: Double): VectorD = { for (i <- range.par) v(i) *= s; this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Divide 'this' vector by vector 'b' (element-by-element). * @param b the vector to divide by */ def / (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) / b(i) c } // / //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Divide 'this' vector by scalar 's'. * @param s the scalar to divide by */ def / (s: Double): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) / s c } // / //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Divide in-place 'this' vector and vector 'b'. * @param b the vector to add */ def /= (b: VectoD): VectorD = { for (i <- range.par) v(i) /= b(i); this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Divide in-place 'this' vector and scalar 's'. * @param s the scalar to add */ def /= (s: Double): VectorD = { for (i <- range.par) v(i) /= s; this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the vector containing each element of 'this' vector raised to the * s-th power. * @param s the scalar exponent */ def ~^ (s: Double): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = v(i) ~^ s c } // ~^ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Raise each element of 'this' vector to the 's'-th power. * @param s the scalar exponent */ def ~^= (s: Double): VectorD = { for (i <- range.par) v(i) = v(i) ~^ s; this } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the vector containing the reciprocal of each element of 'this' vector. */ def recip: VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = 1.0 / v(i) c } // recip //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the vector that is the element-wise absolute value of 'this' vector. */ def abs: VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = ABS (v(i)) c } // abs //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sum the elements of 'this' vector. */ def sum: Double = v.foldLeft (0.0)((s, x) => s + x) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sum the absolute value of the elements of 'this' vector. */ def sumAbs: Double = v.foldLeft (0.0)((s, x) => s + ABS (x)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sum the elements of 'this' vector skipping the 'i'-th element (Not Equal 'i'). * @param i the index of the element to skip */ def sumNE (i: Int): Double = sum - v(i) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sum the positive (> 0) elements of 'this' vector. */ def sumPos: Double = v.foldLeft (0.0)((s, x) => s + MAX (x, 0.0)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Establish the rank order of the elements in 'self' vector, e.g., * (8.0, 2.0, 4.0, 6.0) is (3, 0, 1, 2). */ def rank: VectorI = VectorI (iqsort (v)) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Cumulate the values of 'this' vector from left to right (e.g., create a * CDF from a pmf). Example: (4, 2, 3, 1) --> (4, 6, 9, 10) */ def cumulate: VectorD = { val c = new VectorD (dim) var sum = 0.0 for (i <- range) { sum += v(i); c.v(i) = sum } // FIX - make parallel c } // cumulate //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Normalize 'this' vector so that it sums to one (like a probability vector). */ def normalize: VectorD = this * (1.0 / sum) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Normalize 'this' vector so its length is one (unit vector). */ def normalizeU: VectorD = this * (1.0 / norm) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Normalize 'this' vector to have a maximum of one. */ def normalize1: VectorD = this * (1.0 / max ()) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compute the dot product (or inner product) of 'this' vector with vector 'b'. * @param b the other vector */ def dot (b: VectoD): Double = { var sum = 0.0 for (i <- range) sum += v(i) * b(i) sum } // dot //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compute the dot product (or inner product) of vector 'b' and vector 'c'. * It takes the dot product on a subrange from 'i' (inclusive) to 'j' exclusive. * @param b the first vector * @param c the second vector * @param i the start of the subrange (inclusive) * @param j the end of the subrange (exclusive) */ def dot (b: VectorD, c: VectorD, i: Int, j: Int): Double = { var sum = 0.0 for (k <- i until j) sum += b.v(k) * c.v(k) sum } // dot //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compute the dot product (or inner product) of 'this' vector with vector 'b'. * This is the parallel version. * @param b the other vector */ def dotp (b: VectorD): Double = { import VectorD._ val nn = dim / PAR_LEVEL val dt = makeThreads () for (i <- dt.indices) { dt(i) = new VecThread (this, b, i * nn, (i+1)*nn min dim, dot) dt(i).start () } // for await () dt.foldLeft (0.0)((s, x) => s + x.result) } // dotp //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compute the Manhattan norm (1-norm) of 'this' vector. */ def norm1: Double = { var sum = 0.0 for (i <- range) sum += ABS (v(i)) // FIX - make parallel sum } // norm1 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the maximum element in 'this' vector. * @param e the ending index (exclusive) for the search */ def max (e: Int = dim): Double = { var x = v(0) for (i <- 1 until e if v(i) > x) x = v(i) x } // max //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Take the maximum of 'this' vector with vector 'b' (element-by element). * @param b the other vector */ def max (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = if (b(i) > v(i)) b(i) else v(i) c } // max //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the minimum element in 'this' vector. * @param e the ending index (exclusive) for the search */ def min (e: Int = dim): Double = { var x = v(0) for (i <- 1 until e if v(i) < x) x = v(i) x } // max //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Take the minimum of 'this' vector with vector 'b' (element-by element). * @param b the other vector */ def min (b: VectoD): VectorD = { val c = new VectorD (dim) for (i <- range.par) c.v(i) = if (b(i) < v(i)) b(i) else v(i) c } // min //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the argument maximum of 'this' vector (index of maximum element). * @param e the ending index (exclusive) for the search */ def argmax (e: Int = dim): Int = { var j = 0 for (i <- 1 until e if v(i) > v(j)) j = i j } // argmax //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the argument maximum of 'this' vector (index of maximum element). * @param s the starting index (inclusive) for the search * @param e the ending index (exclusive) for the search */ def argmax (s: Int, e: Int): Int = { var j = s for (i <- s+1 until e if v(i) > v(j)) j = i j } // argmax //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the argument minimum of 'this' vector (index of minimum element). * @param e the ending index (exclusive) for the search */ def argmin (e: Int = dim): Int = { var j = 0 for (i <- 1 until e if v(i) < v(j)) j = i j } // argmin //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find the argument mainmum of 'this' vector (index of minimum element). * @param s the starting index (inclusive) for the search * @param e the ending index (exclusive) for the search */ def argmin (s: Int, e: Int): Int = { var j = s for (i <- s+1 until e if v(i) < v(j)) j = i j } // arginm //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the argument minimum of 'this' vector (-1 if its not negative). * @param e the ending index (exclusive) for the search */ def argminNeg (e: Int = dim): Int = { val j = argmin (e); if (v(j) < 0.0) j else -1 } // argmaxNeg //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the argument maximum of 'this' vector (-1 if its not positive). * @param e the ending index (exclusive) for the search */ def argmaxPos (e: Int = dim): Int = { val j = argmax (e); if (v(j) > 0.0) j else -1 } // argmaxPos //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the index of the first negative element in 'this' vector (-1 otherwise). * @param e the ending index (exclusive) for the search */ def firstNeg (e: Int = dim): Int = { for (i <- 0 until e if v(i) < 0.0) return i; -1 } // firstNeg //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the index of the first positive element in 'this' vector (-1 otherwise). * @param e the ending index (exclusive) for the search */ def firstPos (e: Int = dim): Int = { for (i <- 0 until e if v(i) > 0.0) return i; -1 } // firstPos //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the index of the first occurrence of element 'x' in 'this' vector, * or -1 if not found. * @param x the given element * @param e the ending index (exclusive) for the search */ def indexOf (x: Double, e: Int = dim): Int = { for (i <- 0 until e if v(i) == x) return i; -1 } // indexOf //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Find and return index of first element satisfying predicate 'p', or * -1 if not found. * @param p the predicate to check */ def indexWhere (p: (Double) => Boolean): Int = v.indexWhere (p) //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Count the number of strictly negative elements in 'this' vector. */ def countNeg: Int = { var count = 0 for (i <- 0 until dim if v(i) < 0.0) count += 1 count } // countNeg //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Count the number of strictly positive elements in 'this' vector. */ def countPos: Int = { var count = 0 for (i <- 0 until dim if v(i) > 0.0) count += 1 count } // countPos //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Count the number of zero elements in 'this' vector. */ def countZero: Int = { var count = 0 for (i <- 0 until dim if v(i) == 0.0) count += 1 count } // countZero //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return a new vector consisteing of the distinct elements from 'this' vector. */ def distinct: VectorD = VectorD (v.distinct) //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Count the number of distinct elements in 'this' vector. */ def countinct: Int = v.distinct.length //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Determine whether the predicate 'pred' holds for some element in 'this' vector. * @param pred the predicate to test (e.g., "_ == 5.") */ // def exists (pred: (Double) => Boolean): Boolean = v.exists (pred) //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Determine whether 'x' is contained in 'this' vector. * @param x the element to be checked */ def contains (x: Double): Boolean = v contains x //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sort 'this' vector in-place in ascending (non-decreasing) order. */ def sort () { quickSort (v) } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Sort 'this' vector in-place in descending (non-increasing) order. */ def sort2 () { qsort2 (v) } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Swap elements 'i' and 'j' in 'this' vector. * @param i the first element in the swap * @param j the second element in the swap */ def swap (i: Int, j: Int) { val t = v(j); v(j) = v(i); v(i) = t } // swap //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Check whether the other vector 'b' is at least as long as 'this' vector. * @param b the other vector */ def sameDimensions (b: VectorD): Boolean = dim <= b.dim //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Check whether 'this' vector is nonnegative (has no negative elements). */ def isNonnegative: Boolean = { for (i <- range if v(i) < 0.0) return false true } // isNonnegative //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Compare 'this' vector with vector 'b'. * @param b the other vector */ def tryCompareTo [B >: VectorD] (b: B) (implicit view_1: (B) => PartiallyOrdered [B]): Option [Int] = { var le = true var ge = true for (i <- range.par) { val b_i = b.asInstanceOf [VectorD] (i) if (ge && (v(i) compare b_i) < 0) ge = false else if (le && (v(i) compare b_i) > 0) le = false } // for if (ge && le) Some (0) else if (le) Some (-1) else if (ge) Some (1) else None } // tryCompareTo //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Override equals to determine whether 'this' vector equals vector 'b.. * @param b the vector to compare with this */ override def equals (b: Any): Boolean = { b.isInstanceOf [VectorD] && (v.deep equals b.asInstanceOf [VectorD].v.deep) } // equals //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Must also override hashCode for 'this' vector to be compatible with equals. */ override def hashCode: Int = v.deep.hashCode //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Convert 'this' vector to a String. */ override def toString: String = { var sb = new StringBuilder ("VectorD(") if (dim == 0) return sb.append (")").mkString for (i <- range) { sb.append (fString.format (v(i))) if (i == dim-1) sb = sb.dropRight (1) } // for sb.replace (sb.length-1, sb.length, ")").mkString } // toString } // VectorD class //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `VectorD` object is the companion object for the `VectorD` class. */ object VectorD { import java.util.concurrent.CountDownLatch /** The number of parallel/concurrent tasks to be run. Adjust as needed */ private val PAR_LEVEL = 10 /** Count down latch main thread to wait for `VecThread`s to finish */ private var latch: CountDownLatch = null //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Make several `VecThread`s to run tasks in parallel. */ def makeThreads (): Array [VecThread] = { latch = new CountDownLatch (PAR_LEVEL) Array.ofDim [VecThread] (PAR_LEVEL) } // makeThreads //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Await the completion of all `VecThread`s. */ def await () { latch.await () } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `VecThread` inner class allows tasks to be run in parallel. * @param b the first vector * @param c the second vector * @param i the start of the subrange (inclusive) * @param j the end of the subrange (exclusive) * @param task the task/function to be run in parallel */ class VecThread (b: VectorD, c: VectorD, i: Int, j: Int, task: (VectorD, VectorD, Int, Int) => Double) extends Thread { var result = 0.0 override def run () { result = task (b, c, i, j) latch.countDown () } // run } // VecThread inner class //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a `VectorD` from one or more values (repeated values Double*). * @param x the first Double number * @param xs the rest of the Double numbers */ def apply (x: Double, xs: Double*): VectorD = { val c = new VectorD (1 + xs.length) c(0) = x for (i <- 0 until c.dim-1) c.v(i+1) = xs(i) c } // apply //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a `VectorD` from a sequence of Doubles. * @param xs the sequence of the Double numbers */ def apply (xs: Seq [Double]): VectorD = { val c = new VectorD (xs.length) for (i <- 0 until c.dim) c.v(i) = xs(i) c } // apply //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a `VectorD` from one or more values (repeated values String*). * @param x the first String * @param xs the rest of the Strings */ def apply (x: String, xs: String*): VectorD = { val c = new VectorD (1 + xs.length) c(0) = x.toDouble for (i <- 0 until c.dim-1) c.v(i+1) = xs(i).toDouble c } // apply //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a `VectorD` from an array of Strings. * @param xs the array of the Strings */ def apply (xs: Array [String]): VectorD = { val c = new VectorD (xs.length) for (i <- c.range.par) c.v(i) = xs(i).toDouble c } // apply //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a `VectorD` from an array of Strings, skipping the first 'skip' * elements. If an element is non-numeric, use its hashcode. * FIX: Might be better to map non-numeric Strings to ordinal values. * @param xs the array of the Strings * @param skip the number of elements at the beginning to skip (e.g., id column) */ def apply (xs: Array [String], skip: Int): VectorD = { val c = new VectorD (xs.length - skip) for (i <- skip until xs.length) { c.v(i - skip) = if (xs(i) matches "[\\-\\+]?\\d*(\\.\\d+)?") xs(i).toDouble else xs(i).hashCode () } // for c } // apply //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Create a one vector (all elements are one) of length 'size'. * @param size the size of the vector */ def one (size: Int): VectorD = { val c = new VectorD (size) c.set (1.0) c } // one //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Concatenate scalar 'b' and vector 'u'. * @param b the scalar to be concatenated - first part * @param u the vector to be concatenated - second part */ def ++ (b: Double, u: VectorD): VectorD = { val c = new VectorD (u.dim + 1) for (i <- c.range.par) c(i) = if (i == 0) b else u.v(i - 1) c } // ++ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return a `VectorD` containing a sequence of increasing integers in a range. * @param start the start value of the vector, inclusive * @param end the end value of the vector, exclusive (i.e., the first value not returned) */ def range (start: Int, end: Int): VectorD = { val c = new VectorD (end - start) for (i <- c.range.par) c.v(i) = (start + i).toDouble c } // range } // VectorD object //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `VectorDTest` object tests the operations provided by `VectorD`. * > run-main scalation.linalgebra.par.VectorDTest */ object VectorDTest extends App { import scalation.util.time val rng = new java.util.Random () val n = 40000000 val x = new VectorD (n) val y = new VectorD (n) for (i <- 0 until n) { x(i) = rng.nextDouble () y(i) = rng.nextDouble () } // for var z = 0.0 for (k <- 0 until 6) { time { z = x dot y } println ("x dot y = " + z) } // for for (k <- 0 until 6) { time { z = x dotp y } println ("x dotp y = " + z) } // for } // VectorDTest