QuickStart

anthony-cros edited this page May 14, 2015 · 20 revisions

Building Scalala

Scalala is hosted on github and is built with sbt, which is included in the repo.

Run sbt (./sbt) and first invoke update to download Scalala's dependencies. Then, you can run one or more of the following targets:

  • update -- Downloads Scalala's dependencies
  • compile -- Builds the library
  • test -- Runs the unit tests
  • doc -- Builds scaladoc for the public API
  • proguard -- Builds a distributable jar

Using scalala in your project:

Scalala is hosted at the scala-tools repo.

For SBT, Add these lines to your SBT project definition:

  • For SBT versions 0.10.x
libraryDependencies  ++= Seq(
            // other dependencies here
            "org.scalala" %% "scalala" % "1.0.0.RC3-SNAPSHOT"
)

resolvers ++= Seq(
            // other resolvers here
            "Scala Tools Snapshots" at "https://oss.sonatype.org/content/groups/scala-tools/",
            "ScalaNLP Maven2" at "http://repo.scalanlp.org/repo"
)

scalaVersion := "2.9.1"
  • For SBT versions < 0.10
val scalaToolsSnapshots = "Scala Tools Snapshots" at "http://scala-tools.org/repo-snapshots/"
val scalaNlpRepo = "ScalaNLP Maven2" at "http://repo.scalanlp.org/repo"
val scalala = "org.scalala" %% "scalala_2.9.1" % "1.0.0.RC3-SNAPSHOT"

If this fails to resolve, you may try the following in sbt:

  • publish-local

For Maven: Add the following repository and dependency blocks to your pom.xml

<repository>
  <id>scala-tools.org</id>
  <name>Scala-Tools Maven2 Repository</name>
  <url>http://scala-tools.org/repo-snapshots</url>
</repository>

<repository>
  <id>scalanlp.org</id>
  <name>ScalaNLP Maven2 Repository</name>
  <url>http://repo.scalanlp.org/repo</url>
</repository>

<dependency>
  <groupId>org.scalala</groupId>
  <artifactId>scalala_2.9.1</artifactId>
  <version>1.0.0.RC3-SNAPSHOT</version>
</dependency>

The Scalala console

Scalala is designed to enable interactive exploration through the console. To start up a console session, first build a Scalala executable jar proguard target, and then:

java -jar target/scala_2.9.1/scalala*.min.jar

The console is a standard Scala console in a which a few objects are imported automatically:

import scalala.scalar._;
import scalala.tensor.::;
import scalala.tensor.mutable._;
import scalala.tensor.dense._;
import scalala.tensor.sparse._;
import scalala.library.Library._;
import scalala.library.LinearAlgebra._;
import scalala.library.Statistics._;
import scalala.library.Plotting._;
import scalala.operators.Implicits._;

These lines import the basic Scalala data types (scalala.scalar._ and scalala.tensor._), most of the standard scalala library (scalala.library._), as well as the implicits conversions that support enriching the built-in collections with mathematical operators (scalala.operators.Implicits._).

In the next sections, we'll take a tour of what you can do with Scalala.

Working with Vectors and Matrices

Scalala supports a rich set of data types that can be easily extended in user applications, described in the [DataTypes] page, but to get started, let's first play with Vectors and Matrices, the main ingredients of any linear algebra library. Vectors and matrices are both types of tensors, which store numeric values at positions indexed by one or more integers. So a Vector of Doubles extends Tensor[Int,Double]] because it is indexed by a single Int whereas Matrix extends Tensor[(Int,Int),Double] because it is indexed by a row and column offset.

First, let's request a dense vector of zeros using a constructor method:

scala> val x = DenseVector.zeros[Double](5)
x: scalala.tensor.dense.DenseVectorCol[Double] = 
0.0
0.0
0.0
0.0
0.0

Here we make a column vector of zeros of type Double. We can specify any type of scalala.scalar.Scalar in square brackets [] - e.g. Int, Float, Long, Boolean, Complex. And there are other ways we could create the vector - such as with a literal DenseVector(1,2,3) or with a call to fill or tabulate.

The vector object supports accessing and updating data elements by their index in 0 to x.length-1. The vector is "dense" because it is backed by an Array[Double], but could as well have created a SparseVector.zeros[Double](5), which would not allocate memory for zeros.

