Skip to content

Commit

Permalink
Using MutableVector along with immutable.
Browse files Browse the repository at this point in the history
There's still a lot to fix, since something in the trait does not work properly.
  • Loading branch information
vpatryshev committed Jun 3, 2017
1 parent e2c2183 commit 07763fc
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 249 deletions.
51 changes: 22 additions & 29 deletions scala212/core/src/main/scala/scalakittens/la/Matrix.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ trait Matrix extends ((Int, Int) => Double) with Iterable[Double] {
* @param i row number
* @return the row
*/
def row(i: Int): Vector = {
def row(i: Int): MutableVector = {
val row = new Array[Double](nCols)
columnRange foreach (j => row(j) = this(i, j))
Vector(row)
Expand All @@ -72,7 +72,7 @@ trait Matrix extends ((Int, Int) => Double) with Iterable[Double] {
* @param j column number
* @return the column
*/
def column(j: Int): Vector = {
def column(j: Int): MutableVector = {
val col = new Array[Double](nRows)
rowRange foreach (i => col(i) = this(i, j))
Vector(col)
Expand Down Expand Up @@ -182,7 +182,8 @@ trait Matrix extends ((Int, Int) => Double) with Iterable[Double] {
j <- 0 until that.nCols
} data(i*that.nCols + j) = (0 until nCols) map (k => this(i, k) * that(k, j)) sum

val product = Matrix(nRows, that.nCols, Vector(data))
val vector: MutableVector = Vector(data)
val product = Matrix(nRows, that.nCols, vector)

product
}
Expand All @@ -191,9 +192,9 @@ trait Matrix extends ((Int, Int) => Double) with Iterable[Double] {
* Multiplies this matrix by a vector
*
* @param v the vector
* @return another vector, this * v
* @return another vector, this * v; it so happens that it is mutable
*/
def *(v: Vector): Vector = {
def *(v: Vector): MutableVector = {
require(nCols == v.length, s"To apply a matrix to a vector we need that number of columns ($nCols) is equal to the vector's length (${v.length})")

0 until nRows map {
Expand Down Expand Up @@ -235,17 +236,6 @@ trait Matrix extends ((Int, Int) => Double) with Iterable[Double] {

trait MutableMatrix extends Matrix {


private def normalizeColumn(j: Int): Unit = {
val norm = l2(rowRange map (i => this(i, j)))

if (norm > Double.MinPositiveValue) rowRange foreach (i => this(i, j) /= norm)
}

private[la] def normalizeVertically(): Unit = {
0 until nCols foreach normalizeColumn
}

/**
* generic value setter
*
Expand Down Expand Up @@ -277,12 +267,15 @@ trait UnitaryMatrix extends Matrix {

object Matrix {

def Unitary(basis: Array[Vector]) = new ColumnMatrix(basis.length, basis) with UnitaryMatrix {
def Unitary[T <: Vector](basis: Array[T]) = {
require(basis.nonEmpty)
require(basis.forall(_.length == basis.length))
val columns: Array[MutableVector] = basis map (_.copy)
new ColumnMatrix(basis.length, columns) with UnitaryMatrix {
}
}

def Unitary(basis: List[Vector]) = new ColumnMatrix(basis.length, basis.toArray) with UnitaryMatrix {
def Unitary(basis: List[Vector]) = new ColumnMatrix(basis.length, basis.toArray map (_.copy)) with UnitaryMatrix {
require(basis.nonEmpty)
require(basis.forall(_.length == basis.length))
}
Expand All @@ -294,7 +287,7 @@ object Matrix {
* @param rows rows of the matrix
* @return a matrix built from the rows
*/
def ofRows[V <: Vector](width: Int, rows: Array[V]): Matrix = new Matrix {
def ofRows[V <: MutableVector](width: Int, rows: Array[V]): Matrix = new Matrix {
require(width >= 0, s"Bad width $width")
val nRows = rows.length
val nCols = width
Expand All @@ -312,11 +305,11 @@ object Matrix {
* @param i row number
* @return the row
*/
override def row(i: Int): Vector = rows(i)
override def row(i: Int): MutableVector = rows(i)

override def transpose: Matrix = Matrix.ofColumns(nCols, rows)

override def *(v: Vector): Vector = {
override def *(v: Vector): MutableVector = {
require(nCols == v.length, s"For a product we need that number of columns ($nCols) is equal to the vector's length (${v.length})")
rows map (_ * v)
}
Expand All @@ -329,10 +322,10 @@ object Matrix {
* @param columns colunnss of the matrix
* @return a matrix built from the columns
*/
def ofColumns[V <: Vector](height: Int, columns: Array[V]): Matrix =
def ofColumns[V <: MutableVector](height: Int, columns: Array[V]): Matrix =
new ColumnMatrix(height, columns)

private[la] class ColumnMatrix[V <: Vector](val height: Int, val cols: Array[V]) extends Matrix {
private[la] class ColumnMatrix[V <: MutableVector](val height: Int, val cols: Array[V]) extends Matrix {
require(height >= 0, s"Bad height $height")
val nRows = height
val nCols = cols.length
Expand All @@ -344,26 +337,26 @@ object Matrix {
column(j)(i)
}

override def column(j: Int): Vector = cols(j)
override def column(j: Int): MutableVector = cols(j)

override def transpose: Matrix = Matrix.ofRows(nRows, cols)
}

private[la] def apply(height: Int, width: Int, storage: MutableVector): MutableMatrix =
new OnVector(height, width, storage)

/**
* Builds a mutable matrix of given width and height
*
*
* @param height the height
* @param width the width
* @return a new matrix (mutable)
*/
def apply(height: Int, width: Int): MutableMatrix = {
require(width >= 0, s"Bad width $width")
require(height >= 0, s"Bad height $height")
apply(height, width, new Array[Double](height * width))
apply(height, width, storage = Vector(height * width))
}

private[la] def apply(height: Int, width: Int, storage: MutableVector): MutableMatrix =
new OnVector(height, width, storage)

class OnVector(val nRows: Int, val nCols: Int, protected val data: MutableVector) extends MutableMatrix {

Expand Down
5 changes: 3 additions & 2 deletions scala212/core/src/main/scala/scalakittens/la/Norm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import scala.math._
* Created by vpatryshev on 5/22/17.
*/
trait Norm {

def apply(xs: Iterable[Double]): Double

def apply(m: Matrix): Double = apply(m.allElements)
Expand Down Expand Up @@ -36,7 +37,7 @@ trait Norm {

val vs = new Array[Vector](v.length)

vs(0) = normalize(v.copy)
vs(0) = normalize(v.copy).copy

for {
i <- 1 until v.length
Expand All @@ -45,7 +46,7 @@ trait Norm {
for (j <- 0 until i) {
v1 -= project(vs(j), v1)
}
vs(i) = normalize(v1)
vs(i) = normalize(v1).copy
}

vs
Expand Down
14 changes: 6 additions & 8 deletions scala212/core/src/main/scala/scalakittens/la/PCA.scala
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package scalakittens.la

import language.postfixOps

/**
* Created by vpatryshev on 5/17/17.
*/
object PCA {
case class Iterations(precision: Double, maxRepeats: Int) {

private def oneStep(m: Matrix, v: Vector): (Vector, Double) = {
val v1 = Norm.l2.normalize(m * v)
private def oneStep(m: Matrix, v: MutableVector): (MutableVector, Double) = {
val v1 = Norm.l2.normalize(m * v).copy
val d = Norm.l2(v1 - v)
(v1, d)
}

def maxEigenValue(m: Matrix): Option[(Double, Vector, Int)] = {
def maxEigenValue(m: Matrix): Option[(Double, MutableVector, Int)] = {
require(m.nCols == m.nRows, s"Expected a square matrix, have ${m.nRows}${m.nCols}")
if (m.nCols == 0) None else
if (m.nCols == 1) Some((m(0,0), Vector(1.0), 0)) else
{
val iterator = Iterator.iterate((Vector.unit(m.nCols, 0), Double.MaxValue, 0)) {
val iterator = Iterator.iterate((Vector.unit(m.nCols, 0).copy, Double.MaxValue, 0)) {
case (v, d, i) => val (m1, d1) = oneStep(m, v); (m1, d1, i + 1)
}

Expand All @@ -32,11 +30,11 @@ object PCA {
}

def oneEigenValueBasis(m: Matrix): Option[(Double, UnitaryMatrix, Int)] = maxEigenValue(m) map {
case (value: Double, vector: Vector, nIter) =>
case (value: Double, vector: MutableVector, nIter) =>
(value, Matrix.Unitary(Norm.l2.buildOrthonormalBasis(vector)), nIter)
}

def buildEigenVectors(m: Matrix, numberRequested: Int): Option[List[(Double, Vector)]] = {
def buildEigenVectors(m: Matrix, numberRequested: Int): Option[List[(Double, MutableVector)]] = {
require (numberRequested <= m.nCols)

if (numberRequested == 0) Some(Nil) else {
Expand Down
Loading

0 comments on commit 07763fc

Please sign in to comment.