scala> x(0)
res0: Double = 0.0

scala> x(1) = 2

scala> x
res2: scalala.tensor.dense.DenseVectorCol[Double] = 
0.0
2.0
0.0
0.0
0.0

You can also access or update a range of elements at with slicing.

scala> x(3 to 4) := .5
res8: scalala.tensor.mutable.Vector[Double] = 
0.5
0.5

scala> x
res9: scalala.tensor.dense.DenseVectorCol[Double] = 
0.0
2.0
0.0
0.5
0.5

The slice operator constructs a read-through and write-through view of the given elements in the underlying vector. You set its values using the vectorized-set operator :=. You could as well have set it to a compatibly sized tensor.

scala> x(0 to 1) := DenseVector(.1,.2)

scala> x
res11: scalala.tensor.dense.DenseVectorCol[Double] = 
0.1
0.2
0.0
0.5
0.5

Similarly, a DenseMatrix can be created with a constructor method call, and its elements can be accessed and updated.

scala> val m = DenseMatrix.zeros[Int](5,5)
m: scalala.tensor.dense.DenseMatrix[Int] = 
0  0  0  0  0  
0  0  0  0  0  
0  0  0  0  0  
0  0  0  0  0  
0  0  0  0  0

scala> m(2,1) = 3

scala> m
res15: scalala.tensor.dense.DenseMatrix[Int] = 
0  0  0  0  0  
0  0  0  0  0  
0  3  0  0  0  
0  0  0  0  0  
0  0  0  0  0 

The rows and columns of m can be accessed as Vectors.

scala> (m.numRows, m.numCols)
res10: (Int, Int) = (5,5)

scala> m(::,1)
res17: scalala.tensor.dense.DenseVectorCol[Int] = 
0
0
3
0
0

scala> m(4,::) := DenseVector(1,2,3,4,5).t  // transpose to match row shape
res38: scalala.tensor.dense.DenseVectorRow[Int] = 1 2 3 4 5

scala> m
res39: scalala.tensor.dense.DenseMatrix[Int] = 
0  0  0  0  0  
0  0  0  0  0  
0  3  0  0  0  
0  0  0  0  0  
1  2  3  4  5  

Assignments with incompatible cardinality or a larger numeric type won't compile. Assignments with incompatible size will throw a DomainException:

scala> m := x
<console>:36: error: Could not find a way to scalala.operators.OpSet scalala.tensor.dense.DenseVectorCol[Double] into scalala.tensor.dense.DenseMatrix[Int]
       m := x
scala> m := DenseMatrix.zeros[Int](3,3)
scalala.tensor.domain.DomainException: Incompatible domain: TableDomain(3,3)

Sub-matrices can be sliced and updated, and literal matrices can be specified using a simple tuple-based syntax.

scala> m(0 to 1, 0 to 1) := DenseMatrix((3,1),(-1,-2)) 
res78: scalala.tensor.mutable.Matrix[Int] = 
 3   1 
-1  -2

scala> m
res79: scalala.tensor.dense.DenseMatrix[Int] = 
 3   1   0  0  0  
-1  -2   0  0  0  
 0   3   0  0  0  
 0   0   0  0  0  
 1   2   3  4  5

Elements of a tensor can be updated with standard operators:

scala> x(0) += .01
0.11
0.2
0.0
0.5
0.5

Operators

Scalala supports a rich library of operators defined on vectors and matrices. Tensors can be updated by a scalar value or by another tensor of the same domain (e.g. same size matrices). Tensors can be updated by a scalar with += -= *= /= %= :^=. Tensors can be updated by another tensor with := :+= :-= :*= :/= :%= :^=, where the ":" is used to denote element-wise updates. (Think of : like Matlab's ..) Because :+= and :-= are only defined element-wise, the colon is optional, so you can just write += and -=. The scalar operator :^= is prefixed with a colon to disambiguate from (square) matrix exponentiation.

scala> x += 1
res27: scalala.tensor.dense.DenseVectorCol[Double] = 
1.11
1.2
1.0
1.5
1.5

scala> x :*= DenseVector(-2,-1,0,1,2)
res40: scalala.tensor.dense.DenseVectorCol[Double] = 
-2.22
-1.2
0.0
1.5
3.0

Instead of mutation, new tensors can be created as the result of an operation with another tensor + - * / % :^ or with other tensors using the pairwise operators :+ :- :* :/ :% :^ that act on tensors with the same dimensions. Comparison operators (:== :!= :< :> :<= :>=) also exist, which create Boolean-valued tensors. Because + and - are always pairwise, their : prefix is optional and always mean the same as :+ and :-. By contrast, The * and \ operators represent shaped multiplication and require their arguments to be conformant: e.g. a matrix of size mn can be multiplied only by a column vector of length n or a matrix of size nk.

scala> m * x
res41: scalala.tensor.dense.DenseVectorCol[Double] = 
 -7.860
  4.620
 -3.599
  0.000
  16.38

Note that the returned type correctly abstracts over both the collection type (keeping the return type as dense and a column) as well as the value type (the result of multiplying and Int by a Double is a Double).

Default implementations exist for all tensor types, but some code paths have been optimized to defer to special-purpose numerical optimizations provided by linear algebra backends like BLAS and LAPACK sometimes.

scala> x.t * x
res42: Double = 17.6184

scala> x * x.t
res43: scalala.tensor.dense.DenseMatrix[Double] = 
  4.9284   2.6640 -0.0  ... (2 more)
  2.6640   1.4400 -0.0  ...
 -0.0000  -0.0000  0.0  ...
 -3.3300  -1.7999  0.0  ...
 -6.6600  -3.5999  0.0  ...

Systems of equations can be solved using the \ operator:

scala> DenseMatrix.eye[Double](5) // identity matrix
res44: scalala.tensor.dense.DenseMatrix[Double] = 
1.0  0.0  0.0  0.0  0.0  
0.0  1.0  0.0  0.0  0.0  
0.0  0.0  1.0  0.0  0.0  
0.0  0.0  0.0  1.0  0.0  
0.0  0.0  0.0  0.0  1.0

scala> (m + DenseMatrix.eye[Double](5)) \ x
res44: scalala.tensor.dense.DenseVectorCol[Double] = 
-2.22
-1.2
3.6
1.5
-1.53

Exploring the standard library

Scalala comes with a library of matlab-like matrix and vector operations and plotting commands. These methods are documented in scaladoc (sbt doc) for the traits in the scalala.library package. First, let's plot some lines and save the image to file. All the actual plotting work is done by the excellent JFreeChart library.

val x = DenseVector.range(0,100) / 100.0;
plot.hold = true
plot(x, x :^ 2)
plot(x, x :^ 3, '.')
xlabel("x axis")
ylabel("y axis")
saveas("lines.png") // save current figure as a .png, eps and pdf also supported

Lines plotting using ScalalaLines plotting using Scalala

Then we'll add a new subplot and plot a histogram of 1 million normally distributed random numbers into 100 buckets.

subplot(2,1,2)
hist(DenseVector.randn(1000000),100)
title("A normal distribution")
saveas("subplots.png")

Subplots of a plot, including a histogramSubplots of a plot, including a histogram

Scalala also supports the Matlab-like "image" command, here imaging a random matrix.

figure(2)
image(DenseMatrix.rand(200,200))
saveas("image.png")

Image plotsImage plots

Finally, one of the most useful pieces of scalala.library is simple "Library" which consists of basic mathematical functions and constants. For example, we can compute the mean and variance of a Vector:

val dv = DenseVector.rand(100)
mean(dv) // somewhere around 1/2
variance(dv) // somewhere around 1/12

We can also sum out Matrices along various axes:

val dm = DenseMatrix.rand(10, 20)
sum(dm, Axis.Horizontal) // row vector
sum(dm, Axis.Vertical) // column vector

There's also normalization of vectors and matrices:

val dv = DenseVector.rand(100)
normalize(dv,1) // sums to 1
normalize(dv,2) // has euclidean length 1
val dm = DenseMatrix.rand(10, 20)
normalizeCols(dm, 1) // each column sums to 1
normalizeRows(dm, 1) // each row sums to 1

Support: User Group || Documentation: QuickStart | Operators | ...